Files
secrets/.gitea/workflows/secrets.yml
voson e6db23bd6d
Some checks failed
Secrets CLI - Build & Release / 版本 & Release (push) Successful in 2s
Secrets CLI - Build & Release / 质量检查 (fmt / clippy / test) (push) Successful in 21s
Secrets CLI - Build & Release / 通知 (push) Successful in 7s
Secrets CLI - Build & Release / Build (aarch64-apple-darwin) (push) Successful in 28s
Secrets CLI - Build & Release / Build (x86_64-unknown-linux-musl) (push) Successful in 35s
Secrets CLI - Build & Release / 发布草稿 Release (push) Successful in 0s
Secrets CLI - Build & Release / Build (x86_64-pc-windows-msvc) (push) Has been cancelled
fix(ci): 移除 probe-runners,用变量控制 build,解耦 notify
- 删除探测 Runner job(API 解析不可靠,且 always() 导致 job 被错误调度)
- build-linux: 仅 needs version+check,默认执行
- build-macos: if vars.BUILD_MACOS != 'false'(默认开,runner 离线时设 false)
- build-windows: if vars.BUILD_WINDOWS == 'true'(默认关,无 runner)
- publish-release: 仅依赖 build-linux,避免被 macOS/Windows 阻塞
- notify: 仅 needs version+check + always(),失败也能发飞书;build 状态通过 API 查询

Made-with: Cursor
2026-03-18 16:04:16 +08:00

