Skip to content
Merged
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
58 changes: 58 additions & 0 deletions .github/workflows/ci-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: PR CI (tests & build)

on:
pull_request:
branches:
- main
- dev

permissions:
contents: read

# 使用 PR 的 head SHA 作为并发组,确保同一 PR 的多次推送会取消之前的运行
concurrency:
group: pr-${{ github.event.pull_request.head.sha }}
cancel-in-progress: true

jobs:
pr-checks:
name: Test and Build
runs-on: ubuntu-latest
steps:
# 拉取代码
- name: Checkout
uses: actions/checkout@v4

# 设置 Node.js 20 并启用 yarn 缓存
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: yarn

# 安装依赖(使用 frozen-lockfile 确保一致性)
- name: Install dependencies
run: |
corepack enable
yarn --version
yarn install --frozen-lockfile

# 运行 lint 检查
- name: Run lint
run: |
yarn lint

# 运行单元测试
- name: Run unit tests
run: |
yarn test

# 构建项目(库 + 类型定义)
- name: Build (lib + types)
run: |
yarn build:all

# 验证 npm pack 是否正常(干运行)
- name: Verify npm pack (dry-run)
run: |
npm pack --dry-run
112 changes: 112 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
name: Publish to npm (version branches)

on:
push:
branches:
- 'version/[0-9]+.[0-9]+.[0-9]+'
- 'version/[0-9]+.[0-9]+.[0-9]+-**'

permissions:
contents: read

jobs:
publish:
name: Build and Publish
runs-on: ubuntu-latest
steps:
# 拉取代码(需要完整历史以解析版本)
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

# 解析分支类型并设定 npm dist-tag
# 支持三种标签:latest(正式版)、dev(开发预发布)、beta(测试预发布)
- name: Classify branch and prepare env
run: |
BRANCH="${GITHUB_REF#refs/heads/}"
echo "Detected branch: $BRANCH"

# 从分支名称提取版本号:version/1.0.0 -> 1.0.0
VERSION="${BRANCH#version/}"
echo "VERSION=$VERSION" >> "$GITHUB_ENV"

# 根据 package.json 的 version 判断是否为预发布版本
PKG_VERSION=$(node -e "console.log(JSON.parse(require('fs').readFileSync('package.json','utf8')).version)")

if [[ "$PKG_VERSION" =~ -dev ]]; then
echo "PUBLISH_TAG=dev" >> "$GITHUB_ENV"
echo "Version type: Dev Pre-release"
elif [[ "$PKG_VERSION" =~ -beta ]]; then
echo "PUBLISH_TAG=beta" >> "$GITHUB_ENV"
echo "Version type: Beta Pre-release"
else
echo "PUBLISH_TAG=latest" >> "$GITHUB_ENV"
echo "Version type: Release"
fi

echo "Branch version: $VERSION"
echo "Package version: $PKG_VERSION"
echo "Publish tag: $PUBLISH_TAG"

# 安装 Node,并配置 npm registry(用于 npm publish 鉴权)
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
registry-url: https://registry.npmjs.org
cache: yarn

# 使用 Yarn 安装依赖(项目包含 yarn.lock)
- name: Install dependencies
run: |
corepack enable
yarn --version
yarn install --frozen-lockfile

# 读取 package.json 的 name 与 version,并检查该版本是否已发布
# 已发布则跳过后续发布步骤,避免重复发布导致失败
- name: Check if version already published
id: version
shell: bash
run: |
PKG_NAME=$(node -e "console.log(JSON.parse(require('fs').readFileSync('package.json','utf8')).name)")
VERSION=$(node -e "console.log(JSON.parse(require('fs').readFileSync('package.json','utf8')).version)")
echo "Package: $PKG_NAME"
echo "Version: $VERSION"
if npm view "$PKG_NAME@$VERSION" version > /dev/null 2>&1; then
echo "should_publish=false" >> "$GITHUB_OUTPUT"
echo "Version $VERSION already exists on npm, skip publishing."
else
echo "should_publish=true" >> "$GITHUB_OUTPUT"
echo "Version $VERSION not found on npm, will publish."
fi

# 构建项目(npm publish 会触发 prepublishOnly,其中也会执行构建,但这里提前构建以暴露错误)
- name: Build project
if: steps.version.outputs.should_publish == 'true'
run: |
yarn build:all

