Skip to content

Commit fbad4a0

Browse files
committed
fix(health): accept dependabot.yaml as well as dependabot.yml
GitHub reads Dependabot's config from either name. The lookup now tries .yml first and .yaml only when that is a 404; only two 404s mean there is no config. Any other error still counts as configured.
1 parent 9958963 commit fbad4a0

2 files changed

Lines changed: 47 additions & 12 deletions

File tree

‎machine/health.py‎

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
days. This treats anything other than success/skipped as a problem.
88
99
One exception: GitHub's dynamic "Dependabot Updates" workflow cannot be
10-
disabled, and its old runs outlive the `.github/dependabot.yml` that started
11-
them. Without that file no version update can run, so in a repository that
12-
has none the workflow is skipped as a leftover.
10+
disabled, and its old runs outlive the `.github/dependabot.yml` (or `.yaml`)
11+
that started them. Without that file no version update can run, so in a
12+
repository that has neither the workflow is skipped as a leftover.
1313
1414
It only reads. The report goes to stdout and the run's step summary; nothing
1515
is written to GitHub and nobody is mentioned, so it runs only when a person
@@ -46,6 +46,7 @@
4646

4747
# GitHub's own workflow for Dependabot, present even after its config is gone.
4848
DEPENDABOT_WORKFLOW = "dynamic/dependabot/"
49+
DEPENDABOT_CONFIGS = ("dependabot.yml", "dependabot.yaml")
4950

5051

5152
@dataclass
@@ -131,18 +132,23 @@ def workflow_token_findings(repo: str, branch: str, workflow: dict[str, Any],
131132

132133

133134
def dependabot_configured(repo: str, token: str | None) -> bool:
134-
"""Whether the repository has `.github/dependabot.yml` on its default branch.
135+
"""Whether the repository has `.github/dependabot.yml` or `.yaml` on its default branch.
135136
136-
A 404 means it has none. Any other failure counts as configured, so a
137-
lookup that went wrong never hides a real Dependabot failure.
137+
GitHub accepts either name, so `.yaml` is tried only when `.yml` is a 404,
138+
and only two 404s mean there is none. Any other failure counts as
139+
configured, so a lookup that went wrong never hides a real Dependabot failure.
138140
"""
139-
try:
140-
_get(f"{API}/repos/{repo}/contents/.github/dependabot.yml", token)
141-
except urllib.error.HTTPError as exc:
142-
return exc.code != 404
143-
except urllib.error.URLError:
141+
for name in DEPENDABOT_CONFIGS:
142+
try:
143+
_get(f"{API}/repos/{repo}/contents/.github/{name}", token)
144+
except urllib.error.HTTPError as exc:
145+
if exc.code == 404:
146+
continue
147+
return True
148+
except urllib.error.URLError:
149+
return True
144150
return True
145-
return True
151+
return False
146152

147153

148154
def leftover_workflow(workflow: dict[str, Any], has_dependabot_config: bool) -> bool:

‎tests/test_health.py‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
from __future__ import annotations
44

5+
import urllib.error
6+
7+
from machine import health
8+
59
from machine.health import endpoint_finding, latest_runs, leftover_workflow, render, run_findings
610

711

@@ -47,6 +51,31 @@ def test_dependabot_workflow_without_config_is_a_leftover():
4751
assert not leftover_workflow(dependabot, has_dependabot_config=True)
4852

4953

54+
def _contents(present: set[str]):
55+
"""A stand-in for `_get` where only the named .github files exist."""
56+
def get(url: str, token: str | None) -> dict:
57+
if url.rsplit("/", 1)[1] not in present:
58+
raise urllib.error.HTTPError(url, 404, "Not Found", None, None)
59+
return {}
60+
return get
61+
62+
63+
def test_either_dependabot_file_counts_as_configured(monkeypatch):
64+
monkeypatch.setattr(health, "_get", _contents({"dependabot.yml"}))
65+
assert health.dependabot_configured("org/repo", None)
66+
monkeypatch.setattr(health, "_get", _contents({"dependabot.yaml"}))
67+
assert health.dependabot_configured("org/repo", None)
68+
monkeypatch.setattr(health, "_get", _contents(set()))
69+
assert not health.dependabot_configured("org/repo", None)
70+
71+
72+
def test_a_failed_lookup_keeps_dependabot_checked(monkeypatch):
73+
def forbidden(url: str, token: str | None) -> dict:
74+
raise urllib.error.HTTPError(url, 403, "Forbidden", None, None)
75+
monkeypatch.setattr(health, "_get", forbidden)
76+
assert health.dependabot_configured("org/repo", None)
77+
78+
5079
def test_other_workflows_are_never_leftovers():
5180
pages = {"name": "pages-build-deployment", "path": "dynamic/pages/pages-build-deployment"}
5281
ci = {"name": "test", "path": ".github/workflows/test.yml"}

0 commit comments

Comments
 (0)