275 lines
11 KiB
Markdown
275 lines
11 KiB
Markdown
# Contributing
|
||
|
||
Contributions are appreciated! If you’d like to contribute, please help
|
||
us out by reading this short document.
|
||
|
||
## Before writing code
|
||
|
||
If you’re interested in adding a new feature, consider opening an issue
|
||
suggesting it. Then, we can discuss the feature to make sure that
|
||
everyone is on board.
|
||
|
||
If you’re interested in helping but don’t know where to start, consider
|
||
looking at open issues. [Issues marked **contributions-welcome**][cw]
|
||
may be especially accessible to newcomers.
|
||
|
||
[cw]: https://github.com/sourcecred/sourcecred/issues?q=is%3Aissue+label%3A"contributions+welcome"
|
||
|
||
If you find an issue that you’re interested in addressing, consider
|
||
adding a comment to that effect. This way, we can let you know if the
|
||
issue has gone stale before you put too much work into it, and other
|
||
contributors can know to focus on other issues.
|
||
|
||
## While writing code
|
||
|
||
### Semantically atomic commits
|
||
|
||
> for each desired change, make the change easy (warning: this may be
|
||
> hard), then make the easy change
|
||
>
|
||
> [—Kent Beck][kbeck-tweet]
|
||
|
||
[kbeck-tweet]: https://twitter.com/KentBeck/status/250733358307500032
|
||
|
||
Please factor your work into semantically atomic commits. Each commit
|
||
should represent a single semantic change, and the code included in the
|
||
commit should be the minimal amount of code required to implement, test,
|
||
and document that change.
|
||
|
||
For instance, perhaps you want to change the behavior of a component,
|
||
and along the way you find that it is useful to refactor a helper
|
||
function. In that case, you can create two commits: one to effect the
|
||
refactoring, and one to implement the change that has been made easy by
|
||
the refactoring.
|
||
|
||
This doesn’t mean that you have to physically write the code in this
|
||
order! The Git commit graph is malleable: you can write the code all at
|
||
once and commit it piecewise with `git add -p`; you can split and join
|
||
commits with interactive rebases; etc. What matters is the final
|
||
sequence of commits, not how you got there.
|
||
|
||
At the end of the day, you may find that you have a somewhat long
|
||
sequence of somewhat short changes. This is great. The goal is for a
|
||
reviewer to be able to say, “yep, this commit is obviously correct” as
|
||
many times in a row as are necessary for a full feature to be developed.
|
||
|
||
<details>
|
||
<summary>Why create small commits?</summary>
|
||
|
||
Writing small commits can help improve the design of your code. It is
|
||
common to realize an elegant way to split apart some functionality out
|
||
of a desire to split a commit into smaller, more localized pieces.
|
||
|
||
It is easier to review a commit that does one thing than a commit that
|
||
does many things. Not only will changes to the code be more localized,
|
||
but it will be easier for the reviewer to keep the whole context in
|
||
their mind.
|
||
|
||
Investigating and fixing bugs is much easier when commits are small.
|
||
There are more commits to look through, but an 8-fold increase in the
|
||
number of commits only entails 3 additional steps of bisection, which is
|
||
not a big deal. On the other hand, once the offending commit is
|
||
identified, the cause is more apparent if the commit is tiny than if it
|
||
is large.
|
||
</details>
|
||
|
||
### Checks
|
||
|
||
Each commit will need to pass all tests. Run `yarn test` or `npm test`
|
||
to run them all. This will run:
|
||
|
||
- **Flow** (`yarn flow`). Your code must type-check with no errors or
|
||
warnings. Using `any`-casts is permitted, but should be truly a last
|
||
resort. You should put significant effort into avoiding every
|
||
`any`-cast.
|
||
|
||
- **Unit tests** (`yarn unit`). You can also run `yarn unit --watch`
|
||
to automatically re-run tests when you change a relevant file.
|
||
|
||
- **Sharness** (`yarn sharness`). This runs shell-based tests, located
|
||
in the `sharness/` directory.
|
||
|
||
- **Prettier** (`check-pretty`). You can simply run `yarn prettify` to
|
||
reformat all files. It can be convenient to set up your editor to
|
||
run `yarn prettier --write CURRENT_FILENAME` whenever you save a
|
||
file.
|
||
|
||
- **Lint** (`yarn lint`). You’ll have to fix lint errors manually.
|
||
These are almost always unused imports or unused variables, and
|
||
sometimes catch logic errors before unit tests do. Feel free to
|
||
disable spurious lint errors on a per-line basis by inserting a
|
||
preceding line with `// eslint-disable-next-line LINT_RULE_NAME`.
|
||
|
||
- **Backend applications build** (`yarn backend`). This makes sure
|
||
that the CLI still builds.
|
||
|
||
- **Check for `@flow` pragmas** (`./scripts/ensure-flow.sh`). This
|
||
makes sure that every file includes a `// @flow` directive or an
|
||
explicit `// @no-flow` directive. The former is required for Flow to
|
||
consider a file. The latter has no effect, but we assert its
|
||
existence to make sure that we don’t simply forget to mark a file
|
||
for Flow. If this is failing, you probably added a new file and just
|
||
need to add `// @flow` to the top. Exceptional circumstances
|
||
excepted, all new files should have `// @flow`.
|
||
|
||
- **Check for stopships.** The sequence `STOPSHIP` (in any case) is
|
||
not allowed to appear in the codebase, except in Markdown files. You
|
||
can take advantage of this to insert a quick hack and make sure that
|
||
you remember to remove it later.
|
||
|
||
This is the same set of tests that is run on our CI system, Travis.
|
||
|
||
## When writing commit messages
|
||
|
||
### Summary of changes
|
||
|
||
Include a brief yet descriptive **summary** as the first line of the
|
||
message. The summary should be at most 50 characters, should be written
|
||
in the imperative mood, and should not include trailing punctuation. The
|
||
summary should either be in sentence case (i.e., the first letter of the
|
||
first word capitalized), or of the form “area: change description”. For
|
||
instance, all of the following are examples of good summaries:
|
||
|
||
- Improve error messages when GitHub query fails
|
||
- Make deploy script wait for valid response
|
||
- Upgrade Flow to v0.76.0
|
||
- new-webpack: replace old scripts in `package.json`
|
||
- fetchGithubRepo: remove vestigial data field
|
||
|
||
If you find that you can’t concisely explain your change in 50
|
||
characters, move non-essential information into the body of the commit
|
||
message. If it’s still difficult, you may be trying to change too much
|
||
at once!
|
||
|
||
<details>
|
||
<summary>Why include a summary?</summary>
|
||
|
||
The 50-character summary is critical because this is what Git
|
||
expects. Git often assumes that the first line of a commit contains a
|
||
concise description, and so workflows like interactive rebases surface
|
||
this information. The particular style of the summary is chosen to be
|
||
consistent with those commits emitted by Git itself: commands like
|
||
`git-revert` and `git-merge` are of this form, so it’s a good standard
|
||
to pick.
|
||
</details>
|
||
|
||
### Description
|
||
|
||
After the initial line, include a **description** of the change. Why is
|
||
the change important? Did you consider and reject alternate formulations
|
||
of the same idea? Are there relevant issues or discussions elsewhere? If
|
||
any of these questions provides valuable information, answer it.
|
||
Otherwise, feel free to leave it out—some changes really are
|
||
self-documenting, and there’s no need to add a vacuous description.
|
||
|
||
<details>
|
||
<summary>Why include a description?</summary>
|
||
|
||
A commit describes a _change_ from one state of the codebase to the
|
||
next. If your patch is good, the final state of the code will be clear
|
||
to anyone reading it. But this isn’t always sufficient to explain why
|
||
the change was necessary. Documenting the motivation, alternate
|
||
formulations, etc. is helpful both in the present (for reviewers) and in
|
||
the future (for people using `git-blame` to try to understand how a
|
||
piece of code came to be).
|
||
</details>
|
||
|
||
### Test plan
|
||
|
||
After the description, include a **test plan**. Describe what someone
|
||
should do to verify that your changes are correct. This can include
|
||
automated tests, manual tests, or tests of the form “verify that when
|
||
you change the code in this way, you see this effect.” Feel free to
|
||
include shell commands and expected outputs if helpful.
|
||
|
||
Sometimes, the test plan may appear trivial. It may be the case that you
|
||
only ran the standard unit tests, or that you didn’t feel that any
|
||
testing at all was necessary. In these cases, you should still include
|
||
the test plan: this signals to observers that the trivial steps are
|
||
indeed sufficient.
|
||
|
||
<details>
|
||
<summary>Why include a test plan?</summary>
|
||
|
||
The value of a test plan is many-fold. Simply writing the test plan can
|
||
force you to consider cases that you hadn’t before, in turn helping you
|
||
discover bugs or think of alternate implementations. Even if the test
|
||
plan is as simple as “standard unit tests suffice”, this indicates to
|
||
observers that no additional testing is required. The test plan is
|
||
useful for reviewers, and for anyone bisecting through the history or
|
||
trying to learn more about the development or intention of a commit.
|
||
</details>
|
||
|
||
### Wrapping
|
||
|
||
Wrap all parts of the commit message so that no line has more than **72
|
||
characters**.
|
||
|
||
<details>
|
||
<summary>Why wrap at 72 characters?</summary>
|
||
|
||
This leaves room for four spaces of padding on either side while still
|
||
fitting in an 80-character terminal. Programs like `git-log` expect that
|
||
this amount of padding exists.
|
||
|
||
(Yes, people really still use 80-character terminals. When each of your
|
||
terminals has bounded width, you can display more of them on a screen!)
|
||
</details>
|
||
|
||
### Example
|
||
|
||
Here is an example of a helpful commit message. [The commit in
|
||
question][example-commit] doesn’t change very many lines of code, but
|
||
the commit message explains the context behind the commit, links to
|
||
relevant issues, thanks people who contributed to the commit, and
|
||
describes a manual test plan. Someone reading this commit for the first
|
||
time will have a much better understanding of the change by reading this
|
||
commit message:
|
||
|
||
```
|
||
Improve error messages when GitHub query fails
|
||
|
||
Currently, the GitHub graph fetcher will characteristically fail if:
|
||
1. it times out GitHub's server
|
||
2. it triggers the semidocumented abuse detection mechanism
|
||
|
||
In case 1, an intelligible error is posted to the console. In case 2, it
|
||
produces an unintelligible TypeError, because the response is not a
|
||
valid GraphQL response (the error field is not populated; it has a
|
||
custom message instead).
|
||
|
||
As of this commit, we gracefully catch both cases, and print a message
|
||
to console directing the user to #350, which has context on GitHub query
|
||
failures. This new catch works because in case 2, the data field is
|
||
empty, so we now properly recognize `x.data === undefined` as an error
|
||
case.
|
||
|
||
Thanks to @wchargin for the investigatory work behind this commit.
|
||
|
||
Fixes #223.
|
||
|
||
Test plan:
|
||
We don't have unit tests that cover this case, but I did manually test
|
||
it by asking GitHub to fetch `ipfs/go-ipfs`, which consistently fails.
|
||
I also tested it by using an invalid length-40 GitHub API token.
|
||
```
|
||
|
||
[example-commit]: https://github.com/sourcecred/sourcecred/commit/b61b8fbdb88a64192ca837550b7a53e6c27a90e0
|
||
|
||
## When submitting a pull request
|
||
|
||
Please create pull requests against `master` by default.
|
||
|
||
If your pull request includes multiple commits, please include a
|
||
high-level summary and test plan in the pull request body. Otherwise,
|
||
the text of your pull request can simply be the body of the unique
|
||
commit message.
|
||
|
||
Please be aware that, as a rule, we do not create merge commits. If you
|
||
have a stack of commits, we can either rebase the stack onto master
|
||
(preserving the history) or squash the stack into a single commit.
|
||
|
||
## After your pull request is merged
|
||
|
||
…you’re done! :-)
|