Files
msime-windows/scripts/ci/check-release-pr.sh
T
Evan Hu 2a15c6a4ad ci(release): only build and sign on an explicit dispatch
The signing certificate allows a limited number of signatures, so a release costs something finite. It should not be spent by merging a pull request.

Until now a push to main was enough to spend one: release-please opened the release pull request, merge-release-pr.sh merged it, the merge commit came back through this workflow as release_created, and the build jobs signed two binaries and an installer and published the result. Nobody had to ask for any of that.

should_publish is now true only for workflow_dispatch, and the package job -- the only one that signs -- states that condition itself rather than inheriting it from four other jobs whose conditions a later edit could quietly change.

Auto-merging the release pull request goes with it, since that is the mechanism that turned a merge into a release, and leaving it would also mint a draft release and a tag on every merge to main that nobody intends to build. What remains automatic is getting a passing check onto that pull request, which is not optional: GITHUB_TOKEN cannot start a workflow run, so without the dispatch in check-release-pr.sh the release pull request has no checks at all and required_status_checks (#121) leaves it permanently unmergeable.

Releasing is now two deliberate steps. Merge the release pull request, which creates the draft release and its tag and builds nothing. Then run the Release workflow against that tag. Dispatching the same tag twice is already refused by validate-draft-release.sh, because a published release is no longer a draft, so a retry cannot quietly spend a second signature.
2026-09-06 00:48:51 +09:00

75 lines
3.4 KiB
Bash
Executable File

#!/usr/bin/env bash
# Get a passing check onto the pull request release-please just opened, and stop there.
#
# This script used to merge that pull request too, which is what made releases automatic. Releases
# are manual now: the code signing certificate has a limited number of signatures, and an automatic
# release spends one on every merge to main whether or not anybody wanted a build. Merging the
# release pull request is a deliberate human act, and building and signing the resulting draft is a
# second one (workflow_dispatch on release.yml).
#
# Getting a check onto the pull request is still automatic, and still awkward. GITHUB_TOKEN may not
# start workflows, so the pull_request run is created in action_required and never executes; a push
# to the branch does not produce a run at all. workflow_dispatch is the exception GitHub allows, so
# dispatch CI on the release branch and wait for it. The checks land on the pull request's head
# commit, which is what lets required_status_checks stay on for this repository (MSIME-Windows#121)
# without leaving the release pull request permanently unmergeable.
#
# The pull request is found by branch rather than from release-please's payload, which only reports
# a pull request as created once but rewrites that branch on every later push to main.
#
# Requires GH_TOKEN and GH_REPO.
set -euo pipefail
branch=$(gh api "repos/$GH_REPO/git/matching-refs/heads/release-please--" \
--jq '.[0].ref // empty' | sed 's|^refs/heads/||')
if [[ -z "$branch" ]]; then
echo "No release branch exists; nothing to test."
exit 0
fi
number=$(gh pr list --repo "$GH_REPO" --head "$branch" --state open --limit 1 \
--json number --jq '.[0].number // empty')
if [[ -z "$number" ]]; then
echo "Release branch $branch has no open pull request; nothing to test."
exit 0
fi
pr_json=$(gh pr view "$number" --repo "$GH_REPO" \
--json state,isDraft,headRefName,headRefOid,baseRefName)
state=$(jq -er .state <<< "$pr_json")
is_draft=$(jq -r .isDraft <<< "$pr_json")
head_branch=$(jq -er .headRefName <<< "$pr_json")
head_sha=$(jq -er .headRefOid <<< "$pr_json")
base_branch=$(jq -er .baseRefName <<< "$pr_json")
if [[ "$state" != OPEN || "$is_draft" != false || "$base_branch" != main ]]; then
echo "Release pull request #$number is not an open, non-draft pull request against main." >&2
exit 1
fi
if [[ "$head_branch" != release-please--* ]]; then
echo "Release pull request #$number has an unexpected head branch: $head_branch" >&2
exit 1
fi
echo "Dispatching CI for release pull request #$number at $head_sha"
gh workflow run ci.yml --repo "$GH_REPO" --ref "$head_branch"
# The run does not appear immediately, and gh has no way to ask for the run a dispatch created, so
# poll for one on this branch at this exact commit.
run_id=""
for _ in $(seq 1 150); do
run_id=$(gh run list --repo "$GH_REPO" --workflow ci.yml --branch "$head_branch" \
--event workflow_dispatch --limit 20 --json databaseId,headSha \
--jq "map(select(.headSha == \"$head_sha\")) | first | .databaseId // empty")
[[ -n "$run_id" ]] && break
sleep 2
done
if [[ -z "$run_id" ]]; then
echo "Timed out waiting for CI to start for release pull request #$number at $head_sha." >&2
exit 1
fi
gh run watch "$run_id" --repo "$GH_REPO" --exit-status --interval 15
echo "Release pull request #$number is green at $head_sha and ready to merge when you want a release."