blob: ba250e32acb9eddf5b89cf9bc319671d422b643d [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
import os
import sys
import urllib
import urllib2
import urlparse
import hmac
import hashlib
import json
from optparse import OptionParser
from pprint import pprint
from datetime import datetime
from allura.lib.import_api import AlluraImportApiClient
def main():
optparser, options, args = parse_options()
import_options = {}
for s in options.import_opts:
k, v = s.split('=', 1)
if v == 'false':
v = False
import_options[k] = v
user_map = {}
if options.user_map_file:
f = open(options.user_map_file)
try:
user_map = json.load(f)
if type(user_map) is not type({}):
raise ValueError
for k, v in user_map.iteritems():
print k, v
if not isinstance(k, basestring) or not isinstance(v, basestring):
raise ValueError
except ValueError:
optparser.error('--user-map should specify JSON file with format {"original_user": "sf_user", ...}')
finally:
f.close()
import_options['user_map'] = user_map
cli = AlluraImportApiClient(options.base_url, options.api_key, options.secret_key, options.verbose)
doc_txt = open(args[0]).read()
# import the tracker (if any)
if options.tracker:
import_tracker(cli, options.project, options.tracker, import_options, options, doc_txt,
validate=options.validate,
verbose=options.verbose)
elif options.forum:
import_forum(cli, options.project, options.forum, user_map, doc_txt, validate=options.validate)
def import_tracker(cli, project, tool, import_options, options, doc_txt, validate=True, verbose=False):
url = '/rest/p/' + project + '/' + tool
if validate:
url += '/validate_import'
else:
url += '/perform_import'
existing_map = {}
if options.cont:
existing_tickets = cli.call('/rest/p/' + options.project + '/' + options.tracker + '/')['tickets']
for t in existing_tickets:
existing_map[t['ticket_num']] = t['summary']
doc = json.loads(doc_txt)
if 'trackers' in doc and 'default' in doc['trackers'] and 'artifacts' in doc['trackers']['default']:
tickets_in = doc['trackers']['default']['artifacts']
doc['trackers']['default']['artifacts'] = []
else:
tickets_in = doc
if options.verbose:
print "Processing %d tickets" % len(tickets_in)
for cnt, ticket_in in enumerate(tickets_in):
if ticket_in['id'] in existing_map:
if options.verbose:
print 'Ticket id %d already exists, skipping' % ticket_in['id']
continue
doc_import={}
doc_import['trackers'] = {}
doc_import['trackers']['default'] = {}
doc_import['trackers']['default']['artifacts'] = [ticket_in]
res = cli.call(url, doc=json.dumps(doc_import), options=json.dumps(import_options))
assert res['status'] and not res['errors']
if options.validate:
if res['warnings']:
print "Ticket id %s warnings: %s" % (ticket_in['id'], res['warnings'])
else:
print "Imported ticket id %s" % (ticket_in['id'])
def import_forum(cli, project, tool, user_map, doc_txt, validate=True):
url = '/rest/p/' + project + '/' + tool
if validate:
url += '/validate_import'
print cli.call(url, doc=doc_txt, user_map=json.dumps(user_map))
else:
url += '/perform_import'
print cli.call(url, doc=doc_txt, user_map=json.dumps(user_map))
def parse_options():
optparser = OptionParser(usage='''%prog [options] <JSON dump>
Import project data dump in JSON format into an Allura project.''')
optparser.add_option('-a', '--api-ticket', dest='api_key', help='API ticket')
optparser.add_option('-s', '--secret-key', dest='secret_key', help='Secret key')
optparser.add_option('-p', '--project', dest='project', help='Project to import to')
optparser.add_option('-t', '--tracker', dest='tracker', help='Tracker to import to')
optparser.add_option('-f', '--forum', dest='forum', help='Forum tool to import to')
optparser.add_option('-u', '--base-url', dest='base_url', default='https://sourceforge.net', help='Base Allura URL (%default)')
optparser.add_option('-o', dest='import_opts', default=[], action='append', help='Specify import option(s)', metavar='opt=val')
optparser.add_option('--user-map', dest='user_map_file', help='Map original users to SF.net users', metavar='JSON_FILE')
optparser.add_option('--validate', dest='validate', action='store_true', help='Validate import data')
optparser.add_option('-v', '--verbose', dest='verbose', action='store_true', help='Verbose operation')
optparser.add_option('-c', '--continue', dest='cont', action='store_true', help='Continue import into existing tracker')
options, args = optparser.parse_args()
if len(args) != 1:
optparser.error("Wrong number of arguments")
if not options.api_key or not options.secret_key:
optparser.error("Keys are required")
if not options.project:
optparser.error("Target project is required")
return optparser, options, args
if __name__ == '__main__':
main()