# 发布到 npm。latest/dev/beta 分别使用对应的 dist-tag
# 需要在项目 Secrets 配置 NPM_TOKEN(具有发布权限的 npm 令牌)
- name: Publish to npm
if: steps.version.outputs.should_publish == 'true'
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
# 使用 npm publish 以触发 prepublishOnly(包含构建),并指定 tag 与访问级别
npm publish --tag "$PUBLISH_TAG" --access public

# 确保预发布标签的 dist-tag 指向当前 version(支持 dev 和 beta)
- name: Ensure pre-release dist-tag
if: (env.PUBLISH_TAG == 'dev' || env.PUBLISH_TAG == 'beta') && steps.version.outputs.should_publish == 'true'
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
PKG_NAME=$(node -e "console.log(JSON.parse(require('fs').readFileSync('package.json','utf8')).name)")
VERSION=$(node -e "console.log(JSON.parse(require('fs').readFileSync('package.json','utf8')).version)")
echo "Ensure dist-tag: ${PUBLISH_TAG} -> $VERSION"
# 若版本已存在,也可重复设置 tag;若已指向则不变
npm dist-tag add "$PKG_NAME@$VERSION" "$PUBLISH_TAG" || true
npm dist-tag ls "$PKG_NAME"
116 changes: 116 additions & 0 deletions .github/workflows/sync-master-to-dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
name: Sync master to dev

# 触发条件:
# 1. 直接推送到 master/main 分支
# 2. 向 master/main 分支发起 PR(opened/synchronize/reopened 事件)
on:
push:
branches:
- master
- main
pull_request:
branches:
- master
- main
types: [opened, synchronize, reopened]

permissions:
contents: write
pull-requests: write

# 使用固定并发组,确保同步操作不会并行执行
concurrency:
group: sync-master-to-dev
cancel-in-progress: false

jobs:
sync:
# 仅在以下情况执行:
# - 非 PR 事件(即直接推送)
# - PR 来自同一仓库(非 fork)
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
name: Merge master/main into dev
runs-on: ubuntu-latest
steps:
# 拉取完整 git 历史(合并需要)
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

# 配置 git 用户信息(用于自动提交)
- name: Configure Git user
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"

# 获取所有远程分支
- name: Fetch branches
run: |
git remote set-url origin "${{ github.server_url }}/${{ github.repository }}.git"
git fetch origin --prune
git fetch origin dev || true

# 检测源分支(推送事件取当前分支,PR 事件取 base 分支)
- name: Detect source branch
id: detect
shell: bash
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
SOURCE_BRANCH="${{ github.base_ref }}"
else
SOURCE_BRANCH="${GITHUB_REF#refs/heads/}"
fi

if [ -z "$SOURCE_BRANCH" ]; then
echo "::error::Unable to determine source branch."
exit 1
fi

if ! git ls-remote --exit-code --heads origin "$SOURCE_BRANCH" >/dev/null 2>&1; then
echo "::error::Source branch '$SOURCE_BRANCH' does not exist on origin."
exit 1
fi

echo "name=$SOURCE_BRANCH" >> "$GITHUB_OUTPUT"

# 检出 dev 分支(如果不存在则基于源分支创建)
- name: Checkout dev branch (create if missing)
shell: bash
run: |
if git ls-remote --exit-code --heads origin dev >/dev/null 2>&1; then
git checkout -B dev origin/dev
else
echo "dev branch does not exist on origin, creating it based on ${{ steps.detect.outputs.name }}"
git checkout -B dev "origin/${{ steps.detect.outputs.name }}"
git push -u origin dev
fi

# 将源分支合并到 dev
- name: Merge source branch into dev
shell: bash
run: |
set -e
BASE_BRANCH="${{ steps.detect.outputs.name }}"
echo "Merging origin/${BASE_BRANCH} into dev..."
git fetch origin "$BASE_BRANCH"

if git merge --no-edit "origin/${BASE_BRANCH}"; then
echo "Merge succeeded."
else
echo "::error::Merge conflict when merging ${BASE_BRANCH} into dev. Please resolve conflicts manually."
git merge --abort || true
exit 1
fi

# 推送更新到 dev(如果有新的提交)
- name: Push changes to dev (if any)
shell: bash
run: |
if [ -n "$(git log --oneline origin/dev..HEAD)" ]; then
echo "Pushing updates to origin/dev..."
git push origin dev
else
echo "No updates needed. dev is already up to date with ${{ steps.detect.outputs.name }}"
fi
Loading