From 8cd872e0eba24cf99beeddd2b0b605c30b3791e2 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Wed, 23 Sep 2026 23:37:57 +0000 Subject: [PATCH 1/2] fix: compare PR changes from merge base in CI selector --- scripts/select_ci_problems.py | 16 +++++++++-- tests/python/test_select_ci_problems.py | 35 +++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/scripts/select_ci_problems.py b/scripts/select_ci_problems.py index dad6a007..4e83a0d5 100644 --- a/scripts/select_ci_problems.py +++ b/scripts/select_ci_problems.py @@ -137,9 +137,21 @@ def parse_git_changes(output: bytes) -> tuple[Change, ...]: return tuple(changes) -def git_changes(root: pathlib.Path, base: str, head: str) -> tuple[Change, ...]: +def git_changes(root: pathlib.Path, base: str, head: str, event: str) -> tuple[Change, ...]: if base == ZERO_SHA: return (Change("A", ("",)),) + if event == "pull_request": + # The base branch may have advanced after the contributor branched. + # Comparing its tip directly to the PR head treats base-only changes + # as reversions by the PR, triggering unrelated catalog checks. + ancestor = subprocess.run( + ["git", "merge-base", base, head], + cwd=root, + check=True, + stdout=subprocess.PIPE, + text=True, + ) + base = ancestor.stdout.strip() result = subprocess.run( ["git", "diff", "--name-status", "-z", "--find-renames", f"{base}..{head}"], cwd=root, @@ -359,7 +371,7 @@ def main(argv: Sequence[str] | None = None) -> int: parser.error("--shards must be positive") root = args.root.resolve() problems = load_problems(root) - changes = git_changes(root, args.base, args.head) + changes = git_changes(root, args.base, args.head, args.event) graph = load_import_graph(args.import_graph) selection = select(root, args.event, changes, problems, graph) matrix = make_matrix(selection, problems, args.shards) diff --git a/tests/python/test_select_ci_problems.py b/tests/python/test_select_ci_problems.py index b1340d4c..bde05dae 100644 --- a/tests/python/test_select_ci_problems.py +++ b/tests/python/test_select_ci_problems.py @@ -3,6 +3,7 @@ import importlib.util import json import pathlib +import subprocess import sys import tempfile import unittest @@ -170,6 +171,40 @@ def test_nul_git_changes_reject_truncated_records(self): with self.assertRaisesRegex(ValueError, "unexpected git diff record"): SELECTOR.parse_git_changes(b"R100\0LeanEval/Old.lean\0") + def test_pr_changes_exclude_updates_only_on_base_branch(self): + with tempfile.TemporaryDirectory() as directory: + root = pathlib.Path(directory) + + def git(*args: str) -> str: + return subprocess.check_output( + ["git", *args], cwd=root, text=True + ).strip() + + git("init", "-q") + git("config", "user.name", "CI test") + git("config", "user.email", "ci@example.test") + (root / "README.md").write_text("base\n", encoding="utf-8") + git("add", "README.md") + git("commit", "-qm", "base") + git("branch", "-M", "main") + git("switch", "-qc", "feature") + (root / "LeanEval").mkdir() + (root / "LeanEval" / "New.lean").write_text("-- new\n", encoding="utf-8") + git("add", "LeanEval/New.lean") + git("commit", "-qm", "new problem") + head = git("rev-parse", "HEAD") + git("switch", "-q", "main") + (root / "generated").mkdir() + (root / "generated" / "index.json").write_text("{}\n", encoding="utf-8") + git("add", "generated/index.json") + git("commit", "-qm", "regenerate main") + base = git("rev-parse", "HEAD") + + pr_changes = SELECTOR.git_changes(root, base, head, "pull_request") + self.assertEqual(pr_changes, (Change("A", ("LeanEval/New.lean",)),)) + push_changes = SELECTOR.git_changes(root, base, head, "push") + self.assertIn(Change("D", ("generated/index.json",)), push_changes) + def test_loads_graph_emitted_by_lean(self): payload = [ { From 4a3b9add9dad681b1868aef8bc1fa40f16e65c76 Mon Sep 17 00:00:00 2001 From: Kim Morrison Date: Thu, 24 Sep 2026 00:26:16 +0000 Subject: [PATCH 2/2] fix: use merge base for submission policy PR checks --- .github/workflows/ci.yml | 5 +++-- tests/python/test_select_ci_problems.py | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2f3ce549..975966bc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -141,7 +141,8 @@ jobs: HEAD_SHA: ${{ github.event.pull_request.head.sha }} run: | set -euo pipefail - mapfile -t changed_files < <(git diff --name-only "$BASE_SHA".."$HEAD_SHA") + MERGE_BASE=$(git merge-base "$BASE_SHA" "$HEAD_SHA") + mapfile -t changed_files < <(git diff --name-only "$MERGE_BASE".."$HEAD_SHA") if [ "${#changed_files[@]}" -eq 0 ]; then echo "No changed files; skipping submission diff validation." exit 0 @@ -152,7 +153,7 @@ jobs: exit 0 fi done - lake exe lean-eval validate-submission --base "$BASE_SHA" --head "$HEAD_SHA" + lake exe lean-eval validate-submission --base "$MERGE_BASE" --head "$HEAD_SHA" - name: Run Lean unit tests run: | diff --git a/tests/python/test_select_ci_problems.py b/tests/python/test_select_ci_problems.py index bde05dae..6c930ecc 100644 --- a/tests/python/test_select_ci_problems.py +++ b/tests/python/test_select_ci_problems.py @@ -2,6 +2,7 @@ import importlib.util import json +import os import pathlib import subprocess import sys @@ -174,10 +175,11 @@ def test_nul_git_changes_reject_truncated_records(self): def test_pr_changes_exclude_updates_only_on_base_branch(self): with tempfile.TemporaryDirectory() as directory: root = pathlib.Path(directory) + env = {**os.environ, "GIT_CONFIG_GLOBAL": os.devnull, "GIT_CONFIG_NOSYSTEM": "1"} def git(*args: str) -> str: return subprocess.check_output( - ["git", *args], cwd=root, text=True + ["git", *args], cwd=root, text=True, env=env ).strip() git("init", "-q")