🔧 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
+212
View File
@@ -0,0 +1,212 @@
name: 🧰 准备环境
on:
push:
# 主分支:下游 sync / thirdparty 消费者只关心 main。
# 其它分支(含 ci bot 推送的 tsl-playbook / thirdparty/skill 分支)跑 Prepare 纯属空耗,故在此过滤。
branches:
- main
pull_request:
# PR:为下游 checks 消费者(standards + tests)预备 bare 仓库。
# PR 的 github.sha 是 Gitea 生成的 merge commit,不在 refs/heads/*
# 故下面的 fetch 额外取 PR ref 并按事件类型选校验目标。
branches:
- main
workflow_dispatch:
schedule:
# thirdparty 快照每日轮询:Prepare 定时成功后,update-thirdparty-skills 通过 workflow_run 触发。
- cron: "17 3 * * *"
concurrency:
group: prepare-${{ github.repository }}
cancel-in-progress: false
env:
ACCESS_TOKEN: ${{ secrets.WORKFLOW }}
WORKSPACE_ROOT: "/data/workspace"
jobs:
prepare:
runs-on: standard-ubuntu-22
permissions:
contents: read
steps:
- name: 🔧 检查并安装共享工具
id: tools
shell: bash
run: |
set -euo pipefail
declare -A package_for=(
[git]="git"
[python3]="python3"
[curl]="curl"
[flock]="util-linux"
[realpath]="coreutils"
)
required_commands=(git python3 curl flock realpath)
missing_commands=()
missing_packages=()
declare -A seen_packages=()
for command in "${required_commands[@]}"; do
if ! command -v "$command" >/dev/null 2>&1; then
package="${package_for[$command]}"
missing_commands+=("$command")
if [[ -z "${seen_packages[$package]+x}" ]]; then
missing_packages+=("$package")
seen_packages[$package]=1
fi
fi
done
installed=false
if [ "${#missing_packages[@]}" -gt 0 ]; then
echo "缺失命令: ${missing_commands[*]}"
echo "准备安装: ${missing_packages[*]}"
if [ "$(id -u)" -eq 0 ]; then
APT=(apt-get)
elif command -v sudo >/dev/null 2>&1; then
APT=(sudo apt-get)
else
echo "无法安装缺失命令;当前用户不是 root 且没有 sudo" >&2
echo "命令: ${missing_commands[*]}" >&2
echo "包: ${missing_packages[*]}" >&2
exit 1
fi
"${APT[@]}" update -qq
"${APT[@]}" install -y -qq "${missing_packages[@]}"
installed=true
fi
for command in "${required_commands[@]}"; do
if ! command -v "$command" >/dev/null 2>&1; then
echo "安装后仍找不到命令: $command (${package_for[$command]})" >&2
exit 1
fi
done
{
echo "## Prepare 环境"
echo ""
echo "| 命令 | 版本 |"
echo "| --- | --- |"
for command in "${required_commands[@]}"; do
version_output=$("$command" --version 2>&1 || true)
version_line=${version_output%%$'\n'*}
version_line=${version_line//|/\\|}
printf '| `%s` | `%s` |\n' "$command" "$version_line"
done
echo ""
if [ "$installed" = true ]; then
echo "安装的包:\`${missing_packages[*]}\`"
else
echo "安装的包:无,所有命令已存在。"
fi
} >> "$GITHUB_STEP_SUMMARY"
echo "installed=$installed" >> "$GITHUB_OUTPUT"
- name: 📥 准备共享 bare 仓库
shell: bash
run: |
set -euo pipefail
REPO_NAME="${{ github.event.repository.name }}"
REMOTE_URL="${{ github.server_url }}/${{ github.repository }}.git"
EVENT_NAME="${{ github.event_name }}"
REPOSITORY_DIR="${WORKSPACE_ROOT}/${REPO_NAME}/repository.git"
# 校验目标 SHA 因事件而异:
# - pull_requestgithub.sha 是 Gitea 生成的 merge commit,不在
# refs/heads/* 里,直接校验会失败;改用 PR head SHA,并在下方额外
# fetch PR ref 把 head 提交拉进 bare 仓库。下游 workflow_run 消费者
# 读到的 head_sha 也正是这个 PR head,两者一致。
# - 其它事件(push / schedule / dispatch):沿用 github.sha。
if [ "$EVENT_NAME" = "pull_request" ]; then
HEAD_SHA="${{ github.event.pull_request.head.sha }}"
PR_NUMBER="${{ github.event.pull_request.number }}"
else
HEAD_SHA="${{ github.sha }}"
PR_NUMBER=""
fi
case "$HEAD_SHA" in
''|*[!0-9a-fA-F]*)
echo "无效的触发提交 SHA: $HEAD_SHA" >&2
exit 1
;;
esac
case "$REMOTE_URL" in
https://*) ;;
*)
echo "拒绝通过非 HTTPS remote 使用 WORKFLOW token: $REMOTE_URL" >&2
exit 1
;;
esac
if [ -z "$ACCESS_TOKEN" ]; then
echo "未配置 WORKFLOW secret,无法读取仓库" >&2
exit 1
fi
mkdir -p "$(dirname "$REPOSITORY_DIR")"
if [ ! -e "$REPOSITORY_DIR" ]; then
git init --bare "$REPOSITORY_DIR"
else
if [ ! -d "$REPOSITORY_DIR" ]; then
echo "共享仓库路径存在但不是目录: $REPOSITORY_DIR" >&2
exit 1
fi
if ! is_bare=$(git --git-dir="$REPOSITORY_DIR" rev-parse --is-bare-repository 2>/dev/null) || \
[ "$is_bare" != "true" ]; then
echo "共享仓库路径不是有效 bare 仓库: $REPOSITORY_DIR" >&2
exit 1
fi
fi
if git --git-dir="$REPOSITORY_DIR" remote get-url origin >/dev/null 2>&1; then
git --git-dir="$REPOSITORY_DIR" remote set-url origin "$REMOTE_URL"
else
git --git-dir="$REPOSITORY_DIR" remote add origin "$REMOTE_URL"
fi
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 --prune-tags --tags --force origin \
'+refs/heads/*:refs/remotes/origin/*'
# PR head 不在 refs/heads/*,按需补取 PR ref 把 head 提交拉进 bare 仓库。
# 先试 PR head SHA 是否已在库(同仓库分支 PR 的 head 常已随 refs/heads/*
# 到位),不在再按 PR 号 fetch Gitea 的 refs/pull/<n>/head。
if [ -n "$PR_NUMBER" ] && \
! 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 --force origin \
"+refs/pull/${PR_NUMBER}/head:refs/remotes/origin/pull/${PR_NUMBER}/head" || true
fi
if ! git --git-dir="$REPOSITORY_DIR" cat-file -e "${HEAD_SHA}^{commit}"; then
echo "共享仓库中不存在触发提交: $HEAD_SHA(事件: $EVENT_NAME" >&2
exit 1
fi
resolved_sha=$(git --git-dir="$REPOSITORY_DIR" rev-parse "${HEAD_SHA}^{commit}")
{
echo ""
echo "## Prepare 仓库"
echo ""
echo "- bare 仓库:\`$REPOSITORY_DIR\`"
echo "- 触发提交:\`$resolved_sha\`"
echo "- 远端:\`$REMOTE_URL\`"
} >> "$GITHUB_STEP_SUMMARY"
echo "Prepare 完成: $REPOSITORY_DIR @ $resolved_sha"