Josh Goldberg
Logo of create-typescript-app: the TypeScript blue square with rounded corners, but a plus sign instead of 'TS'

Contributing to a create-typescript-app Repository

Oct 20, 202320 minute read

A thorough guide through contributing to create-typescript-app or any repository scaffolded using it.

create-typescript-app is a project of mine that provides a comprehensive template for any TypeScript repository. It scaffolds building, formatting, linting, releases, semantic versioning, and other commonly useful repository tooling in a standardized way. I use it for most of my open source projects now.

One benefit of using a single template for many repositories is that each of those repositories ends up with a very similar contributing flow. Making changes, running tests, sending pull requests, and so on are all the same now across most of my repositories. This blog post and its associated FAQs are a comprehensive guide to the common activities you’ll need to contribute to any of those repositories.

Prerequisites

You’ll need to install the following two tools on whatever computer/environment you want to develop on:

I recommend VS Code on your own computer because that’s what I personally use and can help with the most. This blog post assumes you’re using VS Code to keep the explanations straightforward. But if you feel more comfortable with a different setup, that’s great too. Just make sure you’re following the equivalent steps for your editor.

My repositories also include a lot of additional tooling that you’ll likely need to work with. Please read the repository’s contributing guide (.github/CONTRIBUTING.md) and development guide (.github/DEVELOPMENT.md). They’ll tell you each of the commands used in that repository.

Git and GitHub Familiarity

You don’t need to be confident in Git or GitHub to contribute. I’ve included common steps to take in this guide. But it’s helpful to understand vaguely what a “repository” is and what the difference between Git and GitHub are. At the very least, go through GitHub’s Hello World and Contributing to Projects guides.

Finding an Issue

A good first step for contributing is to find an open issue on the repository’s issues page that is:

Unless the change you’d like to make is an exceedingly small typo, please don’t skip this step. Respecting the issue process gives several benefits:

I recommend finding an issue labeled good first issue if you’ve never worked in a particular repository before. Those issues are generally smaller, more self-contained ones that the maintainer(s) think should be good for first-timers.

Filing issues

If you already had a change in mind and don’t see it in the issue tracker, great! That’s an opportunity for you to contribute by filing an issue. Please do!

Also please be sure to read and fill out the issue template in full. Remember that the maintainer(s) reading your issues might not know anything about you or your code. They might not have the time to go researching. The issue should clearly and succinctly state what you’re looking for and what you’ve tried so far.

Forking the Repository

At this point, you’re ready to start working on code! 🙌 Your steps now will be to create a branch on a GitHub repository so that the branch’s changes can later be reviewed. But unless you’ve been added as a collaborator or maintainer on someone else’s repository, you won’t have permissions to push branches to that repository on GitHub. You’ll need to:

  1. Fork the repository to your own account on GitHub
  2. Clone that repository to wherever you want to develop from
  3. Tell your local repository clone about its “remotes” (online repositories it can pull from and/or push to):
    • Origin: Your forked repository, which your local clone sees as its main source of truth (as in the, origin of your local repository’s history)
    • Upstream: The original repository (as in, its changes will flow “downstream” to your origin repository)

Let’s say your GitHub username was YourUsername and you wanted to contribute to the create-typescript-app repository owned by the JoshuaKGoldberg user on GitHub. You’d fork the repository and then run something like this:

git clone https://github.com/YourUsername/create-typescript-app
cd create-typescript-app
git remote add origin https://github.com/YourUsername/create-typescript-app
git remote add upstream https://github.com/JoshuaKGoldberg/create-typescript-app

The terms we’d use to refer to your repositories would be:

Consider running git remote -v locally to see its list of remotes. You should see something like:

$ git remote -v
origin  https://github.com/YourUsername/create-typescript-app (fetch)
origin  https://github.com/YourUsername/create-typescript-app (push)
upstream        https://github.com/JoshuaKGoldberg/create-typescript-eslint.git (fetch)
upstream        https://github.com/JoshuaKGoldberg/create-typescript-eslint.git (push)

Setting Up Your Workspace

You’ll now want to set up your workspace with the standard tools to develop with. Run the following two commands:

  1. pnpm install: to install required dependencies into the node_modules/ directory
  2. The build command mentioned in .github/DEVELOPMENT.md (commonly, pnpm build): to make sure that installing succeeded

A VS Code popup should have appeared in the bottom-right corner of the window suggesting you install some editor extensions. I’d highly recommend installing them. They’ll give you real-time feedback as you edit files, which will save you a lot of time debugging issues.

You can see the list of a repository’s extensions in .vscode/extensions.json.

Formatting On Save

A .vscode/settings.json file exists with default settings to configure VS Code. Notably, it indicates that files should be auto-formatted on save with the Prettier extension. Try adding a few spaces after a ; in a TypeScript source file such as src/index.ts, then saving. The spaces should be removed.

