# Perforce Defect Tracking Integration Project
#
#
# MIGRATE_TEAMTRACK.PY -- MIGRATE PERFORCE JOBS TO TEAMTRACK
#
# Gareth Rees, Ravenbrook Limited, 2000-10-19
#
#
# 1. INTRODUCTION
#
# This file contains the outline of a program that can convert Perforce jobs
# into TeamTrack cases and submit them to TeamTrack. Since I don't know what
# fields you have in your Perforce jobs or how you plan to convert them to
# fields in TeamTrack, I can't prepare a complete solution for you. Instead,
# you'll have to go through this file, read the comments and fill in the
# details.
#
# Each instance where you need to think and possibly edit the code is marked
# with three asterisks (***).
#
# Run this script from the command line by switching to the directory
# containing this file, then run the command "python migrate_teamtrack.py".
#
# You should also read section 6.2 of the P4DTI Administrator's Guide [AG,
# 6.2].
#
# This document is intended to meet [Requirements, 95].
#
# The intended readership is P4DTI administrators who have jobs in Perforce
# that need to be migrated to TeamTrack.
#
# This document is not confidential.
import config
import configure_teamtrack
import dt_teamtrack
import p4
import string
import teamtrack
# 2. UTILITIES
# 2.1. Convert text fields from Perforce to TeamTrack.
#
# convert_newlines(s) converts a text field (a string possibly consisting of
# several lines) from Perforce's format (\n only) to TeamTrack's format (\r\n).
def convert_newlines(s):
# Remove final newline (if any).
if s and s[-1] == '\n':
s = s[:-1]
# Replace \n with \r\n.
s = string.replace(s, '\n', '\r\n')
return s
# 3. CONNECT TO PERFORCE AND TEAMTRACK
# Connect to the Perforce server.
p4i = p4.p4(port = config.p4_port,
user = config.p4_user,
password = config.p4_password)
# Connect to the TeamTrack server.
tt = teamtrack.connect(config.teamtrack_user,
config.teamtrack_password,
config.teamtrack_server)
# Add the P4DTI fields to the TeamTrack CASES table.
configure_teamtrack.configure(config)
dt_teamtrack.dt_teamtrack(config).init()
# 4. *** FETCH PERFORCE JOBS FOR MIGRATION
#
# The 'jobs' variable should contain a list of jobs for migrating.
#
# To start with, I suggest only migrating a single job, to check that the
# script is working correctly. You'll probably go through several attempts
# before you get it right. Specify the job you want to migrate in the argument
# to the p4 job command, like this:
jobs = p4i.run('job -o job000001')
# When you are happy that the migration is working correctly, fetch all the
# jobs, like this:
# jobs = p4i.run('jobs')
# 5. MIGRATE JOBS TO TEAMTRACK
#
# For each job in the list of jobs, make a TeamTrack case that will correspond
# to the job.
#
# Fill in each of the case's fields with appropriate values from the job. Five
# fields are normally required by TeamTrack: TITLE, DESCRIPTION, ISSUETYPE,
# PROJECTID and SEVERITY (these are described in sections 5.1 to 5.4). Migrate
# optional fields (5.5). Specify a name for the job (5.7) and a user on whose
# behalf to submit the job (5.8). Set the state of the case so that it matches
# the state of the job (5.11)
for job in jobs:
case = tt.new_record(teamtrack.table['CASES'])
# 5.1. *** The TITLE and DESCRIPTION fields
#
# The TeamTrack TITLE should be a one-sentence summary and the DESCRIPTION
# a detailed explanation.
#
# If you have corresponding fields in Perforce, then just assign them (but
# remember to convert newlines in the description field).
#
# However, if you've been using the default Perforce jobspec, then you only
# have one job field, the Description, that contains information suitable
# for both the TITLE and DESCRIPTION fields. I suggest making the TITLE
# be the first line of the description, and the DESCRIPTION be the full
# description. You may need to go into TeamTrack and fix things up later
# by hand.
first_line = string.split(job['Description'],'\n')[0]
case['TITLE'] = first_line
case['DESCRIPTION'] = convert_newlines(job['Description'])
# 5.2. *** The ISSUETYPE field
#
# The ISSUETYPE indicates whether the case is a bug or change request or
# whatever. The legal values for this field are found in the TS_ID field
# in the TS_SELECTIONS. I have chosen the value 1, which means "Bug
# Report" in my TeamTrack database (you must check yours to find an
# appropriate value).
case['ISSUETYPE'] = 1
# 5.3. *** The PROJECTID field
#
# The legal values for the PROJECTID field are found in the TS_ID field in
# the TS_PROJECTS table. Project 2 is the first project in my TeamTrack
# database (you must check yours to find an appropriate value). Or you
# could compute the TeamTrack project based on the Perforce project if your
# Perforce jobs have a project field.
case['PROJECTID'] = 2
# 5.4. *** The SEVERITY field
#
# The legal values for the SEVERITY field are found in in the TS_ID field
# in the TS_SELECTIONS table where TS_FLDID = 14. I have chosen the value
# 30, which means "Medium" in my TeamTrack database (you must check yours
# to find an appropriate value). Better still would be to compute the
# TeamTrack severity based on the Perforce severity (if your Perforce jobs
# have a severity field).
case['SEVERITY'] = 30
# 5.5. *** Optional fields
#
# You don't have to fill in any more fields in the case if you don't want
# to. But if you have more fields in Perforce, you'll probably want to
# fill in some more fields in the TeamTrack case. You will need to read
# the TeamTrack database schema [TeamShare 2000-01-20] to understand the
# legal values for fields in a TeamTrack case.
#
# If you convert a multi-line text field, use the convert_newlines
# functions to do the conversion so that line ending appear correctly in
# TeamTrack.
#
# The two fields you must not set at this point are the STATE field
# (because when the case is submitted it ends up in state New or whatever
# you've defined to be the first state in the workflow; we correct in in
# section 5.11 below) and the OWNER field (because TeamTrack automatically
# sets the OWNER field when you submit an issue; we correct it in 5.12
# below).
# case['FOO'] = job['Foo']
# case['BAR'] = convert_newlines(job['Bar'])
# etc.
# 5.6. P4DTI fields
#
# Set the P4DTI fields so that the TeamTrack case will be replicated.
case['P4DTI_RID'] = rid
case['P4DTI_SID'] = sid
# 5.7. *** Perforce jobname
#
# Specify the job that the TeamTrack case will be replicated to.
#
# If you want to keep jobnames the same in Perforce, then use the old
# jobname here (leave the following line of code alone). This has the
# advantage that the jobname stays the same for each job (so if you have
# documents that refer to jobs, they will still be valid), but the
# disadvantage that Perforce jobnames won't match the TeamTrack case names
# (so for example TeamTrack BUG00224 might be replicated to Perforce
# job000142).
#
# If you would prefer the Perforce jobname to match the case id, comment
# out the following line of code. This has the advantage that the Perforce
# jobname matches the TeamTrack case name (so TeamTrack BUG00224 is
# replicated to Perforce job BUG00224) but the disadvantage that the job
# names change.
case['P4DTI_JOBNAME'] = job['Job']
# 5.8. *** Pick a user on whose behalf to submit the case
#
# If your Perforce userids are the same as the TeamTrack userids (I
# recommend this), then it should be safe to use the User field of the job,
# as in the code below. Otherwise, you'll have to convert the Perforce
# user to a TeamTrack user somehow.
user = job['User']
# 5.9. Submit the case
issueid = case.submit(user)
# 5.10. Fetch the case
#
# We're not done yet: we need to set the STATE and OWNER fields, which
# could not be set until now, as explained in section 5.5 above. So get
# the case from TeamTrack.
case = tt.query(teamtrack.table['CASES'],
"TS_ISSUETYPE = %d AND TS_ISSUEID = '%05d'"
% (case['ISSUETYPE'], issueid))[0]
# 5.11. *** The STATE field
#
# Set the STATE based on the Perforce job status (using the 'state_table'
# variable to do the conversion).
#
# You must edit the 'state_table' variable. This should be a map from your
# Perforce job status to the TeamTrack state. The legal values for
# TeamTrack states are given by the TS_ID field in the TS_STATES table; you
# must look in your TeamTrack database for the right values.
state_table = { 'open': 2,
'closed': 3,
'suspended': 5, }
case['STATE'] = state_table[job['Status']]
# 5.12. The OWNER field
#
# Set the OWNER field to be the user who submitted the case (who came from
# the job's user field in step 6 above). Note that the TeamTrack OWNER
# field is the user's id (that is, the TS_ID field of their record in the
# TS_USERS table), not their user name.
case['OWNER'] = case['SUBMITTER']
# 5.13. Update the case
#
# Update the case record in TeamTrack. Note that by using 'update' rather
# than 'transition' we bypass TeamTrack's checks on the workflow. This is
# necessary because our setting for STATE in section 5.11 may not result in
# a legal transition.
case.update()
# 5.14. Report on what's been done
print ("Submitted a case with issueid %d corresponding to job %s"
% (issueid, job['Job']))
print '-' * 60
print case
print '-' * 60
print job
print '-' * 60
# A. References
#
# [AG] "Perforce Defect Tracking Integration Administrator's Guide" (living
# document); Richard Brooksby; Ravenbrook Limited; 2000-08-10.
#
# [Requirements] "Perforce Defect Tracking Integration Project Requirements"
# (living document); Gareth Rees; Ravenbrook Limited; 2000-05-24;
# .
#
# [TeamShare 2000-01-20] "TeamTrack Database Schema (Database Version: 21)";
# TeamShare; 2000-01-20; .
#
#
# B. Document History
#
# 2000-10-19 GDR Created.
#
# 2000-12-08 RB Moved config_teamtrack to init_teamtrack.
#
# 2000-12-18 NB Moved init_teamtrack to init.
#
# 2001-02-22 GDR Rewritten so it can run before you've installed the P4DTI.
#
# 2001-02-23 GDR Added STATE and OWNER. Set the P4DTI fields, including
# P4DTI_JOBNAME.
#
# 2001-03-02 RB Transferred copyright to Perforce under their license.
#
# 2001-03-13 GDR Removed verbose parameter; added log_level.
#
# 2001-03-19 GDR Formatted as a document. Improved instructions.
#
#
# C. COPYRIGHT AND LICENCE
#
# This file is copyright (c) 2001 Perforce Software, Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
#
# $Id: //info.ravenbrook.com/project/p4dti/branch/2001-05-17/teamtrack-5/code/replicator/migrate_teamtrack.py#1 $