<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">#!/usr/bin/python3
#
# Copyright (C) 2021 Canonical Ltd.
# Author: Steve Beattie &lt;steve.beattie@canonical.com&gt;
#
# This is an incredibly dumb script to query the yaml output of
# britney's per-team excuses tracker, to report on things blocked in
# proposed in the devel release that a given team is on the hook for.
#
# It is intended as a team specific cli interface to
# https://people.canonical.com/~ubuntu-archive/proposed-migration/update_excuses_by_team.html
# usable from cron

import argparse
import requests
import sys
import yaml

_EXCUSES_PREFIX = "https://people.canonical.com/~ubuntu-archive/proposed-migration/"
EXCUSES_BY_TEAM_URL = _EXCUSES_PREFIX + "update_excuses_by_team.yaml"
EXCUSES_REFERENCE = _EXCUSES_PREFIX + "update_excuses.html"

DEFAULT_TEAM = "ubuntu-security"
MINIMUM_AGE = 2


def get_generic_excuse_info(excuse):
    package = excuse['package_in_proposed']
    age = excuse['age']
    version = excuse['data']['new-version']

    return (package, age, version)


def generate_ref_url(pkg):
    return EXCUSES_REFERENCE + "#" + pkg


def package_in_proposed(excuse, short_output=False):
    (package, age, version) = get_generic_excuse_info(excuse)

    if age &lt; MINIMUM_AGE:
        # only report on things that are lingering
        return []

    blockers = [blocker['package'] for blocker in excuse['regressions']]

    output = [
        "Package %s (%s) blocked in devel-proposed for %d days" %
            (package, version, age),
    ]
    if not short_output:
        output += [
            "Blocking packages: %s" % (", ".join(blockers)),
            "For more details, see:",
            "  %s" % generate_ref_url(package),
            "",
        ]
    return output


def regressing_other(excuse, short_output=False):
    (package, age, version) = get_generic_excuse_info(excuse)
    blocking_package = excuse['regressing_package']

    if age &lt; MINIMUM_AGE:
        # only report on things that are lingering
        return []

    output = [
        "Regression in %s is blocking %s (%s) in devel-proposed for %d days" %
            (blocking_package, package, version, age),
    ]
    if not short_output:
        output += [
            "For more details, see:",
            "  %s" % generate_ref_url(package),
            "",
        ]
    return output

def main():
    parser = argparse.ArgumentParser(
        description='Script to report packages stuck in -proposed'
    )
    parser.add_argument(
        '--oneline', action='store_true', default=False,
        help='compressed output, useful for aggregating cron jobs'
    )
    args = parser.parse_args()

    req = requests.get(EXCUSES_BY_TEAM_URL)
    if not req.status_code == 200:
        print("failed to get the excuses yaml page: %s" % req.url, file=sys.stderr)
        req.raise_for_status()

    excuses_yaml = req.content.decode()
    excuses = yaml.load(excuses_yaml, Loader=yaml.Loader)

    details = excuses[DEFAULT_TEAM]
    output = []

    for detail in details:
        if detail['kind'] == 'package-in-proposed':
            output += package_in_proposed(detail, args.oneline)
        elif detail['kind'] == 'regressing-other':
            output += regressing_other(detail, args.oneline)
        else:
            output += unknown_excuse(detail)

    if len(output) &gt; 0:
        print("Packages for %s sitting in devel-proposed for more than %d days" %
            (DEFAULT_TEAM, MINIMUM_AGE))
        print()
        print("\n".join(output))

if __name__ == "__main__":
    exit(main())
</pre></body></html>