ci: 优化 workflow,拆分 check job,预创建 Release,超时 10m
Some checks failed
Secrets CLI - Build & Release / 版本 & Release (push) Successful in 1s
Secrets CLI - Build & Release / 质量检查 (fmt / clippy / test) (push) Successful in 2m20s
Secrets CLI - Build & Release / Build (aarch64-apple-darwin) (push) Successful in 53s
Secrets CLI - Build & Release / Build (x86_64-unknown-linux-musl) (push) Successful in 2m48s
Secrets CLI - Build & Release / 通知 (push) Has been cancelled
Secrets CLI - Build & Release / Build (x86_64-pc-windows-msvc) (push) Has been cancelled

- 新增 check job:fmt/clippy/test 仅在 Linux 跑一次
- version job 预创建 Release,消除多 job 竞态
- build job 只编译+上传,加 --locked
- 超时从 30m 改为 10m
- AGENTS.md 补充提交前检查规范

Made-with: Cursor
This commit is contained in:
voson
2026-03-18 14:30:54 +08:00
parent 52ee858fd7
commit 3203984fb4
2 changed files with 134 additions and 150 deletions

View File

@@ -24,21 +24,22 @@ env:
RUST_BACKTRACE: short
jobs:
# ========== 版本检查(只跑一次,供后续 job 共用==========
# ========== 版本检查 + Release 预创建(单次运行,消除多 job 竞态==========
version:
name: 检查版本
name: 版本 & Release
runs-on: debian
outputs:
version: ${{ steps.version.outputs.version }}
tag: ${{ steps.version.outputs.tag }}
tag_exists: ${{ steps.version.outputs.tag_exists }}
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: version
- name: 解析版本
id: ver
run: |
version=$(grep -m1 '^version' Cargo.toml | sed 's/.*"\(.*\)".*/\1/')
tag="secrets-${version}"
@@ -54,19 +55,73 @@ jobs:
fi
- name: 创建 Tag
if: steps.version.outputs.tag_exists == 'false'
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.version.outputs.tag }}" -m "Release ${{ steps.version.outputs.tag }}"
git push origin "${{ steps.version.outputs.tag }}"
git tag -a "${{ steps.ver.outputs.tag }}" -m "Release ${{ steps.ver.outputs.tag }}"
git push origin "${{ steps.ver.outputs.tag }}"
# ========== 矩阵构建 ==========
- name: 预创建 Release
id: release
if: steps.ver.outputs.tag_exists == 'false'
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 || (sudo apt-get update -qq && sudo apt-get install -y -qq jq)
tag="${{ steps.ver.outputs.tag }}"
url="${{ github.server_url }}/api/v1/repos/${{ github.repository }}/releases"
release_id=$(curl -sS -H "Authorization: token $RELEASE_TOKEN" \
-H "Content-Type: application/json" -X POST "$url" \
-d "{\"tag_name\":\"${tag}\",\"name\":\"${tag}\",\"body\":\"Release ${tag}\"}" \
| jq -r '.id // empty')
echo "release_id=${release_id}" >> $GITHUB_OUTPUT
# ========== 代码质量检查(只在 Linux 跑一次)==========
check:
name: 质量检查 (fmt / clippy / test)
runs-on: debian
timeout-minutes: 10
steps:
- name: 安装 Rust
run: |
if ! command -v cargo &>/dev/null; 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:
name: Build (${{ matrix.target }})
needs: version
continue-on-error: true # 某平台失败/超时不阻断其他平台和 notify
timeout-minutes: 30 # runner 不在线时 30 分钟后放弃
needs: [version, check]
continue-on-error: true
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
@@ -86,35 +141,24 @@ jobs:
runs-on: ${{ matrix.runner }}
steps:
# ========== 环境准备 ==========
- name: 安装依赖 (Linux)
if: matrix.os == 'linux'
run: |
sudo apt-get update
sudo apt-get install -y jq curl git pkg-config musl-tools binutils
sudo apt-get update && sudo apt-get install -y pkg-config musl-tools binutils curl
if ! command -v cargo &>/dev/null; then
echo "安装 Rust 工具链..."
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable
source "$HOME/.cargo/env"
rustup component add rustfmt clippy
fi
source "$HOME/.cargo/env" 2>/dev/null || true
rustup target add ${{ matrix.target }}
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
- name: 安装依赖 (macOS)
if: matrix.os == 'macos'
run: |
brew install jq
if ! command -v cargo &>/dev/null; then
echo "安装 Rust 工具链..."
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable
source "$HOME/.cargo/env"
rustup component add rustfmt clippy
fi
source "$HOME/.cargo/env" 2>/dev/null || true
rustup target add ${{ matrix.target }}
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
@@ -122,22 +166,16 @@ jobs:
if: matrix.os == 'windows'
shell: pwsh
run: |
# 检查 Rust 是否已安装
if (-not (Get-Command cargo -ErrorAction SilentlyContinue)) {
Write-Host "安装 Rust 工具链..."
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 component add rustfmt clippy
rustup target add ${{ matrix.target }}
- uses: actions/checkout@v4
with:
fetch-depth: 0
# ========== Cargo 缓存 ==========
- name: 缓存 Cargo 依赖
- name: 缓存 Cargo
uses: actions/cache@v4
with:
path: |
@@ -145,169 +183,99 @@ jobs:
~/.cargo/registry/cache
~/.cargo/git/db
target
key: cargo-secrets-${{ matrix.target }}-${{ hashFiles('Cargo.lock') }}
restore-keys: |
cargo-secrets-${{ matrix.target }}-
- name: 检查代码格式
if: matrix.os != 'windows'
run: cargo fmt -- --check
- name: 检查代码格式 (Windows)
if: matrix.os == 'windows'
shell: pwsh
run: cargo fmt -- --check
- name: 运行 Clippy 检查
if: matrix.os != 'windows'
run: cargo clippy --release --target ${{ matrix.target }} -- -D warnings
- name: 运行 Clippy 检查 (Windows)
if: matrix.os == 'windows'
shell: pwsh
run: cargo clippy --release --target ${{ matrix.target }} -- -D warnings
key: cargo-${{ matrix.target }}-${{ hashFiles('Cargo.lock') }}
restore-keys: cargo-${{ matrix.target }}-
- name: 构建
if: matrix.os != 'windows'
env:
GIT_TAG: ${{ needs.version.outputs.version }}
run: cargo build --release --target ${{ matrix.target }} --verbose
run: cargo build --release --locked --target ${{ matrix.target }}
- name: 构建 (Windows)
if: matrix.os == 'windows'
shell: pwsh
env:
GIT_TAG: ${{ needs.version.outputs.version }}
run: cargo build --release --target ${{ matrix.target }} --verbose
run: cargo build --release --locked --target ${{ matrix.target }}
- name: Strip 二进制 (Linux)
- name: Strip (Linux)
if: matrix.os == 'linux'
run: strip target/${{ matrix.target }}/release/${{ env.BINARY_NAME }}
- name: Strip 二进制 (macOS)
- name: Strip (macOS)
if: matrix.os == 'macos'
run: strip -x target/${{ matrix.target }}/release/${{ env.BINARY_NAME }}
# ========== 上传 Release 产物 ==========
- name: 上传 Release 产物 (Linux/macOS)
if: needs.version.outputs.tag_exists == 'false' && matrix.os != 'windows'
- name: 上传产物 (Linux/macOS)
if: needs.version.outputs.tag_exists == 'false' && needs.version.outputs.release_id && matrix.os != 'windows'
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
run: |
[ -z "$RELEASE_TOKEN" ] && echo "跳过:未配置 RELEASE_TOKEN" && exit 0
[ -z "$RELEASE_TOKEN" ] && exit 0
tag="${{ needs.version.outputs.tag }}"
binary="target/${{ matrix.target }}/release/${{ env.BINARY_NAME }}"
bin="target/${{ matrix.target }}/release/${{ env.BINARY_NAME }}"
archive="${{ env.BINARY_NAME }}-${tag}-${{ matrix.archive_suffix }}.tar.gz"
tar -czf "$archive" -C "$(dirname $binary)" "$(basename $binary)"
# 查找已有 Release由首个完成的 job 创建,后续 job 直接上传)
release_url="${{ github.server_url }}/api/v1/repos/${{ github.repository }}/releases"
release_id=$(curl -sS -H "Authorization: token $RELEASE_TOKEN" \
"${release_url}/tags/${tag}" | jq -r '.id // empty')
if [ -z "$release_id" ]; then
release_id=$(curl -sS -H "Authorization: token $RELEASE_TOKEN" \
-H "Content-Type: application/json" \
-X POST "$release_url" \
-d "{\"tag_name\": \"${tag}\", \"name\": \"${tag}\", \"body\": \"Release ${tag}\"}" \
| jq -r '.id')
fi
upload_url="${{ github.server_url }}/api/v1/repos/${{ github.repository }}/releases/${release_id}/assets"
tar -czf "$archive" -C "$(dirname $bin)" "$(basename $bin)"
curl -sS -H "Authorization: token $RELEASE_TOKEN" \
-F "attachment=@${archive}" \
"$upload_url"
"${{ github.server_url }}/api/v1/repos/${{ github.repository }}/releases/${{ needs.version.outputs.release_id }}/assets"
echo "已上传: ${archive}"
echo "已上传: ${archive} → Release ${tag}"
- name: 上传 Release 产物 (Windows)
if: needs.version.outputs.tag_exists == 'false' && matrix.os == 'windows'
- name: 上传产物 (Windows)
if: needs.version.outputs.tag_exists == 'false' && needs.version.outputs.release_id && matrix.os == 'windows'
shell: pwsh
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
run: |
if (-not $env:RELEASE_TOKEN) { Write-Host "跳过:未配置 RELEASE_TOKEN"; exit 0 }
if (-not $env:RELEASE_TOKEN) { exit 0 }
$tag = "${{ needs.version.outputs.tag }}"
$binary = "target\${{ matrix.target }}\release\${{ env.BINARY_NAME }}.exe"
$bin = "target\${{ matrix.target }}\release\${{ env.BINARY_NAME }}.exe"
$archive = "${{ env.BINARY_NAME }}-${tag}-${{ matrix.archive_suffix }}.zip"
Compress-Archive -Path $bin -DestinationPath $archive
$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 }
Write-Host "已上传: ${archive}"
Compress-Archive -Path $binary -DestinationPath $archive
$headers = @{ "Authorization" = "token $env:RELEASE_TOKEN"; "Content-Type" = "application/json" }
$release_url = "${{ github.server_url }}/api/v1/repos/${{ github.repository }}/releases"
# 查找已有 Release
$existing = Invoke-RestMethod -Uri "${release_url}/tags/${tag}" -Headers $headers -ErrorAction SilentlyContinue
if ($existing.id) {
$release_id = $existing.id
} else {
$body = @{ tag_name = $tag; name = $tag; body = "Release ${tag}" } | ConvertTo-Json
$release_id = (Invoke-RestMethod -Uri $release_url -Method Post -Headers $headers -Body $body).id
}
$upload_url = "${release_url}/${release_id}/assets"
$upload_headers = @{ "Authorization" = "token $env:RELEASE_TOKEN" }
$form = @{ attachment = Get-Item $archive }
Invoke-RestMethod -Uri $upload_url -Method Post -Headers $upload_headers -Form $form
Write-Host "已上传: ${archive} → Release ${tag}"
# ========== 汇总通知 ==========
# ========== 通知 ==========
notify:
name: 发送通知
name: 通知
needs: [version, build]
if: always() && github.event_name == 'push'
runs-on: debian
steps:
- uses: actions/checkout@v4
- name: 发送通知
- name: 发送飞书通知
continue-on-error: true
env:
WEBHOOK_URL: ${{ vars.WEBHOOK_URL }}
run: |
[ -z "$WEBHOOK_URL" ] && exit 0
command -v jq &>/dev/null || (sudo apt-get update -qq && sudo apt-get install -y -qq jq)
tag="${{ needs.version.outputs.tag }}"
tag_exists="${{ needs.version.outputs.tag_exists }}"
build_result="${{ needs.build.result }}"
result="${{ needs.build.result }}"
[ "$result" = "success" ] && status="构建成功 ✅" || status="构建失败 ❌"
if [ "$build_result" = "success" ]; then
status_text="构建成功 ✅"
else
status_text="构建失败 ❌"
fi
commit=$(git log -1 --pretty=format:"%s" 2>/dev/null || echo "N/A")
url="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_number }}"
commit_title=$(git log -1 --pretty=format:"%s" 2>/dev/null || echo "N/A")
workflow_url="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_number }}"
if [ "$build_result" != "success" ]; then
payload=$(jq -n \
--arg title "${{ env.BINARY_NAME }} ${status_text}" \
--arg commit "$commit_title" \
--arg version "$tag" \
--arg author "${{ github.actor }}" \
--arg url "$workflow_url" \
'{msg_type: "text", content: {text: "\($title)\n提交\($commit)\n版本\($version)\n作者\($author)\n详情\($url)"}}')
if [ "$result" != "success" ]; then
extra=""
elif [ "$tag_exists" = "false" ]; then
payload=$(jq -n \
--arg title "${{ env.BINARY_NAME }} ${status_text}" \
--arg commit "$commit_title" \
--arg version "$tag" \
--arg author "${{ github.actor }}" \
--arg url "$workflow_url" \
'{msg_type: "text", content: {text: "\($title)\n🆕 新版本已发布 (linux / macOS / windows)\n提交\($commit)\n版本\($version)\n作者\($author)\n详情\($url)"}}')
extra="🆕 新版本已发布 (linux / macOS / windows)"
else
payload=$(jq -n \
--arg title "${{ env.BINARY_NAME }} ${status_text}" \
--arg commit "$commit_title" \
--arg version "$tag" \
--arg author "${{ github.actor }}" \
--arg url "$workflow_url" \
'{msg_type: "text", content: {text: "\($title)\n🔄 重复构建\n提交\($commit)\n版本\($version)\n作者\($author)\n详情\($url)"}}')
extra="🔄 重复构建"
fi
msg="${{ env.BINARY_NAME }} ${status}"
[ -n "$extra" ] && msg="${msg}
${extra}"
msg="${msg}
提交:${commit}
版本:${tag}
作者:${{ 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"

View File

@@ -114,6 +114,22 @@ secrets search --tag hongkong
- 新增 `kind` 类型时:只需在 `add` 调用时传入,无需改代码
- 字段命名CLI 短标志 `-n`=namespace`-m`=meta`-s`=secret`-q`=query
## 提交前检查(必须全部通过)
每次提交代码前,请在本地依次执行以下三项检查,**全部通过后再 push**
```bash
cargo fmt -- --check # 格式检查(不通过则运行 cargo fmt 修复)
cargo clippy -- -D warnings # Lint 检查(消除所有 warning
cargo test # 单元/集成测试
```
或一次性执行:
```bash
cargo fmt -- --check && cargo clippy -- -D warnings && cargo test
```
## CI/CD
- Gitea Actionsrunner: debian