Merge lp:~lool/launchpad-work-items-tracker/jira-support into lp:~linaro-automation/launchpad-work-items-tracker/linaro

Proposed by Loïc Minier
Status: Merged
Merged at revision: 339
Proposed branch: lp:~lool/launchpad-work-items-tracker/jira-support
Merge into: lp:~linaro-automation/launchpad-work-items-tracker/linaro
Diff against target: 555 lines (+321/-47)
6 files modified
all-projects (+45/-20)
collect (+38/-21)
collect_jira (+229/-0)
collect_roadmap (+5/-3)
jira.py (+4/-2)
utils.py (+0/-1)
To merge this branch: bzr merge lp:~lool/launchpad-work-items-tracker/jira-support
Reviewer Review Type Date Requested Status
Milo Casagrande (community) Approve
Review via email: mp+112136@code.launchpad.net

Description of the change

This adds support for getting cards data out of JIRA instead of kanbantool.com + papyrs.com; it's only active if you set cards_source = 'jira' in the project's config though (so it can be merged and remain inactive). This is deployed in staging and works there, but with some limitations:
* description is taken as text, but it's a mixture of HTML and of JIRA wiki syntax in cards; in the current version of status.linaro.org, description is empty/broken so this isn't a regression but it looks ugly
* "Roadmap card id" currently refers to e.g. CARD-12 instead of some human-readable text like TCWG2012-GDB-FOR-ANDROID; this is stricted and safer, but uglier; also, this comes out of the Meta section, but Данило and I had discussed getting this out of the blueprint specification URL
* there are some missing features like setting the sponsor; relatively minor

Probably fixing the latter requires some DB changes; I'm not sure what rules we operate on for these though, e.g. how does one deploy the schema update?

In general, I consider this is ready for merging, but we can keep this branch open until the above bits are also fixed.

To post a comment you must log in.
340. By Loïc Minier

No need to remap priority names and component names.

Revision history for this message
Milo Casagrande (milo) wrote :

Hello Loic,

thanks for working on this.

On Tue, Jun 26, 2012 at 5:14 PM, Loïc Minier <email address hidden> wrote:
>
> Probably fixing the latter requires some DB changes; I'm not sure what rules we operate on for these though, e.g. how does one deploy the schema update?

WRT this point, I have to collect info too: our knowledge base does not report anything for this situation, and will have to ask Danilo and maybe IS too.

From a rapid PEP8 run, I get these two errors:

collect_jira:5:15: E401 multiple imports on one line
all-projects:77:80: E501 line too long (94 characters)

Apart from those, everything looks good. In case, fix during the merge.
Thanks.

review: Approve
341. By Loïc Minier

Split and sort system imports.

342. By Loïc Minier

Misc PEP8 fixes.

343. By Loïc Minier

Split and sort system imports.

344. By Loïc Minier

Fix a bunch of PEP8 issues.

345. By Loïc Minier

Drop useless imports.

Revision history for this message
Loïc Minier (lool) wrote :

I've now fixed the PEP8 issues you mention and others, thanks! Note that collect_jira was copied from collect_roadmap (kanbantool.com + papyrs.com code) and copied over the syntax problems; now code isn't much repeated, and I also had removed useless imports, but the original syntax layout remained.

One problem with fixing these issues is that it makes the delta with the upstream project larger, but then I don't think we will ever merge back, so...

