From 88c15644244fdeb135bda0b2b6faeb525ab8f290 Mon Sep 17 00:00:00 2001 From: Hakula Chen Date: Mon, 2 Nov 2026 14:34:06 +0800 Subject: [PATCH 1/2] ci(release): open the Homebrew formula PR with an app token GitHub holds the pull_request runs of a PR opened with GITHUB_TOKEN until someone with write access approves them, and the dispatched ci.yml run does not report the PR's required checks. Pushing the branch and opening the PR with a GitHub App installation token makes the pull_request workflow run normally, so the job no longer dispatches ci.yml or needs actions: write. --- .github/workflows/release.yml | 29 +++++++++++++---------------- RELEASING.md | 2 +- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2eeaeb508..97fda7e12 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -281,15 +281,22 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 15 permissions: - actions: write - contents: write - issues: write - pull-requests: write + contents: read steps: + - name: Create GitHub App token + id: app-token + uses: actions/create-github-app-token@v3 + with: + app-id: ${{ secrets.RELEASE_APP_ID }} + private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} + owner: ${{ github.repository_owner }} + repositories: ${{ github.event.repository.name }} + - name: Checkout uses: actions/checkout@v7 with: ref: main + token: ${{ steps.app-token.outputs.token }} - name: Download formula uses: actions/download-artifact@v8 @@ -299,7 +306,7 @@ jobs: - name: Open formula PR env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ steps.app-token.outputs.token }} run: | # Follow the latest release, or the newest prerelease before the first stable one. latest=$( @@ -357,19 +364,9 @@ jobs: --label chore \ --body-file .github/templates/homebrew-formula-pr.md then - echo "::error::Could not open the formula PR." \ - 'Enable "Allow GitHub Actions to create and approve pull requests"' \ - 'in Settings > Actions > General, then rerun this job.' - exit 1 - fi - - # GitHub holds CI on a PR opened with GITHUB_TOKEN until approved, so dispatch CI now. - run_url=$(gh workflow run ci.yml --ref "$branch") - if [[ -z "$run_url" ]]; then - echo "::error::The CI dispatch on $branch returned no run." + echo "::error::Could not open the formula PR." exit 1 fi - echo "Dispatched CI: $run_url" notes: name: Republish Release Notes diff --git a/RELEASING.md b/RELEASING.md index 5048d15d3..4bd5d30b9 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -133,7 +133,7 @@ Watch the [Release workflow](https://github.com/hakula139/oxide-code/actions/wor - Every [target](#targets) archive and its `.sha256` sidecar are attached, and `gh attestation verify --repo hakula139/oxide-code` passes for one of them. - `nix run github:hakula139/oxide-code/vX.Y.Z -- --version` prints the version on one host. -The workflow then renders the formula from the release sidecars, installs it through a local tap on `macos-latest` and `ubuntu-latest`, and runs `brew test` there before it opens a `chore(release): refresh Homebrew formula for vX.Y.Z` PR. The same check runs on pull requests that touch the formula, its rendering script, or the release workflows. Merging that PR is the final release step. Because GitHub Actions opened it with `GITHUB_TOKEN`, GitHub holds the PR's runs until someone with write access approves them in the Actions tab ([#364](https://github.com/hakula139/oxide-code/issues/364)). Approve them, wait for the PR's checks to pass, then squash-merge it. The formula follows the latest release, or the newest prerelease until the first stable release, so other tags skip this job. If the job fails, fix the cause and rerun it, since a rerun rebuilds the branch and reuses an open PR. +The workflow then renders the formula from the release sidecars, installs it through a local tap on `macos-latest` and `ubuntu-latest`, and runs `brew test` there before it opens a `chore(release): refresh Homebrew formula for vX.Y.Z` PR. The same check runs on pull requests that touch the formula, its rendering script, or the release workflows. Merging that PR is the final release step. Wait for its checks to pass, then squash-merge it. The formula follows the latest release, or the newest prerelease until the first stable release, so other tags skip this job. If the job fails, fix the cause and rerun it, since a rerun rebuilds the branch and reuses an open PR. ## Re-Cut an Existing Tag From 095b307158d4c552a116cf6d825c9b19c18ca715 Mon Sep 17 00:00:00 2001 From: Hakula Chen Date: Mon, 2 Nov 2026 15:09:13 +0800 Subject: [PATCH 2/2] ci(release): simplify the App token configuration Use client-id, which accepts the App ID and is not deprecated. The action already scopes the token to the current repository, so the owner and repositories inputs and the job-level permissions are redundant. Author the formula commit as the App so the commit and PR share its identity. --- .github/workflows/release.yml | 10 +++------- RELEASING.md | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 97fda7e12..38277bb66 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -280,17 +280,13 @@ jobs: needs: [publish, formula] runs-on: ubuntu-latest timeout-minutes: 15 - permissions: - contents: read steps: - name: Create GitHub App token id: app-token uses: actions/create-github-app-token@v3 with: - app-id: ${{ secrets.RELEASE_APP_ID }} + client-id: ${{ secrets.RELEASE_APP_ID }} private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} - owner: ${{ github.repository_owner }} - repositories: ${{ github.event.repository.name }} - name: Checkout uses: actions/checkout@v7 @@ -349,8 +345,8 @@ jobs: fi git \ - -c user.name='github-actions[bot]' \ - -c user.email='41898282+github-actions[bot]@users.noreply.github.com' \ + -c user.name='hakula-release-bot[bot]' \ + -c user.email='351352052+hakula-release-bot[bot]@users.noreply.github.com' \ commit -am "$title" # A rerun rebuilds this commit on the current main and replaces the earlier push. git push --force origin "$branch" diff --git a/RELEASING.md b/RELEASING.md index 4bd5d30b9..29c2f2153 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -133,7 +133,7 @@ Watch the [Release workflow](https://github.com/hakula139/oxide-code/actions/wor - Every [target](#targets) archive and its `.sha256` sidecar are attached, and `gh attestation verify --repo hakula139/oxide-code` passes for one of them. - `nix run github:hakula139/oxide-code/vX.Y.Z -- --version` prints the version on one host. -The workflow then renders the formula from the release sidecars, installs it through a local tap on `macos-latest` and `ubuntu-latest`, and runs `brew test` there before it opens a `chore(release): refresh Homebrew formula for vX.Y.Z` PR. The same check runs on pull requests that touch the formula, its rendering script, or the release workflows. Merging that PR is the final release step. Wait for its checks to pass, then squash-merge it. The formula follows the latest release, or the newest prerelease until the first stable release, so other tags skip this job. If the job fails, fix the cause and rerun it, since a rerun rebuilds the branch and reuses an open PR. +The workflow then renders the formula from the release sidecars, installs it through a local tap on `macos-latest` and `ubuntu-latest`, and runs `brew test` there before it opens a `chore(release): refresh Homebrew formula for vX.Y.Z` PR. The same check runs on pull requests that touch the formula, its rendering script, or the release workflows. Merging that PR once its checks pass is the final release step. The formula follows the latest release, or the newest prerelease until the first stable release, so other tags skip this job. If the job fails, fix the cause and rerun it, since a rerun rebuilds the branch and reuses an open PR. ## Re-Cut an Existing Tag