Added changelog-release skill.
This commit is contained in:
1 parent
0c8d5edf28
commit
67204cf4de
3 files changed
+295
No files matched your search
@@ -0,0 +1,130 @@
|
||||
---
|
||||
name: changelog-release
|
||||
description: The user's release methodology - how CHANGELOG.md (or debian/changelog) is written, how its newest untagged entry collects every change, and how release.mjs / release.py commit, tag and push from it. Use this skill before EVERY edit of a CHANGELOG.md or debian/changelog, whenever a change is finished and has to be recorded, when a version has to be chosen (patch or minor), when the user mentions a release, a tag, a version bump, release.mjs or release.py, or when a repository needs a changelog and a release script set up - even for a one-line addition to a changelog.
|
||||
---
|
||||
|
||||
# Changelog and release
|
||||
|
||||
The user releases with a release script (`release.mjs` or `release.py`) that reads the newest
|
||||
changelog entry, commits everything with the entry's summary line as the message, tags the commit
|
||||
with the entry's version and pushes. The changelog is therefore both the history of the project and
|
||||
the source of every commit message and tag. Getting the entry right is what makes a release a
|
||||
one-command step for the user.
|
||||
|
||||
## The rule that matters most: check the tag and the commit before every changelog edit
|
||||
|
||||
The user commits, tags and pushes between your edits, often without telling you. An entry whose
|
||||
version is tagged is released: changing it rewrites history that is already published, and the next
|
||||
release fails because the tag exists. This mistake has happened many times and the user finds it
|
||||
very annoying, so treat the check as part of the edit itself, not as a once-per-session step.
|
||||
|
||||
Right before each edit of the changelog, also for a one-line addition, run:
|
||||
|
||||
```sh
|
||||
git tag --sort=-v:refname | head -5
|
||||
git log --oneline -3
|
||||
git status --short
|
||||
```
|
||||
|
||||
Then decide:
|
||||
|
||||
- **The newest entry's version is not in the tags**: the entry is open. Add your items to it, and
|
||||
raise its version if your change needs a bigger bump (a feature in an open patch entry makes it a
|
||||
minor entry; keep one entry per release).
|
||||
- **The newest entry's version is tagged**: it is released. Add a new entry above it with the next
|
||||
version and your items. Never change the tagged entry, not even its wording.
|
||||
- **The newest commit is a release commit** (its message is the summary line of the newest entry):
|
||||
the user has just released; the same holds as for a tagged entry.
|
||||
|
||||
A check made earlier in the session does not count, because a release may have happened since.
|
||||
|
||||
## CHANGELOG.md format
|
||||
|
||||
```markdown
|
||||
# Changelog
|
||||
|
||||
## 1.4.1
|
||||
|
||||
fix: the export page saves the chosen date range instead of the default one.
|
||||
|
||||
- The date range of the export page is kept when the export starts.
|
||||
- The file name of an export names the date range.
|
||||
|
||||
## 1.4.0
|
||||
|
||||
feature: the reports are exported as CSV files from the export page.
|
||||
|
||||
- ...
|
||||
```
|
||||
|
||||
- `# Changelog` once at the top; entries newest first.
|
||||
- An entry is a `## x.y.z` heading, a blank line, one summary line, a blank line, and the changes
|
||||
as `-` items. The blank lines around the summary are what the release script looks for.
|
||||
- **The summary line is the commit message.** It starts with a type prefix as in the git history,
|
||||
`feature:`, `fix:` or `update:` (check `git log --oneline` of the repository for the prefixes it
|
||||
uses), then one sentence. It must not start with `-` or `#`, or the script finds no summary.
|
||||
When an entry collects several changes, rewrite the summary so it covers all of them.
|
||||
- **Items describe what changed for the user** of the software: behaviour, options, paths, pages,
|
||||
commands. Not the reasoning and not the implementation story. Reasons and design decisions go to
|
||||
`ADR.md`, which describes only the decisions behind the current code; the changelog is the only
|
||||
place for history.
|
||||
- Wrap items at about 100 columns, continuation lines indented by two spaces. Separate the list
|
||||
from the summary line with a blank line. Plain ASCII only.
|
||||
|
||||
### Versions
|
||||
|
||||
- Patch (`x.y.Z`) for fixes, minor (`x.Y.0`) for features; the user decides about major versions.
|
||||
- `x.y.z-n`, `n` from 2, is a later release of the same code with changes that are not code
|
||||
changes (documentation, packaging); `release.mjs` accepts it.
|
||||
- Every change you make goes into the newest untagged entry; when there is none, add one. A
|
||||
repository's `CLAUDE.md` may add rules; follow them.
|
||||
|
||||
## debian/changelog format (repositories that build a Debian package)
|
||||
|
||||
Some repositories keep the changelog in `debian-package/debian/changelog` and release with
|
||||
`release.py`. The same rules apply in Debian's format:
|
||||
|
||||
```text
|
||||
example-app (1.4.0-1) unstable; urgency=medium
|
||||
|
||||
feature: the service reads and changes its settings at /settings.
|
||||
|
||||
* GET and PUT /settings show and change the settings; a password is
|
||||
never shown, and an empty one keeps it.
|
||||
* The service starts after the database is reachable.
|
||||
|
||||
-- Maintainer Name <maintainer@example.org> Mon, 02 Mar 2026 10:00:00 +0100
|
||||
```
|
||||
|
||||
- The summary is the first text line, indented by exactly two spaces, between blank lines, not a
|
||||
`*` item. Items are ` * ` with continuation lines indented by four spaces.
|
||||
- The tag is the version without the Debian revision `1`: `(1.4.0-1)` is tagged `1.4.0`,
|
||||
`(1.4.0-2)` is tagged `1.4.0-2`.
|
||||
- The trailer line ` -- name <email> date` follows Debian policy (`date -R` format); keep the
|
||||
maintainer of the previous entries.
|
||||
|
||||
## Releasing
|
||||
|
||||
The user runs the release. Committing, tagging and pushing are the user's decisions, so:
|
||||
|
||||
- Do not run a release script without `-n` (`--dry-run`), which prints the git commands instead of
|
||||
running them. Use the dry run to show the user what a release would do.
|
||||
- Do not commit, tag or push on your own; only when the user asks.
|
||||
- The script refuses when the tag exists ("add a new CHANGELOG.md entry first"); that means an
|
||||
entry was released and the next change needs a new entry.
|
||||
|
||||
What the scripts do, in order: read the newest entry's version and summary, refuse when the tag
|
||||
exists, `git add -A`, `git commit -m <summary>`, `git tag <version>`, and
|
||||
`git push origin main --tags` unless `--no-push`. `-m` overrides the message.
|
||||
|
||||
## Setting up a new repository
|
||||
|
||||
When a repository needs this setup, copy the script that fits its language and changelog:
|
||||
|
||||
- `scripts/release.mjs` - Node.js, `CHANGELOG.md` in the repository root.
|
||||
- `scripts/release.py` - Python, `debian-package/debian/changelog`; change `CHANGELOG` for another
|
||||
path.
|
||||
|
||||
Make it executable, add a `## Releasing` section to the README describing the commands
|
||||
(`./release.mjs`, `-m`, `-n`, `--no-push`), and add a repository `CLAUDE.md` section with the
|
||||
changelog rules above when the user wants one.
|
||||
Reference in new issue
Block a user