# 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 $