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
7 changes: 6 additions & 1 deletion dependabot/reconcile.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,10 @@ def reconcile_repo(repo, owner, gh, shell, opts, policy, workdir):
if rc != 1:
return f"skipped:generator-exit-{rc}", "the generator could not render this file safely"

rc = shell.run(gen + ["--write"], check=False).returncode
# `--strict` is check-only: the generator refuses it beside `--write` with exit 2, which
# silently skipped every repository from the day agent-kit started enforcing that.
write = [sys.executable, opts.generator_script, "check", dest, "--write", "--policy", opts.policy]
rc = shell.run(write, check=False).returncode
if rc not in (0, 1):
return f"skipped:write-exit-{rc}", ""
changed = changed_paths(shell, dest)
Expand Down Expand Up @@ -209,6 +212,8 @@ def main(argv=None, gh=None, shell=None):
except Exception as exc: # one repository's failure must not stop the others
errors += 1
status, note = "error", str(exc)[:300]
if status.startswith("skipped:write-exit-"):
errors += 1 # the generator failed to write: a tool error, not a decision to skip
rows.append((repo["full_name"], status, note))
finally:
shutil.rmtree(workdir, ignore_errors=True)
Expand Down
32 changes: 31 additions & 1 deletion dependabot/tests/test_reconcile.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@ def run(self, cmd, check=True, input_text=None):
if "clone" in cmd:
os.makedirs(cmd[-1])
return subprocess.CompletedProcess(cmd, 0, "", "")
if "check" in cmd and "--strict" in cmd:
if "check" in cmd:
if "--strict" in cmd and "--write" in cmd:
# the real generator: "--strict goes with `check`, without --write"
return subprocess.CompletedProcess(cmd, 2, "", "")
dest = cmd[cmd.index("check") + 1]
name = os.path.basename(dest).split("__", 1)[1]
if "--write" in cmd:
Expand Down Expand Up @@ -161,6 +164,33 @@ def test_apply_pushes_only_the_reconciler_branch(self):
create = next(r for r in gh.runs if r[1] == "create")
self.assertIn("Adopt the Dependabot standard", create)

def test_write_never_carries_strict(self):
# The generator refuses `--strict` beside `--write` (exit 2); on 2026-11-02 that made every
# repository "skipped:write-exit-2" while the run still reported success.
code, _, shell = self.run_main(self.base_routes(), self.RC, "--apply")
self.assertEqual(code, 0)
writes = [c for c in shell.cmds if "--write" in c]
self.assertTrue(writes, "drifting repositories are written")
self.assertFalse([c for c in writes if "--strict" in c])

def test_a_failed_write_fails_the_run(self):
class WriteFails(FakeShell):
def run(self, cmd, check=True, input_text=None):
if "--write" in cmd:
self.cmds.append(cmd)
return subprocess.CompletedProcess(cmd, 3, "", "")
return super().run(cmd, check, input_text)
captured = []
orig = common.write_summary
common.write_summary = captured.append
try:
code = reconcile.main(["--owner", "simtabi", "--generator", self.gen],
gh=FakeGh(self.base_routes()), shell=WriteFails(self.RC))
finally:
common.write_summary = orig
self.assertEqual(code, 1)
self.assertRegex(captured[0], r"\| simtabi/drifting \| skipped:write-exit-3 \|")

def test_error_in_one_repo_is_reported_and_exits_nonzero(self):
routes = self.base_routes()
routes = {"repos/simtabi/drifting/pulls?": common.GhError("boom"), **routes}
Expand Down
Loading