Skip to content

Release/changelog automation: auto PR breakdown + AppChangelog generator - #10

Merged
ryanbr merged 2 commits into
mainfrom
snapshot-v8.2.2
Jul 7, 2026
Merged

ryanbr merged 2 commits into
mainfrom
snapshot-v8.2.2

Conversation

@ryanbr

@ryanbr ryanbr commented Jul 7, 2026

Copy link
Copy Markdown
Owner

What

Release-notes + changelog automation:

  • 12420187 — the release workflow appends GitHub's auto "What's Changed" PR breakdown (merged PRs since the previous release + New Contributors + compare link) below the curated docs/releases notes. Skipped on the first release (no prior tag); uses the generate-notes API diffed from the most recent non-prerelease.
  • 9e372720 — automate the in-app "What's New": Tools/appchangelog-gen.py generates the AppChangelog entry into both Kotlin + Swift from a whatsnew: front-matter block in docs/releases/v<VER>.md, and bumps CURRENT_VERSION. The workflow strips that front-matter from the GitHub body. Also brings the in-app changelog current (added the 8.2.2 entry; it was stuck at 7.9.0).

Verification

Android compileFullDebugKotlin BUILD SUCCESSFUL; the generator is idempotent and produces byte-parallel entries on both platforms; front-matter strip verified both ways. The AppChangelog.swift entry is validated by the CI iOS + macOS build jobs.

ryanbr added 2 commits July 7, 2026 16:19
…to the notes

Each release's GitHub body is now: the curated docs/releases/<TAG>.md notes + GitHub's
auto-generated "What's Changed" breakdown (every merged PR since the previous RELEASE, with
authors/links + New Contributors + full-changelog compare link) + the downloads footer.

Uses the generate-notes REST API (deterministic; not dependent on gh flag-combining) diffed from
the most recent NON-prerelease release (so testing-latest snapshots are ignored). Skipped on the
very first release (no prior tag would diff to repo start). Best-effort — a failure is ignored.
Verified: the API returns the PR list (#1..#9); first-release PREV detection returns empty as expected.
…eases front-matter

The in-app What's New (AppChangelog) was two hand-edits kept byte-identical across Kotlin + Swift,
plus a manual CURRENT_VERSION bump. Now a single source drives it:

- docs/releases/v<VER>.md can carry a `whatsnew:` YAML front-matter block (title, date, items) — the
  curated in-app copy — above the full GitHub release notes.
- Tools/appchangelog-gen.py reads it and prepends the generated Release entry to BOTH AppChangelog.kt
  and AppChangelog.swift (per-language escaping, so parity is guaranteed since both come from one
  source) and bumps CURRENT_VERSION/currentVersion. Idempotent (re-run only refreshes the constant).
- fork-release.yml strips the front-matter when using docs/releases/<TAG>.md as the GitHub release body,
  so the yaml never leaks into the release notes (files without front-matter pass through unchanged).

Also brings the in-app changelog current: added the v8.2.2 entry (it was stuck at 7.9.0) by running
the generator. Verified: Android compiles, entries are byte-parallel on both platforms, idempotent
re-run keeps one entry, and the GitHub-body strip is confirmed both ways.
@ryanbr
ryanbr merged commit 7e60b2b into main Jul 7, 2026
4 checks passed
DX23876 referenced this pull request in DX23876/noop Jul 22, 2026
Release/changelog automation: auto PR breakdown + AppChangelog generator
ryanbr added a commit that referenced this pull request Aug 21, 2026
"Duplicate as manual" is offered only on read-only rows - strap, Apple, lifting,
activity file - and the menu describes it as a copy path that leaves the original
alone. It did not.

The copy is built with source "manual" so the form treats it as editable, and the
sheet hands that pre-fill straight back as `replacing`. It claims to be a manual
row while carrying the ORIGINAL's natural key, so a save with a changed sport or
start reached three different consumers, each of which then acted on the original:

  - the store deleted the old key under the active strap id, where a
    strap-recorded session lives;
  - Apple's #10 GPS route re-key read the route under the original's key, stored
    it under the duplicate's, and REMOVED it from the original - the source
    session's map and distance vanish;
  - Android's Health Connect write-back deleted "noop-workout-<startTs>", which
    carries no deviceId at all, so the original's records went and a duplicate
    saved at a new start left them deleted with nothing to restore them.

Android already had a guard for exactly this - pass `replacing` only for a MANUAL
or DETECTED row - and it could never work, because it tested the copy's source
and the copy says "manual" by design. Apple had no guard.

Both platforms now carry the distinction where a row's source cannot express it:
an isCopy flag on the sheet target, and `replacing` nil for a duplicate. That
stops it reaching every consumer rather than making one consumer's key safe,
which is what the earlier namespace re-seed did (#1489) - sound for the store,
silent about everything downstream.

Health Connect write-back is opt-in, so that face only affected users who enabled
it. The route and store faces did not need it.

Android: 5 tests - a duplicate replaces nothing despite reading as manual, a real
manual edit and a detected bout still do, an imported row is still refused
without the flag, and a fresh add replaces nothing either way. Extracted as
WorkoutEditing.replacingRowFor so the decision is testable rather than sitting
inside a Composable. Apple compiled via app-build, both legs.

On hardware: duplicate a strap session, change its sport, confirm the original
keeps its route, its distance and its Health Connect record.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant