Skip to content

ci: switch to push-to-main semantic-release pipeline#11

Merged
altaywtf merged 4 commits into
mainfrom
chore/release-pipeline
Apr 26, 2026
Merged

ci: switch to push-to-main semantic-release pipeline#11
altaywtf merged 4 commits into
mainfrom
chore/release-pipeline

Conversation

@altaywtf
Copy link
Copy Markdown
Member

@altaywtf altaywtf commented Apr 26, 2026

Summary

Replace the manual `cargo set-version + git tag + git push --tags` flow with a Conventional-Commits-driven push-to-main pipeline. Mirrors `uinaf/react-json-logic` per the `gh-release-pipeline` skill (Flavor A — Rust CLI without crates.io, semantic-release as version-decider).

How it works

```
push to main
└─► verify (PR + push: fmt + clippy + test + coverage + build)
└─► release (push to main only, !contains [skip ci])
├─► semantic-release: analyze commits, decide version
├─► scripts/release-prepare.sh: bump Cargo.toml + Cargo.lock
├─► @semantic-release/git: commit bump back with [skip ci]
├─► @semantic-release/github: tag + GitHub Release + notes
├─► dual-arch darwin build + tarballs + checksums.txt
├─► softprops/action-gh-release: attach assets to Release
└─► dawidd6/action-homebrew-bump-formula: PR on uinaf/homebrew-tap
```

Bot identity is `glitch418x` (matching `react-json-logic`).

The release job folds binary build + Homebrew bump in. A separate tag-triggered `release.yml` would never fire because tags pushed by `GITHUB_TOKEN` don't trigger downstream workflows by design.

Files

  • `.releaserc.json` — semantic-release config: commit-analyzer + release-notes-generator + exec + git + github (no `@semantic-release/npm` since we don't publish to a registry)
  • `scripts/release-prepare.sh` — invoked by `@semantic-release/exec`'s `prepareCmd`. Bumps `Cargo.toml` + `Cargo.lock` to the version semantic-release computed. Tested locally end-to-end.
  • `.github/workflows/ci.yml` — single workflow with `verify` + `release` jobs. Concurrency, `[skip ci]` guards on both jobs, `event_name` short-circuit so PR runs aren't broken by null `head_commit`
  • `Cargo.toml` — adds `license`, `repository`, `homepage`, `readme`, `publish = false`
  • `CONTRIBUTING.md` — `Releases` section
  • `AGENTS.md` — Key files list

Required secrets

Configure on this repo before merging:

  • `GITHUB_TOKEN` — provided automatically. Used for the bump-back commit, tag, and GitHub Release.
  • `TAP_GITHUB_TOKEN` — fine-grained PAT for `glitch418x` with `contents: write` + `pull-requests: write` on `uinaf/homebrew-tap`. Default `GITHUB_TOKEN` is repo-scoped only.

Addresses Copilot review on the previous commit

  • `ci.yml` verify-gate now coalesces on `github.event_name == 'push'` (Copilot caught: `github.event.head_commit` is null on `pull_request` events, which is why CI didn't run on this PR after the first commit on this branch).
  • Also dropped the dead `rustup show` steps from the (now-deleted) `release-plz.yml`.
  • Comment-vs-command mismatch resolved by retiring the file.

Test plan

  • Configure `TAP_GITHUB_TOKEN` repo secret
  • Verify CI green on this PR (the gate fix should make the verify job actually run this time)
  • Merge → on next push to `main`, expect:
    • semantic-release computes `v0.3.0` from `feat:` commits since `v0.2.0`
    • `Cargo.toml` + `Cargo.lock` bumped to `0.3.0` and committed by `glitch418x` with `[skip ci]`
    • `v0.3.0` tag + GitHub Release with auto-generated notes
    • Both `darwin-arm64` and `darwin-amd64` tarballs + `checksums.txt` attached
    • PR on `uinaf/homebrew-tap` bumping `Formula/tccutil-rs.rb`

Note

Medium Risk
Changes the release automation to push-to-main semantic-release with automated version bumps, tagging, asset publishing, and Homebrew tap PRs, which can affect release correctness and requires new repo secrets/permissions. Job-level concurrency and [skip ci] gating reduce but don’t eliminate the risk of mis-publishes if misconfigured.

Overview
Moves from a tag-triggered release.yml to a single .github/workflows/ci.yml with a cancellable verify job (PRs + pushes) and a queued release job that runs only on main pushes.

The new release flow runs semantic-release (configured via .releaserc.json) to compute the next version from Conventional Commits, executes scripts/release-prepare.sh to bump Cargo.toml/Cargo.lock and commit back with [skip ci], then builds and attaches dual-arch macOS tarballs plus checksums.txt and opens a Homebrew tap bump PR.

Also adds Rust package metadata (license, repository, homepage, readme, publish = false) and documents the new release process in CONTRIBUTING.md/AGENTS.md.

Reviewed by Cursor Bugbot for commit 4278e44. Bugbot is set up for automated code reviews on this repo. Configure here.

Replaces the manual `cargo set-version + git tag + git push --tags` flow with
a Conventional-Commits-driven push-to-main pipeline (Flavor A in the
gh-release-pipeline skill: Rust CLI without crates.io).

How it works:
- release-plz watches main; on `feat:`/`fix:` it opens a Release PR that
  bumps Cargo.toml + writes CHANGELOG.md.
- Merging the Release PR creates the v<next> tag and a GitHub Release with
  the changelog body.
- The tag push triggers release.yml, which builds dual-arch macOS tarballs,
  attaches them + checksums.txt to the existing Release, and opens a PR
  against uinaf/homebrew-tap to bump Formula/tccutil-rs.rb.

Required secrets (documented in CONTRIBUTING.md → Releases):
- RELEASE_PLZ_TOKEN: PAT for glitch418x with contents+PR write on this repo
- TAP_GITHUB_TOKEN:  PAT for glitch418x with contents+PR write on
  uinaf/homebrew-tap

Other changes:
- Add license/repository/homepage/publish=false to Cargo.toml metadata
- Add `[skip ci]` guard + concurrency group to ci.yml (defense in depth)
- Update AGENTS.md key-files list with release pipeline files
Copilot AI review requested due to automatic review settings April 26, 2026 15:33
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 manual Rust CLI release process with a Conventional-Commits-driven, push-to-main pipeline using release-plz, while keeping the existing tag-triggered binary build/release workflow and adding an automated Homebrew tap bump.

Changes:

  • Add release-plz.toml and a new release-plz workflow to automate Release PRs and tag/GitHub Release creation.
  • Update the tag-triggered release.yml to preserve release-plz changelog text and bump the Homebrew formula after attaching artifacts.
  • Harden CI with concurrency + a [skip ci] guard, and add crate metadata needed for the release automation.

Reviewed changes

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

Show a summary per file
File Description
release-plz.toml Configures Conventional-Commits parsing, changelog template, and v<version> tag naming for release-plz.
Cargo.toml Adds package metadata (license, repository, etc.) and publish = false to align with binary-only releases.
CONTRIBUTING.md Documents the new two-stage release flow and required GitHub secrets.
AGENTS.md Adds release pipeline files to the repo “key files” list.
.github/workflows/release.yml Adjusts GitHub Release asset upload behavior and adds Homebrew tap bump step.
.github/workflows/release-plz.yml Introduces push-to-main release-plz automation (release + release PR).
.github/workflows/ci.yml Adds concurrency cancellation and a [skip ci] condition.

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

Comment thread .github/workflows/release-plz.yml Outdated
Comment on lines +9 to +11
# 2. Runs `release-plz update` — opens (or refreshes) a Release PR that
# bumps Cargo.toml + writes CHANGELOG.md based on Conventional Commits
# since the last tag.
Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

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

The header comment says the workflow runs release-plz update, but the actual step uses command: release-pr. Update the comment to match the real command to avoid confusion when debugging or changing the pipeline.

Suggested change
# 2. Runs `release-plz update` — opens (or refreshes) a Release PR that
# bumps Cargo.toml + writes CHANGELOG.md based on Conventional Commits
# since the last tag.
# 2. Runs `release-plz release-pr` — opens (or refreshes) a Release PR
# that bumps Cargo.toml + writes CHANGELOG.md based on Conventional
# Commits since the last tag.

Copilot uses AI. Check for mistakes.
Comment thread .github/workflows/release-plz.yml Outdated
Comment on lines +45 to +47
- name: Install Rust toolchain (from rust-toolchain.toml)
run: rustup show

Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

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

These steps are labeled as installing the Rust toolchain, but rustup show only prints the current state and doesn’t ensure the toolchain from rust-toolchain.toml is installed. If release-plz (or its action) needs Cargo/rustc, use a toolchain-setup action (or at least run a command that triggers rustup to install the pinned toolchain); otherwise consider removing/renaming the step to reflect what it does.

Copilot uses AI. Check for mistakes.
Comment thread .github/workflows/release-plz.yml Outdated
Comment on lines +68 to +70
- name: Install Rust toolchain (from rust-toolchain.toml)
run: rustup show

Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

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

These steps are labeled as installing the Rust toolchain, but rustup show only prints the current state and doesn’t ensure the toolchain from rust-toolchain.toml is installed. If release-plz (or its action) needs Cargo/rustc, use a toolchain-setup action (or at least run a command that triggers rustup to install the pinned toolchain); otherwise consider removing/renaming the step to reflect what it does.

Copilot uses AI. Check for mistakes.
Comment thread .github/workflows/ci.yml Outdated
# Skip the verify suite on bot-authored bump commits (release-plz Release
# PR merges are not [skip ci] commits, so they still run; this guard is
# defense-in-depth in case a future automated commit lands on main).
if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }}
Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

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

