Files
secrets/.gitea/workflows/secrets.yml
voson 2ad1abe846
Some checks failed
Secrets CLI - Build & Release / 版本 & Release (push) Successful in 2s
Secrets CLI - Build & Release / 探测 Runner (push) Successful in 1s
Secrets CLI - Build & Release / 质量检查 (fmt / clippy / test) (push) Successful in 22s
Secrets CLI - Build & Release / Build (aarch64-apple-darwin) (push) Successful in 18s
Secrets CLI - Build & Release / Build (x86_64-unknown-linux-musl) (push) Successful in 27s
Secrets CLI - Build & Release / 通知 (push) Has been cancelled
Secrets CLI - Build & Release / Build (x86_64-pc-windows-msvc) (push) Has been cancelled
ci: fix release 401 handling and notify based on actual results
- Replace curl -fsS with HTTP status code checking to avoid hard failures on 401/404
- Release creation failure no longer blocks the entire workflow, just skips asset upload
- Notification now depends on all jobs and reports actual success/failure per platform

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

440 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}')
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
probe-runners:
name: 探测 Runner
runs-on: debian
outputs:
has_linux: ${{ steps.probe.outputs.has_linux }}
has_macos: ${{ steps.probe.outputs.has_macos }}
has_windows: ${{ steps.probe.outputs.has_windows }}
steps:
- name: 查询可用 Runner
id: probe
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
run: |
if [ -z "$RELEASE_TOKEN" ]; then
echo "has_linux=true" >> "$GITHUB_OUTPUT"
echo "has_macos=true" >> "$GITHUB_OUTPUT"
echo "has_windows=true" >> "$GITHUB_OUTPUT"
exit 0
fi
command -v jq >/dev/null 2>&1 || (sudo apt-get update -qq && sudo apt-get install -y -qq jq)
runners=$(curl -fsS -H "Authorization: token $RELEASE_TOKEN" \
"${{ github.server_url }}/api/v1/repos/${{ github.repository }}/actions/runners" || true)
if [ -z "$runners" ]; then
echo "has_linux=true" >> "$GITHUB_OUTPUT"
echo "has_macos=true" >> "$GITHUB_OUTPUT"
echo "has_windows=true" >> "$GITHUB_OUTPUT"
exit 0
fi
has_runner() {
local label="$1"
printf '%s' "$runners" | jq -e --arg label "$label" '
(.runners // .data // . // [])
| any(
(
(.status // (if (.online // false) then "online" else "offline" end))
| ascii_downcase
) == "online"
and (
(.labels // [])
| map(if type == "object" then (.name // .label // "") else tostring end)
| index($label)
) != null
)
' >/dev/null
}
if has_runner "debian"; then
echo "has_linux=true" >> "$GITHUB_OUTPUT"
else
echo "has_linux=false" >> "$GITHUB_OUTPUT"
fi
if has_runner "darwin-arm64"; then
echo "has_macos=true" >> "$GITHUB_OUTPUT"
else
echo "has_macos=false" >> "$GITHUB_OUTPUT"
fi
if has_runner "windows"; then
echo "has_windows=true" >> "$GITHUB_OUTPUT"
else
echo "has_windows=false" >> "$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, probe-runners, check]
if: needs.probe-runners.outputs.has_linux == 'true'
runs-on: debian
timeout-minutes: 10
continue-on-error: true
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, probe-runners, check]
if: needs.probe-runners.outputs.has_macos == 'true'
runs-on: darwin-arm64
timeout-minutes: 10
continue-on-error: true
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, probe-runners, check]
if: needs.probe-runners.outputs.has_windows == 'true'
runs-on: windows
timeout-minutes: 10
continue-on-error: true
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 }
notify:
name: 通知
needs: [version, probe-runners, check, build-linux, build-macos, build-windows]
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 }}
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 }}"
linux_r="${{ needs.build-linux.result }}"
macos_r="${{ needs.build-macos.result }}"
windows_r="${{ needs.build-windows.result }}"
if [ "$version_r" = "success" ] && [ "$check_r" = "success" ]; then
status="构建成功 ✅"
else
status="构建失败 ❌"
fi
icon() {
case "$1" in
success) echo "✅" ;;
skipped) echo "⏭" ;;
*) echo "❌" ;;
esac
}
msg="${{ env.BINARY_NAME }} ${status}"
if [ "$tag_exists" = "false" ]; then
msg="${msg}
🆕 新版本 ${tag}"
else
msg="${msg}
🔄 重复构建 ${tag}"
fi
msg="${msg}
构建结果linux$(icon "$linux_r") macOS$(icon "$macos_r") windows$(icon "$windows_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"