Merge lp:~shypike/trac-launchpad-migrator/bugfixes-custom-mappings into lp:trac-launchpad-migrator

Proposed by shypike
Status: Merged
Approved by: Graham Binns
Approved revision: 21
Merged at revision: not available
Proposed branch: lp:~shypike/trac-launchpad-migrator/bugfixes-custom-mappings
Merge into: lp:trac-launchpad-migrator
Diff against target: 266 lines (+81/-41)
2 files modified
README (+2/-0)
migrate.py (+79/-41)
To merge this branch: bzr merge lp:~shypike/trac-launchpad-migrator/bugfixes-custom-mappings
Reviewer Review Type Date Requested Status
Graham Binns (community) code Approve
Review via email: mp+23046@code.launchpad.net

Description of the change

This change contains:

- Customizable mapping of users and milestones and nickname.

- Add xmlns attribute to <LaunchpadBugs> and <Bug>.

- Prevent crashes when encountering empty Trac fields.

- Convert [[br]] formatting in text fields to newlines.

- Map Trac-type "enhancement" to Lauchpad importance "Wishlist".

- Removed embedded "elisa" project customizations.

To post a comment you must log in.
Revision history for this message
Graham Binns (gmb) wrote :
Download full text (10.4 KiB)

On Thu, Apr 08, 2010 at 06:59:39PM -0000, shypike wrote:
> shypike has proposed merging lp:~shypike/trac-launchpad-migrator/bugfixes-custom-mappings into lp:trac-launchpad-migrator.
>
> Requested reviews:
> Graham Binns (gmb)
>
>
> This change contains:
>
> - Customizable mapping of users and milestones and nickname.
>
> - Add xmlns attribute to <LaunchpadBugs> and <Bug>.
>
> - Prevent crashes when encountering empty Trac fields.
>
> - Convert [[br]] formatting in text fields to newlines.
>
> - Map Trac-type "enhancement" to Lauchpad importance "Wishlist".
>
> - Removed embedded "elisa" project customizations.
>

Hi,

First, thanks for this branch. It's great to have people contributing
their code to this script.

There are a few issues with your branch that need fixing before we can
merge it with trunk. I've pointed these out below. Please reply to this
when you've made the changes I request and pushed them to Launchpad and
I'll happily do the merge for you.

Cheers,

Graham

> === modified file 'README'
> --- README 2009-06-17 14:46:38 +0000
> +++ README 2010-04-08 18:59:38 +0000
> @@ -18,6 +18,8 @@
> Running the migration tool
> --------------------------
>
> +First customize the top part of the migrate.py script for your project.
> +
> To create an XML export of a Trac ticket database, run the following
> command:
>
>
> === modified file 'migrate.py'
> --- migrate.py 2009-10-20 10:31:04 +0000
> +++ migrate.py 2010-04-08 18:59:38 +0000
> @@ -23,12 +23,31 @@
> print "You can install EaseXML by running `easy_install easexml`."
> sys.exit()
>
> -# This can be set to a hostname that will be used to create
> -# email addresses from trac users that only have a username set but not
> -# an email address. It should probably be set to the mailname of the
> +#############################################################################################
> +# Start of customization
> +
> +# This can be set to a hostname that will be used to create
> +# email addresses from trac users that only have a username set but not
> +# an email address. It should probably be set to the mailname of the
> # system that was running the trac instance.
> TRAC_HOSTNAME = None
>
> +
> +# Nickname to be used as a prefix of your TRAC issue numbers
> +# So TRAC bug 123 will result in Nickname-123
> +NICKNAME = 'name'

Thanks for fixing this one; it's been something I've needed to fix but
never got around to.

It's really important that this isn't just left as 'name', so I think it
should be None by default and make the script exit if it hasn't been
changed. What do you think?

> +
> +# Map TRAC aliases to real Lanchpad users
> +USER_ALIAS = {

For the sake of my sanity, this should be USER_ALIASES.

> + 'somebody' : 'user1',
> + 'anonymous' : 'user2',
> +}

Minor niggle, but our coding guidelines state that the closing brace of
a dict should be indented by 4 spacesi [1] (i.e. to line up with the contents
of the dict).

> +
> +# When reporters do not have valid account data
> +# set here which default user to use instead.
> +# If you leave this empty, a warning will be printed and the comment skipped.
> +DEFAULT_REPORTER = 'use...

review: Needs Fixing (code)
Revision history for this message
shypike (shypike) wrote :

>
> There are a few issues with your branch that need fixing before we can
> merge it with trunk. I've pointed these out below. Please reply to this
> when you've made the changes I request and pushed them to Launchpad and
> I'll happily do the merge for you.
>
> Cheers,
>
> Graham
>

Implemented all of your remarks and pushed the changes.
Thanks.

21. By shypike

