Merge lp:~jelmer/lptools/migrate-set-dup into lp:lptools

Proposed by Jelmer Vernooij
Status: Merged
Merged at revision: 18
Proposed branch: lp:~jelmer/lptools/migrate-set-dup
Merge into: lp:lptools
Diff against target: 127 lines (+123/-0)
1 file modified
bin/lp-set-dup (+123/-0)
To merge this branch: bzr merge lp:~jelmer/lptools/migrate-set-dup
Reviewer Review Type Date Requested Status
lptools Hackers Pending
Review via email: mp+69086@code.launchpad.net

Description of the change

Import the generic lp-set-dup tool from ubuntu-dev-tools.

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'bin/lp-set-dup'
2--- bin/lp-set-dup 1970-01-01 00:00:00 +0000
3+++ bin/lp-set-dup 2011-07-25 13:54:31 +0000
4@@ -0,0 +1,123 @@
5+#!/usr/bin/python
6+# -*- coding: UTF-8 -*-
7+"""Sets the "duplicate of" bug of a bug and its dups."""
8+
9+# Copyright (c) 2009 Canonical Ltd.
10+#
11+# lp-set-dup is free software; you can redistribute it and/or modify it
12+# under the terms of the GNU General Public License as published by the
13+# Free Software Foundation; either version 3, or (at your option) any
14+# later version.
15+#
16+# lp-set-dup is distributed in the hope that it will be useful, but
17+# WITHOUT ANY WARRANTY; without even the implied warranty of
18+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19+# General Public License for more details.
20+#
21+# You should have received a copy of the GNU General Public License
22+# along with lp-set-dup; see the file COPYING. If not, write to the Free
23+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
24+# 02110-1301, USA.
25+#
26+# Authors:
27+# Loïc Minier <lool@dooz.org>
28+
29+import sys
30+from optparse import OptionParser
31+
32+from launchpadlib.launchpad import Launchpad
33+from launchpadlib.errors import HTTPError
34+
35+from lptools import config
36+
37+from ubuntutools.config import UDTConfig
38+
39+def die(message):
40+ print >> sys.stderr, "Fatal: " + message
41+ sys.exit(1)
42+
43+def main():
44+ usage = "Usage: %prog [-f] <new main bug> <bug to dup> [<bug to dup>...]"
45+ opt_parser = OptionParser(usage)
46+ opt_parser.add_option("-f",
47+ help="Skip confirmation prompt",
48+ dest="force", default=False, action="store_true")
49+ opt_parser.add_option("-l", "--lpinstance", metavar="INSTANCE",
50+ help="Launchpad instance to connect to "
51+ "(default: production)",
52+ dest="lpinstance", default=None)
53+ opt_parser.add_option("--no-conf",
54+ help="Don't read config files or "
55+ "environment variables.",
56+ dest="no_conf", default=False, action="store_true")
57+ (options, args) = opt_parser.parse_args()
58+
59+ if len(args) < 2:
60+ opt_parser.error("Need at least a new main bug and a bug to dup")
61+
62+ launchpad = config.get_launchpad("set-dup")
63+
64+ # check that the new main bug isn't a duplicate
65+ try:
66+ new_main_bug = launchpad.bugs[args[0]]
67+ except HTTPError, error:
68+ if error.response.status == 401:
69+ print >> sys.stderr, ("E: Don't have enough permissions to access "
70+ "bug %s") % (args[0])
71+ die(error.content)
72+ else:
73+ raise
74+ new_main_dup_of = new_main_bug.duplicate_of
75+ if new_main_dup_of is not None:
76+ answer = None
77+ try:
78+ answer = raw_input("Bug %s is a duplicate of %s; would you like to "
79+ "use %s as the new main bug instead? [y/N]" % \
80+ (new_main_bug.id, new_main_dup_of.id,
81+ new_main_dup_of.id))
82+ except:
83+ die("Aborted")
84+ if answer.lower() not in ("y", "yes"):
85+ die("User aborted")
86+ new_main_bug = new_main_dup_of
87+
88+ # build list of bugs to process, first the dups then the bug
89+ bugs_to_process = []
90+ for bug_number in args[1:]:
91+ print "Processing %s" % (bug_number)
92+ try:
93+ bug = launchpad.bugs[bug_number]
94+ except HTTPError, error:
95+ if error.response.status == 401:
96+ print >> sys.stderr, ("W: Don't have enough permissions to "
97+ "access bug %s") % (bug_number)
98+ print >> sys.stderr, "W: %s" % (error.content)
99+ continue
100+ else:
101+ raise
102+ dups = bug.duplicates
103+ if dups is not None:
104+ bugs_to_process.extend(dups)
105+ print "Found %i dups for %s" % (len(dups), bug_number)
106+ bugs_to_process.append(bug)
107+
108+ # process dups first, then their main bug
109+ print "Would set the following bugs as duplicates of %s: %s" % \
110+ (new_main_bug.id, " ".join([str(b.id) for b in bugs_to_process]))
111+
112+ if not options.force:
113+ answer = None
114+ try:
115+ answer = raw_input("Proceed? [y/N]")
116+ except:
117+ die("Aborted")
118+ if answer.lower() not in ("y", "yes"):
119+ die("User aborted")
120+
121+ for bug in bugs_to_process:
122+ print "Marking bug %s as a duplicate of %s" % (bug.id, new_main_bug.id)
123+ bug.duplicate_of = new_main_bug
124+ bug.lp_save()
125+
126+if __name__ == '__main__':
127+ main()

Subscribers

People subscribed via source and target branches