Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions scripts/open_downstream_qpk_pin_prs.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,33 @@ def update_qpk_revision_contract(repo_dir: Path, qpk_sha: str) -> bool:
return True


def update_drift_workflow_test_contract(
repo_dir: Path,
*,
qpk_sha: str,
previous_qpk_refs: set[str],
) -> bool:
"""Keep workflow-content assertions aligned with an updated reusable workflow pin.

Strategy repositories deliberately test their pinned reusable drift workflow
reference. That test is a dependency surface just like ``pyproject.toml``
and ``drift-check.yml``; leaving it stale makes an otherwise coherent pin
update fail CI. Only QPK SHAs observed before the update are replaced.
"""
path = repo_dir / "tests" / "test_drift_workflow_config.py"
if not path.is_file():
return False
original = path.read_text(encoding="utf-8")
updated = original
for previous_ref in sorted(previous_qpk_refs):
if re.fullmatch(r"[a-f0-9]{40}", previous_ref) and previous_ref != qpk_sha:
updated = updated.replace(previous_ref, qpk_sha)
if updated == original:
return False
path.write_text(updated, encoding="utf-8")
return True


def update_strategy_dependency_pins(
repo_dir: Path,
strategy_heads: dict[str, str],
Expand Down Expand Up @@ -281,6 +308,7 @@ def update_repo(
strategy_heads: dict[str, str] | None = None,
) -> bool:
script = SCRIPT_ROOT / "check_qpk_pin_consistency.py"
previous_qpk_refs = qpk_refs(repo_dir)
run(
["python3", str(script), "--root", str(repo_dir), "--pin-file", str(qpk_pin), "--fix"],
cwd=repo_dir,
Expand All @@ -290,6 +318,11 @@ def update_repo(
repo_dir,
get_qpk_pin_sha(pin_file=qpk_pin),
)
update_drift_workflow_test_contract(
repo_dir,
qpk_sha=get_qpk_pin_sha(pin_file=qpk_pin),
previous_qpk_refs=previous_qpk_refs,
)
if strategy_heads:
update_strategy_dependency_pins(repo_dir, strategy_heads)
update_qsl_strategy_requires(repo_dir, strategy_heads)
Expand Down
26 changes: 26 additions & 0 deletions tests/test_qpk_pin_consistency.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
update_qsl_metadata_test_contract,
update_qsl_strategy_requires,
update_qsl_compat_qpk_pin,
update_drift_workflow_test_contract,
update_qpk_revision_contract,
update_strategy_dependency_pins,
)
Expand Down Expand Up @@ -216,6 +217,31 @@ def test_qpk_revision_contract_tracks_staged_pin(self) -> None:
contract.read_text(encoding="utf-8"),
)

def test_drift_workflow_test_contract_tracks_previously_observed_qpk_refs(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
root.joinpath("tests").mkdir()
contract = root / "tests" / "test_drift_workflow_config.py"
contract.write_text(
f'QPK_REF = "{STALE}"\n'
f'assert "reusable-drift-check.yml@{STALE}" in workflow\n'
'assert "unrelated" in workflow\n',
encoding="utf-8",
)

self.assertTrue(
update_drift_workflow_test_contract(
root,
qpk_sha=TARGET,
previous_qpk_refs={STALE, "unrelated"},
)
)
updated = contract.read_text(encoding="utf-8")

self.assertEqual(2, updated.count(TARGET))
self.assertNotIn(STALE, updated)
self.assertIn("unrelated", updated)

def test_consumer_strategy_pins_update_as_one_bundle(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
Expand Down