alissa-tools-github-genloop 0.1.3__tar.gz → 0.1.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {alissa_tools_github_genloop-0.1.3/src/main/alissa_tools_github_genloop.egg-info → alissa_tools_github_genloop-0.1.4}/PKG-INFO +1 -1
- {alissa_tools_github_genloop-0.1.3 → alissa_tools_github_genloop-0.1.4}/src/main/alissa/tools/github/genloop/github.py +35 -4
- alissa_tools_github_genloop-0.1.4/src/main/alissa/tools/github/genloop/version +1 -0
- {alissa_tools_github_genloop-0.1.3 → alissa_tools_github_genloop-0.1.4/src/main/alissa_tools_github_genloop.egg-info}/PKG-INFO +1 -1
- alissa_tools_github_genloop-0.1.3/src/main/alissa/tools/github/genloop/version +0 -1
- {alissa_tools_github_genloop-0.1.3 → alissa_tools_github_genloop-0.1.4}/LICENSE +0 -0
- {alissa_tools_github_genloop-0.1.3 → alissa_tools_github_genloop-0.1.4}/MANIFEST.in +0 -0
- {alissa_tools_github_genloop-0.1.3 → alissa_tools_github_genloop-0.1.4}/NOTICE +0 -0
- {alissa_tools_github_genloop-0.1.3 → alissa_tools_github_genloop-0.1.4}/README.md +0 -0
- {alissa_tools_github_genloop-0.1.3 → alissa_tools_github_genloop-0.1.4}/requirements.txt +0 -0
- {alissa_tools_github_genloop-0.1.3 → alissa_tools_github_genloop-0.1.4}/setup.cfg +0 -0
- {alissa_tools_github_genloop-0.1.3 → alissa_tools_github_genloop-0.1.4}/setup.py +0 -0
- {alissa_tools_github_genloop-0.1.3 → alissa_tools_github_genloop-0.1.4}/src/main/alissa/tools/github/genloop/__init__.py +0 -0
- {alissa_tools_github_genloop-0.1.3 → alissa_tools_github_genloop-0.1.4}/src/main/alissa/tools/github/genloop/__main__.py +0 -0
- {alissa_tools_github_genloop-0.1.3 → alissa_tools_github_genloop-0.1.4}/src/main/alissa/tools/github/genloop/alissa_cli.py +0 -0
- {alissa_tools_github_genloop-0.1.3 → alissa_tools_github_genloop-0.1.4}/src/main/alissa/tools/github/genloop/alissa_client.py +0 -0
- {alissa_tools_github_genloop-0.1.3 → alissa_tools_github_genloop-0.1.4}/src/main/alissa/tools/github/genloop/config.py +0 -0
- {alissa_tools_github_genloop-0.1.3 → alissa_tools_github_genloop-0.1.4}/src/main/alissa/tools/github/genloop/loop.py +0 -0
- {alissa_tools_github_genloop-0.1.3 → alissa_tools_github_genloop-0.1.4}/src/main/alissa/tools/github/genloop/loop_events.py +0 -0
- {alissa_tools_github_genloop-0.1.3 → alissa_tools_github_genloop-0.1.4}/src/main/alissa/tools/github/genloop/pass_directive.py +0 -0
- {alissa_tools_github_genloop-0.1.3 → alissa_tools_github_genloop-0.1.4}/src/main/alissa/tools/github/genloop/plan.py +0 -0
- {alissa_tools_github_genloop-0.1.3 → alissa_tools_github_genloop-0.1.4}/src/main/alissa/tools/github/genloop/proc.py +0 -0
- {alissa_tools_github_genloop-0.1.3 → alissa_tools_github_genloop-0.1.4}/src/main/alissa/tools/github/genloop/state.py +0 -0
- {alissa_tools_github_genloop-0.1.3 → alissa_tools_github_genloop-0.1.4}/src/main/alissa/tools/github/genloop/version.py +0 -0
- {alissa_tools_github_genloop-0.1.3 → alissa_tools_github_genloop-0.1.4}/src/main/alissa_tools_github_genloop.egg-info/SOURCES.txt +0 -0
- {alissa_tools_github_genloop-0.1.3 → alissa_tools_github_genloop-0.1.4}/src/main/alissa_tools_github_genloop.egg-info/dependency_links.txt +0 -0
- {alissa_tools_github_genloop-0.1.3 → alissa_tools_github_genloop-0.1.4}/src/main/alissa_tools_github_genloop.egg-info/entry_points.txt +0 -0
- {alissa_tools_github_genloop-0.1.3 → alissa_tools_github_genloop-0.1.4}/src/main/alissa_tools_github_genloop.egg-info/top_level.txt +0 -0
|
@@ -13,8 +13,14 @@ same fallback orcloop's `ci-green` read uses. It reads only the run of record:
|
|
|
13
13
|
the newest plan-lint run of the trusted event (`pull_request_target`, the job
|
|
14
14
|
that publishes the `plan-lint` check run), mapped onto the check run's
|
|
15
15
|
`{conclusion}` shape. The offline `pull_request` run never counts, as it never
|
|
16
|
-
does on the check-runs path. A
|
|
17
|
-
|
|
16
|
+
does on the check-runs path. A `failure` is red only when the job's publish
|
|
17
|
+
step (`Publish the plan-lint check run …`, `if: always()`) succeeded: that
|
|
18
|
+
step is the only thing that creates the check run, and it publishes `failure`
|
|
19
|
+
itself when the linter never reported. When the publish step failed (a 5xx
|
|
20
|
+
on its POST), no check run exists, so the fallback reads None, as the
|
|
21
|
+
check-runs path would; the run's jobs (`actions/runs/<id>/jobs`) say which.
|
|
22
|
+
A denied 403 ("Resource not accessible") is latched for the process -- every
|
|
23
|
+
later read goes straight to the Actions path;
|
|
18
24
|
any other 403 (a secondary rate limit) falls back for that read only. When
|
|
19
25
|
the Actions read fails too, the warning is logged once per PR per head and
|
|
20
26
|
`LintUnreadable` is raised, which the caller skips quietly.
|
|
@@ -48,6 +54,9 @@ LINT_WORKFLOW = ".github/workflows/plan-lint.yml"
|
|
|
48
54
|
# conclusion passes through verbatim, so only `failure` is a red lint, as on
|
|
49
55
|
# the check-runs path; the offline `pull_request` run is never read.
|
|
50
56
|
LINT_EVENT = "pull_request_target"
|
|
57
|
+
# The trusted job's step that publishes the `plan-lint` check run, matched as a
|
|
58
|
+
# prefix of the step name (`GitHub(lint_publish_step=...)` names another).
|
|
59
|
+
LINT_PUBLISH_STEP = "Publish the plan-lint check run"
|
|
51
60
|
# The 403 body of a token that cannot read check runs, as against a rate limit.
|
|
52
61
|
_DENIED_MARKER = "resource not accessible"
|
|
53
62
|
# A plan PR thread longer than this many pages of 100 comments is read only up to here.
|
|
@@ -111,10 +120,12 @@ class Comment:
|
|
|
111
120
|
|
|
112
121
|
|
|
113
122
|
class GitHub:
|
|
114
|
-
def __init__(self, *, timeout: int = 60, lint_workflow: str = LINT_WORKFLOW, lint_event: str = LINT_EVENT
|
|
123
|
+
def __init__(self, *, timeout: int = 60, lint_workflow: str = LINT_WORKFLOW, lint_event: str = LINT_EVENT,
|
|
124
|
+
lint_publish_step: str = LINT_PUBLISH_STEP):
|
|
115
125
|
self.timeout = timeout
|
|
116
126
|
self.lint_workflow = lint_workflow
|
|
117
127
|
self.lint_event = lint_event
|
|
128
|
+
self.lint_publish_step = lint_publish_step
|
|
118
129
|
# Latched on the first 403 from check-runs: this token cannot read them.
|
|
119
130
|
self._check_runs_denied = False
|
|
120
131
|
# (repo, pr) -> the head whose unreadable lint has been logged already;
|
|
@@ -274,7 +285,8 @@ class GitHub:
|
|
|
274
285
|
def _lint_actions_run(self, repo: str, sha: str) -> dict | None:
|
|
275
286
|
"""The newest plan-lint run of `lint_event` on `sha` as a check run:
|
|
276
287
|
its conclusion verbatim once completed, pending (None) before, and
|
|
277
|
-
None when there is no such run yet
|
|
288
|
+
None when there is no such run yet -- or when it failed only because
|
|
289
|
+
its publish step did, so that no check run exists."""
|
|
278
290
|
data = self._api(
|
|
279
291
|
"-X", "GET", f"repos/{repo}/actions/runs", "-f", f"head_sha={sha}", "-f", "per_page=100",
|
|
280
292
|
)
|
|
@@ -287,12 +299,31 @@ class GitHub:
|
|
|
287
299
|
return None
|
|
288
300
|
head = max(trusted, key=_run_order)
|
|
289
301
|
completed = head.get("status") == "completed"
|
|
302
|
+
if completed and head.get("conclusion") == "failure" and not self._lint_published(repo, head):
|
|
303
|
+
return None
|
|
290
304
|
return {
|
|
291
305
|
"id": head.get("id"), "name": LINT_CHECK_NAME, "source": "actions",
|
|
292
306
|
"status": "completed" if completed else str(head.get("status") or "") or "in_progress",
|
|
293
307
|
"conclusion": head.get("conclusion") if completed else None, "html_url": head.get("html_url"),
|
|
294
308
|
}
|
|
295
309
|
|
|
310
|
+
def _lint_published(self, repo: str, run: dict) -> bool:
|
|
311
|
+
"""Whether the failed `run` published its `plan-lint` check run: its
|
|
312
|
+
publish step succeeded, or no step of its jobs is the publish step (the
|
|
313
|
+
failure then stands, as before this read)."""
|
|
314
|
+
path = f"repos/{repo}/actions/runs/{run.get('id')}/jobs"
|
|
315
|
+
data = self._api("-X", "GET", path, "-f", "per_page=100")
|
|
316
|
+
jobs = data.get("jobs") if isinstance(data, dict) else None
|
|
317
|
+
if not isinstance(jobs, list):
|
|
318
|
+
raise CommandError(["gh", "api", path], 0, "no jobs in the answer")
|
|
319
|
+
steps = [s for j in jobs if isinstance(j, dict) for s in (j.get("steps") or [])
|
|
320
|
+
if isinstance(s, dict) and str(s.get("name") or "").startswith(self.lint_publish_step)]
|
|
321
|
+
if not steps or any(s.get("conclusion") == "success" for s in steps):
|
|
322
|
+
return True
|
|
323
|
+
log.debug("genloop: plan-lint run %s on %s failed without publishing its check run — no lint, "
|
|
324
|
+
"as on the check-runs path", run.get("id"), repo)
|
|
325
|
+
return False
|
|
326
|
+
|
|
296
327
|
def _is_lint_workflow(self, r: dict) -> bool:
|
|
297
328
|
path = str(r.get("path") or "").split("@", 1)[0]
|
|
298
329
|
return self.lint_workflow in (path, str(r.get("name") or ""))
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.1.4
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0.1.3
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|