♻️ refactor(ci): 重构为 Prepare 上游 + workflow_run 下游消费者模型
- 新增 prepare.yml:统一检查/安装公共工具并集中 fetch 到共享 bare 仓库 - 统计与发布改为消费成功的 Prepare workflow_run,各自维护 stats/release worktree - 四个 workflow name 统一为带 emoji 的中文,同步 workflow_run 触发引用 - 系统信息 workflow 保持独立直接触发 - 删除 tests/ 手动验证脚本
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
name: 📦 自动发布
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "[0-9]*"
|
||||
workflow_run:
|
||||
workflows: ["🧰 准备环境"]
|
||||
types:
|
||||
- completed
|
||||
|
||||
concurrency:
|
||||
group: release-${{ github.repository }}
|
||||
@@ -16,7 +17,7 @@ env:
|
||||
# ===== Token 配置 =====
|
||||
# Gitea/GitHub 访问令牌
|
||||
# 用途:
|
||||
# 1. Git 操作:克隆仓库、推送提交
|
||||
# 1. Git 操作:推送提交(仓库读取由 Prepare 完成)
|
||||
# 2. API 调用:创建 Release、上传附件
|
||||
# 权限要求:
|
||||
# - repo (仓库完整访问权限)
|
||||
@@ -26,7 +27,7 @@ env:
|
||||
#
|
||||
# 💡 提示:同一个 token 可用于所有操作
|
||||
# 如需分离权限,可配置两个不同的 token:
|
||||
# - GIT_TOKEN: 用于 git clone/push
|
||||
# - GIT_TOKEN: 用于 git push
|
||||
# - API_TOKEN: 用于 API 调用
|
||||
ACCESS_TOKEN: ${{ secrets.WORKFLOW }}
|
||||
GIT_CONFIG_COUNT: "3"
|
||||
@@ -38,7 +39,7 @@ env:
|
||||
GIT_CONFIG_VALUE_2: "never"
|
||||
|
||||
# ===== 工作区配置 =====
|
||||
WORKSPACE_DIR: "/data/workspace"
|
||||
WORKSPACE_ROOT: "/data/workspace"
|
||||
WORKSPACE_SLOT: "release"
|
||||
|
||||
# ===== 分支配置 =====
|
||||
@@ -134,10 +135,100 @@ env:
|
||||
# 4. CHANGELOG内容是叠加而非覆盖
|
||||
|
||||
jobs:
|
||||
route-release:
|
||||
if: ${{ github.event.workflow_run.conclusion == 'success' && contains(github.event.workflow_run.path, '@refs/tags/') }}
|
||||
runs-on: standard-ubuntu-22
|
||||
permissions:
|
||||
contents: read
|
||||
outputs:
|
||||
should_release: ${{ steps.route.outputs.should_release }}
|
||||
version: ${{ steps.route.outputs.version }}
|
||||
tag_ref: ${{ steps.route.outputs.tag_ref }}
|
||||
source_sha: ${{ steps.route.outputs.source_sha }}
|
||||
env:
|
||||
UPSTREAM_PATH: ${{ github.event.workflow_run.path }}
|
||||
HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
|
||||
|
||||
steps:
|
||||
- name: 🧭 恢复并验证 Tag
|
||||
id: route
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
if ! command -v git >/dev/null 2>&1; then
|
||||
echo "Prepare 成功后仍缺少发布路由所需命令: git" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "should_release=false" >> "$GITHUB_OUTPUT"
|
||||
|
||||
case "$HEAD_SHA" in
|
||||
''|*[!0-9a-fA-F]*)
|
||||
echo "无效的上游提交 SHA: $HEAD_SHA" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
FULL_REF="${UPSTREAM_PATH##*@}"
|
||||
case "$FULL_REF" in
|
||||
refs/tags/*) ;;
|
||||
*)
|
||||
echo "workflow_run.path 未包含有效 Tag ref: $UPSTREAM_PATH" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
VERSION="${FULL_REF#refs/tags/}"
|
||||
case "$VERSION" in
|
||||
[0-9]*) ;;
|
||||
*)
|
||||
echo "跳过非版本 Tag: $VERSION"
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
if ! git check-ref-format "$FULL_REF"; then
|
||||
echo "数字开头的 Tag ref 格式无效: $FULL_REF" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
REPO_NAME="${{ github.event.repository.name }}"
|
||||
REPOSITORY_DIR="${WORKSPACE_ROOT}/${REPO_NAME}/repository.git"
|
||||
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
|
||||
if ! git --git-dir="$REPOSITORY_DIR" cat-file -e "${HEAD_SHA}^{commit}"; then
|
||||
echo "共享仓库中不存在上游提交: $HEAD_SHA" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! tag_sha=$(git --git-dir="$REPOSITORY_DIR" rev-parse "${FULL_REF}^{commit}" 2>/dev/null); then
|
||||
echo "共享仓库中不存在可解析的 Tag: $FULL_REF" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "$tag_sha" != "$HEAD_SHA" ]; then
|
||||
echo "Tag/SHA 不匹配: $FULL_REF -> $tag_sha,上游为 $HEAD_SHA" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "should_release=true" >> "$GITHUB_OUTPUT"
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
echo "tag_ref=$FULL_REF" >> "$GITHUB_OUTPUT"
|
||||
echo "source_sha=$HEAD_SHA" >> "$GITHUB_OUTPUT"
|
||||
echo "发布路由通过: $VERSION @ $HEAD_SHA"
|
||||
|
||||
changelog-and-release:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: route-release
|
||||
if: ${{ needs.route-release.outputs.should_release == 'true' }}
|
||||
runs-on: standard-ubuntu-22
|
||||
permissions:
|
||||
contents: write
|
||||
env:
|
||||
VERSION: ${{ needs.route-release.outputs.version }}
|
||||
TAG_REF: ${{ needs.route-release.outputs.tag_ref }}
|
||||
SOURCE_SHA: ${{ needs.route-release.outputs.source_sha }}
|
||||
|
||||
steps:
|
||||
- name: ⚙️ 加载配置
|
||||
@@ -148,7 +239,7 @@ jobs:
|
||||
echo "======================================"
|
||||
|
||||
# 从环境变量读取配置
|
||||
VERSION="${{ github.ref_name }}"
|
||||
VERSION="${{ env.VERSION }}"
|
||||
|
||||
KEYWORDS="${{ env.PRERELEASE_KEYWORDS }}"
|
||||
STRIP_REGEX="-($KEYWORDS)[0-9]*$" # 用于 sed 删除后缀
|
||||
@@ -235,78 +326,91 @@ jobs:
|
||||
echo "======================================"
|
||||
echo ""
|
||||
|
||||
- name: 📥 准备隔离仓库
|
||||
id: clone
|
||||
- name: 📥 对齐发布 Worktree
|
||||
id: prepare_worktree
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
echo "======================================"
|
||||
echo "🚀 开始准备仓库"
|
||||
echo "======================================"
|
||||
|
||||
REPO_SLUG="${{ github.repository }}"
|
||||
for command in git python3 curl flock realpath; do
|
||||
if ! command -v "$command" >/dev/null 2>&1; then
|
||||
echo "Prepare 成功后仍缺少发布所需命令: $command" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
REPO_NAME="${{ github.event.repository.name }}"
|
||||
HEAD_SHA="${{ env.SOURCE_SHA }}"
|
||||
MAIN_BRANCH="${{ env.MAIN_BRANCH }}"
|
||||
WORKSPACE_DIR="${{ env.WORKSPACE_DIR }}"
|
||||
WORKSPACE_SLOT="${{ env.WORKSPACE_SLOT }}"
|
||||
REPO_DIR="${WORKSPACE_DIR}/${REPO_NAME}/${WORKSPACE_SLOT}"
|
||||
REMOTE_URL="${GITHUB_SERVER_URL}/${REPO_SLUG}.git"
|
||||
REMOTE_REF="refs/remotes/origin/${MAIN_BRANCH}"
|
||||
REPOSITORY_DIR="${WORKSPACE_ROOT}/${REPO_NAME}/repository.git"
|
||||
WORKTREE_DIR="${WORKSPACE_ROOT}/${REPO_NAME}/worktrees/release"
|
||||
WORKTREE_LOCK="${WORKSPACE_ROOT}/${REPO_NAME}/worktree-admin.lock"
|
||||
MAIN_REMOTE_REF="refs/remotes/origin/${MAIN_BRANCH}"
|
||||
|
||||
if [ -z "$MAIN_BRANCH" ]; then
|
||||
echo "❌ 错误: 未配置主分支"
|
||||
exit 1
|
||||
fi
|
||||
case "$REMOTE_URL" in
|
||||
https://*) ;;
|
||||
*)
|
||||
echo "❌ 拒绝通过非 HTTPS remote 使用 WORKFLOW token" >&2
|
||||
case "$HEAD_SHA" in
|
||||
''|*[!0-9a-fA-F]*)
|
||||
echo "无效的路由提交 SHA: $HEAD_SHA" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
if [ -e "$REPO_DIR" ] && [ ! -d "$REPO_DIR/.git" ]; then
|
||||
echo "❌ Slot 已存在但不是 Git 仓库: $REPO_DIR" >&2
|
||||
if [ -z "$MAIN_BRANCH" ]; then
|
||||
echo "未配置 MAIN_BRANCH" >&2
|
||||
exit 1
|
||||
fi
|
||||
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
|
||||
if ! git --git-dir="$REPOSITORY_DIR" cat-file -e "${HEAD_SHA}^{commit}"; then
|
||||
echo "共享仓库中不存在发布提交: $HEAD_SHA" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! git --git-dir="$REPOSITORY_DIR" show-ref --verify --quiet "$MAIN_REMOTE_REF"; then
|
||||
echo "Prepare 未 fetch 配置的主分支: $MAIN_REMOTE_REF" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "📁 仓库名称: $REPO_NAME"
|
||||
echo "📦 工作区根目录: $WORKSPACE_DIR"
|
||||
echo "🎯 Workflow 职责: $WORKSPACE_SLOT"
|
||||
echo "🌐 服务器: ${GITHUB_SERVER_URL}"
|
||||
echo ""
|
||||
if [ ! -f "$WORKTREE_DIR/.git" ]; then
|
||||
exec 9>"$WORKTREE_LOCK"
|
||||
flock 9
|
||||
|
||||
if [ ! -d "$REPO_DIR/.git" ]; then
|
||||
mkdir -p "$(dirname "$REPO_DIR")"
|
||||
git clone --no-checkout "$REMOTE_URL" "$REPO_DIR"
|
||||
else
|
||||
git -C "$REPO_DIR" remote set-url origin "$REMOTE_URL"
|
||||
if [ ! -f "$WORKTREE_DIR/.git" ]; then
|
||||
if [ -e "$WORKTREE_DIR" ]; then
|
||||
echo "发布 Worktree 路径已存在但不是 linked worktree: $WORKTREE_DIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
mkdir -p "$(dirname "$WORKTREE_DIR")"
|
||||
git --git-dir="$REPOSITORY_DIR" worktree add --detach "$WORKTREE_DIR" "$HEAD_SHA"
|
||||
fi
|
||||
|
||||
flock -u 9
|
||||
fi
|
||||
git -C "$REPO_DIR" fetch \
|
||||
--prune --prune-tags --tags --force origin \
|
||||
'+refs/heads/*:refs/remotes/origin/*'
|
||||
if ! git -C "$REPO_DIR" show-ref --verify --quiet "$REMOTE_REF"; then
|
||||
echo "❌ 配置的远程分支不存在: $MAIN_BRANCH" >&2
|
||||
|
||||
common_dir=$(git -C "$WORKTREE_DIR" rev-parse --path-format=absolute --git-common-dir)
|
||||
if [ "$common_dir" != "$(realpath "$REPOSITORY_DIR")" ]; then
|
||||
echo "发布 Worktree 不属于共享仓库: $WORKTREE_DIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
git -C "$REPO_DIR" checkout --force -B "$MAIN_BRANCH" "$REMOTE_REF"
|
||||
git -C "$REPO_DIR" reset --hard "$REMOTE_REF"
|
||||
git -C "$REPO_DIR" clean -ffdx
|
||||
|
||||
echo "✓ 仓库目录: $REPO_DIR"
|
||||
echo ""
|
||||
git -C "$WORKTREE_DIR" checkout --detach --force "$HEAD_SHA"
|
||||
git -C "$WORKTREE_DIR" reset --hard "$HEAD_SHA"
|
||||
git -C "$WORKTREE_DIR" clean -ffdx
|
||||
|
||||
cd "$REPO_DIR"
|
||||
echo "✓ 主分支 '$MAIN_BRANCH' 已准备并清理"
|
||||
actual_sha=$(git -C "$WORKTREE_DIR" rev-parse HEAD)
|
||||
if [ "$actual_sha" != "$HEAD_SHA" ]; then
|
||||
echo "发布 Worktree 提交不匹配: 期望 $HEAD_SHA,实际 $actual_sha" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 导出到环境变量供后续步骤使用
|
||||
echo "REPO_DIR=$REPO_DIR" >> "$GITHUB_ENV"
|
||||
git -C "$WORKTREE_DIR" config user.name "${{ env.GIT_USER_NAME }}"
|
||||
git -C "$WORKTREE_DIR" config user.email "${{ env.GIT_USER_EMAIL }}"
|
||||
|
||||
echo "REPOSITORY_DIR=$REPOSITORY_DIR" >> "$GITHUB_ENV"
|
||||
echo "REPO_DIR=$WORKTREE_DIR" >> "$GITHUB_ENV"
|
||||
echo "REPO_NAME=$REPO_NAME" >> "$GITHUB_ENV"
|
||||
echo "WORKSPACE_SLOT=$WORKSPACE_SLOT" >> "$GITHUB_ENV"
|
||||
echo "MAIN_BRANCH=$MAIN_BRANCH" >> "$GITHUB_ENV"
|
||||
|
||||
echo ""
|
||||
echo "✅ 仓库准备完成"
|
||||
echo "======================================"
|
||||
echo ""
|
||||
echo "MAIN_REMOTE_REF=$MAIN_REMOTE_REF" >> "$GITHUB_ENV"
|
||||
echo "发布 Worktree: $WORKTREE_DIR @ $actual_sha"
|
||||
|
||||
- name: 🤖 检查 Bot 提交
|
||||
id: check_bot
|
||||
@@ -317,7 +421,7 @@ jobs:
|
||||
|
||||
cd ${{ env.REPO_DIR }}
|
||||
|
||||
COMMIT_MSG=$(git log -1 --pretty=%B ${{ github.ref_name }})
|
||||
COMMIT_MSG=$(git log -1 --pretty=%B "${{ env.SOURCE_SHA }}")
|
||||
echo "📝 Tag commit message:"
|
||||
echo "$COMMIT_MSG"
|
||||
echo ""
|
||||
@@ -344,7 +448,7 @@ jobs:
|
||||
|
||||
cd ${{ env.REPO_DIR }}
|
||||
|
||||
VERSION="${{ github.ref_name }}"
|
||||
VERSION="${{ env.VERSION }}"
|
||||
CHANGELOG_VERSION="${{ env.CHANGELOG_VERSION }}"
|
||||
|
||||
echo "🏷️ Tag: $VERSION"
|
||||
@@ -607,8 +711,12 @@ jobs:
|
||||
echo ""
|
||||
echo "💾 写入 CHANGELOG.md..."
|
||||
|
||||
# 切换到主分支
|
||||
git checkout ${{ env.MAIN_BRANCH }}
|
||||
# 从 Prepare 已 fetch 的远端引用准备主分支,再写入 CHANGELOG
|
||||
MAIN_BRANCH="${{ env.MAIN_BRANCH }}"
|
||||
MAIN_REMOTE_REF="${{ env.MAIN_REMOTE_REF }}"
|
||||
git -C "${{ env.REPO_DIR }}" checkout --force -B "$MAIN_BRANCH" "$MAIN_REMOTE_REF"
|
||||
git -C "${{ env.REPO_DIR }}" reset --hard "$MAIN_REMOTE_REF"
|
||||
git -C "${{ env.REPO_DIR }}" clean -ffdx
|
||||
|
||||
# ============================================
|
||||
# 更新或创建 CHANGELOG.md
|
||||
@@ -819,9 +927,6 @@ jobs:
|
||||
|
||||
cd ${{ env.REPO_DIR }}
|
||||
|
||||
# 确保使用最新的 CHANGELOG
|
||||
git -C "${{ env.REPO_DIR }}" pull --ff-only origin "${{ env.MAIN_BRANCH }}"
|
||||
|
||||
python3 << 'PYSCRIPT'
|
||||
import re
|
||||
|
||||
@@ -871,41 +976,26 @@ jobs:
|
||||
echo "📄 Draft: ${{ env.RELEASE_IS_DRAFT }}"
|
||||
echo ""
|
||||
|
||||
# 转换 bash 布尔值为 Python 布尔值
|
||||
if [ "${{ env.RELEASE_IS_DRAFT }}" = "true" ]; then
|
||||
PY_DRAFT="True"
|
||||
else
|
||||
PY_DRAFT="False"
|
||||
fi
|
||||
|
||||
if [ "${{ env.RELEASE_IS_PRERELEASE }}" = "true" ]; then
|
||||
PY_PRERELEASE="True"
|
||||
else
|
||||
PY_PRERELEASE="False"
|
||||
fi
|
||||
|
||||
echo "🔄 转换布尔值: draft=${{ env.RELEASE_IS_DRAFT }} → $PY_DRAFT, prerelease=${{ env.RELEASE_IS_PRERELEASE }} → $PY_PRERELEASE"
|
||||
echo ""
|
||||
|
||||
python3 << EOF
|
||||
python3 << 'PYSCRIPT'
|
||||
import json
|
||||
import os
|
||||
|
||||
with open('/tmp/release-body.txt', 'r') as f:
|
||||
body = f.read()
|
||||
with open('/tmp/release-body.txt', 'r', encoding='utf-8') as release_body_file:
|
||||
body = release_body_file.read()
|
||||
|
||||
payload = {
|
||||
"tag_name": "${{ github.ref_name }}",
|
||||
"name": "${{ env.RELEASE_TITLE_PROCESSED }}",
|
||||
"tag_name": os.environ["VERSION"],
|
||||
"name": os.environ["RELEASE_TITLE_PROCESSED"],
|
||||
"body": body,
|
||||
"draft": $PY_DRAFT,
|
||||
"prerelease": $PY_PRERELEASE
|
||||
"draft": os.environ["RELEASE_IS_DRAFT"] == "true",
|
||||
"prerelease": os.environ["RELEASE_IS_PRERELEASE"] == "true",
|
||||
}
|
||||
|
||||
with open('/tmp/payload.json', 'w', encoding='utf-8') as f:
|
||||
json.dump(payload, f, ensure_ascii=False, indent=2)
|
||||
with open('/tmp/payload.json', 'w', encoding='utf-8') as payload_file:
|
||||
json.dump(payload, payload_file, ensure_ascii=False, indent=2)
|
||||
|
||||
print("✓ Payload prepared")
|
||||
EOF
|
||||
PYSCRIPT
|
||||
|
||||
echo "🌐 发送 API 请求..."
|
||||
HTTP_CODE=$(curl -s -o /tmp/release_response.json -w "%{http_code}" -X POST \
|
||||
@@ -1010,7 +1100,7 @@ jobs:
|
||||
|
||||
| 项目 | 结果 |
|
||||
|------|------|
|
||||
| 🏷️ Tag 版本 | **`${{ github.ref_name }}`** |
|
||||
| 🏷️ Tag 版本 | **`${{ env.VERSION }}`** |
|
||||
| 📝 CHANGELOG 版本 | **`${{ env.CHANGELOG_VERSION }}`** |
|
||||
| 🌿 主分支 | **`${{ env.MAIN_BRANCH }}`** |
|
||||
| 🌐 Gitea 服务器 | **`${{ env.GITEA_SERVER }}`** |
|
||||
@@ -1113,7 +1203,7 @@ jobs:
|
||||
echo " 原因: 检测到 [skip ci] 标记,防止无限循环"
|
||||
elif [ "${{ steps.changelog.outputs.changelog_updated }}" = "true" ]; then
|
||||
echo "📊 执行结果:"
|
||||
echo " - Tag: ${{ github.ref_name }}"
|
||||
echo " - Tag: ${{ env.VERSION }}"
|
||||
echo " - CHANGELOG 版本: ${{ env.CHANGELOG_VERSION }}"
|
||||
echo " - 主分支: ${{ env.MAIN_BRANCH }}"
|
||||
echo " - Release 标题: ${{ env.RELEASE_TITLE_PROCESSED }}"
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
name: 🧰 准备环境
|
||||
|
||||
on:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: prepare-${{ github.repository }}
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
ACCESS_TOKEN: ${{ secrets.WORKFLOW }}
|
||||
GIT_CONFIG_COUNT: "3"
|
||||
GIT_CONFIG_KEY_0: "credential.helper"
|
||||
GIT_CONFIG_VALUE_0: ""
|
||||
GIT_CONFIG_KEY_1: '!f() { test "$1" = get || exit 0; printf "%s\n" username=oauth2; printf "%s\n" "password=${ACCESS_TOKEN}"; }; f'
|
||||
GIT_CONFIG_KEY_2: "credential.interactive"
|
||||
GIT_CONFIG_VALUE_2: "never"
|
||||
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"
|
||||
[jq]="jq"
|
||||
[bc]="bc"
|
||||
[flock]="util-linux"
|
||||
[realpath]="coreutils"
|
||||
)
|
||||
required_commands=(git python3 curl jq bc 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"
|
||||
HEAD_SHA="${{ github.sha }}"
|
||||
REPOSITORY_DIR="${WORKSPACE_ROOT}/${REPO_NAME}/repository.git"
|
||||
|
||||
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 --git-dir="$REPOSITORY_DIR" fetch \
|
||||
--prune --prune-tags --tags --force origin \
|
||||
'+refs/heads/*:refs/remotes/origin/*'
|
||||
|
||||
if ! git --git-dir="$REPOSITORY_DIR" cat-file -e "${HEAD_SHA}^{commit}"; then
|
||||
echo "共享仓库中不存在触发提交: $HEAD_SHA" >&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"
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Ubuntu System Information
|
||||
name: 🖥️ Ubuntu 系统信息
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -18,75 +18,75 @@ jobs:
|
||||
echo "====================================="
|
||||
echo ""
|
||||
|
||||
- name: 🖥️ 显示系统信息
|
||||
- name: ℹ️ 显示系统信息
|
||||
run: |
|
||||
echo "===== 系统版本 ====="
|
||||
echo "===== 🐧 系统版本 ====="
|
||||
cat /etc/os-release
|
||||
echo ""
|
||||
echo "===== 内核信息 ====="
|
||||
echo "===== 🧩 内核信息 ====="
|
||||
uname -a
|
||||
echo ""
|
||||
echo "===== 主机名 ====="
|
||||
echo "===== 🏷️ 主机名 ====="
|
||||
hostname
|
||||
echo ""
|
||||
echo "===== 系统启动时间 ====="
|
||||
echo "===== ⏱️ 系统启动时间 ====="
|
||||
uptime
|
||||
|
||||
- name: 🧮 显示 CPU 信息
|
||||
- name: ⚙️ 显示 CPU 信息
|
||||
run: |
|
||||
echo "===== CPU 详细信息 ====="
|
||||
echo "===== ⚙️ CPU 详细信息 ====="
|
||||
lscpu
|
||||
echo ""
|
||||
echo "===== CPU 型号 ====="
|
||||
echo "===== 🏷️ CPU 型号 ====="
|
||||
cat /proc/cpuinfo | grep "model name" | head -1
|
||||
echo ""
|
||||
echo "===== CPU 核心数 ====="
|
||||
echo "===== 🔢 CPU 核心数 ====="
|
||||
nproc
|
||||
|
||||
- name: 🧠 显示内存信息
|
||||
run: |
|
||||
echo "===== 内存使用情况 ====="
|
||||
echo "===== 📊 内存使用情况 ====="
|
||||
free -h
|
||||
echo ""
|
||||
echo "===== 内存详细信息 ====="
|
||||
echo "===== 🧠 内存详细信息 ====="
|
||||
cat /proc/meminfo | grep -E 'MemTotal|MemFree|MemAvailable'
|
||||
|
||||
- name: 💾 显示磁盘信息
|
||||
run: |
|
||||
echo "===== 磁盘使用情况 ====="
|
||||
echo "===== 📊 磁盘使用情况 ====="
|
||||
df -h
|
||||
echo ""
|
||||
echo "===== 磁盘分区信息 ====="
|
||||
echo "===== 🗂️ 磁盘分区信息 ====="
|
||||
lsblk
|
||||
|
||||
- name: 🌐 显示网络信息
|
||||
run: |
|
||||
echo "===== 网络接口 ====="
|
||||
echo "===== 🔌 网络接口 ====="
|
||||
cat /proc/net/dev
|
||||
echo ""
|
||||
echo "===== 路由表 ====="
|
||||
echo "===== 🧭 路由表 ====="
|
||||
cat /proc/net/route
|
||||
echo ""
|
||||
echo "===== DNS 配置 ====="
|
||||
echo "===== 📡 DNS 配置 ====="
|
||||
cat /etc/resolv.conf
|
||||
|
||||
- name: 📦 显示已安装的软件
|
||||
run: |
|
||||
echo "===== Python 版本 ====="
|
||||
echo "===== 🐍 Python 版本 ====="
|
||||
python3 --version
|
||||
echo ""
|
||||
echo "===== Node.js 版本 ====="
|
||||
echo "===== 🟢 Node.js 版本 ====="
|
||||
node --version || echo "Node.js 未安装"
|
||||
echo ""
|
||||
echo "===== Docker 版本 ====="
|
||||
echo "===== 🐳 Docker 版本 ====="
|
||||
docker --version || echo "Docker 未安装"
|
||||
echo ""
|
||||
echo "===== Git 版本 ====="
|
||||
echo "===== 🔀 Git 版本 ====="
|
||||
git --version
|
||||
|
||||
- name: 🔧 显示环境变量
|
||||
run: |
|
||||
echo "===== 重要环境变量 ====="
|
||||
echo "===== 🔧 重要环境变量 ====="
|
||||
echo "PATH: $PATH"
|
||||
echo "HOME: $HOME"
|
||||
echo "USER: $USER"
|
||||
@@ -95,8 +95,8 @@ jobs:
|
||||
|
||||
- name: 📂 显示当前目录
|
||||
run: |
|
||||
echo "===== 当前工作目录 ====="
|
||||
echo "===== 📍 当前工作目录 ====="
|
||||
pwd
|
||||
echo ""
|
||||
echo "===== 目录内容 ====="
|
||||
echo "===== 📄 目录内容 ====="
|
||||
ls -lah
|
||||
|
||||
+103
-223
@@ -1,9 +1,10 @@
|
||||
name: 📊 代码统计徽章
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, master]
|
||||
workflow_dispatch:
|
||||
workflow_run:
|
||||
workflows: ["🧰 准备环境"]
|
||||
types:
|
||||
- completed
|
||||
|
||||
concurrency:
|
||||
group: stats-${{ github.repository }}
|
||||
@@ -25,8 +26,10 @@ env:
|
||||
GIT_CONFIG_VALUE_2: "never"
|
||||
|
||||
# ===== 工作区配置 =====
|
||||
WORKSPACE_DIR: "/data/workspace"
|
||||
WORKSPACE_ROOT: "/data/workspace"
|
||||
WORKSPACE_SLOT: "stats"
|
||||
SOURCE_BRANCH: ${{ github.event.workflow_run.head_branch }}
|
||||
SOURCE_SHA: ${{ github.event.workflow_run.head_sha }}
|
||||
|
||||
# ===== 分支配置 =====
|
||||
# 徽章数据存储分支(可配置)
|
||||
@@ -78,7 +81,8 @@ env:
|
||||
|
||||
jobs:
|
||||
update-stats:
|
||||
runs-on: ubuntu-22.04
|
||||
if: ${{ github.event.workflow_run.conclusion == 'success' && (github.event.workflow_run.head_branch == 'main' || github.event.workflow_run.head_branch == 'master') }}
|
||||
runs-on: standard-ubuntu-22
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
@@ -98,195 +102,105 @@ jobs:
|
||||
echo "token_type=WORKFLOW" >> $GITHUB_OUTPUT
|
||||
|
||||
echo "🔗 仓库: ${{ github.repository }}"
|
||||
echo "🌿 分支: ${{ github.ref_name }}"
|
||||
echo "📝 提交: ${GITHUB_SHA:0:7}"
|
||||
echo "🌿 上游分支: ${{ env.SOURCE_BRANCH }}"
|
||||
echo "📝 上游提交: ${{ env.SOURCE_SHA }}"
|
||||
|
||||
- name: 🔧 检查必需工具
|
||||
id: check_deps
|
||||
run: |
|
||||
echo "======================================"
|
||||
echo "🔍 检查依赖工具"
|
||||
echo "======================================"
|
||||
|
||||
MISSING_TOOLS=()
|
||||
|
||||
# 检查 bc(用于数字计算)
|
||||
if ! command -v bc &> /dev/null; then
|
||||
echo "⚠️ bc 未安装"
|
||||
MISSING_TOOLS+=("bc")
|
||||
else
|
||||
echo "✓ bc 已安装"
|
||||
fi
|
||||
|
||||
# 检查 jq(用于 JSON 处理)
|
||||
if ! command -v jq &> /dev/null; then
|
||||
echo "⚠️ jq 未安装"
|
||||
MISSING_TOOLS+=("jq")
|
||||
else
|
||||
echo "✓ jq 已安装"
|
||||
fi
|
||||
|
||||
# 如果有缺失的工具,安装它们
|
||||
if [ ${#MISSING_TOOLS[@]} -gt 0 ]; then
|
||||
echo ""
|
||||
echo "📦 安装缺失的工具: ${MISSING_TOOLS[*]}"
|
||||
|
||||
# 🔧 智能判断是否需要 sudo
|
||||
# Docker 环境通常以 root 运行,不需要 sudo
|
||||
if [ "$EUID" -eq 0 ] || [ "$(id -u)" -eq 0 ]; then
|
||||
# 当前是 root 用户,直接执行
|
||||
echo "🔑 检测到 root 权限,直接安装"
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq "${MISSING_TOOLS[@]}"
|
||||
elif command -v sudo &> /dev/null; then
|
||||
# 有 sudo 命令,使用 sudo
|
||||
echo "🔑 使用 sudo 安装"
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -y -qq "${MISSING_TOOLS[@]}"
|
||||
else
|
||||
# 既不是 root 也没有 sudo
|
||||
echo "❌ 错误:没有足够权限安装工具"
|
||||
echo "请在 Docker 镜像中预装以下工具:"
|
||||
echo " ${MISSING_TOOLS[*]}"
|
||||
echo ""
|
||||
echo "方案1: 使用包含这些工具的镜像"
|
||||
echo "方案2: 在 Dockerfile 中添加:"
|
||||
echo " RUN apt-get update && apt-get install -y bc jq"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "installed=true" >> $GITHUB_OUTPUT
|
||||
echo "✅ 工具安装完成"
|
||||
else
|
||||
echo "installed=false" >> $GITHUB_OUTPUT
|
||||
echo "✅ 所有工具已就绪"
|
||||
fi
|
||||
|
||||
echo "======================================"
|
||||
echo ""
|
||||
|
||||
- name: 📥 准备隔离仓库
|
||||
id: clone_main
|
||||
- name: 📥 对齐统计 Worktree
|
||||
id: prepare_worktree
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
echo "======================================"
|
||||
echo "🚀 开始准备主仓库"
|
||||
echo "======================================"
|
||||
|
||||
REPO_SLUG="${{ github.repository }}"
|
||||
for command in git python3 bc flock realpath; do
|
||||
if ! command -v "$command" >/dev/null 2>&1; then
|
||||
echo "Prepare 成功后仍缺少统计所需命令: $command" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
REPO_NAME="${{ github.event.repository.name }}"
|
||||
TARGET_BRANCH="${{ github.ref_name }}"
|
||||
WORKSPACE_DIR="${{ env.WORKSPACE_DIR }}"
|
||||
WORKSPACE_SLOT="${{ env.WORKSPACE_SLOT }}"
|
||||
REPO_DIR="${WORKSPACE_DIR}/${REPO_NAME}/${WORKSPACE_SLOT}"
|
||||
REMOTE_URL="${GITHUB_SERVER_URL}/${REPO_SLUG}.git"
|
||||
REMOTE_REF="refs/remotes/origin/${TARGET_BRANCH}"
|
||||
HEAD_SHA="${{ env.SOURCE_SHA }}"
|
||||
REPOSITORY_DIR="${WORKSPACE_ROOT}/${REPO_NAME}/repository.git"
|
||||
WORKTREE_DIR="${WORKSPACE_ROOT}/${REPO_NAME}/worktrees/stats"
|
||||
WORKTREE_LOCK="${WORKSPACE_ROOT}/${REPO_NAME}/worktree-admin.lock"
|
||||
|
||||
case "$REMOTE_URL" in
|
||||
https://*) ;;
|
||||
*)
|
||||
echo "❌ 拒绝通过非 HTTPS remote 使用 WORKFLOW token" >&2
|
||||
case "$HEAD_SHA" in
|
||||
''|*[!0-9a-fA-F]*)
|
||||
echo "无效的上游提交 SHA: $HEAD_SHA" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
if [ -e "$REPO_DIR" ] && [ ! -d "$REPO_DIR/.git" ]; then
|
||||
echo "❌ Slot 已存在但不是 Git 仓库: $REPO_DIR" >&2
|
||||
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
|
||||
if ! git --git-dir="$REPOSITORY_DIR" cat-file -e "${HEAD_SHA}^{commit}"; then
|
||||
echo "共享仓库中不存在上游提交: $HEAD_SHA" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "📁 仓库名称: $REPO_NAME"
|
||||
echo "📦 工作区根目录: $WORKSPACE_DIR"
|
||||
echo "🎯 Workflow 职责: $WORKSPACE_SLOT"
|
||||
echo "🌐 服务器: ${GITHUB_SERVER_URL}"
|
||||
echo "🌿 分支: $TARGET_BRANCH"
|
||||
echo ""
|
||||
if [ ! -f "$WORKTREE_DIR/.git" ]; then
|
||||
exec 9>"$WORKTREE_LOCK"
|
||||
flock 9
|
||||
|
||||
if [ ! -d "$REPO_DIR/.git" ]; then
|
||||
mkdir -p "$(dirname "$REPO_DIR")"
|
||||
git clone --no-checkout "$REMOTE_URL" "$REPO_DIR"
|
||||
else
|
||||
git -C "$REPO_DIR" remote set-url origin "$REMOTE_URL"
|
||||
if [ ! -f "$WORKTREE_DIR/.git" ]; then
|
||||
if [ -e "$WORKTREE_DIR" ]; then
|
||||
echo "统计 Worktree 路径已存在但不是 linked worktree: $WORKTREE_DIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
mkdir -p "$(dirname "$WORKTREE_DIR")"
|
||||
git --git-dir="$REPOSITORY_DIR" worktree add --detach "$WORKTREE_DIR" "$HEAD_SHA"
|
||||
fi
|
||||
|
||||
flock -u 9
|
||||
fi
|
||||
git -C "$REPO_DIR" fetch \
|
||||
--prune --prune-tags --tags --force origin \
|
||||
'+refs/heads/*:refs/remotes/origin/*'
|
||||
if ! git -C "$REPO_DIR" show-ref --verify --quiet "$REMOTE_REF"; then
|
||||
echo "❌ 触发分支不存在: $TARGET_BRANCH" >&2
|
||||
|
||||
common_dir=$(git -C "$WORKTREE_DIR" rev-parse --path-format=absolute --git-common-dir)
|
||||
if [ "$common_dir" != "$(realpath "$REPOSITORY_DIR")" ]; then
|
||||
echo "统计 Worktree 不属于共享仓库: $WORKTREE_DIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
git -C "$REPO_DIR" checkout --force -B "$TARGET_BRANCH" "$REMOTE_REF"
|
||||
git -C "$REPO_DIR" reset --hard "$REMOTE_REF"
|
||||
git -C "$REPO_DIR" clean -ffdx
|
||||
|
||||
echo "✓ 仓库目录: $REPO_DIR"
|
||||
echo ""
|
||||
git -C "$WORKTREE_DIR" checkout --detach --force "$HEAD_SHA"
|
||||
git -C "$WORKTREE_DIR" reset --hard "$HEAD_SHA"
|
||||
git -C "$WORKTREE_DIR" clean -ffdx
|
||||
|
||||
cd "$REPO_DIR"
|
||||
actual_sha=$(git -C "$WORKTREE_DIR" rev-parse HEAD)
|
||||
if [ "$actual_sha" != "$HEAD_SHA" ]; then
|
||||
echo "统计 Worktree 提交不匹配: 期望 $HEAD_SHA,实际 $actual_sha" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ 仓库准备成功"
|
||||
echo ""
|
||||
git -C "$WORKTREE_DIR" config user.name "${{ env.GIT_USER_NAME }}"
|
||||
git -C "$WORKTREE_DIR" config user.email "${{ env.GIT_USER_EMAIL }}"
|
||||
|
||||
# 配置 Git 用户信息
|
||||
echo "⚙️ 配置 Git 用户信息..."
|
||||
git config user.name "${{ env.GIT_USER_NAME }}"
|
||||
git config user.email "${{ env.GIT_USER_EMAIL }}"
|
||||
|
||||
# 显示仓库信息
|
||||
echo "📊 仓库信息:"
|
||||
echo " - 当前分支: $(git branch --show-current)"
|
||||
echo " - 最新提交: $(git log -1 --oneline)"
|
||||
echo " - 远程地址: $(git remote get-url origin | sed 's/oauth2:.*@/oauth2:***@/')"
|
||||
echo ""
|
||||
|
||||
# 导出环境变量
|
||||
echo "REPO_DIR=$REPO_DIR" >> "$GITHUB_ENV"
|
||||
echo "REPOSITORY_DIR=$REPOSITORY_DIR" >> "$GITHUB_ENV"
|
||||
echo "REPO_DIR=$WORKTREE_DIR" >> "$GITHUB_ENV"
|
||||
echo "REPO_NAME=$REPO_NAME" >> "$GITHUB_ENV"
|
||||
echo "WORKSPACE_SLOT=$WORKSPACE_SLOT" >> "$GITHUB_ENV"
|
||||
|
||||
echo "✅ 主仓库准备完成"
|
||||
echo "======================================"
|
||||
echo ""
|
||||
echo "统计 Worktree: $WORKTREE_DIR @ $actual_sha"
|
||||
|
||||
- name: 🌿 准备统计分支
|
||||
id: prepare_stats_branch
|
||||
run: |
|
||||
echo "======================================"
|
||||
echo "🌿 准备统计分支"
|
||||
echo "======================================"
|
||||
set -euo pipefail
|
||||
|
||||
cd "${{ env.REPO_DIR }}"
|
||||
REPOSITORY_DIR="${{ env.REPOSITORY_DIR }}"
|
||||
WORKTREE_DIR="${{ env.REPO_DIR }}"
|
||||
BADGE_BRANCH="${{ env.BADGE_BRANCH }}"
|
||||
SOURCE_SHA="${{ env.SOURCE_SHA }}"
|
||||
|
||||
# 获取所有远程分支
|
||||
git -C "${{ env.REPO_DIR }}" fetch origin --prune
|
||||
|
||||
# 检查统计分支是否存在
|
||||
if git -C "${{ env.REPO_DIR }}" ls-remote --heads origin "${{ env.BADGE_BRANCH }}" | \
|
||||
grep -q "refs/heads/${{ env.BADGE_BRANCH }}"; then
|
||||
echo "✅ 统计分支 '${{ env.BADGE_BRANCH }}' 已存在"
|
||||
|
||||
# 检出统计分支
|
||||
git -C "${{ env.REPO_DIR }}" fetch origin \
|
||||
"+refs/heads/${{ env.BADGE_BRANCH }}:refs/remotes/origin/${{ env.BADGE_BRANCH }}"
|
||||
git checkout --force -B "${{ env.BADGE_BRANCH }}" "refs/remotes/origin/${{ env.BADGE_BRANCH }}"
|
||||
|
||||
echo "📂 当前分支内容:"
|
||||
ls -la
|
||||
|
||||
# 返回主分支
|
||||
git checkout ${{ github.ref_name }}
|
||||
|
||||
echo "branch_exists=true" >> $GITHUB_OUTPUT
|
||||
if git --git-dir="$REPOSITORY_DIR" show-ref --verify --quiet "refs/remotes/origin/${BADGE_BRANCH}"; then
|
||||
git -C "$WORKTREE_DIR" checkout --force -B "$BADGE_BRANCH" "refs/remotes/origin/${BADGE_BRANCH}"
|
||||
echo "branch_exists=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "🆕 统计分支 '${{ env.BADGE_BRANCH }}' 不存在,将创建"
|
||||
if git show-ref --verify --quiet "refs/heads/${{ env.BADGE_BRANCH }}"; then
|
||||
echo "🧹 删除上次失败运行遗留的本地统计分支"
|
||||
git branch -D "${{ env.BADGE_BRANCH }}"
|
||||
if git --git-dir="$REPOSITORY_DIR" show-ref --verify --quiet "refs/heads/${BADGE_BRANCH}"; then
|
||||
git -C "$WORKTREE_DIR" branch -D "$BADGE_BRANCH"
|
||||
fi
|
||||
echo "branch_exists=false" >> $GITHUB_OUTPUT
|
||||
echo "branch_exists=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
echo "======================================"
|
||||
echo ""
|
||||
git -C "$WORKTREE_DIR" checkout --detach --force "$SOURCE_SHA"
|
||||
|
||||
- name: 🌱 创建统计分支
|
||||
if: steps.prepare_stats_branch.outputs.branch_exists == 'false'
|
||||
@@ -296,26 +210,12 @@ jobs:
|
||||
echo "======================================"
|
||||
|
||||
cd "${{ env.REPO_DIR }}"
|
||||
|
||||
# 🔴 安全检查:确认在正确的目录
|
||||
echo "🔍 当前目录: $(pwd)"
|
||||
echo "🔍 .git 状态: $([ -d .git ] && echo '✓ 存在' || echo '✗ 不存在')"
|
||||
|
||||
if [ ! -d .git ]; then
|
||||
echo "❌ 错误:.git 目录不存在,无法创建分支"
|
||||
exit 1
|
||||
fi
|
||||
git rev-parse --is-inside-work-tree >/dev/null
|
||||
|
||||
# 创建孤立分支(orphan branch)
|
||||
# 📝 说明:孤立分支与主分支没有共同的提交历史,适合存储独立的数据
|
||||
echo "🌱 创建孤立分支..."
|
||||
git checkout --orphan ${{ env.BADGE_BRANCH }}
|
||||
|
||||
# 🔴 再次确认 .git 仍然存在
|
||||
if [ ! -d .git ]; then
|
||||
echo "❌ 严重错误:.git 目录丢失!"
|
||||
exit 1
|
||||
fi
|
||||
git checkout --orphan "${{ env.BADGE_BRANCH }}"
|
||||
|
||||
# 🧹 清空所有文件(但保留 .git 目录)
|
||||
# ❓ 为什么要删除?
|
||||
@@ -336,16 +236,12 @@ jobs:
|
||||
# 步骤 2: 安全地删除剩余文件
|
||||
# 使用更严格的保护,确保不会误删 .git
|
||||
echo "🔍 查找需要删除的文件..."
|
||||
find . -maxdepth 1 -type f ! -name '.gitignore' -delete 2>/dev/null || true
|
||||
find . -maxdepth 1 -type d ! -name '.' ! -name '..' ! -name '.git' ! -name '.gitea' -exec rm -rf {} + 2>/dev/null || true
|
||||
find . -maxdepth 1 -type f ! -name '.git' ! -name '.gitignore' -delete 2>/dev/null || true
|
||||
find . -maxdepth 1 -type d ! -name '.' ! -name '..' ! -name '.gitea' -exec rm -rf {} + 2>/dev/null || true
|
||||
|
||||
# 🔴 最终检查:确认 .git 仍然完好
|
||||
echo "🔍 最终检查..."
|
||||
if [ ! -d .git ]; then
|
||||
echo "❌ 致命错误:.git 目录在清理过程中被删除!"
|
||||
echo "这不应该发生,请检查 find 命令"
|
||||
exit 1
|
||||
fi
|
||||
git rev-parse --is-inside-work-tree >/dev/null
|
||||
echo "✓ .git 目录完好"
|
||||
echo "✓ 文件清理完成"
|
||||
echo ""
|
||||
@@ -371,8 +267,8 @@ jobs:
|
||||
|
||||
## 🔄 更新机制
|
||||
|
||||
- ✅ 每次 push 到主分支时自动更新
|
||||
- ✅ 可通过 workflow_dispatch 手动触发
|
||||
- ✅ 主分支的 Prepare 成功后自动更新
|
||||
- ✅ 可在 main/master 上手动运行 Prepare
|
||||
|
||||
## 📊 数据来源
|
||||
|
||||
@@ -384,7 +280,7 @@ jobs:
|
||||
EOF
|
||||
|
||||
# 创建徽章目录
|
||||
mkdir -p ${{ env.BADGE_DIR }}
|
||||
mkdir -p "${{ env.BADGE_DIR }}"
|
||||
|
||||
# 添加并提交
|
||||
git add .
|
||||
@@ -397,10 +293,9 @@ jobs:
|
||||
echo "======================================"
|
||||
echo ""
|
||||
|
||||
# 🔴 重要:返回主分支,后续统计需要在主分支进行
|
||||
echo "🔄 切换回主分支: ${{ github.ref_name }}"
|
||||
git checkout ${{ github.ref_name }}
|
||||
echo "✓ 已切换回主分支"
|
||||
echo "🔄 返回上游提交: ${{ env.SOURCE_SHA }}"
|
||||
git checkout --detach --force "${{ env.SOURCE_SHA }}"
|
||||
echo "✓ 已返回上游提交"
|
||||
echo ""
|
||||
|
||||
- name: 📊 统计总代码量
|
||||
@@ -412,16 +307,11 @@ jobs:
|
||||
|
||||
cd "${{ env.REPO_DIR }}"
|
||||
|
||||
# 🔴 重要:确保在主分支进行统计(不要统计 stats 分支)
|
||||
echo "🔍 确认当前分支..."
|
||||
CURRENT_BRANCH=$(git branch --show-current)
|
||||
if [ "$CURRENT_BRANCH" != "${{ github.ref_name }}" ]; then
|
||||
echo "⚠️ 当前在分支: $CURRENT_BRANCH,切换到主分支: ${{ github.ref_name }}"
|
||||
git checkout ${{ github.ref_name }}
|
||||
else
|
||||
echo "✓ 已在主分支: $CURRENT_BRANCH"
|
||||
ACTUAL_SHA=$(git rev-parse HEAD)
|
||||
if [ "$ACTUAL_SHA" != "${{ env.SOURCE_SHA }}" ]; then
|
||||
echo "源码 Worktree 不在上游提交: 期望 ${{ env.SOURCE_SHA }},实际 $ACTUAL_SHA" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# 构建排除参数
|
||||
EXCLUDE_FIND_ARGS=()
|
||||
@@ -465,16 +355,11 @@ jobs:
|
||||
|
||||
cd "${{ env.REPO_DIR }}"
|
||||
|
||||
# 🔴 重要:确保在主分支进行统计
|
||||
echo "🔍 确认当前分支..."
|
||||
CURRENT_BRANCH=$(git branch --show-current)
|
||||
if [ "$CURRENT_BRANCH" != "${{ github.ref_name }}" ]; then
|
||||
echo "⚠️ 当前在分支: $CURRENT_BRANCH,切换到主分支: ${{ github.ref_name }}"
|
||||
git checkout ${{ github.ref_name }}
|
||||
else
|
||||
echo "✓ 已在主分支: $CURRENT_BRANCH"
|
||||
ACTUAL_SHA=$(git rev-parse HEAD)
|
||||
if [ "$ACTUAL_SHA" != "${{ env.SOURCE_SHA }}" ]; then
|
||||
echo "源码 Worktree 不在上游提交: 期望 ${{ env.SOURCE_SHA }},实际 $ACTUAL_SHA" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# 创建临时目录
|
||||
mkdir -p /tmp/lang_stats
|
||||
@@ -555,8 +440,8 @@ jobs:
|
||||
|
||||
cd "${{ env.REPO_DIR }}"
|
||||
|
||||
# 在主分支渲染产物,避免依赖 stats 分支中的脚本文件
|
||||
git checkout ${{ github.ref_name }}
|
||||
# 在上游提交渲染产物,避免依赖 stats 分支中的脚本文件
|
||||
git checkout --detach --force "${{ env.SOURCE_SHA }}"
|
||||
|
||||
RENDER_ROOT=$(mktemp -d)
|
||||
UPDATED_AT=$(date -u '+%Y-%m-%d %H:%M:%S UTC')
|
||||
@@ -579,7 +464,7 @@ jobs:
|
||||
--min-lines-threshold "${{ env.MIN_LINES_THRESHOLD }}" \
|
||||
--lang-summary /tmp/lang_summary.txt
|
||||
|
||||
git checkout ${{ env.BADGE_BRANCH }}
|
||||
git checkout --force "${{ env.BADGE_BRANCH }}"
|
||||
rm -rf "${{ env.BADGE_DIR }}"
|
||||
mkdir -p "${{ env.BADGE_DIR }}"
|
||||
cp -f "$RENDER_ROOT/README.md" README.md
|
||||
@@ -629,7 +514,7 @@ jobs:
|
||||
- 语言数: ${{ steps.languages.outputs.language_count }} 种
|
||||
- 徽章数: ${{ steps.generate_badges.outputs.generated_count }} 个
|
||||
|
||||
🔗 触发提交: ${GITHUB_SHA:0:7}
|
||||
🔗 触发提交: ${{ env.SOURCE_SHA }}
|
||||
🤖 由 Gitea Actions 自动生成"
|
||||
|
||||
git commit -m "$COMMIT_MSG"
|
||||
@@ -660,7 +545,8 @@ jobs:
|
||||
| 项目 | 结果 |
|
||||
|------|------|
|
||||
| 🔐 Token 类型 | **${{ steps.validate_token.outputs.token_type }}** |
|
||||
| 🔧 依赖检查 | ${{ steps.check_deps.outputs.installed == 'true' && '✅ 已安装缺失工具' || '✅ 所有工具就绪' }} |
|
||||
| 🌿 来源分支 | `${{ env.SOURCE_BRANCH }}` |
|
||||
| 📝 来源提交 | `${{ env.SOURCE_SHA }}` |
|
||||
| 📊 总代码行数 | **${{ steps.total.outputs.formatted_code }}** 行 |
|
||||
| 📁 总文件数 | **${{ steps.total.outputs.formatted_files }}** 个 |
|
||||
| 🌐 语言种类 | **${{ steps.languages.outputs.language_count }}** 种 |
|
||||
@@ -671,7 +557,7 @@ jobs:
|
||||
|
||||
- 📊 [查看详细统计报告](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/src/branch/${{ env.BADGE_BRANCH }}/README.md)
|
||||
- 🎨 [浏览徽章文件](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/src/branch/${{ env.BADGE_BRANCH }}/${{ env.BADGE_DIR }})
|
||||
- 🔧 [查看 Workflow 配置](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/src/branch/${{ github.ref_name }}/.gitea/workflows/update_stats_badge.yaml)
|
||||
- 🔧 [查看 Workflow 配置](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/src/branch/${{ env.SOURCE_BRANCH }}/.gitea/workflows/update_stats_badge.yml)
|
||||
|
||||
## 📝 语言分布
|
||||
|
||||
@@ -758,12 +644,6 @@ jobs:
|
||||
echo ""
|
||||
echo "================================================"
|
||||
|
||||
# 如果有警告或特殊情况,也输出
|
||||
if [ "${{ steps.check_deps.outputs.installed }}" == "true" ]; then
|
||||
echo ""
|
||||
echo "ℹ️ 本次运行安装了缺失的依赖工具"
|
||||
fi
|
||||
|
||||
if [ "${{ steps.languages.outputs.language_count }}" == "0" ]; then
|
||||
echo ""
|
||||
echo "⚠️ 警告: 未找到符合条件的语言文件"
|
||||
Reference in New Issue
Block a user