Skip to content

Automate releases via PR + GitHub Release#6

Draft
fnando wants to merge 16 commits into
reprofrom
release-docs
Draft

Automate releases via PR + GitHub Release#6
fnando wants to merge 16 commits into
reprofrom
release-docs

Conversation

@fnando
Copy link
Copy Markdown
Member

@fnando fnando commented May 21, 2026

What

Replaces the previous "push a v* tag" trigger with a PR-driven release flow. A new release workflow opens a release PR for review; merging plus publishing a GitHub Release fires the publish workflow. Refreshing an already-released cli with newer rust versions uses the same flow with a v<cli>-N iteration suffix on the tag.

  • scripts/release-prepare.sh — given a stellar-cli version, detects new vs refresh mode, auto-picks the last two minor stable Rusts at their latest patch from rust-lang/rust (override via --rust-versions), updates builds.json accordingly, resolves the cli ref + rust digests, validates, and prints the chosen GitHub Release tag (v<cli> for new, v<cli>-<N> for refresh). Errors loudly when a refresh would be a no-op (no new Rusts available + nothing else changed).
  • scripts/release-body.sh — composes the markdown body for a GitHub Release from the per-arch metadata files uploaded by the publish workflow.
  • scripts/verify-image.sh — wraps gh attestation verify for both predicate types against a digest-pinned image (consumer-facing).
  • .github/workflows/release.ymlworkflow_dispatch with a required stellar_cli_version input. Stages the changes via release-prepare.sh, captures the picked release tag, pushes a release/<tag> branch, opens a PR titled "Release stellar-cli " or "Refresh stellar-cli ()" with a pre-filled releases/new?tag=<tag> link. SHA-pinned actions.
  • .github/workflows/publish.yml — switched from push: tags: v* to release: types: [published]. Parses both v<version> and v<version>-<N> tags to derive the cli version. Existence check changed from fail to skip with a ⚠️ workflow warning + step summary: per-arch tags and per-pair manifest lists are still immutable (never overwritten), but a re-run / refresh just no-ops on already-published rows instead of breaking the workflow. Skipped pairs still emit metadata (digest queried from the registry) so the release body always reflects the full declared state.
  • RELEASE.md — rewritten to describe the workflow-driven flow, the -N refresh tag scheme, the skip-with-warning behaviour, and the manual / local-prepare path.

Why

Three problems the previous design had:

  1. Tag pushes bypass review. git push origin v26.0.0 was a single-user low-ceremony action with no PR review of the release contents. The new flow puts a reviewed PR between the maintainer's intent and the publish.
  2. Re-running the workflow with the same cli failed loudly on every already-published row. Adding a new Rust to an existing cli required manually deleting tags from Docker Hub before re-running. The skip-with-warning change removes that friction without weakening the immutability property — existing tags still can't be overwritten, they're just skipped instead of erroring.
  3. In-place release-page updates were going to need sentinel markers or risk duplicating sections on re-runs. Switching to one-release-tag-per-iteration (v26.0.0, v26.0.0-1, v26.0.0-2, ...) makes every release page a fresh artifact — no append/overwrite dance, historical pages stay intact as snapshots.

Notable choices

  • Tag scheme: v<cli> for new releases, v<cli>-<N> for refreshes. The -N is our refresh iteration, not stellar-cli's patch versions. Docker image tags (:26.0.0-rust1.94.0-amd64) are unaffected — they remain pinned by cli + rust + arch.
  • Auto-pick: always the last two minor stable Rusts at their latest patch. Maintainers who need different pairings push commits to the release branch before merging. No workflow input for explicit rust versions — keeps the dispatch form minimal.
  • No-op refresh fails fast. If a refresh would produce no changes to builds.json (auto-pick matches the current declared state), release-prepare.sh exits non-zero with a clear message before pushing an empty commit.
  • Skip-with-warning, not skip-silently. Already-published rows emit ::warning:: annotations and a step-summary block, so the run page surfaces what was skipped without dressing it up as a failure.
  • append_body: true on the release update. Each release tag is fresh, so there's no body to overwrite — the workflow's structural section appends below whatever notes the maintainer wrote when they clicked "Publish release".

Depends on

#5 (repro) — this branch is based on it. Base auto-updates to main as the upstream chain merges.

Verification

  • shellcheck clean on all new + modified scripts.
  • release-prepare.sh smoke-tested locally:
    • New cli: refuses if cli exists, accepts new, picks v<cli>.
    • Refresh: detects existing cli, updates rust_versions, picks v<cli>-1 when v<cli> already exists (queried via gh release list).
    • No-op refresh: when auto-pick matches the existing state, exits 1 with error: no changes to builds.json — nothing to release.
  • release-body.sh renders a clean markdown body against synthetic per-arch metadata files (full state of every declared pair).
  • verify-image.sh --help works; refuses tag-only refs.

End-to-end behaviour verifiable by triggering the release workflow once this PR merges, reviewing the auto-generated PR, merging, and publishing the resulting GitHub Release.

@fnando fnando self-assigned this May 21, 2026
@fnando fnando requested a review from Copilot May 21, 2026 20:11
@fnando fnando added this to DevX May 21, 2026
@github-project-automation github-project-automation Bot moved this to Backlog (Not Ready) in DevX May 21, 2026
@fnando fnando moved this from Backlog (Not Ready) to In Progress in DevX May 21, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR replaces the prior tag-push-driven release mechanism with a PR-reviewed, workflow-driven release flow: a dispatchable release workflow stages builds.json changes into a release PR, and publishing a GitHub Release triggers publish to build/push images and enrich the release.

Changes:

  • Add scripts/release-prepare.sh to stage/update builds.json, resolve refs/digests, detect no-op refreshes, and pick the next release tag (v<cli> / v<cli>-N).
  • Add .github/workflows/release.yml to create a release branch + PR from a workflow_dispatch input.
  • Update .github/workflows/publish.yml to trigger on release: published, parse refresh tags, and skip already-published rows with warnings while still emitting metadata.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
scripts/release-prepare.sh New staging script for release/refresh runs: rust selection, builds.json edits, digest/ref resolution, and release tag selection.
RELEASE.md Rewritten maintainer documentation for the PR + GitHub Release-driven flow and refresh tag scheme.
README.md Adds a “Releasing” pointer to RELEASE.md.
.github/workflows/release.yml New dispatch workflow that runs release-prepare.sh, pushes release/<tag>, and opens a PR.
.github/workflows/publish.yml Switch publish trigger to release: published, support v<version>-N tags, and implement skip-with-warning behavior for immutable tags.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread README.md Outdated
Comment thread RELEASE.md
Comment thread .github/workflows/release.yml
Comment thread scripts/release-prepare.sh
Comment thread scripts/release-prepare.sh
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

2 participants