diff --git a/docs/public-release-workflow.md b/docs/public-release-workflow.md new file mode 100644 index 0000000..c813067 --- /dev/null +++ b/docs/public-release-workflow.md @@ -0,0 +1,207 @@ +# KsADK 公开分支与发布流程 + +本文档定义内部 `master` 与 GitHub 公开 `main` 的长期维护方式。它是发布和公开同步的执行依据。 + +## 当前模型 + +`master` 是内部源主干,GitHub `main` 是公开发布主干。两者不应该长期维护两套功能代码或两套发布门禁。公开版本由内部 `master` 的已审核状态通过 clean export 生成,导出脚本只移除不适合公开的材料。 + +公开 `main` 应包含: + +- 公开 SDK 源码:`ksadk/`、`ksadk_runtime_common/`。 +- 公开构建与发布门禁:`Makefile`、`scripts/open_source_audit.py`、`scripts/check_*`、`.github/workflows/*`。 +- 公开文档站:`docs-site/`。 +- 公开 README、CHANGELOG、LICENSE、CONTRIBUTING、AGENTS、CLAUDE。 +- 公开发布所需的最小测试集。 + +内部 `master` 可以额外包含: + +- 内部 docs、archive、runbook、设计草稿和预览材料。 +- 内部 agent skills / operator playbooks。 +- 内部验证脚本、E2E、长任务和平台集成测试。 +- 内部部署资产、临时缓存、zread/site/build 产物等。 + +因此不能简单理解为“只差 docs 和 skills 两个目录”。准确说法是:**公开导出的源码和发布门禁必须与 `master` 的公开子集一致;非公开材料由导出脚本排除**。 + +## 硬性规则 + +1. 不直接 `merge master -> main`,也不把内部 `master` 直接 push 到 GitHub。 +2. 公开同步必须走 clean export candidate 或等价的公开候选分支。 +3. 公开候选必须先通过 `make public-preflight`。 +4. npm、PyPI、GitHub Pages 都必须由可信 GitHub workflow 发布;不使用本地 `npm publish`、本地 `twine upload` 或手工上传 Pages。 +5. GitHub Release、PyPI 包、Pages 文档必须能追溯到同一个已审核 GitHub `main` 提交。 +6. `.pypirc`、私有 registry 凭证、kubeconfig、真实 API key、临时 token 不得进入仓库。 + +## 准备 ksadk-web + +`ksadk-web` 是共享 UI 源头。需要新 UI 时,先在 `agentengine/ksadk-web` 发 npm 版本,再让 `ksadk-python` 和 `agentengine-hosted-ui` 消费 registry 里的固定版本。 + +本地只做验证: + +```bash +cd agentengine/ksadk-web +npm test +node --test tests/*.test.mjs +npm run build:all +npm pack --dry-run --access public +``` + +正式 npm 发布只走 GitHub workflow: + +- 推送 `ksadk-web` 代码到 GitHub `main`。 +- 创建 GitHub Release 或手动触发 `publish-npm.yml`。 +- workflow 使用 `npm publish --provenance` 发布。 +- 发布后用 `npm view @kingsoftcloud/ksadk-web@` 确认 registry 可见。 + +## 准备内部 master + +在 `agentengine/ksadk-python` 内部主干完成代码、文档、版本和审批记录: + +```bash +git checkout master +git status --short --branch +uv run pytest <相关测试> +git diff --check +``` + +如果本次需要绑定新的 UI 版本,确认 `KSADK_WEB_VERSION` 默认值、README、docs-site、approval record 都引用同一个 npm 版本。 + +更新审批记录: + +```bash +uv run python scripts/check_approval_record.py \ + --expected-current-commit +uv run pytest tests/test_check_approval_record.py tests/test_public_release_positioning.py -q +``` + +审批记录必须写清: + +- reviewed internal `ksadk-python` commit。 +- `ksadk-web` npm version 和 source commit。 +- 已执行的 public preflight / docs build / package audit 证据。 +- Maintainer、Security reviewer、Release owner sign-off。 + +## 生成公开候选 + +公开候选从内部 master clean export 生成: + +```bash +cd agentengine/ksadk-python +rm -rf /tmp/ksadk-python-export-candidate- +python scripts/prepare_ksadk_python_export.py \ + --output-dir /tmp/ksadk-python-export-candidate- \ + --summary +python3 scripts/open_source_audit.py \ + --target public-repo \ + --root /tmp/ksadk-python-export-candidate- +``` + +同步到长期 public worktree: + +```bash +git fetch github main +git worktree add .worktrees/public-main github/main # 首次需要 +rsync -a --delete --exclude .git \ + /tmp/ksadk-python-export-candidate-/ \ + .worktrees/public-main/ +``` + +`.worktrees/public-main` 是公开候选工作区,不做日常内部开发。 + +## 公开候选门禁 + +在 public worktree 运行完整门禁: + +```bash +cd .worktrees/public-main +make public-preflight +``` + +该门禁至少覆盖: + +- PyPI 版本未重复发布。 +- secret 和公开路径 audit。 +- 从 npm registry 同步 `@kingsoftcloud/ksadk-web` 静态资源。 +- 公开测试集。 +- `docs-site` Fumadocs 静态构建。 +- wheel/sdist 构建。 +- `twine check dist/*`。 +- wheel/sdist 文件列表 audit。 + +失败即停止,不创建 Release,不触发 PyPI,不部署 Pages。 + +## 同步 GitHub main + +公开候选通过门禁后,通过 GitHub PR 或受保护 main 策略合入 GitHub `main`。推荐路径: + +1. 在 `.worktrees/public-main` 提交候选。 +2. 推送到 GitHub release candidate 分支。 +3. 开 PR 到 GitHub `main`。 +4. 等 CI / release-check / docs-site build 通过并完成 review。 +5. 合并 PR,使 GitHub `main` 成为唯一公开发布源。 + +如果维护者明确选择 fast-forward 或直接更新 `main`,也必须满足同样门禁和 review 条件。不要从内部 `master` 创建公开 release 资产。 + +## Tag 与 GitHub Release + +tag 必须指向 GitHub `main` 上已审核、已合入的公开提交: + +```bash +git fetch github main +git checkout .worktrees/public-main +git pull --ff-only github main +make public-release-tag V= +git push github v +``` + +创建 GitHub Release 时使用该 tag。发布说明应引用: + +- GitHub `main` commit。 +- tag。 +- `ksadk-web` npm version。 +- `make public-preflight` 结果。 +- PyPI/Pages workflow run。 + +## PyPI 与 GitHub Pages + +正式发布只走 `.github/workflows/publish-pypi.yml`: + +- 触发条件:GitHub Release `published` 或手动 `workflow_dispatch`。 +- 输入:`ksadk_web_version`、`approved_source_commit` 和 `publish_target`。 +- 正常发版使用 `publish_target=full`:workflow 会跑完整 `make public-preflight`,发布 `ksadk` 主包,构建并发布 `agentengine-sdk-python` 别名包,并部署 GitHub Pages。 +- 补发别名包使用 `publish_target=alias-only`:workflow 只跑公开审计、公开测试、别名包构建审计和 approval gate,只发布 `agentengine-sdk-python`,不重发 `ksadk`,也不部署 GitHub Pages。 +- workflow 先同步 npm registry 中的 UI 静态资源。 +- workflow 再按 `publish_target` 运行对应发布前检查。 +- workflow 再运行 `make public-publish-gate`,校验 approval record。 +- PyPI 上传使用 OIDC Trusted Publishing。 +- GitHub Pages 由同一个 workflow 构建 `docs-site` 并部署。 + +发布后核对: + +```bash +python scripts/check_publication_state.py --phase post-publish --version +npm view @kingsoftcloud/ksadk-web@ version +python - <<'PY' +import json, urllib.request +for name in ["ksadk", "agentengine-sdk-python"]: + with urllib.request.urlopen(f"https://pypi.org/pypi/{name}/json", timeout=20) as r: + data = json.load(r) + print(name, data["info"]["version"], data["info"].get("project_urls")) +PY +``` + +## 最短可执行清单 + +一次正常公开发布的最短路径是: + +1. `ksadk-web` 合入 GitHub `main`,由 GitHub workflow 发布 npm。 +2. 内部 `ksadk-python/master` 记录版本、文档、approval evidence。 +3. 从内部 master 生成 clean export。 +4. 在 public candidate 运行 `make public-preflight`。 +5. public candidate 通过 GitHub PR 合入公开 `main`。 +6. 在公开 `main` commit 上打 `v` tag。 +7. 创建 GitHub Release 或手动触发 `publish-pypi.yml`。 +8. workflow 发布 PyPI 并部署 GitHub Pages。 +9. 运行 post-publish publication check。 + +这不是“提交 PR 到 main 后手工打 tag 和 release 文件”就结束。PR 到 `main` 只是公开源码同步;真正的 npm、PyPI、Pages 发布必须由 GitHub workflow 完成并通过发布后核对。 diff --git a/export-manifest.json b/export-manifest.json index d6bf08f..53b3e10 100644 --- a/export-manifest.json +++ b/export-manifest.json @@ -1,9 +1,9 @@ { - "generatedAt": "2026-07-08T04:45:14.107433+00:00", + "generatedAt": "2026-07-08T04:58:29.018956+00:00", "targetRepository": "https://github.com/kingsoftcloud/ksadk-python", "documentation": "https://kingsoftcloud.github.io/ksadk-python/", - "exportPathCount": 556, - "excludedPathCount": 201, + "exportPathCount": 557, + "excludedPathCount": 200, "excludedPaths": [ "docs/Agent 开发者上下文接入指南.md", "docs/DeepAgents说明.md", @@ -47,7 +47,6 @@ "docs/preview/images/claw_robot.png", "docs/preview/images/wps_support_group.jpg", "docs/prompt-driven-agent-creation-draft.md", - "docs/public-release-workflow.md", "docs/reference/ksadk技术设计.md", "docs/reference/远程Agent运行时接口说明.md", "docs/superpowers/plans/2026-04-16-hosted-hermes-gateway.md", @@ -244,7 +243,8 @@ "ksadk_runtime_common/" ], "curatedDocs": [ - "docs/maintainer-approval-record.md" + "docs/maintainer-approval-record.md", + "docs/public-release-workflow.md" ], "curatedReferenceDocs": [ "docs/reference/ksadk环境变量参考.md" diff --git a/scripts/open_source_audit.py b/scripts/open_source_audit.py index 12ad121..09875a9 100644 --- a/scripts/open_source_audit.py +++ b/scripts/open_source_audit.py @@ -107,6 +107,7 @@ def to_dict(self) -> dict[str, object]: prefixes=("docs/",), allowed_paths=( "docs/maintainer-approval-record.md", + "docs/public-release-workflow.md", "docs/ksadk\u73af\u5883\u53d8\u91cf\u53c2\u8003.md", "docs/\u8fdc\u7a0bAgent\u8fd0\u884c\u65f6\u63a5\u53e3\u8bf4\u660e.md", "docs/reference/ksadk\u6280\u672f\u8bbe\u8ba1.md", diff --git a/scripts/prepare_ksadk_python_export.py b/scripts/prepare_ksadk_python_export.py index 1f2a4d2..c5acf25 100644 --- a/scripts/prepare_ksadk_python_export.py +++ b/scripts/prepare_ksadk_python_export.py @@ -27,7 +27,10 @@ DEFAULT_OUTPUT_DIR = Path("/tmp/ksadk-python-export-candidate") -CURATED_DOCS: set[str] = {"docs/maintainer-approval-record.md"} +CURATED_DOCS: set[str] = { + "docs/maintainer-approval-record.md", + "docs/public-release-workflow.md", +} CURATED_REFERENCE_DOCS: set[str] = {"docs/reference/ksadk环境变量参考.md"} ROOT_EXPORT_FILES = { diff --git a/tests/test_open_source_audit.py b/tests/test_open_source_audit.py index ddc3078..1b4a647 100644 --- a/tests/test_open_source_audit.py +++ b/tests/test_open_source_audit.py @@ -124,6 +124,7 @@ def test_public_repo_audit_allows_curated_environment_reference_doc(): "public-repo", [ "docs/maintainer-approval-record.md", + "docs/public-release-workflow.md", "docs/reference/ksadk环境变量参考.md", ], )