ci: refine release workflow

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Zyy
2026-07-03 10:25:44 +08:00
co-authored by Codex
parent 345d884ac1
commit 71279877df
5 changed files with 40 additions and 7 deletions
+35 -1
View File
@@ -15,6 +15,10 @@ permissions:
contents: write
packages: write
concurrency:
group: release-${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }}
cancel-in-progress: false
env:
REGISTRY: ghcr.io
IMAGE_NAME: zyycn/codex-proxy-rs
@@ -29,12 +33,14 @@ jobs:
git_sha: ${{ steps.version.outputs.git_sha }}
platform_matrix: ${{ steps.version.outputs.platform_matrix }}
docker_platforms: ${{ steps.version.outputs.docker_platforms }}
previous_tag: ${{ steps.version.outputs.previous_tag }}
steps:
- name: Checkout
uses: actions/checkout@v7
with:
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref }}
fetch-depth: 0
- name: Read release metadata
id: version
@@ -45,6 +51,7 @@ jobs:
ruby <<'RUBY' >> "$GITHUB_OUTPUT"
require "json"
require "open3"
require "rubygems"
require "time"
require "yaml"
@@ -62,13 +69,19 @@ jobs:
value.strip
end
def version_sort_key(version)
Gem::Version.new(version.split("+", 2).first)
rescue ArgumentError
nil
end
version_path = "release/version.yaml"
platforms_path = "release/platforms.yaml"
version_data = YAML.load_file(version_path)
platforms_data = YAML.load_file(platforms_path)
version = require_string(version_data, "version", version_path).delete_prefix("v")
tag_prefix = require_string(version_data, "tagPrefix", version_path)
tag_prefix = "v"
expected_tag = "#{tag_prefix}#{version}"
release_tag = ENV.fetch("RELEASE_TAG")
fail("Release tag #{release_tag} does not match #{version_path} tag #{expected_tag}") unless release_tag == expected_tag
@@ -101,6 +114,23 @@ jobs:
git_sha, status = Open3.capture2("git", "rev-parse", "HEAD")
fail("failed to resolve git sha") unless status.success?
matrix = JSON.generate({ "include" => platforms })
current_sort_key = version_sort_key(version)
tags, status = Open3.capture2("git", "tag", "--list", "#{tag_prefix}*", "--merged", "HEAD")
fail("failed to list git tags") unless status.success?
previous_tag = tags
.lines
.map(&:strip)
.reject(&:empty?)
.reject { |tag| tag == release_tag }
.filter_map do |tag|
tag_version = tag.delete_prefix(tag_prefix)
next unless tag_version.match?(SEMVER)
sort_key = version_sort_key(tag_version)
next unless sort_key && current_sort_key && sort_key < current_sort_key
[sort_key, tag]
end
.max_by(&:first)
&.last
puts "tag=#{release_tag}"
puts "version=#{version}"
@@ -108,6 +138,7 @@ jobs:
puts "git_sha=#{git_sha.strip}"
puts "platform_matrix=#{matrix}"
puts "docker_platforms=#{docker_platforms.join(",")}"
puts "previous_tag=#{previous_tag}"
RUBY
build-frontend:
@@ -149,6 +180,7 @@ jobs:
retention-days: 1
build-binary:
name: build-binary (${{ matrix.os }}-${{ matrix.arch }})
needs: [release-info, build-frontend]
strategy:
fail-fast: false
@@ -416,6 +448,7 @@ jobs:
with:
tag_name: ${{ needs.release-info.outputs.tag }}
generate_release_notes: true
previous_tag: ${{ needs.release-info.outputs.previous_tag }}
body: |
## 📥 Installation
@@ -432,5 +465,6 @@ jobs:
- [GitHub Repository](https://github.com/${{ github.repository }})
- [Installation Guide](https://github.com/${{ github.repository }}/blob/main/deploy/README.md)
fail_on_unmatched_files: true
files: |
dist/release/*
+2 -2
View File
@@ -100,12 +100,12 @@ flowchart LR
版本和平台发布契约集中在 `release/`:
- `release/version.yaml`:产品版本和 tag 前缀。
- `release/version.yaml`:产品版本,发布 tag 固定使用 `v` 前缀。
- `release/platforms.yaml`:Release asset 构建平台、归档格式和 Docker 平台。
日常发布只需要执行 `release/publish 0.1.4`。该命令会更新 `release/version.yaml`、生成带署名的版本提交、创建 `v0.1.4` tag,并 push 分支和 tag 触发发布 workflow。
发布 workflow 会校验触发 tag 必须等于 `tagPrefix + version`。发布构建时通过 `CPR_VERSION`、`CPR_GIT_SHA`、`CPR_BUILD_TIME` 和 `CPR_BUILD_TYPE=release` 注入编译期元数据。
发布 workflow 会校验触发 tag 必须等于 `v` + `version`。发布构建时通过 `CPR_VERSION`、`CPR_GIT_SHA`、`CPR_BUILD_TIME` 和 `CPR_BUILD_TYPE=release` 注入编译期元数据。
`backend/build/build.rs` 负责把这些值写入二进制。没有 `CPR_VERSION` 时,版本回落到 `release/version.yaml`,最后才回落到 Cargo 的 `CARGO_PKG_VERSION`。
+2 -2
View File
@@ -3,6 +3,7 @@ set -euo pipefail
APP_NAME="codex-proxy-rs"
VERSION_FILE="release/version.yaml"
TAG_PREFIX="v"
SEMVER='^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$'
SIGNATURE="Co-authored-by: Codex <noreply@openai.com>"
@@ -94,8 +95,7 @@ current_version="$(read_version_key version)"
current_version="${current_version#v}"
[[ "$version" != "$current_version" ]] || die "$VERSION_FILE is already $version"
tag_prefix="$(read_version_key tagPrefix)"
tag="${tag_prefix}${version}"
tag="${TAG_PREFIX}${version}"
if git rev-parse --quiet --verify "refs/tags/$tag" >/dev/null; then
die "local tag already exists: $tag"
-1
View File
@@ -1,2 +1 @@
version: "0.1.4"
tagPrefix: "v"
@@ -90,7 +90,7 @@ docker compose -f deploy/docker-compose.yml up -d
- Release workflow:`.github/workflows/release.yml`。
- `v*` tag 触发发布。
- 日常发布入口:`release/publish <version>`。该命令会更新 `release/version.yaml`、提交版本变更、创建 tag,并 push 分支和 tag 触发 workflow。
- 产品版本来源是 `release/version.yaml`;workflow 会校验触发 tag 等于 `tagPrefix + version`,并通过 `CPR_VERSION` build arg 写入编译期元数据。
- 产品版本来源是 `release/version.yaml`;workflow 会校验触发 tag 等于 `v` + `version`,并通过 `CPR_VERSION` build arg 写入编译期元数据。
- 发布平台来源是 `release/platforms.yaml`;新增/删除 Release asset 平台时优先改这个文件。
- 运行时版本接口展示编译期元数据:`CPR_VERSION`、`CPR_GIT_SHA`、`CPR_BUILD_TIME`。
- 当前发布的 Docker 镜像平台是 `linux/amd64` 和 `linux/arm64`。