(I've not fixed all the E501 line too long issues because there were too many of these.)

346. By Loïc Minier

Update sponsor information from JIRA.

347. By Loïc Minier

Set card Size from JIRA timetracking information if available.

348. By Loïc Minier

Wrap card sponsor in unicode().

349. By Loïc Minier

PEP8 line too long fixes.

350. By Loïc Minier

Acceptance criteria is in the description by design.

351. By Loïc Minier

Merge with Linaro branch of workitems tracker which has some independent PEP8
fixes.

Revision history for this message
Loïc Minier (lool) wrote :

I've pushed some further changes to complete support for other fields; what's still missing is support for fetching the description, but need to get beautifulsoup deployed on status.linaro.org to get this done; the other changes can wait and require DB changes.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'all-projects'
--- all-projects 2012-01-30 10:03:24 +0000
+++ all-projects 2012-07-10 16:26:24 +0000
@@ -13,12 +13,19 @@
13import subprocess13import subprocess
14import sys14import sys
1515
16import report_tools
17
1618
17def collect(source_dir, db_file, config_file, extra_args):19def collect(source_dir, db_file, config_file, extra_args):
18 return run_collect_script(source_dir, db_file, config_file, extra_args,20 return run_collect_script(source_dir, db_file, config_file, extra_args,
19 "collect")21 "collect")
2022
2123
24def collect_jira(source_dir, db_file, config_file, extra_args):
25 return run_collect_script(source_dir, db_file, config_file, extra_args,
26 "collect_jira")
27
28
22def collect_roadmap(source_dir, db_file, config_file, extra_args):29def collect_roadmap(source_dir, db_file, config_file, extra_args):
23 return run_collect_script(source_dir, db_file, config_file, extra_args,30 return run_collect_script(source_dir, db_file, config_file, extra_args,
24 "collect_roadmap")31 "collect_roadmap")
@@ -67,7 +74,8 @@
6774
6875
69def main():76def main():
70 parser = optparse.OptionParser(usage="%prog <database dir> <www root dir> [www root url]")77 parser = optparse.OptionParser(
78 usage="%prog <database dir> <www root dir> [www root url]")
71 parser.add_option("--config-dir", dest="config_dir", default="config")79 parser.add_option("--config-dir", dest="config_dir", default="config")
72 parser.add_option("--roadmap-config-file", dest="roadmap_config_file",80 parser.add_option("--roadmap-config-file", dest="roadmap_config_file",
73 default="roadmap-config")81 default="roadmap-config")
@@ -103,6 +111,11 @@
103 os.path.join(source_dir, opts.config_dir, "*%s" % valid_config_suffix))111 os.path.join(source_dir, opts.config_dir, "*%s" % valid_config_suffix))
104112
105 for config_file in filenames:113 for config_file in filenames:
114 # read roadmap config to find where to get cards from
115 cfg = report_tools.load_config(config_file)
116 # default to kanbantool
117 cards_source = cfg.get('cards_source', 'kanban')
118
106 project_name = os.path.basename(config_file)[:-len(valid_config_suffix)]119 project_name = os.path.basename(config_file)[:-len(valid_config_suffix)]
107 project_output_dir = os.path.join(output_dir, project_name)120 project_output_dir = os.path.join(output_dir, project_name)
108 db_file = os.path.join(db_dir, "%s.db" % project_name)121 db_file = os.path.join(db_dir, "%s.db" % project_name)
@@ -127,26 +140,38 @@
127 sys.stderr.write("collect failed for %s" % project_name)140 sys.stderr.write("collect failed for %s" % project_name)
128 continue141 continue
129142
130 extra_collect_roadmap_args = []143 if cards_source == 'jira':
131 extra_collect_roadmap_args.extend(["--board", '10721'])144 extra_collect_jira_args = []
132 if opts.kanban_token_file is not None:145 if not collect_jira(source_dir, db_file, opts.roadmap_config_file,
133 with open(opts.kanban_token_file) as token_file:146 extra_collect_jira_args):
134 token = token_file.read()147 sys.stderr.write("collect_jira failed for %s" % project_name)
135 extra_collect_roadmap_args.extend(["--kanbantoken", token])148 continue
136 else:149 elif cards_source == 'kanban':
137 sys.stderr.write("No Kanbantool API token given to "150 extra_collect_roadmap_args = []
138 "collect_roadmap for %s" % project_name)151 extra_collect_roadmap_args.extend(["--board", '10721'])
139 if opts.papyrs_token_file is not None:152 if opts.kanban_token_file is not None:
140 with open(opts.papyrs_token_file) as token_file:153 with open(opts.kanban_token_file) as token_file:
141 token = token_file.read()154 token = token_file.read()
142 extra_collect_roadmap_args.extend(["--papyrstoken", token])155 extra_collect_roadmap_args.extend(["--kanbantoken", token])
143 else:156 else:
144 sys.stderr.write("No Papyrs API token given to "157 sys.stderr.write("No Kanbantool API token given to "
145 "collect_roadmap for %s" % project_name)158 "collect_roadmap for %s" % project_name)
159 if opts.papyrs_token_file is not None:
160 with open(opts.papyrs_token_file) as token_file:
161 token = token_file.read()
162 extra_collect_roadmap_args.extend(["--papyrstoken", token])
163 else:
164 sys.stderr.write("No Papyrs API token given to "
165 "collect_roadmap for %s" % project_name)
146166
147 if not collect_roadmap(source_dir, db_file, opts.roadmap_config_file,167 if not collect_roadmap(source_dir, db_file,
148 extra_collect_roadmap_args):168 opts.roadmap_config_file,
149 sys.stderr.write("collect_roadmap failed for %s" % project_name)169 extra_collect_roadmap_args):
170 sys.stderr.write("collect_roadmap failed for %s" %
171 project_name)
172 else:
173 sys.stderr.write("Unknown cards source %s" % cards_source)
174 continue
150175
151 publish_new_db(project_name, project_output_dir, db_file)176 publish_new_db(project_name, project_output_dir, db_file)
152 generate_reports(project_output_dir, config_file, db_file,177 generate_reports(project_output_dir, config_file, db_file,
153178
=== modified file 'collect'
--- collect 2012-06-29 14:04:58 +0000
+++ collect 2012-07-10 16:26:24 +0000
@@ -6,15 +6,16 @@
6# Copyright (C) 2010, 2011 Canonical Ltd.6# Copyright (C) 2010, 2011 Canonical Ltd.
7# License: GPL-37# License: GPL-3
88
9import urllib9import logging
10import optparse
11import os
12import pwd
10import re13import re
14import smtplib
11import sys15import sys
12import optparse16import urllib
13import smtplib
14import pwd
15import os
16import urlparse17import urlparse
17import logging18
18from email.mime.text import MIMEText19from email.mime.text import MIMEText
1920
20from launchpadlib.launchpad import Launchpad, EDGE_SERVICE_ROOT21from launchpadlib.launchpad import Launchpad, EDGE_SERVICE_ROOT
@@ -23,8 +24,8 @@
23 CollectorStore,24 CollectorStore,
24 PersonCache,25 PersonCache,
25 WorkitemParser,26 WorkitemParser,
26 bug_wi_states27 bug_wi_states,
27)28 )
28from lpworkitems.database import get_store29from lpworkitems.database import get_store
29from lpworkitems.error_collector import (30from lpworkitems.error_collector import (
30 BlueprintURLError,31 BlueprintURLError,
@@ -71,11 +72,13 @@
71 """Get a link to the Launchpad API object on the website."""72 """Get a link to the Launchpad API object on the website."""
72 api_link = item.self_link73 api_link = item.self_link
73 parts = urlparse.urlparse(api_link)74 parts = urlparse.urlparse(api_link)
74 link = parts.scheme + "://" + parts.netloc.replace("api.", "") + "/" + parts.path.split("/", 2)[2]75 link = parts.scheme + "://" + parts.netloc.replace("api.", "") + \
76 "/" + parts.path.split("/", 2)[2]
75 return link.decode("utf-8")77 return link.decode("utf-8")
7678
7779
78import simplejson80import simplejson
81
79_orig_loads = simplejson.loads82_orig_loads = simplejson.loads
8083
8184
@@ -103,7 +106,10 @@
103 '''106 '''
104 model_bp = Blueprint.from_launchpad(bp)107 model_bp = Blueprint.from_launchpad(bp)
105 if model_bp.milestone_name not in collector.valid_milestone_names():108 if model_bp.milestone_name not in collector.valid_milestone_names():
106 data_error(web_link(bp), 'milestone "%s" is unknown/invalid' % model_bp.milestone_name, True)109 data_error(
110 web_link(bp),
111 'milestone "%s" is unknown/invalid' % model_bp.milestone_name,
112 True)
107 model_bp = collector.store_blueprint(model_bp)113 model_bp = collector.store_blueprint(model_bp)
108 if model_bp:114 if model_bp:
109 dbg('lp_import_blueprint: added blueprint: %s' % bp.name)115 dbg('lp_import_blueprint: added blueprint: %s' % bp.name)
@@ -123,7 +129,10 @@
123 model_group = BlueprintGroup.from_launchpad(bp)129 model_group = BlueprintGroup.from_launchpad(bp)
124 model_group.area = area130 model_group.area = area
125 if model_group.milestone_name not in collector.valid_milestone_names():131 if model_group.milestone_name not in collector.valid_milestone_names():
126 data_error(web_link(bp), 'milestone "%s" is unknown/invalid' % model_group.milestone, True)132 data_error(
133 web_link(bp),
134 'milestone "%s" is unknown/invalid' % model_group.milestone,
135 True)
127136
128 model_group = collector.store_blueprint_group(model_group)137 model_group = collector.store_blueprint_group(model_group)
129 if model_group is None:138 if model_group is None:
@@ -154,7 +163,8 @@
154 collector.store_meta(key, value, bp_name)163 collector.store_meta(key, value, bp_name)
155164
156165
157def parse_complexity_item(collector, line, bp_name, bp_url, def_milestone, def_assignee):166def parse_complexity_item(collector, line, bp_name, bp_url, def_milestone,
167 def_assignee):
158 line = line.strip()168 line = line.strip()
159 # remove special characters people tend to type169 # remove special characters people tend to type
160 line = re.sub('[^\w -.]', '', line)170 line = re.sub('[^\w -.]', '', line)
@@ -183,7 +193,9 @@
183 dbg('\tComplexity: %s MS: %s Who: %s' % (num, milestone, assignee))193 dbg('\tComplexity: %s MS: %s Who: %s' % (num, milestone, assignee))
184 collector.store_complexity(assignee, num, milestone, bp_name)194 collector.store_complexity(assignee, num, milestone, bp_name)
185 except ValueError:195 except ValueError:
186 data_error(bp_url, "\tComplexity line '%s' could not be parsed %s" % (line, ValueError))196 data_error(bp_url,
197 "\tComplexity line '%s' could not be parsed %s" %
198 (line, ValueError))
187199
188200
189def milestone_extract(text, valid_milestones):201def milestone_extract(text, valid_milestones):
@@ -196,7 +208,7 @@
196 return None208 return None
197209
198210
199def lp_import_blueprint_workitems(collector, bp, distro_release, people_cache=None, projects=None):211def lp_import_blueprint_workitems(collector, bp, distro_release,
200 '''Collect work items from a Launchpad blueprint.212 '''Collect work items from a Launchpad blueprint.
201213
202 This includes work items from the whiteboard as well as linked bugs.214 This includes work items from the whiteboard as well as linked bugs.
@@ -212,17 +224,19 @@
212224
213 model_bp = collector.store.find(225 model_bp = collector.store.find(
214 Blueprint, Blueprint.name == bp.name).one()226 Blueprint, Blueprint.name == bp.name).one()
215 assert model_bp is not None, "Asked to process workitems of %s when it is not in the db" % bp.name227 assert model_bp is not None, \
228 "Asked to process workitems of %s when it is not in the db" % bp.name
216229
217 dbg('lp_import_blueprint_workitems(): processing %s (spec milestone: %s, spec assignee: %s, spec implementation: %s)' % (230 dbg('lp_import_blueprint_workitems(): processing %s (spec milestone: %s,' \
231 ' spec assignee: %s, spec implementation: %s)' % (
218 bp.name, model_bp.milestone_name, model_bp.assignee_name,232 bp.name, model_bp.milestone_name, model_bp.assignee_name,
219 model_bp.implementation))233 model_bp.implementation))
220234
221 valid_milestones = collector.valid_milestone_names()235 valid_milestones = collector.valid_milestone_names()
222 global error_collector236 global error_collector
223 parser = WorkitemParser(237 parser = WorkitemParser(
224 model_bp, model_bp.milestone_name, collector.lp, people_cache=people_cache,238 model_bp, model_bp.milestone_name, collector.lp,
225 error_collector=error_collector)239 people_cache=people_cache, error_collector=error_collector)
226240
227 # Get work items from both the whiteboard and the new workitems_text241 # Get work items from both the whiteboard and the new workitems_text
228 # property. Once the migration is completed and nobody's using the242 # property. Once the migration is completed and nobody's using the
@@ -239,16 +253,19 @@
239 m = work_items_re.search(l)253 m = work_items_re.search(l)
240 if m:254 if m:
241 in_workitems_block = True255 in_workitems_block = True
242 dbg('lp_import_blueprint_workitems(): starting work items block at ' + l)256 dbg('lp_import_blueprint_workitems():'
257 ' starting work items block at ' + l)
243 milestone = milestone_extract(m.group(1), valid_milestones)258 milestone = milestone_extract(m.group(1), valid_milestones)
244 dbg(' ... setting milestone to ' + str(milestone))259 dbg(' ... setting milestone to ' + str(milestone))
245 parser.milestone_name = milestone or parser.blueprint.milestone_name260 parser.milestone_name = \
261 milestone or parser.blueprint.milestone_name
246 continue262 continue
247263
248 if in_workitems_block:264 if in_workitems_block:
249 dbg("\tworkitem (raw): '%s'" % (l.strip()))265 dbg("\tworkitem (raw): '%s'" % (l.strip()))
250 if not l.strip():266 if not l.strip():
251 dbg('lp_import_blueprint_workitems(): closing work items block with line: ' + l)267 dbg('lp_import_blueprint_workitems():'
268 ' closing work items block with line: ' + l)
252 in_workitems_block = False269 in_workitems_block = False
253 parser.milestone_name = parser.blueprint.milestone_name270 parser.milestone_name = parser.blueprint.milestone_name
254 workitem = parser.parse_blueprint_workitem(l)271 workitem = parser.parse_blueprint_workitem(l)
255272
=== added file 'collect_jira'
--- collect_jira 1970-01-01 00:00:00 +0000
+++ collect_jira 2012-07-10 16:26:24 +0000
@@ -0,0 +1,229 @@
1#!/usr/bin/python
2#
3# Pull items from cards.linaro.org and put them into a database.
4
5import logging
6import optparse
7import os
8import simplejson
9import sys
10import urllib2
11
12import jira
13from lpworkitems.collect_roadmap import (
14 CollectorStore,
15 )
16from lpworkitems.database import get_store
17from lpworkitems.error_collector import (
18 ErrorCollector,
19 StderrErrorCollector,
20 )
21from lpworkitems.models_roadmap import (
22 Lane,
23 Card,
24 )
25import report_tools
26
27
28# An ErrorCollector to collect the data errors for later reporting
29error_collector = None
30
31
32logger = logging.getLogger("linarojira")
33
34JIRA_API_URL = 'http://cards.linaro.org/rest/api/2'
35JIRA_PROJECT_KEY = 'CARD'
36JIRA_ISSUE_BY_KEY_URL = 'http://cards.linaro.org/browse/%s'
37
38
39def dbg(msg):
40 '''Print out debugging message if debugging is enabled.'''
41 logger.debug(msg)
42
43
44def get_json_data(url):
45 data = None
46 try:
47 data = simplejson.load(urllib2.urlopen(url))
48 except urllib2.HTTPError, e:
49 print "HTTP error for url '%s': %d" % (url, e.code)
50 except urllib2.URLError, e:
51 print "Network error for url '%s': %s" % (url, e.reason.args[1])
52 except ValueError, e:
53 print "Data error for url '%s': %s" % (url, e.args[0])
54
55 return data
56
57
58def jira_import(collector, cfg, opts):
59 '''Collect roadmap items from JIRA into DB.'''
60
61 # import JIRA versions as database Lanes
62 result = jira.do_request(opts, 'project/%s/versions' % JIRA_PROJECT_KEY)
63 for version in result:
64 dbg('Adding lane (name = %s, id = %s)' %
65 (version['name'], version['id']))
66 model_lane = Lane(unicode(version['name']), int(version['id']))
67 if model_lane.name == cfg['current_lane']:
68 model_lane.is_current = True
69 else:
70 model_lane.is_current = False
71 collector.store_lane(model_lane)
72
73 # find id of "Sponsor" custom field in JIRA
74 result = jira.do_request(opts, 'field')
75 sponsor_fields = [field for field in result if field['name'] == 'Sponsor']
76 assert len(sponsor_fields) == 1, 'Not a single Sponsor field'
77 sponsor_field_id = sponsor_fields[0]['id']
78
79 # import JIRA issues as database Cards
80 result = jira.do_request(
81 opts, 'search', jql='project = %s' % JIRA_PROJECT_KEY,
82 fields=['summary', 'fixVersions', 'status', 'components',
83 'priority', 'description', 'timetracking', sponsor_field_id])
84 for issue in result['issues']:
85 fields = issue['fields']
86 name = unicode(fields['summary'])
87 card_id = int(issue['id'])
88 key = unicode(issue['key'])
89 fixVersions = fields['fixVersions']
90 if len(fixVersions) == 0:
91 dbg('Skipping card without lane (name = %s, key = %s)' %
92 (name, key))
93 continue
94 # JIRA allows listing multiple versions in fixVersions
95 assert len(fixVersions) == 1
96 lane_id = int(fixVersions[0]['id'])
97
98 dbg('Adding card (name = %s, id = %s, lane_id = %s, key = %s)' %
99 (name, card_id, lane_id, key))
100 model_card = Card(name, card_id, lane_id, key)
101 model_card.status = unicode(fields['status']['name'])
102 components = fields['components']
103 if len(components) == 0:
104 dbg('Skipping card without component (name = %s, key = %s)' %
105 (name, key))
106 # JIRA allows listing multiple components
107 assert len(components) == 1
108 model_card.team = unicode(components[0]['name'])
109 model_card.priority = unicode(fields['priority']['name'])
110 size_fields = []
111 timetracking = fields['timetracking']
112 if 'originalEstimate' in timetracking:
113 size_fields += [
114 'original estimate: %s' % timetracking['originalEstimate']]
115 if 'remainingEstimate' in timetracking:
116 size_fields += [
117 'remaining estimate: %s' % timetracking['remainingEstimate']]
118 model_card.size = unicode(', '.join(size_fields))
119 model_card.sponsor = u''
120 # None if no sponsor is selected
121 if fields[sponsor_field_id] is not None:
122 sponsors = [s['value'] for s in fields[sponsor_field_id]]
123 model_card.sponsor = unicode(', '.join(sorted(sponsors)))
124 model_card.url = JIRA_ISSUE_BY_KEY_URL % key
125 # XXX need to either download the HTML version or convert this to HTML
126 model_card.description = unicode(fields['description'])
127 # acceptance criteria is in the description
128 model_card.acceptance_criteria = u''
129 collector.store_card(model_card)
130 return
131
132########################################################################
133#
134# Program operations and main
135#
136########################################################################
137
138
139def parse_argv():
140 '''Parse CLI arguments.
141
142 Return (options, args) tuple.
143 '''
144 optparser = optparse.OptionParser()
145 optparser.add_option('-d', '--database',
146 help='Path to database', dest='database', metavar='PATH')
147 optparser.add_option('-c', '--config',
148 help='Path to configuration file', dest='config', metavar='PATH')
149 optparser.add_option('--debug', action='store_true', default=False,
150 help='Enable debugging output in parsing routines')
151 optparser.add_option('--mail', action='store_true', default=False,
152 help='Send data errors as email (according to "error_config" map in '
153 'config file) instead of printing to stderr', dest='mail')
154 optparser.add_option('--jira-username', default='robot',
155 help='JIRA username for authentication', dest='jira_username')
156 optparser.add_option('--jira-password', default='cuf4moh2',
157 help='JIRA password for authentication', dest='jira_password')
158
159 (opts, args) = optparser.parse_args()
160
161 if not opts.database:
162 optparser.error('No database given')
163 if not opts.config:
164 optparser.error('No config given')
165
166 return opts, args
167
168
169def setup_logging(debug):
170 ch = logging.StreamHandler()
171 ch.setLevel(logging.INFO)
172 formatter = logging.Formatter("%(message)s")
173 ch.setFormatter(formatter)
174 logger.setLevel(logging.INFO)
175 logger.addHandler(ch)
176 if debug:
177 ch.setLevel(logging.DEBUG)
178 formatter = logging.Formatter(
179 "%(asctime)s - %(name)s - %(levelname)s - %(message)s")
180 ch.setFormatter(formatter)
181 logger.setLevel(logging.DEBUG)
182
183
184def update_todays_blueprint_daily_count_per_state(collector):
185 """Clear today's entries and create them again to reflect the current
186 state of blueprints."""
187 collector.clear_todays_blueprint_daily_count_per_state()
188 collector.store_roadmap_bp_count_per_state()
189
190
191def main():
192 report_tools.fix_stdouterr()
193
194 (opts, args) = parse_argv()
195 opts.jira_api_url = JIRA_API_URL
196
197 setup_logging(opts.debug)
198
199 global error_collector
200 if opts.mail:
201 error_collector = ErrorCollector()
202 else:
203 error_collector = StderrErrorCollector()
204
205 cfg = report_tools.load_config(opts.config)
206
207 lock_path = opts.database + ".lock"
208 lock_f = open(lock_path, "wb")
209 if report_tools.lock_file(lock_f) is None:
210 print "Another instance is already running"
211 sys.exit(0)
212
213 store = get_store(opts.database)
214 collector = CollectorStore(store, '', error_collector)
215
216 collector.clear_lanes()
217 collector.clear_cards()
218
219 jira_import(collector, cfg, opts)
220
221 update_todays_blueprint_daily_count_per_state(collector)
222
223 store.commit()
224
225 os.unlink(lock_path)
226
227
228if __name__ == '__main__':
229 main()
0230
=== modified file 'collect_roadmap'
--- collect_roadmap 2012-01-30 12:08:06 +0000
+++ collect_roadmap 2012-07-10 16:26:24 +0000
@@ -2,10 +2,12 @@
2#2#
3# Pull items from the Linaro roadmap in Kanbantool and put them into a database.3# Pull items from the Linaro roadmap in Kanbantool and put them into a database.
44
5import urllib2, re, sys, optparse, smtplib, pwd, os5import logging
6import optparse
7import os
6import simplejson8import simplejson
7import logging9import sys
8from email.mime.text import MIMEText10import urllib2
911
10from lpworkitems.collect_roadmap import (12from lpworkitems.collect_roadmap import (
11 CollectorStore,13 CollectorStore,
1214
=== modified file 'jira.py'
--- jira.py 2012-05-14 11:39:09 +0000
+++ jira.py 2012-07-10 16:26:24 +0000
@@ -6,6 +6,7 @@
6import simplejson6import simplejson
7import urllib27import urllib2
88
9
9def do_request(opts, relpathname, **kwargs):10def do_request(opts, relpathname, **kwargs):
10 request = urllib2.Request('%s/%s' % (opts.jira_api_url, relpathname))11 request = urllib2.Request('%s/%s' % (opts.jira_api_url, relpathname))
11 if opts.jira_username and opts.jira_password:12 if opts.jira_username and opts.jira_password:
@@ -20,6 +21,7 @@
20 response_data = urllib2.urlopen(request, request_data)21 response_data = urllib2.urlopen(request, request_data)
21 return simplejson.load(response_data)22 return simplejson.load(response_data)
2223
24
23def main():25def main():
24 parser = optparse.OptionParser(usage="%prog")26 parser = optparse.OptionParser(usage="%prog")
25 parser.add_option("--jira-api-url", dest="jira_api_url",27 parser.add_option("--jira-api-url", dest="jira_api_url",
@@ -31,7 +33,8 @@
31 opts, args = parser.parse_args()33 opts, args = parser.parse_args()
3234
33 # simple search35 # simple search
34 print do_request(opts, 'search', maxResults=1, jql='project = CARD', fields=['summary', 'status'])36 print do_request(opts, 'search', maxResults=1, jql='project = CARD',
37 fields=['summary', 'status'])
3538
36 # information about a project39 # information about a project
37 #print do_request(opts, 'project/CARD')40 #print do_request(opts, 'project/CARD')
@@ -50,4 +53,3 @@
5053
51if __name__ == "__main__":54if __name__ == "__main__":
52 main()55 main()
53
5456
=== modified file 'utils.py'
--- utils.py 2011-09-12 14:41:07 +0000
+++ utils.py 2012-07-10 16:26:24 +0000
@@ -4,4 +4,3 @@
4 if isinstance(attr, unicode):4 if isinstance(attr, unicode):
5 return attr5 return attr
6 return attr.decode("utf-8")6 return attr.decode("utf-8")
7

Subscribers

People subscribed via source and target branches