From aae0960a13d1b987b3857be23d08abcb8dde6a02 Mon Sep 17 00:00:00 2001 From: Angel Date: Mon, 1 Jun 2026 23:33:38 -0400 Subject: [PATCH] =?UTF-8?q?docs:=20=E8=A1=A5=E5=85=85=20PyPI=20=E5=8F=91?= =?UTF-8?q?=E5=B8=83=E6=AD=A5=E9=AA=A4=E5=88=B0=20CLAUDE.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 记录 Trusted Publishing(OIDC) 发布流程:release.yml 由 v* tag 触发、 一次性 PyPI trusted publisher 配置、bump 版本→打 tag→监控→验证的步骤、 版本不可变约束,以及 web/dist force-include 打包要点与本地构建校验命令。 --- CLAUDE.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index 1f7cb1a..c3771be 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -200,6 +200,48 @@ API key resolution order: shell env vars → `.merge/.env` → `~/.config/code-m Branches: `feature/`, `fix/`, `chore/`. PRs squash-merged into `main`. +## Releasing (PyPI) + +The package publishes to PyPI as `code-merge-system` via **Trusted Publishing +(OIDC)** — no API token is stored anywhere. `.github/workflows/release.yml` +triggers on any `v*` tag, builds the wheel + sdist (after `npm run build` bakes +`web/dist` into the package), and publishes through the `pypi` GitHub +environment. + +One-time setup (already configured for this repo): a PyPI *trusted publisher* +must exist with project `code-merge-system`, owner `GOSICK-Angel`, repository +`code-merge-system`, workflow `release.yml`, environment `pypi`. Set it up at +https://pypi.org/manage/account/publishing/ before the first release. + +To cut a release: + +```bash +# 1. Bump the version in pyproject.toml ([project].version) and merge to main. +# 2. Make sure main CI is green (the tag-triggered release runs independently, +# so a red CI won't block it — but don't ship a broken main). +# 3. Tag the release commit and push the tag: +git tag -a vX.Y.Z -m "release: vX.Y.Z" +git push origin vX.Y.Z +# 4. Watch the publish workflow: +gh run watch "$(gh run list --workflow release.yml --limit 1 --json databaseId -q '.[0].databaseId')" --exit-status +# 5. Verify it is live: +curl -s https://pypi.org/pypi/code-merge-system/json | python -c "import sys,json;print(json.load(sys.stdin)['info']['version'])" +``` + +PyPI versions are immutable — a given `X.Y.Z` can never be re-uploaded, so bump +the version for every retry. Packaging note: `web/dist` is gitignored, so both +the wheel and sdist targets `force-include` it in `pyproject.toml`; the release +job rebuilds the Web UI first so the bundled assets resolve at runtime via +`importlib.resources.files("src.web") / "dist"`. + +To build/validate the artifacts locally before tagging: + +```bash +cd web && npm run build && cd .. # produce web/dist (required by force-include) +python -m build # builds sdist + wheel into dist/ +python -m twine check dist/* # PyPI metadata sanity check +``` + ## Testing Notes `asyncio_mode = "auto"` is set globally — all async test functions run without explicit `@pytest.mark.asyncio`. Unit tests use `patch_llm_factory` to mock LLM calls; integration tests (`tests/integration/`) make real API calls and require valid `ANTHROPIC_API_KEY` / `OPENAI_API_KEY`.