Merge lp:~jelmer/bzr-builddeb/dep3-patch into lp:bzr-builddeb

Proposed by Jelmer Vernooij
Status: Merged
Approved by: James Westby
Approved revision: 569
Merged at revision: 559
Proposed branch: lp:~jelmer/bzr-builddeb/dep3-patch
Merge into: lp:bzr-builddeb
Diff against target: 647 lines (+578/-2)
8 files modified
__init__.py (+1/-0)
cmds.py (+70/-0)
debian/changelog (+7/-0)
dep3.py (+177/-0)
tests/__init__.py (+1/-0)
tests/blackbox/__init__.py (+1/-2)
tests/blackbox/test_dep3.py (+104/-0)
tests/test_dep3.py (+217/-0)
To merge this branch: bzr merge lp:~jelmer/bzr-builddeb/dep3-patch
Reviewer Review Type Date Requested Status
James Westby Approve
Review via email: mp+60320@code.launchpad.net

Description of the change

Add a 'bzr dep3-patch' command which can spit out a -p1 patch with a DEP-3 compliant
header, looking at bzr metadata to pre-fill-in as much of the metadata as possible.

Another neat thing to do would be to use this new infrastructure to export a
set of loom threads to a debian/patches directory, but I'll leave that for some
other time.

To post a comment you must log in.
Revision history for this message
James Westby (james-w) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '__init__.py'
2--- __init__.py 2011-02-19 20:43:49 +0000
3+++ __init__.py 2011-05-08 15:53:28 +0000
4@@ -37,6 +37,7 @@
5 commands = {
6 "bd_do": [],
7 "builddeb": ["bd"],
8+ "dep3_patch": [],
9 "dh_make": ["dh_make"],
10 "import_dsc": [],
11 "import_upstream": [],
12
13=== modified file 'cmds.py'
14--- cmds.py 2011-04-29 22:32:59 +0000
15+++ cmds.py 2011-05-08 15:53:28 +0000
16@@ -1205,3 +1205,73 @@
17 note('Package prepared in %s'
18 % urlutils.unescape_for_display(tree.basedir,
19 self.outf.encoding))
20+
21+
22+class cmd_dep3_patch(Command):
23+ """Format the changes in a branch as a DEP-3 patch.
24+
25+ """
26+
27+ takes_args = ["location"]
28+
29+ directory_opt = Option('directory',
30+ help='Packaging tree for which to generate patch.',
31+ short_name='d', type=unicode)
32+
33+ no_upstream_check_opt = Option('no-upstream-check',
34+ help="Don't check whether patch has been merged upstream.")
35+
36+ takes_options = [directory_opt, "revision", no_upstream_check_opt]
37+
38+ def run(self, location, directory=".", revision=None, no_upstream_check=False):
39+ from bzrlib.plugins.builddeb.dep3 import (
40+ determine_applied_upstream,
41+ determine_forwarded,
42+ describe_origin,
43+ gather_bugs_and_authors,
44+ write_dep3_patch,
45+ )
46+ packaging_tree, packaging_branch = BzrDir.open_containing_tree_or_branch(
47+ directory)[:2]
48+ tree, branch = BzrDir.open_containing_tree_or_branch(location)[:2]
49+ branch.lock_read()
50+ try:
51+ if revision is not None and len(revision) >= 1:
52+ revision_id = revision[-1].as_revision_id(branch)
53+ else:
54+ revision_id = branch.last_revision()
55+ graph = branch.repository.get_graph(packaging_branch.repository)
56+ if revision is not None and len(revision) == 2:
57+ base_revid = revision[0].as_revision_id(branch)
58+ else:
59+ base_revid = graph.find_unique_lca(revision_id,
60+ packaging_branch.last_revision())
61+ interesting_revision_ids = graph.find_unique_ancestors(revision_id, [base_revid])
62+ if len(interesting_revision_ids) == 0:
63+ raise BzrCommandError("No unmerged revisions")
64+ (bugs, authors, last_update) = gather_bugs_and_authors(branch.repository,
65+ interesting_revision_ids)
66+ config = branch.get_config()
67+ description = config.get_user_option("description")
68+ if description is None and len(interesting_revision_ids) == 1:
69+ # if there's just one revision, use that revisions commits message
70+ rev = branch.repository.get_revision(iter(interesting_revision_ids).next())
71+ description = rev.message
72+ origin = describe_origin(branch, revision_id)
73+ if packaging_tree is None:
74+ packaging_tree = packaging_branch.basis_tree()
75+ builddeb_config = debuild_config(packaging_tree, True)
76+ if not no_upstream_check and builddeb_config.upstream_branch:
77+ upstream_branch = Branch.open(builddeb_config.upstream_branch)
78+ applied_upstream = determine_applied_upstream(upstream_branch, branch,
79+ revision_id)
80+ forwarded = determine_forwarded(upstream_branch, branch, revision_id)
81+ else:
82+ applied_upstream = None
83+ forwarded = None
84+ write_dep3_patch(self.outf, branch, base_revid,
85+ revision_id, bugs=bugs, authors=authors, origin=origin,
86+ forwarded=forwarded, applied_upstream=applied_upstream,
87+ description=description, last_update=last_update)
88+ finally:
89+ branch.unlock()
90
91=== modified file 'debian/changelog'
92--- debian/changelog 2011-05-06 16:43:16 +0000
93+++ debian/changelog 2011-05-08 15:53:28 +0000
94@@ -1,3 +1,10 @@
95+bzr-builddeb (2.7.5) UNRELEASED; urgency=low
96+
97+ * New 'bzr dep3-patch' subcommand that can generate DEP-3 compliant
98+ patches. LP: #460576
99+
100+ -- Jelmer Vernooij <jelmer@debian.org> Sun, 08 May 2011 17:45:14 +0200
101+
102 bzr-builddeb (2.7.4) unstable; urgency=low
103
104 [ Jelmer Vernooij ]
105
106=== added file 'dep3.py'
107--- dep3.py 1970-01-01 00:00:00 +0000
108+++ dep3.py 2011-05-08 15:53:28 +0000
109@@ -0,0 +1,177 @@
110+# dep3.py -- DEP-3 compatible patch formatting
111+# Copyright (C) 2011 Canonical Ltd.
112+#
113+# This file is part of bzr-builddeb.
114+#
115+# bzr-builddeb is free software; you can redistribute it and/or modify
116+# it under the terms of the GNU General Public License as published by
117+# the Free Software Foundation; either version 2 of the License, or
118+# (at your option) any later version.
119+#
120+# bzr-builddeb is distributed in the hope that it will be useful,
121+# but WITHOUT ANY WARRANTY; without even the implied warranty of
122+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
123+# GNU General Public License for more details.
124+#
125+# You should have received a copy of the GNU General Public License
126+# along with bzr-builddeb; if not, write to the Free Software
127+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
128+#
129+
130+"""DEP-3 style patch formatting."""
131+
132+from bzrlib import diff
133+
134+import time
135+
136+
137+def write_dep3_bug_line(f, bug_url, status):
138+ """Write a DEP-3 compatible line with a bug link.
139+
140+ :param f: File-like object to write to
141+ :param bug_url: Bug URL
142+ :param status: Bug status (e.g. "fixed")
143+ """
144+ # For the moment, we only care about fixed bugs
145+ if status != "fixed":
146+ return
147+ if bug_url.startswith("http://bugs.debian.org/"):
148+ f.write("Bug-Debian: %s\n" % bug_url)
149+ else:
150+ # FIXME: Filter out Ubuntu bugs on Launchpad
151+ f.write("Bug: %s\n" % bug_url)
152+
153+
154+def write_dep3_patch_header(f, description=None, origin=None, forwarded=None,
155+ bugs=None, authors=None, revision_id=None, last_update=None,
156+ applied_upstream=None):
157+ """Write a DEP3 patch header.
158+
159+ :param f: File-like object to write to
160+ :param description: Description of the patch
161+ :param origin: Single line describing the origin of the patch
162+ :param forwarded: Single line describing whether and how the patch was
163+ forwarded
164+ :param bugs: Set of bugs fixed in this patch
165+ :param authors: Authors of the patch
166+ :param revision_id: Relevant bzr revision id
167+ :param last_update: Last update timestamp
168+ :param applied_upstream: If the patch is applied upstream,
169+ an informal string describing where it was merged
170+ """
171+ # FIXME: Handle line breaks, etc sensibly
172+ if description is not None:
173+ description = description.strip("\n")
174+ description = description.replace("\n\n", "\n.\n")
175+ description = description.replace("\n", "\n ")
176+ f.write("Description: %s\n" % description)
177+ if origin is not None:
178+ f.write("Origin: %s\n" % origin)
179+ if forwarded is not None:
180+ f.write("Forwarded: %s\n" % forwarded)
181+ if authors is not None:
182+ for author in authors:
183+ f.write("Author: %s\n" % author)
184+ if bugs is not None:
185+ for bug_url, status in bugs:
186+ write_dep3_bug_line(f, bug_url, status)
187+ if last_update is not None:
188+ f.write("Last-Update: %s\n" % time.strftime("%Y-%m-%d",
189+ time.gmtime(last_update)))
190+ if applied_upstream is not None:
191+ f.write("Applied-Upstream: %s\n" % applied_upstream)
192+ if revision_id is not None:
193+ f.write("X-Bzr-Revision-Id: %s\n" % revision_id)
194+ f.write("\n")
195+
196+
197+def gather_bugs_and_authors(repository, interesting_revision_ids):
198+ """Gather bug and author information from revisions.
199+
200+ :param interesting_revision_ids: Iterable of revision ids to check
201+ :return: Tuple of bugs, authors and highest found commit timestamp
202+ """
203+ authors = set()
204+ bugs = set()
205+ last_update = None
206+ for rev in repository.get_revisions(interesting_revision_ids):
207+ last_update = max(rev.timestamp, last_update)
208+ authors.update(rev.get_apparent_authors())
209+ bugs.update(rev.iter_bugs())
210+ return (bugs, authors, last_update)
211+
212+
213+def determine_applied_upstream(upstream_branch, feature_branch, feature_revid=None):
214+ """Check if a particular revision has been merged upstream.
215+
216+ :param upstream_branch: Upstream branch object
217+ :param feature_branch: Feature branch
218+ :param feature_revid: Revision id in feature branch to check,
219+ defaults to feature_branch tip.
220+ :return: String that can be used for Applied-Upstream field
221+ """
222+ if feature_revid is None:
223+ feature_revid = feature_branch.last_revision()
224+ upstream_graph = feature_branch.repository.get_graph(upstream_branch.repository)
225+ merger = upstream_graph.find_lefthand_merger(feature_revid,
226+ upstream_branch.last_revision())
227+ if merger is not None:
228+ return "merged in revision %s" % (
229+ ".".join(str(x) for x in upstream_branch.revision_id_to_dotted_revno(merger)), )
230+ else:
231+ return "no"
232+
233+
234+def determine_forwarded(upstream_branch, feature_branch, feature_revid):
235+ """See if a branch has been forwarded to upstream.
236+
237+ :param upstream_branch: Upstream branch object
238+ :param feature_branch: Feature branch
239+ :param feature_revid: Revision id in feature branch to check
240+ :return: String that can be used for Applied-Upstream field
241+ """
242+ # FIXME: Check for Launchpad merge proposals from feature_branch (or its
243+ # public_branch) to upstream_branch
244+
245+ # Are there any other ways to see that a patch has been forwarded upstream?
246+ return None
247+
248+
249+def describe_origin(branch, revid):
250+ """Describe a tree for use in the origin field.
251+
252+ :param branch: Branch to retrieve the revision from
253+ :param revid: Revision id
254+ """
255+ public_branch_url = branch.get_public_branch()
256+ if public_branch_url is not None:
257+ return "commit, %s, revision: %s" % (
258+ public_branch_url,
259+ ".".join(str(x) for x in branch.revision_id_to_dotted_revno(revid)), )
260+ else:
261+ return "commit, revision id: %s" % revid
262+
263+
264+def write_dep3_patch(f, branch, base_revid, target_revid, description=None,
265+ origin=None, forwarded=None, applied_upstream=None, bugs=None,
266+ authors=None, last_update=None):
267+ """Write a DEP-3 compliant patch.
268+
269+ :param f: File-like object to write to
270+ :param repository: Repository to retrieve revisions from
271+ :param base_revid: Base revision id
272+ :param target_revid: Target revision id
273+ :param description: Optional description
274+ :param forwarded: Optional information on if/how the patch was forwarded
275+ :param applied_upstream: Optional information on how whether the patch
276+ was merged upstream
277+ :param bugs: Sequence of bug reports related to this patch
278+ :param authors: Sequence of authors of this patch
279+ :param last_update: Timestamp for last time this patch was updated
280+ """
281+ write_dep3_patch_header(f, bugs=bugs, authors=authors, last_update=last_update,
282+ description=description, revision_id=target_revid, origin=origin,
283+ applied_upstream=applied_upstream, forwarded=forwarded)
284+ old_tree = branch.repository.revision_tree(base_revid)
285+ new_tree = branch.repository.revision_tree(target_revid)
286+ diff.show_diff_trees(old_tree, new_tree, f, old_label='old/', new_label='new/')
287
288=== modified file 'tests/__init__.py'
289--- tests/__init__.py 2011-02-11 13:35:53 +0000
290+++ tests/__init__.py 2011-05-08 15:53:28 +0000
291@@ -119,6 +119,7 @@
292 'test_bzrtools_import',
293 'test_commit_message',
294 'test_config',
295+ 'test_dep3',
296 'test_dh_make',
297 'test_hooks',
298 'test_import_dsc',
299
300=== modified file 'tests/blackbox/__init__.py'
301--- tests/blackbox/__init__.py 2010-05-03 03:03:34 +0000
302+++ tests/blackbox/__init__.py 2011-05-08 15:53:28 +0000
303@@ -18,12 +18,11 @@
304 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
305 #
306
307-from bzrlib.tests import TestUtil
308-
309
310 def load_tests(standard_tests, module, loader):
311 testmod_names = [
312 'test_builddeb',
313+ 'test_dep3',
314 'test_do',
315 'test_import_dsc',
316 'test_import_upstream',
317
318=== added file 'tests/blackbox/test_dep3.py'
319--- tests/blackbox/test_dep3.py 1970-01-01 00:00:00 +0000
320+++ tests/blackbox/test_dep3.py 2011-05-08 15:53:28 +0000
321@@ -0,0 +1,104 @@
322+# test_dep3.py -- Blackbox tests for dep3-patch.
323+# Copyright (C) 2011 Canonical Ltd.
324+#
325+# This file is part of bzr-builddeb.
326+#
327+# bzr-builddeb is free software; you can redistribute it and/or modify
328+# it under the terms of the GNU General Public License as published by
329+# the Free Software Foundation; either version 2 of the License, or
330+# (at your option) any later version.
331+#
332+# bzr-builddeb is distributed in the hope that it will be useful,
333+# but WITHOUT ANY WARRANTY; without even the implied warranty of
334+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
335+# GNU General Public License for more details.
336+#
337+# You should have received a copy of the GNU General Public License
338+# along with bzr-builddeb; if not, write to the Free Software
339+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
340+#
341+
342+
343+"""Blackbox tests for "bzr dep3-patch"."""
344+
345+
346+from bzrlib.tests.blackbox import ExternalBase
347+
348+import os
349+
350+
351+class TestDep3Patch(ExternalBase):
352+
353+ def setUp(self):
354+ super(TestDep3Patch, self).setUp()
355+ self.upstream_tree = self.make_branch_and_tree("upstream")
356+ self.upstream_tree.commit(message="initial commit")
357+ packaging = self.upstream_tree.bzrdir.sprout("packaging")
358+ self.packaging_tree = packaging.open_workingtree()
359+ feature = self.upstream_tree.bzrdir.sprout("feature")
360+ self.feature_tree = feature.open_workingtree()
361+
362+ def test_nothing_to_do(self):
363+ (out, err) = self.run_bzr("dep3-patch -d packaging feature", retcode=3)
364+ self.assertEquals("bzr: ERROR: No unmerged revisions\n", err)
365+ self.assertEquals("", out)
366+
367+ def test_simple(self):
368+ # If there is a single revision the commit message from
369+ # that revision will be used.
370+ self.build_tree_contents([("feature/foo", "bar\n")])
371+ self.feature_tree.add("foo")
372+ self.feature_tree.commit(message="A message", timestamp=1304850124,
373+ timezone=0, authors=["Jelmer <jelmer@debian.org>"], rev_id="therevid")
374+ (out, err) = self.run_bzr("dep3-patch -d packaging feature")
375+ self.assertEquals(out, "Description: A message\n"
376+ "Origin: commit, revision id: therevid\n"
377+ "Author: Jelmer <jelmer@debian.org>\n"
378+ "Last-Update: 2011-05-08\n"
379+ "X-Bzr-Revision-Id: therevid\n"
380+ "\n"
381+ "=== added file 'foo'\n"
382+ "--- old/foo\t1970-01-01 00:00:00 +0000\n"
383+ "+++ new/foo\t2011-05-08 10:22:04 +0000\n"
384+ "@@ -0,0 +1,1 @@\n"
385+ "+bar\n"
386+ "\n")
387+
388+ def test_uses_single_revision_commit(self):
389+ # If there is a single revision the commit message from
390+ # that revision will be used.
391+ self.feature_tree.commit(message="A message", timestamp=1304850124,
392+ timezone=0, authors=["Jelmer <jelmer@debian.org>"])
393+ (out, err) = self.run_bzr("dep3-patch -d packaging feature")
394+ self.assertContainsRe(out, "Description: A message\n")
395+
396+ def test_uses_config_description(self):
397+ config = self.feature_tree.branch.get_config()
398+ config.set_user_option("description", "What this does")
399+ self.feature_tree.commit(message="a message")
400+ (out, err) = self.run_bzr("dep3-patch -d packaging feature")
401+ self.assertContainsRe(out, "Description: What this does\n")
402+
403+ def test_upstream_branch(self):
404+ os.mkdir('packaging/.bzr-builddeb/')
405+ f = open('packaging/.bzr-builddeb/local.conf', 'wb')
406+ try:
407+ f.write('[BUILDDEB]\nupstream-branch = %s\n' %
408+ self.upstream_tree.branch.base)
409+ finally:
410+ f.close()
411+ self.feature_tree.commit(message="a message")
412+ (out, err) = self.run_bzr("dep3-patch -d packaging feature")
413+ self.assertContainsRe(out, "Applied-Upstream: no\n")
414+
415+ def test_upstream_branch_disabled(self):
416+ os.mkdir('packaging/.bzr-builddeb/')
417+ f = open('packaging/.bzr-builddeb/local.conf', 'wb')
418+ try:
419+ f.write('[BUILDDEB]\nupstream-branch = %s\n' %
420+ self.upstream_tree.branch.base)
421+ finally:
422+ f.close()
423+ self.feature_tree.commit(message="a message")
424+ (out, err) = self.run_bzr("dep3-patch --no-upstream-check -d packaging feature")
425+ self.assertNotContainsRe(out, "Applied-Upstream")
426
427=== added file 'tests/test_dep3.py'
428--- tests/test_dep3.py 1970-01-01 00:00:00 +0000
429+++ tests/test_dep3.py 2011-05-08 15:53:28 +0000
430@@ -0,0 +1,217 @@
431+# test_dep3.py -- Testsuite for builddeb dep3.py
432+# Copyright (C) 2011 Canonical Ltd.
433+#
434+# This file is part of bzr-builddeb.
435+#
436+# bzr-builddeb is free software; you can redistribute it and/or modify
437+# it under the terms of the GNU General Public License as published by
438+# the Free Software Foundation; either version 2 of the License, or
439+# (at your option) any later version.
440+#
441+# bzr-builddeb is distributed in the hope that it will be useful,
442+# but WITHOUT ANY WARRANTY; without even the implied warranty of
443+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
444+# GNU General Public License for more details.
445+#
446+# You should have received a copy of the GNU General Public License
447+# along with bzr-builddeb; if not, write to the Free Software
448+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
449+#
450+
451+from cStringIO import StringIO
452+
453+import rfc822
454+
455+from bzrlib.revision import (
456+ NULL_REVISION,
457+ )
458+from bzrlib.tests import (
459+ TestCase,
460+ TestCaseWithTransport,
461+ )
462+
463+from bzrlib.plugins.builddeb.dep3 import (
464+ describe_origin,
465+ determine_applied_upstream,
466+ gather_bugs_and_authors,
467+ write_dep3_bug_line,
468+ write_dep3_patch,
469+ write_dep3_patch_header,
470+ )
471+
472+
473+class Dep3HeaderTests(TestCase):
474+
475+ def dep3_header(self, description=None, origin=None, forwarded=None,
476+ bugs=None, authors=None, revision_id=None, last_update=None,
477+ applied_upstream=None):
478+ f = StringIO()
479+ write_dep3_patch_header(f, description=description, origin=origin,
480+ forwarded=forwarded, bugs=bugs, authors=authors,
481+ revision_id=revision_id, last_update=last_update,
482+ applied_upstream=applied_upstream)
483+ f.seek(0)
484+ return rfc822.Message(f)
485+
486+ def test_description(self):
487+ ret = self.dep3_header(description="This patch fixes the foobar")
488+ self.assertEquals("This patch fixes the foobar", ret["Description"])
489+
490+ def test_last_updated(self):
491+ ret = self.dep3_header(last_update=1304840034)
492+ self.assertEquals("2011-05-08", ret["Last-Update"])
493+
494+ def test_revision_id(self):
495+ ret = self.dep3_header(revision_id="myrevid")
496+ self.assertEquals("myrevid", ret["X-Bzr-Revision-Id"])
497+
498+ def test_authors(self):
499+ authors = [
500+ "Jelmer Vernooij <jelmer@canonical.com>",
501+ "James Westby <james.westby@canonical.com>"]
502+ ret = self.dep3_header(authors=authors)
503+ self.assertEquals([
504+ ("Jelmer Vernooij", "jelmer@canonical.com"),
505+ ("James Westby", "james.westby@canonical.com")],
506+ ret.getaddrlist("Author"))
507+
508+ def test_origin(self):
509+ ret = self.dep3_header(origin="Cherrypick from upstream")
510+ self.assertEquals("Cherrypick from upstream",
511+ ret["Origin"])
512+
513+ def test_forwarded(self):
514+ ret = self.dep3_header(forwarded="not needed")
515+ self.assertEquals("not needed",
516+ ret["Forwarded"])
517+
518+ def test_applied_upstream(self):
519+ ret = self.dep3_header(applied_upstream="commit 45")
520+ self.assertEquals("commit 45", ret["Applied-Upstream"])
521+
522+ def test_bugs(self):
523+ bugs = [
524+ ("http://bugs.debian.org/424242", "fixed"),
525+ ("https://bugs.launchpad.net/bugs/20110508", "fixed"),
526+ ("http://bugzilla.samba.org/bug.cgi?id=52", "fixed")]
527+ ret = self.dep3_header(bugs=bugs)
528+ self.assertEquals([
529+ "https://bugs.launchpad.net/bugs/20110508",
530+ "http://bugzilla.samba.org/bug.cgi?id=52"],
531+ ret.getheaders("Bug"))
532+ self.assertEquals(["http://bugs.debian.org/424242"],
533+ ret.getheaders("Bug-Debian"))
534+
535+ def test_write_bug_fix_only(self):
536+ # non-fixed bug lines are ignored
537+ f = StringIO()
538+ write_dep3_bug_line(f, "http://bar/", "pending")
539+ self.assertEquals("", f.getvalue())
540+
541+ def test_write_normal_bug(self):
542+ f = StringIO()
543+ write_dep3_bug_line(f, "http://bugzilla.samba.org/bug.cgi?id=42",
544+ "fixed")
545+ self.assertEquals("Bug: http://bugzilla.samba.org/bug.cgi?id=42\n",
546+ f.getvalue())
547+
548+ def test_write_debian_bug(self):
549+ f = StringIO()
550+ write_dep3_bug_line(f, "http://bugs.debian.org/234354", "fixed")
551+ self.assertEquals("Bug-Debian: http://bugs.debian.org/234354\n",
552+ f.getvalue())
553+
554+
555+class GatherBugsAndAuthors(TestCaseWithTransport):
556+
557+ def test_none(self):
558+ branch = self.make_branch(".")
559+ self.assertEquals((set(), set(), None),
560+ gather_bugs_and_authors(branch.repository, []))
561+
562+ def test_multiple_authors(self):
563+ tree = self.make_branch_and_tree(".")
564+ revid1 = tree.commit(authors=["Jelmer Vernooij <jelmer@canonical.com>"],
565+ timestamp=1304844311, message="msg")
566+ revid2 = tree.commit(authors=["Max Bowsher <maxb@f2s.com>"],
567+ timestamp=1304844278, message="msg")
568+ self.assertEquals((set(), set([
569+ "Jelmer Vernooij <jelmer@canonical.com>",
570+ "Max Bowsher <maxb@f2s.com>"]), 1304844311),
571+ gather_bugs_and_authors(tree.branch.repository, [revid1, revid2]))
572+
573+ def test_bugs(self):
574+ tree = self.make_branch_and_tree(".")
575+ revid1 = tree.commit(authors=["Jelmer Vernooij <jelmer@canonical.com>"],
576+ timestamp=1304844311, message="msg", revprops={"bugs":
577+ "http://bugs.samba.org/bug.cgi?id=2011 fixed\n"})
578+ self.assertEquals((
579+ set([("http://bugs.samba.org/bug.cgi?id=2011", "fixed")]),
580+ set(["Jelmer Vernooij <jelmer@canonical.com>"]), 1304844311),
581+ gather_bugs_and_authors(tree.branch.repository, [revid1]))
582+
583+
584+class DetermineAppliedUpstreamTests(TestCaseWithTransport):
585+
586+ def test_not_applied(self):
587+ upstream = self.make_branch_and_tree("upstream")
588+ feature = self.make_branch_and_tree("feature")
589+ feature.commit(message="every bloody emperor")
590+ self.addCleanup(feature.lock_read().unlock)
591+ self.assertEquals("no",
592+ determine_applied_upstream(upstream.branch, feature.branch))
593+
594+ def test_merged(self):
595+ upstream = self.make_branch_and_tree("upstream")
596+ upstream.commit(message="initial upstream commit")
597+ feature = upstream.bzrdir.sprout("feature").open_workingtree()
598+ feature.commit(message="nutter alert")
599+ upstream.merge_from_branch(feature.branch)
600+ upstream.commit(message="merge feature")
601+ self.addCleanup(upstream.lock_read().unlock)
602+ self.addCleanup(feature.lock_read().unlock)
603+ self.assertEquals("merged in revision 2",
604+ determine_applied_upstream(upstream.branch, feature.branch))
605+
606+
607+class DescribeOriginTests(TestCaseWithTransport):
608+
609+ def test_no_public_branch(self):
610+ tree = self.make_branch_and_tree(".")
611+ revid1 = tree.commit(message="msg1")
612+ self.assertEquals("commit, revision id: %s" % revid1,
613+ describe_origin(tree.branch, revid1))
614+
615+ def test_public_branch(self):
616+ tree = self.make_branch_and_tree(".")
617+ tree.branch.set_public_branch("http://example.com/public")
618+ revid1 = tree.commit(message="msg1")
619+ self.assertEquals("commit, http://example.com/public, revision: 1",
620+ describe_origin(tree.branch, revid1))
621+
622+
623+class FullDep3PatchTests(TestCaseWithTransport):
624+
625+ def test_simple(self):
626+ f = StringIO()
627+ tree = self.make_branch_and_tree(".")
628+ self.build_tree_contents([("foo", "data")])
629+ tree.add("foo")
630+ revid = tree.commit("msg", rev_id="arevid", timestamp=1304849661,
631+ timezone=0)
632+ write_dep3_patch(f, tree.branch, NULL_REVISION, revid,
633+ description="Nutter alert",
634+ forwarded="not needed",
635+ authors=set(["Jelmer <jelmer@samba.org>"]))
636+ self.assertEquals("Description: Nutter alert\n"
637+ "Forwarded: not needed\n"
638+ "Author: Jelmer <jelmer@samba.org>\n"
639+ "X-Bzr-Revision-Id: arevid\n"
640+ "\n"
641+ "=== added file 'foo'\n"
642+ "--- old/foo\t1970-01-01 00:00:00 +0000\n"
643+ "+++ new/foo\t2011-05-08 10:14:21 +0000\n"
644+ "@@ -0,0 +1,1 @@\n"
645+ "+data\n"
646+ "\\ No newline at end of file\n"
647+ "\n", f.getvalue())

Subscribers

People subscribed via source and target branches