🔧 chore(workflows): migrate to prepare + worktree model and merge checks

- add prepare.yml: install tools + maintain shared bare repo, anchors the workflow_run chain
- add checks.yml: merge lint + full test suite into a single workflow_run consumer job
- remove standards-check.yml and test.yml (superseded by checks.yml)
- convert sync-tsl-playbook and update-thirdparty-skills to worktree-model consumers
- unify workflow/job/step display names and emoji
This commit is contained in:
csh
2026-07-21 17:29:24 +08:00
parent 49e6dadc60
commit d83707de23
7 changed files with 600 additions and 267 deletions
+157
View File
@@ -0,0 +1,157 @@
name: 🔎 校验
on:
workflow_run:
workflows: ["🧰 准备环境"]
types:
- completed
concurrency:
group: checks-${{ github.repository }}-${{ github.event.workflow_run.head_sha }}
cancel-in-progress: true
# ==========================================
# 🔧 配置区域 - 校验参数
# ==========================================
env:
# Prepare 完成后经 workflow_run 触发;Prepare 已装工具 + fetch 到共享 bare 仓库。
# 本 workflow 只做只读校验(lint + 测试),不推任何分支,故 token 仅用于
# 极端情况下补取缺失提交(正常路径 Prepare 已 fetch 到位)。
#
# 安全:ACCESS_TOKEN 不放在 workflow 级 env。lint/test 步骤会执行上游提交
# (PR 场景为不受信输入)的脚本,其环境里不应出现 token;仅下放到
# prepare_worktree 步骤。
WORKSPACE_ROOT: "/data/workspace"
SOURCE_BRANCH: ${{ github.event.workflow_run.head_branch }}
SOURCE_SHA: ${{ github.event.workflow_run.head_sha }}
SOURCE_EVENT: ${{ github.event.workflow_run.event }}
COMMIT_LINT_REQUIRE_EMOJI: "1"
jobs:
checks:
# 仅在 Prepare 成功后触发。Prepare 覆盖 push(main) / pull_request /
# schedule / dispatch,故 checks 在这些场景均会运行。
# lint 与 test 合并为单 job:共用一个临时 worktree,准备一次,顺序执行
# lint 在前 fail-fast,失败即不跑 test)。二者跑同一 SOURCE_SHA、皆只读、
# 无依赖,无需拆分为并行 job(那会重复整段 worktree 准备逻辑 + 多一个 worktree)。
if: ${{ github.event.workflow_run.conclusion == 'success' }}
name: 🔎 规范检查 + 全量测试
runs-on: standard-ubuntu-22
permissions:
contents: read
steps:
- name: 📥 准备临时 Worktree
id: prepare_worktree
shell: bash
env:
ACCESS_TOKEN: ${{ secrets.WORKFLOW }}
run: |
set -euo pipefail
REPO_NAME="${{ github.event.repository.name }}"
HEAD_SHA="${SOURCE_SHA}"
REPOSITORY_DIR="${WORKSPACE_ROOT}/${REPO_NAME}/repository.git"
WORKTREE_DIR="${WORKSPACE_ROOT}/${REPO_NAME}/worktrees/checks-${{ github.run_id }}-${{ github.run_attempt }}"
WORKTREE_LOCK="${WORKSPACE_ROOT}/${REPO_NAME}/worktree-admin.lock"
case "$HEAD_SHA" in
''|*[!0-9a-fA-F]*)
echo "无效的上游提交 SHA: $HEAD_SHA" >&2
exit 1
;;
esac
if [ ! -d "$REPOSITORY_DIR" ] || \
[ "$(git --git-dir="$REPOSITORY_DIR" rev-parse --is-bare-repository 2>/dev/null)" != "true" ]; then
echo "Prepare 未创建有效共享 bare 仓库: $REPOSITORY_DIR" >&2
exit 1
fi
# 正常路径 Prepare 已把上游提交 fetch 到位;极端情况下(bare 仓库被清理
# 重建、或 Prepare 与本 run 之间发生 prune)补取一次,token 仅用于此。
if ! git --git-dir="$REPOSITORY_DIR" cat-file -e "${HEAD_SHA}^{commit}" 2>/dev/null; then
git \
-c credential.helper= \
-c 'credential.helper=!f() { test "$1" = get || exit 0; printf "%s\n" username=oauth2; printf "%s\n" "password=${ACCESS_TOKEN}"; }; f' \
-c credential.interactive=never \
--git-dir="$REPOSITORY_DIR" fetch --prune --force origin \
'+refs/heads/*:refs/remotes/origin/*' || true
fi
if ! git --git-dir="$REPOSITORY_DIR" cat-file -e "${HEAD_SHA}^{commit}"; then
echo "共享仓库中不存在上游提交: $HEAD_SHA(事件: $SOURCE_EVENT" >&2
exit 1
fi
exec 9>"$WORKTREE_LOCK"
flock 9
# 回收陈旧临时 worktree(超过 24h 的 checks-* 目录)。worktree prune 只清理
# 指向已消失目录的 metadata,不删仍存在的陈旧目录,故按 mtime 主动回收。
worktrees_root="$(dirname "$WORKTREE_DIR")"
if [ -d "$worktrees_root" ]; then
find "$worktrees_root" -mindepth 1 -maxdepth 1 -type d -name 'checks-*' \
-mmin +1440 -print 2>/dev/null | while IFS= read -r stale; do
[ "$stale" = "$WORKTREE_DIR" ] && continue
git --git-dir="$REPOSITORY_DIR" worktree remove --force "$stale" 2>/dev/null || rm -rf "$stale"
done
fi
git --git-dir="$REPOSITORY_DIR" worktree prune
if [ -e "$WORKTREE_DIR" ]; then
git --git-dir="$REPOSITORY_DIR" worktree remove --force "$WORKTREE_DIR" 2>/dev/null || rm -rf "$WORKTREE_DIR"
fi
mkdir -p "$(dirname "$WORKTREE_DIR")"
git --git-dir="$REPOSITORY_DIR" worktree add --detach "$WORKTREE_DIR" "$HEAD_SHA"
flock -u 9
git -C "$WORKTREE_DIR" reset --hard "$HEAD_SHA"
git -C "$WORKTREE_DIR" clean -ffdx
echo "REPOSITORY_DIR=$REPOSITORY_DIR" >> "$GITHUB_ENV"
echo "REPO_DIR=$WORKTREE_DIR" >> "$GITHUB_ENV"
echo "✅ Worktree 就绪: $WORKTREE_DIR @ $HEAD_SHA"
- name: 🔍 校验提交信息
shell: bash
run: |
set -euo pipefail
cd "$REPO_DIR"
# 注:经 workflow_run 触发,事件 payload 为 workflow_run,不含 PR title
# lint 脚本会回落到 head commit message 校验(PR 标题本身不再校验)。
echo "🔍 检查 commit message 规范(上游事件: $SOURCE_EVENT..."
python3 .gitea/ci/commit_message_lint.py
echo "✅ Lint 检查通过"
- name: 🧪 运行全量测试
shell: bash
run: |
set -euo pipefail
echo "========================================"
echo "🐍 Python 测试(上游事件: $SOURCE_EVENT"
echo "========================================"
cd "$REPO_DIR"
echo "📋 覆盖:CLI、subtree/snapshot 部署路线、模板同步、文档一致性"
python3 -m unittest discover -s test -p "test_*.py" -v
echo "✅ Python 测试通过"
echo "========================================"
echo "🔗 文档链接检查"
echo "========================================"
python3 test/integration/check_doc_links.py
echo "✅ 文档链接检查通过"
echo "🎉 所有测试完成"
- name: 🧹 清理临时 Worktree
if: always()
shell: bash
run: |
set -uo pipefail
[ -n "${REPOSITORY_DIR:-}" ] || exit 0
[ -n "${REPO_DIR:-}" ] || exit 0
WORKTREE_LOCK="$(dirname "$REPOSITORY_DIR")/worktree-admin.lock"
exec 9>"$WORKTREE_LOCK"
flock 9
git --git-dir="$REPOSITORY_DIR" worktree remove --force "$REPO_DIR" 2>/dev/null || rm -rf "$REPO_DIR"
git --git-dir="$REPOSITORY_DIR" worktree prune
flock -u 9