ci: 接入提交规范闸门与自动编译流水线(本机Runner+微信通知)
build / build (push) Has been cancelled

This commit is contained in:
2026-09-28 18:38:33 +08:00
parent ba090d1705
commit f803365a20
+156
View File
@@ -0,0 +1,156 @@
name: build
# 提交 -> 本机 Runner 编译 -> 微信通知 + 网页预览
# 实测结论(勿随意改动):
# 1. 不用任何第三方 action(作业容器不联网拉 action,全用镜像自带工具)
# 2. 必须自己 clone —— Runner 不会自动检出代码,工作区初始为空
# 3. act 以 `bash -e -o pipefail` 执行每步 -> 禁止 `cmd | head` 这种会 SIGPIPE 提前退出的管道
# 4. 工具链来自主机只读挂载 /opt/citools(go/uv),缓存写 /opt/citools-cache
# 5. bridge 从容器内走 docker 网关 172.17.0.1:8899(实测可达)
# 6. 校验/上报逻辑放在 .gitea/scripts/ 下的脚本里,YAML 只负责调用(避免 YAML 里嵌深缩进代码)
on:
push:
branches:
- "**"
workflow_dispatch:
env:
BRIDGE_URL: ${{ vars.CI_BRIDGE_URL }}
BRIDGE_TOKEN: ${{ secrets.CI_BRIDGE_TOKEN }}
GIT_TOKEN: ${{ secrets.GITHUB_TOKEN }}
concurrency:
group: build-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 40
steps:
- name: 检出代码
run: |
set -uo pipefail
SRV="${GITHUB_SERVER_URL:-http://192.168.50.223:3000}"
HP="${SRV#*://}"
BR="${GITHUB_REF_NAME:-${GITHUB_REF#refs/heads/}}"
cd "${GITHUB_WORKSPACE:-$(pwd)}"
rm -rf ./* .git 2>/dev/null || true
git init -q .
git remote add origin "http://x-access-token:${GIT_TOKEN}@${HP}/${GITHUB_REPOSITORY}.git"
git fetch -q --depth 50 origin "$BR"
git checkout -q -B "$BR" FETCH_HEAD
git rev-parse HEAD > /tmp/ci-sha
date +%s > /tmp/ci-start
: > /tmp/ci-preview-url
echo skipped > /tmp/ci-build-status
git rev-list --count FETCH_HEAD > /tmp/ci-commits-count 2>/dev/null || echo 1 > /tmp/ci-commits-count
echo "已检出 ${GITHUB_REPOSITORY} 分支 ${BR}"
git log -1 --format=' %h %an %s'
- name: 提交信息规范校验
run: python3 .gitea/scripts/ci_gate.py
- name: 编译与自检
run: |
set +e; set +o pipefail
LOG=/tmp/ci-build.log; : > "$LOG"
run() { echo "-- $* --"; "$@" 2>&1 | tee -a "$LOG"; return "${PIPESTATUS[0]}"; }
runin(){ local d="$1"; shift; echo "-- ($d) $* --"; ( cd "$d" && "$@" ) 2>&1 | tee -a "$LOG"; return "${PIPESTATUS[0]}"; }
export PATH=/opt/citools/go/bin:/opt/citools/bin:$PATH
export GOCACHE=/opt/citools-cache/gocache GOMODCACHE=/opt/citools-cache/gomod UV_CACHE_DIR=/opt/citools-cache/uv
export GOPROXY=https://goproxy.cn,direct GOTOOLCHAIN=local GOFLAGS=-mod=mod GOPATH=/opt/citools-cache/gopath
mkdir -p "$GOCACHE" "$GOMODCACHE" "$UV_CACHE_DIR" "$GOPATH" 2>/dev/null
echo "工具链: $(go version 2>&1) | $(uv --version 2>&1) | $(node -v 2>&1) | $(python3 -V 2>&1)"
fail=0; ran=""
if [ -f go.mod ]; then
ran="$ran go"
run go build ./... || fail=1
run go vet ./... || fail=1
run go test ./... || fail=1
fi
if [ -f pyproject.toml ] || [ -f requirements.txt ] || [ -f setup.py ]; then
ran="$ran python"
if grep -qE '^check:' Makefile 2>/dev/null; then
run make UV=uv check || fail=1
else
run uv sync || fail=1
run uv run pytest -q || fail=1
fi
fi
WEBPKG=""
for p in package.json web/package.json frontend/package.json ui/package.json; do
if [ -f "$p" ]; then WEBPKG="$p"; break; fi
done
if [ -n "$WEBPKG" ]; then
ran="$ran node"
D="$(dirname "$WEBPKG")"
if [ -f "$D/package-lock.json" ]; then
runin "$D" npm ci || fail=1
else
runin "$D" npm install || fail=1
fi
if grep -q '"build"[[:space:]]*:' "$WEBPKG" 2>/dev/null; then
runin "$D" npm run build || fail=1
fi
fi
if [ -z "$ran" ] && [ -f Makefile ]; then
ran="$ran make"
run make || fail=1
fi
if [ -z "$ran" ]; then
echo "未识别到构建入口(go.mod / pyproject.toml / package.json / Makefile 都没有),跳过编译"
fi
if [ "$fail" -eq 0 ]; then echo success > /tmp/ci-build-status; else echo failure > /tmp/ci-build-status; fi
tail -c 4000 "$LOG" > /tmp/ci-build-tail
echo "构建结果: $(cat /tmp/ci-build-status)(识别:$ran)"
[ "$fail" -eq 0 ] || exit 1
- name: 发布网页预览
if: always()
run: |
set +e; set +o pipefail
: > /tmp/ci-preview-url
if [ "$(cat /tmp/ci-build-status 2>/dev/null)" != "success" ]; then
echo "构建未成功,跳过预览发布"; exit 0
fi
WEB=""
for d in web/dist dist build out public web/build frontend/dist; do
if [ -f "$d/index.html" ]; then WEB="$d"; break; fi
done
if [ -z "$WEB" ]; then echo "未发现静态网页产物目录,跳过预览发布"; exit 0; fi
tar -czf /tmp/ci-web.tgz -C "$WEB" . || { echo "打包失败"; exit 0; }
B="${BRIDGE_URL:-}"
for cand in "$B" "http://172.17.0.1:8899" "http://192.168.50.134:8899" "http://100.92.49.78:8899"; do
if [ -n "$cand" ]; then
curl -s -m 5 -o /dev/null "$cand/healthz" && { B="$cand"; break; }
fi
done
SHA="$(cat /tmp/ci-sha)"
echo "发布预览到 $B(产物目录 $WEB)"
curl -sS -m 90 -X POST "$B/api/ci/publish?repo=${GITHUB_REPOSITORY}&sha=${SHA}" -H "X-CI-Token: ${BRIDGE_TOKEN}" -H 'Content-Type: application/gzip' --data-binary @/tmp/ci-web.tgz -o /tmp/ci-pub.json
cat /tmp/ci-pub.json; echo
URL="$(python3 -c "import json;print(json.load(open('/tmp/ci-pub.json')).get('url',''))" 2>/dev/null)"
if [ -n "$URL" ]; then echo "$URL" > /tmp/ci-preview-url; echo "网页预览: $URL"; fi
- name: 通知微信
if: always()
run: |
set +e; set +o pipefail
B="${BRIDGE_URL:-}"
for cand in "$B" "http://172.17.0.1:8899" "http://192.168.50.134:8899" "http://100.92.49.78:8899"; do
if [ -n "$cand" ]; then
curl -s -m 5 -o /dev/null "$cand/healthz" && { B="$cand"; break; }
fi
done
echo "使用 ci-bridge: $B"
S=$(date +%s); T=$(cat /tmp/ci-start 2>/dev/null); [ -n "$T" ] || T=$S
echo $((S - T)) > /tmp/ci-duration
CI_BRIDGE_RESOLVED="$B" python3 .gitea/scripts/ci_report.py