You’re now ready to start editing source files! 🎉

Building Changes

The repository’s .github/DEVELOPMENT.md should describe how to build source files into runnable output files. Commonly:

pnpm build --watch

I recommend also keeping the TypeScript compiler (tsc) running in a second, split terminal window as you make changes, so that you can get real-time updates from the type checker:

pnpm tsc --watch

Now, as you edit source files, equivalent output files should be made and continuously updated.

Validating Changes

I’d recommend trying out your changes locally to make sure they’re working as you’d expect. Two common situations for repositories are:

The repository will also have automated tooling to validate changes. Those tools will also be describe in its .github/DEVELOPMENT.md file.

Most repositories have the following commands:

Running Tests

Most repositories -mine included- generally ask that any changes to code logic should be accompanied by unit tests. Doing so makes sure that the logic is correct and stays correct as the repository changes over time.

Tests can most commonly be run with something like:

pnpm test

Test Snapshots

Vitest snapshots are used in some repositories to help tests assert that some set of values is exactly what’s expected. I generally use them when writing out the exact values would be annoying and cumbersome. You can generally update snapshots in repositories with a command like:

pnpm test -u

Sending a Pull Request

Once you’ve gotten as much confidence as you can in your changes, you’ll want to send them in as a Pull Request for review. It’s best to create a separate branch for your changes instead of sending the pull request from your main branch.

I recommend giving the first commit on that branch a message adhering to conventional commits. New pull requests’ titles must adhere to conventional commits, and when the branch has just one commit, they default to that commit’s message.

Continuing the YourUsername/create-typescript-app example:

# 1. Create a new branch named my-changes
git checkout -b my-changes

# 2. "Stage" (mark as ready to commit) all file changes
git add -A

# 3. Make a commit with all those files on the branch
git commit -m "feat: your message here"

# 4. Send the commit from your local to the origin
git push -u origin my-changes

The last step should output a message with a URL to create a new pull request. It may look something like:

Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Writing objects: 100% (1/1), 123 bytes | 123.45 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0), pack-reused 0
remote:
remote: Create a pull request for 'my-changes' on GitHub by visiting:
remote:      https://github.com/JoshuaKGoldberg/create-typescript-app/pull/new/my-changes
remote:
To https://github.com/JoshuaKGoldberg/create-typescript-app
 * [new branch]      my-changes -> my-changes
branch 'my-changes' set up to track 'origin/my-changes'.

Click that link to visit the GitHub pull request creation page. Be sure to read and [x] check all the

Check the boxes with exactly [x]. Not [ x ] or [x ] or [ x]. Not [✔️] or [✅]. Just [x].

Review Comments

You can always add more changes to the pull request by making a new commit on the same branch and pushing it. The -u origin is no longer necessary for git push now that your local repository knows which remote the branch’s commits should be pushed to:

git add -A
git commit -m "more changes etc etc"
git push

Please don’t force push (git push --force) after a PR has been sent. It’s annoying to review changes over time if the history keeps changing.

Re-Requesting Review

Reviews that are waiting resolutions to commits are given the status: waiting for author label. Once you’re ready to have the pull request looked at again, re-request review from the maintainer(s) whose requests you feel are ready to be reviewed. The label should be removed automatically.

If there are any comment threads you didn’t resolve, such as from not knowing the right way to, post a response to each specific comment thread. Otherwise there’s no need to @ tag any maintainers. You can mark any other comment threads as resolved.

Pulling in Branch Changes

After you send your pull request for review, a maintainer might make some changes on GitHub for you. For example, I might sync the latest main into your branch or apply code review suggestions.

Those changes will be made to your origin repository on GitHub. You’ll want to pull the changes into your local repository:

git pull

Pulling in Repository Changes

When a pull request is merged (yay!), a new “squash merge” commit is made on the upstream repository’s main branch. That commit contains all the same file changes from the pull request - but is not the same commit hash as any of the origin repository’s. You’ll want to pull the upstream repository’s new main commit into the main branches of both your local and origin repositories.

One common way is to switch to the main branch locally, pull in the upstream’s new history, and then push to the origin:

git checkout main
git pull upstream main
git push

At this point, your pull request and all associated tasks should be complete! Everybody’s main branch is up-to-date and contains all the changes. Hooray!

Feeling Good About Yourself

Open source is awesome! I love working in the open. It lets me work with all sorts of people: from fresh newcomers to some of the most knowledgeable, experienced developers out there.

Even if you only made a small change -or didn’t get all the way through a pull request- you’re still working in open source. That’s awesome. I hope you feel great about it.

Acknowledgements

Many thanks to Andrii Dieiev and Michael Faith for proofreading and suggesting improvements to this post!

Got any questions on the flow in this guide? See the associated FAQs!