fix(lvl5): lint executor PR-path — abra lint selects+checks out the repo DEFAULT BRANCH; scratch clone of a detached per-run tree has none (FATA, live 400-402), and a stale default would be silently linted instead of the PR head. Force local main AT the tested ref + repoint origin to the scratch itself (offline tag fetch, no drift). Regression test with detached two-commit source proves exact-ref content is linted. 247 unit tests green; real-abra detached-source smoke pass.
This commit is contained in:
@ -128,14 +128,35 @@ def run_lint(recipe: str, ref: str | None, out_dir: str | None) -> dict:
|
||||
text=True,
|
||||
timeout=LINT_TIMEOUT,
|
||||
)
|
||||
if ref:
|
||||
subprocess.run(
|
||||
["git", "-C", clone, "checkout", "-f", "--quiet", ref],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=LINT_TIMEOUT,
|
||||
)
|
||||
# abra lint SELECTS AND CHECKS OUT THE REPO'S DEFAULT BRANCH before linting (observed
|
||||
# live, build 400-402: a clone of a detached-HEAD per-run tree has no local branch →
|
||||
# FATA "failed to select default branch"; and if a default branch existed at some OTHER
|
||||
# commit, abra would silently lint THAT, not the tested ref). So: force a local `main`
|
||||
# AT exactly the tested ref and make it the default everywhere abra could look —
|
||||
# HEAD, and origin (repointed to the scratch itself, which also turns abra's tag
|
||||
# force-fetch into an offline no-op; the run's true tags were already cloned in).
|
||||
subprocess.run(
|
||||
["git", "-C", clone, "checkout", "-f", "--quiet", "-B", "main"]
|
||||
+ ([ref] if ref else []),
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=LINT_TIMEOUT,
|
||||
)
|
||||
subprocess.run(
|
||||
["git", "-C", clone, "remote", "set-url", "origin", clone],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=LINT_TIMEOUT,
|
||||
)
|
||||
subprocess.run(
|
||||
["git", "-C", clone, "remote", "set-head", "origin", "main"],
|
||||
check=False, # cosmetic: helps any origin-HEAD-based default-branch lookup
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=LINT_TIMEOUT,
|
||||
)
|
||||
# catalogue: R006 (published catalogue version) reads it; servers: harmless, some abra
|
||||
# paths stat it. Symlink the live ones (read-only use).
|
||||
for shared in ("catalogue", "servers"):
|
||||
|
||||
@ -183,6 +183,41 @@ def test_run_lint_missing_recipe_is_unver_not_raise(tmp_path, monkeypatch):
|
||||
assert (tmp_path / "artifacts" / "lint.txt").exists()
|
||||
|
||||
|
||||
def test_run_lint_detached_pr_tree_lints_exact_ref(tmp_path, monkeypatch):
|
||||
# PR-path regression (live builds 400-402): the per-run tree sits at a DETACHED HEAD (the PR
|
||||
# sha), and abra lint selects+checks out the repo's DEFAULT BRANCH before linting. run_lint
|
||||
# must (a) not FATA on the branchless clone, and (b) make the default branch BE the tested
|
||||
# ref — never some other commit's content. Source repo: branch main at C1, detached at C2
|
||||
# (the "PR head", which adds marker-c2). The shim passes only if the linted tree contains
|
||||
# marker-c2 AND HEAD is a local branch.
|
||||
repo = _mkrecipe(tmp_path)
|
||||
(repo / "marker-c2.txt").write_text("pr head\n")
|
||||
subprocess.run(["git", "add", "."], cwd=repo, check=True)
|
||||
subprocess.run(
|
||||
["git", "-c", "user.email=t@t", "-c", "user.name=t", "commit", "-qm", "c2"],
|
||||
cwd=repo,
|
||||
check=True,
|
||||
)
|
||||
c2 = subprocess.run(
|
||||
["git", "rev-parse", "HEAD"], cwd=repo, check=True, capture_output=True, text=True
|
||||
).stdout.strip()
|
||||
subprocess.run(["git", "branch", "-f", "main", "HEAD^"], cwd=repo, check=True)
|
||||
subprocess.run(["git", "checkout", "-q", c2], cwd=repo, check=True) # detached, like a PR run
|
||||
monkeypatch.setenv("ABRA_DIR", str(tmp_path / "abra"))
|
||||
out = TABLE_OK.replace("\r\n", "\\n")
|
||||
shim = (
|
||||
'C="$ABRA_DIR/recipes/fakerec"\n'
|
||||
'git -C "$C" symbolic-ref HEAD >&2 || { echo "FATA no default branch" >&2; exit 1; }\n'
|
||||
'[ -f "$C/marker-c2.txt" ] || { echo "FATA wrong ref linted" >&2; exit 1; }\n'
|
||||
f'printf "{out}"\nexit 0\n'
|
||||
)
|
||||
monkeypatch.setenv("PATH", _shim(tmp_path, shim) + os.pathsep + os.environ["PATH"])
|
||||
res = L.run_lint("fakerec", c2, str(tmp_path / "artifacts"))
|
||||
assert res == {"status": "pass", "detail": "", "rules_failed": []}
|
||||
txt = (tmp_path / "artifacts" / "lint.txt").read_text()
|
||||
assert "refs/heads/main" in txt # HEAD was a local default branch when abra ran
|
||||
|
||||
|
||||
def test_run_lint_abra_blowup_is_unver(tmp_path, monkeypatch):
|
||||
_mkrecipe(tmp_path)
|
||||
monkeypatch.setenv("ABRA_DIR", str(tmp_path / "abra"))
|
||||
|
||||
Reference in New Issue
Block a user