Date: Mon, 08 Jun 2026 06:28:19 +0000 From: Yuri Victorovich <yuri@FreeBSD.org> To: ports-committers@FreeBSD.org, dev-commits-ports-all@FreeBSD.org, dev-commits-ports-main@FreeBSD.org Subject: git: 7160053217ef - main - Tools/scripts/report-outdated-for-maintainer.py: Update Message-ID: <6a266103.3cd81.5edbe05d@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch main has been updated by yuri: URL: https://cgit.FreeBSD.org/ports/commit/?id=7160053217ef2df40a69b1739ad8009681685dc0 commit 7160053217ef2df40a69b1739ad8009681685dc0 Author: Yuri Victorovich <yuri@FreeBSD.org> AuthorDate: 2026-06-07 20:09:56 +0000 Commit: Yuri Victorovich <yuri@FreeBSD.org> CommitDate: 2026-06-08 06:28:11 +0000 Tools/scripts/report-outdated-for-maintainer.py: Update --- Tools/scripts/report-outdated-for-maintainer.py | 124 +++++++++++++++--------- 1 file changed, 78 insertions(+), 46 deletions(-) diff --git a/Tools/scripts/report-outdated-for-maintainer.py b/Tools/scripts/report-outdated-for-maintainer.py index 6ebec0a31db2..a897a0dab147 100755 --- a/Tools/scripts/report-outdated-for-maintainer.py +++ b/Tools/scripts/report-outdated-for-maintainer.py @@ -193,20 +193,49 @@ def resolve_make_value(value, portname): def get_github_repo(makefile_path): - """Return (account, project) for USE_GITHUB=yes ports, else None.""" + """Return (account, project) for USE_GITHUB=yes ports or from WWW field, else None.""" use_github = get_makefile_var(makefile_path, "USE_GITHUB") - if not use_github or use_github.lower() != "yes": - return None - - portname = get_makefile_var(makefile_path, "PORTNAME") - if not portname: - return None - - gh_account = get_makefile_var(makefile_path, "GH_ACCOUNT") or portname - gh_project = get_makefile_var(makefile_path, "GH_PROJECT") or portname - gh_account = resolve_make_value(gh_account.split()[0], portname) - gh_project = resolve_make_value(gh_project.split()[0], portname) - return gh_account, gh_project + if use_github and use_github.lower() == "yes": + portname = get_makefile_var(makefile_path, "PORTNAME") + if not portname: + return None + + gh_account = get_makefile_var(makefile_path, "GH_ACCOUNT") or portname + gh_project = get_makefile_var(makefile_path, "GH_PROJECT") or portname + gh_account = resolve_make_value(gh_account.split()[0], portname) + gh_project = resolve_make_value(gh_project.split()[0], portname) + return gh_account, gh_project + + # If USE_GITHUB is not set, try to extract from WWW field, but only for ports + # that appear to use GitHub releases and are explicitly marked with a comment + # or have DISTVERSION matching a GitHub-style tag pattern (YYYY.M.DD or similar) + version = get_makefile_var(makefile_path, "DISTVERSION") or get_makefile_var(makefile_path, "PORTVERSION") + if version and looks_like_version(version): + # Only query from WWW if version matches GitHub-style patterns: + # - YYYY.M.DD (date-based like 2026.4.26, 2026.4.29) + # - X.Y.Z.W (4+ numeric components) + # This filters out most non-GitHub ports while catching real GitHub releases + parts = re.findall(r"\d+", version) + if len(parts) >= 3: + # Check if it looks like YYYY.M.DD (year >= 2000) + if int(parts[0]) >= 2000 and int(parts[0]) <= 2099: + if int(parts[1]) >= 1 and int(parts[1]) <= 12: + if int(parts[2]) >= 1 and int(parts[2]) <= 31: + # Looks like a date-based version from GitHub + www = get_makefile_var(makefile_path, "WWW") + if www: + m = re.match(r"https?://(?:www\.)?github\.com/([^/]+)/([^/\s]+)", www) + if m: + return m.group(1), m.group(2) + # Also check for simple 4+ component versions (e.g., 1.2.3.4) + elif len(parts) >= 4: + www = get_makefile_var(makefile_path, "WWW") + if www: + m = re.match(r"https?://(?:www\.)?github\.com/([^/]+)/([^/\s]+)", www) + if m: + return m.group(1), m.group(2) + + return None # --- Version handling --- @@ -328,14 +357,16 @@ def get_port_version_via_make(port_dir): def find_maintained_ports(maintainer_email): """ - Return (versions, uses_types, github_repos) keyed by port origin. + Return (versions, uses_types, github_repos, github_version_prefixes) keyed by port origin. versions[origin] = real version string uses_types[origin] = comma-separated port type string github_repos[origin] = (account, project) for USE_GITHUB ports + github_version_prefixes[origin] = (prefix, suffix) to strip from GitHub release tags """ versions = {} uses_types = {} github_repos = {} + github_version_prefixes = {} top_makefile = os.path.join(PORTSDIR, "Makefile") categories = get_subdir_entries(top_makefile) @@ -367,8 +398,15 @@ def find_maintained_ports(maintainer_email): github_repo = get_github_repo(port_makefile) if github_repo: github_repos[origin] = github_repo + portname = get_makefile_var(port_makefile, "PORTNAME") or "" + prefix_raw = get_makefile_var(port_makefile, "DISTVERSIONPREFIX") or "" + suffix_raw = get_makefile_var(port_makefile, "DISTVERSIONSUFFIX") or "" + prefix = resolve_make_value(prefix_raw, portname) + suffix = resolve_make_value(suffix_raw, portname) + if prefix or suffix: + github_version_prefixes[origin] = (prefix, suffix) - return versions, uses_types, github_repos + return versions, uses_types, github_repos, github_version_prefixes # --- Repology API --- @@ -451,48 +489,36 @@ def query_github_latest_release(account, project, cache): if key in cache: return cache[key] - quoted_account = urllib.parse.quote(account, safe="") - quoted_project = urllib.parse.quote(project, safe="") - url = f"{GITHUB_API_BASE}/repos/{quoted_account}/{quoted_project}/releases/latest" - + # Use 'gh' CLI for better rate limit handling and authentication try: - with github_request(url) as resp: - data = json.load(resp) - except urllib.error.HTTPError as e: - if e.code != 404: - print( - f"Warning: Could not query GitHub latest release for {account}/{project}: HTTP {e.code}", - file=sys.stderr, - ) - cache[key] = None - return None - except urllib.error.URLError as e: - print( - f"Warning: Could not query GitHub latest release for {account}/{project}: {e.reason}", - file=sys.stderr, + result = subprocess.run( + ["gh", "release", "view", "--repo", f"{account}/{project}"], + capture_output=True, + text=True, + timeout=30, ) + if result.returncode == 0: + for line in result.stdout.split("\n"): + if line.startswith("tag:"): + tag = line.split(":", 1)[1].strip() + cache[key] = tag.strip() or None + return cache[key] cache[key] = None return None - except Exception as e: - print( - f"Warning: Could not query GitHub latest release for {account}/{project}: {e}", - file=sys.stderr, - ) + except Exception: cache[key] = None return None - tag = (data.get("tag_name") or "").strip() - cache[key] = tag.strip() or None - return cache[key] - -def query_github_releases(github_repos): +def query_github_releases(github_repos, version_prefixes=None): """Return dict {origin: latest_release_tag} for GitHub-based ports with releases.""" cache = {} latest_releases = {} unique_repos = sorted(set(github_repos.values())) - with concurrent.futures.ThreadPoolExecutor(max_workers=16) as executor: + # gh CLI handles rate limiting better than direct API calls, so we can use more workers + max_workers = min(8, len(unique_repos)) if unique_repos else 1 + with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor: future_map = { executor.submit(query_github_latest_release, account, project, cache): (account, project) for account, project in unique_repos @@ -503,6 +529,12 @@ def query_github_releases(github_repos): for origin, repo in github_repos.items(): latest = cache.get(repo) if latest: + if version_prefixes and origin in version_prefixes: + prefix, suffix = version_prefixes[origin] + if prefix and latest.startswith(prefix): + latest = latest[len(prefix):] + if suffix and latest.endswith(suffix): + latest = latest[:-len(suffix)] latest_releases[origin] = latest return latest_releases @@ -651,7 +683,7 @@ def main(): check_portsdir() print(f"Scanning {PORTSDIR} for ports maintained by {maintainer_email}...", file=sys.stderr) - local_versions, local_uses, github_repos = find_maintained_ports(maintainer_email) + local_versions, local_uses, github_repos, github_version_prefixes = find_maintained_ports(maintainer_email) if not local_versions: print(f"No ports maintained by {maintainer_email}") @@ -662,7 +694,7 @@ def main(): file=sys.stderr, ) outdated_repology = query_repology_outdated(maintainer_email) - github_latest = query_github_releases(github_repos) + github_latest = query_github_releases(github_repos, github_version_prefixes) print(f"Repology reports {len(outdated_repology)} outdated FreeBSD ports.", file=sys.stderr) print(f"GitHub provides latest releases for {len(github_latest)} GitHub-based ports.", file=sys.stderr)home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a266103.3cd81.5edbe05d>
