Skip to content

Commit 2a4af26

Browse files
committed
pkg_in_pipe: log the progress, the cache usage and the source problems during the generation
Add a --debug option and log the koji tag and the build being processed, whether values come from the cache or are fetched again, and warn when the plane tickets or github can't be reached, using the same logger setup as gen-dnf-proxy.py. Signed-off-by: Gaëtan Lehmann <gaetan.lehmann@vates.tech>
1 parent 2ed80de commit 2a4af26

2 files changed

Lines changed: 71 additions & 11 deletions

File tree

‎scripts/pkg_in_pipe/README.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ environment variable or the `--plane-token` command line option.
1616

1717
An extra `--generated-info` command line option may be used to add some info about the report generation process.
1818

19+
The `--debug` option logs more details about the generation on stderr.
20+
1921
A machine readable version of the report can also be generated with the `--json-output` option:
2022

2123
```sh

‎scripts/pkg_in_pipe/pkg_in_pipe.py‎

Lines changed: 69 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
import argparse
33
import io
44
import json
5+
import logging
56
import os
67
import re
8+
import sys
79
import tomllib
810
from collections import defaultdict
911
from datetime import datetime
@@ -19,6 +21,31 @@
1921
from github.GithubException import BadCredentialsException
2022
from github.PullRequest import PullRequest
2123

24+
log = logging.getLogger(__name__)
25+
26+
27+
class ColorFormatter(logging.Formatter):
28+
colors = {
29+
logging.CRITICAL: '\033[31m',
30+
logging.ERROR: '\033[31m',
31+
logging.WARNING: '\033[33m',
32+
logging.DEBUG: '\033[34m',
33+
}
34+
35+
def __init__(self, use_color: bool) -> None:
36+
super().__init__(fmt='{message}', style='{')
37+
self.use_color = use_color
38+
39+
def format(self, record: logging.LogRecord) -> str:
40+
message = super().format(record)
41+
if record.levelno == logging.INFO:
42+
return message
43+
44+
prefix = f'{record.levelname.lower()}: '
45+
if color := self.colors.get(record.levelno) if self.use_color else None:
46+
prefix = f'{color}{prefix}\033[0m'
47+
return '\n'.join(f'{prefix}{line}' for line in message.splitlines() or [''])
48+
2249

2350
with open(os.path.join(os.path.dirname(__file__), 'missing_sources.toml'), 'rb') as missing_sources_file:
2451
MISSING_SOURCES = tomllib.load(missing_sources_file)
@@ -254,6 +281,21 @@ def find_released_build(build_tag, package_name):
254281
return get_koji_build(max(tagged, key=lambda t: t['build_id'])['build_id'])
255282
return None
256283

284+
def cached(key):
285+
"""Return the value cached for that key, or None when it must be fetched again."""
286+
if args.re_cache:
287+
log.debug("cache ignored because of --re-cache: %s", key)
288+
return None
289+
if key in CACHE:
290+
log.debug("cache hit: %s", key)
291+
return CACHE[key]
292+
log.debug("cache miss: %s", key)
293+
return None
294+
295+
def cache(key, value):
296+
log.debug("caching: %s", key)
297+
CACHE.set(key, value, expire=RETENTION_TIME)
298+
257299
def find_commits(gh, repo, start_sha, end_sha) -> list[Commit]:
258300
"""
259301
List the commits in the range [start_sha,end_sha[.
@@ -262,24 +304,24 @@ def find_commits(gh, repo, start_sha, end_sha) -> list[Commit]:
262304
A commit older that the end_sha commit and added by a merge commit won't appear in this list.
263305
"""
264306
cache_key = f'commits-2-{start_sha}-{end_sha}'
265-
if not args.re_cache and cache_key in CACHE:
266-
return cast(list[Commit], CACHE[cache_key])
307+
if (commits := cast(list[Commit], cached(cache_key))) is not None:
308+
return commits
267309
commits = []
268310
if gh:
269311
for commit in gh.get_repo(repo).get_commits(start_sha):
270312
if commit.sha == end_sha:
271313
break
272314
commits.append(commit)
273-
CACHE.set(cache_key, commits, expire=RETENTION_TIME)
315+
cache(cache_key, commits)
274316
return commits
275317

276318
def find_pull_requests(repo, start_sha, end_sha):
277319
"""Find the pull requests for the commits in the [start_sha,end_sha[ range."""
278320
prs = set()
279321
for commit in find_commits(GITHUB, repo, start_sha, end_sha):
280322
cache_key = f'commit-prs-6-{commit.sha}'
281-
if not args.re_cache and cache_key in CACHE:
282-
prs.update(cast(list[PullRequest], CACHE[cache_key]))
323+
if (commit_prs := cast(list[PullRequest], cached(cache_key))) is not None:
324+
prs.update(commit_prs)
283325
elif GITHUB:
284326
commit_prs = list(commit.get_pulls())
285327
if not commit_prs:
@@ -295,17 +337,17 @@ def find_pull_requests(repo, start_sha, end_sha):
295337
# commit. The latter is needed for the PRs merged by rebase or squash, whose merge
296338
# commit on the base branch is not one of the PR commits.
297339
commit_prs = [pr for pr in commit_prs if commit in pr.get_commits() or commit.sha == pr.merge_commit_sha]
298-
CACHE.set(cache_key, commit_prs, expire=RETENTION_TIME)
340+
cache(cache_key, commit_prs)
299341
prs.update(commit_prs)
300342
return sorted(prs, key=lambda p: p.number, reverse=True)
301343

302344
def get_koji_build(build_id) -> dict:
303345
cache_key = f'koji-build-{build_id}'
304-
if not args.re_cache and cache_key in CACHE:
305-
return cast(dict, CACHE[cache_key])
346+
if (build := cast(dict, cached(cache_key))) is not None:
347+
return build
306348
else:
307349
build = KOJI.getBuild(build_id)
308-
CACHE.set(cache_key, build, expire=RETENTION_TIME)
350+
cache(cache_key, build)
309351
return build
310352

311353
def get_plane_issues(plane_token):
@@ -409,8 +451,15 @@ def get_plane_issues_with_milestones(plane_token):
409451
)
410452
parser.add_argument('--re-cache', help="Refresh the cache", action='store_true')
411453
parser.add_argument('--json-output', help="Also write a machine readable report in json format to this path")
454+
parser.add_argument('--debug', help="Log more details on stderr", action='store_true')
412455
args = parser.parse_args()
413456

457+
handler = logging.StreamHandler()
458+
handler.setFormatter(ColorFormatter(
459+
not os.environ.get('NO_COLOR') and (bool(os.environ.get('FORCE_COLOR')) or sys.stderr.isatty()),
460+
))
461+
logging.basicConfig(level=logging.DEBUG if args.debug else logging.INFO, handlers=[handler])
462+
414463
CACHE = diskcache.Cache(args.cache)
415464
RETENTION_TIME = 24 * 60 * 60 # 24 hours
416465

@@ -426,8 +475,9 @@ def get_plane_issues_with_milestones(plane_token):
426475
# load the issues from plane, so we can search for the plane card related to a build
427476
try:
428477
issues = get_plane_issues_with_milestones(args.plane_token)
429-
except Exception:
478+
except Exception as e:
430479
issues = []
480+
log.warning("failed to load the tickets from plane: %s", e)
431481

432482
# connect to github
433483
GITHUB = None
@@ -437,6 +487,12 @@ def get_plane_issues_with_milestones(plane_token):
437487
GITHUB.get_repo('xcp-ng/xcp') # check that the token is valid
438488
except BadCredentialsException:
439489
GITHUB = None
490+
log.warning("the github token is invalid")
491+
except github.GithubException as e:
492+
GITHUB = None
493+
log.warning("failed to connect to github: %s", e)
494+
else:
495+
log.warning("no github token, the pull requests come from the cache")
440496

441497
# load the packages maintainers
442498
with urlopen('https://github.com/xcp-ng/xcp/raw/refs/heads/master/scripts/rpm_owners/packages.json') as f:
@@ -463,6 +519,7 @@ def get_plane_issues_with_milestones(plane_token):
463519
KOJI = koji.ClientSession('https://kojihub.xcp-ng.org', config)
464520
KOJI.ssl_login(config['cert'], None, config['serverca'])
465521
for tag in tags:
522+
log.info('processing tag %s', tag)
466523
tag_data = {'tag': tag, 'builds': []}
467524
report_data['tags'].append(tag_data)
468525
tag_history = dict(
@@ -474,6 +531,8 @@ def get_plane_issues_with_milestones(plane_token):
474531
taggeds = (t for t in taggeds if t['package_name'] in args.packages or args.packages == [])
475532
taggeds = sorted(taggeds, key=lambda t: (tag_history[t['build_id']], t['build_id']), reverse=True)
476533
for tagged in taggeds:
534+
build_url = f'https://koji.xcp-ng.org/buildinfo?buildID={tagged["build_id"]}'
535+
log.info(' processing build %s (%s)', tagged['nvr'], build_url)
477536
build = get_koji_build(tagged['build_id'])
478537
prs: list[PullRequest] = []
479538
maintained_by = None
@@ -483,7 +542,6 @@ def get_plane_issues_with_milestones(plane_token):
483542
(repo, sha) = parse_source(build['source'])
484543
prs = find_pull_requests(repo, sha, previous_build_sha)
485544
maintained_by = PACKAGES.get(tagged['package_name'], {}).get('maintainer')
486-
build_url = f'https://koji.xcp-ng.org/buildinfo?buildID={tagged["build_id"]}'
487545
build_issues = filter_issues(issues, [build_url] + [pr.html_url for pr in prs])
488546
print_table_line(
489547
temp_out, tagged['nvr'], build_url, build_issues, tagged['owner_name'], prs, maintained_by

0 commit comments

Comments
 (0)