Skip to content

Maintainer guide

How to use these docs

These docs are meant to be linked to. Include a link in your project’s readme or CONTRIBUTING.md file. E.g.,

See https://dmyersturnbull.github.io/ref/maintainer-guide/
but disregard the `security:` commit type.

Or just link to individual sections; e.g.,

Source headers: Refer to https://dmyersturnbull.github.io/ref/maintainer-guide/#source-headers

This guide is collection of best-practices that are easy to learn, use, and automate. It specifies:

  • One-commit-to-one-PR and one-issue-to-one-PR policies
  • A commit message specification compatible with Conventional Commits
  • type: issue labels that map 1-1 with commit types and map to changelog sections

Development process overview

There should be a 1-1-1-1-1 correspondence between issues, feature branches, pull requests, commits to the main branch, and changelog items. This simplifies project management, makes development more transparent, and facilitates automation that reduces manual effort and potential human error.

flowchart LR
  A[feature branch] --- B[issue] --- C[PR] --- D[commit to <i>main</i>] --- E[changelog item]

Changelog generation

This enables generation of changelogs that are actually useful. It allows GitHub’s automatically generated release notes feature and other tools to produce well-organized changelogs that cover every significant change but exclude unimportant ones (e.g. style). Changelog entries can be linked, too. In fact, every entry can be linked to the corresponding issue, PR, and commit.

Example

Bug fixes

Branches

Use trunk-based development. In that terminology, a feature branch is a branch to be merged into main. All development should happen in feature branches, and short-lived feature branches are preferred. Name feature branches <type>/<issue>-<description>--<author-initials>, where <type> is the issue type (see the section on commit types), <issue> is the issue number, <description> is a short description of the issue, Example: doc/14-japanese-translation--sw.

Each feature branch must be tied to exactly 1 issue and result in 1 commit to main. That means that branches must be squash-merged.

Example

gitGraph
commit id: "initial" tag: "v0.1.0"
commit id: "update docs"
branch feat/12-async-api--dmt
checkout feat/12-async-api--dmt
commit id: "start feature"
checkout main
commit id: "fix bug" tag: "v0.1.1"
checkout feat/12-async-api--dmt
commit id: "complete feature"
checkout main
merge feat/12-async-api--dmt id: "squash and rebase" tag: "v0.2.0"

In some situations, earlier versions need to be maintained, such as for security fixes. Name these branches by releases/<version> (e.g., releases/v1).

Issues

Issues must have exactly 1 type: label. Use effort: and priority: labels if they are helpful. Split large issues into bit-sized pieces and list those in the larger issue’s description.

Example

Requires several steps:

