Skip to content

Commit 1162494

Browse files
committed
introduce two level bug expiration
1 parent 84ab6ea commit 1162494

7 files changed

Lines changed: 51 additions & 55 deletions

File tree

startriage/cli.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ def _build_parser() -> argparse.ArgumentParser:
119119
+ last activity NOT from the team (reply pending)
120120
U updated recently (within --flag-recent days)
121121
O old / dormant (beyond --flag-old days)
122-
X expiring (not seen in today's window, --expire-tagged/--expire days)
122+
X expiring (not seen in today's window, --expire-level1/2 days)
123123
N new bug since last --compare file
124124
v verification-needed-* tag set
125125
V verification-done-* tag set
@@ -142,16 +142,16 @@ def _build_parser() -> argparse.ArgumentParser:
142142
)
143143
triage_p.add_argument("--no-expiration", action="store_true", help="Skip expiring bugs subsection")
144144
triage_p.add_argument(
145-
"--expire-tagged",
145+
"--expire-level1",
146146
type=int,
147147
metavar="DAYS",
148-
help="Days to consider todo-tagged bugs expired if no update happened",
148+
help="Days to re-display old expiring bugs (level 1)",
149149
)
150150
triage_p.add_argument(
151-
"--expire",
151+
"--expire-level2",
152152
type=int,
153153
metavar="DAYS",
154-
help="Days to consider subscribed bugs expired if no update happened",
154+
help="Days to re-display ay old expiring bugs (level 2)",
155155
)
156156
triage_p.add_argument(
157157
"--extended",
@@ -192,7 +192,7 @@ def _build_parser() -> argparse.ArgumentParser:
192192

193193
config_setdefaults_p = config_sp.add_parser("set", help="Persist settings to config file")
194194
config_setdefaults_p.add_argument("--discourse-site", help="Discourse website base URL")
195-
config_setdefaults_p.add_argument("--discourse-category", help="Discourse category")
195+
config_setdefaults_p.add_argument("--discourse-categories", help="Discourse category (comma separated)")
196196
config_setdefaults_p.add_argument("--default-team", help="Set general.default_team in config")
197197
config_setdefaults_p.add_argument(
198198
"--save-bugs-dir", metavar="PATH", help="Directory to track previous bugs in"
@@ -277,10 +277,10 @@ async def _run_triage(args: argparse.Namespace, config: StarTriageConfig) -> Non
277277
team = team.model_copy(update={"lp_ignore_packages": []})
278278

279279
general = config.general
280-
if args.expire_tagged is not None:
281-
general = general.model_copy(update={"lp_expire_tagged": args.expire_tagged})
282-
if args.expire is not None:
283-
general = general.model_copy(update={"lp_expire": args.expire})
280+
if args.expire_level1 is not None:
281+
general = general.model_copy(update={"lp_expire_level1_days": args.expire_level1})
282+
if args.expire_level2 is not None:
283+
general = general.model_copy(update={"lp_expire_level2_days": args.expire_level2})
284284
if args.extended is not None:
285285
general = general.model_copy(update={"lp_extended": args.extended})
286286
if args.proposed_min_age is not None:
@@ -340,11 +340,11 @@ async def _set_config_settings(args: argparse.Namespace, _config: StarTriageConf
340340
data.setdefault("general", {})["default_team"] = args.default_team
341341
if args.discourse_site:
342342
data.setdefault("general", {})["discourse_site"] = args.discourse_site
343-
if args.discourse_category:
343+
if args.discourse_categories:
344344
if not args.team:
345-
raise ValueError("error: --discourse-category requires -t/--team")
345+
raise ValueError("error: --discourse-categories requires -t/--team")
346346
team_section = data.setdefault("team", {}).setdefault(args.team, {})
347-
team_section["discourse_categories"] = args.discourse_category
347+
team_section["discourse_categories"] = args.discourse_categories.split(",")
348348
if args.save_bugs_dir:
349349
if not Path(args.save_bugs_dir).is_dir():
350350
raise ValueError(f"error: --save-bugs-dir {args.save_bugs_dir!r} is not a directory")

startriage/config.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
class GeneralConfig(BaseModel):
1919
model_config = ConfigDict(extra="forbid")
2020

21-
lp_expire_tagged: int = 60
22-
lp_expire: int = 180
21+
lp_expire_level1_days: int = 60
22+
lp_expire_level2_days: int = 180
2323
lp_extended: bool | None = None
2424
lp_triage_updates: UpdateFilter = UpdateFilter.theirs
2525
savebugs_dir: Path | None = None

startriage/data/defaults.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[general]
2-
lp_expire_tagged = 60
3-
lp_expire = 180
2+
lp_expire_level1_days = 60
3+
lp_expire_level2_days = 180
44
lp_triage_updates = "theirs"
55
#savebugs_dir = ~/src/ubuntu/mnt/savebugs/
66
#default_team = automatic if 1 defined

startriage/output.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,11 @@ async def record(self, persistor: BugPersistor) -> None:
4646

4747

4848
@lru_cache(maxsize=256)
49-
def hyperlink(url: str, text: str, fmt: OutputFormat = OutputFormat.TERMINAL) -> str:
49+
def hyperlink(
50+
url: str, text: str, fmt: OutputFormat = OutputFormat.TERMINAL, pad_right: int | None = None
51+
) -> str:
5052
"""Format text as a hyperlink for the given output format.
53+
pad_right: pad the resulting string, but the clickable surface remains just text.
5154
5255
Terminal: ANSI OSC8 escape sequence (only when stdout is a TTY).
5356
Markdown: [text](url)
@@ -59,7 +62,11 @@ def hyperlink(url: str, text: str, fmt: OutputFormat = OutputFormat.TERMINAL) ->
5962
if os.isatty(sys.stdout.fileno()):
6063
osc8 = "\x1b]8"
6164
st = "\x1b\\"
62-
return f"{osc8};;{url}{st}{text}{osc8};;{st}"
65+
padding = ""
66+
if pad_right is not None:
67+
padding_len = max(0, pad_right - len(text))
68+
padding = " " * padding_len
69+
return f"{osc8};;{url}{st}{text}{osc8};;{st}{padding}"
6370
return text
6471
case _:
6572
raise NotImplementedError

startriage/sources/launchpad/finder.py

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,8 @@ def fetch_bugs(
136136
filter: TaskFilterOptions,
137137
mode: FetchMode,
138138
update_filter: str | None,
139-
expire_tagged_days: int = 60,
140-
expire_days: int = 180,
139+
expire_level1_days: int = 60,
140+
expire_level2_days: int = 180,
141141
) -> LaunchpadTasks:
142142
"""Synchronous LP fetch - run inside asyncio.to_thread().
143143
@@ -241,7 +241,7 @@ def fetch_bugs(
241241
expiring_subscribed: list[Task] = []
242242
if mode == FetchMode.triage and filter.show_expiration and filter.start and filter.end:
243243

244-
def _expiring_window(days: int, tags: list[str], statuses: list[str]) -> list[Task]:
244+
def _expiring_window(days: int) -> list[Task]:
245245
shift = timedelta(days=days)
246246
w_start = filter.start - shift
247247
w_end = filter.end - shift
@@ -251,21 +251,17 @@ def _expiring_window(days: int, tags: list[str], statuses: list[str]) -> list[Ta
251251
for t in _search_tasks_all_series(
252252
ubuntu,
253253
modified_since=w_start,
254-
bug_subscriber=team,
255-
tags=tags,
256-
tags_combinator="All",
257-
status=statuses,
254+
structural_subscriber=team,
255+
status=OPEN_BUG_STATUSES,
258256
)
259257
}
260258
since_end = {
261259
(t.bug_link, _fast_target_name(t)): t
262260
for t in _search_tasks_all_series(
263261
ubuntu,
264262
modified_since=w_end,
265-
bug_subscriber=team,
266-
tags=tags,
267-
tags_combinator="All",
268-
status=statuses,
263+
structural_subscriber=team,
264+
status=OPEN_BUG_STATUSES,
269265
)
270266
}
271267
result = []
@@ -279,21 +275,13 @@ def _expiring_window(days: int, tags: list[str], statuses: list[str]) -> list[Ta
279275
result.append(Task(lp_task, subscribed=True, last_activity_ours=is_ours, expiring=True))
280276
return result
281277

282-
logging.info("Fetching expiring tagged bugs (~%d days ago)\u2026", expire_tagged_days)
283-
expiring_tagged = _expiring_window(
284-
expire_tagged_days,
285-
[team_config.lp_todo_tag, "-bot-stop-nagging"],
286-
OPEN_BUG_STATUSES,
287-
)
288-
logging.info("Launchpad: %d expiring tagged bugs.", len({t.number for t in expiring_tagged}))
278+
logging.info("Fetching expiring bugs level 1 (~%d days ago)\u2026", expire_level1_days)
279+
expiring_tagged = _expiring_window(expire_level1_days)
280+
logging.info("Launchpad: %d expiring level-1 bugs.", len({t.number for t in expiring_tagged}))
289281

290-
logging.info("Fetching expiring subscribed bugs (~%d days ago)\u2026", expire_days)
291-
expiring_subscribed = _expiring_window(
292-
expire_days,
293-
["-bot-stop-nagging", f"-{team_config.lp_todo_tag}"],
294-
OPEN_BUG_STATUSES,
295-
)
296-
logging.info("Launchpad: %d expiring subscribed bugs.", len({t.number for t in expiring_subscribed}))
282+
logging.info("Fetching expiring bugs level 2 (~%d days ago)\u2026", expire_level2_days)
283+
expiring_subscribed = _expiring_window(expire_level2_days)
284+
logging.info("Launchpad: %d expiring level-2 bugs.", len({t.number for t in expiring_subscribed}))
297285

298286
active_series = [s.name for s in ubuntu.series_collection if s.active]
299287

startriage/sources/launchpad/models.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
COLOR_STATUS_OPEN = "\033[0;31m" # red
2424
COLOR_RESET = "\033[0m"
2525

26-
LONG_URL_ROOT = "https://bugs.launchpad.net/ubuntu/+bug/"
26+
_LP_BUG_URL_ROOT = "https://bugs.launchpad.net/ubuntu/+bug/"
27+
_LP_SOURCE_URL = "https://launchpad.net/ubuntu/+source/{pkg}"
2728
LPBUGREF = "LP: #"
2829

2930
# Visual width of the Release column in the triage table.
@@ -121,7 +122,7 @@ def short_title(self) -> str:
121122

122123
@property
123124
def url(self) -> str:
124-
return LONG_URL_ROOT + self.number
125+
return _LP_BUG_URL_ROOT + self.number
125126

126127
@property
127128
def bug_reference(self) -> str:
@@ -220,7 +221,7 @@ def get_table_row(
220221
newbug: bool = False,
221222
) -> str:
222223
bug_ref = self.bug_reference if shortlinks else self.url
223-
fmt_len = bugid_len + len(LPBUGREF if shortlinks else LONG_URL_ROOT)
224+
fmt_len = bugid_len + len(LPBUGREF if shortlinks else _LP_BUG_URL_ROOT)
224225
bug_str = hyperlink(self.url, f"%-{fmt_len}s" % bug_ref)
225226

226227
# split up distro tasks to multiple lines if necessary.
@@ -233,12 +234,12 @@ def get_table_row(
233234
def _release_col(chunk: list[str]) -> str:
234235
return "".join(chunk) + " " * (_RELEASE_COL_WIDTH - len(chunk))
235236

236-
text = "%-12s | %6s | %s | %-13s | %-19s |" % (
237+
text = "%-12s | %6s | %s | %-13s | %s |" % (
237238
bug_str,
238239
self.get_flags(ctx, newbug),
239240
_release_col(chunks[0]),
240241
self.status,
241-
truncate_string(self.src, 19),
242+
hyperlink(_LP_SOURCE_URL.format(pkg=self.src), truncate_string(self.src, 19), pad=19),
242243
)
243244
if extended:
244245
text += " %8s | %-10s | %-13s |" % (

startriage/sources/launchpad/triage.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -238,15 +238,15 @@ async def _print_old_bugs(
238238
case OutputFormat.TERMINAL:
239239
for label, exp_tasks, days, order_by_date in [
240240
(
241-
"Expiring tagged",
241+
"Expiring level 1",
242242
expiring_tagged,
243-
config.lp_expire_tagged,
243+
config.lp_expire_level1_days,
244244
False,
245245
),
246246
(
247-
"Expiring subscribed",
247+
"Expiring level 2",
248248
expiring_subscribed,
249-
config.lp_expire,
249+
config.lp_expire_level2_days,
250250
True,
251251
),
252252
]:
@@ -289,8 +289,8 @@ async def find(
289289
filter,
290290
mode,
291291
effective_update_filter,
292-
config.general.lp_expire_tagged,
293-
config.general.lp_expire,
292+
config.general.lp_expire_level1_days,
293+
config.general.lp_expire_level2_days,
294294
)
295295
logging.info("Launchpad: %d bugs fetched. Checking unapproved queue…", len(lp_tasks.tasks))
296296

0 commit comments

Comments
 (0)