nisse-review: repository patterns, and the wall checked every round
At bring-up, nisse-review read no repositories: Gitea's /user/repos leaves out a public repository's Read collaborators, so dev/nisse never showed up. `repositories` now holds patterns (dev/nisse, dev/*, */*) matched against every repository the account can read, public ones included (an organization's or user's list, or the instance's search); unset, it is /user/repos as before. A configured repository it can't read is left out with an oplog line. The read-only wall (R3) is checked every round, not only at startup: an account granted push or admin while running stops (exit 3) rather than review on. nisse-core's Gitea client gains GiteaNotFound for 404s, owner_repositories and visible_repositories. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J5Utyfzw7gF7UhjRDEtjTk
This commit is contained in:
1 parent
52c6704b17
commit
2139ddd05c
12 files changed
+283
-44
No files matched your search
@@ -28,6 +28,10 @@ class GiteaError(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
class GiteaNotFound(GiteaError):
|
||||
"""A 404: no such thing, or nothing this account may see."""
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class PullRequest:
|
||||
number: int
|
||||
@@ -123,7 +127,8 @@ class GiteaClient:
|
||||
except httpx.HTTPError as exc:
|
||||
raise GiteaError(f"gitea request failed: {exc}") from exc
|
||||
if response.status_code >= 400:
|
||||
raise GiteaError(
|
||||
error = GiteaNotFound if response.status_code == 404 else GiteaError
|
||||
raise error(
|
||||
f"gitea {method} {path} returned {response.status_code}: "
|
||||
f"{response.text[:300]}"
|
||||
)
|
||||
@@ -416,6 +421,30 @@ class GiteaClient:
|
||||
return found
|
||||
raise GiteaError("too many repositories to list")
|
||||
|
||||
def owner_repositories(self, owner: str) -> list[str]:
|
||||
"""Every repository of an organization (or a user) this account can
|
||||
read, as "owner/name"."""
|
||||
try:
|
||||
return self._paged_names(f"/orgs/{owner}/repos")
|
||||
except GiteaNotFound:
|
||||
return self._paged_names(f"/users/{owner}/repos")
|
||||
|
||||
def visible_repositories(self) -> list[str]:
|
||||
"""Every repository this account can read, public ones included."""
|
||||
return self._paged_names("/repos/search", key="data")
|
||||
|
||||
def _paged_names(self, path: str, key: str | None = None) -> list[str]:
|
||||
found: list[str] = []
|
||||
for page in range(1, MAX_PR_PAGES + 1):
|
||||
answer = self._request(
|
||||
"GET", path, params={"limit": PR_PAGE_SIZE, "page": page}
|
||||
)
|
||||
items = (answer or {}).get(key, []) if key else (answer or [])
|
||||
found += [str(item["full_name"]) for item in items]
|
||||
if len(items) < PR_PAGE_SIZE:
|
||||
return found
|
||||
raise GiteaError("too many repositories to list")
|
||||
|
||||
def open_pull_requests(self, repo: str) -> list[PullRequest]:
|
||||
found: list[PullRequest] = []
|
||||
for page in range(1, MAX_PR_PAGES + 1):
|
||||
|
||||
Reference in new issue
Block a user