ci: skip-existing on PyPI publish to unblock concurrent PR pushes#96
Merged
ci: skip-existing on PyPI publish to unblock concurrent PR pushes#96
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates the CI publish workflow to avoid failing the entire run when a computed “next version” already exists on PyPI (a race that can happen with concurrent runs or repeated pushes).
Changes:
- Configure
pypa/gh-action-pypi-publishwithskip-existing: trueso existing artifacts don’t hard-fail the job. - Add inline comments documenting why version collisions occur and why skipping is acceptable as a short-term fix.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+166
to
+169
| # 当 PR 多次 push 或并发 CI 跑出相同版本号时,跳过已存在版本而非报错。 | ||
| # 根因是版本号自增逻辑依赖 PyPI API 拉取最新版本,存在缓存/并发窗口。 | ||
| # 不阻塞 PR 合入即可,长期方案是在版本号中嵌入 commit SHA 实现唯一化。 | ||
| skip-existing: true |
When a PR is pushed multiple times in quick succession (or two CI runs race), the version-bump step can compute the same next version twice because PyPI's JSON API has a small cache window after a release. The second 'Publish to PyPI' then fails with HTTP 400 "File already exists", marking the entire CI run red and blocking PR merge even though tests, type-check, build and verify all passed. Add skip-existing: true so the publish action treats an existing version as a non-error (it logs a warning and exits 0). PR merge is no longer gated by this race. Side note: skip-existing means the second push's *content* won't be republished under the same version. The proper long-term fix is to embed the commit SHA in the dev version (e.g. 0.0.187+sha.<short>) so each push gets a unique artefact. Tracked separately. release-test.yml is intentionally left unchanged: it is triggered manually with an explicit version bump, where a conflict should fail loudly rather than be silently skipped. Change-Id: I4be2fb05fd06e32b83dd64d52bd62bfe8b8355cf Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: OhYee <oyohyee@oyohyee.com>
3f9a02b to
7ec9682
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
问题
PR #88 的 CI 失败暴露了 `ci.yml` 中一个发布流水线缺陷:
```
ERROR: HTTPError: 400 Bad Request from https://upload.pypi.org/legacy/
File already exists ('agentrun_inner_test-0.0.187-py3-none-any.whl', ...)
```
测试、类型检查、构建、验证全部通过,仅 `Publish to PyPI` 步骤报错,但整个 CI 标红,导致 `mergeStateStatus=BLOCKED`,阻塞 PR 合入。
根因
`.github/workflows/ci.yml` L77-92 的版本计算逻辑:每次 push 都从 PyPI API 拉取 `agentrun-inner-test` 最新版本,自增 patch 号作为下一版。
当一个 PR 多次 push commit,或两个 CI run 因 PyPI API 缓存窗口拿到同样的"最新版本",会算出同一个下一版本(如两次都算到 `0.0.187`)。第二次 `Publish to PyPI` 自然 `400 File already exists`。
修复
为 `pypa/gh-action-pypi-publish` 加 `skip-existing: true`:遇到已存在版本时跳过并记录 warning,而非以 400 退出。
```yaml
if: steps.changes.outputs.agentrun_changed == 'true'
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}
verify-metadata: false
```
参见 pypa/gh-action-pypi-publish 文档,该参数对应 twine 的 `--skip-existing`。
设计取舍
已知限制(不在本 PR 范围)
`skip-existing` 后存在隐性问题:PR 多次 push 时,第二次 push 的代码不会被发到 PyPI(版本号没变,跳过),消费方拿到的还是第一次的代码。
属于版本号自增逻辑的根本缺陷,但不阻塞当前修复。后续可在版本号中嵌入 commit SHA 实现唯一化(如 `0.0.187+sha.` 或 PEP 440 兼容的 `0.0.187.dev<run_number>`)。
为什么 release-test.yml 保持不动?
`release-test.yml` 是手动触发的工作流(`workflow_dispatch` + `workflow_call`),用户主动选择版本递增类型。在那里版本冲突应硬性报错让用户察觉,而非静默跳过。
测试计划
合入这个 PR 后,未来 #77 等 PR 的 CI 不会再因发布步骤的版本号竞态而被阻塞。