whats-new

command
v0.7.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 28, 2026 License: AGPL-3.0 Imports: 5 Imported by: 0

README

What's New feed

The Console landing page (#/console, the "Welcome to Atlas" view) shows a compact, collapsible What's New section: the newest user-facing features, in plain language, newest-first, each with a link to its PR/ADR and — where the UI is involved — a small step-by-step tutorial and a "Try it" deep link. It is bilingual (DE/EN) with a per-visitor toggle.

How it works

CHANGELOG.md ──┐
               ├─► go run ./scripts/whats-new ──► api/web/whats-new.json ──► app.js renderWhatsNew()
overrides/*.json ┘
  • CHANGELOG.md is the source of truth. The generator reads its version sections and Added / Changed / Fixed bullets and derives each entry's structure: a stable id (the title slug), the headline, the version/date, and a link to the ADR or PR the bullet names. New CHANGELOG entries appear automatically.
  • overrides/ adds the human polish. One file per entry, named <id>.json, supplying the layman-friendly, bilingual summary, tags, an optional tutorial, and an optional "Try it" route — none of which belong in the developer-facing CHANGELOG. It can also hidden: true a purely internal/API bullet so it stays out of the user list.
  • api/web/whats-new.json is generated and committed. It is served straight off the embedded FS (//go:embed web in api/server.go), so the web UI stays buildless (ADR-0012): the generator runs only at authoring time, never at runtime.
  • The generator is Go (scripts/whats-new, logic in feed/), and that is the whole of why (ADR-0375): the feed was the only reason go build, go vet, the race job and the docs job needed Node. Node stays where it is the technology — the browser end-to-end suite and the screenshot capture — and left the four places where it was incidental. The output is byte-for-byte what the script produced, which is not a nicety: CI regenerates the feed to check the commit is current, so anything else would fail that check on every run.

Adding or polishing an entry

  1. Write the change in CHANGELOG.md as usual.

  2. Run the generator once to see the derived id:

    go run ./scripts/whats-new   # or: make whats-new
    

    Look up the entry's id in api/web/whats-new.json.

  3. (Optional but recommended for anything a user should notice) add an override in overrides/<id>.json — copy the id, don't retype it. The id is the headline slugified and cut to 60 characters, so a hand-typed key is easy to get one character wrong, and a key that matches nothing is not an error the entry shows: it renders from the CHANGELOG's own wording, in English, in both languages. The generator refuses an unmatched key for exactly that reason (below). Every field is optional:

    The file is the entry — its name carries the id, so the object holds only fields:

    {
      "tags": ["Organization", "Secrets"],
      "summary": { "en": "…one or two plain sentences…", "de": "…dito auf Deutsch…" },
      "tutorial": { "en": ["Step 1", "Step 2"], "de": ["Schritt 1", "Schritt 2"] },
      "try": { "label": { "en": "Open Organization", "de": "Organisation öffnen" },
               "route": "#/console/org" },
      "hidden": false
    }
    
    • summary / title / try.label: either a { en, de } object or a bare string (used for both languages). de falls back to en.
    • try.route must start with a known hash route: #/console, #/modeler, #/operations, or #/tasks (the UI ignores anything else).
    • link: only needed to override the auto-derived PR/ADR link.
  4. Re-run make whats-new and commit the regenerated api/web/whats-new.json.

The only entries shown are the newest MaxEntries (see feed/feed.go) after hidden ones are dropped.

What keeps it honest

Nothing regenerates the feed at build or run time, so two checks stand in for that:

  • CI fails on a stale feed. The check job re-runs the generator and diffs api/web/whats-new.json; a CHANGELOG entry committed without re-running make whats-new turns the build red with the missing diff printed. This is why generatedAt is derived from the newest dated CHANGELOG section rather than the wall clock — a today-stamp would make every CI run differ from the commit.

  • The generator refuses an override key that matches no bullet. Such a key does nothing — the entry still renders, from the CHANGELOG headline, with German falling back to English — and that is indistinguishable from having written no override at all. Keys are curated by hand, so an unmatched one is always a typo or a headline that was reworded out from under it; the generator exits non-zero and names it.

  • api/whatsnew_test.go guards the committed JSON: valid, non-empty, required fields present, newest-first, and no summary that starts with punctuation (the signature of a generator parse artifact rather than real prose).

  • Git will not merge the feed for you (.gitattributes: -merge). Two branches that each add a changelog entry each regenerate the feed, and a textual merge of the two results is not a function of the merged CHANGELOG — it lands clean, silently wrong (an entry duplicated, or one past MAX_ENTRIES left in), and main goes red on its own push rather than on either branch. So the merge conflicts instead.

    The overrides used to have the same edge for a different reason: one JSON object, every branch adding its key at the top, and git interleaving two insertions into a single wrong entry. They are one file per entry now, so two branches adding two entries touch two files and merge cleanly. Two branches editing the same entry still conflict — in a small file, where that is the honest answer.

    If you hit that conflict, do not pick a side. Take the merged CHANGELOG.md, then:

    git checkout --ours api/web/whats-new.json   # any side; it is about to be overwritten
    make whats-new
    git add api/web/whats-new.json
    

    This covers merges git performs. GitHub's merge button ignores the attribute — the same merge that conflicts locally lands clean there — so it is not prevention.

  • .github/workflows/whats-new-sync.yml repairs main. On every push to main it regenerates the feed and pushes the correction if the committed one differs. That is the backstop for the merge-button path; it is not a licence to skip make whats-new on a branch, which still fails CI. Preventing the bad merge outright takes branch protection's "require branches to be up to date before merging" — a repository setting, not something a file in the tree can do.

Neither check can tell that an entry reads well, or that a user-facing change has an override at all. That part stays a human step — step 3 above.

The other thing a changelog bullet feeds

The Console landing page carries a second bilingual section below this one: the key features tile (api/web/key-features.json), which says what Atlas is rather than what changed. It is hand-written, not generated — but it reads the same source indirectly, through a reviewedThrough marker naming the newest ### Added bullet somebody has held against it. go test ./api fails while bullets sit above that marker, so a feature cannot land without the question being asked. Most bullets change nothing in the tile; moving the marker records that they were considered.

Documentation

Overview

Command whats-new regenerates the Console's "What's New" feed (api/web/whats-new.json) from CHANGELOG.md and the overrides beside it.

go run ./scripts/whats-new          (or: make whats-new)

The work is in the feed package next to it, so the guards can call it directly rather than shelling out to a process and parsing what it printed.

Directories

Path Synopsis
Package feed builds the Console's "What's New" feed from CHANGELOG.md and the curated overrides beside it.
Package feed builds the Console's "What's New" feed from CHANGELOG.md and the curated overrides beside it.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL