Automate miner release versioning - #523
Conversation
Release proposal workflow computes the next miner-v version (patch/minor/major/custom) from tags and opens a version-bump PR; merging it tags, builds all platforms, and publishes the release.
dewabisma
left a comment
There was a problem hiding this comment.
Have you tested the CI workflows? It can be tricky to make CI works without actually run and see it works.
|
Yes thats why i did not merge yet ;) |
🔍 Review — Automate miner release versioning (CI)Verdict: 🟡 Approve with non-blocking comments The design is sound: the release-firing guard is correct (only a merged PR carrying the What it does
Strengths
Findings
Verification
🤖 AI-assisted review generated with Claude Code |
|
Update: all 8 findings from the review above are now fixed on this branch, and the full flow has been tested for real this time. Fixes (commit
End-to-end verification on a disposable repo (n13/miner-release-e2e-test) with the two orchestration workflows byte-identical to this branch and a stub build keeping the exact
Also 33 local tests run against the actual scripts extracted from the workflow YAML (version math, guards, title parsing, prev-tag lookup, tag idempotency incl. collision at a different commit). What remains untested is only the real Flutter/signing build internals, which this PR doesn't change apart from the trigger/interface conversion — and that interface is exactly what the E2E exercised. |
n13
left a comment
There was a problem hiding this comment.
Verdict: REQUEST_CHANGES — the release build is not pinned unambiguously to the tag/merge commit.
Blocking finding
- [P1] A same-named branch can shadow the release tag and get different code signed and published. In
.github/workflows/publish_miner_release.yml:88and:101, the workflow passes the bare valueminer-vX.Y.Ztoactions/checkout. Checkout v4 resolves an unqualified ref by testingrefs/remotes/origin/<name>beforerefs/tags/<name>. Therefore, if a branch namedminer-vX.Y.Zexists, the build jobs check out that branch even thoughcreate-tagcorrectly created the tag at the merge commit. The macOS job will then build and Developer-ID-sign the branch contents, andcreate-releasewill publish those artifacts under the legitimate tag. This bypasses the protected merge/release path for any collaborator able to create a branch. Pass a fully-qualified tag ref (refs/tags/${{ needs.create-tag.outputs.tag }}) at both sites, or output the verified merge SHA and use that SHA for every build/release checkout.
The disposable E2E run is real: the two orchestration workflow files are byte-identical to this head, attempt 2 completed successfully, and miner-v0.5.1 dereferences to the PR merge commit. It did not exercise the branch/tag collision above.
Non-blocking note
- The PR summary's first-run example is stale after the latest merge from
main: both base and head now haveminer-appat0.6.0while the latest miner tag is0.5.0, so a patch dispatch computesminer-v0.6.1, notminer-v0.5.1.
Validation
- Inspected the complete
8e68f1a...4b9888adiff and intervening fix/merge commits. actionlint v1.7.12— clean for all three changed workflows.dart run melos bootstrap— passed for all four packages.dart run melos exec --concurrency=1 -- 'flutter analyze . --fatal-infos'— all four packages passed.dart run melos exec -- dart format lib test --line-length=120— passed; 0 files changed.git diff --check— clean.- Live GitHub
Analyzecheck — passed.
GitHub does not allow an author to submit a native request-changes review on their own PR, so this is posted as a COMMENTED request-changes opinion.
…d merge SHA actions/checkout resolves bare refs as branches before tags, so a branch named miner-vX.Y.Z could shadow the release tag and get different code signed and published. Build and release now check out the merge commit SHA that the pubspec verification and tag creation already ran against.
|
Both points addressed in P1 (branch shadowing the release tag): Stale first-run example: PR body updated — with pubspec at SHA checkouts are the same mechanism the E2E already exercised in |
n13
left a comment
There was a problem hiding this comment.
Verdict: APPROVE — the prior release-integrity blocker is fixed, and no blocking findings remain.
The new d904d8a8 commit exports github.event.pull_request.merge_commit_sha from create-tag and passes that verified SHA to both the reusable miner build and the release checkout (publish_miner_release.yml:27, :91, :104). The tag name is no longer used as a checkout ref anywhere in the publish path, so a same-named branch cannot redirect the code that is built, Developer-ID-signed, or packaged. The PR summary's first-run version example is also now accurate for the current 0.6.0 pubspec / miner-v0.5.0 tag state.
Validation:
- Inspected the complete
4b9888a..d904d8aincremental commit and the full resolved8e68f1a...d904d8adiff. actionlint v1.7.12— clean for all three changed workflows, including the new job output/reusable-workflow expression.- Exact SHA-wiring assertions — passed: one merge-SHA output, two downstream SHA checkouts, and no remaining tag-output checkout.
git diff --check— clean.- Live GitHub
Analyzecheck ond904d8a— passed.
No blocking findings remain. GitHub does not allow an author to submit a native approval on their own PR, so this is posted as a COMMENTED approval opinion.
|
Shipping this |
Summary
Replaces the manual version-entry miner release with the same automated flow as quantus-cli / chain / quantus-miner:
create_miner_release_proposal.yml(new): dispatch withpatch/minor/major/custom. Computes the next version from max(latestminer-v*tag,miner-app/pubspec.yaml) — so a manually pre-bumped pubspec can never be silently downgraded — bumps the pubspec, and opens a PR labeledminer-release-proposal(labels auto-created on first run). Custom versions below the current version are rejected; an already-existing tag is rejected via a remotels-remotecheck.publish_miner_release.yml(new): when that PR merges — checks outmerge_commit_shadirectly, verifies pubspec matches the PR-title version, tags the merge commitminer-vX.Y.Z, then builds and releases pinned to that verified merge SHA (never a bare tag name, which checkout would resolve branch-first, letting a same-named branch shadow the release). The GitHub release is published with--notes-start-tagpinned to the previous miner tag so generated notes don't diff againstwallet-v*tags. The whole run is idempotent: re-running after a partial failure skips the existing tag (if it points at the merge commit) and re-uploads assets to the existing release instead of dying. Aconcurrencygroup serializes publish runs.create_miner_build.yml: now build-only and reusable (workflow_callwith arefinput); manual dispatch still available for test builds. The old in-workflow release job (deprecatedactions/create-release@v1) is removed.Notes
PAT_TOKENsecret forgh pr createso CI triggers on the release PR (same asADMIN_PATin the other repos). If it has expired, the proposal job fails at PR creation and the secret needs rotating.mainpubspec is at0.6.0while the latest tag isminer-v0.5.0, so a patch dispatch releasesminer-v0.6.1. To release exactly0.6.0, dispatch with custom =0.6.0.Test plan
sort -Vcases), custom-version validation and downgrade rejection, pubspec parsing (incl.+buildsuffix and malformed input), PR-title tag extraction, previous-tag lookup with wallet tags interspersed, and tag-push idempotency against a bare origin (fresh, re-run same commit, re-run fresh clone, collision at different commit)n13/miner-release-e2e-test) with the two orchestration workflows byte-identical to this branch (pre-SHA-pinning; that later commit only changes which ref the already-proven checkouts receive) and a stub build keeping the exactworkflow_call/artifact interface:ci: Miner version bump to miner-v0.5.1with correct labels and pubspec bumpFull Changelog: miner-v0.5.0...miner-v0.5.1(wallet tag correctly skipped)0.4.0proposal → rejected in the calculate job (downgrade guard)is_draft=true→ PR carrieddraft-releaselabel and the release was published as a draft