423 lines
15 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: Secrets CLI - Build & Release
on:
push:
branches: [main]
paths:
- 'src/**'
- 'Cargo.toml'
- 'Cargo.lock'
- '.gitea/workflows/secrets.yml'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: write
env:
BINARY_NAME: secrets
CARGO_INCREMENTAL: 0
CARGO_NET_RETRY: 10
CARGO_TERM_COLOR: always
RUST_BACKTRACE: short
jobs:
version:
name: 版本 & Release
runs-on: debian
outputs:
version: ${{ steps.ver.outputs.version }}
tag: ${{ steps.ver.outputs.tag }}
tag_exists: ${{ steps.ver.outputs.tag_exists }}
release_id: ${{ steps.release.outputs.release_id }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 解析版本
id: ver
run: |
version=$(grep -m1 '^version' Cargo.toml | sed 's/.*"\(.*\)".*/\1/')
tag="secrets-${version}"
previous_tag=$(git tag --list 'secrets-*' --sort=-v:refname | awk -v tag="$tag" '$0 != tag { print; exit }')
echo "version=${version}" >> "$GITHUB_OUTPUT"
echo "tag=${tag}" >> "$GITHUB_OUTPUT"
echo "previous_tag=${previous_tag}" >> "$GITHUB_OUTPUT"
if git rev-parse "refs/tags/${tag}" >/dev/null 2>&1; then
echo "tag_exists=true" >> "$GITHUB_OUTPUT"
echo "版本 ${tag} 已存在"
else
echo "tag_exists=false" >> "$GITHUB_OUTPUT"
echo "将创建新版本 ${tag}"
fi
- name: 创建 Tag
if: steps.ver.outputs.tag_exists == 'false'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag -a "${{ steps.ver.outputs.tag }}" -m "Release ${{ steps.ver.outputs.tag }}"
git push origin "${{ steps.ver.outputs.tag }}"
- name: 解析或创建 Release
id: release
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
run: |
if [ -z "$RELEASE_TOKEN" ]; then
echo "release_id=" >> "$GITHUB_OUTPUT"
exit 0
fi
command -v jq >/dev/null 2>&1 || (sudo apt-get update -qq && sudo apt-get install -y -qq jq)
tag="${{ steps.ver.outputs.tag }}"
version="${{ steps.ver.outputs.version }}"
release_api="${{ github.server_url }}/api/v1/repos/${{ github.repository }}/releases"
http_code=$(curl -sS -o /tmp/release.json -w '%{http_code}' \
-H "Authorization: token $RELEASE_TOKEN" \
"${release_api}/tags/${tag}")
if [ "$http_code" = "200" ]; then
release_id=$(jq -r '.id // empty' /tmp/release.json)
if [ -n "$release_id" ]; then
echo "已找到现有 Release: ${release_id}"
echo "release_id=${release_id}" >> "$GITHUB_OUTPUT"
exit 0
fi
fi
previous_tag="${{ steps.ver.outputs.previous_tag }}"
if [ -n "$previous_tag" ]; then
changes=$(git log --pretty=format:'- %s (%h)' "${previous_tag}..HEAD")
else
changes=$(git log --pretty=format:'- %s (%h)')
fi
[ -z "$changes" ] && changes="- 首次发布"
body=$(printf '## 变更日志\n\n%s' "$changes")
payload=$(jq -n \
--arg tag "$tag" \
--arg name "${{ env.BINARY_NAME }} ${version}" \
--arg body "$body" \
'{tag_name: $tag, name: $name, body: $body, draft: true}')
http_code=$(curl -sS -o /tmp/create-release.json -w '%{http_code}' \
-H "Authorization: token $RELEASE_TOKEN" \
-H "Content-Type: application/json" \
-X POST "$release_api" \
-d "$payload")
if [ "$http_code" = "201" ] || [ "$http_code" = "200" ]; then
release_id=$(jq -r '.id // empty' /tmp/create-release.json)
fi
if [ -n "$release_id" ]; then
echo "已创建草稿 Release: ${release_id}"
echo "release_id=${release_id}" >> "$GITHUB_OUTPUT"
else
echo "⚠ 创建 Release 失败 (HTTP ${http_code}),跳过产物上传"
cat /tmp/create-release.json 2>/dev/null || true
echo "release_id=" >> "$GITHUB_OUTPUT"
fi
check:
name: 质量检查 (fmt / clippy / test)
runs-on: debian
timeout-minutes: 10
steps:
- name: 安装 Rust
run: |
if ! command -v cargo >/dev/null 2>&1; then
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
fi
source "$HOME/.cargo/env" 2>/dev/null || true
rustup component add rustfmt clippy
- uses: actions/checkout@v4
- name: 缓存 Cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
target
key: cargo-check-${{ hashFiles('Cargo.lock') }}
restore-keys: |
cargo-check-
- run: cargo fmt -- --check
- run: cargo clippy --locked -- -D warnings
- run: cargo test --locked
build-linux:
name: Build (x86_64-unknown-linux-musl)
needs: [version, check]
runs-on: debian
timeout-minutes: 10
steps:
- name: 安装依赖
run: |
sudo apt-get update
sudo apt-get install -y pkg-config musl-tools binutils curl
if ! command -v cargo >/dev/null 2>&1; then
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable
fi
source "$HOME/.cargo/env" 2>/dev/null || true
rustup target add x86_64-unknown-linux-musl
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
- uses: actions/checkout@v4
- name: 缓存 Cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
target
key: cargo-x86_64-unknown-linux-musl-${{ hashFiles('Cargo.lock') }}
restore-keys: |
cargo-x86_64-unknown-linux-musl-
- run: cargo build --release --locked --target x86_64-unknown-linux-musl
- run: strip target/x86_64-unknown-linux-musl/release/${{ env.BINARY_NAME }}
- name: 上传 Release 产物
if: needs.version.outputs.release_id != ''
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
run: |
[ -z "$RELEASE_TOKEN" ] && exit 0
tag="${{ needs.version.outputs.tag }}"
bin="target/x86_64-unknown-linux-musl/release/${{ env.BINARY_NAME }}"
archive="${{ env.BINARY_NAME }}-${tag}-x86_64-linux-musl.tar.gz"
tar -czf "$archive" -C "$(dirname "$bin")" "$(basename "$bin")"
curl -fsS -H "Authorization: token $RELEASE_TOKEN" \
-F "attachment=@${archive}" \
"${{ github.server_url }}/api/v1/repos/${{ github.repository }}/releases/${{ needs.version.outputs.release_id }}/assets"
build-macos:
name: Build (aarch64-apple-darwin)
needs: [version, check]
if: vars.BUILD_MACOS != 'false'
runs-on: darwin-arm64
timeout-minutes: 10
steps:
- name: 安装依赖
run: |
if ! command -v cargo >/dev/null 2>&1; then
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable
fi
source "$HOME/.cargo/env" 2>/dev/null || true
rustup target add aarch64-apple-darwin
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
- uses: actions/checkout@v4
- name: 缓存 Cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
target
key: cargo-aarch64-apple-darwin-${{ hashFiles('Cargo.lock') }}
restore-keys: |
cargo-aarch64-apple-darwin-
- run: cargo build --release --locked --target aarch64-apple-darwin
- run: strip -x target/aarch64-apple-darwin/release/${{ env.BINARY_NAME }}
- name: 上传 Release 产物
if: needs.version.outputs.release_id != ''
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
run: |
[ -z "$RELEASE_TOKEN" ] && exit 0
tag="${{ needs.version.outputs.tag }}"
bin="target/aarch64-apple-darwin/release/${{ env.BINARY_NAME }}"
archive="${{ env.BINARY_NAME }}-${tag}-aarch64-macos.tar.gz"
tar -czf "$archive" -C "$(dirname "$bin")" "$(basename "$bin")"
curl -fsS -H "Authorization: token $RELEASE_TOKEN" \
-F "attachment=@${archive}" \
"${{ github.server_url }}/api/v1/repos/${{ github.repository }}/releases/${{ needs.version.outputs.release_id }}/assets"
build-windows:
name: Build (x86_64-pc-windows-msvc)
needs: [version, check]
if: vars.BUILD_WINDOWS == 'true'
runs-on: windows
timeout-minutes: 10
steps:
- name: 安装依赖
shell: pwsh
run: |
if (-not (Get-Command cargo -ErrorAction SilentlyContinue)) {
Invoke-WebRequest -Uri "https://win.rustup.rs/x86_64" -OutFile rustup-init.exe
.\rustup-init.exe -y --default-toolchain stable
Remove-Item rustup-init.exe
}
rustup target add x86_64-pc-windows-msvc
- uses: actions/checkout@v4
- name: 缓存 Cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
target
key: cargo-x86_64-pc-windows-msvc-${{ hashFiles('Cargo.lock') }}
restore-keys: |
cargo-x86_64-pc-windows-msvc-
- name: 构建
shell: pwsh
run: cargo build --release --locked --target x86_64-pc-windows-msvc
- name: 上传 Release 产物
if: needs.version.outputs.release_id != ''
shell: pwsh
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
run: |
if (-not $env:RELEASE_TOKEN) { exit 0 }
$tag = "${{ needs.version.outputs.tag }}"
$bin = "target\x86_64-pc-windows-msvc\release\${{ env.BINARY_NAME }}.exe"
$archive = "${{ env.BINARY_NAME }}-${tag}-x86_64-windows.zip"
Compress-Archive -Path $bin -DestinationPath $archive -Force
$url = "${{ github.server_url }}/api/v1/repos/${{ github.repository }}/releases/${{ needs.version.outputs.release_id }}/assets"
Invoke-RestMethod -Uri $url -Method Post `
-Headers @{ "Authorization" = "token $env:RELEASE_TOKEN" } `
-Form @{ attachment = Get-Item $archive }
publish-release:
name: 发布草稿 Release
needs: [version, build-linux]
if: needs.version.outputs.release_id != ''
runs-on: debian
timeout-minutes: 2
steps:
- name: 发布草稿
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
run: |
[ -z "$RELEASE_TOKEN" ] && exit 0
linux_r="${{ needs.build-linux.result }}"
if [ "$linux_r" != "success" ]; then
echo "Linux 构建未成功 (${linux_r}),保留草稿 Release"
exit 0
fi
release_api="${{ github.server_url }}/api/v1/repos/${{ github.repository }}/releases/${{ needs.version.outputs.release_id }}"
http_code=$(curl -sS -o /tmp/publish-release.json -w '%{http_code}' \
-H "Authorization: token $RELEASE_TOKEN" \
-H "Content-Type: application/json" \
-X PATCH "$release_api" \
-d '{"draft":false}')
if [ "$http_code" != "200" ]; then
echo "发布草稿 Release 失败 (HTTP ${http_code})"
cat /tmp/publish-release.json 2>/dev/null || true
exit 1
fi
notify:
name: 通知
needs: [version, check]
if: always() && github.event_name == 'push'
runs-on: debian
timeout-minutes: 1
continue-on-error: true
steps:
- uses: actions/checkout@v4
- name: 发送飞书通知
env:
WEBHOOK_URL: ${{ vars.WEBHOOK_URL }}
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
run: |
[ -z "$WEBHOOK_URL" ] && exit 0
command -v jq >/dev/null 2>&1 || (sudo apt-get update -qq && sudo apt-get install -y -qq jq)
tag="${{ needs.version.outputs.tag }}"
tag_exists="${{ needs.version.outputs.tag_exists }}"
commit=$(git log -1 --pretty=format:"%s" 2>/dev/null || echo "N/A")
url="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_number }}"
version_r="${{ needs.version.result }}"
check_r="${{ needs.check.result }}"
# 通过 API 查询当前 run 的构建 job 状态best-effort
linux_r="unknown"; macos_r="unknown"; windows_r="unknown"; publish_r="unknown"
if [ -n "$RELEASE_TOKEN" ]; then
sleep 3
run_api="${{ github.server_url }}/api/v1/repos/${{ github.repository }}/actions/tasks"
http_code=$(curl -sS -o /tmp/jobs.json -w '%{http_code}' \
-H "Authorization: token $RELEASE_TOKEN" "$run_api" 2>/dev/null) || true
if [ "$http_code" = "200" ] && [ -f /tmp/jobs.json ]; then
get_status() {
jq -r --arg name "$1" '
(.workflow_runs // .task_runs // . // [])[]?
| select(.name == $name)
| .status // "unknown"
' /tmp/jobs.json 2>/dev/null | head -1
}
s=$(get_status "Build (x86_64-unknown-linux-musl)"); [ -n "$s" ] && linux_r="$s"
s=$(get_status "Build (aarch64-apple-darwin)"); [ -n "$s" ] && macos_r="$s"
s=$(get_status "Build (x86_64-pc-windows-msvc)"); [ -n "$s" ] && windows_r="$s"
s=$(get_status "发布草稿 Release"); [ -n "$s" ] && publish_r="$s"
fi
fi
if [ "$version_r" = "success" ] && [ "$check_r" = "success" ]; then
status="检查通过 ✅"
else
status="检查失败 ❌"
fi
icon() {
case "$1" in
success) echo "✅" ;;
skipped) echo "⏭" ;;
unknown) echo "⏳" ;;
*) echo "❌" ;;
esac
}
msg="${{ env.BINARY_NAME }} ${status}"
if [ "$tag_exists" = "false" ]; then
msg="${msg}
🆕 新版本 ${tag}"
else
msg="${msg}
🔄 重复构建 ${tag}"
fi
msg="${msg}
质量检查:$(icon "$check_r")
构建结果linux$(icon "$linux_r") macOS$(icon "$macos_r") windows$(icon "$windows_r")
Release$(icon "$publish_r")
提交:${commit}
作者:${{ github.actor }}
详情:${url}"
payload=$(jq -n --arg text "$msg" '{msg_type: "text", content: {text: $text}}')
curl -sS -H "Content-Type: application/json" -X POST -d "$payload" "$WEBHOOK_URL"