Merge ubuntu-archive-tools:sru-review-sync-diffs into ubuntu-archive-tools:main

Proposed by Łukasz Zemczak
Status: Merged
Merged at revision: a70796d33394bbcb02b1475513a9ac55c36e18df
Proposed branch: ubuntu-archive-tools:sru-review-sync-diffs
Merge into: ubuntu-archive-tools:main
Diff against target: 196 lines (+84/-37)
1 file modified
sru-review (+84/-37)
Reviewer Review Type Date Requested Status
Steve Langasek Approve
Review via email: mp+410047@code.launchpad.net

Commit message

sru-review: Support sync uploads in the queue by generating their debdiffs locally

Description of the change

This is an initial try on getting proper support for SRU reviewing sync uploads. Sync uploads are troublesome as they generally come with no debdiffs for reviewing. Everytime this happens, SRU members need to manually fetch and debdiff those packages.

This MP automates that process. Basically it pulls the sources for both the new upload and the latest upload in the target archive/series and does a dumb debdiff on those. We could probably optimize this a bit, but that's a good working start point for sure.

To post a comment you must log in.
Revision history for this message
Steve Langasek (vorlon) :
review: Needs Fixing
Revision history for this message
Łukasz Zemczak (sil2100) wrote :

Thank you for the review, Steve!

Ok, fixed the typo + a whitespace thing. As for your inline comment about directory cleanup: no manual cleanup should be needed as the packages are extracted into a temporary directory created using the TemporaryDirectory() context manager. This should ensure that when we go out of context (or the tool closes early), the temporary directory is auto-removed with all its contents. So cleanup is automatic!

