diff --git a/plugins/ndf/scripts/lib/approved_commit.py b/plugins/ndf/scripts/lib/approved_commit.py index 02e3feeba..aa18cc07c 100644 --- a/plugins/ndf/scripts/lib/approved_commit.py +++ b/plugins/ndf/scripts/lib/approved_commit.py @@ -67,11 +67,11 @@ class Verdict: actual_tree: str | None = None -def parse_sha(text) -> str: - """40 桁の 16 進(小文字へ揃える)。形が違えば ValueError。""" +def parse_sha(text, what: str = "承認したコミット") -> str: + """40 桁の 16 進(小文字へ揃える)。形が違えば ValueError(文言の主語は what)。""" s = str(text or "").strip().lower() if not SHA_RE.match(s): - raise ValueError(f"承認したコミットが 40 桁の 16 進でない: {text!r}") + raise ValueError(f"{what}が 40 桁の 16 進でない: {text!r}") return s @@ -177,7 +177,7 @@ def verified_sha(path) -> str: if len(found) != 1: what = "無い" if not found else f"{len(found)} 行ある" raise ValueError(f"導入の確認の承認資料 {p} に確かめたコミットの行が{what}") - return parse_sha(found[0]) + return parse_sha(found[0], f"導入の確認の承認資料 {p} の確かめたコミット") # --- 比較 --------------------------------------------------------------------- diff --git a/plugins/ndf/scripts/merged-steps.py b/plugins/ndf/scripts/merged-steps.py index 63578ebcc..4559df214 100755 --- a/plugins/ndf/scripts/merged-steps.py +++ b/plugins/ndf/scripts/merged-steps.py @@ -20,7 +20,7 @@ CI を待たずに承認ゲート 2 で止まる(status: gate・metrics.gate: production-merge。判定は lib/delivery.py。#1336)。 merge-gate: 宛先の判定だけを行う(0 = 進めてよい / 10 = 承認ゲート 2)。 promote: 昇格の Pull Request(ベースブランチ → 本番チャネル)を探すか作り、merge-when-green と同じ判定と待ちでマージする(後片付けはしない)。 ---prepare は用意して承認資料を書くところで 0 で終える。--expect-head-from は導入の確認の承認資料の確かめたコミットを --expect-head と同じ照合に使う(違えば head_moved で 1、読めなければ 2。#1529)。承認ゲート 2 で止まるときは先端を「承認したコミット」として承認資料(--out)と metrics.approved_sha に載せ、--approved-from はその資料の承認したコミットを同じ照合に使う(--gate-approved user に要る。#2104)。 +--prepare は用意して承認資料を書くところで 0 で終える。--expect-head-from は導入の確認の承認資料の確かめたコミットを --expect-head と同じ照合に使う(違えば head_moved で 1、読めなければ 2。どちらもマージせず、プランの handoff が承認ゲート 2 の by: mvv の記録を外して 10 を返し、承認ゲート 2 へ戻す。流し直しは run <プラン> --from verify。#1529)。承認ゲート 2 で止まるときは先端を「承認したコミット」として承認資料(--out)と metrics.approved_sha に載せ、--approved-from はその資料の承認したコミットを同じ照合に使う(--gate-approved user に要る。#2104)。 実行が終わったのにチェックが pending のまま --stale-after 秒続けば、そのジョブを 1 度だけ `gh run rerun --job` で再実行し、 再実行でも取り残されれば止まる。実行が終わりジョブに結論があれば、チェックの表示が pending のままでも待たずにその結論で扱う。 ジョブがランナーを待つ間は、待ち行列の件数を待ちの 1 周ごとに stderr へ 1 行出す。同じチェック(workflow の名前と名前の組)は最新の項目だけで数え、古い項目の失敗は items に result: superseded で残す。 diff --git a/plugins/ndf/scripts/merged_lib/merge.py b/plugins/ndf/scripts/merged_lib/merge.py index c88236a07..a31a2b3c5 100644 --- a/plugins/ndf/scripts/merged_lib/merge.py +++ b/plugins/ndf/scripts/merged_lib/merge.py @@ -57,7 +57,15 @@ def add_promote_args(pm): pm.add_argument("--prepare", action="store_true", help="Pull Request を用意して承認資料を書くところで終える(マージしない)") pm.add_argument("--out", help="--prepare と承認ゲート 2 の停止で書く昇格の承認資料の置き場(既定は提示物の置き場)") pin = pm.add_mutually_exclusive_group() - pin.add_argument("--expect-head-from", metavar="資料", help="導入の確認の承認資料。確かめたコミットが PR の先端のときだけマージする") + pin.add_argument( + "--expect-head-from", + metavar="資料", + help=( + "導入の確認の承認資料。確かめたコミットが PR の先端のときだけマージする(照合)。" + "食い違えば head_moved で 1、資料から読めなければ 2 で止まり、プランの handoff が承認ゲート 2 へ戻す" + "(run <プラン> --from verify から流し直す)" + ), + ) pin.add_argument( "--approved-from", metavar="資料", diff --git a/plugins/ndf/scripts/tests/test_approved_commit.py b/plugins/ndf/scripts/tests/test_approved_commit.py index 22c68d148..9b2b5e534 100644 --- a/plugins/ndf/scripts/tests/test_approved_commit.py +++ b/plugins/ndf/scripts/tests/test_approved_commit.py @@ -218,3 +218,13 @@ def test_verified_sha_rejects_an_unreadable_material(tmp_path: Path, text): p.write_text(text.format(l=ac.verified_line("trunk", "a" * 40), short=ac.verified_line("trunk", "a" * 39))) with pytest.raises(ValueError): ac.verified_sha(p) + + +def test_verified_sha_names_the_verify_material_when_the_sha_is_malformed(tmp_path: Path): + """#2142: 40 桁でない確かめたコミットの文言は導入の確認の資料を指し、承認したコミットの文言は変わらない。""" + p = tmp_path / "approval-verify.md" + p.write_text(ac.verified_line("trunk", "a" * 39) + "\n") + with pytest.raises(ValueError, match="導入の確認の承認資料 .* の確かめたコミットが 40 桁"): + ac.verified_sha(p) + with pytest.raises(ValueError, match="^承認したコミットが 40 桁"): + ac.parse_sha("a" * 39) diff --git a/plugins/ndf/scripts/tests/test_sprint_close_merge_green.py b/plugins/ndf/scripts/tests/test_sprint_close_merge_green.py index afd0c381c..d4962af72 100644 --- a/plugins/ndf/scripts/tests/test_sprint_close_merge_green.py +++ b/plugins/ndf/scripts/tests/test_sprint_close_merge_green.py @@ -1006,9 +1006,11 @@ def test_promote_does_not_merge_without_a_readable_verified_commit(repo, gh, tmp def test_promote_help_shows_the_verified_commit_argument(gh, repo): - """AC9: promote の --help に照合の引数が出る。""" + """AC9・#2142: promote の --help に照合の引数と、食い違えば承認ゲート 2 へ戻ることが出る。""" p = subprocess.run([PY, str(SCRIPTS / "merged-steps.py"), "promote", "--help"], capture_output=True, text=True, env=gh.env) - assert p.returncode == 0 and "--expect-head-from" in p.stdout + text = "".join(p.stdout.split()) # argparse の折り返しを外す + assert p.returncode == 0 and "--expect-head-from" in text + assert "承認ゲート2へ戻す" in text and "--fromverify" in text # --- #2104: 昇格の承認の後のマージは、承認ゲート 2 の承認資料の承認したコミットのときだけ行う ----------------------