diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 72851ebb5..3d8d363d5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -88,6 +88,13 @@ jobs: fail("Release tag #{release_tag} does not match #{version_path} tag #{expected_tag}") unless release_tag == expected_tag fail("#{version_path}: version #{version} is not a valid semver") unless version.match?(SEMVER) + notes_path = "release/notes.md" + fail("#{notes_path}: release notes are required") unless File.file?(notes_path) + notes = File.readlines(notes_path) + unless notes.first&.strip == "# #{release_tag}" && !notes.drop(1).join.strip.empty? + fail("#{notes_path}: expected non-empty notes starting with '# #{release_tag}'") + end + platforms = platforms_data["platforms"] fail("#{platforms_path}: platforms must be a non-empty array") unless platforms.is_a?(Array) && !platforms.empty? @@ -643,15 +650,10 @@ jobs: cosign sign --yes "${images[@]}" - - name: Publish GitHub Release - uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3 - with: - tag_name: ${{ needs.release-info.outputs.tag }} - generate_release_notes: true - previous_tag: ${{ needs.release-info.outputs.previous_tag }} - prerelease: ${{ needs.release-info.outputs.prerelease == 'true' }} - make_latest: ${{ needs.release-info.outputs.prerelease == 'true' && 'false' || 'true' }} - body: | + - name: Prepare release notes + shell: bash + env: + INSTALLATION_NOTES: | > [!WARNING] > **Upgrading across major versions?** Online upgrades across major versions are not supported. Deploy the new major fresh with a new `.runtime/` data directory, then re-import or re-authorize provider accounts and client keys. See the [upgrade notes](https://github.com/${{ github.repository }}/blob/main/deploy/README.md#镜像升级与源码构建). @@ -672,6 +674,26 @@ jobs: - [GitHub Repository](https://github.com/${{ github.repository }}) - [Installation Guide](https://github.com/${{ github.repository }}/blob/main/deploy/README.md) + run: | + python3 <<'PY' + import os + from pathlib import Path + + notes = "\n".join(Path("release/notes.md").read_text().splitlines()[1:]).strip() + installation = os.environ["INSTALLATION_NOTES"].strip() + output = Path(os.environ["RUNNER_TEMP"]) / "release-notes.md" + output.write_text(f"{notes}\n\n{installation}\n") + PY + + - name: Publish GitHub Release + uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3 + with: + tag_name: ${{ needs.release-info.outputs.tag }} + generate_release_notes: true + previous_tag: ${{ needs.release-info.outputs.previous_tag }} + prerelease: ${{ needs.release-info.outputs.prerelease == 'true' }} + make_latest: ${{ needs.release-info.outputs.prerelease == 'true' && 'false' || 'true' }} + body_path: ${{ runner.temp }}/release-notes.md fail_on_unmatched_files: true files: | dist/release/* diff --git a/deploy/README.md b/deploy/README.md index d089cee8d..61f574656 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -313,16 +313,6 @@ docker compose -f deploy/compose.yaml build codex-proxy-rs docker compose -f deploy/compose.yaml up -d --no-build --wait ``` -仓库维护者发布新版本时必须从干净且已同步上游的分支运行: - -```bash -release/publish X.Y.Z -``` - -将 `X.Y.Z` 替换为待发布版本。脚本需要 Git、Ruby 和已登录的 GitHub CLI, -负责更新 `release/version.yaml`、创建版本提交和带注释 tag,并原子推送分支与 tag。 -它不会登录任何服务器,也不会拉取镜像或调用管理端在线更新。 - 源码提交、仓库发版和运行实例升级是三种独立状态:本地 commit 不等于 Release,Release/tag 和镜像 已生成也不等于实例已升级。判断某项修复是否在线前,应先通过管理端版本接口或容器 image digest 确认运行实例的实际 revision;实例只有在执行上面的 Compose pull/up,或成功完成管理端在线更新后 diff --git a/release/notes.md b/release/notes.md new file mode 100644 index 000000000..c63c58865 --- /dev/null +++ b/release/notes.md @@ -0,0 +1,21 @@ +# v3.3.31 + +## What's new + +- Add daily and weekly API key spending limits, persistent usage accounting, and audited reconciliation. Set a limit to `0` to leave it unrestricted. +- Support per-account outbound proxies for authentication, imports, and model requests. +- Support importing Codex personal access tokens. + +## Improvements + +- Configure scheduling, concurrency, weight, and groups before importing account credentials. +- Share account settings across import, individual editing, and batch editing, with consistent modal actions and spacing. +- Improve account plan labels and fill missing plan information from provider quota snapshots. + +## Fixes + +- Apply updated API key limits and enabled state to new requests on existing WebSocket connections. +- Prevent a flash at the end of light/dark theme transitions. +- Return explicit errors when a requested model is unavailable. + +Spending limits use the existing dollar-based accounting rules. Requests already admitted can finish and cause settled usage to exceed a limit; usage-log cleanup does not reset budget accounting. diff --git a/release/publish b/release/publish index 17d6b62c6..5ec475761 100755 --- a/release/publish +++ b/release/publish @@ -3,6 +3,7 @@ set -euo pipefail APP_NAME="codex-proxy-rs" VERSION_FILE="release/version.yaml" +NOTES_FILE="release/notes.md" 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 " @@ -14,6 +15,9 @@ Usage: Example: release/publish 0.1.4 + +Before publishing, replace release/notes.md with the new version's notes and +commit it. Its first line must be "# v". USAGE } @@ -103,6 +107,16 @@ current_version="${current_version#v}" tag="${TAG_PREFIX}${version}" +git ls-files --error-unmatch "$NOTES_FILE" >/dev/null 2>&1 || die "$NOTES_FILE is not tracked" +ruby - "$NOTES_FILE" "$tag" <<'RUBY' +path, tag = ARGV +lines = File.readlines(path) +unless lines.first&.strip == "# #{tag}" && !lines.drop(1).join.strip.empty? + warn "#{path}: replace the contents with notes for #{tag}, starting with '# #{tag}'" + exit 1 +end +RUBY + if git rev-parse --quiet --verify "refs/tags/$tag" >/dev/null; then die "local tag already exists: $tag" fi diff --git a/skills/codex-proxy-rs/SKILL.md b/skills/codex-proxy-rs/SKILL.md index 1317cafe1..9b760778f 100644 --- a/skills/codex-proxy-rs/SKILL.md +++ b/skills/codex-proxy-rs/SKILL.md @@ -88,4 +88,5 @@ docker compose -f deploy/compose.yaml config --quiet - 提交前检查 status、cached/unstaged diff 和 `git diff --check`。 - 使用简短 Conventional Commit subject;按用户要求添加 `Co-authored-by: Codex `。 - 发布权威是 `release/version.yaml` 与带注释的 `vX.Y.Z` tag。 -- 正式发布使用 `release/publish `;提交、Release 和实例升级是三个独立状态。 +- 发版前替换并提交 `release/notes.md`,首行必须为目标版本的 `# vX.Y.Z`,正文只记录本次更新。 +- 正式发布使用 `release/publish `;工作流读取 tag 中的发版说明。提交、Release 和实例升级是三个独立状态。