feat(APP-963): modular release system — design + modules - #5
Open
tyhonchik wants to merge 6 commits into
Open
Conversation
tyhonchik
force-pushed
the
app-963-study-and-design-the-modules-structure-to-release
branch
from
August 3, 2026 16:23
e4e9d5d to
f2322ed
Compare
…flows)
Design-first deliverable for APP-963: standardise releases across repos around the
Build → Test → Release → Deploy spine, with loadable modules in github-templates.
- docs/release-design.md: scenarios A–D, the 4-step spine, module catalog, the
explicit-paths credential model + security contract, distribution/versioning.
- steps/: composite actions (setup, compute-version[changesets|semantic-release],
slack-notify, extract-slack-ts, read-changelog, build-release-notes,
generate-release-summary, parse-playwright-results, gh-ensure-{pr,tag,release},
git-ensure-branch). Scripts co-located + referenced via $GITHUB_ACTION_PATH so the
actions are self-contained across repos; generateReleaseSummary genericised (no
hardcoded repo).
- .github/workflows/: reusable workflows (release-start, release-finalize,
deploy-vercel, deploy-docker, e2e, release-self). VERCEL_TOKEN resolved only inside
deploy-vercel. op:// inputs validated; no secrets: inherit; third-party actions
SHA-pinned.
- examples/: per-scenario caller workflows. .github/dependabot.yml + _selftest.yml.
Additive only: steps/credential-retrieval (v0.4, live) is untouched, so existing SHA
pins keep working. Consumer migrations are downstream (SREDO-695/697/698).
… and pnpm monorepos Port the improvements the aragon/app monorepo migration produced back into the shared modules, and parameterize every release/deploy module so the monorepo shape is an input diff (package-dir / tag-prefix / scope / release-branch-prefix / workspace), never a fork: - compute-version absorbs app's changeset-version: release scopes from the consumer's .github/release-scopes.yml inverted into 'changeset version --ignore' flags, version/tag read from package-dir, prettier over every touched CHANGELOG, new 'tag' output. - generate-release-summary merges app's script: per-package tag boundary (tag-glob), path filtering via .github/filters.yml (path-filter), --first-parent log, merge-commit title resolution, release-commit dropping after resolution. - New steps: generate-version-summary (per-package PR body), changesets-guard (pending changesets at the release commit, scope-aware), gh-pr-get-body / gh-pr-edit-body. - New lib/ with vendored strict flat-YAML parser (mapper files parse without consumer node_modules), releaseScopes, changelog, output helpers — unit-tested (node --test), wired into a new ci.yml and the extended _selftest. - release-start: stages the consumed .changeset/*.md deletions (double-release fix), git identity without GPG, --force-with-lease, per-lineage concurrency, on-active-release skip mode, summary-mode history|packages, ceremony steps continue-on-error. - release-finalize: 'sha' replaces 'merge-sha' (caller picks tested-head vs merge-commit tagging), package-dir version/changelog resolution, optional changesets-guard, URL-encoded tag in the Slack release link. - deploy-vercel unified with app's shared-deploy: workspace, env-overrides, runtime-env(-keys), sentry source maps, patch-root-directory, missing 'vercel pull' added. - e2e: working-directory + install/test-command inputs, no direct input interpolation. - credential-retrieval: drop workflow-only 'type:'/'options:' keys from action metadata (invalid in composite actions; actionlint now clean)
generate-release-summary now fetches each referenced Linear ticket's state and prepends a '⚠️ Open tickets' section for tickets that are not completed/canceled, with their current status (warn only, never a gate; no Linear token → no section). New reusable release-pr-refresh.yml regenerates the history summary on every release-PR push and rewrites the PR body, preserving the slack_ts marker; history mode only — packages summaries detect bumps via dirty files and cannot be re-derived after the release commit. Caller examples added to both changesets examples.
tyhonchik
force-pushed
the
app-963-study-and-design-the-modules-structure-to-release
branch
from
August 3, 2026 18:49
6404125 to
5f1f2d6
Compare
Optional inputs (all default off — the plain single-package flow needs none of them)
so app / app-backend / gov-ui-kit can migrate without duplicating behavior in their
own workflows:
- release-pr-refresh: edit the Slack head message in place (chat.update) on every
push, matching the PR-body refresh; op-slack-* paths optional.
- release-start + release-pr-refresh: 'op-slack-codeowners-group-path' (<!subteam^…>
ping in the head message), 'body-extras' (caller-computed markdown — e.g. a
DB-migration warning — carried into the PR body and Slack message, preserved on
refresh); the start head message now carries the generated summary like the
consumers' originals.
- release-start: 'require-version-above-latest-tag' — the stale-lineage guard for
linear-history/back-merge repos, checked right after compute-version.
- e2e: generics for wallet/extension suites ('env-secret-refs' + optional
OP_SERVICE_ACCOUNT_TOKEN secret, 'pre-test-command' with EXTRA_CACHE_HIT,
'use-xvfb', 'extra-cache-path'/'extra-cache-key-files'); bv artifacts get their
own names so smoke+bv can share one run.
- deploy-docker: optional Slack gate/result ceremony (notify-gate runs as a sibling
of deploy so it can never block it; 'gate-ts' output for rollback threading) and
'op-env-vault' env-file materialization before the sync.
- release-finalize: per-lineage concurrency group (no same-tag races between two
near-simultaneous merges).
- ci: fix wrong actions/checkout + actions/setup-node SHA pins (did not resolve).
Docs and examples updated accordingly.
tyhonchik
force-pushed
the
app-963-study-and-design-the-modules-structure-to-release
branch
from
August 4, 2026 10:02
3564724 to
84ba37a
Compare
…ow-ups
read-changelog and generate-version-summary share lib/changelog.js, which only
recognised the changesets heading form ('## 1.2.0') and matched the requested
version as a prefix. Two defects followed:
- conventional-changelog (the semantic-release path) writes
'## [0.33.0](…/compare/v0.32.0...v0.33.0) (2026-07-27)', and '# [2.0.0](…)' for
a major. Neither matched, so extraction returned null and release-finalize
published "No changes." as the GitHub Release body for every semantic-release
repo. Verified against app-backend's real CHANGELOG.
- a prefix match let '## 1.0.10' answer a lookup for '1.0.1' (returning the wrong
release's notes, with the stray '0' left where the heading was stripped), and
'## 1.0.0-rc.1' answer one for '1.0.0' — prerelease versions compute-version
already accepts.
Headings are now matched at a line start with the version optionally wrapped in a
link, bounded so it must end at the requested version, and the rest of the heading
line is stripped so a compare link and date don't lead the notes. Verified against
the real changelogs of app, app-backend and gov-ui-kit, plus the _selftest fixture.
Also notes the Node >= 22.5 floor that path.matchesGlob imposes on
generate-release-summary's path filtering.
Review follow-ups on the module drop:
- e2e.yml's 'extra-cache-key-files' documented comma-separated patterns, but the
input is passed to hashFiles() as ONE argument. The runner joins hashFiles
arguments with a newline and @actions/glob splits on newlines, so a comma-joined
string is a single glob that matches nothing: hashFiles returns an empty string
and the cache key becomes a constant that never invalidates. The input is now
documented as newline-separated, and a guard fails the run when the patterns
match no files instead of caching a stale asset forever. Consumers must not port
app's two-argument hashFiles('a', 'b') key as "a,b".
- e2e.yml interpolated 'pre-test-command' / 'test-command' straight into `run:`,
which §5.3 of the design forbids. Both now travel via env: and execute through
`bash -euo pipefail -c`, which also makes an `&&` chain work under xvfb-run —
the caveat the removed comment used to push onto callers.
- one bash helper (lib/gha.sh) replaces three spellings of "append a multiline
value with a random heredoc delimiter" and three copies of the per-line
::add-mask:: loop. Composite actions source it via $GITHUB_ACTION_PATH; a
reusable workflow cannot (it runs in the caller's checkout), so e2e.yml's single
call site keeps the inline form with a comment saying why. ci.yml now bash -n's
lib/**.sh alongside node --check.
- compute-version dropped the ${ARR[@]+"${ARR[@]}"} guard around an empty array:
it is only needed below bash 4.4, and runners ship bash 5.
- git-ensure-branch is called by no workflow here, which read as dead code. It is
a consumer-facing leaf for the flows that stay in the consumer repo (hotfix
start) — labelled as such in the action and the README rather than dropped, so
migrating repos don't have to keep a per-repo copy.
- trimmed comments that narrated the refactor ("now lives there too", "no longer
needs", "replaces calling load-secrets-action") down to the constraint they
were wrapped around.
tyhonchik
force-pushed
the
app-963-study-and-design-the-modules-structure-to-release
branch
from
August 4, 2026 11:19
84ba37a to
bde710b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
APP-963 (SEAL best-practices; blocks SREDO-695/697/698). Every Aragon repo re-implements a near-identical release pipeline. This design-first PR standardises them into loadable modules here, so secrets are handled the same way, the broad-permission Vercel token has one place it can be read, and a fix patches everywhere via one bump.
Deliverables
docs/release-design.md— the study/design: scenarios A–D (app / library / backend / indexer), the Build → Test → Release → Deploy spine, the module catalog, the explicit-paths credential model, the security contract, and distribution/versioning. (primary deliverable)steps/— 12 new composite actions incl.compute-version(the pluggablechangesets | semantic-releaseseam). Scripts are co-located and called via$GITHUB_ACTION_PATHso the actions work cross-repo;generateReleaseSummaryno longer hardcodes a repo..github/workflows/— reusable workflows:release-start,release-finalize,deploy-vercel,deploy-docker,e2e,release-self.examples/— per-scenario caller workflows. Plus.github/dependabot.ymland a_selftestsmoke workflow.Key decisions
op://paths; one scopedOP_SERVICE_ACCOUNT_TOKEN; nosecrets: inherit; inputs validated; third-party actions SHA-pinned.release-self); consumers pin SHAs + Dependabot.Safety
Additive only —
steps/credential-retrieval(v0.4, in use by app / app-backend / gov-ui-kit) is untouched, so existing@v0.4SHA pins keep working. Migrating consumers is downstream (SREDO tickets).Validation
actionlintclean; all workflow/action YAML parses;node --checkon all scripts._selftest.yml(manual dispatch) smoke-tests the leaf actions in-repo.Reviewer notes
aragon/github-templates/steps/*@mainduring bootstrap (relative./steps/*would resolve against the caller repo). Pin these to the cut tag/SHA when releasingv0.5.v0.5/v1is for the DevOps owner (CODEOWNER).Update 2026-08-03: monorepo support
This PR was written before aragon/app became a pnpm monorepo. The app repo has since grown improved copies of several modules (scope-based changeset versioning,
@aragon/app@x.y.ztags, workspace-aware Vercel deploys). This update ports those improvements back and parameterizes every release/deploy module so both repo shapes work from the same files: single-package repos use the defaults, monorepos pass inputs (package-dir,tag-prefix,scope,release-branch-prefix,workspace). gov-ui-kit and aragon-domain can adopt the modules now and migrate to monorepos later by changing inputs only.compute-versionabsorbs app'schangeset-version: ascopeinput names an entry in the consumer's.github/release-scopes.ymland is inverted intochangeset version --ignoreflags against the live workspace list (new packages fail safe). Version and tag come frompackage-dir; newtagoutput.generate-release-summarymerges the app script:tag-globboundary (v*or@aragon/app@*), optional path filtering via.github/filters.yml,--first-parent, merge-commit title resolution.generate-version-summary(per-package PR body),changesets-guard(pending changesets at the release commit, scope-aware),gh-pr-get-body/gh-pr-edit-body.lib/with a vendored strict flat-YAML parser, so the two mapper files parse without consumer node_modules. Unit tests run vianode --test(17 tests) and a newci.ymlon every PR..changeset/*.md(before, consumed changesets merged back to main and re-released next cycle); git identity is configured when no GPG key is passed;push --forcebecame--force-with-lease;credential-retrievalmetadata used workflow-onlytype:/options:keys, which composite actions reject (actionlint is clean again).release-finalize:merge-sharenamed tosha; the caller picks what to tag (tested head SHA, recommended, or merge commit).deploy-vercelunified with app'sshared-deploy.yml: workspace, runtime env lifting, optional Sentry source maps, and the missingvercel pullstep.examples/release-changesets-monorepo.yml; the design doc gains seam 3 (package location & repo shape).Correction to "Safety" above:
steps/credential-retrievalIS modified (byref mode + this update's metadata fix), but@v0.4SHA pins are immutable and unaffected.Validation:
node --test17/17, actionlint clean,node --checkon all scripts. Both shapes simulated locally: a scratch single-package repo end-to-end (changeset → version → the staging includes the changeset deletion) and the app checkout (scope inversion produces the same--ignoreflags as app's currentchangeset-version, version read fromapps/app).