mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
`release:notes:blog` used to emit the notes as a type-grouped inventory with area prefixes and the highlight sections buried after the feature list; the v0.23 post shipped in exactly that form and had to be restructured after publication. The scaffold now starts from the shape the posts end up in: a "What changed" table with one row per highlight, one `##` section per highlight ahead of everything else, breaking changes on their own, the remaining features folded into reader-facing themed sections instead of conventional-commit scopes, Performance, every remaining fix under a Spoiler grouped by theme, and the before-updating alert, Thanks and Download cards (including the compare link to the previous version). Only the components a post uses are imported. The blog renderer moves to `release-notes-blog.mjs`; `release-notes-render.mjs` keeps the GitHub/CHANGELOG renderers and exports the shared text helpers. Editorial work stays editorial and is marked with TODOs: which fixes deserve promotion out of the spoiler, one-line bullets, lead-ins, intro and thanks. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
172 lines
8.3 KiB
Markdown
172 lines
8.3 KiB
Markdown
# Release notes (`.changes/`)
|
||
|
||
Every PR with a user-visible change drops one file here describing that change
|
||
in plain language. At release time
|
||
`tools/release/build-release-notes.mjs` turns the accumulated files into the
|
||
GitHub release body, the `CHANGELOG.md` section, a blog-post scaffold for
|
||
the website, and Telegram/Reddit announcement drafts — then deletes them.
|
||
|
||
The point is to write the note **while the context is still fresh**, instead of
|
||
reconstructing three months of work from commit titles at release time.
|
||
|
||
## File
|
||
|
||
Name it `<area>-<short-slug>.md`, e.g. `.changes/playback-up-next-rail.md`.
|
||
|
||
```markdown
|
||
---
|
||
type: feature
|
||
area: playback
|
||
issues: [1187]
|
||
screenshot: up-next-rail
|
||
highlight: Up Next rail
|
||
---
|
||
|
||
Series now show an "Up Next" rail beside the player on wide windows: the rest
|
||
of the current season, watch progress, and click-to-play inline.
|
||
```
|
||
|
||
| Field | Required | Value |
|
||
| ------------ | -------- | ----------------------------------------------------------- |
|
||
| `type` | yes | `breaking`, `feature`, `fix`, `perf`, or `internal` |
|
||
| `area` | yes | lowercase slug, same as the conventional-commit scope |
|
||
| `issues` | no | issue numbers this closes — `[1187]` or `1187` |
|
||
| `screenshot` | no | slug from `tools/release/screenshots.manifest.json` |
|
||
| `highlight` | no | short headline (max 60 chars) marking a release highlight |
|
||
|
||
There is **no version field**. The release version is chosen deliberately at
|
||
release time, not derived from these files.
|
||
|
||
You never write a PR number: the generator resolves it from the commit that
|
||
added the file.
|
||
|
||
## Writing the body
|
||
|
||
One to three sentences, present tense, **written for a user, not a reviewer**.
|
||
The body is capped at 400 characters — depth belongs in the blog post.
|
||
|
||
- ❌ "Refactor `WebVideoControlsAdapter` to hoist volume state into the session"
|
||
- ✅ "The player now remembers volume between episodes"
|
||
|
||
- ❌ "Fix off-by-one in `resolveEnrichmentSeasonNumber`"
|
||
- ✅ "Series whose title carries a season marker no longer show the wrong season"
|
||
|
||
`highlight` marks the change as one of the release's headline features and
|
||
gives it a short, poster-worthy name. The 60-character cap keeps it roughly to
|
||
one line on the hero card; card text wraps by estimated width, so a headline of
|
||
unusually wide glyphs may still wrap or ellipsize rather than overflow. Highlights lead the Telegram/Reddit
|
||
announcements (everything else collapses into a "+N more" counter) and open the
|
||
blog scaffold: a row in its "What changed" table and a `##` section ahead of
|
||
the themed sections, while fixes without a highlight collapse under a spoiler
|
||
there. Set it on the two or three
|
||
changes worth announcing — a release where everything is a highlight has none.
|
||
Not allowed on `type: internal`.
|
||
|
||
`type: internal` records invisible maintenance. Internal notes stay collapsed in
|
||
`CHANGELOG.md`, are omitted from the blog scaffold, and are removed from the
|
||
authored public GitHub body by
|
||
`extract-changelog-section.mjs --public`. GitHub's generated commit list remains
|
||
separate. An internal-only release can therefore have an empty authored body.
|
||
|
||
## When a note is not needed
|
||
|
||
The gate auto-exempts website, E2E and mock-server apps, `*.spec.{js,ts}`,
|
||
`*.e2e.{js,ts}`, snapshots, any `/testing/` path, and Markdown. For other
|
||
test-only, documentation, CI/workflow, or pure-refactor changes under
|
||
`apps/`/`libs/`, apply `no-release-note` when no user-visible note is warranted.
|
||
|
||
## Commands
|
||
|
||
```bash
|
||
pnpm run release:notes:validate
|
||
pnpm run release:notes:github
|
||
pnpm run release:notes:changelog
|
||
pnpm run release:notes:blog
|
||
pnpm --silent run release:notes:telegram
|
||
pnpm --silent run release:notes:reddit
|
||
node tools/release/build-release-notes.mjs --consume
|
||
```
|
||
|
||
The release version comes from the root `package.json` — bump it first, then
|
||
generate. `--version 0.24.0` overrides it to preview a release before the bump:
|
||
|
||
```bash
|
||
pnpm run release:notes:github --version 0.24.0
|
||
```
|
||
|
||
A bare `--` separator is accepted and ignored, so the npm habit of
|
||
`pnpm run release:notes:github -- --version 0.24.0` works too: pnpm forwards
|
||
that separator to the script rather than consuming it the way npm does.
|
||
|
||
`--validate`, `--format github`, `--format telegram`, and `--format reddit`
|
||
only read and print. `--format changelog` and `--format blog` write their
|
||
target file (rerunning `changelog` for the same version replaces that section
|
||
rather than duplicating it). Only `--consume` deletes anything.
|
||
|
||
The announcement formats print paste-ready posts to stdout, each guaranteed
|
||
to fit its platform's limit: Telegram plain text within 4096 characters,
|
||
Reddit markdown within 40,000, with a suggested post title on the first line.
|
||
Whatever does not fit collapses into a counter; a breaking change is never
|
||
collapsed, and if the highlights alone will not fit, the render fails with an
|
||
actionable error rather than shipping a post that cannot be submitted. Use `pnpm --silent run` for these two —
|
||
plain `pnpm run` prints its lifecycle banner to the same stdout, so a
|
||
redirected post starts with two lines of build noise. Render and save them
|
||
**before**
|
||
`--consume` — the changelog keeps the entries, but the `highlight:` metadata
|
||
lives only in the note files. Publishing is manual; nothing posts anywhere.
|
||
An internal-only release has nothing to announce: both formats then print an
|
||
explanation on stderr, leave stdout empty, and exit 0 — the same shape
|
||
`extract-changelog-section.mjs --public` uses for its empty public body.
|
||
|
||
The release sequence is: bump the version → `release:notes:changelog` →
|
||
`release:notes:blog` → `release:screenshots` → `release:notes:telegram` /
|
||
`release:notes:reddit` → `release:cards:generate` → `--consume` → commit → tag
|
||
→ push → `release:verify:draft`. Everything reading `highlight:` comes before
|
||
`--consume`, because that step deletes the only copy of it. Full contract:
|
||
`docs/architecture/release-pipeline.md`. The tag build then
|
||
extracts the new `CHANGELOG.md` section into the GitHub release body
|
||
(`tools/release/extract-changelog-section.mjs`) and **fails the release** if
|
||
the section is missing — a tag cut without the changelog step cannot silently
|
||
ship PR-title-only notes.
|
||
|
||
The website publishes **one post per minor version** (`v0-18` … `v0-22`), and
|
||
release screenshots live under the matching `blog/v0-24/` directory. A patch
|
||
release therefore edits the existing post rather than generating a new one, so
|
||
`--format blog` refuses to overwrite unless you pass `--force`.
|
||
|
||
## Screenshots
|
||
|
||
`pnpm run release:screenshots` captures every manifest shot in dark and light
|
||
against the built app plus the Xtream mock server — never a real account.
|
||
The run is fail-closed: it proves the real `~/.iptvnator/databases` directory
|
||
(including the SQLite WAL sidecars, checked after Electron exits) was not
|
||
touched, launches the app with an allowlisted environment, records and blocks
|
||
all non-localhost traffic, scans every frame for external resources and
|
||
credential-shaped text, and asserts TMDB enrichment stays disabled. Frames are
|
||
staged outside the repository and published only once every shot and every
|
||
guard has passed.
|
||
|
||
Adding a shot for a new feature = one entry in
|
||
`tools/release/screenshots.manifest.json` (plus, if navigation is new, one
|
||
named action in `tools/release/capture-navigation.ts`).
|
||
|
||
## Highlight cards
|
||
|
||
`pnpm run release:cards:generate` renders one branded 1200×630 card per
|
||
`highlight:` note (headline, body, and a framed screenshot strip when the note
|
||
names one) plus a release hero card — for Telegram/Reddit previews and the
|
||
blog `hero.jpg`. It reads screenshots from the published blog directory, so it
|
||
runs after `release:screenshots` and, like the announcement formats, before
|
||
`--consume`. Output goes to `dist/release-highlight-cards/v<version>/`, and a
|
||
rerun replaces the cards it previously wrote there; copying a card into the
|
||
website tree is a deliberate manual act. `release:cards:dry-run` lists what
|
||
would be rendered. A release without highlights still gets its hero card, and
|
||
an internal-only release writes nothing — neither is an error.
|
||
|
||
```bash
|
||
pnpm nx run electron-backend:build-e2e # once, before capturing
|
||
pnpm run release:screenshots # all shots, both themes
|
||
pnpm run release:screenshots -- --only dashboard --theme dark
|
||
pnpm run release:screenshots -- --release v0-24
|
||
```
|