diff --git a/docs/compare/tools.md b/docs/compare/tools.md index 1b0f820..c6a76e5 100644 --- a/docs/compare/tools.md +++ b/docs/compare/tools.md @@ -2,7 +2,7 @@ What else checks commit messages, branch names and pull request titles on GitHub, what each one does, and when it is the better choice. Prices and -features are as the projects list them in September 2026; follow the links +features are as the projects list them in September and October 2026; follow the links for the current state. GitHub's own rulesets are on [their own page](github-rules.md). @@ -11,6 +11,7 @@ for the current state. GitHub's own rulesets are on | Tool | What it is | What it checks | Where it runs | Price | |---|---|---|---|---| | [commitlint](https://commitlint.js.org/) with [commitlint-github-action](https://github.com/wagoid/commitlint-github-action) | The reference Conventional Commits linter in the JavaScript world: shared configs, plugins, a [commitizen](https://commitizen.github.io/cz-cli/) prompt | Commit messages | Node hook (husky), CI Action | Free, open source | +| [gitlint](https://github.com/jorisroovers/gitlint) | A Python commit message linter with a `commit-msg` hook, configured in a `.gitlint` file; one of the two commit linters the [pre-commit hooks page](https://pre-commit.com/hooks.html) features. Its latest release, 0.19.1, is from March 2023, and its [PyPI page](https://pypi.org/project/gitlint/) says the maintainer is looking for co-maintainers | Commit messages: title and body length, whitespace, required words, regexes; Conventional Commits and sign-off as opt-in rules | Git hook, pre-commit, CLI | Free, open source | | [action-semantic-pull-request](https://github.com/amannn/action-semantic-pull-request) | The most-used pull request title check; Electron, Vite and Vercel run it | The pull request title (optionally the single commit, for squash merges) | GitHub Action | Free, open source | | [Semantic PRs](https://github.com/Ezard/semantic-prs) | A GitHub App with the same idea: type and scope on the title or the commits | Pull request title or commits | GitHub App | Free, open source | | [commitcheck](https://github.com/marketplace/commitcheck) | A hosted App that applies one regular expression, set in its web admin | Commit message, pull request title or description, by regex | GitHub App | Free for public repositories; $25 a month for private ones | @@ -53,11 +54,67 @@ for the current state. GitHub's own rulesets are on [rulesets page](github-rules.md). Every tool above, Commit Check included, marks the commit or blocks the merge. +## Coming from gitlint + +Both are Python, both run as a `commit-msg` hook through pre-commit, so the +switch is a change to `.pre-commit-config.yaml` and a translation of +`.gitlint` into `cchk.toml`. + +Replace the hook: + +```yaml title=".pre-commit-config.yaml" +repos: + - repo: https://github.com/commit-check/commit-check + rev: v2.19.4 + hooks: + - id: check-message +``` + +Install it the same way: `pre-commit install --hook-type commit-msg`. + +Two defaults differ. Commit Check requires +[Conventional Commits](../rules.md#cc001) unless you turn it off, where +gitlint makes it an opt-in rule (`contrib=CT1`). And gitlint requires a body +out of the box (B6), where Commit Check does not. This keeps gitlint's +defaults: + +```toml title="cchk.toml" +[commit] +conventional_commits = false # drop if you used contrib=CT1 +subject_max_length = 72 # T1 +subject_min_length = 5 # T8 +allow_wip_commits = false # T5's default word, WIP +require_body = true # B6 +``` + +Rule by rule: + +| gitlint | Commit Check | +|---|---| +| T1 `title-max-length` | `subject_max_length` ([CC004](../rules.md#cc004)) | +| T5 `title-must-not-contain-word` (default `WIP`) | `allow_wip_commits = false` ([CC010](../rules.md#cc010)), which rejects a subject that starts with `WIP`; gitlint rejects the word anywhere in the title | +| T7 `title-match-regex`, B8 `body-match-regex` | `message_pattern`, one regex over the whole message ([CC001](../rules.md#cc001)) | +| T8 `title-min-length` | `subject_min_length` ([CC005](../rules.md#cc005)) | +| B5 `body-min-length`, B6 `body-is-missing` | `require_body` ([CC011](../rules.md#cc011)); there is no minimum length | +| M1 `author-valid-email` | the `check-author-email` hook ([CC102](../rules.md#cc102)), with `author_email_pattern` | +| CT1 `contrib-title-conventional-commits` | `conventional_commits`, on by default ([CC001](../rules.md#cc001)) | +| CC1 `contrib-body-requires-signed-off-by` | `require_signed_off_by` ([CC012](../rules.md#cc012)) | +| CC2 `contrib-disallow-cleanup-commits` | `allow_fixup_commits = false` ([CC009](../rules.md#cc009)) | +| I4 `ignore-by-author-name` | `ignore_authors` | +| merge, revert, fixup commits ignored | the format rules already skip the subjects git writes; [CC006](../rules.md#cc006), [CC007](../rules.md#cc007) and [CC009](../rules.md#cc009) decide whether they are allowed | +| T2–T4, T6 whitespace and tab rules, T3 trailing punctuation, B1–B4 body line rules, B7 changed-file mention, user-defined Python rules | no equivalent | + +The last row is the honest gap: if your policy depends on body line length or +a custom rule written in Python, gitlint still does that and Commit Check does +not. What you gain is the rest of this page: branch names, authors, the +Action, the App, and a release that is current. + ## Which to choose - You want the pull request title checked and nothing else: `action-semantic-pull-request`. - You are in a JavaScript repository with husky and want plugins: commitlint. - You need sign-off with a remediation flow: the DCO app, or DCO-2. +- You rely on gitlint's body line rules or your own Python rules: gitlint. - You want one policy for messages, branches and authors, the same everywhere a commit is made and checked, with a hosted option that needs no workflow file: Commit Check. diff --git a/docs/guides/release-tools.md b/docs/guides/release-tools.md new file mode 100644 index 0000000..93ad4aa --- /dev/null +++ b/docs/guides/release-tools.md @@ -0,0 +1,95 @@ +# With release tools + +release-please, semantic-release, git-cliff and `cz bump` read your commit +messages to decide the next version and write the changelog. A commit they +cannot parse is not an error to them: it is left out of the changelog, or it +does not count toward a release. Commit Check is the gate in front of them, +so what they read always parses. + +## Check the message the tool will read + +Which message that is depends on how pull requests are merged. + +- **Merge commits or rebase.** Every commit on the branch lands on `main`, and + the release tool reads each one. Check each one: the + [pre-commit hook](pre-commit.md) while it is written, and the + [Action](github-actions.md) with its default `message: true` on the pull + request. +- **Squash merge.** The branch's commits are thrown away, and the pull + request title becomes the commit on `main`. release-please, for one, + "highly recommend[s]" squash merges. Check the title: `pr-title: true` on + the Action, or `check = "squash"` on the [App](github-app.md#pull-requests), + which checks the full message a squash merge would land. With GitHub's + default squash message, a pull request of a single commit lands that + commit's message rather than the title. The App follows that setting; with + the Action, set the squash commit message to "Pull request title" in the + repository settings so the title you check is the one that lands. + +```yaml title=".github/workflows/commit-check.yml" +name: Commit Check + +on: + pull_request: + types: [opened, edited, synchronize, reopened] + +jobs: + commit-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: commit-check/commit-check-action@v2 + with: + message: false # the branch's commits do not reach main + pr-title: true +``` + +The default [commit types](../configuration.md) are the Conventional Commits +ones the tools release on (`feat`, `fix`, `perf`) plus the ones they parse but +do not release on, such as `docs` and `chore`; whether those show in the +changelog is the tool's setting. A breaking change written as `feat!:` or +`feat(api)!:` passes Commit Check, and so does a `BREAKING CHANGE:` footer. +semantic-release's default Angular preset does not read the `!`, though: give +the commit a `BREAKING CHANGE:` footer, or switch it to the +`conventionalcommits` preset. + +## Let the tool's own pull request through + +release-please and changesets open their release pull request from a branch +whose name you cannot choose: + +| Tool | Branch | Default title | +|---|---|---| +| release-please | `release-please--branches--main`, plus `--components--` in a monorepo | `chore(main): release 1.2.3` | +| [changesets/action](https://github.com/changesets/action) | `changeset-release/main` | `Version Packages` | + +The default branch rule, [CC201](../rules.md#cc201), rejects both names. +Allow the ones you use: + +```toml title="cchk.toml" +[branch] +allow_branch_names = ["release-please--branches--.+", "changeset-release/.+"] +``` + +Each entry is a regular expression that has to match the whole branch name, +so these allow the tools' branches and nothing that merely contains them. + +release-please's title passes [CC001](../rules.md#cc001) as it is. +changesets' `Version Packages` does not, so with `pr-title: true` give it a +Conventional Commits title and commit message: + +```yaml +- uses: changesets/action@v1 + with: + commit: "chore: version packages" + title: "chore: version packages" +``` + +## Per tool + +| Tool | What it reads | Notes | +|---|---|---| +| [release-please](https://github.com/googleapis/release-please) | Conventional Commits on the release branch since the last release | Branch name above. Its README recommends squash merges, so check the title. | +| [semantic-release](https://github.com/semantic-release/semantic-release) | Commits since the last release, with the Angular preset by default | The Angular types are Commit Check's defaults. | +| [git-cliff](https://github.com/orhun/git-cliff) | Commits, parsed as Conventional Commits when `conventional_commits = true` in `cliff.toml` | With `filter_unconventional = true`, a commit that does not parse is dropped from the changelog without a word. | +| [Commitizen](https://commitizen-tools.github.io/commitizen/) `cz bump` | Conventional Commits since the last tag | Commitizen has its own `cz check`. Commit Check adds branch names, authors, sign-off and the App, from one config. | +| [changesets](https://github.com/changesets/changesets) | Changeset files, not commit messages | Only its branch name and PR title matter here, both above. | diff --git a/mkdocs.yml b/mkdocs.yml index 0bddd7e..713556a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -175,6 +175,7 @@ nav: - GitHub Action: guides/github-actions.md - GitHub App: guides/github-app.md - GitLab, Bitbucket, Azure: guides/other-ci.md + - With release tools: guides/release-tools.md - Across an organization: guides/organization.md - MCP server: guides/mcp.md - Python API: guides/python-api.md