Skip to content

Latest commit

 

History

History
196 lines (149 loc) · 9.28 KB

File metadata and controls

196 lines (149 loc) · 9.28 KB

Releasing

meteor-decomp uses Semantic Versioning 2.0.0 driven entirely by git tags. The annotated git tag vX.Y.Z is the sole source of truth — there is nothing in the tree to version. This repo has no Cargo.toml and no VERSION file, so a release writes no commit back to the branch: it only creates and pushes a tag (and publishes a GitHub Release).

Branching model

  • develop is the default branch and the integration branch for day-to-day decomp work. It is unprotected — commit/push to it directly (agent orchestration included) or via PR, whatever fits the moment. Nothing merged into develop produces a release or a tag.
  • master is the protected release branch. A release is cut by opening a PR from develop into master; when it merges, release.yml fires (tag + GitHub Release + Discord). master requires a pull request (no direct pushes) but no approving review, so you can self-merge your own developmaster release PR. Any merge method works — squash, merge commit, or rebase (see Why pull_request_target, not push).

Flow: work on develop → release PR developmaster → merge → automatic tag + GitHub Release + Discord announcement.

Branch protection on master does not block the release automation: the workflow pushes only a tag (refs/tags/vX.Y.Z), and tag pushes are not gated by branch-protection rules — only commits to the branch are, which this workflow never makes. So the default GITHUB_TOKEN still suffices (see Why no PAT).

How it works

.github/workflows/release.yml runs when a developmaster release PR merges (a pull_request_target closed + merged event), or on a manual workflow_dispatch, and:

  1. reads the highest existing vX.Y.Z tag,
  2. picks a bump level (see below),
  3. creates an annotated vX.Y.Z tag on the merge commit and pushes only that tag (no commit, no file edits — nothing is rewritten in the tree),
  4. publishes a GitHub Release with auto-generated notes, best-effort appended with the current decomp progress (see Progress tie-in), and
  5. posts a Discord release notification (see Discord release notification).

After a release, git describe --tags on master reports the new X.Y.Z.

Choosing the bump level

Bump How to trigger
Patch Default. A merged developmaster release PR (or manual dispatch) with no release label → Z increments.
Minor Add the release:minor label to the PR before merging → Y+1, Z=0.
Major Add the release:major label to the PR before merging → X+1, Y=0, Z=0.

