~ubuntu-archive/ubuntu-archive-tools/trunk

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#!/usr/bin/python3
# Generate a list of autopkgtest request.cgi URLs to
# re-run all autopkgtests which regressed
# Copyright (C) 2015-2016 Canonical Ltd.
# Author: Martin Pitt <martin.pitt@ubuntu.com>

# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.

# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.

# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
# USA

import urllib.request
import urllib.parse
import argparse
import yaml
import json

request_url = 'https://autopkgtest.ubuntu.com/request.cgi'
default_series = 'bionic'
args = None


def parse_args():
    parser = argparse.ArgumentParser(
        'Generate %s URLs to re-run regressions' % request_url,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        description='''Typical workflow:
 - export autopkgtest.ubuntu.com session cookie into ~/.cache/autopkgtest.cookie
   Use a browser plugin or get the value from the settings and create it with
   printf "autopkgtest.ubuntu.com\\tTRUE\\t/\\tTRUE\\t0\\tsession\\tVALUE\\n" > ~/.cache/autopkgtest.cookie
   (The cookie is valid for one month)

 - retry-autopkgtest-regressions [opts...] | vipe | xargs -rn1 -P10 wget --load-cookies ~/.cache/autopkgtest.cookie -O-
   edit URL list to pick/remove requests as desired, then close editor to let it run
''')
    parser.add_argument('-s', '--series', default=default_series,
                        help='Ubuntu series (default: %(default)s)')
    parser.add_argument('--bileto', metavar='TICKETNUMBER',
                        help='Run for bileto ticket')
    parser.add_argument('--all-proposed', action='store_true',
                        help='run tests against all of proposed, i. e. with disabling apt pinning')
    parser.add_argument('--state', default='REGRESSION',
                        help='generate commands for given test state (default: %(default)s)')
    parser.add_argument('--max-age', type=float, metavar='DAYS',
                        help='only consider candiates which are at most '
                        'this number of days old (float allowed)')
    parser.add_argument('--min-age', type=float, metavar='DAYS',
                        help='only consider candiates which are at least '
                        'this number of days old (float allowed)')
    args = parser.parse_args()

    return args


def get_regressions(excuses_url, release, retry_state, min_age, max_age):
    '''Return dictionary with regressions

    Return dict: release → pkg → arch → [trigger, ...]
    '''
    # load YAML excuses
    with urllib.request.urlopen(excuses_url) as f:
        excuses = yaml.load(f)
    regressions = {}
    for excuse in excuses['sources']:
        try:
            age = excuse['policy_info']['age']['current-age']
        except KeyError:
            age = None

        # excuses are sorted by ascending age
        if min_age is not None and age is not None and age < min_age:
            continue
        if max_age is not None and age is not None and age > max_age:
            break
        for pkg, archinfo in excuse.get('policy_info', {}).get('autopkgtest', {}).items():
            pkg = pkg.split('/')[0].split()[0]  # strip off version (either / or space separated)
            trigger = excuse['source'] + '/' + excuse['new-version']
            for arch, state in archinfo.items():
                if state[0] == retry_state:
                    regressions.setdefault(release, {}).setdefault(
                        pkg, {}).setdefault(arch, []).append(trigger)

    return regressions


args = parse_args()

extra_params = []
if args.all_proposed:
    extra_params.append(('all-proposed', '1'))

if args.bileto:
    url_root = 'https://bileto.ubuntu.com'
    ticket_url = url_root + '/v2/ticket/%s' % args.bileto
    excuses_url = None
    with urllib.request.urlopen(ticket_url) as f:
        ticket = json.loads(f.read().decode('utf-8'))['tickets'][0]
    ppa_name = ticket.get('ppa', '')
    for line in ticket.get('autopkgtest', '').splitlines():
        if args.series in line:
            excuses_url = line
            break
    if excuses_url.startswith('/'):
        excuses_url = url_root + excuses_url
    excuses_url = excuses_url.replace('.html', '.yaml')
    extra_params += [('ppa', 'ci-train-ppa-service/stable-phone-overlay'),
                     ('ppa', 'ci-train-ppa-service/%s' % ppa_name)]
else:
    excuses_url = 'http://people.canonical.com/~ubuntu-archive/proposed-migration/%s/update_excuses.yaml' % args.series
regressions = get_regressions(excuses_url, args.series, args.state,
                              args.min_age, args.max_age)

for release, pkgmap in regressions.items():
    for pkg, archmap in pkgmap.items():
        for arch, triggers in archmap.items():
            params = [('release', release), ('arch', arch), ('package', pkg)]
            params += [('trigger', t) for t in triggers]
            params += extra_params
            url = request_url + '?' + urllib.parse.urlencode(params)
            print(url)