mirror of
https://github.com/zyycn/codex-proxy-rs.git
synced 2026-11-07 00:05:49 +00:00
chore: add release publish command
Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
@@ -103,6 +103,8 @@ flowchart LR
|
||||
- `release/version.yaml`:产品版本和 tag 前缀。
|
||||
- `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` 注入编译期元数据。
|
||||
|
||||
`backend/build/build.rs` 负责把这些值写入二进制。没有 `CPR_VERSION` 时,版本回落到 `release/version.yaml`,最后才回落到 Cargo 的 `CARGO_PKG_VERSION`。
|
||||
|
||||
Executable
+136
@@ -0,0 +1,136 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
APP_NAME="codex-proxy-rs"
|
||||
VERSION_FILE="release/version.yaml"
|
||||
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>"
|
||||
|
||||
usage() {
|
||||
cat <<USAGE
|
||||
Usage:
|
||||
release/publish <version>
|
||||
|
||||
Example:
|
||||
release/publish 0.1.4
|
||||
USAGE
|
||||
}
|
||||
|
||||
die() {
|
||||
echo "error: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
require_command() {
|
||||
command -v "$1" >/dev/null 2>&1 || die "$1 is required"
|
||||
}
|
||||
|
||||
read_version_key() {
|
||||
local key="$1"
|
||||
ruby -ryaml -e '
|
||||
path, key = ARGV
|
||||
data = YAML.load_file(path)
|
||||
value = data[key] if data.is_a?(Hash)
|
||||
unless value.is_a?(String) && !value.strip.empty?
|
||||
warn "#{path}: #{key} must be a non-empty string"
|
||||
exit 1
|
||||
end
|
||||
puts value.strip
|
||||
' "$VERSION_FILE" "$key"
|
||||
}
|
||||
|
||||
update_version_file() {
|
||||
local version="$1"
|
||||
ruby - "$VERSION_FILE" "$version" <<'RUBY'
|
||||
path, version = ARGV
|
||||
content = File.read(path)
|
||||
|
||||
unless content.match?(/^version:/)
|
||||
warn "#{path}: missing version key"
|
||||
exit 1
|
||||
end
|
||||
|
||||
content = content.sub(/^version:\s*.*$/, %(version: "#{version}"))
|
||||
File.write(path, content)
|
||||
RUBY
|
||||
}
|
||||
|
||||
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
|
||||
usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
[[ "$#" -eq 1 ]] || {
|
||||
usage >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
require_command git
|
||||
require_command ruby
|
||||
|
||||
version="${1#v}"
|
||||
[[ "$version" =~ $SEMVER ]] || die "version must be semver, for example 0.1.4"
|
||||
|
||||
repo_root="$(git rev-parse --show-toplevel 2>/dev/null)" || die "not inside a git repository"
|
||||
cd "$repo_root"
|
||||
|
||||
git ls-files --error-unmatch "$VERSION_FILE" >/dev/null 2>&1 || die "$VERSION_FILE is not tracked"
|
||||
|
||||
branch="$(git symbolic-ref --quiet --short HEAD)" || die "publishing from detached HEAD is not supported"
|
||||
remote="$(git config --get "branch.$branch.remote" || true)"
|
||||
merge_ref="$(git config --get "branch.$branch.merge" || true)"
|
||||
[[ -n "$remote" && -n "$merge_ref" ]] || die "current branch has no upstream"
|
||||
remote_branch="${merge_ref#refs/heads/}"
|
||||
[[ "$remote_branch" != "$merge_ref" && -n "$remote_branch" ]] || die "unsupported upstream ref: $merge_ref"
|
||||
|
||||
if ! git diff --quiet --ignore-submodules --; then
|
||||
die "tracked files have unstaged changes; commit or stash them first"
|
||||
fi
|
||||
if ! git diff --cached --quiet --ignore-submodules --; then
|
||||
die "index has staged changes; commit or unstage them first"
|
||||
fi
|
||||
|
||||
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}"
|
||||
|
||||
if git rev-parse --quiet --verify "refs/tags/$tag" >/dev/null; then
|
||||
die "local tag already exists: $tag"
|
||||
fi
|
||||
|
||||
git fetch "$remote"
|
||||
|
||||
upstream="$remote/$remote_branch"
|
||||
local_head="$(git rev-parse HEAD)"
|
||||
upstream_head="$(git rev-parse "$upstream")"
|
||||
merge_base="$(git merge-base HEAD "$upstream")"
|
||||
|
||||
if [[ "$local_head" != "$upstream_head" && "$merge_base" != "$upstream_head" ]]; then
|
||||
if [[ "$merge_base" == "$local_head" ]]; then
|
||||
die "branch is behind $upstream; pull or rebase first"
|
||||
fi
|
||||
die "branch has diverged from $upstream"
|
||||
fi
|
||||
|
||||
if git ls-remote --exit-code --tags "$remote" "refs/tags/$tag" >/dev/null 2>&1; then
|
||||
die "remote tag already exists: $tag"
|
||||
fi
|
||||
|
||||
update_version_file "$version"
|
||||
|
||||
git add "$VERSION_FILE"
|
||||
git commit \
|
||||
-m "chore: bump version to $version" \
|
||||
-m "$SIGNATURE"
|
||||
|
||||
git tag -a "$tag" -m "$tag"
|
||||
git push --atomic "$remote" "HEAD:$remote_branch" "refs/tags/$tag"
|
||||
|
||||
cat <<DONE
|
||||
Published $APP_NAME $version
|
||||
Commit: $(git rev-parse --short HEAD)
|
||||
Tag: $tag
|
||||
DONE
|
||||
@@ -89,6 +89,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/platforms.yaml`;新增/删除 Release asset 平台时优先改这个文件。
|
||||
- 运行时版本接口展示编译期元数据:`CPR_VERSION`、`CPR_GIT_SHA`、`CPR_BUILD_TIME`。
|
||||
|
||||
Reference in New Issue
Block a user