My favorites | Sign in
Project Home Downloads Issues Source
Repository:
Checkout   Browse   Changes   Clones    
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#!/usr/bin/python
#
# Copyright 2011 James Purser, Christian Ohler, Michael MacFadden
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


""" This script imports issues from Code.Google and builds a csv file.
The intent is to imported the csv file into JIRA.

In order to run the script you will need the following library:

GData: http://code.google.com/p/gdata-python-client/"""

import gdata.projecthosting.client
import os

""" Configuration Values """

project_name = "wave-protocol"
export_file_name = "exported_issues.csv"

"""Mappings between Google Code Values and Jira Values"""
types = {}
types["Defect"] = "Bug"
types["Enhancement"] = "Improvemnet"
types["Patch"] = "Bug"
types["Review"] = "Bug"
types["Task"] = "Task"

priorities = {}
priorities["Critical"] = "Critical"
priorities["High"] = "Major"
priorities["Medium"] = "Minor"
priorities["Low"] = "Trivial"

statuses = {}
statuses["New"] = "Open"
statuses["Accepted"] = "Open"
statuses["Started"] = "In Progress"
statuses["Fixed"] = "Closed"
statuses["Invalid"] = "Closed"
statuses["Duplicate"] = "Closed"
statuses["WontFix"] = "Closed"

resolutions = {}
resolutions["New"] = ""
resolutions["Accepted"] = ""
resolutions["Started"] = ""
resolutions["Fixed"] = "Fixed"
resolutions["Invalid"] = "Invalid"
resolutions["Duplicate"] = "Duplicate"
resolutions["WontFix"] = "Won't Fix"

""" Helper Functions """

def get_comments(issue_id):
comments = []
while True:
comments_query = gdata.projecthosting.client.Query(start_index=len(comments) + 1)
comments_feed = hosting_client.get_comments(project_name, issue_id, query=comments_query)
if not comments_feed.entry:
break
comments.extend(comments_feed.entry)

comments_text = ""

if len(comments) > 0:
for comment in comments:
if len(comments_text) > 0:
comments_text += "---\n"
comments_text += "%s:\n%s\n\n" % (comment.title.text, comment.content.text)
updates = comment.updates
if updates:
if updates.summary:
comments_text += "Summary: %s\n\n" % updates.summary.text
if updates.status:
comments_text += "Status: %s\n\n" % updates.status.text
if updates.ownerUpdate:
comments_text += "OwnerUpdate: %s\n\n" % updates.ownerUpdate.text
for label in updates.label:
comments_text += "Label: %s\n\n" % label.text
for ccUpdate in updates.ccUpdate:
comments_text += "CcUpdate: %s\n\n" % ccUpdate.text
return comments_text

def escape(s):
return '"' + s.encode('utf-8').replace('"', '""') + '"'

def get_id(issue):
return issue.get_id().split('/')[-1]

def get_link(issue):
return "http://code.google.com/p/%s/issues/detail?id=%s" % (project_name, get_id(issue))

def get_description(issue):
# TODO: The content seems to be HTML, I'm not sure if that's what JIRA expects.
description = issue.content.text
description += "\n\n---\nIssue imported from %s\n\n" % issue_link
if issue.owner:
description += "Owner: %s\n" % issue.owner.username.text
for cc in issue.cc:
description += "Cc: %s\n" % cc.username.text
for label in issue.label:
description += "Label: %s\n" % label.text
if issue.stars:
description += "Stars: %s\n" % issue.stars.text
if issue.state:
description += "State: %s\n" % issue.state.text
if issue.status:
description += "Status: %s\n" % issue.status.text
return description

def convert_value(list,value):
if len(value) > 0:
return list[value]
else:
return ""

""" Export Process """

hosting_client = gdata.projecthosting.client.ProjectHostingClient()
export_file = open(export_file_name, "w")

# First row with column titles
export_file.write("Id,Summary,Issue Type,Priority,Status,Resolution,Description,Comment Body\n")

print "Exporting issues to: " + os.path.abspath(export_file_name)

issues_total = 0
while True:
issues_query = gdata.projecthosting.client.Query(start_index=issues_total + 1)
issues_feed = hosting_client.get_issues(project_name, query=issues_query)
if not issues_feed.entry:
break
for issue in issues_feed.entry:
issue_id = get_id(issue)
issue_link = get_link(issue)
print "Exporting Issue %s: %s" % (issue_id, issue_link)

# Append one row per issue

# Id, e.g. http://code.google.com/feeds/issues/p/wave-protocol/issues/full/1
row = escape(issue_id) + ","

# Title
row += escape(issue.title.text) + ","

# Fetch the type and priority from the labels
# There are any number of labels, but we are only interested in two. Namely
# Type-* and Priority-*
type = "";
priority = "";
for label in issue.label:
if label.text.startswith("Type-"):
type = label.text[5:]
elif label.text.startswith("Priority-"):
priority = label.text[9:]
row += escape(convert_value(types,type)) + ","
row += escape(convert_value(priorities,priority)) + ","

# Google Code only has the concept of status, while Jira has status and resolution.
# Status, e.g. Open or Closed
row += escape(convert_value(statuses,issue.status.text)) + ","
# Status, e.g. Fixed, Invalid, etc
row += escape(convert_value(resolutions,issue.status.text)) + ","

# Fetch the description text
description = get_description(issue)
row += escape(description) + ","

# Fetch all the comments and put them in a single column
comments = get_comments(issue_id)
row += escape(comments)

export_file.write(row + "\n")
issues_total += len(issues_feed.entry)

export_file.close()
print "\n%s issues exported" % issues_total

Change log

68673178bbc4 by Michael MacFadden <michael.macfadden> on Apr 23, 2011   Diff
- The id was shortened to simply the issue
Id number from the url.
- The columns were re-ordered and renamed
to line up with how Jira typically orders
them.
- The comments from the google code issue
were moved from the description to a
single comment column.
  This way the comments will appear as a
single comment in the Jira issue.
- The handling of the labels was enhanced
to specifically look for the priority and
...
Go to: 
Sign in to write a code review

Older revisions

220f3170df43 by Michael MacFadden <michael.macfadden> on Apr 22, 2011   Diff
Updated the issue_exporter.py script
to handle the type and priority labels
more flexibly.
3bd95fb6ce5b by oh...@google.com on Apr 22, 2011   Diff
issue_exporter: Get all issues, not
just 25, and embed the comments in the
description rather than dropping them.

Also assert that there are exactly 2
...
af9b90b4ed4b by so...@google.com on Mar 16, 2011   Diff
Tweaked James's Issue Exporter code.
All revisions of this file

File info

Size: 6315 bytes, 190 lines
Powered by Google Project Hosting