Files
nexu-io__open-design/.github/workflows/cut-release.yml
Ray Xi 7ecd35a746 fix(release): guard automated release trains (#6729)
* fix(release): guard automated release trains

* fix(release): resolve beta recovery before checkout

* style(release): group workflow outputs

* fix(release): publish daily beta snapshots without promotion
2026-08-11 06:06:53 +00:00

162 lines
6.8 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: cut-release
# Every Tuesday 09:00 Asia/Shanghai, cut the next minor release branch from main:
# 1. Compute version (highest release/vX.Y.Z -> bump minor -> X.(Y+1).0; e.g. 0.11.0 -> 0.12.0)
# 2. Create release/vX.Y.Z from main, bump apps/packaged/package.json, push
# 3. Create the "backport release/vX.Y.Z" label
# The independent main prerelease Windows canary remains an advisory signal: its
# smoke result is notified separately and never blocks a branch cut or package.
# The push uses the App token (not GITHUB_TOKEN), so it triggers notify-release-feishu
# -> builds a nightly package and posts the Feishu card.
on:
schedule:
- cron: '0 1 * * 2' # 01:00 UTC = 09:00 Asia/Shanghai, Tuesday
workflow_dispatch:
inputs:
version:
description: 'Full version x.y.z (empty = bump minor of the highest release branch)'
required: false
default: ''
permissions:
contents: read # branch/label writes still go through the App token below
jobs:
cut:
if: github.repository == 'nexu-io/open-design'
runs-on: ubuntu-latest
steps:
- uses: actions/create-github-app-token@v2
id: app
with:
app-id: ${{ secrets.RELEASE_BOT_APP_ID }}
private-key: ${{ secrets.RELEASE_BOT_PRIVATE_KEY }}
- uses: actions/checkout@v4
with:
# Smoke is advisory; release cuts always use the current main tip.
ref: main
fetch-depth: 0
token: ${{ steps.app.outputs.token }}
- uses: actions/setup-node@v4
with:
node-version: 24
- name: Compute next version
id: ver
env:
# Never interpolate the raw input into the shell; pass via env and validate.
INPUT_VERSION: ${{ inputs.version }}
run: |
set -euo pipefail
latest=""
if [ -n "$INPUT_VERSION" ]; then
# Strict x.y.z, digits only — rejects shell metacharacters, newlines, etc.
if ! printf '%s' "$INPUT_VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "::error::Invalid version '$INPUT_VERSION' (expected x.y.z, digits only)"
exit 1
fi
V="$INPUT_VERSION"
else
latest=$(git ls-remote --heads origin 'release/v*' \
| sed -E 's#.*/release/v##' \
| grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' \
| sort -t. -k1,1n -k2,2n -k3,3n | tail -1)
major=${latest%%.*}; rest=${latest#*.}; minor=${rest%%.*}
V="${major}.$((minor+1)).0"
fi
# V is now guaranteed to match ^[0-9]+\.[0-9]+\.[0-9]+$
{
echo "version=$V"
echo "branch=release/v$V"
echo "latest_release=$latest"
} >> "$GITHUB_OUTPUT"
echo "Cutting v$V (branch release/v$V)"
- name: Check the current release line is published
id: gate
env:
GH_TOKEN: ${{ steps.app.outputs.token }}
GITHUB_EVENT_NAME: ${{ github.event_name }}
LATEST_RELEASE: ${{ steps.ver.outputs.latest_release }}
run: |
set -euo pipefail
if [ "$GITHUB_EVENT_NAME" != "schedule" ]; then
echo "ready=true" >> "$GITHUB_OUTPUT"
echo "Manual cut requested; published-line guard does not apply."
exit 0
fi
published="$(gh release view "open-design-v$LATEST_RELEASE" \
--repo nexu-io/open-design \
--json isDraft,isPrerelease \
--jq '(.isDraft or .isPrerelease) | not' 2>/dev/null || true)"
if [ "$published" != "true" ]; then
echo "ready=false" >> "$GITHUB_OUTPUT"
echo "Scheduled cut skipped: release/v$LATEST_RELEASE has not been published stable." | tee -a "$GITHUB_STEP_SUMMARY"
exit 0
fi
echo "ready=true" >> "$GITHUB_OUTPUT"
echo "release/v$LATEST_RELEASE is published stable; scheduled cut may proceed."
- name: Bail out if the branch already exists
if: steps.gate.outputs.ready == 'true'
env:
BRANCH: ${{ steps.ver.outputs.branch }}
run: |
set -euo pipefail
if git ls-remote --exit-code --heads origin "$BRANCH" >/dev/null 2>&1; then
echo "::error::$BRANCH already exists, skipping"
exit 1
fi
- name: Create branch + bump version + push
if: steps.gate.outputs.ready == 'true'
env:
VERSION: ${{ steps.ver.outputs.version }}
BRANCH: ${{ steps.ver.outputs.branch }}
run: |
set -euo pipefail
git config user.name 'open-design-release-bot[bot]'
git config user.email 'open-design-release-bot[bot]@users.noreply.github.com'
git switch -c "$BRANCH"
( cd apps/packaged && npm pkg set version="$VERSION" )
git commit -am "chore(release): v$VERSION"
git push origin "$BRANCH" # App token push -> triggers notify-release-feishu (nightly + Feishu)
- name: Create backport label
if: steps.gate.outputs.ready == 'true'
env:
GH_TOKEN: ${{ steps.app.outputs.token }}
VERSION: ${{ steps.ver.outputs.version }}
run: |
set -euo pipefail
gh label create "backport release/v$VERSION" \
--repo nexu-io/open-design \
--color 0E8A16 \
--description "Backport this fix to release/v$VERSION" \
--force
# Post an immediate "branch cut" card so the team is notified the moment the
# release branch exists, without waiting ~20-40 min for notify-release-feishu
# to finish the prerelease build. The download card still follows from that
# build. feishu-notice.ts only imports node:crypto, so the setup-node above
# is all it needs.
- name: Notify Feishu that the branch was cut
if: steps.gate.outputs.ready == 'true'
env:
FEISHU_WEBHOOK: ${{ secrets.FEISHU_RELEASE_WEBHOOK }}
FEISHU_SIGN_SECRET: ${{ secrets.FEISHU_RELEASE_SIGN_SECRET }}
NOTICE_TITLE: "🌿 已切出 release 分支 v${{ steps.ver.outputs.version }}(大版本 minor)"
NOTICE_TEMPLATE: "green"
NOTICE_BODY: |
**分支**:[`release/v${{ steps.ver.outputs.version }}`](${{ github.server_url }}/${{ github.repository }}/tree/release/v${{ steps.ver.outputs.version }})(从 main 切出,大版本 / minor)
**Backport label**:`backport release/v${{ steps.ver.outputs.version }}` —— 要回灌到这个版本的修复,给 PR 打这个 label。
Prerelease 打包已开始(约 20–40 分钟);完成后会再发一张带各平台下载链接的卡片。
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: node --experimental-strip-types tools/release/src/notifications/feishu-notice.ts