alissa-tools-github-revloop 0.21.0__tar.gz → 0.23.0__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_revloop-0.21.0/src/main/alissa_tools_github_revloop.egg-info → alissa_tools_github_revloop-0.23.0}/PKG-INFO +1 -1
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/src/main/alissa/tools/github/revloop/alissa.py +116 -6
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/src/main/alissa/tools/github/revloop/prreview.py +3 -3
- alissa_tools_github_revloop-0.23.0/src/main/alissa/tools/github/revloop/version +1 -0
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0/src/main/alissa_tools_github_revloop.egg-info}/PKG-INFO +1 -1
- alissa_tools_github_revloop-0.21.0/src/main/alissa/tools/github/revloop/version +0 -1
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/LICENSE +0 -0
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/MANIFEST.in +0 -0
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/NOTICE +0 -0
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/README.md +0 -0
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/requirements.txt +0 -0
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/setup.cfg +0 -0
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/setup.py +0 -0
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/src/main/alissa/tools/github/revloop/__init__.py +0 -0
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/src/main/alissa/tools/github/revloop/__main__.py +0 -0
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/src/main/alissa/tools/github/revloop/config.py +0 -0
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/src/main/alissa/tools/github/revloop/ghclient.py +0 -0
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/src/main/alissa/tools/github/revloop/loop.py +0 -0
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/src/main/alissa/tools/github/revloop/proc.py +0 -0
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/src/main/alissa/tools/github/revloop/state.py +0 -0
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/src/main/alissa/tools/github/revloop/version.py +0 -0
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/src/main/alissa/tools/github/revloop/webui/__init__.py +0 -0
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/src/main/alissa/tools/github/revloop/webui/__main__.py +0 -0
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/src/main/alissa/tools/github/revloop/webui/auth.py +0 -0
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/src/main/alissa/tools/github/revloop/webui/page.py +0 -0
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/src/main/alissa/tools/github/revloop/webui/server.py +0 -0
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/src/main/alissa/tools/github/revloop/webui/sources.py +0 -0
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/src/main/alissa/tools/github/revloop/webui/sysinfo.py +0 -0
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/src/main/alissa_tools_github_revloop.egg-info/SOURCES.txt +0 -0
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/src/main/alissa_tools_github_revloop.egg-info/dependency_links.txt +0 -0
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/src/main/alissa_tools_github_revloop.egg-info/entry_points.txt +0 -0
- {alissa_tools_github_revloop-0.21.0 → alissa_tools_github_revloop-0.23.0}/src/main/alissa_tools_github_revloop.egg-info/top_level.txt +0 -0
|
@@ -13,8 +13,42 @@ from .proc import CommandError, run, run_json
|
|
|
13
13
|
|
|
14
14
|
log = logging.getLogger(__name__)
|
|
15
15
|
|
|
16
|
-
#
|
|
17
|
-
|
|
16
|
+
# The seven canonical Alissa task statuses -- `TaskStatusSchema` in the studio
|
|
17
|
+
# repo (`packages/client/src/schemas/common.ts`). Mirrored here for the reason
|
|
18
|
+
# the studio CLI mirrors it into `TASK_STATUSES` rather than importing it: what
|
|
19
|
+
# this module needs is the SET of names, not the schema that validates them.
|
|
20
|
+
#
|
|
21
|
+
# It is the vocabulary the `--status` filter below is allowed to speak. CLI
|
|
22
|
+
# 0.2.0 validates `--status` against exactly these seven client-side and exits 1
|
|
23
|
+
# on anything else BEFORE issuing any request, so a single non-canonical value
|
|
24
|
+
# does not narrow the call slightly less -- it costs the whole narrowed call.
|
|
25
|
+
#
|
|
26
|
+
# A status Alissa adds lands HERE first: a name added to `OPEN_STATUSES` alone
|
|
27
|
+
# reads as non-canonical and drops the narrowing for the whole fleet. That is
|
|
28
|
+
# the safe direction -- wide, never a wrong task resolved -- and the canonical
|
|
29
|
+
# test fails on it, but it fails naming `OPEN_STATUSES`, which is the constant
|
|
30
|
+
# that is right; this is the one that is stale (PR #98 round 1).
|
|
31
|
+
CANONICAL_TASK_STATUSES = frozenset(
|
|
32
|
+
{
|
|
33
|
+
"draft",
|
|
34
|
+
"committed",
|
|
35
|
+
"in_progress",
|
|
36
|
+
"blocked",
|
|
37
|
+
"pending_validation",
|
|
38
|
+
"validated",
|
|
39
|
+
"cancelled",
|
|
40
|
+
}
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# A review task is "open" while it can still receive a verdict. Every member is
|
|
44
|
+
# canonical, and a test pins that: a status Alissa cannot issue is dead weight
|
|
45
|
+
# in `is_open` and poison in the `--status` filter derived from it.
|
|
46
|
+
#
|
|
47
|
+
# `todo` was such a member until 0.22.0 (issue #97). Alissa has never had that
|
|
48
|
+
# status, so `is_open` could never match it -- but it was still reaching CLI
|
|
49
|
+
# 0.2.0's `--status` validator, which rejects the call over it, which in turn
|
|
50
|
+
# drops this process back to the unnarrowed whole-corpus list for good.
|
|
51
|
+
OPEN_STATUSES = {"committed", "in_progress", "pending_validation"}
|
|
18
52
|
|
|
19
53
|
# -- narrowing the `alissa task list` call (issue #87) ------------------------
|
|
20
54
|
#
|
|
@@ -26,13 +60,48 @@ OPEN_STATUSES = {"committed", "in_progress", "pending_validation", "todo"}
|
|
|
26
60
|
# not evidence, and this daemon turns a non-zero `alissa` exit into a SKIPPED
|
|
27
61
|
# decision, so sending a flag the CLI does not have costs a review.
|
|
28
62
|
|
|
29
|
-
# Statuses a LIVE review task can hold. Deliberately
|
|
30
|
-
# not a hand-written list: `is_review_task_for` already rejects every other
|
|
63
|
+
# Statuses a LIVE review task can hold. Deliberately derived from OPEN_STATUSES
|
|
64
|
+
# and not a hand-written list: `is_review_task_for` already rejects every other
|
|
31
65
|
# status client-side, so filtering server-side on exactly this set cannot change
|
|
32
66
|
# which task the daemon resolves -- it only stops shipping the rows over the
|
|
33
67
|
# wire. Any status added to `is_open` is added here by construction.
|
|
68
|
+
#
|
|
69
|
+
# The canonical guard below does not weaken that invariant, and is deliberately
|
|
70
|
+
# not an INTERSECTION with the canonical set, which would: an intersection makes
|
|
71
|
+
# the filter a strict subset of the open set the moment the two disagree, so the
|
|
72
|
+
# daemon would stop fetching rows `is_open` still accepts -- a skipped review,
|
|
73
|
+
# reported as an empty corpus. The whole derivation is kept or nothing is sent.
|
|
74
|
+
# Sending nothing degrades to the call the daemon has always made: wide, but
|
|
75
|
+
# complete, which is the direction every other failure on this path degrades in.
|
|
34
76
|
TASK_LIST_STATUS_FLAG = "--status"
|
|
35
|
-
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _status_filter(statuses: "set[str] | frozenset[str]") -> str:
|
|
80
|
+
"""The `--status` argument for `statuses`, or `""` when they cannot be one.
|
|
81
|
+
|
|
82
|
+
`""` means "do not narrow by status". It is returned for a set carrying any
|
|
83
|
+
non-canonical value, because such a value is not a filter the CLI serves
|
|
84
|
+
less precisely -- it is one the CLI refuses outright, taking the `--view`
|
|
85
|
+
and `--self` narrowing down with it and pinning this process to the
|
|
86
|
+
whole-corpus list (`list_tasks`). One wide call beats every call being wide.
|
|
87
|
+
|
|
88
|
+
Pure on purpose. The condition is a code defect and deserves saying out
|
|
89
|
+
loud, but not from here: this runs at IMPORT, which is the one moment the
|
|
90
|
+
daemon's logging is not configured yet (see
|
|
91
|
+
`Alissa._warn_status_filter_dropped`). The tests are what pin the condition;
|
|
92
|
+
the runtime warning is the second line, and it is emitted where it can both
|
|
93
|
+
be formatted and be true.
|
|
94
|
+
"""
|
|
95
|
+
if set(statuses) - CANONICAL_TASK_STATUSES:
|
|
96
|
+
return ""
|
|
97
|
+
return ",".join(sorted(statuses))
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
TASK_LIST_STATUS_FILTER = _status_filter(OPEN_STATUSES)
|
|
101
|
+
|
|
102
|
+
# Why the filter above is empty, when it is -- kept for the diagnostic, which
|
|
103
|
+
# cannot be emitted from module scope. Empty in the healthy case.
|
|
104
|
+
NON_CANONICAL_OPEN_STATUSES = tuple(sorted(OPEN_STATUSES - CANONICAL_TASK_STATUSES))
|
|
36
105
|
|
|
37
106
|
# `--self` drops the SPONSOR's corpus and keeps only the calling actor's rows.
|
|
38
107
|
#
|
|
@@ -320,6 +389,9 @@ class Alissa:
|
|
|
320
389
|
# wrongly is worse than a list that is large: `find_review_task` reads an
|
|
321
390
|
# empty corpus as "this PR has no review task".
|
|
322
391
|
self._task_list_narrowing_disabled = False
|
|
392
|
+
# One diagnostic per client for a status filter that could not be sent
|
|
393
|
+
# (see `_warn_status_filter_dropped`); this path runs every poll pass.
|
|
394
|
+
self._status_filter_warned = False
|
|
323
395
|
|
|
324
396
|
# -- the `alissa task list` narrowing probe -----------------------------
|
|
325
397
|
|
|
@@ -365,6 +437,38 @@ class Alissa:
|
|
|
365
437
|
self._task_list_flags = flags
|
|
366
438
|
return flags
|
|
367
439
|
|
|
440
|
+
def _warn_status_filter_dropped(self) -> None:
|
|
441
|
+
"""Say, once, that a status narrowing this CLI offers is going unused.
|
|
442
|
+
|
|
443
|
+
Not emitted where the filter is COMPUTED, which is import time, and that
|
|
444
|
+
is the whole point of it living here (PR #98 round 1): `__main__` pulls
|
|
445
|
+
this module in through `.loop` long before it calls
|
|
446
|
+
`logging.basicConfig`, so a warning at module scope falls through to
|
|
447
|
+
`logging.lastResort` -- bare on stderr, no timestamp or logger name, and
|
|
448
|
+
outside whatever handler the deployment configured.
|
|
449
|
+
|
|
450
|
+
It would also be premature there. At import nothing yet knows whether
|
|
451
|
+
this CLI serves `--status` at all, and on a CLI that does not, the
|
|
452
|
+
filter costs nothing and there is nothing to warn about. Here the
|
|
453
|
+
message is only emitted when the flag was on offer and could not be
|
|
454
|
+
used, which is the only case where the defect actually costs reads.
|
|
455
|
+
"""
|
|
456
|
+
if self._status_filter_warned:
|
|
457
|
+
return
|
|
458
|
+
self._status_filter_warned = True
|
|
459
|
+
reason = (
|
|
460
|
+
"non-canonical status(es) in OPEN_STATUSES: "
|
|
461
|
+
+ ", ".join(NON_CANONICAL_OPEN_STATUSES)
|
|
462
|
+
if NON_CANONICAL_OPEN_STATUSES
|
|
463
|
+
else "OPEN_STATUSES is empty"
|
|
464
|
+
)
|
|
465
|
+
log.warning(
|
|
466
|
+
"`alissa task list` offers --status and this daemon is not using "
|
|
467
|
+
"it (%s) -- the CLI rejects the whole call over one unknown value, "
|
|
468
|
+
"so the corpus is listed unnarrowed",
|
|
469
|
+
reason,
|
|
470
|
+
)
|
|
471
|
+
|
|
368
472
|
def task_list_argv(self, *, narrow_status: bool = True) -> list[str]:
|
|
369
473
|
"""The narrowest `alissa task list` this CLI actually supports.
|
|
370
474
|
|
|
@@ -375,8 +479,14 @@ class Alissa:
|
|
|
375
479
|
if self._task_list_narrowing_disabled:
|
|
376
480
|
return argv
|
|
377
481
|
flags = self.probe_task_list()
|
|
482
|
+
# An empty filter is not a filter: `_status_filter` answers `""` when
|
|
483
|
+
# the open set carries a status the CLI would reject, and sending
|
|
484
|
+
# `--status ""` would be that same rejected call with an extra step.
|
|
378
485
|
if flags.status and narrow_status:
|
|
379
|
-
|
|
486
|
+
if TASK_LIST_STATUS_FILTER:
|
|
487
|
+
argv += [TASK_LIST_STATUS_FLAG, TASK_LIST_STATUS_FILTER]
|
|
488
|
+
else:
|
|
489
|
+
self._warn_status_filter_dropped()
|
|
380
490
|
if flags.self_scope and self._task_list_self_scope:
|
|
381
491
|
argv.append(TASK_LIST_SELF_FLAG)
|
|
382
492
|
if flags.digest:
|
|
@@ -75,9 +75,9 @@ def _review_task_ref(alissa: Alissa, owner: str, repo: str, number: int) -> str
|
|
|
75
75
|
Deliberately not `Alissa.find_review_task` (which filters to open tasks): we
|
|
76
76
|
still want the ref just after the task is validated, to read its verdict.
|
|
77
77
|
`narrow_status=False` says the same thing to the LIST call for the same
|
|
78
|
-
reason -- the daemon's server-side status filter is exactly its
|
|
79
|
-
set
|
|
80
|
-
exists to avoid.
|
|
78
|
+
reason -- the daemon's server-side status filter is either exactly its
|
|
79
|
+
`is_open` set or absent altogether, and in the first case narrowing by it
|
|
80
|
+
here would re-impose the filter this function exists to avoid.
|
|
81
81
|
"""
|
|
82
82
|
pattern = re.compile(
|
|
83
83
|
rf"^Review PR\s+{re.escape(owner)}/{re.escape(repo)}#{number}\b", re.IGNORECASE
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.23.0
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0.21.0
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|