Implemented all Graham Binns' review remarks.
- Indents
- No default custom dictionaries
- Empty default nickname
- xlmns -> xmlns
- Check on empty nickname
- Check on commandline parms and print "Usage"

Revision history for this message
Graham Binns (gmb) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'README'
2--- README 2009-06-17 14:46:38 +0000
3+++ README 2010-04-09 17:37:32 +0000
4@@ -18,6 +18,8 @@
5 Running the migration tool
6 --------------------------
7
8+First customize the top part of the migrate.py script for your project.
9+
10 To create an XML export of a Trac ticket database, run the following
11 command:
12
13
14=== modified file 'migrate.py'
15--- migrate.py 2009-10-20 10:31:04 +0000
16+++ migrate.py 2010-04-09 17:37:32 +0000
17@@ -23,12 +23,33 @@
18 print "You can install EaseXML by running `easy_install easexml`."
19 sys.exit()
20
21-# This can be set to a hostname that will be used to create
22-# email addresses from trac users that only have a username set but not
23-# an email address. It should probably be set to the mailname of the
24+#############################################################################################
25+# Start of customization
26+
27+# This can be set to a hostname that will be used to create
28+# email addresses from trac users that only have a username set but not
29+# an email address. It should probably be set to the mailname of the
30 # system that was running the trac instance.
31 TRAC_HOSTNAME = None
32
33+
34+# Nickname to be used as a prefix of your TRAC issue numbers
35+# So TRAC bug 123 will result in Nickname-123
36+NICKNAME = ''
37+
38+# Map TRAC aliases to real Lanchpad users
39+#USER_ALIASES = {
40+# 'somebody' : 'user1',
41+# 'anonymous' : 'user2',
42+# }
43+USER_ALIASES = {
44+ }
45+
46+# When reporters do not have valid account data
47+# set here which default user to use instead.
48+# If you leave this empty, a warning will be printed and the comment skipped.
49+DEFAULT_REPORTER = ''
50+
51 # If you have a group of users whose details you already know, include
52 # them in the KNOWN_USERS dict in the following format to save time and
53 # database queries:
54@@ -38,7 +59,25 @@
55 # 'email': 'test@example.com',
56 # },
57 # }
58-KNOWN_USERS = {}
59+KNOWN_USERS = {
60+ }
61+
62+# Create mapping of milestones used in TRAC to milestones you have
63+# defined in Lauchpad.
64+#MILESTONES = {
65+# # TRAC Launchpad
66+# '0.1.0' : '0.1.0' ,
67+# '0.1.1' : '0.1.0' ,
68+# '0.2.0' : '0.2.0' ,
69+# 'future' : ''
70+# }
71+MILESTONES = {
72+ }
73+
74+
75+# End of customization
76+#############################################################################################
77+
78
79 RST_RE = r"""\{\{\{
80 #!rst
81@@ -50,13 +89,6 @@
82 EMAIL_RE = r"^[_\.0-9a-zA-Z-+=]+@(([0-9a-zA-Z-]{1,}\.)*)[a-zA-Z]{2,}$"
83
84
85-class LP(Namespace):
86- uri = 'https://launchpad.net/xmlns/2006/bugs'
87-
88- def getName(self):
89- return ""
90-
91-
92 class Person(XMLObject):
93 _name = 'person'
94 username = StringAttribute(name='name')
95@@ -115,6 +147,7 @@
96 class Bug(XMLObject):
97 _name = 'bug'
98 id = StringAttribute()
99+ xmlns = StringAttribute(default='https://launchpad.net/xmlns/2006/bugs')
100 private = TextNode(optional=True)
101 security_related = TextNode(optional=True)
102 duplicateof = TextNode(optional=True)
103@@ -134,6 +167,7 @@
104 class LaunchpadBugs(XMLObject):
105 _name = 'launchpad-bugs'
106 _prettyPrint = False
107+ xmlns = StringAttribute(default='https://launchpad.net/xmlns/2006/bugs')
108 bugs = ListNode('Bug')
109
110
111@@ -160,8 +194,9 @@
112 self._known_users_by_email[email] = new_data
113
114 def get_user(self, username):
115+ username = USER_ALIASES.get(username, username)
116 user = {}
117- is_email = username.find('@') > -1
118+ is_email = username and username.find('@') > -1
119 if is_email:
120 email = username
121
122@@ -243,6 +278,7 @@
123 trac_priority = ticket['priority']
124 #trac_severity = ticket['severity']
125 trac_resolution = ticket['resolution']
126+ trac_type = ticket['type']
127
128 priority_to_importance = {
129 'high': 'HIGH',
130@@ -255,6 +291,11 @@
131 importance = priority_to_importance.get(
132 trac_priority, 'UNKNOWN')
133
134+ # LP doesn't have Defect/Enhancement distinction,
135+ # so map Enhancement to priority Whishlist
136+ if trac_type == 'enhancement':
137+ importance = 'WISHLIST'
138+
139 if trac_status == 'closed':
140 resolution_to_status = {
141 '': 'NEW',
142@@ -294,7 +335,11 @@
143 # Simply remove the {{{s and }}}s from the text. We don't want to
144 # care too much about blocks right now, so we just remove them.
145 block_re = re.compile('(\{\{\{|\}\}\})\r?\n')
146- return block_re.sub('', text)
147+ text = block_re.sub('', text)
148+
149+ # Convert WikiFormatting for newlines
150+ text = text.replace('[[br]]', '\\n')
151+ return text
152
153
154 def ensure_valid_username(username):
155@@ -304,7 +349,7 @@
156
157 if re.match(valid_name_re, username):
158 # If the name is already valid, return it.
159- return username
160+ return USER_ALIASES.get(username, username)
161
162 # Lowercase the username so that letters aren't treated as invalid.
163 username = username.lower()
164@@ -317,7 +362,7 @@
165 # that it becomes valid.
166 valid_name = valid_name + '1'
167
168- return valid_name
169+ return USER_ALIASES.get(valid_name, valid_name)
170
171
172 def extract_person_fullname(trac_person):
173@@ -370,7 +415,7 @@
174 #reporter_email = trac_reporter.get('email', 'foo@bar.com')
175 reporter_email = extract_person_email(trac_reporter)
176 if not reporter_email:
177- print '[ticket %s] pb with reporter %s' % (bug_id, reporter)
178+ print 'UNMAPPED REPORTER %s in ticket %s' % (reporter, bug_id)
179 return None
180
181 reporter_name = extract_person_fullname(trac_reporter)
182@@ -387,8 +432,7 @@
183 trac_owner = db.get_user(owner)
184 owner_email = extract_person_email(trac_owner)
185 if not owner_email:
186- print '[ticket %s] pb with owner %s' % (bug_id,
187- owner)
188+ print 'UNMAPPED OWNER %s in ticket %s' % (owner, bug_id)
189 return None
190
191 owner_name = extract_person_fullname(trac_owner)
192@@ -416,7 +460,7 @@
193
194 contents = dict(id=str(bug_id),
195 datecreated=datecreated,
196- nickname="elisa-%s" % bug_id,
197+ nickname= "%s-%s" % (NICKNAME, bug_id),
198 title=title,
199 description=description,
200 reporter=lp_reporter,
201@@ -427,23 +471,9 @@
202 contents['assignee'] = assignee
203
204 if milestone:
205- invalid = {'0.0.1 Guadec06 Preview': '0.0.1',
206- '0.0 bugfix': '0.0.1',
207- 'elisa-0.3.3': 'core-0.3.3',
208- 'testing': '',
209- 'elisa-0.3.6': 'core-0.3.6',
210- 'elisa-0.3.4': 'core-0.3.4',
211- 'misc.win32.installer-0.1': '',
212- 'elisa-0.3.5': 'core-0.3.5',
213- }
214- try:
215- milestone = invalid[milestone]
216- except KeyError:
217- pass
218- else:
219- if milestone:
220- milestone = "elisa-%s" % milestone
221- contents['milestone'] = milestone
222+ milestone = MILESTONES.get(milestone.strip())
223+ if milestone:
224+ contents['milestone'] = milestone
225
226 bug = Bug(**contents)
227
228@@ -463,13 +493,14 @@
229 #title = "%s ..." % description[:20]
230
231 reporter = trac_comment['author']
232- if reporter is None:
233- return None
234+ if not reporter:
235+ reporter = DEFAULT_REPORTER
236 trac_reporter = db.get_user(reporter)
237+ if not trac_reporter:
238+ trac_reporter = db.get_user(DEFAULT_REPORTER)
239 reporter_email = extract_person_email(trac_reporter)
240 if not reporter_email:
241- print '[comment %s] pb with comment reporter %s' % (1,
242- reporter)
243+ print 'UNMAPPED COMMENTER %s in comment' % (reporter, )
244 return None
245 reporter_name = extract_person_fullname(trac_reporter)
246 sender = Sender(
247@@ -496,6 +527,10 @@
248 return lp_comment
249
250 def main(args):
251+ if not NICKNAME:
252+ print "ERROR: You must set a nickname"
253+ return 1
254+
255 trac_db = args[0]
256 attachments_dir = args[1]
257 filename = args[2]
258@@ -536,4 +571,7 @@
259 return 0
260
261 if __name__ == '__main__':
262- sys.exit(main(sys.argv[1:]))
263+ if len(sys.argv) < 4:
264+ print 'Usage: ./migrate.py <path/to/trac/db> <path/to/attachments/dir> <output-filename>'
265+ else:
266+ sys.exit(main(sys.argv[1:]))

Subscribers

People subscribed via source and target branches

to all changes: