summaryrefslogtreecommitdiffstats
path: root/scripts/check-upgrade-paths.py
blob: 40bf1cdfc3c0f8e0156716a22421bc40cff0cd06 (plain)
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#!/usr/bin/python
#
# check-upgrade-paths.py - A utility to examine a set of tags to verify upgrade
#       paths for all the packages.
#
# Copyright (c) 2008 Red Hat
#
# Authors:
#     Jesse Keating <jkeating@redhat.com>
#
# This script is loosely based on previous Extras script found at http://cvs.fedoraproject.org/viewcvs/upgradecheck/upgradecheck.py
# We don't actually do checking of subpackages, nor upgrade testing with Obsoletes/Provides.  In an ideal world these kinds of
# tests would be done as part of automated testing post-build or post-update submission.  We're getting close to these things
# so I decided to leave it out of this script for now.
#
# We also don't generate a owner sorted list of packages, instead we create a /builder/ sorted list, since
# the builder is the more interesting person involved.
#
# Hopefully soon we'll have package aliases that we can mail
# thus we'll be able to send mail to those that are interested in given packages about upgrade path problems.
# For now we just print out something suitable to be sent through /bin/mail


import koji
import rpm
import sys
import smtplib
import datetime

fromaddr = 'buildsys@fedoraproject.org'
toaddr = 'fedora-devel-list@fedoraproject.org'
domain = '@fedoraproject.org'
smtpserver = 'localhost'

def usage():
    print """
    check-upgrade-paths.py tag1 tag2 [tag3 tag4]
    tags must be in ascending order, f8-gold dist-f8-updates dist-f8-updates-testing dist-f9-updates ...
    """

def compare(pkgA, pkgB):
    pkgdictA = koji.parse_NVR(pkgA)
    pkgdictB = koji.parse_NVR(pkgB)

    rc = rpm.labelCompare((pkgdictA['epoch'], pkgdictA['version'], pkgdictA['release']),
                         (pkgdictB['epoch'], pkgdictB['version'], pkgdictB['release']))

    return rc

def buildToNvr(build):
    if build['epoch']:
        return '%s:%s' % (build['epoch'], build['nvr'])
    else:
        return build['nvr']

def genPackageMail(builder, package):
    """Send a mail to the package watchers and the builder regarding the break.
       Mail is set out once per broken package."""

    # This relies on the package-owner alias sets
    addresses = [builder, '%s-owner']
    msg = """From: %s
To: %s
Subject: Broken upgrade path(s) detected for: %s

""" % (fromaddr, ','.join([addy+domain for addy in addresses]), package)

    for path in badpaths[pkg]:
        msg += "    %s\n" % path

    msg += "\n\nPlease fix the(se) issue(s) as soon as possible.\n"

    msg += "\n---------------\n"
    msg += "This report generated by Fedora Release Engineering, using http://git.fedorahosted.org/git/?p=releng;a=blob;f=scripts/check-upgrade-paths.py;hb=HEAD"

    try:
        server = smtplib.SMTP(smtpserver)
        server.set_debuglevel(1)
        server.sendmail(fromaddr, [addy+domain for addy in addresses], msg)
    except:
        print 'sending mail failed'

if len(sys.argv) > 1 and sys.argv[1] in ['-h', '--help', '-help', '--usage']:
    usage()
    sys.exit(0)
elif len(sys.argv) < 3:
    usage()
    sys.exit(1)
else:
    tags = sys.argv[1:]

kojisession = koji.ClientSession('http://koji.fedoraproject.org/kojihub')
tagdict = {}
pkgdict = {}
badpaths = {}
badpathsbybuilder = {}

# Use multicall to get the latest tagged builds from each tag
kojisession.multicall = True
for tag in tags:
    kojisession.listTagged(tag, latest=True)

results = kojisession.multiCall()

# Stuff the results into a dict of tag to builds
for tag, result in zip(tags, results):
    tagdict[tag] = result[0]

# Populate the pkgdict with a set of package names to tags to nvrs
for tag in tags:
    for pkg in tagdict[tag]:
        if not pkgdict.has_key(pkg['name']):
            pkgdict[pkg['name']] = {}
        pkgdict[pkg['name']][tag] = {'nvr': buildToNvr(pkg), 'builder': pkg['owner_name']}

# Loop through the packages, compare e:n-v-rs from the first tag upwards
# then proceed to the next given tag and again compare upwards
for pkg in pkgdict:
    for tag in tags[:-1]: # Skip the last tag since there is nothing to compare it to
        for nexttag in tags[tags.index(tag)+1:]: # Compare from current tag up
            if pkgdict[pkg].has_key(tag):
                if pkgdict[pkg].has_key(nexttag): # only compare if the next tag knows about this package
                    rc = compare(pkgdict[pkg][tag]['nvr'], pkgdict[pkg][nexttag]['nvr'])
                    if rc <= 0:
                        continue
                    if rc > 0:
                        # We've got something broken here.
                        if not badpaths.has_key(pkg):
                            badpaths[pkg] = []
                        if not badpathsbybuilder.has_key(pkgdict[pkg][tag]['builder']):
                            badpathsbybuilder[pkgdict[pkg][tag]['builder']] = {}
                        if not badpathsbybuilder[pkgdict[pkg][tag]['builder']].has_key(pkg):
                            badpathsbybuilder[pkgdict[pkg][tag]['builder']][pkg] = []
                        badpaths[pkg].append('%s > %s (%s %s)' % (tag, nexttag, pkgdict[pkg][tag]['nvr'], pkgdict[pkg][nexttag]['nvr']))
                        badpathsbybuilder[pkgdict[pkg][tag]['builder']][pkg].append('%s > %s (%s %s)' % (tag, nexttag, pkgdict[pkg][tag]['nvr'], pkgdict[pkg][nexttag]['nvr']))

# TODO We should print ownership here
print """Broken upgrade path report for tags %s""" % tags
print "\n"
pkgs = badpaths.keys()
pkgs.sort()
for pkg in pkgs:
    print "%s:" % pkg
    for path in badpaths[pkg]:
        print "    %s" % path
    print "\n"

print "-----------------------\n"
print "Broken paths by builder:\n"
builders = badpathsbybuilder.keys()
builders.sort()
for builder in builders:
    print "%s:" % builder
    pkgs = badpathsbybuilder[builder].keys()
    pkgs.sort()
    for pkg in pkgs:
        print "    %s:" % pkg
        for path in badpathsbybuilder[builder][pkg]:
            print "        %s" % path
    print "\n"

print "---------------"
print "This report generated by Fedora Release Engineering, using http://git.fedorahosted.org/git/?p=releng;a=blob;f=scripts/check-upgrade-paths.py;hb=HEAD"