ci: two-stage release with manual approval#814
Conversation
Split the release into a manually dispatched Prepare Release workflow that bumps the version and opens a release PR, and a Release workflow that runs when the bump lands on master. Release is gated by the `release` environment (required reviewers) for manual approval, and pushes the approval prompt to DingTalk via a signed webhook before the gate.
|
Note Gemini is unable to generate a review for this pull request due to the file types involved not being currently supported. |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds a manual Prepare Release workflow that bumps package.json and opens a release PR, and revises the release pipeline to run on package.json changes, check/version-gate the run, send a signed DingTalk approval, require environment approval, re-check npm, compute dist-tags from VERSION, and create GitHub Release. ChangesRelease Automation with Manual Preparation and Approval Gating
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
commit: |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #814 +/- ##
=======================================
Coverage 94.65% 94.65%
=======================================
Files 10 10
Lines 730 730
Branches 228 228
=======================================
Hits 691 691
Misses 36 36
Partials 3 3 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
This PR reworks the project’s npm/GitHub Release process into a two-stage GitHub Actions flow: a manually-triggered “prepare” workflow that opens a version-bump PR, and an automated “release” workflow that runs on master version changes and gates publishing behind a protected release Environment.
Changes:
- Replace tag-based releasing with a
master+package.json-path triggered release workflow, including a version-change check against the published npm package. - Add a DingTalk notification step to request manual approval before publishing, and gate the publish job via the
releaseenvironment. - Add a new
Prepare Releaseworkflow to bumppackage.jsonversion and open arelease/vX.Y.Zpull request.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| .github/workflows/release.yml | Split release into check → notify → environment-gated publish/release on master version changes. |
| .github/workflows/prepare_release.yml | Add manual workflow to bump package.json and open a versioned release PR. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@cursor review |
|
@codex review |
- release: mark DingTalk notify as continue-on-error so a webhook failure cannot block reaching the manual approval gate - prepare_release: validate the version input is semver without a leading v before mutating package.json
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/prepare_release.yml:
- Around line 31-37: Validate and sanitize the incoming VERSION before mutating
package.json or using it for branch names: ensure the inputs.version matches a
safe pattern (e.g., a strict semver or at minimum disallow characters like /, &,
and quotes) and fail fast if it does not; replace the brittle sed-based
replacement in the "Bump version" step with a safe update using a JSON-aware
tool (e.g., jq) to set .version in package.json so you don't need to escape
VERSION for regex replacement; also sanitize or normalize VERSION when deriving
branch names (e.g., strip or replace unsafe characters) so the branch creation
step cannot be broken by malicious/invalid input.
- Line 41: The workflow currently references the mutable tag "uses:
peter-evans/create-pull-request@v8"; replace that tag with an immutable full
commit SHA for the peter-evans/create-pull-request action (e.g., "uses:
peter-evans/create-pull-request@<full-commit-sha>"). Find the canonical commit
SHA from the action repository (GitHub UI or git ls-remote), paste that SHA in
place of "`@v8`", and commit the change so the workflow uses a pinned, immutable
action version.
In @.github/workflows/release.yml:
- Line 26: Replace mutable action tags with immutable 40-character commit SHAs
for each uses: entry identified (EndBug/version-check@v3,
voidzero-dev/setup-vp@v1, softprops/action-gh-release@v3): locate the
corresponding GitHub repository for each action, find the commit SHA you want to
lock to (usually the SHA of the release/tag currently referenced), and update
the workflow uses value to the full commit SHA (e.g. owner/repo@<40-char-sha>)
for each of the three action references so the workflow no longer depends on
mutable tags.
- Around line 58-60: The curl POST that sends "$PAYLOAD" to "$URL" should
include connection and overall timeouts plus retries to avoid hangs: update the
curl invocation (the line invoking curl -fsS -X POST "$URL" -H 'Content-Type:
application/json' -d "$PAYLOAD" ) to add flags such as --connect-timeout 5
--max-time 15 --retry 3 --retry-delay 5 --retry-connrefused --fail (and keep
-sS/-f as desired) so transient network issues or stalls are retried and the job
times out rather than blocking downstream jobs.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: be069e22-a22a-4aa0-8bb2-766641b1f1c0
📒 Files selected for processing (2)
.github/workflows/prepare_release.yml.github/workflows/release.yml
- Pin third-party actions to commit SHAs: version-check, action-gh-release, create-pull-request (setup-vp stays @v1, consistent with other workflows) - Add connect/max timeout and retries to the DingTalk webhook curl so a stalled request cannot hang the request-approval job
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
.github/workflows/release.yml:99
- The dist-tag detection only treats prereleases with a letter-only identifier (e.g.
-beta.0) as prereleases. Sinceprepare_release.ymlallows prerelease identifiers starting with digits (e.g.1.2.3-0.1), this workflow would incorrectly publish those prereleases under thelatestdist-tag.
if echo "$VERSION" | grep -qE '-([a-zA-Z]+)'; then
# Extract pre-release identifier (e.g. "beta" from "4.10.0-beta.0")
PRE_TAG=$(echo "$VERSION" | sed -E 's/.*-([a-zA-Z]+).*/\1/')
echo "tag=$PRE_TAG" >> "$GITHUB_OUTPUT"
else
echo "tag=latest" >> "$GITHUB_OUTPUT"
fi
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0bbd10ac0a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
workflow_dispatch can be launched from any ref; pin the checkout to master so the release branch and version bump always start from the PR base.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
.github/workflows/release.yml (2)
93-99:⚠️ Potential issue | 🟠 Major | ⚡ Quick winDon't let unsupported prerelease formats fall back to
latest.
prepare_release.ymlaccepts prerelease suffixes matching[0-9A-Za-z.]+, but this parser only recognizes alphabetic identifiers. Versions such as4.10.0-1or4.10.0-0.beta.1would hit theelsebranch and publish under thelatestdist-tag. Either reject unsupported prerelease shapes here or derive the tag from any-*suffix before defaulting tolatest.Suggested fix
- name: Determine npm dist-tag id: dist-tag run: | - if echo "$VERSION" | grep -qE '-([a-zA-Z]+)'; then - # Extract pre-release identifier (e.g. "beta" from "4.10.0-beta.0") - PRE_TAG=$(echo "$VERSION" | sed -E 's/.*-([a-zA-Z]+).*/\1/') + if [[ "$VERSION" == *-* ]]; then + # Extract the first prerelease identifier (e.g. "beta" from "4.10.0-beta.0") + PRE_TAG=${VERSION#*-} + PRE_TAG=${PRE_TAG%%.*} + if [[ -z "$PRE_TAG" || "$PRE_TAG" =~ ^[0-9] ]]; then + echo "::error::Unsupported prerelease tag in $VERSION" + exit 1 + fi echo "tag=$PRE_TAG" >> "$GITHUB_OUTPUT" else echo "tag=latest" >> "$GITHUB_OUTPUT" fi🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/release.yml around lines 93 - 99, The prerelease detection only matches alphabetic identifiers; change the check to detect any hyphenated prerelease suffix that matches [0-9A-Za-z.]+ and extract it into PRE_TAG from VERSION (e.g. use a regex like -([0-9A-Za-z.]+)$ with sed -E 's/.*-([0-9A-Za-z.]+)$/\1/'), then echo "tag=$PRE_TAG" to GITHUB_OUTPUT; keep the existing else branch to emit "tag=latest" for everything else. Ensure you update the conditional that currently examines VERSION and the PRE_TAG extraction so the variable PRE_TAG holds the full allowed prerelease token (and not just alphabetic chars).
25-30:⚠️ Potential issue | 🟠 MajorFix npm version gating and dist-tag derivation in release workflow
.github/workflows/release.ymlusesEndBug/version-checkagainsthttps://unpkg.com/urllib@latest/package.json, which only reflects the currentlatestdist-tag; it won’t detect re-releases of a version already published under another dist-tag (so the publish job can still reachnpm publishand fail with “version already exists”)..github/workflows/release.ymlderives the npm dist-tag withgrep -qE '-([a-zA-Z]+)'andsed ... 's/.*-([a-zA-Z]+).*/\1/', but.github/workflows/prepare_release.ymlallows prerelease suffixes matching(-[0-9A-Za-z.]+)?. Valid prereleases likex.y.z-123would be treated aslatest(and not marked prerelease), and identifiers likebeta.1would be truncated to justbeta.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/release.yml around lines 25 - 30, Replace the EndBug/version-check invocation that points at unpkg (the file-url using https://unpkg.com/urllib@latest/package.json) with a registry-based lookup so the check sees all published versions (e.g., query the npm registry metadata for the package instead of the unpkg latest package.json), and adjust the version-check inputs so it detects if the candidate version already exists under any dist-tag; additionally replace the brittle dist-tag extraction that uses grep -qE '-([a-zA-Z]+)' and sed 's/.*-([a-zA-Z]+).*/\1/' with a robust prerelease extractor that matches the full prerelease identifier per prepare_release.yml's allowed pattern ((-[0-9A-Za-z.]+)?), for example using a shell regex like if [[ "$VERSION" =~ -([0-9A-Za-z.]+)$ ]]; then TAG="${BASH_REMATCH[1]}"; else TAG=latest; fi so tags like 123, beta.1, or rc.2 are preserved intact and numeric-only prereleases aren’t misclassified as latest.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In @.github/workflows/release.yml:
- Around line 93-99: The prerelease detection only matches alphabetic
identifiers; change the check to detect any hyphenated prerelease suffix that
matches [0-9A-Za-z.]+ and extract it into PRE_TAG from VERSION (e.g. use a regex
like -([0-9A-Za-z.]+)$ with sed -E 's/.*-([0-9A-Za-z.]+)$/\1/'), then echo
"tag=$PRE_TAG" to GITHUB_OUTPUT; keep the existing else branch to emit
"tag=latest" for everything else. Ensure you update the conditional that
currently examines VERSION and the PRE_TAG extraction so the variable PRE_TAG
holds the full allowed prerelease token (and not just alphabetic chars).
- Around line 25-30: Replace the EndBug/version-check invocation that points at
unpkg (the file-url using https://unpkg.com/urllib@latest/package.json) with a
registry-based lookup so the check sees all published versions (e.g., query the
npm registry metadata for the package instead of the unpkg latest package.json),
and adjust the version-check inputs so it detects if the candidate version
already exists under any dist-tag; additionally replace the brittle dist-tag
extraction that uses grep -qE '-([a-zA-Z]+)' and sed 's/.*-([a-zA-Z]+).*/\1/'
with a robust prerelease extractor that matches the full prerelease identifier
per prepare_release.yml's allowed pattern ((-[0-9A-Za-z.]+)?), for example using
a shell regex like if [[ "$VERSION" =~ -([0-9A-Za-z.]+)$ ]]; then
TAG="${BASH_REMATCH[1]}"; else TAG=latest; fi so tags like 123, beta.1, or rc.2
are preserved intact and numeric-only prereleases aren’t misclassified as
latest.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: f94e7782-7100-4604-a5b5-c6ba976727ac
📒 Files selected for processing (2)
.github/workflows/prepare_release.yml.github/workflows/release.yml
🚧 Files skipped from review as they are similar to previous changes (1)
- .github/workflows/prepare_release.yml
- Check whether the exact version is already published on npm instead of comparing against urllib@latest, so a prerelease under its own dist-tag is not treated as perpetually newer than latest and re-released - Add workflow concurrency (cancel-in-progress) to cancel an older run still pending approval when a newer version lands - Re-check publication state immediately before npm publish as a guard against a stale run approved after a newer version was published
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/release.yml:
- Around line 31-46: The npm view check using npm view "urllib@$VERSION" version
currently treats any non-zero exit as “not published”; change it to capture npm
view's stdout/stderr and exit code, and only treat the result as “missing” when
the output/stderr clearly indicates a 404/not-found for that exact version (e.g.
messages containing "404", "Not Found", "No matching version", or similar); for
any other non-zero exit (auth, network, registry errors) fail the job with exit
1 so the workflow doesn't continue. Apply this change to the existing npm view
invocations that use VERSION (the command npm view "urllib@$VERSION" version and
the step that sets VERSION) so they inspect the error output and branch on
not-found vs fatal errors accordingly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 1bedf3bf-3205-4cf3-a43b-a453d05cb49a
📒 Files selected for processing (1)
.github/workflows/release.yml
…ling - prepare_release: use POSIX [[:space:]] instead of \s in the sed so the version line matches reliably across sed implementations - release: derive dist-tag from any pre-release identifier (including numeric, e.g. 1.2.3-0), stripping build metadata, so prereleases are never published to latest - release: treat npm view non-zero exits as "not published" only on a genuine E404; fail the job on auth/network/registry errors instead of assuming the version is missing
- Capture npm view exit code with `STATUS=0; OUTPUT=$(...) || STATUS=$?` instead of toggling set +e/set -e, and grep the output via here-string - Merge the prepare-release validate and bump steps into one, dropping the duplicated env and set -euo pipefail boilerplate No behavior change.
Brings the 4.x maintenance branch onto the same release flow as master (#814), so every line releases the same way. **Flow:** run **Prepare Release** (manual, with a version) -> it opens a `release/vX.Y.Z` PR -> merge it -> **Release** checks the version against npm, pushes an approval request to DingTalk, waits on the `release` environment gate, then publishes and creates the GitHub Release. **4.x specifics:** - Publishes under dist-tag `latest-4` (never `latest`). - Builds via the Vite+ (`vp`) toolchain. - Replaces the previous tag-based `release.yml`. - npm auth via OIDC trusted publishing (`id-token: write`). Requires the repo `release` environment (required reviewers) and npm trusted-publisher config to allow this branch's workflow. DingTalk secrets are already set repo-wide.
Brings the 3.x maintenance branch onto the same release flow as master (#814), so every line releases the same way. **Flow:** run **Prepare Release** (manual, with a version) -> it opens a `release/vX.Y.Z` PR -> merge it -> **Release** checks the version against npm, pushes an approval request to DingTalk, waits on the `release` environment gate, then publishes and creates the GitHub Release. **3.x specifics:** - Publishes under dist-tag `latest-3` (never `latest`). - Builds via tshy (npm `prepublishOnly`) on Node 22. - Replaces the previous shared `node-release` reusable workflow. - npm auth via OIDC trusted publishing (`id-token: write`). Requires the repo `release` environment (required reviewers) and npm trusted-publisher config to allow this branch's workflow. DingTalk secrets are already set repo-wide.
Brings the 2.x maintenance branch onto the same release flow as master (#814), so every line releases the same way. **Flow:** run **Prepare Release** (manual, with a version) -> it opens a `release/vX.Y.Z` PR -> merge it -> **Release** checks the version against npm, pushes an approval request to DingTalk, waits on the `release` environment gate, then publishes and creates the GitHub Release. **2.x specifics:** - Publishes under dist-tag `latest-2` (never `latest`). - Publishes `lib/` directly (no build step). - Replaces the previous shared `node-release` reusable workflow. - npm auth via OIDC trusted publishing (`id-token: write`). Requires the repo `release` environment (required reviewers) and npm trusted-publisher config to allow this branch's workflow. DingTalk secrets are already set repo-wide.
Reworks the release into two workflows, modeled on vite-plus, with the final publish gated by manual approval.
prepare_release.yml: manualworkflow_dispatchwith aversioninput. Bumpspackage.jsonand opens arelease/vX.Y.ZPR.release.yml: triggers when the version lands onmaster.checkconfirms the version actually changed vs npm,request-approvalpushes the approval prompt to DingTalk (signed webhook), thenreleasepublishes to npm and creates the GitHub Release.Manual approval is enforced by the
releaseenvironment gate. Setup needed before first use: create an Environment namedreleasewith required reviewers. SecretsDINGTALK_RELEASE_WEBHOOK_URLandDINGTALK_RELEASE_WEBHOOK_SECRETare already configured.Release flow: run Prepare Release -> merge the PR -> approve the
releaseenvironment -> publish.Summary by CodeRabbit