#                Perforce Defect Tracking Integration Project
#                 <http://www.ravenbrook.com/project/p4dti/>
#
#         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;
# <http://www.ravenbrook.com/project/p4dti/req/>.
#
# [TeamShare 2000-01-20] "TeamTrack Database Schema (Database Version: 21)";
# TeamShare; 2000-01-20; <URL: http://www.ravenbrook.com/project/p4dti/import/2000-01-20/teamtrack-schema/TTschema21.pdf>.
#
#
# 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-15/capacity/code/replicator/migrate_teamtrack.py#1 $
