Skip to content

Commit 827b9a2

Browse files
chore: adopt changesets for releases and publish a compatibility policy (#1392)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent b12ccdd commit 827b9a2

33 files changed

Lines changed: 1246 additions & 619 deletions

.changeset/README.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Changesets
2+
3+
A **changeset** here is a release note: a `.changeset/*.md` file that becomes `CHANGELOG.md` and drives
4+
the version bump. (Not a Liquibase `<changeSet>` — a schema change needs both.)
5+
6+
Every PR that changes shipped code (anything under `server/`, `webapp/`, or `docker/` except tests and in-tree docs) ships one; CI (`verify-changesets`) enforces it.
7+
8+
```bash
9+
pnpm changeset # write one (pick the bump, describe the change)
10+
pnpm changeset --empty # no user-facing effect — then write why in the file body (non-interactive)
11+
```
12+
13+
The summary lands in the changelog **verbatim**, in the operator/user's voice — lead with what they can now
14+
do, or the symptom a fix removes. No class/hook/file names. No agent-attribution trailers. One changeset per
15+
user-visible change; unsure whether it's visible? Add one — a reviewer can delete it, a missing note can't.
16+
17+
No TTY (agents, CI)? `pnpm changeset` is interactive — instead write `.changeset/<slug>.md` by hand in the
18+
format shown below. That is the one sanctioned hand-write; never touch `CHANGELOG.md` directly.
19+
20+
**Bump = the operator's upgrade cost:**
21+
22+
| Bump | Operator upgrade | Examples |
23+
| --- | --- | --- |
24+
| `patch` | no action | bug fix, internal change, additive auto-applied migration |
25+
| `minor` | no action | new capability; note any new *optional* env var / flag in the summary |
26+
| `major` | must act first | required new env var, removed/renamed config, destructive/manual migration, dropped API — state the action + update `MIGRATION.md` |
27+
28+
**Pre-1.0 (now): never pick `major`** — it would cut 1.0.0; CI rejects it. Breaking changes ride in `minor`
29+
instead, so a pre-1.0 `minor` is *not* guaranteed zero-action: if the operator must act, say so
30+
(`**Operators:** …`) and update `MIGRATION.md` exactly as a `major` would.
31+
32+
Example (a migration-bearing fix):
33+
34+
```md
35+
---
36+
"hephaestus": minor
37+
---
38+
39+
Fixes duplicate leaderboard entries after a team rename.
40+
```
41+
42+
Full flow and rules: [release management guide](https://ls1intum.github.io/Hephaestus/contributor/release-management).

.changeset/changelog.cjs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Changelog entries are the summary verbatim — no commit hashes, PR links, or
2+
// attribution (the default formatter prefixes a commit hash; changelog-github
3+
// adds PR links + "Thanks @user!"). Operators read this file; git metadata
4+
// lives in git.
5+
module.exports = {
6+
getReleaseLine: async (changeset) => `- ${changeset.summary.trim().split("\n").join("\n ")}`,
7+
getDependencyReleaseLine: async () => "",
8+
};

.changeset/config.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json",
3+
"changelog": "./changelog.cjs",
4+
"commit": false,
5+
"baseBranch": "main",
6+
"privatePackages": {
7+
"version": true,
8+
"tag": false
9+
},
10+
"ignore": [
11+
"webapp",
12+
"docs"
13+
]
14+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"hephaestus": patch
3+
---
4+
5+
Fixes a release deploy that never started: the signature check on the pinned agent image rejected every
6+
valid release, so the application server stayed down.

.claude/skills/land-pr/SKILL.md

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ disable-model-invocation: true
77
allowed-tools:
88
- Bash(gh *)
99
- Bash(git *)
10-
- Bash(npm *)
11-
- Bash(mvn *)
10+
- Bash(pnpm *)
11+
- Bash(./mvnw *)
1212
- Read
1313
- Grep
1414
- Glob
@@ -112,7 +112,19 @@ pnpm run check
112112

113113
Both must pass.
114114

115-
## 9. Create Branch (if on main)
115+
## 9. Changeset (required for shipped-code changes)
116+
117+
If this PR changes `server/`, `webapp/`, or `docker/`, it must carry a changeset or CI (`verify-changesets`) fails:
118+
119+
```bash
120+
pnpm changeset # user-facing change: pick the bump, describe it for operators
121+
pnpm changeset --empty # no user-facing effect (refactor/test/docs-only)
122+
```
123+
124+
Pre-1.0: never pick `major`. Stage the generated `.changeset/*.md` before committing. `pnpm changeset` is
125+
interactive — with no TTY, write `.changeset/<slug>.md` by hand (`.changeset/README.md` shows the format).
126+
127+
## 10. Create Branch (if on main)
116128

117129
```bash
118130
git branch --show-current
@@ -126,7 +138,7 @@ git checkout -b <type>/<description>
126138

127139
Types: `feat`, `fix`, `docs`, `refactor`, `test`, `ci`, `chore`
128140

129-
## 10. Commit
141+
## 11. Commit
130142

131143
```bash
132144
git add -A
@@ -135,23 +147,23 @@ git commit -m "<type>(<scope>): <description>"
135147

136148
**Scopes:**
137149

138-
- Service: `webapp`, `server`, `ai`, `webhooks`, `docs`
139-
- Infra (no release): `ci`, `config`, `deps`, `deps-dev`, `docker`, `scripts`, `security`, `db`, `no-release`
140-
- Feature: `gitprovider`, `leaderboard`, `mentor`, `notifications`, `profile`, `teams`, `workspace`
150+
- Service: `webapp`, `server`, `docs`
151+
- Infra: `ci`, `config`, `deps`, `deps-dev`, `docker`, `scripts`, `security`, `db`, `release`
152+
- Feature: `auth`, `integration`, `scm`, `leaderboard`, `mentor`, `notifications`, `profile`, `teams`, `workspace`
141153

142-
## 11. Push
154+
## 12. Push
143155

144156
```bash
145157
git push -u origin HEAD
146158
```
147159

148-
## 12. Check if PR Exists
160+
## 13. Check if PR Exists
149161

150162
```bash
151163
PAGER=cat gh pr view --json number,url 2>/dev/null && echo "PR exists - skip creation" || echo "No PR - create one"
152164
```
153165

154-
## 13. Create PR (if needed)
166+
## 14. Create PR (if needed)
155167

156168
Skip if step 13 showed "PR exists".
157169

@@ -167,7 +179,7 @@ PAGER=cat gh pr create --base main \
167179
<steps to verify, or 'CI covers this'>"
168180
```
169181

170-
## 14. Verify
182+
## 15. Verify
171183

172184
```bash
173185
PAGER=cat gh pr view --json url,title -q '"PR: \(.title)\nURL: \(.url)"'

.github/CODEOWNERS

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66

77
# Release management and CI/CD
88
.github/ @ls1intum/hephaestus-maintainers
9-
.releaserc @ls1intum/hephaestus-maintainers
9+
.changeset/ @ls1intum/hephaestus-maintainers
10+
CHANGELOG.md @ls1intum/hephaestus-maintainers
11+
commitlint.config.mjs @ls1intum/hephaestus-maintainers
1012
renovate.json @ls1intum/hephaestus-maintainers
1113

1214
# Application Server (Java/Spring)

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
TITLE FORMAT (required):
33
<type>(<scope>): <description>
44
5-
Types: feat | fix | docs | refactor | test | ci | perf | revert
6-
Scopes (Service): webapp | server | ai | docs
7-
Scopes (Infra - NO RELEASE): ci | config | deps | deps-dev | docker | scripts | security | db | no-release
8-
Scopes (Feature): integration | scm | leaderboard | mentor | notifications | profile | teams | workspace
5+
Types: feat | fix | docs | style | refactor | perf | test | build | ci | chore | revert
6+
Scopes (Service): webapp | server | docs
7+
Scopes (Infra): ci | config | deps | deps-dev | docker | scripts | security | db | release
8+
Scopes (Feature): auth | integration | scm | leaderboard | mentor | notifications | profile | teams | workspace
99
10-
Breaking: Add ! before colon (feat!: or feat(scope)!:)
10+
Breaking changes: carried by the changeset (pre-1.0 = minor + MIGRATION.md), not the title.
1111
1212
✓ Good: feat(leaderboard): add weekly ranking filter
13-
✓ Good (No Release): fix(ci): update workflow configuration
13+
✓ Good: fix(ci): update workflow configuration
1414
✗ Bad: Added weekly ranking filter to leaderboard
1515
1616
BEFORE PUSHING:
@@ -34,6 +34,13 @@ Fixes # <!-- Link issue if applicable, or delete this line -->
3434

3535
<!-- Manual steps to verify, OR "CI covers this" for config/docs changes. -->
3636

37+
## Checklist
38+
39+
<!-- Only what CI can't check for you. Changeset presence is enforced by `verify-changesets`. -->
40+
41+
- [ ] My changeset summary reads as an operator/user-facing note (it becomes the changelog entry) — see `.changeset/README.md`
42+
- [ ] If the operator must act on this change (new required env var, manual migration step), the changeset summary says how (`**Operators:** …`) and `MIGRATION.md` is updated
43+
3744
## Screenshots
3845

3946
<!-- For UI changes. Delete section if not applicable. -->

.github/labeler.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
# Auto-labeler configuration for PRs
2-
# Labels assigned here are used by .github/release.yml for categorized release notes
1+
# Auto-labeler configuration for PRs (triage only — release notes come from
2+
# changesets, not labels; see docs/contributor/release-management.mdx)
33

44
documentation:
55
- changed-files:

.github/prompts/land-pr.prompt.md

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,19 @@ pnpm run check
9898

9999
Both must pass.
100100

101-
## 9. Create Branch (if on main)
101+
## 9. Changeset (required for shipped-code changes)
102+
103+
If this PR changes `server/`, `webapp/`, or `docker/`, it must carry a changeset or CI (`verify-changesets`) fails:
104+
105+
```bash
106+
pnpm changeset # user-facing change: pick the bump, describe it for operators
107+
pnpm changeset --empty # no user-facing effect (refactor/test/docs-only)
108+
```
109+
110+
Pre-1.0: never pick `major`. Stage the generated `.changeset/*.md` before committing. `pnpm changeset` is
111+
interactive — with no TTY, write `.changeset/<slug>.md` by hand (`.changeset/README.md` shows the format).
112+
113+
## 10. Create Branch (if on main)
102114

103115
```bash
104116
git branch --show-current
@@ -112,7 +124,7 @@ git checkout -b <type>/<description>
112124

113125
Types: `feat`, `fix`, `docs`, `refactor`, `test`, `ci`, `chore`
114126

115-
## 10. Commit
127+
## 11. Commit
116128

117129
```bash
118130
git add -A
@@ -122,22 +134,22 @@ git commit -m "<type>(<scope>): <description>"
122134
**Scopes:**
123135

124136
- Service: `webapp`, `server`, `docs`
125-
- Infra (no release): `ci`, `config`, `deps`, `deps-dev`, `docker`, `scripts`, `security`, `db`, `no-release`
126-
- Feature: `integration`, `scm`, `leaderboard`, `mentor`, `notifications`, `profile`, `teams`, `workspace`
137+
- Infra: `ci`, `config`, `deps`, `deps-dev`, `docker`, `scripts`, `security`, `db`, `release`
138+
- Feature: `auth`, `integration`, `scm`, `leaderboard`, `mentor`, `notifications`, `profile`, `teams`, `workspace`
127139

128-
## 11. Push
140+
## 12. Push
129141

130142
```bash
131143
git push -u origin HEAD
132144
```
133145

134-
## 12. Check if PR Exists
146+
## 13. Check if PR Exists
135147

136148
```bash
137149
PAGER=cat gh pr view --json number,url 2>/dev/null && echo "PR exists - skip creation" || echo "No PR - create one"
138150
```
139151

140-
## 13. Create PR (if needed)
152+
## 14. Create PR (if needed)
141153

142154
Skip if step 13 showed "PR exists".
143155

@@ -153,7 +165,7 @@ PAGER=cat gh pr create --base main \
153165
<steps to verify, or 'CI covers this'>"
154166
```
155167

156-
## 14. Verify
168+
## 15. Verify
157169

158170
```bash
159171
PAGER=cat gh pr view --json url,title -q '"PR: \(.title)\nURL: \(.url)"'

.github/release.yml

Lines changed: 0 additions & 63 deletions
This file was deleted.

0 commit comments

Comments
 (0)