Skip to content

Commit 30ecc4a

Browse files
authored
Migliora bootstrap PR e warning GitHub (#15)
1 parent 73a0819 commit 30ecc4a

3 files changed

Lines changed: 71 additions & 8 deletions

File tree

src/agent_context_builder/github.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class PR:
1515
repo: str
1616
url: str
1717
state: str = "open"
18+
author: str = ""
1819

1920

2021
@dataclass
@@ -44,6 +45,21 @@ def __init__(self, org: str, token: Optional[str] = None):
4445
# Populated by get_prs/get_issues — maps "<repo>:prs" or "<repo>:issues" to error message
4546
self.fetch_errors: dict[str, str] = {}
4647

48+
def collector_warning(self) -> str | None:
49+
"""Return a human-readable warning if fetch errors suggest rate-limit or auth degradation."""
50+
if not self.fetch_errors:
51+
return None
52+
msgs = " ".join(self.fetch_errors.values()).lower()
53+
if "403" in msgs or "rate limit" in msgs or "secondary rate" in msgs:
54+
return (
55+
"GitHub rate-limit or auth error "
56+
f"({len(self.fetch_errors)} collector(s) affected) - data may be incomplete"
57+
)
58+
return (
59+
f"GitHub fetch error ({len(self.fetch_errors)} collector(s) affected) "
60+
"- data may be incomplete"
61+
)
62+
4763
def get_prs(self, repos: list[str], state: str = "open") -> list[PR]:
4864
"""Get open PRs across repos.
4965
@@ -100,6 +116,7 @@ def _get_repo_prs(self, repo: str, state: str = "open") -> list[PR]:
100116
repo=repo,
101117
url=item["html_url"],
102118
state=item["state"],
119+
author=item.get("user", {}).get("login", ""),
103120
)
104121
)
105122
return prs

src/agent_context_builder/render.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,21 @@ def render_session_bootstrap(self) -> str:
7474
lines.append("")
7575
prs = self.github_collector.get_prs(self.config.repos)
7676
github_errors = self.github_collector.fetch_errors
77-
if github_errors:
78-
lines.append(
79-
f"> **GitHub unavailable** — {len(github_errors)} fetch error(s);"
80-
" PR/issue counts may be incomplete"
81-
)
77+
collector_warn = self.github_collector.collector_warning()
78+
if collector_warn:
79+
lines.append(f"> **Warning**: {collector_warn}")
8280
if prs:
83-
for pr in prs[:10]: # Limit to first 10
81+
_DEPENDABOT = {"dependabot[bot]", "dependabot"}
82+
feature_prs = [pr for pr in prs if pr.author not in _DEPENDABOT]
83+
dep_prs = [pr for pr in prs if pr.author in _DEPENDABOT]
84+
for pr in feature_prs[:10]:
8485
lines.append(f"- [{pr.repo}#{pr.number}]({pr.url}): {pr.title}")
86+
if dep_prs:
87+
lines.append(
88+
f"- **Dependabot**: {len(dep_prs)} bump PR(s) - "
89+
+ ", ".join(f"[#{pr.number}]({pr.url})" for pr in dep_prs[:2])
90+
+ (" ..." if len(dep_prs) > 2 else "")
91+
)
8592
elif not github_errors:
8693
lines.append("*No open PRs*")
8794
lines.append("")

tests/test_render.py

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from agent_context_builder.config import Config
99
from agent_context_builder.discussions import Discussion, DiscussionCollector
1010
from agent_context_builder.git_local import GitLocalCollector, GitState
11-
from agent_context_builder.github import GitHubCollector
11+
from agent_context_builder.github import GitHubCollector, PR
1212
from agent_context_builder.render import Renderer
1313

1414
_UNAVAILABLE = GitState(available=False, reason="path_not_found", dirty=None, current_branch=None)
@@ -36,6 +36,21 @@ def _make_github_mock(prs=None, issues=None, fetch_errors=None, raw_file=None):
3636
m.get_issues.return_value = issues or []
3737
m.fetch_errors = fetch_errors or {}
3838
m.get_raw_file.return_value = raw_file # None by default = signal fetch fails gracefully
39+
errors = fetch_errors or {}
40+
if errors:
41+
msgs = " ".join(errors.values()).lower()
42+
if "403" in msgs or "rate limit" in msgs:
43+
m.collector_warning.return_value = (
44+
"GitHub rate-limit or auth error "
45+
f"({len(errors)} collector(s) affected) - data may be incomplete"
46+
)
47+
else:
48+
m.collector_warning.return_value = (
49+
f"GitHub fetch error ({len(errors)} collector(s) affected) "
50+
"- data may be incomplete"
51+
)
52+
else:
53+
m.collector_warning.return_value = None
3954
return m
4055

4156

@@ -77,10 +92,34 @@ def test_render_session_bootstrap_github_error():
7792
)
7893
bootstrap = renderer.render_session_bootstrap()
7994

80-
assert "GitHub unavailable" in bootstrap
95+
assert "rate-limit" in bootstrap
8196
assert "No open PRs" not in bootstrap
8297

8398

99+
def test_render_session_bootstrap_groups_dependabot_prs():
100+
"""Bootstrap keeps Dependabot PRs compact and leaves feature PRs visible."""
101+
config = Config(
102+
workspace_root=Path("/tmp/test"),
103+
github_org="test-org",
104+
repos=["repo1"],
105+
)
106+
prs = [
107+
PR(1, "feat: improve context", "repo1", "https://example.test/pr/1", author="gabry"),
108+
PR(2, "chore(deps): bump package", "repo1", "https://example.test/pr/2", author="dependabot[bot]"),
109+
PR(3, "chore(deps): bump action", "repo1", "https://example.test/pr/3", author="dependabot[bot]"),
110+
]
111+
renderer = Renderer(
112+
config,
113+
_make_github_mock(prs=prs),
114+
_make_git_mock({"repo1": _UNAVAILABLE}),
115+
)
116+
bootstrap = renderer.render_session_bootstrap()
117+
118+
assert "feat: improve context" in bootstrap
119+
assert "**Dependabot**: 2 bump PR(s)" in bootstrap
120+
assert "chore(deps): bump package" not in bootstrap
121+
122+
84123
def test_render_workspace_triage():
85124
"""Test workspace_triage.json rendering with no errors."""
86125
config = Config(

0 commit comments

Comments
 (0)