Revision history for this message
Steve Langasek (vorlon) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/sru-review b/sru-review
2index e9e1493..0f55d5d 100755
3--- a/sru-review
4+++ b/sru-review
5@@ -122,10 +122,27 @@ def parse_changes(changes_url):
6 return info
7
8
9+def fetch_source(pub, dest_dir):
10+ '''Downloads source files of a given source publishing.
11+
12+ Return path to the downloaded source's .dsc file.'''
13+ sources = pub.sourceFileUrls()
14+
15+ dsc_file = None
16+ for src in sources:
17+ basename = os.path.basename(src)
18+ dst = os.path.join(dest_dir, basename)
19+ if dst.endswith('.dsc'):
20+ dsc_file = dst
21+ urlretrieve(src, dst)
22+
23+ return dsc_file
24+
25+
26 def from_queue(options, archive, sourcepkg, series, version=None):
27 '''Get package_upload from LP and debdiff from queue page.
28
29- Return (package_upload, changes URL, debdiff URL) tuple.
30+ Return (package_upload, changes URL, debdiff contents) tuple.
31 '''
32 queues = {'New': 0, 'Unapproved': 1, 'Rejected': 4}
33 queue = options.queue.title()
34@@ -147,55 +164,87 @@ def from_queue(options, archive, sourcepkg, series, version=None):
35 upload = uploads[0]
36
37 if upload.contains_copy:
38- archive = upload.copy_source_archive
39- pubs = archive.getPublishedSources(
40+ source_archive = upload.copy_source_archive
41+ pubs = source_archive.getPublishedSources(
42 exact_match=True, source_name=upload.package_name,
43 version=upload.package_version)
44 if pubs:
45 changes_url = pubs[0].changesFileUrl()
46 else:
47 print("ERROR: Can't find source package %s %s in %s" %
48- (upload.package_name, upload.package_version,
49+ (source_archive.package_name, upload.package_version,
50 archive.web_link),
51 file=sys.stderr)
52 sys.exit(1)
53 else:
54 changes_url = upload.changes_file_url
55
56+ debdiff = None
57 if options.diff:
58- oops_re = re.compile('class="oopsid">(OOPS[a-zA-Z0-9-]+)<')
59- if version:
60- re_version = re.escape(version)
61+ if upload.contains_copy:
62+ # The upload is a sync - we need to create the debdiff ourselves
63+ print('This upload is a sync, no autogenerated debdiff present.',
64+ file=sys.stderr)
65+ print('''Do you want to generate the debdiff locally? [Yn]''',
66+ end="")
67+ sys.stdout.flush()
68+ response = sys.stdin.readline()
69+ if not response.strip().lower().startswith('n'):
70+ with tempfile.TemporaryDirectory() as tempdir:
71+ source_archive = upload.copy_source_archive
72+ pubs = source_archive.getPublishedSources(
73+ exact_match=True, source_name=upload.package_name,
74+ version=upload.package_version)
75+ sru_dsc_file = fetch_source(pubs[0], tempdir)
76+
77+ pubs = archive.getPublishedSources(
78+ exact_match=True, source_name=upload.package_name,
79+ order_by_date=True, status='Published',
80+ distro_series=series)
81+ cur_dsc_file = fetch_source(pubs[0], tempdir)
82+
83+ ret = subprocess.run(
84+ ["debdiff", cur_dsc_file, sru_dsc_file],
85+ stdout=subprocess.PIPE,
86+ stderr=subprocess.DEVNULL)
87+
88+ # ...not a filelike object, but should work
89+ debdiff = ret.stdout.splitlines(keepends=True)
90 else:
91- re_version = '[^_"]+'
92- debdiff_re = re.compile(
93- 'href="(http://launchpadlibrarian.net/'
94- '\d+/%s_[^"_]+_%s\.diff\.gz)">\s*diff from' %
95- (re.escape(sourcepkg), re_version))
96-
97- queue_html = urlopen(queue_url).read().decode('utf-8')
98+ oops_re = re.compile('class="oopsid">(OOPS[a-zA-Z0-9-]+)<')
99+ if version:
100+ re_version = re.escape(version)
101+ else:
102+ re_version = '[^_"]+'
103+ debdiff_re = re.compile(
104+ 'href="(http://launchpadlibrarian.net/'
105+ '\d+/%s_[^"_]+_%s\.diff\.gz)">\s*diff from' %
106+ (re.escape(sourcepkg), re_version))
107+
108+ queue_html = urlopen(queue_url).read().decode('utf-8')
109+
110+ m = oops_re.search(queue_html)
111+ if m:
112+ print('ERROR: Launchpad failure:', m.group(1), file=sys.stderr)
113+ sys.exit(1)
114
115- m = oops_re.search(queue_html)
116- if m:
117- print('ERROR: Launchpad failure:', m.group(1), file=sys.stderr)
118- sys.exit(1)
119+ m = debdiff_re.search(queue_html)
120+ if not m:
121+ print('ERROR: queue does not have a debdiff', file=sys.stderr)
122+ sys.exit(1)
123+ debdiff_url = m.group(1)
124+ #print('debdiff URL:', debdiff_url, file=sys.stderr)
125
126- m = debdiff_re.search(queue_html)
127- if not m:
128- print('ERROR: queue does not have a debdiff', file=sys.stderr)
129- sys.exit(1)
130- debdiff_url = m.group(1)
131- #print('debdiff URL:', debdiff_url, file=sys.stderr)
132- else:
133- debdiff_url = None
134+ with tempfile.NamedTemporaryFile() as f:
135+ debdiff = gzip.open(urlretrieve(debdiff_url, f.name)[0])
136
137- return (upload, changes_url, debdiff_url)
138+ return (upload, changes_url, debdiff)
139
140
141 def from_ppa(options, sourcepkg, user, ppaname):
142 '''Get .changes and debdiff from a PPA.
143
144- Return (changes URL, debdiff URL) pair.
145+ Return (changes URL, debdiff contents) pair.
146 '''
147 changes_re = re.compile(
148 'href="(https://launchpad.net/[^ "]+/%s_[^"]+_source.changes)"' %
149@@ -243,11 +292,12 @@ def from_ppa(options, sourcepkg, user, ppaname):
150 # print('ERROR: PPA does not have a debdiff', file=sys.stderr)
151 # sys.exit(1)
152 # debdiff_url = m.group(1)
153+ # # TODO: we need to download the debdiff now
154 # #print('debdiff URL:', debdiff_url, file=sys.stderr)
155 #else:
156- debdiff_url = None
157+ debdiff = None
158
159- return (changes_url, debdiff_url)
160+ return (changes_url, debdiff)
161
162
163 def reject_comment(launchpad, num, package, release, reason):
164@@ -284,9 +334,9 @@ if __name__ == '__main__':
165
166 if opts.ppa:
167 (user, ppaname) = opts.ppa.split('/', 1)
168- (changes_url, debdiff_url) = from_ppa(opts, sourcepkg, user, ppaname)
169+ (changes_url, debdiff) = from_ppa(opts, sourcepkg, user, ppaname)
170 else:
171- (upload, changes_url, debdiff_url) = from_queue(
172+ (upload, changes_url, debdiff) = from_queue(
173 opts, archive, sourcepkg, series, version)
174
175 # Check for existing version in proposed
176@@ -322,11 +372,7 @@ if __name__ == '__main__':
177 print('''Exiting''')
178 sys.exit(1)
179
180- debdiff = None
181- if debdiff_url:
182- with tempfile.NamedTemporaryFile() as f:
183- debdiff = gzip.open(urlretrieve(debdiff_url, f.name)[0])
184- elif opts.diff:
185+ if opts.diff and not debdiff:
186 print('No debdiff available')
187
188 # parse changes and open bugs first since we are using subprocess
189@@ -365,6 +411,7 @@ if __name__ == '__main__':
190 for line in debdiff:
191 tfile.write(line)
192 tfile.flush()
193+ debdiff = None
194 if opts.diffstat:
195 combinedfile = resources.enter_context(
196 tempfile.NamedTemporaryFile())

Subscribers

People subscribed via source and target branches