- [x] [write schema](#21)
- [x] [build schema linter](#22)
- [ ] [create infrastructure to deploy schema](#23)

Handling pull requests

Before required status checks have completed successfully, avoid submitting reviews. Instead, just comment.

Squash the commits into one, and ensure the resulting commit message follows the commit message format specification.

!!! tip “GitHub squash and merge

GitHub has a "Squash and merge" button, but there is nowhere to add a commit body or footer.
However, you can work around this in the repository settings:
Under "General" → "Pull Requests" → "Allow squash merging" (which should be checked),
set "default commit message" to "Pull request title and description".

Before clicking "Squash and merge", edit the PR title and description.
The title will be the commit message, and the description will be the commit body and footer.
(Separate the body and footer with a blank line.)

To help a contributor with their PR directly, see “Committing changes to a pull request branch created from a fork”. If the contributor abandoned the PR, instead use gh pr checkout <number>.

Versioning

Versioning is a subset of Semantic Versioning. Pre-releases are permitted only in the forms alpha<int>, beta<int>, preview<int>, and rc<int>, where <int> starts at 0. Alpha/beta/preview/RC MUST NOT be used out of order (e.g., not alpha1, beta1, alpha2).

Tags and deployment

Tags of the form v<semver> should result in full deployments. Tags of the form v<major> should automatically track their most recent semver tags. The latest tag should always match the main branch.

Repository contents

File types

  • Prefer open standards like AVIF, WEBP, OGGm FLAC, and AV1. (Choose webm over the more general MKV.)
  • Use simpler formats, like Markdown instead of ReST.
  • Prefer modern compression algorithms like LZ4 (.lz4) and ZSTD (.zst).

Source headers

Ensure that nontrivial files contain a header such as

SPDX-FileCopyrightText: Copyright <years>, Contributors to <project>
SPDX-PackageHomePage: <url>
SPDX-License-Identifier: <spdx-id>

Example

For Tyrannosaurus, this is:

SPDX-FileCopyrightText: Copyright 2020-2024, Contributors to Tyrannosaurus
SPDX-PackageHomePage: https://github.com/dmyersturnbull/tyrannosaurus
SPDX-License-Identifier: Apache-2.0

3rd-party code

Use SPDX headers in the aforementioned form.

Include a section in NOTICE.txt mentioning the source file(s), license, and external source. Include the license file in the form LICENSE-<spdx-id>.txt.

If you are modifying the file, you need 2 sets of SPDX headers, which should be visually separated. Follow those headers with a plain-language statement that you have modified the file.

!!! “example”

Example from
[rcsb/rcsb-chem-search pyproject.toml](https://github.com/rcsb/rcsb-chem-search/blob/master/pyproject.toml):

```python
# SPDX-FileCopyrightText: Copyright 2020-2024, Contributors to Tyrannosaurus
# SPDX-PackageHomePage: https://github.com/dmyersturnbull/tyrannosaurus
# SPDX-License-Identifier: Apache-2.0
#
# SPDX-FileCopyrightText: Copyright 2024, Contributors to rcsb-chem-search
# SPDX-PackageHomePage: https://github.com/rcsb/rcsb-chem-search
# SPDX-License-Identifier: BSD-3-Clause
#
# Adapted from Tyrannosaurus <https://github.com/dmyersturnbull/tyrannosaurus>.
```

Commit messages

Conventional commit messages

Commit messages must follow a subset of Conventional Commits.

  • Breaking changes MUST use !.
  • The body SHOULD be written as CommonMark. In that case, headings more significant than level 4 (####) MUST NOT be used. (Treat the subject as a level 3 (###) heading.) Imperative phrasing SHOULD be used.
  • Footers MUST be listed one per line in a single paragraph.
  • For a breaking change, if a body is included, the BREAKING CHANGE: footer MUST be present.
  • If a body is included, deprecations SHOULD be indicated by a Deprecates: footer of the form Deprecates: first, second.
  • Closed issues SHOULD be listed in a footer of the form Closes: #10, #22, #33. (Note: This guideline requires exactly 1 issue.)
  • Commits MUST NOT use footers that have not defined. The footers that are defined in this document are BREAKING CHANGE, Deprecates, Closes, and the attribution trailers listed below.
  • Projects MAY define their own additional footers; any such footer MUST be designed to facilitate automation or computational analysis.
  • Trailers MUST be ordered as: BREAKING CHANGE:, Deprecates:, Closes:, attribution(s).
  • Each commit type MUST be drop, depr, feat, security, fix, perf, build, docs, test, ci, refactor, or style.
Allowed attribution trailers
  • Acked-by
  • Reviewed-by
  • Helped-by
  • Reported-by
  • Mentored-by
  • Suggested-by
  • CC
  • Noticed-by
  • Tested-by
  • Improved-by
  • Thanks-to
  • Based-on-patch-by
  • Contributions-by
  • Co-authored-by
  • Requested-by
  • Original-patch-by
  • Inspired-by
  • Signed-off-by

Examples – only message

Example 1:

feat!: add schema

Example 2:

doc(i18n): add JP translation

Example – body and footers

feat!: add major new feature

Introduce option to set custom template **for paid users only**.

Define template parameters:
- name
- status

BREAKING CHANGE: /api/v1/generate-report endpoint
Closes: #14
Co-authored-by: Amelia Johnson <amelia@dev.com>
Co-authored-by: Cecilia Johnson <cecilia@dev.com>
Reviewed-by: Kerri Hendrix <kerri@dev.com>
Acked-by: Tom Monson <joe@dev.com>
Signed-off-by: Sadie Wu <sadie@dev.com>

Refer to the supplemental labels document for details.

Invalid and reverted changes

Note that there is no invalid or state: invalid: Duplicate issues, issues created by mistake, uninterpretable issues, etc., should be deleted.

Also, there is no revert type. Instead, use the type that reflects the reversion commit. This might be drop: or the type of the reverted commit. Label both commits with changelog: exclude.

Forcibly omitting or including release notes entries

Use changelog: exclude and changelog: exclude to override which changes are included in the release notes.

changelog: exclude excludes changes that would normally be included (e.g. feat:). Use it for

  • reversions and reverted commits,
  • trivial changes, and
  • docs:, tests:, style:, etc. commits that support a feat: commit added in the same release.

changelog: include adds changes that would normally be ommitted (e.g. style). Use it only to acknowledge unusually important style contributions.

Including dependent changes in one commit

It is completely acceptable – and encouraged – to add tests and documentation for a new feature inside a feat: commit, to remove them inside a drop: commit, and to update them inside a fix: or security: commit.

If separate commits were made, consider applying changelog: exclude to some, as described in the section above.

Details

Effectively, some types can be subsumed into others. This diagram details the allowed ways:

graph TD
    fix --> feat
    security --> feat
    perf --> feat
    test --> fix
    test --> feat
    test --> perf
    test --> security
    docs --> feat
    docs --> fix
    ci --> build
    build --> fix
    refactor --> feat
    refactor --> fix
    refactor --> build
    refactor --> ci
    refactor --> test
    refactor --> security
    s["style"] --> any["*"]

Scopes

Scopes should be defined per project. If a scope is defined, it should be applied to all relevant commits, at least to those made after the scope’s introduction.

Suggestions:

  • i18n
  • plugins

Reference

Pattern

<type>[(<scope>)][!]: <subject>

<body>

[BREAKING CHANGE: <feature, etc.>]
[Deprecates: <feature, etc.>]
[Closes: #<issue>]
[*: <author>]*
"""