Skip to content

Commit 2887b9e

Browse files
chore: adopt Changesets for release-note generation (#690)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 53f3e8d commit 2887b9e

17 files changed

Lines changed: 781 additions & 22 deletions

File tree

.changeset/config.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"$schema": "https://unpkg.com/@changesets/config@3.1.4/schema.json",
3+
"changelog": ["@changesets/changelog-github", { "repo": "ls1intum/Apollon" }],
4+
"access": "public",
5+
"baseBranch": "main",
6+
"fixed": [["@tumaet/webapp", "@tumaet/server"]],
7+
"updateInternalDependencies": "patch",
8+
"privatePackages": { "version": true, "tag": false },
9+
"ignore": [
10+
"@tumaet/apollon-docs",
11+
"apollon-vscode",
12+
"apollon-vscode-menu",
13+
"apollon-vscode-editor"
14+
]
15+
}

.github/pull_request_template.md

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,25 @@
1-
<!-- Thanks for contributing to Apollon! Before you submit your pull request, please make sure to check the following boxes by putting an x in the [ ] (don't: [x ], [ x], do: [x]) -->
2-
<!-- If your pull request is not ready for review yet, create a draft pull request! -->
1+
<!-- PR title = Conventional Commit subject. Squash-merge: title + body become the commit. Run `pnpm changeset` if you change a Changesets-tracked package (@tumaet/apollon, @tumaet/webapp, @tumaet/server). See CONTRIBUTING.md. -->
32

4-
### Checklist
5-
6-
- [ ] I linked PR with a related issue
7-
- [ ] I added multiple screenshots/screencasts of my UI changes
3+
### Summary
84

9-
### Motivation and Context
5+
<!-- What changed and why, for the reviewer. The user-facing wording lives in the changeset body. -->
106

11-
<!-- Why is this change required? What problem does it solve? -->
12-
<!-- If it fixes an open issue, please link to the issue here. -->
7+
### Implementation notes
138

14-
This PR completes https://github.com/ls1intum/Apollon/issues/xx
9+
<!-- Approach, trade-offs, alternatives considered, follow-ups. -->
1510

16-
### Description
11+
### Steps for testing
1712

18-
<!-- Describe your changes in detail -->
13+
1.
1914

20-
### Steps for Testing
15+
### Screenshots / screencasts
2116

22-
<!-- Please describe in detail how the reviewer can test your changes. -->
17+
<!-- Required for UI changes. -->
2318

24-
1. ...
25-
26-
### Screenshots
19+
### Checklist
2720

28-
<!-- Add screenshots to demonstrate the changes in the UI. -->
29-
<!-- Create a GIF file from a screen recording in a docker container https://toub.es/2017/09/11/high-quality-gif-with-ffmpeg-and-docker/ -->
21+
- [ ] Linked to a related issue (if applicable)
22+
- [ ] Added a changeset (`pnpm changeset`, [how](https://ls1intum.github.io/Apollon/contributor/development/release-notes/)), or this PR doesn't touch a Changesets-tracked package (`@tumaet/apollon`, `@tumaet/webapp`, `@tumaet/server`)
23+
- [ ] Tests added or updated
24+
- [ ] Documentation updated (if applicable)
25+
- [ ] Screenshots or screencasts attached (if a UI change)

.github/workflows/pr-title.yml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: PR title
2+
3+
# The PR title becomes the squash-merge commit subject, so it must pass the
4+
# same commitlint rules as a commit message. Runs on pull_request_target so it
5+
# can post a sticky comment on fork PRs; it never checks out PR-head code and
6+
# reads the title only through an env var (never interpolated into a shell).
7+
8+
on:
9+
pull_request_target:
10+
types: [opened, edited, reopened, ready_for_review]
11+
12+
permissions:
13+
contents: read
14+
pull-requests: write
15+
16+
concurrency:
17+
group: pr-title-${{ github.event.pull_request.number }}
18+
cancel-in-progress: true
19+
20+
jobs:
21+
validate:
22+
name: Validate title
23+
runs-on: ubuntu-latest
24+
timeout-minutes: 10
25+
if: ${{ !github.event.pull_request.draft }}
26+
steps:
27+
# Default ref is the base branch (trusted), not PR head.
28+
# commitlint.config.mjs is the single source of truth for types + scopes.
29+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
30+
- uses: pnpm/action-setup@ac6db6d3c1f721f886538a378a2d73e85697340a # v6.0.8
31+
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
32+
with:
33+
node-version-file: .nvmrc
34+
cache: pnpm
35+
- run: pnpm install --frozen-lockfile
36+
37+
- id: commitlint
38+
continue-on-error: true
39+
env:
40+
PR_TITLE: ${{ github.event.pull_request.title }}
41+
run: printf '%s' "$PR_TITLE" | pnpm exec commitlint
42+
43+
- uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2.9.4
44+
if: steps.commitlint.outcome == 'failure'
45+
with:
46+
header: pr-title-lint-error
47+
message: |
48+
## ❌ PR title is not a valid Conventional Commit
49+
50+
Expected `<type>(<scope>)?: <subject>`, where `type` is one of `feat | fix | chore | docs | refactor | test | build | ci | perf | style | revert` and `scope` comes from the list in `commitlint.config.mjs`. See [`CONTRIBUTING.md`](https://github.com/ls1intum/Apollon/blob/main/CONTRIBUTING.md).
51+
52+
- uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2.9.4
53+
if: steps.commitlint.outcome == 'success'
54+
with:
55+
header: pr-title-lint-error
56+
delete: true
57+
58+
- if: steps.commitlint.outcome == 'failure'
59+
run: exit 1
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: Verify changesets
2+
3+
# Advisory only: reminds authors when a user-visible change ships without a
4+
# changeset. It never blocks merge — a maintainer can always add the changeset
5+
# in a follow-up, and docs-/CI-/refactor-only PRs legitimately have none.
6+
7+
on:
8+
pull_request:
9+
types: [opened, synchronize, reopened]
10+
branches: [main]
11+
12+
permissions:
13+
contents: read
14+
15+
concurrency:
16+
group: verify-changesets-${{ github.event.pull_request.number }}
17+
cancel-in-progress: true
18+
19+
jobs:
20+
status:
21+
runs-on: ubuntu-latest
22+
timeout-minutes: 10
23+
# Forks can't fetch origin/<base> for the diff; skip rather than fail.
24+
if: github.event.pull_request.head.repo.full_name == github.repository
25+
steps:
26+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
27+
with:
28+
fetch-depth: 0
29+
- uses: pnpm/action-setup@ac6db6d3c1f721f886538a378a2d73e85697340a # v6.0.8
30+
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
31+
with:
32+
node-version-file: .nvmrc
33+
cache: pnpm
34+
- run: pnpm install --frozen-lockfile
35+
36+
- name: Changesets status (advisory)
37+
# Surface the result in the job summary — base.ref via env, never
38+
# interpolated into the shell. changeset writes the "no changesets
39+
# were found" reminder to stderr, so fold stderr in and keep the
40+
# pipeline's real exit code with pipefail.
41+
env:
42+
BASE_REF: ${{ github.event.pull_request.base.ref }}
43+
run: |
44+
set -o pipefail
45+
pnpm exec changeset status --since="origin/$BASE_REF" 2>&1 | tee -a "$GITHUB_STEP_SUMMARY"
46+
continue-on-error: true

AGENTS.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Apollon agent conventions
2+
3+
Conventions for AI coding agents in this repo, the TUM UML diagram editor. Follows the [agents.md](https://agents.md) convention; `CLAUDE.md` is a symlink to this file. Versions and engines live in the manifests — read them, don't trust a number written here.
4+
5+
## Commands
6+
7+
- `pnpm install` to bootstrap; `pnpm dev` runs the full stack (library watch + server + webapp, and spins up Redis in Docker).
8+
- After editing, run the relevant check and iterate until green. Before a PR this gate must pass: `pnpm lint && pnpm format:check && pnpm build && pnpm test`.
9+
- `pnpm test` runs the **library** suite only; `pnpm test:e2e` runs Playwright against a _built_ webapp.
10+
- `pnpm changeset` records a release note (see PRs and releases). Full script reference: [`scripts.md`](docs/contributor/development/scripts.md).
11+
12+
## Layout
13+
14+
A pnpm + Vite monorepo (the server compiles with `tsc`, not Vite).
15+
16+
- **`library/`**`@tumaet/apollon`, the embeddable React editor, published to npm. MUI + `@emotion/react`; Yjs collaboration — the live-cursor/presence layer lives here ([`collaboration.md`](docs/library/api/collaboration.md)).
17+
- **`standalone/webapp/`**`@tumaet/webapp` (private). React + Vite + Tailwind; Capacitor for iOS/Android.
18+
- **`standalone/server/`**`@tumaet/server` (private). Express + Redis Stack (RedisJSON diagram storage + version history).
19+
- **`vscode-extension/`**`apollon-vscode`, with nested `menu/` and `editor/` webview sub-packages.
20+
- **`docs/`**`@tumaet/apollon-docs` (private), the Docusaurus site (`user/` · `library/` · `contributor/`).
21+
- **`ops/`** — runbooks and legal/DSMS material; not part of any release.
22+
23+
`@tumaet/apollon` is consumed via `workspace:*` by every other workspace, so a library change can ripple everywhere. `standalone/webapp` + `standalone/server` are paired in `.changeset/config.json#fixed` and release together. The `library/` workspace targets an older Node floor than the repo (it ships to external consumers) — check `library/package.json` before using newer Node APIs.
24+
25+
## Conventions
26+
27+
- **Prettier is authoritative:** no semicolons, double quotes (`.prettierrc`). **ESLint** flat config lives in `library/`, `standalone/{webapp,server}/`, and `vscode-extension/`.
28+
- **Styling boundary:** MUI + `@emotion/react` in `library/`; Tailwind only in `standalone/webapp/`. Don't cross them.
29+
- **Shared dependency versions** go through the pnpm `catalog:` in `pnpm-workspace.yaml` — write `"catalog:"`, never duplicate a version string.
30+
- **Tests** live in `library/tests/unit/` and `standalone/webapp/tests/` (unit, visual, e2e).
31+
- **Conventional Commits** with a constrained scope set — `commitlint.config.mjs` is the source of truth.
32+
33+
## PRs and releases
34+
35+
- **Squash-merge only** — the PR title becomes the merge commit subject and must be a valid Conventional Commit (enforced in CI by [`pr-title.yml`](.github/workflows/pr-title.yml)).
36+
- **Changesets** carry release notes. Run `pnpm changeset` when you change `@tumaet/apollon`, `@tumaet/webapp`, or `@tumaet/server`. Skip docs-/CI-/refactor-only PRs and the VS Code extension (separate release; excluded in `.changeset/config.json`). Writing rules: [`release-notes.md`](docs/contributor/development/release-notes.md).
37+
38+
## Gotchas / do not
39+
40+
- The library is consumed by the standalone app, the VS Code extension, and external embedders — don't couple its APIs to standalone-only assumptions; gate behind options.
41+
- The server requires `OWNER_SECRET` ≥ 32 chars in production (`openssl rand -hex 32`); local dev accepts a placeholder.
42+
- Never commit build output (`library/dist/`, `standalone/webapp/dist/`, …).
43+
- Don't hand-edit the `.changeset/*.md` entries the changelog automation will consume — create them with `pnpm changeset`.
44+
- Don't put co-authored-by / agent-attribution trailers in a changeset body — it lands in `CHANGELOG.md` verbatim.
45+
- `CLAUDE.md` is a checked-in symlink to this file (git mode `120000`); on Windows, enable symlinks (`git config --global core.symlinks true`) or it checks out as plain text.
46+
47+
## Deeper docs
48+
49+
- Contributing: [`CONTRIBUTING.md`](CONTRIBUTING.md)
50+
- Project structure: [`docs/contributor/development/project-structure.md`](docs/contributor/development/project-structure.md)
51+
- Deployment + ops: [`docs/contributor/deployment/github-actions.md`](docs/contributor/deployment/github-actions.md), [`ops/operations.md`](ops/operations.md)
52+
- Mobile: [`docs/contributor/development/mobile-builds.md`](docs/contributor/development/mobile-builds.md)

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
AGENTS.md

CONTRIBUTING.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@ pnpm run build
2323
pnpm test
2424
```
2525

26-
Commits follow [Conventional Commits](https://www.conventionalcommits.org/) with a constrained scope set — see `commitlint.config.mjs`.
26+
Commits follow [Conventional Commits](https://www.conventionalcommits.org/) with a constrained scope set — see `commitlint.config.mjs`. The repository is **squash-merge only**, so your PR title is the merge commit subject and is checked against the same rules.
27+
28+
On any PR that changes a Changesets-tracked package — `@tumaet/apollon`, `@tumaet/webapp`, or `@tumaet/server` — add a changeset:
29+
30+
```sh
31+
pnpm changeset
32+
```
33+
34+
It becomes the changelog entry — writing rules are in the [release-notes guide](https://ls1intum.github.io/Apollon/contributor/development/release-notes/). Skip it on docs-, CI-, or refactor-only PRs, and on the VS Code extension (it has a separate release flow and is excluded in `.changeset/config.json`).
35+
36+
AI coding agents (Claude Code, Cursor, Copilot, Codex, …) follow [`AGENTS.md`](./AGENTS.md).
2737

2838
By participating in this project you agree to abide by its [Code of Conduct](./CODE_OF_CONDUCT.md).

docs/contributor/deployment/npm-publishing.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ Standalone starts at `4.2.18` (the library version at the time of the release-pi
1818

1919
All three workflows trigger automatically when their version changes on `main`. There is **one** manual step per release: merge the bump PR.
2020

21+
The per-PR side of this is [Changesets](https://github.com/changesets/changesets): authors run `pnpm changeset` on every user-visible PR to record a changelog entry (see [Release notes](/contributor/development/release-notes)). Those entries are what the changelog automation will consume when it replaces the manual version bump.
22+
2123
The `library` bump also rewrites the pinned `@tumaet/apollon@X.Y.Z` CDN URLs in the README and docs (via `scripts/sync-library-version.mjs`) so the published examples never lag the package version. PR Health Checks run the same script with `--check`, so a drift can never merge — run `pnpm sync:version` locally to fix one.
2224

2325
## Cut a release
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
---
2+
id: release-notes
3+
title: Release notes
4+
description: How to write the changeset that becomes a changelog entry — voice, bump type, worked examples.
5+
---
6+
7+
# Release-notes style guide
8+
9+
User-facing release notes come from [Changesets](https://github.com/changesets/changesets). One changeset per user-visible PR; its summary becomes the changelog entry verbatim.
10+
11+
Three release lines carry changesets: `@tumaet/apollon` on npm, and `@tumaet/webapp` + `@tumaet/server` as paired `ghcr.io` Docker images. The VS Code extension, the docs site, and the webview sub-packages are excluded in `.changeset/config.json#ignore` — they have their own (or no) release flow, and without the exclusion a routine library bump would version them too, since every package depends on `@tumaet/apollon` via `workspace:*`.
12+
13+
:::note
14+
Changesets are the per-PR convention now; the pipeline that consumes them (`changeset version``CHANGELOG.md` → release) lands in a follow-up. Until then, write the changeset so the backlog is ready — and note that the existing `CHANGELOG.md` files are hand-maintained, since the tool does not yet regenerate them. See [Releases](/contributor/deployment/npm-publishing).
15+
:::
16+
17+
## When do you need one?
18+
19+
Add a changeset whenever a **user, embedder, or operator would notice** a change to `@tumaet/apollon`, `@tumaet/webapp`, or `@tumaet/server` — a new feature, a bug fix, a changed API, or a new deployment step.
20+
21+
Skip it when nothing downstream is affected: docs, CI, tests, refactors, and formatting — plus anything touching only the VS Code extension or the docs site (both excluded above). When unsure, add one; an extra changelog line beats a silent gap. The advisory **Verify changesets** check on each PR reminds you.
22+
23+
## What you write per PR
24+
25+
```sh
26+
pnpm changeset
27+
```
28+
29+
Pick the packages and bump type when prompted; **the summary you type becomes the changelog entry, verbatim.** Edit `.changeset/<name>.md` afterwards and commit it with your PR.
30+
31+
## Writing the summary
32+
33+
**Write for the user, not the engineer.** Lead with what the user can now do (or, for fixes, the symptom they would have seen). Implementation language — internal types, hook names, file paths — stays in the PR description.
34+
35+
| Don't | Do |
36+
| --------------------------------------------------------------- | ----------------------------------------------------------------- |
37+
| `add useExportAsPPTX hook with lazy-loaded pptxgenjs` | `Export diagrams as animatable PowerPoint slides.` |
38+
| `Reset isLoading on effect re-entry and thread AbortController` | `Sharing a diagram twice no longer leaves a blank canvas behind.` |
39+
40+
For an embedder-facing library change, name the API and describe the contract instead — see [Per-package conventions](#per-package-conventions) below.
41+
42+
For **breaking changes**, mark the changeset `major` and link a migration runbook — the GitHub Release body, or [`ops/operations.md`](https://github.com/ls1intum/Apollon/blob/main/ops/operations.md).
43+
44+
## Per-package conventions
45+
46+
| Package | Audience | Voice |
47+
| -------------------------------------------- | --------------------- | ----------------------------------------------------- |
48+
| `@tumaet/apollon` | embedders | name the API; describe the contract |
49+
| `@tumaet/webapp` + `@tumaet/server` (paired) | end users + operators | what the user can do; for operators, link the runbook |
50+
51+
## Picking the bump type
52+
53+
- **patch** — bug fixes, internal-only changes consumers adopt without code changes.
54+
- **minor** — new backwards-compatible functionality (new options, exports, optional behaviour).
55+
- **major** — breaks an existing caller, deployment, or storage layout. Must link a migration runbook.
56+
57+
## Worked examples
58+
59+
A standalone-only fix (`#683`, in v4.4.1):
60+
61+
```markdown
62+
---
63+
"@tumaet/webapp": patch
64+
---
65+
66+
Sharing a diagram a second time, or starting a new diagram during a collaboration session, no longer leaves a blank canvas behind.
67+
```
68+
69+
A library API addition (`#657`, in v4.4.0):
70+
71+
```markdown
72+
---
73+
"@tumaet/apollon": minor
74+
---
75+
76+
Adds editor primitives for hosting a version-history UX on top of the live Yjs document — preview mode, programmatic readonly, fit-to-view, and full-state broadcast.
77+
```
78+
79+
A change that spans the webapp and the library lands as two changesets in the same PR — one per audience, each in its track's voice.
80+
81+
## CHANGELOG.md and the GitHub Release body
82+
83+
`CHANGELOG.md` is the per-version bullet log Changesets writes; once the consuming pipeline lands it is tool-owned, not edited by hand. The **GitHub Release body** carries the human-curated lede and highlights (screenshots, video).
84+
85+
You write only the changeset body (the markdown after the frontmatter). At `changeset version` time, `@changesets/changelog-github` prepends the PR link, commit link, and `Thanks @author!` automatically. The backfilled v4.4.0 / v4.4.1 entries omit the commit-SHA link — those commits predate Changesets; new releases include it.

docs/contributor/development/scripts.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,12 @@ release by dispatching the **Version Bump** workflow and merging the PR it
123123
opens; see [npm publishing](/contributor/deployment/npm-publishing).
124124
`pnpm package:vscode` builds a local `.vsix` for the VS Code extension.
125125

126+
| Script | Does |
127+
| ---------------- | ---------------------------------------------- |
128+
| `pnpm changeset` | Record a changelog entry for a user-visible PR |
129+
130+
Writing rules: [Release notes](/contributor/development/release-notes).
131+
126132
## Before opening a PR
127133

128134
The pull-request checklist (lint, format check, build, test) lives in the

0 commit comments

Comments
 (0)