Merge lp:~corey.bryant/ubuntu-reports/upstream into lp:ubuntu-reports

Proposed by Corey Bryant
Status: Merged
Merged at revision: 137
Proposed branch: lp:~corey.bryant/ubuntu-reports/upstream
Merge into: lp:ubuntu-reports
Diff against target: 342 lines (+211/-10)
4 files modified
server/cloud-archive/version-tracker/README.txt (+9/-0)
server/cloud-archive/version-tracker/ca-versions.py (+21/-7)
server/cloud-archive/version-tracker/common.py (+4/-0)
server/cloud-archive/version-tracker/gather-versions.py (+177/-3)
To merge this branch: bzr merge lp:~corey.bryant/ubuntu-reports/upstream
Reviewer Review Type Date Requested Status
Ubuntu Reports Dev Team Pending
Review via email: mp+302940@code.launchpad.net

Description of the change

This tool provides an easier way to track upstream releases vs watching mailing lists, etc. It's similar to the current cloud archive reports.

We may want to keep these reports behind the firewall. Currently I'm publishing reports here:
https://private-fileshare.canonical.com/~coreycb/ca_upstream_versions_newton.html
https://private-fileshare.canonical.com/~coreycb/ca_upstream_versions_mitaka.html
https://private-fileshare.canonical.com/~coreycb/ca_upstream_versions_liberty.html
https://private-fileshare.canonical.com/~coreycb/ca_upstream_versions_kilo.html

To post a comment you must log in.
134. By Brian Murray

switch incoming release tags

135. By Brian Murray

be smarter about which duplicate bugs we check who the reporter is, handle an inaccessible bug

136. By Corey Bryant

Add cloud-archive upstream version-tracker

Add support for tracking the latest upstream versions against current
package versions. The versions are normalized to enable version
comparison and the package list is trimmed to include OpenStack
deliverables only.

For more details see: server/cloud-archive/version-tracker/README.txt

137. By Corey Bryant

Add ocata for UCA reports

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'server/cloud-archive/version-tracker/README.txt'
--- server/cloud-archive/version-tracker/README.txt 2013-12-03 20:52:26 +0000
+++ server/cloud-archive/version-tracker/README.txt 2016-10-19 14:41:11 +0000
@@ -9,6 +9,15 @@
9 ./gather-versions.py "--output_dir=$datadir" "$ca_item"9 ./gather-versions.py "--output_dir=$datadir" "$ca_item"
10 ./ca-versions.py "--json_dir=$datadir" --os_release="$ca_item"10 ./ca-versions.py "--json_dir=$datadir" --os_release="$ca_item"
1111
12Below is an example that includes upstream version details for Ocata, where the
13versions are normalized and packages trimmed down to OpenStack deliverables only:
14 datadir="$PWD/data";
15 ca_item="ocata"
16
17 mkdir "$datadir"
18 ./gather-versions.py "--output_dir=$datadir" "$ca_item" --upstream
19 ./ca-versions.py "--json_dir=$datadir" --os_release="$ca_item" --upstream
20
12After doing so, output is in 'ca_versions_${ca_item}.html'21After doing so, output is in 'ca_versions_${ca_item}.html'
1322
14 # output is in ca_versions_${ca_item}.html23 # output is in ca_versions_${ca_item}.html
1524
=== modified file 'server/cloud-archive/version-tracker/ca-versions.py'
--- server/cloud-archive/version-tracker/ca-versions.py 2014-07-22 13:15:44 +0000
+++ server/cloud-archive/version-tracker/ca-versions.py 2016-10-19 14:41:11 +0000
@@ -59,10 +59,13 @@
59 return rc == 059 return rc == 0
6060
6161
62def load_sets(json_dir, release, sets=None):62def load_sets(json_dir, release, sets=None, include_upstream=False):
63 # this list determines which pockets to display, and in what order.63 # this list determines which pockets to display, and in what order.
64 if sets is None:64 if sets is None:
65 sets = ['ubuntu', 'staging', 'proposed', 'updates']65 if include_upstream:
66 sets = ['ubuntu', 'staging', 'proposed', 'updates', 'upstream']
67 else:
68 sets = ['ubuntu', 'staging', 'proposed', 'updates']
66 i = 169 i = 1
67 package_sets = {}70 package_sets = {}
68 for s in sets:71 for s in sets:
@@ -75,8 +78,12 @@
75 i += 178 i += 1
76 return package_sets79 return package_sets
7780
78def render_table(package_sets, release):81def render_table(package_sets, opts):
79 table = '<html><body><center>Ubuntu Cloud Archive Version Tracker: '82 release = opts.os_release
83 if opts.include_upstream:
84 table = '<html><body><center>Ubuntu Cloud Archive Upstream Version Tracker: '
85 else:
86 table = '<html><body><center>Ubuntu Cloud Archive Version Tracker: '
80 if release == 'cloud-tools':87 if release == 'cloud-tools':
81 table += '<b>Cloud Tools</b><br>'88 table += '<b>Cloud Tools</b><br>'
82 vers_suffix = '~ctools'89 vers_suffix = '~ctools'
@@ -191,6 +198,9 @@
191 action='store_true', default=False,198 action='store_true', default=False,
192 help='Ensure Ubuntu pockets do not contain newer '199 help='Ensure Ubuntu pockets do not contain newer '
193 'packages than what is at least in CA staging.')200 'packages than what is at least in CA staging.')
201parser.add_option('-u', '--upstream', dest='include_upstream',
202 action='store_true', default=False,
203 help='Include upstream version column in output.')
194(opts, args) = parser.parse_args()204(opts, args) = parser.parse_args()
195205
196if not os.path.exists(opts.json_dir):206if not os.path.exists(opts.json_dir):
@@ -203,7 +213,8 @@
203 if f['name'] == "staging":213 if f['name'] == "staging":
204 f['header'] = "next"214 f['header'] = "next"
205else:215else:
206 sets = load_sets(opts.json_dir, opts.os_release)216 sets = load_sets(opts.json_dir, opts.os_release,
217 include_upstream=opts.include_upstream)
207218
208if opts.check_ubuntu:219if opts.check_ubuntu:
209 # ensure there are no newer packages in the ubuntu release than in220 # ensure there are no newer packages in the ubuntu release than in
@@ -241,11 +252,14 @@
241252
242253
243if not opts.out_file:254if not opts.out_file:
244 out_file = 'ca_versions_%s.html' % opts.os_release255 if opts.include_upstream:
256 out_file = 'ca_upstream_versions_%s.html' % opts.os_release
257 else:
258 out_file = 'ca_versions_%s.html' % opts.os_release
245else:259else:
246 out_file = opts.out_file260 out_file = opts.out_file
247261
248html = render_table(sets, opts.os_release)262html = render_table(sets, opts)
249out = open(out_file, 'w')263out = open(out_file, 'w')
250out.write(html)264out.write(html)
251out.close()265out.close()
252266
=== modified file 'server/cloud-archive/version-tracker/common.py'
--- server/cloud-archive/version-tracker/common.py 2016-05-31 08:45:05 +0000
+++ server/cloud-archive/version-tracker/common.py 2016-10-19 14:41:11 +0000
@@ -44,6 +44,10 @@
44 'ubuntu_stable': 'xenial',44 'ubuntu_stable': 'xenial',
45 'ubuntu_dev': 'yakkety',45 'ubuntu_dev': 'yakkety',
46 },46 },
47 'ocata': {
48 'ubuntu_stable': 'xenial',
49 'ubuntu_dev': 'zesty',
50 },
47 'cloud-tools': {51 'cloud-tools': {
48 'ubuntu_stable': CURRENT_UBUNTU_STABLE,52 'ubuntu_stable': CURRENT_UBUNTU_STABLE,
49 'ubuntu_dev': 'trusty',53 'ubuntu_dev': 'trusty',
5054
=== modified file 'server/cloud-archive/version-tracker/gather-versions.py'
--- server/cloud-archive/version-tracker/gather-versions.py 2014-03-17 10:51:33 +0000
+++ server/cloud-archive/version-tracker/gather-versions.py 2016-10-19 14:41:11 +0000
@@ -14,19 +14,26 @@
14# The package set to be tracked is determined by what currently exists in the14# The package set to be tracked is determined by what currently exists in the
15# staging PPA.15# staging PPA.
16#16#
17# Optionally include upstream version details, where versions are normalized
18# and resulting packages trimmed down to OpenStack deliverables only.
19#
17# Version info is dumped to JSON files (one for each repo) to a specified20# Version info is dumped to JSON files (one for each repo) to a specified
18# directory ($HOME/.ca-versions) by default. These can be used to generate21# directory ($HOME/.ca-versions) by default. These can be used to generate
19# a HTML report using the ca-versions.py script.22# a HTML report using the ca-versions.py script.
2023
21import common24import common
25import git
22import json26import json
23import os27import os
28import re
24import sys29import sys
25import logging30import logging
26import httplib231import httplib2
27import optparse32import optparse
28import gzip33import gzip
34import shutil
29import StringIO35import StringIO
36import yaml
3037
31from launchpadlib.launchpad import Launchpad38from launchpadlib.launchpad import Launchpad
3239
@@ -37,6 +44,9 @@
37parser.add_option('-o', '--output_dir', action='store', dest='out_dir',44parser.add_option('-o', '--output_dir', action='store', dest='out_dir',
38 default=os.path.join(os.getenv('HOME'), '.ca-versions'),45 default=os.path.join(os.getenv('HOME'), '.ca-versions'),
39 help='Directory to dump JSON (Default: $HOME/.ca-versions)')46 help='Directory to dump JSON (Default: $HOME/.ca-versions)')
47parser.add_option('-u', '--upstream', dest='include_upstream',
48 action='store_true', default=False,
49 help='Get upstream versions and normalize/trim results.')
40(opts, args) = parser.parse_args()50(opts, args) = parser.parse_args()
4151
42if len(args) == 0:52if len(args) == 0:
@@ -192,6 +202,122 @@
192 out[p] = vers202 out[p] = vers
193 return out203 return out
194204
205def normalize_version(version):
206 '''
207 Convert a package version into its upstream version format, in order to
208 enable version comparison.
209 '''
210 normalize_regular_expressions = {
211 "^\d+:": "",
212 "\-.*$": "",
213 "\+dfsg.*$": "",
214 "\~b1": ".0b1",
215 "\~b2": ".0b2",
216 "\~b3": ".0b3",
217 "\~rc1": ".0rc1",
218 "\~rc2": ".0rc2",
219 "\~rc3": ".0rc3",
220 "\~rc4": ".0rc4",
221 "\~cloud.*$": "",
222 "ubuntu.*$": "",
223 }
224 normalized_version = version
225 if version:
226 for pattern, replacement in normalize_regular_expressions.iteritems():
227 normalized_version = re.sub(r"{}".format(pattern),
228 replacement,
229 normalized_version)
230 return normalized_version
231
232# Map of ubuntu package names to their corresponding upstream project names.
233# Most mappings are programatically determined in query_release_deliverables.
234# This mapping is just for the tricky names.
235PKG_TO_UPSTREAM_MAP = {
236 'openstack-trove': 'trove',
237 'oslo-sphinx': 'oslosphinx',
238 'python-django-openstack-auth': 'django_openstack_auth',
239 'python-keystoneauth1': 'keystoneauth',
240}
241
242def _clone_repo(url, out_dir, sub_dir, branch=None):
243 '''
244 Clone a git repo.
245 '''
246 dest = os.path.join(out_dir, sub_dir)
247 shutil.rmtree(dest, ignore_errors=True)
248 if branch:
249 git.Repo.clone_from(url, dest, branch=branch)
250 else:
251 git.Repo.clone_from(url, dest)
252 return dest
253
254def query_release_deliverables(pkgs, release, out_dir):
255 '''
256 Loop through pkgs and get corresponding upstream versions from release
257 repo's deliverables files.
258 '''
259 dest = _clone_repo('git://github.com/openstack/releases',
260 out_dir, 'releases')
261 release_dir = os.path.join(dest, 'deliverables', release)
262 release_files = os.listdir(release_dir)
263
264 branch = 'stable/{}'.format(release)
265 try:
266 dest = _clone_repo('git://github.com/openstack/requirements',
267 out_dir, 'requirements', branch)
268 except git.exc.GitCommandError:
269 # if stable branch not found, clone master branch
270 branch = 'master'
271 dest = _clone_repo('git://github.com/openstack/requirements',
272 out_dir, 'requirements', branch)
273 uc_file = os.path.join(dest, 'upper-constraints.txt')
274
275 upstream_versions = {}
276 for pkg_name in pkgs:
277 # generate upstream project name based on package name
278 upstream_name = pkg_name
279 if 'client' not in pkg_name:
280 upstream_name = re.sub(r'python-', '', pkg_name)
281 if pkg_name in PKG_TO_UPSTREAM_MAP.keys():
282 upstream_name = PKG_TO_UPSTREAM_MAP[pkg_name]
283
284 release_file = "{}.yaml".format(upstream_name)
285 if release_file not in release_files:
286 continue
287
288 # Get latest version from project's release deliverable file.
289 # Note: some projects exist in release deliverables but not in
290 # upper-constraints.
291 stream = file(os.path.join(release_dir, release_file), 'r')
292 project_yaml = yaml.load(stream)
293 upstream_vers = project_yaml['releases'][-1]['version']
294
295 # If version exists in upper-constraints, use that instead. Release
296 # deliverables files can get updated before upper-constraints.
297 stream = file(uc_file, 'r')
298 for line in stream:
299 lline = line.lower().rstrip()
300 if upstream_name == re.sub(r'===.*$', '', lline):
301 upstream_vers = re.sub(r'^.*===', '', lline)
302
303 upstream_versions[pkg_name] = upstream_vers
304
305 return upstream_versions
306
307def trim_packages_file(filename, packages):
308 '''
309 Trim the file to only include packages that are in the packages dict.
310 '''
311 f = open(filename, 'r')
312
313 pkgs = json.loads(f.read())
314 for k in pkgs.keys():
315 if k not in packages.keys():
316 del pkgs[k]
317
318 f = open(filename, 'w')
319 f.write(json.dumps(pkgs))
320
195stable_rel = "precise"321stable_rel = "precise"
196322
197stable_rel = common.VERSION_MAP[os_release]['ubuntu_stable']323stable_rel = common.VERSION_MAP[os_release]['ubuntu_stable']
@@ -212,7 +338,13 @@
212staging_versions = query_ca_ppa(ppa=staging_ppa,338staging_versions = query_ca_ppa(ppa=staging_ppa,
213 release=stable_rel)339 release=stable_rel)
214f = open(os.path.join(opts.out_dir, '%s_staging_versions' % os_release), 'w+')340f = open(os.path.join(opts.out_dir, '%s_staging_versions' % os_release), 'w+')
215f.write(json.dumps(staging_versions))341if opts.include_upstream:
342 staging_versions_normalized = {}
343 for pkg_name, version in staging_versions.iteritems():
344 staging_versions_normalized[pkg_name] = normalize_version(version[0])
345 f.write(json.dumps(staging_versions_normalized))
346else:
347 f.write(json.dumps(staging_versions))
216f.close()348f.close()
217349
218# with the names of the packages published to the staging ppa, we can determine350# with the names of the packages published to the staging ppa, we can determine
@@ -220,7 +352,13 @@
220logging.info("Querying Ubuntu versions for all packages.")352logging.info("Querying Ubuntu versions for all packages.")
221ubuntu_versions = query_ubuntu(staging_versions.keys(), dev_rel)353ubuntu_versions = query_ubuntu(staging_versions.keys(), dev_rel)
222f = open(os.path.join(opts.out_dir, "%s_ubuntu_versions" % os_release), 'w+')354f = open(os.path.join(opts.out_dir, "%s_ubuntu_versions" % os_release), 'w+')
223f.write(json.dumps(ubuntu_versions))355if opts.include_upstream:
356 ubuntu_versions_normalized = {}
357 for pkg_name, version in ubuntu_versions.iteritems():
358 ubuntu_versions_normalized[pkg_name] = normalize_version(version)
359 f.write(json.dumps(ubuntu_versions_normalized))
360else:
361 f.write(json.dumps(ubuntu_versions))
224f.close()362f.close()
225363
226for p in pockets:364for p in pockets:
@@ -228,4 +366,40 @@
228 versions = versions_from_packages(os_release, p, staging_versions.keys())366 versions = versions_from_packages(os_release, p, staging_versions.keys())
229 out = os.path.join(opts.out_dir, '%s_%s_versions' % (os_release, p))367 out = os.path.join(opts.out_dir, '%s_%s_versions' % (os_release, p))
230 f = open(out, 'w+')368 f = open(out, 'w+')
231 f.write(json.dumps(versions))369 versions_normalized = {}
370 if opts.include_upstream:
371 for pkg_name, version in versions.iteritems():
372 normalized_version = version
373 if version:
374 normalized_version = normalize_version(version)
375 versions_normalized[pkg_name] = normalized_version
376 f.write(json.dumps(versions_normalized))
377 else:
378 f.write(json.dumps(versions))
379
380if opts.include_upstream:
381 # with the names of the packages published to the staging ppa, we can determine
382 # the upstream versions we need to track.
383 logging.info("Querying upstream versions for packages from release deliverables repo.")
384 upstream_versions = query_release_deliverables(staging_versions,
385 os_release, opts.out_dir)
386
387 # trim the results to only include packages that we've detected upstream
388 # versions for
389 for k in upstream_versions.keys():
390 if upstream_versions[k] == None:
391 del upstream_versions[k]
392
393 out = os.path.join(opts.out_dir, '%s_upstream_versions' % os_release)
394 f = open(out, 'w')
395 f.write(json.dumps(upstream_versions))
396
397 out = os.path.join(opts.out_dir, '%s_staging_versions' % os_release)
398 trim_packages_file(out, upstream_versions)
399
400 out = os.path.join(opts.out_dir, '%s_ubuntu_versions' % os_release)
401 trim_packages_file(out, upstream_versions)
402
403 for p in pockets:
404 out = os.path.join(opts.out_dir, '%s_%s_versions' % (os_release, p))
405 trim_packages_file(out, upstream_versions)

Subscribers

People subscribed via source and target branches