The job-level condition uses github.event.head_commit.message, but this workflow also runs on pull_request events where head_commit is not present. That can cause the expression to evaluate with null/undefined and fail the workflow. Consider guarding on github.event_name == 'push' (or coalescing to an empty string) before calling contains(...), so PR runs aren't broken.

Suggested change
if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }}
if: ${{ github.event_name != 'push' || !contains(github.event.head_commit.message, '[skip ci]') }}

Copilot uses AI. Check for mistakes.
Replaces the release-plz scaffolding from the previous commit on this
branch with semantic-release, matching uinaf/react-json-logic's release
shape per the gh-release-pipeline skill (Flavor A: Rust CLI without
crates.io, version-decider via semantic-release, no cargo-dist).

Pipeline shape (single ci.yml):

  push to main
    └─► verify        (PR + push: fmt + clippy + test + coverage + build)
          └─► release (push to main only, !contains [skip ci])
                ├─► semantic-release: analyze commits, decide version
                ├─► scripts/release-prepare.sh: bump Cargo.toml + Cargo.lock
                ├─► @semantic-release/git: commit bump back with [skip ci]
                ├─► @semantic-release/github: tag + GitHub Release + notes
                ├─► dual-arch darwin build + tarballs + checksums.txt
                ├─► softprops/action-gh-release: attach assets to Release
                └─► dawidd6/action-homebrew-bump-formula: PR on tap

Bot identity is glitch418x (matching react-json-logic).

Required secrets (CONTRIBUTING.md → Releases):
- GITHUB_TOKEN (provided automatically) for tag + bump-back + Release
- TAP_GITHUB_TOKEN (PAT) for cross-repo Homebrew formula bump

Folded the previously-separate tag-triggered release.yml into the release
job because GITHUB_TOKEN-pushed tags do not trigger downstream workflows
by design — keeping release.yml standalone would never fire.

Also addresses Copilot review on PR #11:
- ci.yml verify gate now coalesces on github.event_name (was breaking on
  pull_request events where github.event.head_commit is null, which is why
  CI didn't run on this PR after the last commit)
@altaywtf altaywtf changed the title ci: wire push-to-main release pipeline with release-plz ci: switch to push-to-main semantic-release pipeline Apr 26, 2026
Comment thread .github/workflows/ci.yml Outdated
…light

Workflow-level `cancel-in-progress: true` overrides the `release` job's
job-level `cancel-in-progress: false` guard, because the cancellation
happens at the parent workflow run level. If a second push to main
arrives while a release is mid-flight, semantic-release may have already
created the tag and GitHub Release, but the binary asset upload and
Homebrew tap bump would never run — leaving a half-published release.

Move the concurrency groups to be job-level: verify stays cancellable,
release queues. The skill's own example has this bug; uinaf/react-json-
logic does too. Catching it proactively for tccutil since release jobs
involve external state (the tap repo) that is harder to recover from.

Closes Cursor Bugbot review on PR #11.
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 4278e44. Configure here.

Comment thread .github/workflows/ci.yml
- name: Install Rust toolchain (with darwin cross-compile targets)
uses: dtolnay/rust-toolchain@stable
with:
targets: aarch64-apple-darwin,x86_64-apple-darwin
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cross-compile targets installed on overridden toolchain

High Severity

dtolnay/rust-toolchain@stable installs cross-compile targets (aarch64-apple-darwin, x86_64-apple-darwin) on the stable toolchain via rustup default, but rust-toolchain.toml (with channel = "1.93") takes precedence per rustup's override order. When cargo build --target x86_64-apple-darwin runs, it uses the 1.93 toolchain, which doesn't have that target installed. On ARM64 macos-latest runners, the aarch64 build would succeed (host target), but the x86_64 cross-compile build would fail. By that point, semantic-release has already created the tag and GitHub Release, leaving a half-published release with no binary assets.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 4278e44. Configure here.

@altaywtf altaywtf merged commit 2ad5f4c into main Apr 26, 2026
3 checks passed
@altaywtf altaywtf deleted the chore/release-pipeline branch April 26, 2026 18:20
@github-actions
Copy link
Copy Markdown

🎉 This PR is included in version 0.2.1 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@github-actions
Copy link
Copy Markdown

🎉 This PR is included in version 0.2.1 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants