Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
<!--
Please write this PR in ENGLISH: summary, changes, testing notes, and related issue references.
Please write this PR in ENGLISH: title, summary, changes, testing notes, and related issue references.

Title: name the whole change in English. A single-intention PR mirrors its commit
header (type(scope): description); a multi-intention PR uses a short descriptive
title. Issue links go in "Related issues" below, not the title.
See CONTRIBUTING.md -> "Pull request titles".

Fill in the applicable sections below.
Do not invent information.
Expand Down
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,6 @@ errors should stay structured, documented, and close to the code.
* Do not open a pull request unless I explicitly ask for one.
* PR titles, descriptions, commits, and branch names must be written in English.
* Write every commit message per [`CONTRIBUTING.md`](CONTRIBUTING.md): Conventional Commits, a closed type list, the scopes `core, analyzers, cli, gendoc, testing`, an imperative header within 72 characters, and `Refs: #NN` in a footer when a GitHub issue exists (issue-closing keywords belong in the PR description, not the commit).
* Write every pull request title per [`CONTRIBUTING.md`](CONTRIBUTING.md): name the whole change in English; a single-intention PR mirrors its commit header (`type(scope): description`), a multi-intention PR uses a short descriptive title, and issue references stay in the description, not the title.
* Enable the local commit-message hook once per clone with `git config core.hooksPath .githooks`; the same check runs in CI on every pull request.
* In PR descriptions, do not invent testing results. Only check items that were actually run.
59 changes: 59 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -349,3 +349,62 @@ commits, generated by GitHub, are exempt.

This section adapts the [Conventional Commits 1.0.0](https://www.conventionalcommits.org/en/v1.0.0/)
specification, published under [CC BY 3.0](https://creativecommons.org/licenses/by/3.0/).

## Pull request titles

The convention above governs each commit. A pull request needs a line of its
own, and it is not the same object: the commit is the unit of the change, the
**pull request the unit of the request** — the relation the doctrine already
draws between the commit and the issue. A pull request MAY therefore gather
several commits, of several types.

Its title is read in three places: the list of open pull requests, the
`Merge pull request #NN` commit GitHub writes when the branch lands (this
repository merges with a merge commit), and the draft of the release notes. It
earns the same care as a commit header. Unlike a commit, it is **not** linted;
it stands on the review, as the code does.

### The rule

* The title MUST be in **English**, like everything else recorded here.
* It MUST name the **whole** pull request, not one of its commits. The per-commit
types live in the commits, where the hook and CI check them; the title says
what the branch delivers.
* Its shape follows from how many intentions the pull request carries:
* **One intention** — the branch does a single kind of thing. The title MUST
mirror the commit header it collapses to:
`<type>[(<scope>)][!]: <description>`, under the very rules of the section
above — imperative present, lowercase after the colon, no trailing period. A
one-commit pull request's title is that commit's header, verbatim.
* **Several intentions** — the branch carries a feature and the refactor that
prepared it, or a fix and the test that pins it. The title MUST NOT borrow a
single `type:` prefix: it would name one commit and hide the rest. It states
the subject in plain words, as a title — an initial capital, no trailing
period. A topical prefix (`Release supply chain: …`) is welcome; a
Conventional-Commits type is not, unless it is honestly the only one.
* Keep the title within the **72 characters** a commit header targets, so the
pull request list shows it whole.
* The issue reference lives in the **description**, never the title: `Closes #NN`
when the pull request closes the issue, so GitHub closes it on merge; `Refs:
#NN` otherwise. The title states the change, not where it was asked. A breaking
change is signalled the same way it is on a commit — the `!` and the
`BREAKING CHANGE:` note ride the commit, and the template's "Breaking change"
box repeats it — not the title.

### Examples

| Title | Why it fits |
|---|---|
| `ci: add dependency review on pull requests` | One intention. The title is the commit header. |
| `feat(analyzers): add FCE016 for an undocumented error code` | One intention, scoped. The issue it closes lives in the description, not here. |
| `Adopt and enforce a Conventional Commits convention` | The guide, the hook, and the CI gate — several commits of several types. A plain title names them all. |
| `Release supply chain: build provenance + embedded SBOM` | Several intentions under one topic. A topical prefix carries it; no single `type:` would be honest. |

### Anti-patterns

| Title | What is wrong |
|---|---|
| `feat: various improvements` | A type on a grab-bag. Either it is one intention — name it — or it is several, and `feat:` hides them. |
| `fix(core): Fixed the null dereference.` | The single-intention form, wearing the commit header's own faults: capital, past tense, trailing period. |
| `Add Outcome.Map (#142)` | The issue number belongs in the description's `Closes`/`Refs`, where GitHub reads it — not eating the title. |
| `Corrige le rendu des exemples` | Not English. |