Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions .github/workflows/develop-synced-dispatch.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: Dispatch develop-synced after release

on:
push:
branches:
- develop

jobs:
dispatch_develop_synced:
if: contains(github.event.head_commit.message, 'prelease version')
runs-on: ubuntu-latest
permissions:
contents: write

steps:
- name: Checkout develop
uses: actions/checkout@v4
with:
ref: develop

- name: Extract version from commit message
id: meta
env:
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
run: |
set -euo pipefail
echo "Commit message: ${COMMIT_MESSAGE}"
VERSION_WITH_V="$(echo "${COMMIT_MESSAGE}" | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' || true)"
if [ -n "${VERSION_WITH_V}" ]; then
VERSION="${VERSION_WITH_V#v}"
else
VERSION="$(echo "${COMMIT_MESSAGE}" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1 || true)"
fi
if [ -z "${VERSION}" ]; then
echo "Failed to parse version from commit message" >&2
exit 1
fi
echo "Parsed version: ${VERSION}"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"

- name: Send develop-synced repository_dispatch
uses: actions/github-script@v7
env:
VERSION: ${{ steps.meta.outputs.version }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const version = process.env.VERSION;
if (!version) {
core.setFailed('VERSION env is not set');
return;
}
core.info(`Sending repository_dispatch develop-synced for version ${version}`);
await github.rest.repos.createDispatchEvent({
owner: context.repo.owner,
repo: context.repo.repo,
event_type: 'develop-synced',
client_payload: { version }
});
207 changes: 207 additions & 0 deletions .github/workflows/post-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
name: Post release after develop synced

on:
repository_dispatch:
types: [develop-synced]

jobs:
post_release:
runs-on: ubuntu-latest

permissions:
contents: write

steps:
- name: Read version from repository_dispatch payload
id: meta
env:
PAYLOAD_VERSION: ${{ github.event.client_payload.version }}
run: |
set -euo pipefail
if [ -z "${PAYLOAD_VERSION}" ]; then
echo "No version in client_payload, skip post-release."
echo "skip=true" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "Using version from payload: ${PAYLOAD_VERSION}"
echo "version=${PAYLOAD_VERSION}" >> "$GITHUB_OUTPUT"
echo "skip=false" >> "$GITHUB_OUTPUT"

- name: Checkout main
if: steps.meta.outputs.skip != 'true'
uses: actions/checkout@v4
with:
ref: main
fetch-depth: 0
persist-credentials: false

- name: Configure git remote to use PAT
if: steps.meta.outputs.skip != 'true'
env:
GH_PAT: ${{ secrets.CREATE_TAG_RELEASE_TOKEN }}
run: |
set -euo pipefail
git remote set-url origin "https://x-access-token:${GH_PAT}@github.com/${GITHUB_REPOSITORY}.git"
git remote -v

- name: Fetch tags
if: steps.meta.outputs.skip != 'true'
run: |
set -euo pipefail
git fetch --tags --force

- name: Check existing tag and release
id: exist
if: steps.meta.outputs.skip != 'true'
env:
VERSION: ${{ steps.meta.outputs.version }}
GH_TOKEN: ${{ secrets.CREATE_TAG_RELEASE_TOKEN }}
run: |
set -euo pipefail
TAG="v${VERSION}"

if git rev-parse "refs/tags/${TAG}" >/dev/null 2>&1; then
echo "Tag ${TAG} already exists, skip post-release."
echo "skip=true" >> "$GITHUB_OUTPUT"
exit 0
fi

if gh release view "${TAG}" >/dev/null 2>&1; then
echo "Release ${TAG} already exists, skip post-release."
echo "skip=true" >> "$GITHUB_OUTPUT"
exit 0
fi

echo "skip=false" >> "$GITHUB_OUTPUT"

- name: Ensure main changelog exists
if: steps.meta.outputs.skip != 'true' && steps.exist.outputs.skip != 'true'
run: |
set -euo pipefail
if [ ! -f "docs/assets/changelog/en/release.md" ]; then
echo "Error: docs/assets/changelog/en/release.md not found in main."
exit 1
fi

- name: Extract release body from main changelog
id: body
if: steps.meta.outputs.skip != 'true' && steps.exist.outputs.skip != 'true'
env:
VERSION: ${{ steps.meta.outputs.version }}
run: |
set -euo pipefail
node <<'NODE'
const fs = require('fs');

const version = process.env.VERSION;
const changelogPath = 'docs/assets/changelog/en/release.md';
const content = fs.readFileSync(changelogPath, 'utf8');

function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

const headerPattern = new RegExp('^#\\s*v?' + escapeRegExp(version) + '\\b', 'm');
const match = headerPattern.exec(content);

if (!match) {
console.error('No changelog block for version', version, 'found in main changelog.');
process.exit(1);
}

const startIndex = match.index;
const rest = content.slice(startIndex);

// Find the next release header after the current one.
const nextHeaderPattern = /^#\s*v?\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?[^\n]*$/gm;
let nextIndex = rest.length;
let m;
while ((m = nextHeaderPattern.exec(rest)) !== null) {
if (m.index > 0) {
nextIndex = m.index;
break;
}
}

const block = rest.slice(0, nextIndex).trimEnd() + '\n';
if (!block.trim()) {
console.error('Extracted changelog block is empty for version', version);
process.exit(1);
}
fs.writeFileSync('release-body.md', block, 'utf8');
NODE
echo "has_body=true" >> "$GITHUB_OUTPUT"

- name: Validate extracted release body
if: steps.meta.outputs.skip != 'true' && steps.exist.outputs.skip != 'true' && steps.body.outputs.has_body == 'true'
env:
VERSION: ${{ steps.meta.outputs.version }}
run: |
set -euo pipefail
if [ ! -s "release-body.md" ]; then
echo "Error: release-body.md is missing or empty."
exit 1
fi

if ! grep -Eq "^#\\s*v?${VERSION}\\b" release-body.md; then
echo "Error: release-body.md does not start with expected version header v${VERSION}."
exit 1
fi

HEADER_COUNT="$(grep -Ec '^#\s*v?[0-9]+\.[0-9]+\.[0-9]+([-.][0-9A-Za-z.]+)?\b' release-body.md || true)"
if [ "${HEADER_COUNT}" -ne 1 ]; then
echo "Error: extracted release body contains ${HEADER_COUNT} release headers, expected exactly 1."
exit 1
fi

- name: Verify gh identity
if: steps.meta.outputs.skip != 'true' && steps.exist.outputs.skip != 'true' && steps.body.outputs.has_body == 'true'
env:
GH_TOKEN: ${{ secrets.CREATE_TAG_RELEASE_TOKEN }}
run: |
set -euo pipefail
gh api user -q '.login'

- name: Diagnose PAT repository permission
if: steps.meta.outputs.skip != 'true' && steps.exist.outputs.skip != 'true' && steps.body.outputs.has_body == 'true'
env:
GH_TOKEN: ${{ secrets.CREATE_TAG_RELEASE_TOKEN }}
run: |
set -euo pipefail
LOGIN=$(gh api user -q '.login')
echo "PAT user: $LOGIN"
OWNER=${GITHUB_REPOSITORY%%/*}
REPO=${GITHUB_REPOSITORY#*/}
RESP=$(gh api "/repos/$OWNER/$REPO/collaborators/$LOGIN/permission" 2>&1 || true)
echo "$RESP"
if echo "$RESP" | grep -q '404'; then
echo "Not a collaborator (404), repository access may be restricted or PAT not authorized to org"
elif echo "$RESP" | grep -q '"permission":"write"'; then
echo "permission ok: write"
elif echo "$RESP" | grep -q '"permission":"admin"'; then
echo "permission ok: admin"
else
echo "permission insufficient: $RESP"
fi

- name: Create tag and GitHub Release
if: steps.meta.outputs.skip != 'true' && steps.exist.outputs.skip != 'true' && steps.body.outputs.has_body == 'true'
env:
VERSION: ${{ steps.meta.outputs.version }}
GH_TOKEN: ${{ secrets.CREATE_TAG_RELEASE_TOKEN }}
run: |
set -euo pipefail
TAG="v${VERSION}"

git fetch origin main:refs/remotes/origin/main --depth=1
MAIN_SHA="$(git rev-parse origin/main)"

echo "Creating tag ${TAG} at ${MAIN_SHA}"
git tag "${TAG}" "${MAIN_SHA}"
git push origin "${TAG}"

echo "Creating GitHub Release ${TAG}"
gh release create "${TAG}" \
--target "main" \
--title "${TAG}" \
--notes-file "release-body.md"
51 changes: 15 additions & 36 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,21 @@ on:

jobs:
build:
runs-on: macOS-latest # 如果用了electron,记得改成 macOS-latest
runs-on: macOS-latest
permissions:
contents: write
pull-requests: write

strategy:
matrix:
node-version: [18.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/

steps:
- uses: actions/checkout@v3
- run: |
- name: Checkout
uses: actions/checkout@v3

- name: Configure git user
run: |
git config user.name ${{ github.actor }}
git config user.email ${{ github.actor }}@users.noreply.github.com

Expand All @@ -30,7 +32,6 @@ jobs:
cache: 'npm'
cache-dependency-path: './common/config/rush/pnpm-lock.yaml'

# Install rush
- name: Install rush
run: node common/scripts/install-run-rush.js install --bypass-policy

Expand All @@ -40,9 +41,9 @@ jobs:
with:
path: packages/vtable
semver_string: ${{ github.ref_name }}
semver_pattern: '^release/(.*)$' # ^v?(.*)$ by default
semver_pattern: '^release/(.*)$'

- name: update nextBump of version policies
- name: Update nextBump of version policies
uses: xile611/set-next-bump-of-rush@main
with:
release_version: ${{ steps.semver_parser.outputs.full }}
Expand All @@ -53,33 +54,24 @@ jobs:

- name: Build packages
env:
NODE_OPTIONS: "--max_old_space_size=4096"
NO_EMIT_ON_ERROR: "true"
NODE_OPTIONS: '--max_old_space_size=4096'
NO_EMIT_ON_ERROR: 'true'
run: |
# 设置环境变量确保错误信息完整输出
export NODE_OPTIONS="--max_old_space_size=4096"
export NO_EMIT_ON_ERROR="true"
# 运行构建,并将输出保存到文件
node common/scripts/install-run-rush.js build --only tag:package 2>&1 | tee build.log || {
echo "=== Build failed, showing last 1000 lines of build.log ==="
tail -n 1000 build.log
echo "=== Full error details ==="
# 尝试从日志中提取错误信息
grep -A 50 "TypeScript Compilation Errors" build.log || true
grep -A 50 "Build Error" build.log || true
exit 1
}

# - name: Run Bugserver
# working-directory: ./packages/vtable
# env:
# BUG_SERVER_TOKEN: ${{ secrets.BUG_SERVER_TOKEN }}
# run: node ../../common/scripts/install-run-rushx.js ci

- name: Publish to npm
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
NPM_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: node common/scripts/install-run-rush.js publish --publish --include-all

- name: Update shrinkwrap
Expand All @@ -91,7 +83,7 @@ jobs:
with:
path: packages/vtable

- name: Commit & Push changes
- name: Commit and push changes
uses: actions-js/push@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
Expand All @@ -104,27 +96,14 @@ jobs:
with:
version: ${{ steps.package-version.outputs.current_version }}

- name: Create Release for Tag
id: release_tag
uses: ncipollo/release-action@v1.12.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag: v${{ steps.package-version.outputs.current_version }}
commit: main
prerelease: false
body: |
${{ steps.changelog.outputs.markdown }}
draft: true #

- name: Create Pull Request
uses: dustinirving/create-pr@v1.0.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
title: '[Auto release] release ${{ steps.package-version.outputs.current_version }}'
base: main
head: ${{ github.ref_name }}
labels: release # default labels, the action will throw error if not specified
reviewers: fangsmile,Rui-Sun # default reviewers, the action will throw error if not specified
labels: release
reviewers: fangsmile,Rui-Sun
body: |
${{ steps.changelog.outputs.markdown }}
Loading
Loading