From ec0b77e885448678ceabb135f83751acb699d7a8 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 11 Oct 2026 12:24:41 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=A0=A1=E9=AA=8C=E9=87=87=E9=9B=86?= =?UTF-8?q?=E5=99=A8=E8=8D=89=E7=A8=BF=E7=BB=91=E5=AE=9A=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=E4=BB=A5=E6=94=AF=E6=8C=81=E5=AE=89=E5=85=A8=E9=87=8D=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/site-adapter-collector.yml | 12 ++-- tests/test_site_adapter_collector_release.py | 58 +++++++++++++++++++- 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/.github/workflows/site-adapter-collector.yml b/.github/workflows/site-adapter-collector.yml index dfa9f569a..97702491d 100644 --- a/.github/workflows/site-adapter-collector.yml +++ b/.github/workflows/site-adapter-collector.yml @@ -233,10 +233,14 @@ jobs: SOURCE_SHA: ${{ needs.prepare.outputs.source_sha }} run: | if gh release view "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" \ - --json isDraft --jq '.isDraft' > collector-is-draft.txt; then - [[ "$(cat collector-is-draft.txt)" == "true" ]] - git fetch --no-tags origin "refs/tags/$RELEASE_TAG:refs/tags/$RELEASE_TAG" - [[ "$(git rev-parse "$RELEASE_TAG^{commit}")" == "$SOURCE_SHA" ]] + --json isDraft,targetCommitish --jq '[.isDraft, .targetCommitish] | @tsv' \ + > collector-draft-state.txt; then + # 草稿尚未发布时标签可能不存在,应核对创建草稿时绑定的源码提交。 + IFS=$'\t' read -r is_draft draft_source < collector-draft-state.txt + if [[ "$is_draft" != "true" || "$draft_source" != "$SOURCE_SHA" ]]; then + echo "Refusing to overwrite a published release or a draft from another source commit" >&2 + exit 1 + fi gh release upload "$RELEASE_TAG" release-assets/* \ --clobber --repo "$GITHUB_REPOSITORY" gh release edit "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" \ diff --git a/tests/test_site_adapter_collector_release.py b/tests/test_site_adapter_collector_release.py index b1ef6b261..6a0fa18ed 100644 --- a/tests/test_site_adapter_collector_release.py +++ b/tests/test_site_adapter_collector_release.py @@ -1,5 +1,6 @@ """验证采集器独立版本及发布边界,所有 Git 操作仅使用临时仓库。""" +import os import subprocess from pathlib import Path @@ -134,4 +135,59 @@ def test_workflow_separates_releases_and_pins_all_build_sources(): publish = jobs["publish"]["steps"][-1]["run"] assert "--target \"$SOURCE_SHA\" --draft" in publish assert "--draft=false --latest=false" in publish - assert '"$RELEASE_TAG^{commit}"' in publish + assert "--json isDraft,targetCommitish" in publish + assert '"$draft_source" != "$SOURCE_SHA"' in publish + assert '"$RELEASE_TAG^{commit}"' not in publish + + +@pytest.mark.parametrize( + ("draft_flag", "draft_source", "accepted"), + [("true", "source-sha", True), ("true", "other-sha", False), ("false", "source-sha", False)], +) +def test_draft_retry_checks_source_without_requiring_git_tag( + tmp_path: Path, draft_flag: str, draft_source: str, accepted: bool, +): + """实际运行发布 Shell,确认无标签草稿可重试且拒绝错误源码或正式版本。""" + workflow = YAML(typ="safe").load( + (PROJECT_ROOT / ".github/workflows/site-adapter-collector.yml").read_text(encoding="utf-8"), + ) + commands = workflow["jobs"]["publish"]["steps"][-1]["run"] + binaries = tmp_path / "bin" + binaries.mkdir() + gh_stub = binaries / "gh" + gh_stub.write_text( + '#!/bin/bash\n' + 'if [[ "$1 $2" == "release view" ]]; then\n' + ' printf "%s\\t%s\\n" "$DRAFT_FLAG" "$DRAFT_SOURCE"\n' + 'else\n' + ' printf "%s\\n" "$*" >> "$GH_LOG"\n' + 'fi\n', encoding="utf-8", + ) + git_stub = binaries / "git" + git_stub.write_text("#!/bin/bash\nexit 79\n", encoding="utf-8") + for path in (gh_stub, git_stub): + path.chmod(0o755) + log = tmp_path / "gh.log" + environment = { + **os.environ, + "PATH": f"{binaries}{os.pathsep}{os.environ['PATH']}", + "DRAFT_FLAG": draft_flag, + "DRAFT_SOURCE": draft_source, + "GH_LOG": str(log), + "SOURCE_SHA": "source-sha", + "RELEASE_TAG": "site-adapter-collector-v1.0.2", + "COLLECTOR_VERSION": "1.0.2", + "GITHUB_REPOSITORY": "test/collector", + } + result = subprocess.run( + ["bash", "-e", "-o", "pipefail", "-c", commands], + cwd=tmp_path, env=environment, capture_output=True, text=True, check=False, + ) + if accepted: + assert result.returncode == 0, result.stderr + calls = log.read_text(encoding="utf-8") + assert "release upload site-adapter-collector-v1.0.2" in calls + assert "--draft=false --latest=false" in calls + else: + assert result.returncode != 0 + assert not log.exists()