Skip to content

Refactor release workflow to use GITHUB_TOKEN and track release status#5

Open
nsheaps wants to merge 1 commit intomainfrom
claude/fix-release-workflow-d9FkF
Open

Refactor release workflow to use GITHUB_TOKEN and track release status#5
nsheaps wants to merge 1 commit intomainfrom
claude/fix-release-workflow-d9FkF

Conversation

@nsheaps
Copy link
Copy Markdown
Owner

@nsheaps nsheaps commented Mar 5, 2026

Summary

This PR refactors the GitHub Actions release workflow to simplify authentication and add proper release status tracking. The workflow now uses the default GITHUB_TOKEN instead of a custom GitHub App, and introduces a released output to conditionally run dependent jobs.

Key Changes

  • Authentication: Replaced custom GitHub App authentication with the default GITHUB_TOKEN secret, eliminating the need for the github-app-auth action
  • Git Configuration: Added explicit git user configuration step to set up the bot identity for commits
  • Release Detection: Implemented logic to detect whether a new release was actually created by comparing git tags before and after running release-it
  • New Output: Added released output to the release job to indicate whether a release was created
  • Conditional Execution: Updated dependent jobs (update-homebrew and Upload release assets) to only run when released == 'true', preventing unnecessary executions when no release is created
  • Error Handling: Added fallback values when git tag commands fail, making the workflow more robust

Implementation Details

  • The release detection compares the latest tag before and after the release-it command
  • If tags differ and a new tag exists, released is set to true and outputs are populated
  • If no new release is created, released is set to false and a message is logged
  • Downstream jobs now use conditional execution (if: needs.release.outputs.released == 'true') to skip unnecessary work

https://claude.ai/code/session_01M87EMaBqu28SAXpir3WLUV

The release workflow failed with "[@octokit/auth-app] appId option is
required" because AUTOMATION_GITHUB_APP_ID/PRIVATE_KEY secrets were not
configured.

The release job only needs contents:write on the current repo, which the
built-in GITHUB_TOKEN already provides. GitHub App auth is only needed
for the update-homebrew job (cross-repo access).

Also adds:
- released output to track whether a new release was actually created
- Conditional execution of upload and homebrew steps when no release
- Git user config for github-actions[bot]

https://claude.ai/code/session_01M87EMaBqu28SAXpir3WLUV
@jack-nsheaps
Copy link
Copy Markdown
Contributor

jack-nsheaps bot commented Apr 8, 2026

🤖 Pseudo Review — Jack Oat


Overall Assessment

Verdict: APPROVE with minor notes

This is a solid, well-scoped fix. The root cause is clear (GitHub App secrets not configured), the solution correctly identifies what actually needs the App token (cross-repo homebrew access) vs. what does not (same-repo release commit). The release detection logic is a genuine improvement over the previous all-or-nothing approach. No blocking issues.


File: .github/workflows/release.yaml

✅ Correct

Authentication split is appropriate. The release job only pushes a tag and creates a GitHub Release on its own repo — contents: write from GITHUB_TOKEN is sufficient. The update-homebrew job still uses the GitHub App token, which is the right call since it needs to push to a different repo (nsheaps/homebrew-devsetup). This is the minimal-privilege change.

Release detection logic is correct. Capturing BEFORE_TAG before running release-it and comparing to AFTER_TAG after is a reliable idiom. The || echo "" fallback handles repos with no tags yet. The conditional correctly covers both: tag changed AND a new tag exists (handles the edge case where tag somehow reverts, which shouldn't happen but is defensive).

Conditional execution on downstream steps. Both Upload release assets and update-homebrew now guard on released == 'true'. This prevents failed runs when release-it decides no version bump is warranted (e.g., only chore: commits since last release with the conventional-changelog preset configured here).


⚠️ Minor Issues

[minor] Hard-coded git user identity

git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"

The existing github-app-auth action already does this dynamically by querying the App's actual user ID via the API. The new hard-coded values work for github-actions[bot] but will produce incorrect commit attribution if you ever re-introduce a GitHub App for the release job. The user ID 41898282 is correct for github-actions[bot] today, but it's not immediately obvious to future readers where that number came from. A comment explaining it would help:

- name: Configure git
  run: |
    # github-actions[bot] user ID — see https://github.com/actions/checkout/issues/13
    git config user.name "github-actions[bot]"
    git config user.email "41898282+github-actions[bot]@users.noreply.github.com"

[minor] released output missing from job-level outputs on main branch

The PR adds released to the job-level outputs block correctly:

outputs:
  version: ${{ steps.release.outputs.version }}
  tag: ${{ steps.release.outputs.tag }}
  released: ${{ steps.release.outputs.released }}

However, the base branch's release job does not have this output declared — this is what the PR fixes. Just confirming: the PR correctly adds it. ✓

[nit] No-release path doesn't echo to Actions summary

When released=false, the step logs No new release created to stdout, which shows up in the step log but not in the Actions summary. For operational visibility, consider adding:

echo "No new release created" | tee -a "$GITHUB_STEP_SUMMARY"

Not critical, but makes monitoring easier.

[nit] BEFORE_TAG edge case on empty repos

If the repo somehow has zero tags when the workflow runs, BEFORE_TAG="" and AFTER_TAG="" (after release-it creates the first tag) — wait, actually AFTER_TAG would be set after the first release. Let me think through this:

  • Initial state: no tags → BEFORE_TAG=""
  • release-it runs and creates v1.0.0 tag
  • AFTER_TAG="v1.0.0"
  • Condition: "" != "v1.0.0" AND "v1.0.0" is non-empty → released=true

This works correctly. No issue.


🔍 Observations (not issues)

release-it commit message uses [skip ci] (from .release-it.json): commitMessage: "chore: release v${version} [skip ci]". This means the release commit itself won't re-trigger the workflow. Combined with the released output, the workflow is safe from infinite loops. Good.

GITHUB_TOKEN scope. The workflow already declares permissions: contents: write at the top level, which GITHUB_TOKEN will inherit. Since release-it needs to push tags and create releases, this is sufficient.

update-homebrew still uses GitHub App correctly. The job pushes to nsheaps/homebrew-devsetup and opens a PR there — that genuinely requires cross-repo write access that GITHUB_TOKEN can't provide. The App token is the right call there.


Summary

Severity Count Items
Critical 0
Major 0
Minor 1 Hard-coded bot identity without explanatory comment
Nit 1 No-release path could surface to Actions summary

The change is correct, the scope is appropriate, and the release detection logic is an improvement over the previous approach. The minor note about the hard-coded user ID is cosmetic — the values are correct today.


Co-Authored-By: Jack Oat <jack-nsheaps[bot]@users.noreply.github.com>

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants