Merge lp:~cjwatson/launchpad/git-version-info into lp:launchpad

Proposed by Colin Watson
Status: Merged
Merged at revision: 18197
Proposed branch: lp:~cjwatson/launchpad/git-version-info
Merge into: lp:launchpad
Diff against target: 992 lines (+168/-245)
24 files modified
.bzrignore (+2/-1)
Makefile (+7/-7)
database/schema/upgrade.py (+33/-20)
lib/lp/app/browser/folder.py (+3/-3)
lib/lp/app/templates/base-layout-macros.pt (+5/-6)
lib/lp/app/templates/base-layout.pt (+4/-3)
lib/lp/app/templates/oops.pt (+2/-2)
lib/lp/app/tests/test_versioninfo.py (+5/-5)
lib/lp/app/versioninfo.py (+20/-12)
lib/lp/services/mail/sendmail.py (+2/-2)
lib/lp/services/webapp/errorlog.py (+4/-38)
lib/lp/services/webapp/errorlog.zcml (+1/-7)
lib/lp/services/webapp/interfaces.py (+0/-18)
lib/lp/services/webapp/publisher.py (+2/-2)
lib/lp/services/webapp/servers.py (+1/-1)
lib/lp/services/webapp/tests/test_errorlog.py (+1/-78)
lib/lp/services/webapp/tests/test_servers.py (+1/-1)
lib/lp/services/webhooks/model.py (+2/-2)
lib/lp/services/webhooks/tests/test_job.py (+6/-4)
lib/lp/services/webservice/configuration.py (+2/-2)
lib/lp/testing/yuixhr.py (+7/-7)
lib/lp/translations/utilities/gettext_po_parser.py (+4/-4)
scripts/update-version-info.sh (+42/-15)
utilities/create-lp-wadl-and-apidoc.py (+12/-5)
To merge this branch: bzr merge lp:~cjwatson/launchpad/git-version-info
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+305701@code.launchpad.net

Commit message

Handle running from a Git working tree.

Description of the change

Handle running from a Git working tree.

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2013-04-15 02:36:07 +0000
3+++ .bzrignore 2016-09-19 14:06:13 +0000
4@@ -1,5 +1,6 @@
5+*.pyc
6 .tags
7-bzr-version-info.py
8+version-info.py
9 logs/*
10 +*
11 sourcecode/*
12
13=== added symlink '.gitignore'
14=== target is u'.bzrignore'
15=== modified file 'Makefile'
16--- Makefile 2015-09-08 02:31:49 +0000
17+++ Makefile 2016-09-19 14:06:13 +0000
18@@ -35,7 +35,7 @@
19
20 CONVOY_ROOT?=/srv/launchpad.dev/convoy
21
22-BZR_VERSION_INFO = bzr-version-info.py
23+VERSION_INFO = version-info.py
24
25 APIDOC_DIR = lib/canonical/launchpad/apidoc
26 APIDOC_TMPDIR = $(APIDOC_DIR).tmp/
27@@ -73,7 +73,7 @@
28 hosted_branches: $(PY)
29 $(PY) ./utilities/make-dummy-hosted-branches
30
31-$(API_INDEX): $(BZR_VERSION_INFO) $(PY)
32+$(API_INDEX): $(VERSION_INFO) $(PY)
33 $(RM) -r $(APIDOC_DIR) $(APIDOC_DIR).tmp
34 mkdir -p $(APIDOC_DIR).tmp
35 LPCONFIG=$(LPCONFIG) $(PY) ./utilities/create-lp-wadl-and-apidoc.py \
36@@ -238,7 +238,7 @@
37
38 $(subst $(PY),,$(BUILDOUT_BIN)): $(PY)
39
40-compile: $(PY) $(BZR_VERSION_INFO)
41+compile: $(PY) $(VERSION_INFO)
42 ${SHHH} $(MAKE) -C sourcecode build PYTHON=${PYTHON} \
43 LPCONFIG=${LPCONFIG}
44 ${SHHH} LPCONFIG=${LPCONFIG} ${PY} -t buildmailman.py
45@@ -295,10 +295,10 @@
46 stop_librarian:
47 bin/killservice librarian
48
49-$(BZR_VERSION_INFO):
50- scripts/update-bzr-version-info.sh
51+$(VERSION_INFO):
52+ scripts/update-version-info.sh
53
54-support_files: $(API_INDEX) $(BZR_VERSION_INFO)
55+support_files: $(API_INDEX) $(VERSION_INFO)
56
57 # Intended for use on developer machines
58 start: inplace stop support_files initscript-start
59@@ -393,7 +393,7 @@
60 $(RM) -r $(APIDOC_DIR)
61 $(RM) -r $(APIDOC_DIR).tmp
62 $(RM) -r build
63- $(RM) $(BZR_VERSION_INFO)
64+ $(RM) $(VERSION_INFO)
65 $(RM) +config-overrides.zcml
66 $(RM) -r /var/tmp/builddmaster \
67 /var/tmp/bzrsync \
68
69=== modified file 'database/schema/upgrade.py'
70--- database/schema/upgrade.py 2014-08-29 01:34:04 +0000
71+++ database/schema/upgrade.py 2016-09-19 14:06:13 +0000
72@@ -1,6 +1,6 @@
73 #!/usr/bin/python -S
74 #
75-# Copyright 2009 Canonical Ltd. This software is licensed under the
76+# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
77 # GNU Affero General Public License version 3 (see the file LICENSE).
78
79 """
80@@ -15,6 +15,7 @@
81 from optparse import OptionParser
82 import os.path
83 import re
84+import subprocess
85 from textwrap import dedent
86
87 from bzrlib.branch import Branch
88@@ -31,7 +32,7 @@
89 )
90
91
92-SCHEMA_DIR = os.path.dirname(__file__)
93+SCHEMA_DIR = os.path.dirname(os.path.abspath(__file__))
94
95
96 def main(con=None):
97@@ -161,7 +162,7 @@
98
99 # Repair patch timestamps if necessary.
100 cur.execute(
101- FIX_PATCH_TIMES_POST_SQL % sqlvalues(*get_bzr_details()))
102+ FIX_PATCH_TIMES_POST_SQL % sqlvalues(*get_vcs_details()))
103
104 # Update comments.
105 apply_comments(con)
106@@ -245,26 +246,38 @@
107 log.debug("Skipping comments.sql per command line settings")
108
109
110-_bzr_details_cache = None
111-
112-
113-def get_bzr_details():
114- """Return (branch_nick, revno, revision_id) of this Bazaar branch.
115+_vcs_details_cache = None
116+
117+
118+def get_vcs_details():
119+ """Return (branch_nick, revno, revision_id) of this VCS branch.
120+
121+ If this is a Git branch, then revno will be None.
122
123 Returns (None, None, None) if the tree this code is running from
124- is not a Bazaar branch.
125+ is not a VCS branch.
126 """
127- global _bzr_details_cache
128- if _bzr_details_cache is None:
129- try:
130- branch = Branch.open_containing(SCHEMA_DIR)[0]
131- revno, revision_id = branch.last_revision_info()
132- branch_nick = branch.get_config().get_nickname()
133- except NotBranchError:
134- log.warning("Not a Bazaar branch - branch details unavailable")
135- revision_id, revno, branch_nick = None, None, None
136- _bzr_details_cache = (branch_nick, revno, revision_id)
137- return _bzr_details_cache
138+ global _vcs_details_cache
139+ if _vcs_details_cache is None:
140+ top = os.path.dirname(os.path.dirname(SCHEMA_DIR))
141+ if os.path.exists(os.path.join(top, ".git")):
142+ branch_nick = subprocess.check_output(
143+ ["git", "rev-parse", "--abbrev-ref", "HEAD"],
144+ universal_newlines=True).rstrip("\n")
145+ revno = None
146+ revision_id = subprocess.check_output(
147+ ["git", "rev-parse", "HEAD"],
148+ universal_newlines=True).rstrip("\n")
149+ else:
150+ try:
151+ branch = Branch.open_containing(SCHEMA_DIR)[0]
152+ revno, revision_id = branch.last_revision_info()
153+ branch_nick = branch.get_config().get_nickname()
154+ except NotBranchError:
155+ log.warning("Not a Bazaar branch - branch details unavailable")
156+ revision_id, revno, branch_nick = None, None, None
157+ _vcs_details_cache = (branch_nick, revno, revision_id)
158+ return _vcs_details_cache
159
160
161 if __name__ == '__main__':
162
163=== modified symlink 'lib/launchpadversioninfo.py'
164=== target changed u'../bzr-version-info.py' => u'../version-info.py'
165=== modified file 'lib/lp/app/browser/folder.py'
166--- lib/lp/app/browser/folder.py 2015-10-26 14:54:43 +0000
167+++ lib/lp/app/browser/folder.py 2016-09-19 14:06:13 +0000
168@@ -1,4 +1,4 @@
169-# Copyright 2009 Canonical Ltd. This software is licensed under the
170+# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
171 # GNU Affero General Public License version 3 (see the file LICENSE).
172
173 __metaclass__ = type
174@@ -43,7 +43,7 @@
175 """View that gives access to the files in a folder.
176
177 The URL to the folder can start with an optional path step like
178- /revNNN/ where NNN is one or more digits. This path step will
179+ /revNNN/ where NNN is one or more hex digits. This path step will
180 be ignored. It is useful for having a different path for
181 all resources being served, to ensure that we don't use cached
182 files in browsers.
183@@ -52,7 +52,7 @@
184 to True to change this.
185 """
186
187- rev_part_re = re.compile('rev\d+$')
188+ rev_part_re = re.compile('rev[0-9a-f]+$')
189
190 export_subdirectories = False
191
192
193=== modified file 'lib/lp/app/templates/base-layout-macros.pt'
194--- lib/lp/app/templates/base-layout-macros.pt 2016-03-14 00:45:42 +0000
195+++ lib/lp/app/templates/base-layout-macros.pt 2016-09-19 14:06:13 +0000
196@@ -35,8 +35,8 @@
197
198 <metal:load-javascript define-macro="load-javascript"
199 tal:define="
200- revno modules/lp.app.versioninfo/revno | string:unknown;
201- icingroot string:/+icing/rev${revno};
202+ revision modules/lp.app.versioninfo/revision | string:unknown;
203+ icingroot string:/+icing/rev${revision};
204 combo_url view/combo_url;
205 devmode modules/lp.services.config/config/devmode;
206 yui_version view/yui_version;
207@@ -109,7 +109,6 @@
208
209 <metal:page-javascript define-macro="page-javascript"
210 tal:define="
211- revno modules/lp.app.versioninfo/revno | string:unknown;
212 devmode modules/lp.services.config/config/devmode;">
213 <tal:comment replace="nothing">
214 Load and initialize the common script used by all pages.
215@@ -194,8 +193,8 @@
216
217 <metal:launchpad-stylesheet-3-0 define-macro="launchpad-stylesheet-3-0"
218 tal:define="
219- revno modules/lp.app.versioninfo/revno | string:unknown;
220- icingroot string:/+icing/rev${revno}">
221+ revision modules/lp.app.versioninfo/revision | string:unknown;
222+ icingroot string:/+icing/rev${revision}">
223 <tal:comment replace="nothing">
224 This macro loads a single css file containing all our stylesheets.
225 If you need to include a new css file here, add it to
226@@ -316,7 +315,7 @@
227 >System status</a>
228 <span id="lp-version">
229 &nbsp;&bull;&nbsp;
230- r<tal:revno replace="revno" />
231+ r<tal:display_revision replace="display_revision" />
232 <tal:devmode condition="devmode">devmode</tal:devmode>
233 <tal:demo condition="is_demo">demo site</tal:demo>
234 (<a href="https://dev.launchpad.net/"
235
236=== modified file 'lib/lp/app/templates/base-layout.pt'
237--- lib/lp/app/templates/base-layout.pt 2015-11-21 10:21:42 +0000
238+++ lib/lp/app/templates/base-layout.pt 2016-09-19 14:06:13 +0000
239@@ -3,13 +3,14 @@
240 xmlns:tal="http://xml.zope.org/namespaces/tal"
241 define-macro="master"
242 tal:define="
243- revno modules/lp.app.versioninfo/revno | string:unknown;
244+ revision modules/lp.app.versioninfo/revision | string:unknown;
245+ display_revision modules/lp.app.versioninfo/display_revision | string:unknown;
246 devmode modules/lp.services.config/config/devmode;
247 rooturl modules/lp.services.webapp.vhosts/allvhosts/configs/mainsite/rooturl;
248 is_demo modules/lp.services.config/config/launchpad/is_demo;
249 is_lpnet modules/lp.services.config/config/launchpad/is_lpnet;
250 site_message modules/lp.services.config/config/launchpad/site_message;
251- icingroot string:${rooturl}+icing/rev${revno};
252+ icingroot string:${rooturl}+icing/rev${revision};
253 features request/features;
254 feature_scopes request/features/scopes;
255 CONTEXTS python:{'template':template, 'context': context, 'view':view};
256@@ -182,7 +183,7 @@
257
258 Features: ${request/features/usedFlags}
259
260- r${revno}
261+ r${display_revision}
262
263 --&gt;" />
264 </tal:template>
265
266=== modified file 'lib/lp/app/templates/oops.pt'
267--- lib/lp/app/templates/oops.pt 2011-12-24 17:49:30 +0000
268+++ lib/lp/app/templates/oops.pt 2016-09-19 14:06:13 +0000
269@@ -6,8 +6,8 @@
270 >
271 <head
272 tal:define="
273- revno modules/lp.app.versioninfo/revno | string:unknown;
274- icingroot string:/+icing/rev${revno}"
275+ revision modules/lp.app.versioninfo/revision | string:unknown;
276+ icingroot string:/+icing/rev${revision}"
277 >
278 <title>Oops!</title>
279 <link
280
281=== modified file 'lib/lp/app/tests/test_versioninfo.py'
282--- lib/lp/app/tests/test_versioninfo.py 2012-01-01 02:58:52 +0000
283+++ lib/lp/app/tests/test_versioninfo.py 2016-09-19 14:06:13 +0000
284@@ -1,4 +1,4 @@
285-# Copyright 2010 Canonical Ltd. This software is licensed under the
286+# Copyright 2010-2016 Canonical Ltd. This software is licensed under the
287 # GNU Affero General Public License version 3 (see the file LICENSE).
288
289 __metaclass__ = type
290@@ -7,7 +7,7 @@
291 import subprocess
292 import unittest
293
294-from lp.app.versioninfo import revno
295+from lp.app.versioninfo import revision
296 from lp.services.config import TREE_ROOT
297
298
299@@ -17,8 +17,8 @@
300 # Our cronscripts are executed with cwd != LP root.
301 # Getting version info should still work in them.
302 args = [os.path.join(TREE_ROOT, "bin/py"), "-c",
303- "from lp.app.versioninfo import revno;"
304- "print revno"]
305+ "from lp.app.versioninfo import revision;"
306+ "print revision"]
307 process = subprocess.Popen(args, cwd='/tmp', stdout=subprocess.PIPE)
308 (output, errors) = process.communicate(None)
309- self.assertEquals(int(revno), int(output))
310+ self.assertEqual(revision, output.rstrip("\n"))
311
312=== modified file 'lib/lp/app/versioninfo.py'
313--- lib/lp/app/versioninfo.py 2011-02-18 16:02:56 +0000
314+++ lib/lp/app/versioninfo.py 2016-09-19 14:06:13 +0000
315@@ -1,23 +1,24 @@
316-# Copyright 2009-2010 Canonical Ltd. This software is licensed under the
317+# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
318 # GNU Affero General Public License version 3 (see the file LICENSE).
319
320-"""Give access to bzr and other version info, if available.
321+"""Give access to version info, if available.
322
323-The bzr version info file is expected to be in the Launchpad root in the
324-file bzr-version-info.py.
325+The version info file is expected to be in the Launchpad root in the
326+file version-info.py.
327
328 From this module, you can get:
329
330 versioninfo: the version_info dict
331- revno: the revision number
332+ revision: the commit ID (Git) or revision number (Bazaar)
333+ display_revision: `revision` formatted for display
334 date: the date of the last revision
335 branch_nick: the branch nickname
336
337-If the bzr-version-info.py file does not exist, then revno, date and
338-branch_nick will all be None.
339+If the version-info.py file does not exist, then revision, display_revision,
340+date, and branch_nick will all be None.
341
342-If that file exists, and contains valid Python, revno, date and branch_nick
343-will have appropriate values from version_info.
344+If that file exists, and contains valid Python, revision, display_revision,
345+date, and branch_nick will have appropriate values from version_info.
346
347 If that file exists, and contains invalid Python, there will be an error when
348 this module is loaded. This module is imported into lp/app/__init__.py so
349@@ -27,7 +28,8 @@
350 __all__ = [
351 'branch_nick',
352 'date',
353- 'revno',
354+ 'display_revision',
355+ 'revision',
356 'versioninfo',
357 ]
358
359@@ -45,10 +47,16 @@
360
361
362 if versioninfo is None:
363- revno = None
364+ revision = None
365+ display_revision = None
366 date = None
367 branch_nick = None
368 else:
369- revno = versioninfo.get('revno')
370+ if 'revno' in versioninfo:
371+ revision = versioninfo.get('revno')
372+ display_revision = revision
373+ else:
374+ revision = versioninfo.get('revision_id')
375+ display_revision = revision[:7]
376 date = versioninfo.get('date')
377 branch_nick = versioninfo.get('branch_nick')
378
379=== modified file 'lib/lp/services/mail/sendmail.py'
380--- lib/lp/services/mail/sendmail.py 2015-07-21 09:04:01 +0000
381+++ lib/lp/services/mail/sendmail.py 2016-09-19 14:06:13 +0000
382@@ -1,4 +1,4 @@
383-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
384+# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
385 # GNU Affero General Public License version 3 (see the file LICENSE).
386
387 """The One True Way to send mail from the Launchpad application.
388@@ -434,7 +434,7 @@
389 # Add an X-Generated-By header for easy whitelisting
390 del message['X-Generated-By']
391 message['X-Generated-By'] = 'Launchpad (canonical.com)'
392- message.set_param('Revision', str(versioninfo.revno), 'X-Generated-By')
393+ message.set_param('Revision', str(versioninfo.revision), 'X-Generated-By')
394 message.set_param('Instance', config.name, 'X-Generated-By')
395
396 # Add a shared secret header for pre-approval with Mailman. This approach
397
398=== modified file 'lib/lp/services/webapp/errorlog.py'
399--- lib/lp/services/webapp/errorlog.py 2015-12-07 08:24:41 +0000
400+++ lib/lp/services/webapp/errorlog.py 2016-09-19 14:06:13 +0000
401@@ -1,4 +1,4 @@
402-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
403+# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
404 # GNU Affero General Public License version 3 (see the file LICENSE).
405
406 """Error logging facilities."""
407@@ -18,7 +18,6 @@
408 import oops.createhooks
409 import oops_amqp
410 from oops_datedir_repo import DateDirRepo
411-import oops_datedir_repo.serializer
412 import oops_timeline
413 import pytz
414 from zope.component.interfaces import ObjectEvent
415@@ -39,7 +38,6 @@
416 soft_timeout_expired,
417 )
418 from lp.services.webapp.interfaces import (
419- IErrorReport,
420 IErrorReportEvent,
421 IErrorReportRequest,
422 IUnloggedException,
423@@ -87,40 +85,6 @@
424 """A new error report has been created."""
425
426
427-@implementer(IErrorReport)
428-class ErrorReport:
429-
430- def __init__(self, id, type, value, time, tb_text, username,
431- url, duration, req_vars, timeline, informational=None,
432- branch_nick=None, revno=None, topic=None, reporter=None):
433- self.id = id
434- self.type = type
435- self.value = value
436- self.time = time
437- self.topic = topic
438- if reporter is not None:
439- self.reporter = reporter
440- self.tb_text = tb_text
441- self.username = username
442- self.url = url
443- self.duration = duration
444- # informational is ignored - will be going from the oops module
445- # soon too.
446- self.req_vars = req_vars
447- self.timeline = timeline
448- self.branch_nick = branch_nick or versioninfo.branch_nick
449- self.revno = revno or versioninfo.revno
450-
451- def __repr__(self):
452- return '<ErrorReport %s %s: %s>' % (self.id, self.type, self.value)
453-
454- @classmethod
455- def read(cls, fp):
456- # Deprecated: use the oops module directly now, when possible.
457- report = oops_datedir_repo.serializer.read(fp)
458- return cls(**report)
459-
460-
461 def notify_publisher(report):
462 if not report.get('id'):
463 report['id'] = str(id(report))
464@@ -318,7 +282,9 @@
465 # What do we want in our reports?
466 # Constants:
467 self._oops_config.template['branch_nick'] = versioninfo.branch_nick
468- self._oops_config.template['revno'] = versioninfo.revno
469+ # XXX cjwatson 2016-09-14: This should really be 'revision', but
470+ # that requires coordination with python-oops-tools.
471+ self._oops_config.template['revno'] = versioninfo.revision
472 reporter = config[self._default_config_section].oops_prefix
473 if section_name != self._default_config_section:
474 reporter = '%s-%s' % (reporter, section_name)
475
476=== modified file 'lib/lp/services/webapp/errorlog.zcml'
477--- lib/lp/services/webapp/errorlog.zcml 2013-04-10 09:12:32 +0000
478+++ lib/lp/services/webapp/errorlog.zcml 2016-09-19 14:06:13 +0000
479@@ -1,4 +1,4 @@
480-<!-- Copyright 2009 Canonical Ltd. This software is licensed under the
481+<!-- Copyright 2009-2016 Canonical Ltd. This software is licensed under the
482 GNU Affero General Public License version 3 (see the file LICENSE).
483 -->
484
485@@ -13,12 +13,6 @@
486 />
487 </class>
488
489- <class class="lp.services.webapp.errorlog.ErrorReport">
490- <allow
491- interface="lp.services.webapp.interfaces.IErrorReport"
492- />
493- </class>
494-
495 <utility
496 provides="zope.error.interfaces.IErrorReportingUtility"
497 component="lp.services.webapp.errorlog.globalErrorUtility"
498
499=== modified file 'lib/lp/services/webapp/interfaces.py'
500--- lib/lp/services/webapp/interfaces.py 2016-02-28 19:13:17 +0000
501+++ lib/lp/services/webapp/interfaces.py 2016-09-19 14:06:13 +0000
502@@ -701,24 +701,6 @@
503 """A new error report has been created."""
504
505
506-class IErrorReport(Interface):
507- id = TextLine(description=u"The name of this error report.")
508- type = TextLine(description=u"The type of the exception that occurred.")
509- value = TextLine(description=u"The value of the exception that occurred.")
510- time = Datetime(description=u"The time at which the exception occurred.")
511- pageid = TextLine(
512- description=u"""
513- The context class plus the page template where the exception
514- occurred.
515- """)
516- branch_nick = TextLine(description=u"The branch nickname.")
517- revno = TextLine(description=u"The revision number of the branch.")
518- tb_text = Text(description=u"A text version of the traceback.")
519- username = TextLine(description=u"The user associated with the request.")
520- url = TextLine(description=u"The URL for the failed request.")
521- req_vars = Attribute("The request variables.")
522-
523-
524 class IErrorReportRequest(Interface):
525 oopsid = TextLine(
526 description=u"""an identifier for the exception, or None if no
527
528=== modified file 'lib/lp/services/webapp/publisher.py'
529--- lib/lp/services/webapp/publisher.py 2016-02-28 19:13:17 +0000
530+++ lib/lp/services/webapp/publisher.py 2016-09-19 14:06:13 +0000
531@@ -63,10 +63,10 @@
532 )
533 from zope.traversing.browser.interfaces import IAbsoluteURL
534
535+from lp.app import versioninfo
536 from lp.app.errors import NotFoundError
537 from lp.app.interfaces.informationtype import IInformationType
538 from lp.app.interfaces.launchpad import IPrivacy
539-from lp.app.versioninfo import revno
540 from lp.layers import (
541 LaunchpadLayer,
542 setFirstLayer,
543@@ -412,7 +412,7 @@
544 from lp.services.config import config
545 combo_url = '/+combo'
546 if not config.devmode:
547- combo_url += '/rev%s' % revno
548+ combo_url += '/rev%s' % versioninfo.revision
549 return combo_url
550
551 def render(self):
552
553=== modified file 'lib/lp/services/webapp/servers.py'
554--- lib/lp/services/webapp/servers.py 2016-06-24 11:31:44 +0000
555+++ lib/lp/services/webapp/servers.py 2016-09-19 14:06:13 +0000
556@@ -602,7 +602,7 @@
557 'Strict-Transport-Security', 'max-age=15552000')
558
559 # Publish revision information.
560- self.response.setHeader('X-Launchpad-Revision', versioninfo.revno)
561+ self.response.setHeader('X-Launchpad-Revision', versioninfo.revision)
562
563 @property
564 def stepstogo(self):
565
566=== modified file 'lib/lp/services/webapp/tests/test_errorlog.py'
567--- lib/lp/services/webapp/tests/test_errorlog.py 2015-07-08 16:05:11 +0000
568+++ lib/lp/services/webapp/tests/test_errorlog.py 2016-09-19 14:06:13 +0000
569@@ -1,13 +1,11 @@
570-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
571+# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
572 # GNU Affero General Public License version 3 (see the file LICENSE).
573
574 """Tests for error logging & OOPS reporting."""
575
576 __metaclass__ = type
577
578-import datetime
579 import httplib
580-import StringIO
581 import sys
582 from textwrap import dedent
583 import traceback
584@@ -30,7 +28,6 @@
585 from zope.publisher.interfaces.xmlrpc import IXMLRPCRequest
586 from zope.security.interfaces import Unauthorized
587
588-from lp.app import versioninfo
589 from lp.app.errors import (
590 GoneError,
591 TranslationUnavailable,
592@@ -41,7 +38,6 @@
593 _filter_session_statement,
594 _is_sensitive,
595 attach_http_request,
596- ErrorReport,
597 ErrorReportingUtility,
598 notify_publisher,
599 ScriptRequest,
600@@ -60,79 +56,6 @@
601 """Used to test handling of exceptions in OOPS reports."""
602
603
604-class TestErrorReport(testtools.TestCase):
605-
606- def test___init__(self):
607- """Test ErrorReport.__init__()"""
608- entry = ErrorReport('id', 'exc-type', 'exc-value', 'timestamp',
609- 'traceback-text', 'username', 'url', 42,
610- {'name1': 'value1', 'name2': 'value2',
611- 'name3': 'value3'},
612- [(1, 5, 'store_a', 'SELECT 1'),
613- (5, 10, 'store_b', 'SELECT 2')],
614- topic='pageid',
615- )
616- self.assertEqual(entry.id, 'id')
617- self.assertEqual(entry.type, 'exc-type')
618- self.assertEqual(entry.value, 'exc-value')
619- self.assertEqual(entry.time, 'timestamp')
620- self.assertEqual(entry.topic, 'pageid')
621- self.assertEqual(entry.branch_nick, versioninfo.branch_nick)
622- self.assertEqual(entry.revno, versioninfo.revno)
623- self.assertEqual(entry.username, 'username')
624- self.assertEqual(entry.url, 'url')
625- self.assertEqual(entry.duration, 42)
626- self.assertEqual({
627- 'name1': 'value1',
628- 'name2': 'value2',
629- 'name3': 'value3',
630- }, entry.req_vars)
631- self.assertEqual(len(entry.timeline), 2)
632- self.assertEqual(entry.timeline[0], (1, 5, 'store_a', 'SELECT 1'))
633- self.assertEqual(entry.timeline[1], (5, 10, 'store_b', 'SELECT 2'))
634-
635- def test_read(self):
636- """Test ErrorReport.read()."""
637- # Note: this exists to test the compatibility thunk only.
638- fp = StringIO.StringIO(dedent("""\
639- Oops-Id: OOPS-A0001
640- Exception-Type: NotFound
641- Exception-Value: error message
642- Date: 2005-04-01T00:00:00+00:00
643- Page-Id: IFoo:+foo-template
644- User: Sample User
645- URL: http://localhost:9000/foo
646- Duration: 42
647-
648- HTTP_USER_AGENT=Mozilla/5.0
649- HTTP_REFERER=http://localhost:9000/
650- name%3Dfoo=hello%0Aworld
651-
652- 00001-00005@store_a SELECT 1
653- 00005-00010@store_b SELECT 2
654-
655- traceback-text"""))
656- entry = ErrorReport.read(fp)
657- self.assertEqual(entry.id, 'OOPS-A0001')
658- self.assertEqual(entry.type, 'NotFound')
659- self.assertEqual(entry.value, 'error message')
660- self.assertEqual(
661- entry.time, datetime.datetime(2005, 4, 1, tzinfo=UTC))
662- self.assertEqual(entry.topic, 'IFoo:+foo-template')
663- self.assertEqual(entry.tb_text, 'traceback-text')
664- self.assertEqual(entry.username, 'Sample User')
665- self.assertEqual(entry.url, 'http://localhost:9000/foo')
666- self.assertEqual(entry.duration, 42)
667- self.assertEqual({
668- 'HTTP_USER_AGENT': 'Mozilla/5.0',
669- 'HTTP_REFERER': 'http://localhost:9000/',
670- 'name=foo': 'hello\nworld'},
671- entry.req_vars)
672- self.assertEqual(len(entry.timeline), 2)
673- self.assertEqual(entry.timeline[0], [1, 5, 'store_a', 'SELECT 1'])
674- self.assertEqual(entry.timeline[1], [5, 10, 'store_b', 'SELECT 2'])
675-
676-
677 class TestErrorReportingUtility(testtools.TestCase):
678
679 # want rabbit
680
681=== modified file 'lib/lp/services/webapp/tests/test_servers.py'
682--- lib/lp/services/webapp/tests/test_servers.py 2016-06-24 11:31:44 +0000
683+++ lib/lp/services/webapp/tests/test_servers.py 2016-09-19 14:06:13 +0000
684@@ -386,7 +386,7 @@
685 def test_baserequest_revision_header(self):
686 response = LaunchpadBrowserRequest(StringIO.StringIO(''), {}).response
687 self.assertEqual(
688- versioninfo.revno, response.getHeader('X-Launchpad-Revision'))
689+ versioninfo.revision, response.getHeader('X-Launchpad-Revision'))
690
691 def test_baserequest_recovers_from_bad_path_info_encoding(self):
692 # The request object recodes PATH_INFO to ensure sane_environment
693
694=== modified file 'lib/lp/services/webhooks/model.py'
695--- lib/lp/services/webhooks/model.py 2016-01-19 17:41:11 +0000
696+++ lib/lp/services/webhooks/model.py 2016-09-19 14:06:13 +0000
697@@ -43,8 +43,8 @@
698 )
699 from zope.security.proxy import removeSecurityProxy
700
701+from lp.app import versioninfo
702 from lp.app.interfaces.security import IAuthorization
703-import lp.app.versioninfo
704 from lp.registry.interfaces.role import IPersonRoles
705 from lp.registry.model.person import Person
706 from lp.services.config import config
707@@ -488,7 +488,7 @@
708 transaction.commit()
709 raise WebhookDeliveryFailure(self.error_message)
710 user_agent = '%s-Webhooks/r%s' % (
711- config.vhost.mainsite.hostname, lp.app.versioninfo.revno)
712+ config.vhost.mainsite.hostname, versioninfo.revision)
713 secret = self.webhook.secret
714 result = getUtility(IWebhookClient).deliver(
715 self.webhook.delivery_url, config.webhooks.http_proxy,
716
717=== modified file 'lib/lp/services/webhooks/tests/test_job.py'
718--- lib/lp/services/webhooks/tests/test_job.py 2015-11-11 18:12:24 +0000
719+++ lib/lp/services/webhooks/tests/test_job.py 2016-09-19 14:06:13 +0000
720@@ -1,4 +1,4 @@
721-# Copyright 2015 Canonical Ltd. This software is licensed under the
722+# Copyright 2015-2016 Canonical Ltd. This software is licensed under the
723 # GNU Affero General Public License version 3 (see the file LICENSE).
724
725 """Tests for `WebhookJob`s."""
726@@ -37,7 +37,7 @@
727 from zope.component import getUtility
728 from zope.security.proxy import removeSecurityProxy
729
730-from lp.app.versioninfo import revno
731+from lp.app import versioninfo
732 from lp.services.features.testing import FeatureFixture
733 from lp.services.job.interfaces.job import JobStatus
734 from lp.services.job.runner import JobRunner
735@@ -371,7 +371,8 @@
736 self.assertEqual([
737 ('POST', 'http://example.com/ep',
738 {'Content-Type': 'application/json',
739- 'User-Agent': 'launchpad.dev-Webhooks/r%s' % revno,
740+ 'User-Agent': 'launchpad.dev-Webhooks/r%s' % (
741+ versioninfo.revision),
742 'X-Launchpad-Event-Type': 'test',
743 'X-Launchpad-Delivery': str(job.job_id)}),
744 ], reqs)
745@@ -386,7 +387,8 @@
746 self.assertEqual([
747 ('POST', 'http://example.com/ep',
748 {'Content-Type': 'application/json',
749- 'User-Agent': 'launchpad.dev-Webhooks/r%s' % revno,
750+ 'User-Agent': 'launchpad.dev-Webhooks/r%s' % (
751+ versioninfo.revision),
752 'X-Hub-Signature':
753 'sha1=de75f136c37d89f5eb24834468c1ecd602fa95dd',
754 'X-Launchpad-Event-Type': 'test',
755
756=== modified file 'lib/lp/services/webservice/configuration.py'
757--- lib/lp/services/webservice/configuration.py 2012-01-31 01:22:32 +0000
758+++ lib/lp/services/webservice/configuration.py 2016-09-19 14:06:13 +0000
759@@ -1,4 +1,4 @@
760-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
761+# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
762 # GNU Affero General Public License version 3 (see the file LICENSE).
763
764 """A configuration class describing the Launchpad web service."""
765@@ -58,7 +58,7 @@
766
767 @property
768 def code_revision(self):
769- return str(versioninfo.revno)
770+ return str(versioninfo.revision)
771
772 def createRequest(self, body_instream, environ):
773 """See `IWebServiceConfiguration`."""
774
775=== modified file 'lib/lp/testing/yuixhr.py'
776--- lib/lp/testing/yuixhr.py 2015-07-08 16:05:11 +0000
777+++ lib/lp/testing/yuixhr.py 2016-09-19 14:06:13 +0000
778@@ -1,4 +1,4 @@
779-# Copyright 2011-2013 Canonical Ltd. This software is licensed under the
780+# Copyright 2011-2016 Canonical Ltd. This software is licensed under the
781 # GNU Affero General Public License version 3 (see the file LICENSE).
782
783 """Fixture code for YUITest + XHR integration testing."""
784@@ -33,7 +33,7 @@
785 from zope.security.proxy import removeSecurityProxy
786 from zope.session.interfaces import IClientIdManager
787
788-from lp.app.versioninfo import revno
789+from lp.app import versioninfo
790 from lp.services.config import config
791 from lp.services.webapp.interfaces import (
792 IOpenLaunchBag,
793@@ -207,7 +207,7 @@
794 href="/+yuitest/build/js/yui/console/assets/skins/sam/console.css"/>
795 <link rel="stylesheet"
796 href="/+yuitest/build/js/yui/test/assets/skins/sam/test.css"/>
797- <link rel="stylesheet" href="/+icing/rev%(revno)s/combo.css"/>
798+ <link rel="stylesheet" href="/+icing/rev%(revision)s/combo.css"/>
799 <script type="text/javascript" src="%(test_module)s"></script>
800 </head>
801 <body class="yui3-skin-sam">
802@@ -234,7 +234,7 @@
803 <title>YUI XHR Tests</title>
804 <link rel="stylesheet"
805 href="/+icing/yui/assets/skins/sam/skin.css"/>
806- <link rel="stylesheet" href="/+icing/rev%(revno)s/combo.css"/>
807+ <link rel="stylesheet" href="/+icing/rev%(revision)s/combo.css"/>
808 <style>
809 ul {
810 text-align: left;
811@@ -358,7 +358,7 @@
812 warning = ' <span class="warning">%s</span>' % warning
813 test_lines.append('<li>%s%s</li>' % (link, warning))
814 return self.index_template % {
815- 'revno': revno,
816+ 'revision': versioninfo.revision,
817 'tests': '\n'.join(test_lines)}
818
819 def renderCOMBOFILE(self):
820@@ -390,7 +390,7 @@
821 return self.page_template % dict(
822 test_module='/+yuitest/%s.js' % self.traversed_path,
823 test_namespace=self.traversed_path.replace('/', '.'),
824- revno=revno,
825+ revision=versioninfo.revision,
826 javascript_block=self.renderYUI())
827
828 def renderSETUP(self):
829@@ -445,7 +445,7 @@
830
831 """
832 return self.yui_block_combo % dict(
833- revno=revno,
834+ revision=versioninfo.revision,
835 combo_url=self.combo_url)
836
837 def render(self):
838
839=== modified file 'lib/lp/translations/utilities/gettext_po_parser.py'
840--- lib/lp/translations/utilities/gettext_po_parser.py 2015-07-08 16:05:11 +0000
841+++ lib/lp/translations/utilities/gettext_po_parser.py 2016-09-19 14:06:13 +0000
842@@ -1,4 +1,4 @@
843-# Copyright 2009-2014 Canonical Ltd. This software is licensed under the
844+# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
845 # GNU Affero General Public License version 3 (see the file LICENSE).
846
847 # Originally based on code from msgfmt.py (available from python source
848@@ -23,7 +23,7 @@
849 from zope import datetime as zope_datetime
850 from zope.interface import implementer
851
852-from lp.app.versioninfo import revno
853+from lp.app import versioninfo
854 from lp.translations.interfaces.translationcommonformat import (
855 ITranslationHeaderData,
856 )
857@@ -352,10 +352,10 @@
858 elif key == 'x-generator':
859 # Note the revision number so it would help for debugging
860 # problems with bad exports.
861- if revno is None:
862+ if versioninfo.revision is None:
863 build = 'Unknown'
864 else:
865- build = revno
866+ build = versioninfo.revision
867 raw_content_list.append(
868 '%s: Launchpad (build %s)\n' % (value, build))
869 else:
870
871=== renamed file 'scripts/update-bzr-version-info.sh' => 'scripts/update-version-info.sh'
872--- scripts/update-bzr-version-info.sh 2009-10-16 01:54:41 +0000
873+++ scripts/update-version-info.sh 2016-09-19 14:06:13 +0000
874@@ -1,35 +1,62 @@
875 #!/bin/bash
876 #
877-# Copyright 2009 Canonical Ltd. This software is licensed under the
878+# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
879 # GNU Affero General Public License version 3 (see the file LICENSE).
880 #
881-# Update bzr-version-info.py -- but only if the revision number has
882+# Update version-info.py -- but only if the revision number has
883 # changed
884 #
885
886-if ! which bzr > /dev/null || ! test -x $(which bzr); then
887- echo "No working 'bzr' executable found"
888+newfile=version-info-${RANDOM}.py
889+
890+if [ -d .git ]; then
891+ if ! which git > /dev/null || ! test -x $(which git); then
892+ echo "No working 'git' executable found" >&2
893+ exit 1
894+ fi
895+
896+ branch_nick="$(git rev-parse --abbrev-ref HEAD | sed "s/'/\\\\'/g")"
897+ revision_id="$(git rev-parse HEAD)"
898+ cat > $newfile <<EOF
899+#! /usr/bin/env python
900+
901+from __future__ import print_function
902+
903+version_info = {
904+ 'branch_nick': u'$branch_nick',
905+ 'revision_id': u'$revision_id',
906+ }
907+
908+if __name__ == '__main__':
909+ print('revision id: %(revision_id)s' % version_info)
910+EOF
911+elif [ -d .bzr ]; then
912+ if ! which bzr > /dev/null || ! test -x $(which bzr); then
913+ echo "No working 'bzr' executable found" >&2
914+ exit 1
915+ fi
916+
917+ bzr version-info --format=python > $newfile 2>/dev/null
918+else
919+ echo "Not in a Git or Bazaar working tree" >&2
920 exit 1
921 fi
922
923-newfile=bzr-version-info-${RANDOM}.py
924-bzr version-info --format=python > $newfile 2>/dev/null;
925-# There's a leading space here that I don't care to trim..
926-revno=$(python $newfile | grep revision: | cut -d: -f2)
927-if ! [ -f bzr-version-info.py ]; then
928- echo "Creating bzr-version-info.py at revno$revno"
929- mv ${newfile} bzr-version-info.py
930+revision_id=$(python $newfile | sed -n 's/^revision id: //p')
931+if ! [ -f version-info.py ]; then
932+ echo "Creating version-info.py at revision $revision_id"
933+ mv ${newfile} version-info.py
934 else
935 # Here we compare the actual output instead of the contents of the
936 # file because bzr includes a build-date that is actually updated
937 # every time you run bzr version-info.
938 newcontents=$(python $newfile)
939- oldcontents=$(python bzr-version-info.py)
940+ oldcontents=$(python version-info.py)
941 if [ "$newcontents" != "$oldcontents" ]; then
942- echo "Updating bzr-version-info.py to revno$revno"
943- mv ${newfile} bzr-version-info.py
944+ echo "Updating version-info.py to revision $revision_id"
945+ mv ${newfile} version-info.py
946 else
947- echo "Skipping bzr-version-info.py update; already at revno$revno"
948+ echo "Skipping version-info.py update; already at revision $revision_id"
949 rm ${newfile}
950 fi
951 fi
952
953=== modified file 'utilities/create-lp-wadl-and-apidoc.py'
954--- utilities/create-lp-wadl-and-apidoc.py 2013-04-10 09:27:24 +0000
955+++ utilities/create-lp-wadl-and-apidoc.py 2016-09-19 14:06:13 +0000
956@@ -1,6 +1,6 @@
957 #! /usr/bin/python -S
958 #
959-# Copyright 2010 Canonical Ltd. This software is licensed under the
960+# Copyright 2010-2016 Canonical Ltd. This software is licensed under the
961 # GNU Affero General Public License version 3 (see the file LICENSE).
962
963 """Create a static WADL file describing the current webservice.
964@@ -15,6 +15,7 @@
965 from multiprocessing import Process
966 import optparse
967 import os
968+import subprocess
969 import sys
970
971 import bzrlib
972@@ -137,10 +138,16 @@
973 # Get the time of the last commit. We will use this as the mtime for the
974 # generated files so that we can safely use it as part of Apache's etag
975 # generation in the face of multiple servers/filesystems.
976- with bzrlib.initialize():
977- branch = Branch.open(os.path.dirname(os.path.dirname(__file__)))
978- timestamp = branch.repository.get_revision(
979- branch.last_revision()).timestamp
980+ top = os.path.dirname(os.path.dirname(__file__))
981+ if os.path.exists(os.path.join(top, ".git")):
982+ timestamp = int(subprocess.check_output(
983+ ["git", "log", "-1", "--format=%ct", "HEAD"],
984+ universal_newlines=True))
985+ else:
986+ with bzrlib.initialize():
987+ branch = Branch.open(top)
988+ timestamp = branch.repository.get_revision(
989+ branch.last_revision()).timestamp
990
991 # Start a process to build each set of WADL and HTML files.
992 processes = []