The label is read from the PR associated with the merge commit; if both labels are present, release:major wins. A run with no associated PR (a manual workflow_dispatch, or a merge GitHub doesn't link to a PR) is treated as a patch bump.

The release:minor and release:major labels must exist in the repo.

Manual minor/major (alternative)

Because the next version is computed from the highest tag, you can also bump out-of-band by pushing a tag yourself:

git tag -a v0.2.0 -m v0.2.0 && git push origin v0.2.0

The automation then continues patch-incrementing from there (v0.2.1, …). This is handy for the first minor/major when no PR is involved.

Why pull_request_target, not push

The release PR merges develop into master, and develop is saturated with [skip ci] commits (the reconcile bot stamps every progress-doc commit with [skip ci]). A squash merge folds all the squashed commit messages — [skip ci] markers included — into the squash commit's body. GitHub then scans the merged commit's message, sees [skip ci], and skips every workflow for that push (including release.yml). With a push: branches: [master] trigger, a squash-merged release therefore silently never releases — no tag, no GitHub Release, no Discord ping. (This is exactly what happened to the first release PR after the Discord step was added.)

pull_request_target keys off the PR-merge event, not the pushed commit, so it is immune to [skip ci] and fires regardless of merge method (squash, merge commit, or rebase). The job is gated on pull_request.merged == true (so a PR closed without merging never releases) and base.ref == 'master'.

Safety: despite the pull_request_target event, this workflow never checks out or runs PR head code — it checks out master and reads only git tags and the merged PR's labels. The usual pull_request_target risk (running attacker-controlled code with secrets in scope) does not apply.

Manual release (workflow_dispatch)

release.yml also exposes a manual Run workflow button (workflow_dispatch, no inputs). Use it to cut a release on demand — e.g. to recover a push that was skipped before this trigger fix landed, or to force a patch bump. It always checks out and releases master HEAD, computing the next version from the highest tag exactly like an automatic run.

gh workflow run release.yml --repo swstegall/meteor-decomp

Why no PAT

This workflow pushes only a tag — it never commits anything back to the branch. Tag pushes are not gated by branch-protection rules (only commits to the branch are), so even though master is protected, the default GITHUB_TOKEN (github.token) can:

  • push the vX.Y.Z tag, and
  • create the GitHub Release.

So no fine-grained RELEASE_PAT is required (unlike the sibling garlemald-server / garlemald-client release workflows, which commit a version bump back to a protected branch and therefore do need a PAT). The checkout uses the default token.

Why no loop guard

Because nothing is committed back to master, there is no re-trigger to guard against:

  • The workflow triggers on a PR merge into master (and manual dispatch).
  • Pushing a tag creates no PR-close event and matches no trigger here, so creating vX.Y.Z cannot re-run this workflow.

So there is deliberately no bot-identity if guard and no [skip ci] marker — both are only needed when a workflow pushes a commit back to the branch it triggers on, which this one never does.

Progress tie-in

The Release body is best-effort augmented with current decomp progress. The workflow runs tools/progress.py (after pip install pyyaml), captures the overall (YAML status): and overall (_rosetta/*.cpp): summary lines, and edits the just-created Release to prepend a short "Decomp progress at vX.Y.Z" block above GitHub's auto-generated notes.

The create-then-edit approach is used because gh release create cannot combine --generate-notes with --notes-file; editing afterward keeps the generated notes and the progress block. The whole progress attempt is wrapped so that a failure (PyYAML missing, network blip, progress.py change, no YAML present) never fails the release — the tag and Release publish regardless.

Discord release notification

After the tag and GitHub Release publish, release.yml's final step POSTs a Discord embed announcing the new release to the release-announcements channel (mirrors the sibling garlemald-server / garlemald-client release announcers). Because every reached run is a genuine release — a merged developmaster release PR, or a manual workflow_dispatch, both of which compute and publish a new version — each successful release is announced; there is no separate event guard.

The embed reads:

Meteor Decomp vX.Y.Z — A new Meteor Decomp release is available: vX.Y.Z.

…linked to the Release page.

This step requires a repo secret DISCORD_RELEASE_WEBHOOK_URL (the Discord webhook URL for the release-announcements channel — distinct from DISCORD_PR_WEBHOOK_URL and DISCORD_WEBHOOK_URL). It is a separate webhook so release pings land in their own channel and a leaked/rotated webhook is scoped to one purpose. Hardening matches the other Discord workflows:

  • the payload is assembled with jq --arg (every value escaped), so the tag can never break out of the shell or the JSON;
  • a missing secret logs a ::warning:: and skips the post (exit 0) rather than failing — so the release still succeeds before the secret is configured;
  • a webhook failure (unreachable/rejected) is likewise non-fatal — the tag and Release have already published.

If DISCORD_RELEASE_WEBHOOK_URL is not set, releases still cut normally; only the Discord ping is skipped (with a warning in the job log). Add the secret to enable announcements: gh secret set DISCORD_RELEASE_WEBHOOK_URL --repo swstegall/meteor-decomp.

Seeding

The sequence starts from an initial v0.1.0 tag on master HEAD, created once by a maintainer as a seed step outside this workflow:

git tag -a v0.1.0 -m v0.1.0 <master-HEAD-sha> && git push origin v0.1.0

The first developmaster release PR merged after the release automation lands bumps it to v0.1.1 (or the labeled minor/major). The workflow never creates v0.1.0 itself.