- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
- <head>
- <title>Perforce Defect Tracking Integration Integrator's Guide</title>
- </head>
- <body bgcolor="#FFFFFF" text="#000000" link="#000099" vlink="#660066" alink="#FF0000">
- <div align="center">
- <p><i><a href="http://www.ravenbrook.com/project/p4dti/">Perforce Defect Tracking Integration Project</a></i></p>
- <hr />
- <h1>Perforce Defect Tracking Integration Integrator's Guide</h1>
- <address>
- <a href="mailto:gdr@ravenbrook.com">Gareth Rees</a>,
- <a href="http://www.ravenbrook.com/">Ravenbrook Limited</a>,
- 2000-10-16
- </address>
- </div>
- <h2><a id="section-Contents" name="section-Contents">Contents</a></h2>
- <ul>
- <li><a href="#section-1">1. Introduction</a>
- <ul>
- <li><a href="#section-1.1">1.1. Kit layout</a></li>
- <li><a href="#section-1.2">1.2. Levels of requirement</a></li>
- </ul>
- </li>
- <li><a href="#section-2">2. Understanding the <abbr title="Perforce Defect Tracking Integration">P4DTI</abbr></a>
- <ul>
- <li><a href="#section-2.1">2.1. Prerequisites</a></li>
- <li><a href="#section-2.2">2.2. Requirements overview</a></li>
- <li><a href="#section-2.3">2.3. Architecture overview</a></li>
- <li><a href="#section-2.4">2.4. Design overview</a></li>
- </ul>
- </li>
- <li><a href="#section-3">3. What you need to do</a>
- <ul>
- <li><a href="#section-3.1">3.1. Before you start work</a></li>
- <li><a href="#section-3.2">3.2. Getting help</a></li>
- <li><a href="#section-3.3">3.3. Adapting an existing integration</a></li>
- <li><a href="#section-3.4">3.4. Developing a new integration</a></li>
- <li><a href="#section-3.5">3.5. Optional features</a></li>
- </ul>
- </li>
- <li><a href="#section-4">4. Defect tracker database schema extensions</a>
- <ul>
- <li><a href="#section-4.1">4.1. Issues</a></li>
- <li><a href="#section-4.2">4.2. Changelists</a></li>
- <li><a href="#section-4.3">4.3. Fixes</a></li>
- <li><a href="#section-4.4">4.4. Filespecs</a></li>
- <li><a href="#section-4.5">4.5. Replicator configuration and state</a></li>
- <li><a href="#section-4.6">4.6. Discovering what's changed</a></li>
- <li><a href="#section-4.7">4.7. Distinguishing replicated changes from other changes</a></li>
- <li><a href="#section-4.8">4.8. Perforce users who don't have licenses in the defect tracker</a></li>
- </ul>
- </li>
- <li><a href="#section-5">5. Coding conventions</a>
- <ul>
- <li><a href="#section-5.1">5.1. Messages</a></li>
- <li><a href="#section-5.2">5.2. Message catalogs</a></li>
- <li><a href="#section-5.3">5.3. Logging</a></li>
- <li><a href="#section-5.4">5.4. Errors</a></li>
- <li><a href="#section-5.5">5.5. Source code layout</a></li>
- <li><a href="#section-5.6">5.6. Making changes</a></li>
- </ul>
- </li>
- <li><a href="#section-6">6. The Python interface to the defect tracker</a></li>
- <li><a href="#section-7">7. The defect tracker module</a>
- <ul>
- <li><a href="#section-7.1">7.1. The <code class="source">defect_tracker</code> class</a></li>
- <li><a href="#section-7.2">7.2. The <code class="source">defect_tracker_issue</code> class</a>
- <ul>
- <li><a href="#section-7.2.1">7.2.1. Issue identifiers</a></li>
- <li><a href="#section-7.2.2">7.2.2. Issues are dictionaries</a></li>
- </ul>
- </li>
- <li><a href="#section-7.3">7.3. The <code class="source">defect_tracker_fix</code> class</a></li>
- <li><a href="#section-7.4">7.4. The <code class="source">defect_tracker_filespec</code> class</a></li>
- <li><a href="#section-7.5">7.5. The <code class="source">translator</code> class</a>
- <ul>
- <li><a href="#section-7.5.1">7.5.1. Date translator</a></li>
- <li><a href="#section-7.5.2">7.5.2. State translator</a></li>
- <li><a href="#section-7.5.3">7.5.3. Text translator</a></li>
- <li><a href="#section-7.5.4">7.5.4. User translator</a></li>
- </ul>
- </li>
- <li><a href="#section-7.6">7.6. Cursors</a></li>
- </ul>
- </li>
- <li><a href="#section-8">8. Configuration</a>
- <ul>
- <li><a href="#section-8.1">8.1. The configuration generator</a></li>
- <li><a href="#section-8.2">8.2. Perforce interface configuration</a></li>
- <li><a href="#section-8.3">8.3. Replicator configuration</a></li>
- <li><a href="#section-8.4">8.4. Perforce jobspecs</a></li>
- <li><a href="#section-8.5">8.5. Adapting the configuration module</a></li>
- <li><a href="#section-8.6">8.6. Making your own configurations</a>
- <ul>
- <li><a href="#section-8.6.1">8.6.1. Steps to making your own configuration</a></li>
- <li><a href="#section-8.6.2">8.6.2. Example: custom jobspec and translators</a></li>
- </ul>
- </li>
- </ul>
- </li>
- <li><a href="#section-9">9. Building and testing</a></li>
- <li><a href="#section-10">10. Providing a defect tracker interface to Perforce relations</a></li>
- <li><a href="#section-11">11. Adapting the manuals</a></li>
- <li><a href="#section-12">12. Making your work available to the community</a>
- <ul>
- <li><a href="#section-12.1">12.1. Reporting defects</a></li>
- <li><a href="#section-12.2">12.2. Making a contribution</a></li>
- </ul>
- </li>
- <li><a href="#section-13">13. Changes since previous releases</a>
- <ul>
- <li><a href="#section-13.1">13.1. Changes since release 1.1.1</a></li>
- <li><a href="#section-13.2">13.2. Changes since release 1.1.6</a></li>
- <li><a href="#section-13.3">13.3. Changes since release 1.2.1</a></li>
- <li><a href="#section-13.4">13.4. Changes since release 1.3.3</a></li>
- </ul>
- </li>
- <li><a href="#section-A">A. References</a></li>
- <li><a href="#section-B">B. Document History</a></li>
- </ul>
- <h2><a id="section-1" name="section-1">1. Introduction</a></h2>
- <p> This is the Perforce Defect Tracking Integration (<abbr
- title="Perforce Defect Tracking Integration">P4DTI</abbr>) Integrator's
- Guide. It explains how to extend the <abbr title="Perforce Defect
- Tracking Integration">P4DTI</abbr> to work with defect tracking systems
- that aren't supported by the standard distribution, or adapt the <abbr
- title="Perforce Defect Tracking Integration">P4DTI</abbr> to work with a
- supported defect tracker but in some way that isn't supported. </p>
- <p> The intended readership is developers adapting or extending the
- <abbr title="Perforce Defect Tracking Integration">P4DTI</abbr>, and
- project staff. </p>
- <p> This manual is not confidential. </p>
- <h3><a id="section-1.1" name="section-1.1">1.1. Kit layout</a></h3>
- <p> The Integration Kit is a copy of the development sources for the
- <abbr title="Perforce Defect Tracking Integration">P4DTI</abbr>. The
- directory layout is summarized in the <a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/">index to the kit</a>. </p>
- <h3><a id="section-1.2" name="section-1.2">1.2. Levels of requirement</a></h3>
- <p> I use some words in a precise way to express the importance of an
- instruction. </p>
- <ul>
- <li><p> I say "must" when the instruction is critical. This means
- that the integration will fail if the instruction is not
- followed. </p></li>
- <li><p> I say "should" when the instruction is essential. This means
- that integration will be of noticeably lower quality than the supported
- integrations if the instruction is not followed. However, it won't
- fail. </p></li>
- <li><p> I say "may" when the instruction is optional. This means that
- the integration will not suffer much if you don't follow the
- instruction. </p></li>
- </ul>
- <h2><a id="section-2" name="section-2">2. Understanding the <abbr title="Perforce Defect Tracking Integration">P4DTI</abbr></a></h2>
- <p> This section gives an overview of the requirements, architecture and
- design of the <abbr title="Perforce Defect Tracking
- Integration">P4DTI</abbr>, with references to the documents that provide
- more detail. You must have a good overall understanding of the <abbr
- title="Perforce Defect Tracking Integration">P4DTI</abbr> in order to
- extend or adapt it. </p>
- <h3><a id="section-2.1" name="section-2.1">2.1. Prerequisites</a></h3>
- <p> This manual assumes you are familiar with the following subjects:
- </p>
- <ul>
- <li><p> The jobs subsystem of Perforce, and the relationship between
- jobs, fixes and changelists [<a
- href="http://www.perforce.com/perforce/doc.031/manuals/p4guide/10_jobtrack.html">Perforce
- 2003-07-15a, 10</a>]. </p></li>
- <li><p> How the <abbr title="Perforce Defect Tracking
- Integration">P4DTI</abbr> works, from the administrator's point of
- view. I strongly recommend that you download, install, configure and
- run one of the supported integrations, following the <cite>Perforce
- Defect Tracking Integration Administrator's Guide</cite> [<a
- href="../ag/index.html">RB 2000-08-10a</a>], so that
- you know what the administrator has to know and do, where the data is
- stored, what problems can occur. </p></li>
- <li><p> How the <abbr title="Perforce Defect Tracking
- Integration">P4DTI</abbr> works, from the user's point of view. I
- strongly recommend that you try out one of the supported integrations,
- carrying out all the tasks in the <cite>Perforce Defect Tracking
- Integration User's Guide</cite> [<a
- href="../ug/index.html">RB 2000-08-10b</a>], so that
- you know what it's like to use, and what benefit the users
- get. </p></li>
- <li><p> The programming language Python. See the <a
- href="http://www.python.org/">Python web site
- <http://www.python.org/></a> for downloads and documentation.
- If you're new to Python, try the tutorial [<a
- href="http://www.python.org/doc/current/tut/tut.html">van Rossum
- 2000-10-16</a>], or the book <cite>Programming Python</cite> [<a
- href="#ref-Lutz-1996">Lutz 1996</a>]. </p></li>
- </ul>
- <h3><a id="section-2.2" name="section-2.2">2.2. Requirements overview</a></h3>
- <p> The five most important requirements are these [<a
- href="http://www.ravenbrook.com/project/p4dti/req/#req-1">GDR
- 2000-05-24, 1-5</a>]: </p>
- <ul>
- <li><p> Defect tracker state is consistent with the state of the product
- sources. </p></li>
- <li><p> The defect tracking integration makes the jobs of the developers
- and managers easier (i.e. make it easier for them to produce a quality
- product etc.). </p></li>
- <li><p> It is easy to discover why the product sources are the way they
- are, and why they have changed, in terms of the customer
- requirements. </p></li>
- <li><p> The interface that allows Perforce to be integrated with defect
- tracking systems is public, documented, and maintained. </p></li>
- <li><p> The integration provides the ability to ask questions involving
- both the defect tracking system and the <abbr title="Source
- Configuration Management">SCM</abbr> system. </p></li>
- </ul>
- <p> The <abbr title="Perforce Defect Tracking Integration">P4DTI</abbr>
- meets <a
- href="http://www.ravenbrook.com/project/p4dti/req/#req-1">requirement
- 1</a> and <a
- href="http://www.ravenbrook.com/project/p4dti/req/#req-5">requirement
- 5</a> by replicating data between the defect tracker and Perforce (see
- <a href="#section-2.3">section 2.3</a>). It meets <a
- href="http://www.ravenbrook.com/project/p4dti/req/#req-2">requirement
- 2</a> by making it possible for developers to do their routine defect
- tracking activity entirely from Perforce (by making the defects
- available through Perforce's jobs interface). It meets <a
- href="http://www.ravenbrook.com/project/p4dti/req/#req-3">requirement
- 3</a> by supplying a user guide [<a
- href="../ug/index.html">RB 2000-08-10b</a>] that
- describes a development process in which issues are linked to changes by
- making fixes in Perforce. It meets <a
- href="http://www.ravenbrook.com/project/p4dti/req/#req-4">requirement
- 4</a> by making the project sources and documents <a
- href="http://www.ravenbrook.com/project/p4dti/">available to the
- public</a>. </p>
- <p> See the <cite>Perforce Defect Tracking Integration Project
- Requirements</cite> [<a
- href="http://www.ravenbrook.com/project/p4dti/req/">GDR 2000-05-24</a>]
- for a full and maintained set of requirements and references to their
- original sources. </p>
- <h3><a id="section-2.3" name="section-2.3">2.3. Architecture overview</a></h3>
- <p> The <abbr title="Perforce Defect Tracking Integration">P4DTI</abbr>
- meets these requirements using a replication architecture [<a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/design/architecture/">RB 2000-08-10c</a>].
- A replicator process repeatedly polls two databases (Perforce and the
- defect tracker) and copies entities from one to the other. This makes
- and keep them consistent, to meet <a
- href="http://www.ravenbrook.com/project/p4dti/req/#req-1">requirement
- 1</a>; it makes them available to users of both systems, to meet <a
- href="http://www.ravenbrook.com/project/p4dti/req/#req-2">requirement
- 2</a>; and it makes them available for queries combining data from both
- systems, to meet <a
- href="http://www.ravenbrook.com/project/p4dti/req/#req-5">requirement
- 5</a>. </p>
- <p> The replicator replicates four relations: </p>
- <ul>
- <li><p> <b>Issues</b> are replicated from the defect tracker to Perforce
- (where they appear as jobs). Changes to issues and jobs are replicated
- in both directions, but the Perforce jobs are considered to be a
- subsidiary copy of the real data in the defect tracker. This means that
- when the two databases differ (for example, because they have been
- changed simultaneously) the defect tracker is considered to be
- definitive. </p></li>
- <li><p> <b>Changelist descriptions</b> are replicated from Perforce to the
- defect tracker. </p></li>
- <li><p> <b>Fixes</b> (links between issues and changelists) are
- replicated in both directions. </p></li>
- <li> <p> <b>Filespecs</b> (links between issues and files) are replicated in both directions. </p> </li>
- </ul>
- <p> The <abbr title="Perforce Defect Tracking Integration">P4DTI</abbr>
- replicates the filespec relation in order to support use cases like
- "Associate revisions of documents with task" [<a
- href="http://www.ravenbrook.com/project/p4dti/doc/2000-05-03/reqs-and-use-cases/">GDR
- 2000-05-03, 6.2</a>] and "Check out copies of revisions of documents
- associated with task" [<a
- href="http://www.ravenbrook.com/project/p4dti/doc/2000-05-03/reqs-and-use-cases/">GDR
- 2000-05-03, 6.3</a>] and to support defect trackers like DevTrack by
- TechExcel that provide a revision control interface based on associating
- documents with an issue. However, because the currently supported defect tracker
- (Bugzilla) has no such feature, and because alpha and
- beta testing showed no demand for use cases involving associating
- documents with tasks, we haven't made any use of this relation (for
- example, it's not documented in the user's guide). However, it's there
- if you need it for integrating with your defect tracker. </p>
- <h3><a id="section-2.4" name="section-2.4">2.4. Design overview</a></h3>
- <p> The replicator is designed to be highly independent of both Perforce
- and the defect tracker, using public interfaces wherever possible, so
- that the integration doesn't have to change frequently to keep up with
- the systems it integrates (<a
- href="http://www.ravenbrook.com/project/p4dti/req/#req-27">requirement
- 27</a>) and the cost of maintenance is low (<a
- href="http://www.ravenbrook.com/project/p4dti/req/#req-30">requirement
- 30</a>). It runs as a separate process and uses public protocols to
- access both databases. It doesn't require any special support from
- either system (though users benefit if the defect tracker provides an
- interface to Perforce fixes; (see <a href="#section-10">section
- 10</a>). </p>
- <p> The replicator is written in the interpreted programming language
- Python, a portable, stable, readable and open programming language (to
- meet <a
- href="http://www.ravenbrook.com/project/p4dti/req/#req-21">requirement
- 21</a>, <a
- href="http://www.ravenbrook.com/project/p4dti/req/#req-24">requirement
- 24</a>, <a
- href="http://www.ravenbrook.com/project/p4dti/req/#req-25">requirement
- 25</a>, and <a
- href="http://www.ravenbrook.com/project/p4dti/req/#req-26">requirement
- 26</a>.). </p>
- <p> <a href="#figure-1">Figure 1</a> below shows the broad outlines of
- how the replicator is constructed. Parts in black are shared by the
- integrations with all defect trackers. The components in red are the
- components that you must write in order to integrate with your defect
- tracker. </p>
- <p> If you need to modify any other components to integrate with your
- defect tracker, that's a defect in the integration kit. Please report
- it (see <a href="#section-12.1">section 12.1</a>) or make the necessary
- modifications and submit them as a contribution (see <a
- href="#section-12.2">section 12.2</a>). </p>
- <div align="center">
- <p> <a id="figure-1" name="figure-1">Figure 1</a>. Replicator block
- diagram </p>
- <img src="replicator-design.gif" alt="Replicator block diagram"
- usemap="#map-1" width="444" height="467" />
- </div>
- <map id="map-1" name="map-1">
- <p> The replicator is divided into these components: </p>
- <ul>
- <li><p> <a href="http://www.ravenbrook.com/project/p4dti/version/2.2/code/replicator/replicator.py"
- shape="rect" coords="187,1,302,65"><code
- class="filename">replicator.py</code></a>, a module that runs the
- replication algorithm and reports failures by e-mail [<a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/design/replicator/">GDR
- 2000-09-13</a>]. </p></li>
- <li><p> A defect tracker module, called <code
- class="filename">dt_<i>defect_tracker</i>.py</code> (<code
- class="filename">dt_abc.py</code> in <a href="#figure-1">figure 1</a>).
- This defines a subclass of <code class="filename">defect_tracker</code>.
- It is responsible for fetching, translating and updating entities in the
- defect tracker database at a high level of abstraction (see <a
- href="#section-7" shape="poly"
- coords="105,59,171,59,171,79,244,79,244,142,128,142,128,79,105,79">section
- 7</a>). For each new defect tracker, you need to write such a
- module. </p></li>
- <li><p> A defect tracker interface. This provides a low-level interface
- to the defect tracker, allowing entities to be fetched from and stored
- in records in the defect tracker's database (see <a href="#section-6"
- shape="poly"
- coords="47,136,113,136,113,156,186,156,186,219,70,219,70,156,47,156">section
- 6</a>). For each new defect tracker, you need to write such a module.
- To avoid the replicator needing any internal state, the defect tracker
- interface stores any persistent information needed by the replicator in
- the defect tracker's database; see <a href="#section-4" shape="poly"
- coords="32,427,113,427,113,442,182,442,182,460,113,460,113,467,32,467">section
- 4</a> for the necessary schema extensions. </p></li>
- <li><p> A configuration generator. This is responsible for taking the
- raw configuration supplied by the <abbr title="Perforce Defect Tracking
- Integration">P4DTI</abbr> administrator and building a detailed
- configuration suitable for the replicator (see <a
- href="#section-8">section 8</a>). </p></li>
- <li><p> Supporting components, including an interface to Perforce (<a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/code/replicator/p4.py" shape="rect"
- coords="258,79,375,141"><code class="filename">p4.py</code></a>, a
- message system, and configuration checking functions. </p></li>
- </ul>
- </map>
- <h2><a id="section-3" name="section-3">3. What you need to do</a></h2>
- <p> This section gives an overview of the work required in adapting an
- existing integration or developing a new integration. </p>
- <h3><a id="section-3.1" name="section-3.1">3.1. Before you start work</a></h3>
- <p> Someone might already have developed the integration or adaption
- that you plan to work on. Take a look at the <a
- href="http://www.ravenbrook.com/project/p4dti/contrib/"><abbr
- title="Perforce Defect Tracking Integration">P4DTI</abbr> contributions
- page <http://www.ravenbrook.com/project/p4dti/contrib/></a>. </p>
- <p> Someone might be currently be working on the integration or adaption
- that you plan to work on. If so, <a
- href="http://www.perforce.com/perforce/support.html">Perforce
- support</a> may know about them. </p>
- <p> The feature you want may in fact be part of the supported <abbr
- title="Perforce Defect Tracking Integration">P4DTI</abbr> product and it
- is missing from the manuals or the manuals are unclear. If so, <a
- href="http://www.perforce.com/perforce/support.html">Perforce
- support</a> can tell you. And if the manuals are unclear or missing
- information, then please submit a defect report (see <a
- href="#section-12.1">section 12.1</a>). </p>
- <h3><a id="section-3.2" name="section-3.2">3.2. Getting help</a></h3>
- <p> The Perforce Defect Tracking Integration Kit is a supported
- product. If you have trouble adapting the <abbr title="Perforce Defect
- Tracking Integration">P4DTI</abbr> or developing an integration after
- following the instructions in here, contact <a
- href="http://www.perforce.com/perforce/support.html">Perforce
- support</a> for help. </p>
- <p> <a href="http://www.ravenbrook.com/services/perforce/">Ravenbrook
- Limited</a> may be able to develop or consult on adaptions and
- extensions to the <abbr title="Perforce Defect Tracking
- Integration">P4DTI</abbr>. </p>
- <h3><a id="section-3.3" name="section-3.3">3.3. Adapting an existing integration</a></h3>
- <p> You may need to adapt the <abbr title="Perforce Defect Tracking
- Integration">P4DTI</abbr> to work with a supported defect tracker but in
- some way that isn't supported. For example: </p>
- <ul>
- <li> You want more control over which defect tracker issues are
- replicated to Perforce. </li>
- <li> You want to change the names of the fields in Perforce. </li>
- <li> You want to match up the fields in an unusual way, for example you
- have a single field in the defect tracker that ought to be two fields in
- Perforce (or vice versa). </li>
- <li> You want to translate values in a field in a different way. </li>
- <li> You want to use a locally customized version of Bugzilla. </li>
- </ul>
- <p> In these and many similar cases, make the <abbr title="Perforce
- Defect Tracking Integration">P4DTI</abbr> do what you want by writing a
- "configuration generator" (see <a href="#section-8.6">section
- 8.6</a>). </p>
- <p> But don't skip straight to that section. At least skim the rest of
- the manual. You'll need to understand many of the details in order to
- write a configuration generator, especially how to write translator
- classes (see <a href="#section-7.5">section 7.5</a>) and how the
- configuration works (see <a href="#section-8">section 8</a>). </p>
- <h3><a id="section-3.4" name="section-3.4">3.4. Developing a new integration</a></h3>
- <p> Follow these steps to integrate Perforce with a new defect tracker:
- </p>
- <ol>
- <li><p> Choose a name for the integration. This should be the name of
- the defect tracker, for example "Bugzilla". This name
- (when converted to lower case) must be used as part of the names of
- modules making up the integration (see <a href="#section-7">section
- 7</a> and <a href="#section-8">section 8</a>). </p></li>
- <li><p> Decide which of the optional features you are going to support
- (see <a href="#section-3.5">section 3.5</a>). </p></li>
- <li>
- <p> Provide full implementations of these components: </p>
- <ol type="a">
- <li><p> A documented design for extensions for the defect tracker
- database schema (see <a href="#section-4">section 4</a>); </p></li>
- <li><p> A Python interface to the defect tracker (see <a
- href="#section-6">section 6</a>); </p></li>
- <li><p> A defect tracker module (see <a href="#section-7">section
- 7</a>); </p></li>
- <li><p> A configuration generator (see <a href="#section-8">section
- 8</a>). </p></li>
- </ol>
- </li>
- <li><p> You should develop and apply tests (both automated and manual)
- of your integration (see <a href="#section-9">section 9</a>). </p>
- </li>
- <li><p> You should provide a defect tracker interface to the Perforce
- relations, if possible (see <a href="#section-10">section
- 10</a>).</p></li>
- <li><p> You must adapt or extend these components: </p>
- <ol type="a">
- <li><p> The configuration module <a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/code/replicator/config.py"><code
- class="filename">config.py</code></a> (see <a
- href="#section-8.5">section 8.5</a>). </p></li>
- <li><p> The Administrator's Guide (see <a href="#section-11">section
- 11</a>); </p></li>
- <li><p> The User's Guide (see <a href="#section-11">section 11</a>);
- </p></li>
- </ol>
- <p> All other components are designed to be portable between defect
- trackers. If your integration cannot be made to work without changing
- the portable components, then there is a defect in the <abbr
- title="Perforce Defect Tracking Integration">P4DTI</abbr> Integration
- Kit. Please report this (see <a href="#section-12.1">section
- 12.1</a>). </p>
- </li>
- <li><p> Once all the work outlined above is completed and tested to
- your satisfaction, you should make your work available to the
- community so that others can benefit from your efforts (see <a
- href="#section-12.2">section 12.2</a>). </p></li>
- </ol>
- <p> I estimate that at least 10 weeks of effort are required to develop,
- test, document and release a new integration [<a
- href="http://www.ravenbrook.com/project/p4dti/doc/2000-05-30/arch-analysis/#section-2.21.1">GDR
- 2000-05-30</a>] </p>
- <h3><a id="section-3.5" name="section-3.5">3.5. Optional features</a></h3>
- <p> The features in the following list are optional. You should
- implement as many as possible. Use the <a
- href="#defect_tracker.supports"><code
- class="source">supports</code></a> method of your defect tracker
- interface to specify to the <abbr title="Perforce Defect Tracking
- Integration">P4DTI</abbr> the features that you support. </p>
- <dl>
- <dt><a id="feature-fixes" name="feature-fixes">fixes</a></dt>
- <dd><p> Replication of fixes between Perforce and the defect tracker,
- and replication of changeslists from Perforce to the defect tracker.
- </p></dd>
- <dt><a id="feature-filespecs" name="feature-filespecs">filespecs</a></dt>
- <dd><p> Replication of file specifications between Perforce and the
- defect tracker. </p></dd>
- <dt><a id="feature-migrate_issues" name="feature-migrate_issues">migrate_issues</a></dt>
- <dd><p> Creation of new issues in the defect tracker based on jobs in
- Perforce (during migration). </p></dd>
- <dt><a id="feature-new_issues" name="feature-new_issues">new_issues</a></dt>
- <dd><p> Creation of new issues in the defect tracker based on jobs in
- Perforce (during normal operation of the <abbr title="Perforce Defect
- Tracking Integration">P4DTI</abbr>). </p></dd>
- <dt><a id="feature-new_users" name="feature-new_users">new_users</a></dt>
- <dd><p> Creation of new users in the defect tracker based on users in
- Perforce. </p></dd>
- </dl>
- <h2><a id="section-4" name="section-4">4. Defect tracker database schema extensions</a></h2>
- <p> You must extend the database schema by adding new fields to the
- issue relation (see <a href="#section-4.1">section 4.1</a>), and adding
- three new relations: the changelist relation (see <a
- href="#section-4.2">section 4.2</a>), the fixes relation (see <a
- href="#section-4.3">section 4.3</a>), and the filespecs relation (see <a
- href="#section-4.4">section 4.4</a>). You should add another relation
- to the database, to store the replicator state and configuration (see <a
- href="#section-4.5">section 4.5</a>). These schema extensions must be
- documented so that users of your integration can implement database
- queries and reports that use this data, to meet <a
- href="http://www.ravenbrook.com/project/p4dti/req/#req-5">requirement
- 5</a>. </p>
- <p> These relations should be stored in separate tables if possible, to
- most easily support queries and reporting using standard database tools.
- However, some defect trackers do not support this. </p>
- <blockquote><p> <i>Example.</i> TeamTrack release 4.5 doesn't support
- the addition of tables to its database schema, so the TeamTrack schema
- extensions squashed these relations into a single table, using a type
- field to distinguish them [<a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/design/teamtrack-p4dti-schema/#section-2.1">GDR
- 2000-09-04, 2.1</a>]. </p></blockquote>
- <p> The design must support multiple replicators replicating from a
- single defect tracker, and support a single replicator replicating to
- multiple Perforce servers from one defect tracker, in order to meet <a
- href="http://www.ravenbrook.com/project/p4dti/req/#req-96">requirement
- 96</a>. To support this, each relation includes a replicator identifier
- which identifies the replicator which is handling replication for that
- record, and a Perforce server identifier, which identifies the Perforce
- server that the record is replicated to. </p>
- <blockquote><p> <i>Examples.</i> The TeamTrack database schema
- extensions [<a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/design/teamtrack-p4dti-schema/">GDR
- 2000-09-04</a>] and the Bugzilla database schema extensions [<a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/design/bugzilla-p4dti-schema/">NB
- 2000-11-14b</a>]. </p></blockquote>
- <h3><a id="section-4.1" name="section-4.1">4.1. Issues</a></h3>
- <p> The issue relation must be extended with these fields: </p>
- <table border="1" cellspacing="0" cellpadding="5">
- <tr valign="top" align="left">
- <th>Field contents</th>
- <th>Field type</th>
- </tr>
- <tr valign="top">
- <td>Replicator identifier of the replicator that is in charge of
- replicating this issue, or the empty string or NULL if the issue is
- not replicated.</td>
- <td><code class="source">char(32)</code></td>
- </tr>
- <tr valign="top">
- <td>Server identifier of the Perforce server to which this issue is
- replicated, or the empty string or NULL if the issue is not
- replicated.</td>
- <td><code class="source">char(32)</code></td>
- </tr>
- <tr valign="top">
- <td>Name of Perforce job to which this issue is replicated, or the
- empty string or NULL if the issue is not replicated.</td>
- <td><code class="source">char(1024)</code> (or <code
- class="source">varchar(1024)</code> since most jobnames are
- short).</td>
- </tr>
- </table>
- <p> You may add these fields to the defect tracker's issue table, or
- you may store them in a separate table and use the issue key to relate
- the two tables. </p>
- <blockquote><p> <i>Examples.</i> The TeamTrack integration added the new
- fields to the existing <code class="source">TS_CASES</code> table [<a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/design/teamtrack-p4dti-schema/#section-3.1">GDR
- 2000-09-04, 3.1</a>]. The Bugzilla integration creates a table <code
- class="source">p4dti_bugs</code> containing the new fields and
- associates them with the <code class="source">bugs</code> table using
- the <code class="source">bug_id</code> field [<a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/design/bugzilla-p4dti-schema/">NB
- 2000-11-14b</a>]. </p></blockquote>
- <h3><a id="section-4.2" name="section-4.2">4.2. Changelists</a></h3>
- <p> (Changelists belong to the <a href="#feature-fixes">fixes</a>
- feature.) </p>
- <p> The changelist relation has these fields: </p>
- <table border="1" cellspacing="0" cellpadding="5">
- <tr valign="top" align="left">
- <th>Field contents</th>
- <th>Field type</th>
- </tr>
- <tr valign="top">
- <td>Replicator identifier.</td>
- <td><code class="source">char(32)</code></td>
- </tr>
- <tr valign="top">
- <td>Perforce server identifier.</td>
- <td><code class="source">char(32)</code></td>
- </tr>
- <tr valign="top">
- <td>Change number.</td>
- <td><code class="source">int</code></td>
- </tr>
- <tr valign="top">
- <td>User who created the change.</td>
- <td>A foreign key reference to the defect tracker's user relation
- giving the user who created or submitted the change.</td>
- </tr>
- <tr valign="top">
- <td>Change status.</td>
- <td>An enumeration with two values: pending or submitted.</td>
- </tr>
- <tr valign="top">
- <td>Date the change was last modified.</td>
- <td>A date and time.</td>
- </tr>
- <tr valign="top">
- <td>Change description.</td>
- <td>Text, unlimited in length.</td>
- </tr>
- <tr valign="top">
- <td>Client from which the change was submitted.</td>
- <td><code class="source">char(1024)</code> (or <code
- class="source">varchar(1024)</code> since most client names are
- short).</td>
- </tr>
- </table>
- <p> The combination of (change number, Perforce server identifier) is
- the primary key for this relation: there can only be one change with a
- particular number on a Perforce server. </p>
- <h3><a id="section-4.3" name="section-4.3">4.3. Fixes</a></h3>
- <p> (Fixes belong to the <a href="#feature-fixes">fixes</a> feature.)
- </p>
- <p> The fixes relation has these fields: </p>
- <table border="1" cellspacing="0" cellpadding="5">
- <tr valign="top" align="left">
- <th>Field contents</th>
- <th>Field type</th>
- </tr>
- <tr valign="top">
- <td>Replicator identifier.</td>
- <td><code class="source">char(32)</code></td>
- </tr>
- <tr valign="top">
- <td>Perforce server identifier.</td>
- <td><code class="source">char(32)</code></td>
- </tr>
- <tr valign="top">
- <td>Issue.</td>
- <td>A foreign key reference to the defect tracker's issue relation,
- giving the issue which is fixed by the change.</td>
- </tr>
- <tr valign="top">
- <td>Change number</td>
- <td><code class="source">int</code></td>
- </tr>
- <tr valign="top">
- <td>Date the fix was last modified.</td>
- <td>A date and time.</td>
- </tr>
- <tr valign="top">
- <td>User who created the fix.</td>
- <td>A foreign key reference to the defect tracker's user relation,
- giving the user who last modified the fix.</td>
- </tr>
- <tr valign="top">
- <td>Status the job was/will be fixed to.</td>
- <td><code class="source">char(1024)</code> (or <code
- class="source">varchar(1024)</code> since most job statuses are
- short).</td>
- </tr>
- <tr valign="top">
- <td>Client from which the fix was made.</td>
- <td><code class="source">char(1024)</code> (or <code
- class="source">varchar(1024)</code> since most client names are
- short).</td>
- </tr>
- </table>
- <p> The combination of (issue, change number, Perforce server
- identifier) is the primary key for this relation: there can only be one
- fix between a change and an issue on a Perforce server. </p>
- <h3><a id="section-4.4" name="section-4.4">4.4. Filespecs</a></h3>
- <p> (Filespecs belong to the <a href="#feature-filespecs">filespecs</a>
- feature.) </p>
- <p> The associated filespecs relation has these fields: </p>
- <table border="1" cellspacing="0" cellpadding="5">
- <tr valign="top" align="left">
- <th>Field contents</th>
- <th>Field type</th>
- </tr>
- <tr valign="top">
- <td>Replicator identifier.</td>
- <td><code class="source">char(32)</code></td>
- </tr>
- <tr valign="top">
- <td>Perforce server identifier.</td>
- <td><code class="source">char(32)</code></td>
- </tr>
- <tr valign="top">
- <td>Issue.</td>
- <td>A foreign key reference to the defect tracker's issue relation,
- giving the issue which is fixed by the change.</td>
- </tr>
- <tr valign="top">
- <td>Filespec.</td>
- <td>Text, unlimited in length.</td>
- </tr>
- </table>
- <h3><a id="section-4.5" name="section-4.5">4.5. Replicator configuration and state</a></h3>
- <p> By design, the replicator has no internal state. This is to make
- the replicator robust against losing a network connection, or the
- machine it's running on crashing in the middle of a replication: when
- the network comes back up or it starts again, it tries the replication
- again [<a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/design/replicator/#section-2.10">GDR
- 2000-09-13, 2.9</a>]. This design principle helps to meet <a
- href="http://www.ravenbrook.com/project/p4dti/req/#req-1">requirement 1</a> (consistency between
- databases). </p>
- <p> This means that if you need to store information, such as a record
- of which changes have been replicated (see <a
- href="#section-4.6">section 4.6</a>) you must store it in the defect
- tracker's database. </p>
- <p> The replicator also needs to pass information to the defect tracker,
- to support an interface from the defect tracker to Perforce (see <a
- href="#section-10">section 10</a>). There are three configuration
- parameters which should be communicated to the defect tracker by storing
- them in a configuration table: <a
- href="../ag/index.html#config-changelist_url"><code
- class="source">changelist_url</code></a>, <a
- href="../ag/index.html#config-job_url"><code
- class="source">job_url</code></a>, and <a
- href="../ag/index.html#config-p4_server_description"><code
- class="source">p4_server_description</code></a>. </p>
- <h3><a id="section-4.6" name="section-4.6">4.6. Discovering what's changed</a></h3>
- <p> The replicator works by repeatedly polling the databases, so you
- must provide a way to tell it which issues have changed since the last
- time it polled. Here are some strategies: </p>
- <ul>
- <li>
- <p> If the defect tracker has a changes table which records the
- history of changes to issues, then store a record number in the
- replicator state that gives the last record in the changes table that
- has been replicated.</p>
- <blockquote><p> <i>Example.</i> The TeamTrack integration used this
- approach [<a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/design/teamtrack-p4dti-schema/#section-3.5">GDR
- 2000-09-04, 3.5</a>]. </p></blockquote>
- </li>
- <li><p> If the defect tracker has a last modified date field in the
- issue table, store the value of this field at the point when the
- replicator was last replicated. Then you can fetch the changed issues
- by looking for issues whose last modified date is greater than the last
- replicated date. This is likely to be less efficient than solution
- 1. </p></li>
- <li><p> Modify the defect tracker so that it supports solution 1 or
- 2. </p></li>
- <li><p> If all else fails, store a "shadow" table of issues, containing
- copies of the issue records as they were when last modified. Then you
- can find changed issues by finding differing corresponding records.
- This is likely to be very inefficient. </p></li>
- </ul>
- <h3><a id="section-4.7" name="section-4.7">4.7. Distinguishing replicated changes from other changes</a></h3>
- <p> The replicator needs to distinguish the changes it made from changes
- made by other users of the defect tracker. Otherwise it attempts to
- replicate its own changes back to Perforce. This won't actually end up
- in an infinite loop of replication, since when it replicates back it
- discovers that there are no changes to be made, and so not actually do
- anything. However, this double replication gives twice the opportunity
- for conflicts, and hence annoying e-mail messages for the users of the
- <abbr title="Perforce Defect Tracking Integration">P4DTI</abbr> (see <a
- href="http://www.ravenbrook.com/project/p4dti/issue/job000016/">Ravenbrook
- issue job000016</a>). </p>
- <p> Here are some strategies: </p>
- <ul>
- <li>
- <p> Suppose that the defect tracker has separate concepts of "logged
- in user" and "user who is making the change". In this case, make a
- special user to represent the replicator and have the replicator log
- in as that user. The replicator's changes show up with logged in user
- being the replicator user; all other changes need to be
- replicated. </p>
- <blockquote><p> <i>Example.</i> The TeamTrack integration used this
- approach [<a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/design/teamtrack-p4dti-schema/#section-5">GDR
- 2000-09-04, 5</a>]. </p></blockquote>
- </li>
- <li>
- <p> Store a table listing the changes that were made by the
- replicator. Any other changes need to be replicated. </p>
- </li>
- <li><p> If the defect tracker has a last modified date field in the issue
- table, store the value of this field at the point when the replicator
- was last replicated. Then an issue has been changed by someone else if
- its last modified date differs from the last replicated date. </p></li>
- </ul>
- <h3><a id="section-4.8" name="section-4.8">4.8. Perforce users who don't have licenses in the defect tracker</a></h3>
- <p> The replicator replicates user fields in issues, changelists and
- fixes (for example, the owner of an issue or the user who submitted a
- changelist) by applying a user translation function (see <a
- href="#section-7.5.4">section 7.5.4</a>). When a defect tracker user
- has no license in Perforce, the translation function can simply use that
- user's defect tracker login name, since Perforce doesn't validate user
- fields in jobs. But if a Perforce user has no license in the defect
- tracker, the translator needs to do something with them. For issues
- your defect tracker interface should simply refuse to replicate when a
- Perforce user has no license in the defect tracker. But you should be
- less strict when replicating fixes and changelists: while it is a
- sensible policy (and required by some defect tracker vendors) to require
- the current owner of a job in Perforce to have a license, it is not
- sensible to require every user in Perforce who ever submitted a
- changelist to have a license in the defect tracker. </p>
- <blockquote><p> <i>Example.</i> The TeamTrack integration mapped unknown
- users in changelists and fixes to the special TeamTrack user 0
- (representing "no user"). When there's an unknown user in an issue, the
- integration rejects the attempt to replicate it by raising an error.
- </p></blockquote>
- <h2><a id="section-5" name="section-5">5. Coding conventions</a></h2>
- <p> This section covers coding conventions followed in the <abbr
- title="Perforce Defect Tracking Integration">P4DTI</abbr>. You should
- follow these conventions in your adaptions and extensions. They make
- your code more reliable and easier to debug, and make it easier for
- users to diagnose problems and fix them. If you contribute your code
- for inclusion in the <abbr title="Perforce Defect Tracking
- Integration">P4DTI</abbr> (see <a href="#section-12.2">section 12.2</a>)
- then it is easier for us to integrate your contribution. </p>
- <blockquote><p> <i>Example.</i> Look at the Bugzilla module, <a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/code/replicator/dt_bugzilla.py"><code
- class="filename">dt_bugzilla.py</code></a> for uses of all conventions
- and features covered in this section. </p></blockquote>
- <h3><a id="section-5.1" name="section-5.1">5.1. Messages</a></h3>
- <p> The <a href="http://www.ravenbrook.com/project/p4dti/version/2.2/code/replicator/message.py"><code
- class="filename">message.py</code></a> module defines a class of
- messages. You must use this class when writing messages to the
- replicator's log (see <a href="#section-5.3">section 5.3</a>). You
- should use this class when raising errors (see <a
- href="#section-5.4">section 5.4</a>). </p>
- <p> You create a message like this: </p>
- <blockquote><pre class="source">
- import message
- id = 123
- text = "Constructed a test message."
- priority = message.DEBUG
- product = "Test"
- msg = message.message(id, text, priority, product)
- </pre></blockquote>
- <p> The four arguments to the constructor are as follows: </p>
- <dl>
- <dt><code class="source">id</code></dt>
- <dd><p> A message identifier (an integer). This is unique among all
- messages generated by the product. </p></dd>
- <dt><code class="source">text</code></dt>
- <dd><p> The text of the message (a string). </p></dd>
- <dt><code class="source">priority</code></dt>
- <dd><p> The level of importance of the message. This must be one of
- the constants in the following table: </p>
- <table border="1" cellspacing="0" cellpadding="5">
- <tr valign="top">
- <td> <code class="source">message.CRIT</code> </td>
- <td> A critical error: the replicator stops immediately. Use this
- priority for errors in configuration discovered by your
- configuration generator or by the <a
- href="#defect_tracker.__init__"><code
- class="source">__init__</code></a> and <a
- href="#defect_tracker.init"><code class="source">init</code></a>
- methods of your defect tracker interface. </td>
- </tr>
- <tr valign="top">
- <td> <code class="source">message.ERR</code> </td>
- <td> An error. The replicator can't complete some operation. Use
- this priority for errors discovered during replication, such as
- untranslatable fields or permission failures. </td>
- </tr>
- <tr valign="top">
- <td> <code class="source">message.WARNING</code> </td>
- <td>
- <p> A warning. The replicator can continue, but the administrator
- may want to take some action. </p>
- <blockquote><p> <i>Example.</i> The Bugzilla integration issues
- a warning when it fails to find the Bugzilla configuration
- parameters in the MySQL database. The integration can continue
- (it just can't use the 'emailsuffix' parameter to assist in
- translating user identities), but it may not do what users
- expect. </p></blockquote>
- </td>
- </tr>
- <tr valign="top">
- <td> <code class="source">message.NOTICE</code> </td>
- <td>
- <p> A significant but expected condition. </p>
- <blockquote><p> <i>Example.</i> The replicator uses this priority
- when it has to overwrite a Perforce job with a defect tracker
- issue. This is the correct thing to do, and is the documented
- behaviour [<a
- href="../ug/index.html#section-2.2">UG, 2.2</a>]
- but it is still a significant event. </p></blockquote>
- </td>
- </tr>
- <tr valign="top">
- <td> <code class="source">message.INFO</code> </td>
- <td> For information only. </td>
- </tr>
- <tr valign="top">
- <td> <code class="source">message.DEBUG</code> </td>
- <td> Unlikely to be useful except for debugging. </td>
- </tr>
- </table>
- </dd>
- <dt><code class="source">product</code></dt>
- <dd><p> The name of software product which generated the message. For
- the supported <abbr title="Perforce Defect Tracking
- Integration">P4DTI</abbr>, this must be <code
- class="source">"P4DTI"</code>. </p></dd>
- </dl>
- <p> You can format a message as text by converting the message object to
- a string: </p>
- <blockquote><samp class="source">
- >>> str(msg) <br />
- "(Test-123X) Constructed a test message."
- </samp></blockquote>
- <p> Note that a check digit has been appended to the message identifier.
- (The check digit uses a mod-11 algorithm similar to that used in <abbr
- title="International Standard Book Number">ISBNs</abbr> [<a title="ISO
- 2108: International standard book number (ISBN)"
- href="#ref-ISO-2108">ISO 2108</a>], so the check digit can be 0-9 or X.)
- The idea of the check digit is so that <a
- href="http://www.perforce.com/perforce/support.html">Perforce
- support</a> can ask users for the message identifier of the error that
- they are reporting. The check digit makes it very likely that if the
- error is misreported or misheard the mistake is detected. </p>
- <p> You can wrap a message to some number of columns by calling its
- <code class="source">wrap</code> method: </p>
- <blockquote><samp class="source">
- >>> print msg.wrap(25) <br />
- (Test-123X) Constructed <br />
- a test message.
- </samp></blockquote>
- <h3><a id="section-5.2" name="section-5.2">5.2. Message catalogs</a></h3>
- <p> You may create each message when you need it, but you should use a
- message catalog. A catalog helps you keep message identifiers distinct
- and internationalizes your code. </p>
- <p> A message catalog is a dictionary that maps message identifier to a
- tuple of two elements: the message priority, and a format string that
- can be used to build the message text. For example: </p>
- <blockquote><pre class="source">
- # Test catalog in English
- test_en_catalog = {
- 123: (message.DEBUG, "Constructed a test message."),
- 124: (message.CRIT, "Couldn't connect to defect tracker on host '%s'."),
- 125: (message.ERR, "User '%s' has no permission to edit issue '%s'."),
- 126: (message.INFO, "Replicated issue %d."),
- # ...
- }
- </pre></blockquote>
- <p> Note that a message catalog must not have an entry for message id 0.
- That's reserved for errors from the catalog implementation. </p>
- <p> Once you have a message catalog for a product, you should build a
- message factory that dispenses messages from that catalog, like this:
- </p>
- <blockquote><pre class="source">
- import message
- product = "Test"
- factory = message.catalog_factory(test_en_catalog, product)
- </pre></blockquote>
- <p> Now you can construct a message by calling the factory's <code
- class="source">new</code> method and passing the message identifier,
- and the arguments for the format string: </p>
- <blockquote><pre class="source">
- msg1 = factory.new(124, 'dt.ravenbrook.com')
- msg2 = factory.new(125, ('gdr', 'BUG00123'))
- </pre></blockquote>
- <p> See the <a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/code/replicator/catalog.py"><code
- class="filename">catalog.py</code></a> module for the <abbr
- title="Perforce Defect Tracking Integration">P4DTI</abbr> catalog and
- message factory. </p>
- <h3><a id="section-5.3" name="section-5.3">5.3. Logging</a></h3>
- <p> The <abbr title="Perforce Defect Tracking Integration">P4DTI</abbr>
- logs its progress and errors by creating messages (see <a
- href="#section-5.1">section 5.1</a>) and sending them to a "logger":
- that is, an instance of the logger class defined by the <a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/code/replicator/logger.py"><code
- class="filename">logger.py</code></a> module. </p>
- <p> The logger module defines classes for logging to files, to standard
- output, and to the system log on Unix. The <code
- class="source">multi_logger</code> class directs a single message to
- several loggers. Each logger class takes a priority argument on
- instantiation: only messages with this priority, or a higher priority,
- appear in the log. </p>
- <p> You should log as many debugging messages as you like (by default
- the <a
- href="../ag/index.html#config-log_level"><code
- class="source">log_level</code></a> configuration parameter is <code
- class="source">message.INFO</code> so these messages won't appear). You
- should log informational messages sparingly, and only when you actually
- make a change in a database. You should not log error messages, but
- should raise them as exceptions instead (see <a
- href="#section-5.4">section 5.4</a>); the replicator logs them for you
- when it catches them. </p>
- <p> To add a message to a log, create a message object (see <a
- href="#section-5.1">section 5.1</a>) and pass it to the logger's
- <code class="source">log</code> message: </p>
- <blockquote><pre class="source">
- import logger
- # Log messages of priority INFO and higher to test.log:
- logger_object = logger.file_logger("test.log", message.INFO)
- msg = factory.new(126, issue_id)
- logger_object.log(msg)
- </pre></blockquote>
- <p> The configuration generator (see <a href="#section-8">section 8</a>)
- must construct a logger object for use by the replicator. The same
- logger object should be used by the defect tracker module (see <a
- href="#section-7">section 7</a>) as well, so that all messages are
- collected in the same place. You must allow the <abbr title="Perforce
- Defect Tracking Integration">P4DTI</abbr> administrator to control the
- volume of log messages by setting the <a
- href="../ag/index.html#config-log_level"><code
- class="source">log_level</code></a> configuration parameter. </p>
- <h3><a id="section-5.4" name="section-5.4">5.4. Errors</a></h3>
- <p> In the <abbr title="Perforce Defect Tracking
- Integration">P4DTI</abbr>, errors are indicated by raising a Python
- exception, not by returning an exceptional value. </p>
- <p> Raise an error using a string as the exception object, and a message
- object (see <a href="#section-5.1">section 5.1</a>) as the message. For
- example: </p>
- <blockquote><pre class="source">
- error = "Example error"
- # ...
- raise error, factory.new(124, 'dt.ravenbrook.com')
- </pre></blockquote>
- <p> It doesn't make any difference what priority you give to the
- message, but it is conventional to use <code
- class="source">message.CRIT</code> when the replicator stops (for
- example, configuration errors), and <code
- class="source">message.ERR</code> when the replicator continues (for
- example, untranslatable fields or permission failures). </p>
- <h3><a id="section-5.5" name="section-5.5">5.5. Source code layout</a></h3>
- <p> You should include in each file of source code: </p>
- <ol>
- <li><p> The author. </p></li>
- <li><p> An introduction explaining what the file is intended to
- achieve: for example, which requirements does it help to meet?
- </p></li>
- <li><p> A references section listing the sources you've used in
- preparing the code and which other people need to read in order to
- understand it. You should certainly refer to the appropriate sections
- in this manual. </p></li>
- <li><p> A history section listing the changes made to the code, with
- the date and the person who changed it. </p></li>
- <li><p> A statement of copyright. </p></li>
- <li><p> A license giving people permission to copy the file under
- certain conditions (or denying them permission if that's what you
- intend). </p></li>
- </ol>
- <blockquote><p> <i>Example.</i> The <a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/code/replicator/logger.py"><code
- class="filename">logger.py</code></a> module displays all these
- features. </p></blockquote>
- <h3><a id="section-5.6" name="section-5.6">5.6. Making changes</a></h3>
- <p> If you make a change to the <abbr title="Perforce Defect Tracking
- Interface">P4DTI</abbr> that you want to contribute to the project (see
- <a href="#section-12.2">section 12.2</a>), you should follow the rules
- in this section. The reason for this is that if we accept your
- contribution, we'll merge it into our product sources. It must be
- possible to carry out this merge reliably and without introducing
- errors. That means being able to consider each change separately,
- evaluate it and make a decision about how to merge it. </p>
- <p> To enable us to do so, follow the following rules: </p>
- <ol>
- <li><p> Don't delete stuff. Comment it out or skip it. </p></li>
- <li><p> Don't fiddle with the formatting of code or comments. It
- creates bogus conflicts that create extra work when merging. </p></li>
- <li><p> Add comments explaining why a change was made. Sign the
- comments with your name and the date. Explain why you had to make the
- change. Refer to defect reports when fixing them. </p></li>
- </ol>
- <h2><a id="section-6" name="section-6">6. The Python interface to the defect tracker</a></h2>
- <p> You'll need a way for Python to read and write defect tracking
- records. If the defect tracker has an <abbr title="Application
- Programmer Interface">API</abbr> of some sort, you'll need to use that;
- if not, you'll have to read and write the database directly, using one
- of the Python database interfaces. Your defect tracker interface needs
- to support these kinds of operations: </p>
- <ul>
- <li><p> Get an issue record. </p></li>
- <li><p> Update an issue record. </p></li>
- <li><p> Create a new issue record (if you support the <a
- href="#feature-migrate_issues">migrate_issues</a> or <a
- href="#feature-new_issues">new_issues</a> features). </p></li>
- <li><p> Get all the issues needing replication. </p></li>
- <li><p> Get all the fixes for an issue (if you support the <a
- href="#feature-fixes">fixes</a> feature). </p></li>
- <li><p> Add/update/delete a fix (if you support the <a
- href="#feature-fixes">fixes</a> feature). </p></li>
- <li><p> Create a table. </p></li>
- <li><p> Add a field to a table. </p></li>
- <li><p> Get a list of the fields that make up the issue relation,
- together with the field types, lengths, legal values, etc. </p></li>
- <li><p> Get a list of users, with names, userids, e-mail
- addresses. </p></li>
- <li><p> Add a new user (if you support the <a
- href="#feature-new_users">new_users</a> feature). </p></li>
- </ul>
- <p> I can't give you a complete or precise list of operations here;
- you'll have to see what's required as you implement your schema
- extensions (see <a href="#section-4">section 4</a>) and defect tracker
- module (see <a href="#section-7">section 7</a>). </p>
- <blockquote><p> <i>Example.</i> The TeamTrack integration used the
- TeamShare <abbr title="Application Programmer Interface">API</abbr> to
- connect to the defect tracker, because the <abbr title="Application
- Programmer Interface">API</abbr> provides methods that apply
- TeamTrack's privilege system and database validation. The integration
- used a Python extension module that provided an interface to the parts
- of the TeamShare <abbr title="Application Programmer
- Interface">API</abbr> that it needed (only a small part of the whole
- <abbr title="Application Programmer Interface">API</abbr>, as it
- happened). See the design of the interface to Teamtrack [<a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/design/python-teamtrack-interface/">GDR
- 2000-08-08</a>]. </p></blockquote>
- <blockquote><p> <i>Example.</i> Bugzilla has no <abbr title="Application
- Programmer Interface">API</abbr>: you have to understand the Bugzilla
- database schema [<a
- href="http://www.ravenbrook.com/project/p4dti/tool/cgi/bugzilla-schema/">NB 2000-11-14a</a>]
- and connect directly to the MySQL database. The Bugzilla integration
- uses a wrapper module that encapsulates the direct database operations
- as defect tracker oriented functions like <code
- class="source">update_bug</code>. See <a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/code/replicator/bugzilla.py"><code
- class="filename">bugzilla.py</code></a> and its design [<a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/design/python-bugzilla-interface/">NB
- 2000-11-14c</a>]. </p></blockquote>
- <h2><a id="section-7" name="section-7">7. The defect tracker module</a></h2>
- <p> You must create a module called <code
- class="filename">dt_<i>defect_tracker</i>.py</code> (where <code
- class="filename"><i>defect_tracker</i></code> is the lower-case form of
- the name your chose for your defect tracker (see <a
- href="#section-3">section 3</a>)) that implements these classes: </p>
- <ol>
- <li><p> The defect tracker interface itself: a subclass of <code
- class="source">dt_interface.defect_tracker</code> (see <a
- href="#section-7.1">section 7.1</a>). </p></li>
- <li><p> Defect tracker issue: a subclass of <code
- class="source">dt_interface.defect_tracker_issue</code> (see <a
- href="#section-7.2">section 7.2</a>). </p></li>
- <li><p> If you support the <a href="#feature-fixes">fixes</a> feature,
- defect tracker fix: a subclass of <code
- class="source">dt_interface.defect_tracker_fix</code> (see <a
- href="#section-7.3">section 7.3</a>). </p></li>
- <li><p> If you support the <a href="#feature-filespecs">filespecs</a>
- feature, defect tracker filespec: a subclass of <code
- class="source">dt_interface.defect_tracker_filespec</code> (see <a
- href="#section-7.4">section 7.4</a>). </p></li>
- <li><p> A translator between dates in the defect tracker and Perforce:
- a subclass of <code class="source">translator.translator</code> (see
- <a href="#section-7.5.1">section 7.5.1</a>). </p></li>
- <li><p> A translator between multi-line text fields in the defect
- tracker and Perforce: a subclass of <code
- class="source">translator.translator</code> (see <a
- href="#section-7.5.3">section 7.5.3</a>). </p></li>
- <li><p> A translator between users in the defect tracker and Perforce:
- a subclass of <code class="source">translator.user_translator</code>
- (see <a href="#section-7.5.4">section 7.5.4</a>). </p></li>
- <li><p> Any other translator classes that are needed to translate
- fields in the issue relation (see <a href="#section-7.5">section
- 7.5</a>). </p></li>
- </ol>
- <blockquote><p> <i>Example.</i> The Bugzilla module, <a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/code/replicator/dt_bugzilla.py"><code
- class="filename">dt_bugzilla.py</code></a>. </p></blockquote>
- <h3><a id="section-7.1" name="section-7.1">7.1. The <code class="source">dt_interface.defect_tracker</code> class</a></h3>
- <p> A subclass of <code
- class="source">dt_interface.defect_tracker</code> implements the
- replicator's interface to a defect tracker. </p>
- <blockquote><p> <i>Example.</i> The <a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/code/replicator/dt_bugzilla.py"><code
- class="source">dt_bugzilla.py</code></a> module defines a class <code
- class="source">dt_bugzilla</code>. </p></blockquote>
- <p> A subclass of <code
- class="source">dt_interface.defect_tracker</code> must define the
- following methods: </p>
- <h4> <a id="defect_tracker.__init__" name="defect_tracker.__init__"><code class="source">__init__(self, config)</code></a> </h4>
- <p> This is called when the defect tracker object is created. The <code
- class="source">config</code> argument is an object whose attributes are
- the configuration parameters for the defect tracker. See <a
- href="#section-8">section 8</a> for the details of how configuration
- parameters end up in this object. </p>
- <p> This method should check that all configuration parameters are
- supplied and have valid values. Use the methods in <code
- class="filename"><a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/code/replicator/check_config.py">check_config.py</a></code>
- for basic checks. </p>
- <p> The required parameters should certainly include <a
- href="../ag/index.html#config-changelist_url"><code
- class="source">changelist_url</code></a>, <a
- href="../ag/index.html#config-job_url"><code
- class="source">job_url</code></a>, <a
- href="../ag/index.html#config-p4_server_description"><code
- class="source">p4_server_description</code></a>, <a
- href="../ag/index.html#config-rid"><code
- class="source">rid</code></a>, <a
- href="../ag/index.html#config-sid"><code
- class="source">sid</code></a>, and <a
- href="../ag/index.html#config-start_date"><code
- class="source">start_date</code></a>, but may include others, either
- supplied by the <abbr title="Perforce Defect Tracking
- Integration">P4DTI</abbr> administrator in <a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/code/replicator/config.py"><code
- class="filename">config.py</code></a> or generated by the configuration
- generator. </p>
- <h4> <a id="defect_tracker.add_replicator_user" name="defect_tracker.add_replicator_user"><code class="source">add_replicator_user(self)</code></a> </h4>
- <p> (The <code class="source">add_replicator_user</code> method
- belongs to the <a href="#feature-new_users">new_users</a> feature.)
- </p>
- <p> This method is called during migration from Perforce to request
- that the distinguished replicator user be added to the defect tracker.
- The e-mail address of this user is defined by the <a
- href="../ag/index.html#config-replicator_address"><code
- class="source">replicator_address</code></a> configuration
- parameter). </p>
- <p> If there is already a user in the defect tracker with this e-mail
- address, then do nothing. Return the userid of that user. </p>
- <p> If there is no such user, then if possible add a user to the
- defect tracker who will in future be mapped to the replicator's
- Perforce user (<a href="../ag/index.html#config-p4_user"><code
- class="source">p4_user</code></a>) by your user translator (<a
- href="#section-7.5.4">section 7.5.4</a>). Return the userid of the
- new user. </p>
- <p> If it's not possible to add such a user, return <code
- class="source">None</code>. </p>
- <p> This method is optional. You need not provide it if you don't
- support migration of users from Perforce. </p>
- <h4> <a id="defect_tracker.add_user" name="defect_tracker.add_user"><code class="source">add_user(self, p4_user, email, fullname)</code></a> </h4>
- <p> (The <code class="source">add_user</code> method belongs to the <a
- href="#feature-new_users">new_users</a> feature.) </p>
- <p> This method is called during migration from Perforce to request that
- a user be added to the defect tracker. The <code
- class="source">p4_user</code> argument is the userid in Perforce; the
- <code class="source">email</code> argument is the user's e-mail address,
- and the <code class="source">fullname</code> argument is the user's full
- name. </p>
- <p> If there is already a user in the defect tracker who is mapped to
- this Perforce user by your user translator (<a
- href="#section-7.5.4">section 7.5.4</a>), then do nothing. Return the
- userid of that user. </p>
- <p> If there is no such user, then if possible add a user to the defect
- tracker who will in future be mapped to the this Perforce user by your
- user translator (<a href="#section-7.5.4">section 7.5.4</a>). Return
- the userid of the new user. </p>
- <p> If it's not possible to add such a user, return <code
- class="source">None</code>. </p>
- <p> This method is optional. You need not provide it if you don't
- support migration of users from Perforce. </p>
- <h4> <a id="defect_tracker.all_issues" name="defect_tracker.all_issues"><code class="source">all_issues(self)</code></a> </h4>
- <p> Return a cursor (see <a href="#section-7.6">section 7.6</a>) that
- fetches all defect tracking issues that either (a) are replicated by this
- replicator or (b) are not replicated and have been modified since the
- starting point for replication (that is, the date given by the <abbr
- title="Perforce Defect Tracking Integration">P4DTI</abbr>
- administrator in the <a
- href="../ag/index.html#config-start_date"><code
- class="source">start_date</code></a> parameter). </p>
- <p> Include in the cursor: </p>
- <ul>
- <li><p> Issues replicated by this replicator (that is, the replicator
- identifier for those issues matches the <a
- href="../ag/index.html#config-rid"><code
- class="source">rid</code></a> configuration parameter); </p></li>
- <li><p> Issues not replicated by any replicator (that is, the
- replicator identifier for those issues is blank) and changed since the
- start date. </p></li>
- </ul>
- <p> Omit from the cursor: </p>
- <ul>
- <li><p> Issues replicated by a different replicator (that is, the
- replicator identifier for those issues differs from the <a
- href="../ag/index.html#config-rid"><code
- class="source">rid</code></a> configuration parameter); </p></li>
- <li><p> Issues not replicated by any replicator and unchanged since
- the start date. </p></li>
- </ul>
- <p> Each element fetched by the returned cursor must belong to your
- subclass of the <code
- class="source">dt_interface.defect_tracker_issue</code> class (see <a
- href="#section-7.2">section 7.2</a>). </p>
- <h4> <a id="defect_tracker.changed_entities" name="defect_tracker.changed_entities"><code class="source">changed_entities(self)</code></a> </h4>
- <p> This method is called at the start of each replication cycle to
- determine what work there is to do. The method <a
- href="#defect_tracker.poll_start"><code
- class="source">poll_start</code></a> is called just before this.</p>
- <p> It must return a tuple of three elements: </p>
- <ol>
- <li><p> A cursor (see <a href="#section-7.6">section 7.6</a>) that
- fetches the defect tracking issues that require replication. </p>
- <p> Each element fetched by the returned cursor must belong to your
- subclass of the <code
- class="source">dt_interface.defect_tracker_issue</code> class (see <a
- href="#section-7.2">section 7.2</a>). </p>
- <p> Include in the cursor: </p>
- <ul>
- <li><p> Issues replicated by this replicator (that is, the
- replicator identifier for those issues matches the <a
- href="../ag/index.html#config-rid"><code
- class="source">rid</code></a> configuration parameter); </p></li>
- <li><p> Issues not replicated by any replicator (that is, the
- replicator identifier for those issues is blank). The replicator
- considers these issues as candidates for replication. </p></li>
- </ul>
- <p> Omit from the cursor: </p>
- <ul>
- <li><p> Issues replicated by a different replicator (that is, the
- replicator identifier for those issues differs from the <a
- href="../ag/index.html#config-rid"><code
- class="source">rid</code></a> configuration parameter). </p></li>
- <li><p> Issues known to be up to date with Perforce; either because
- they are unchanged since they were last replicated, or because they
- have only been changed by the replicator (see <a
- href="#section-4.6">section 4.6</a> and <a
- href="#section-4.7">section 4.7</a>). </p></li>
- </ul></li>
- <li><p> The empty list <code class="source">[ ]</code>. (This is for
- symmetry with the Perforce interface, which returns a list of
- changelists. Since changelists are not editable in the defect
- tracker, there's nothing that can be returned here, hence the empty
- list.) </p></li>
- <li><p> A marker. This must be some token that identifies what has
- been done on this poll. At the end of the replication cycle it is
- passed to <a href="#defect_tracker.mark_changes_done"><code
- class="source">mark_changes_done</code></a>. </p>
- <blockquote><p> <i>Example.</i> The TeamTrack integration used the
- record number of the last record in the <code
- class="source">TS_CHANGES</code> table that the replicator looked at
- as the marker indicating what it's done. See the design [<a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/design/teamtrack-p4dti-schema/#section-3.5">GDR
- 2000-09-04, 3.5</a>]. </p></blockquote></li>
- </ol>
- <p> This method must not record that the issues it returns have been
- considered for replication or replicated. The replicator can encounter
- an error during the course of replication that prevents it from making
- any progress (Perforce can go down, the defect tracker can go down, the
- replicator can crash). When the system comes back up, the replicator
- must re-consider these issues and possibly replicate them again. This
- helps keep the databases consistent (<a
- href="http://www.ravenbrook.com/project/p4dti/req/#req-1">requirement
- 1</a>) and is consistent with the design principle that the replicator
- must have no internal state (see <a href="#section-4.5">section
- 4.5</a>). </p>
- <p> Recording that issues have been replicated must be left for the end
- of each replication cycle, when the marker (the third item in the tuple)
- is passed to <a href="#defect_tracker.mark_changes_done"><code
- class="source">mark_changes_done</code></a>.</p>
- <h4> <a id="defect_tracker.init" name="defect_tracker.init"><code class="source">init(self)</code></a> </h4>
- <p> This method is called each time the replicator starts. </p>
- <p> The method must initialize the defect tracking database so that it
- is ready to start replication. The tables and fields in your schema
- extensions (see <a href="#section-4">section 4</a>) must be added if they
- are not yet present. </p>
- <h4> <a id="defect_tracker.issue" name="defect_tracker.issue"><code class="source">issue(self, issue_id)</code></a> </h4>
- <p> Return the defect tracking issue identified by the <code
- class="source">issue_id</code> argument, or None if there is no such
- issue. The returned issue (if any) must belong to your subclass of the
- <code class="source">dt_interface.defect_tracker_issue</code> class (see <a
- href="#section-7.2">section 7.2</a>). </p>
- <p> The <code class="source">issue_id</code> argument is a string
- identifying the issue (see <a href="#section-7.2.1">section 7.2.1</a>). </p>
- <h4> <a id="defect_tracker.mark_changes_done" name="defect_tracker.mark_changes_done"><code class="source">mark_changes_done(self, marker)</code></a> </h4>
- <p> This method is called at the end of each replication cycle, when all
- issues have been replicated. </p>
- <p> The <code class="source">marker</code> argument is the third item in
- the tuple returned by the <a
- href="#defect_tracker.changed_entities"><code
- class="source">changed_entities</code></a> method at the start of the
- replication cycle. </p>
- <p> This method must now record that it has considered all changes up to
- the start of this replication cycle and replicated them successfully, so
- that at the next replication cycle it can ignore these changes and
- consider a new set of changes (see <a href="#section-4.6">section
- 4.6</a>). </p>
- <h4> <a id="defect_tracker.new_issue" name="defect_tracker.new_issue"><code class="source">new_issue(self, dict, jobname)</code></a> </h4>
- <p> (The <code class="source">new_issue</code> method belongs to the <a
- href="#feature-migrate_issues">migrate_issues</a> and <a
- href="#feature-new_issues">new_issues</a> features.) </p>
- <p> Create a new issue in the defect tracker and set it up for
- replication (this is called both during migration from Perforce jobs,
- and when a new job has been created in Perforce). The <code
- class="source">dict</code> argument is a dictionary mapping defect
- tracker field name to a value for that field (the values have been
- translated from Perforce), and the <code class="source">jobname</code>
- argument is the name of the corresponding job in Perforce. </p>
- <p> You should do your best to supply default values for required fields
- if they are not present in <code class="source">dict</code>, and you
- should try to avoid defect tracker workflow constraints (such as
- insisting that an issue start out in a particular state). If all else
- fails, raise an error. </p>
- <p> Return the newly-created issue as an object belonging to the <a
- href="#section-7.2"><code class="source">defect_tracker_issue</code></a>
- class. </p>
- <p> The newly-created issue should respond in future as if its <a
- href="#defect_tracker_issue.setup_for_replication"><code
- class="source">setup_for_replication</code></a> method had been called
- with <code class="source">jobspec</code> as the argument. It is up to
- you whether to call that method or implement the effect in some other
- way. </p>
- <p> This method is optional. You need not provide it if you don't
- support migration from Perforce. </p>
- <h4> <a id="defect_tracker.new_issues_start" name="defect_tracker.new_issues_start"><code class="source">new_issues_start(self)</code></a> </h4>
- <p> (The <code class="source">new_issues_start</code> method belongs to
- the <a href="#feature-migrate_issues">migrate_issues</a> and <a
- href="#feature-new_issues">new_issues</a> features.) </p>
- <p> This method is called by the <abbr title="Perforce Defect Tracking
- Integration">P4DTI</abbr> just before it starts migrating jobs from
- Perforce to the defect tracker. </p>
- <p> If you need to take a lock in the defect tracker database, take it
- here and release it in <a href="#defect_tracker.new_issues_end"><code
- class="source">new_issues_end</code></a>. </p>
- <p> This method is optional. You need not provide it if you don't
- support migration from Perforce. </p>
- <h4> <a id="defect_tracker.new_issues_end" name="defect_tracker.new_issues_end"><code class="source">new_issues_end(self)</code></a> </h4>
- <p> (The <code class="source">new_issues_end</code> method belongs to
- the <a href="#feature-migrate_issues">migrate_issues</a> and <a
- href="#feature-new_issues">new_issues</a> features.) </p>
- <p> This method is called by the <abbr title="Perforce Defect Tracking
- Integration">P4DTI</abbr> just after it finishes migrating jobs from
- Perforce to the defect tracker. </p>
- <p> If you needed to take a lock in the defect tracker database, in <a
- href="#defect_tracker.new_issues_start"><code
- class="source">new_issues_start</code></a>, release it here. </p>
- <p> This method is optional. You need not provide it if you don't
- support migration from Perforce. </p>
- <h4> <a id="defect_tracker.poll_start" name="defect_tracker.poll_start"><code class="source">poll_start(self)</code></a> </h4>
- <p> This method is called by the <abbr title="Perforce Defect Tracking
- Integration">P4DTI</abbr> just before it polls the defect tracker with
- the <a href="#defect_tracker.changed_entities"><code
- class="source">changed_entities</code></a> method to discover changed
- entities. </p>
- <p> If you need to take a lock in the defect tracker database, take it
- here and release it in <a href="#defect_tracker.poll_end"><code
- class="source">poll_end</code></a>. </p>
- <p> This method is optional. You need not provide it. </p>
- <h4> <a id="defect_tracker.poll_end" name="defect_tracker.poll_end"><code class="source">poll_end(self)</code></a> </h4>
- <p> This method is called by the <abbr title="Perforce Defect Tracking
- Integration">P4DTI</abbr> at the end of each replication cycle. It is
- called whether or not the replication succeeded.</p>
- <p> If you needed to take a lock in the defect tracker database, in <a
- href="#defect_tracker.poll_start"><code
- class="source">poll_start</code></a>, release it here. </p>
- <p> This method is optional. You need not provide it. </p>
- <h4> <a id="defect_tracker.replicate_changelist" name="defect_tracker.replicate_changelist"><code class="source">replicate_changelist(self, change, client, date, description, status, user)</code></a> </h4>
- <p> (The <code class="source">replicate_changelist</code> method belongs
- to the <a href="#feature-fixes">fixes</a> feature.) </p>
- <p> Replicate a changelist to the defect tracker database (see <a
- href="#section-4.2">section 4.2</a>). </p>
- <p> The arguments specify the changelist; these arguments correspond to
- a subset of the fields in the changelist relation in the Perforce
- database (the names of the actual files changed, and their new revision
- numbers, are not replicated). </p>
- <dl>
- <dt><code class="source">change</code></dt>
- <dd><p> The change number (an integer). </p></dd>
- <dt><code class="source">client</code></dt>
- <dd><p> The client on which the change was last modified (a
- string). </p></dd>
- <dt><code class="source">date</code></dt>
- <dd><p> The date and time at which the change was last modified. It
- has been converted by the date translator (see <a
- href="#section-7.5.1">section 7.5.1</a>). </p></dd>
- <dt><code class="source">description</code></dt>
- <dd><p> The change comment. It has been converted by the text
- translator (see <a href="#section-7.5.3">section 7.5.3</a>). </p></dd>
- <dt><code class="source">status</code></dt>
- <dd><p> <code class="source">"pending"</code> if the changelist is
- pending, <code class="source">"submitted"</code> otherwise. </p></dd>
- <dt><code class="source">user</code></dt>
- <dd><p> The user who last modified the changelist. It has been
- converted by the user translator (see <a href="#section-7.5.4">section
- 7.5.4</a>). </p></dd>
- </dl>
- <p> This method must return 1 if the changelist was new or changed, or
- 0 if it was unchanged. </p>
- <h4> <a id="defect_tracker.supports" name="defect_tracker.supports"><code class="source">supports(self, feature)</code></a> </h4>
- <p> Return 1 if your integration supports the feature named by the
- <code class="source">feature</code> argument (a string); return 0 if you
- don't support the feature. See <a href="#section-3.5">section 3.5</a>
- for the list of optional features. If you don't recognize the feature,
- return 0. </p>
- <h3><a id="section-7.2" name="section-7.2">7.2. The <code class="source">dt_interface.defect_tracker_issue</code> class</a></h3>
- <p> A subclass of <code
- class="source">dt_interface.defect_tracker_issue</code> implements the
- replicator's interface to the issues in a defect tracker. </p>
- <blockquote><p> <i>Example.</i> The <a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/code/replicator/dt_bugzilla.py"><code
- class="source">dt_bugzilla.py</code></a> module defines a class <code
- class="source">bugzilla_bug</code> (issues are called "bugs" in
- Bugzilla). </p></blockquote>
- <h4><a id="section-7.2.1" name="section-7.2.1">7.2.1. Issue identifiers</a></h4>
- <p> The replicator needs a unique identifier for each issue in the
- defect tracker. This must be a string, so that it can be stored in the
- <code class="source">P4DTI-issue-id</code> field in the Perforce jobspec
- [<a href="http://www.ravenbrook.com/project/p4dti/version/2.2/design/replicator/#section-4.2">GDR
- 2000-09-13, 4.2</a>]. The replicator gets the identifier from an
- issue's <a href="#defect_tracker_issue.id"><code
- class="source">id</code></a> method. Later, it may pass the
- identifier to the defect tracker's <a href="#defect_tracker.issue"><code
- class="source">issue</code></a> method. </p>
- <blockquote><p> <i>Example.</i> Bugzilla uniquely identifies bugs by
- their bug number. So in the <code class="source">dt_bugzilla</code>
- module, the issue identifier is the string conversion of the bug
- number. </p></blockquote>
- <h4><a id="section-7.2.2" name="section-7.2.2">7.2.2. Issues are dictionaries</a></h4>
- <p> The replicator considers an issue to consist of a collection of
- named fields, with a value for each field. Instances of the <code
- class="source">defect_tracker_issue</code> subclass must support at
- least the <a href="#defect_tracker_issue.__getitem__"><code
- class="source">__getitem__</code></a> method, so that the replicator
- can get the value for a field in an issue using the expression <code
- class="source">issue["fieldname"]</code>. </p>
- <p> You may want to implement the whole of the Python dictionary
- interface for your own use, but the replicator only uses
- <code class="source">__getitem__</code>.</p>
- <p> A subclass of <code
- class="source">dt_interface.defect_tracker_issue</code> must define the
- following methods: </p>
- <h4> <a id="defect_tracker_issue.__getitem__" name="defect_tracker_issue.__getitem__"><code class="source">__getitem__(self, field)</code></a> </h4>
- <p> Return the value of the field named by the <code
- class="source">field</code> argument. Raise <code
- class="source">KeyError</code> if the issue has no such field. </p>
- <h4> <a id="defect_tracker_issue.__str__" name="defect_tracker_issue.__str__"><code class="source">__str__(self)</code></a> </h4>
- <p> Return a string describing the issue, suitable for presentation to a
- user or administrator in a report. Having several lines of the form
- "field name: value" is fine. </p>
- <h4> <a id="defect_tracker_issue.add_filespec" name="defect_tracker_issue.add_filespec"><code class="source">add_filespec(self, filespec)</code></a> </h4>
- <p> (The <code class="source">add_filespec</code> method belongs to the <a
- href="#feature-filespecs">filespecs</a> feature.) </p>
- <p> Add a filespec to the issue (see <a href="#section-4.4">section 4.4</a>). </p>
- <p> The argument is the filespec to add (a string). </p>
- <h4> <a id="defect_tracker_issue.add_fix" name="defect_tracker_issue.add_fix"><code class="source">add_fix(self, change, client, date, status, user)</code></a> </h4>
- <p> (The <code class="source">add_fix</code> method belongs to the <a
- href="#feature-fixes">fixes</a> feature.) </p>
- <p> Add a fix to the issue (see <a href="#section-4.3">section 4.3</a>). </p>
- <p> The arguments specify the fix; these arguments correspond to the
- fields in the fix relation in the Perforce database. </p>
- <dl>
- <dt><code class="source">change</code></dt>
- <dd><p> The Perforce change number (an integer). </p></dd>
- <dt><code class="source">client</code></dt>
- <dd><p> The Perforce client name from which the fix was made (a
- string). </p></dd>
- <dt><code class="source">date</code></dt>
- <dd><p> The date the fix was made. It has been converted by the date
- translator (see <a href="#section-7.5.1">section 7.5.1</a>). </p></dd>
- <dt><code class="source">status</code></dt>
- <dd><p> The effect of the fix. It is the status the job was changed
- to when the fix was made (or if the fix is to a pending changelist,
- then this is the status the job is changed to when the changelist is
- submitted). </p>
- <p> The status is also known as the "effect" (for example, in the
- defect tracker's interface to fixes (see <a href="#section-9">section
- 9</a>)) because it gives the effect on the job when the fix is
- submitted. </p></dd>
- <dt><code class="source">user</code></dt>
- <dd><p> The user who made the fix. It has been converted by the user
- translator (see <a href="#section-7.5.4">section 7.5.4</a>). </p></dd>
- </dl>
- <h4> <a id="defect_tracker_issue.corresponding_id" name="defect_tracker_issue.corresponding_id"><code class="source">corresponding_id(self)</code></a> </h4>
- <p> If this issue has been replicated, return the name of the Perforce
- job to which this issue is replicated. </p>
- <p> If this issue has not yet been replicated, return the name for the
- Perforce job to which this issue is replicated. The returned value must
- be legal as the name of a Perforce job. You may want to use the result
- of the <a href="#defect_tracker_issue.corresponding_id"><code
- class="source">readable_name</code></a> method if that is
- suitable. </p>
- <h4> <a id="defect_tracker_issue.delete" name="defect_tracker_issue.delete"><code class="source">delete(self)</code></a> </h4>
- <p> (The <code class="source">delete</code> method belongs to the <a
- href="#feature-migrate_issues">migrate_issues</a> and <a
- href="#feature-new_issues">new_issues</a> features.) </p>
- <p> Delete the issue from the defect tracker (or flag the issue so that
- it is not returned by the <a href="#defect_tracker.all_issues"><code
- class="source">all_issues</code></a> and <a
- href="#defect_tracker.changed_entities"><code
- class="source">changed_entities</code></a> methods in future, if
- deletion is impossible). </p>
- <p> This method is only ever called of an issue that has just been
- created by the <a href="#defect_tracker.new_issue"><code
- class="source">new_issue</code></a> method, if an error occurred while
- setting up the new issue. </p>
- <h4> <a id="defect_tracker_issue.filespecs" name="defect_tracker_issue.filespecs"><code class="source">filespecs(self)</code></a> </h4>
- <p> (The <code class="source">filespecs</code> method belongs to the <a
- href="#feature-filespecs">filespecs</a> feature.) </p>
- <p> Return a list of the filespecs associated with this issue. Each
- item in the list belongs to your subclass of the <code
- class="source">defect_tracker_filespec</code> class (see <a
- href="#section-7.4">section 7.4</a>). </p>
- <h4> <a id="defect_tracker_issue.fixes" name="defect_tracker_issue.fixes"><code class="source">fixes(self)</code></a> </h4>
- <p> (The <code class="source">fixes</code> method belongs to the <a
- href="#feature-fixes">fixes</a> feature.) </p>
- <p> Return a list of the fixes for this issue. Each item in the list
- belongs to your subclass of the <code
- class="source">defect_tracker_fix</code> class (see <a
- href="#section-7.3">section 7.3</a>). </p>
- <h4> <a id="defect_tracker_issue.id" name="defect_tracker_issue.id"><code class="source">id(self)</code></a> </h4>
- <p> Return a string that can be used to uniquely identify this issue
- among all the issues in the defect tracker and to fetch it in future (see <a
- href="#section-7.2.1">section 7.2.1</a>). </p>
- <h4> <a id="defect_tracker_issue.readable_name" name="defect_tracker_issue.readable_name"><code class="source">readable_name(self)</code></a> </h4>
- <p> Return a string giving a human-readable name for the issue. This
- name is only used in logs and e-mail messages. </p>
- <h4> <a id="defect_tracker_issue.rid" name="defect_tracker_issue.rid"><code class="source">rid(self)</code></a> </h4>
- <p> Return the replicator identifier of the replicator that is in charge
- of replicating this issue, or the empty string if the issue is not being
- replicated. </p>
- <h4> <a id="defect_tracker_issue.setup_for_replication" name="defect_tracker_issue.setup_for_replication"><code class="source">setup_for_replication(self, jobname)</code></a> </h4>
- <p> Set up the issue for replication. That is, record that the issue is
- replicated by this replicator and record any other information in the
- database that is needed to replicate this issue. </p>
- <p> You must do at least these three steps: </p>
- <ol>
- <li><p> Record that the issue is replicated by this replicator, so
- that in the future its <a href="#defect_tracker_issue.rid"><code
- class="source">rid</code></a> method returns the correct replicator
- identifier (this is the <code class="source">rid</code> parameter in
- the configuration passed to the defect tracker class when it was
- instantiated). </p></li>
- <li><p> Record the Perforce server identifier of the Perforce server
- it is replicated to (this is the <code class="source">sid</code>
- parameter in the configuration passed to the defect tracker class when
- it was instantiated). </p></li>
- <li><p> Record that the issue is replicated to the Perforce job named
- by the <code class="source">jobname</code> argument, so that in future
- its <a href="#defect_tracker_issue.corresponding_id"><code
- class="source">corresponding_id</code></a> method returns <code
- class="source">jobname</code>. </p></li>
- </ol>
- <p> See <a href="#section-4.1">section 4.1</a>. </p>
- <h4> <a id="defect_tracker_issue.update" name="defect_tracker_issue.update"><code class="source">update(self, user, changes)</code></a> </h4>
- <p> Update the issue in the defect tracker's database. </p>
- <p> The <code class="source">user</code> argument is the user who made
- the change. It has been converted by the user translator (see <a
- href="#section-7.5.4">section 7.5.4</a>). </p>
- <p> The <code class="source">changes</code> argument is a dictionary of
- the changes that must be applied to the issue. The keys of the
- dictionary are the names of the fields that have changed; the values are
- the new values for those fields. Each value in the dictionary has been
- converted by the appropriate translator. If <code
- class="source">changes</code> is the empty dictionary, then do
- nothing. </p>
- <p> If the defect tracker supports transitions in a workflow, then this
- method should deduce the transition to apply (if any) based on the old
- and new values for the issue fields. </p>
- <blockquote><p> <i>Example.</i> The TeamTrack integration attempted to
- find and apply a transition when the <code class="source">STATE</code>
- field changes. It looked at all the available transitions for the
- issue and selected the transition resulting in the correct new
- state. </p></blockquote>
- <blockquote><p> <i>Example.</i> Bugzilla doesn't have transitions as
- distinguished workflow objects, so there's no need for the Bugzilla
- integration to deduce one.</p></blockquote>
- <p> This method must check that the proposed change to the issue is
- legal in the defect tracker. (The changed fields have been converted by
- their translators, so each is legal individually, but the defect tracker
- may be more stringent, for example it may require a field not to have a
- value when the issue is in a particular state.) It must also check that
- the user has permission to make the proposed change. It's best if you
- can call a function in the defect tracker's <abbr title="Application
- Programmer Interface">API</abbr> to apply the defect tracker's own rules
- (this is likely to be robust and maintainable), but if there's no such
- function, then you must do your best to emulate the defect tracker's
- checks. </p>
- <p> If the issue can't be updated (for example, because the user doesn't
- have permission to make the change, or because no workflow transition
- can be discovered, or because the proposed change is illegal in some
- way) then this method must raise an error. </p>
- <blockquote><p> <i>Example.</i> The TeamTrack integration called the
- <code class="source">TSServer::Transition</code> method in the
- TeamShare <abbr title="Application Programmer Interface">API</abbr>,
- which checked the issue for correctness and checked that the user has
- the correct privilege. All the integration needed to do is raise an
- error if the function rejected the transition. </p></blockquote>
- <blockquote><p> <i>Example.</i> Bugzilla has no <abbr title="Application
- Programmer Interface">API</abbr>, so the Bugzilla integration must
- emulate Bugzilla's checking. The <a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/code/replicator/dt_bugzilla.py"><code
- class="filename">dt_bugzilla.py</code></a> module defines three checking
- methods: <code class="source">restrict_fields</code>, <code
- class="source">enforce_invariants</code>, and <code
- class="source">check_permissions</code>. </p></blockquote>
- <h3><a id="section-7.3" name="section-7.3">7.3. The <code class="source">dt_interface.defect_tracker_fix</code> class</a></h3>
- <p> (The <code class="source">defect_tracker_fix</code> class belongs to
- the <a href="#feature-fixes">fixes</a> feature.) </p>
- <p> A subclass of <code
- class="source">dt_interface.defect_tracker_fix</code> implements the
- replicator's interface to a fix record in a defect tracker (see <a
- href="#section-4.3">section 4.3</a>). </p>
- <blockquote><p> <i>Example.</i> The <a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/code/replicator/dt_bugzilla.py"><code
- class="source">dt_bugzilla.py</code></a> module defines a class <code
- class="source">bugzilla_fix</code>. </p></blockquote>
- <p> A subclass of <code
- class="source">dt_interface.defect_tracker_fix</code> must define the
- following methods: </p>
- <h4> <a id="defect_tracker_fix.change" name="defect_tracker_fix.change"><code class="source">change(self)</code></a> </h4>
- <p> Return the change number for the fix, an integer. </p>
- <h4> <a id="defect_tracker_fix.delete" name="defect_tracker_fix.delete"><code class="source">delete(self)</code></a> </h4>
- <p> Delete the fix in the defect tracker so that the change is no longer
- linked to the issue. </p>
- <h4> <a id="defect_tracker_fix.status" name="defect_tracker_fix.status"><code class="source">status(self)</code></a> </h4>
- <p> Return the status of the fix, a string. </p>
- <h4> <a id="defect_tracker_fix.update" name="defect_tracker_fix.update"><code class="source">update(self, change, client, date, status, user)</code></a> </h4>
- <p> Update this fix in the defect tracker so that has the given
- fields. If the fields are unchanged, do nothing. </p>
- <p> This method is called when someone makes a new fix between the
- change and issue of an existing fix (for example, the status used to be
- "open", but now is "closed"). Since there can be only one fix for a
- given change and issue, the replicator updates the fix rather than
- creating a new fix. </p>
- <p> The arguments specify the fix; these arguments correspond to the
- fields in the fix relation in the Perforce database. </p>
- <dl>
- <dt><code class="source">change</code></dt>
- <dd><p> The Perforce change number (an integer). </p></dd>
- <dt><code class="source">client</code></dt>
- <dd><p> The Perforce client name from which the fix was made (a
- string). </p></dd>
- <dt><code class="source">date</code></dt>
- <dd><p> The date the fix was made. It has been converted by the date
- translator (see <a href="#section-7.5.1">section 7.5.1</a>). </p></dd>
- <dt><code class="source">status</code></dt>
- <dd><p> The effect of the fix. It is the status the job was changed
- to when the fix was made (or if the fix is to a pending changelist,
- then this is the status the job is changed to when the changelist is
- submitted). </p>
- <p> The status is also known as the "effect" (for example, in the
- defect tracker's interface to fixes (see <a href="#section-9">section
- 9</a>)) because it gives the effect on the job when the fix is
- submitted. </p></dd>
- <dt><code class="source">user</code></dt>
- <dd><p> The user who made the fix. It has been converted by the user
- translator (see <a href="#section-7.5.4">section 7.5.4</a>). </p></dd>
- </dl>
- <h3><a id="section-7.4" name="section-7.4">7.4. The <code class="source">dt_interface.defect_tracker_filespec</code> class</a></h3>
- <p> (The <code class="source">defect_tracker_filespec</code> class
- belongs to the <a href="#feature-filespecs">filespecs</a> feature.) </p>
- <p> A subclass of <code
- class="source">dt_interface.defect_tracker_filespec</code> implements the
- replicator's interface to a filespec record in a defect tracker (see <a
- href="#section-4.4">section 4.4</a>). </p>
- <blockquote><p> <i>Example.</i> The <a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/code/replicator/dt_bugzilla.py"><code
- class="source">dt_bugzilla.py</code></a> module defines a class <code
- class="source">bugzilla_filespec</code>. </p></blockquote>
- <p> A subclass of <code
- class="source">dt_interface.defect_tracker_filespec</code> must define the
- following methods: </p>
- <h4> <a id="defect_tracker_filespec.delete" name="defect_tracker_filespec.delete"><code class="source">delete(self)</code></a> </h4>
- <p> Delete the filespec record so that the issue is no longer associated
- with the filespec. </p>
- <h4> <a id="defect_tracker_filespec.name" name="defect_tracker_filespec.name"><code class="source">name(self)</code></a> </h4>
- <p> Return the filespec, a string. </p>
- <h3><a id="section-7.5" name="section-7.5">7.5. The <code class="source">translator.translator</code> class</a></h3>
- <p> A subclass of <code class="source">translator.translator</code>
- translates values of a particular type between the defect tracker and
- Perforce. You should define a translator for each field type in the
- defect tracker that you want the <abbr title="Perforce Defect Tracking Integration">P4DTI</abbr> administrator to be
- able to replicate. You must define translators for dates (see <a
- href="#section-7.5.1">section 7.5.1</a>), multi-line text fields (see <a
- href="#section-7.5.3">section 7.5.3</a>), and users (see <a
- href="#section-7.5.4">section 7.5.4</a>). If your defect tracker has any
- concept of the state of an issue, then you must define a translator for
- states (see <a href="#section-7.5.2">section 7.5.2</a>). </p>
- <blockquote><p> <i>Example.</i> The TeamTrack integration defined, in
- addition to the three required translators, translators for: fields that
- cross-referenced an auxiliary table like <code
- class="source">TS_PROJECTS</code>; elapsed time fields; selection
- fields; and the <code class="source">STATE</code> field.
- </p></blockquote>
- <p> The translator base class doesn't know anything about Perforce; all
- it knows is that it is translating between two defect trackers, called 0
- and 1. In the <abbr title="Perforce Defect Tracking Integration">P4DTI</abbr>, defect tracker 1 is always Perforce,
- but we haven't limited the design of the translator class by requiring
- that it is. </p>
- <p> Each subclass of <code class="source">translator.translator</code>
- must define the following methods: </p>
- <h4> <a id="translator.translate_0_to_1" name="translator.translate_0_to_1"><code class="source">translate_0_to_1(self, value, dt0, dt1, issue0=None, issue1=None)</code></a> </h4>
- <p> Return <code class="source">value</code>, suitably translated from
- defect tracker 0 to defect tracker 1. If translation is not possible,
- raise an error. </p>
- <dl>
- <dt><code class="source">value</code></dt>
- <dd><p> The value for a field in a defect tracker issue that is to be
- translated. </p></dd>
- <dt><code class="source">dt0</code></dt>
- <dd><p> Your defect tracker: an instance of your subclass of <a
- href="#section-7.1"><code
- class="source">dt_interface.defect_tracker</code></a>. </p></dd>
- <dt><code class="source">dt1</code></dt>
- <dd><p> Perforce (represented by an instance of a subclass of <a
- href="#section-7.1"><code
- class="source">dt_interface.defect_tracker</code></a>). </p></dd>
- <dt><code class="source">issue0</code></dt>
- <dd><p> The issue in your defect tracker from which the value comes,
- or <code class="source">None</code> if the value doesn't come from an
- issue. An instance of your subclass of <a href="#section-7.2"><code
- class="source">dt_interface.defect_tracker_issue</code></a>. </p></dd>
- <dt><code class="source">issue1</code></dt>
- <dd><p> The job in Perforce to which the value is going, or <code
- class="source">None</code> if the value isn't going to a job
- (represented by an instance of a subclass of <a
- href="#section-7.2"><code
- class="source">dt_interface.defect_tracker_issue</code></a>).
- </p></dd>
- </dl>
- <p> This method takes defect trackers as arguments because it may need
- to query the defect tracker to carry out the translation. </p>
- <blockquote><p> <i>Example.</i> In the TeamTrack integration, the single
- select translator needed to read the <code
- class="source">TS_SELECTIONS</code> table to discover the available
- selections. To do this it called the private method <code
- class="source">read_selections</code> in <code
- class="source">dt0</code>. </p></blockquote>
- <p> This method takes issues as arguments because some translators need
- to know about the whole issue in order to carry out the translation. </p>
- <blockquote><p> <i>Example.</i> In the TeamTrack integration the state
- translator needed to know the project to which the issue belonged (because
- different projects may have different states with the same name which
- correspond to the same Perforce state). </p></blockquote>
- <p> Many translators can ignore the <code class="source">dt0</code> and
- <code class="source">dt1</code> arguments; most can ignore the <code
- class="source">issue0</code> and <code class="source">issue1</code>
- arguments. </p>
- <h4> <a id="translator.translate_1_to_0" name="translator.translate_1_to_0"><code class="source">translate_1_to_0(self, value, dt0, dt1, issue0=None, issue1=None)</code></a> </h4>
- <p> Return <code class="source">value</code>, suitably translated from
- defect tracker 1 to defect tracker 0. If translation is not possible,
- raise an error. </p>
- <dl>
- <dt><code class="source">value</code></dt>
- <dd><p> The value in a job in Perforce that is to be translated. </p>
- <p> <strong>Warning.</strong> Be careful not to assume that a value in
- field in Perforce is valid for that field. Perforce's checks on field
- values can be bypassed (for example, by the <code
- class="command">-f</code> option to the <code class="command">p4
- job</code> command, or by editing a job and changing the jobspec to
- make the job invalid). So you should do something appropriate with
- invalid values, such as raising an error, or substituting a default
- value. It's particularly important to be able to do something
- sensible with the empty string, which is what you'll get when there's
- no value for that field in Perforce. </p></dd>
- <dt><code class="source">dt0</code></dt>
- <dd><p> Your defect tracker: an instance of your subclass of <a
- href="#section-7.1"><code
- class="source">dt_interface.defect_tracker</code></a>. </p></dd>
- <dt><code class="source">dt1</code></dt>
- <dd><p> Perforce (represented by an instance of a subclass of <a
- href="#section-7.1"><code
- class="source">dt_interface.defect_tracker</code></a>). </p></dd>
- <dt><code class="source">issue0</code></dt>
- <dd><p> The issue in your defect tracker to which the value is going,
- or <code class="source">None</code> if the value isn't going to an
- issue. An instance of your subclass of <a href="#section-7.2"><code
- class="source">dt_interface.defect_tracker_issue</code></a>. </p></dd>
- <dt><code class="source">issue1</code></dt>
- <dd><p> The job in Perforce from which the value comes, or <code
- class="source">None</code> if the value doesn't come from a job
- (represented by an instance of a subclass of <a
- href="#section-7.2"><code
- class="source">dt_interface.defect_tracker_issue</code></a>).
- </p>
- <p> <strong>Warning.</strong> Be careful not to assume that the
- dictionary representing the job has all fields present. It's possible
- that it has only a subset of fields. So don't write <code
- class="source">issue1['Spong']</code>, write <code class="source">if
- issue1.has_key('Spong'):</code> or <code
- class="source">issue1.get('Spong',
- <i>default_value</i>)</code>. </p></dd>
- </dl>
- <h4><a id="section-7.5.1" name="section-7.5.1">7.5.1. Date translator</a></h4>
- <p> You must define a date translator class, a subclass of <a
- href="#section-7.5"><code
- class="source">translator.translator</code></a>, to translate dates
- between your defect tracker and Perforce. </p>
- <p> When translating to Perforce: </p>
- <ol>
- <li><p> An empty or null date field must be translated to the empty
- string. </p></li>
- <li><p> Any other date must be translated to a string looking like
- <code class="source">"2000/12/31 23:59:59"</code> (you can do this by
- calling <code class="source">time.strftime</code> with <code
- class="source">"%Y/%m/%d %H:%M:%S"</code> as the first
- argument). </p></li>
- </ol>
- <p> When translating from Perforce: </p>
- <ol>
- <li><p> The empty string must be translated to an empty or null date
- field. </p></li>
- <li><p> A string in the format <code class="source">"2000/12/31
- 23:59:59"</code> specifies the calendar date. (This form is used by
- changelists and jobs.) </p></li>
- <li><p> A string consisting only of digits specifies the number of
- seconds since 1970-01-01 00:00:00 UTC. (This form is used by fixes.)
- </p></li>
- </ol>
- <p> <strong>Timezones.</strong> When Perforce creates a timestamp for a
- changelist or for a field in job with a preset of <code
- class="source">$now</code>, it uses local time on the Perforce server.
- For other date fields in jobs, Perforce just stores the date the user
- entered, without conversion. Your date translator must make sure that
- its translations in the two directions are inverses of each other. The
- simplest way to do this is to follow the same principle as the Perforce
- server: just treat the date as you get it, without conversion. </p>
- <blockquote><p> <i>Example.</i> TeamTrack specifies all dates as seconds
- since 1970-01-01 00:00:00, so the TeamTrack integration used <code
- class="source">time.strftime</code> to convert from TeamTrack to
- Perforce, and either <code class="source">time.mktime</code> or simply
- <code class="source">int</code> to convert from Perforce to
- TeamTrack.</p></blockquote>
- <h4><a id="section-7.5.2" name="section-7.5.2">7.5.2. State translator</a></h4>
- <p> If your defect tracker has a concept of states for issues, then you
- must define a state translator class, a subclass of <a
- href="#section-7.5"><code
- class="source">translator.translator</code></a>. </p>
- <p> The state field in Perforce should be a "select" field (see <a
- href="#section-8.4">section 8.4</a>) so the values for this field should
- be legal selections in Perforce. This means no whitespace, hashes,
- double quotes, semicolons or slashes. Since the defect tracker probably
- allows these character to appear in state names, you must convert them
- somehow. </p>
- <p> We have provided a translator to do this conversion: it is the
- <code class="source">keyword_translator</code> class in the <a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/code/replicator/translator.py"><code
- class="filename">translator.py</code></a> module. </p>
- <p> You shouldn't just use the keyword translator as your state
- translator, since all it does is to convert strings. You should develop
- a translator that checks that applies the keyword translator, checks
- that the converted state is legal and raises an error if it is
- not. </p>
- <h4><a id="section-7.5.3" name="section-7.5.3">7.5.3. Text translator</a></h4>
- <p> You must define a text translator class, a subclass of <a
- href="#section-7.5"><code
- class="source">translator.translator</code></a>, to translate multi-line
- text fields between your defect tracker and Perforce. </p>
- <p> This translator must translate line endings (if needed). Perforce
- uses newline (<code class="source">"\n"</code>) as the line ending;
- values always end in a newline (unless the field is empty); values never
- end in more than one newline. </p>
- <blockquote><p> <i>Example.</i> TeamTrack uses a carriage return plus a
- newline (<code class="source">\r\n</code>) as its line ending, and there
- need not be a final newline. </p></blockquote>
- <blockquote><p> <i>Example.</i> The MySQL database interface converts
- newlines if necessary, so the Bugzilla integration uses <code
- class="source">translator.translator</code> (a translator which does
- nothing) for its text translator. </p></blockquote>
- <h4><a id="section-7.5.4" name="section-7.5.4">7.5.4. User translator</a></h4>
- <p> You must define a user translator class, a subclass of <code
- class="source">translator.user_translator</code>, to translate users
- between your defect tracker and Perforce. </p>
- <p> It is important not to assume that userids are the same in Perforce
- and the defect tracker, because an organization may have different
- policies for assigning userids in the two systems, or there may be
- legacy users from a previous policy. The TeamTrack and Bugzilla
- integrations translate between users based on their e-mail addresses.
- Your integration should do the same if possible and appropriate. </p>
- <p> When translating from the defect tracker to Perforce: </p>
- <ol>
- <li><p> Map the defect tracker user to a Perforce user with the same
- e-mail address, if there is one. </p></li>
- <li><p> Otherwise, map the defect tracker user to the Perforce user
- with the same userid, if there is one. </p></li>
- <li><p> Otherwise, return the defect tracker userid unchanged
- (assuming it is valid syntactically as a Perforce userid; if it isn't,
- apply the keyword translator (see <a href="#section-7.5.2">section
- 7.5.2</a>) to it). </p></li>
- </ol>
- <p> When translating from Perforce to the defect tracker: </p>
- <ol>
- <li><p> Map the Perforce user to a defect tracker user with the same
- e-mail address, if there is one. </p></li>
- <li><p> Otherwise, map the Perforce user to the defect tracker user
- with the same userid, if there is one. </p></li>
- <li><p> Otherwise, if translating the user in a changelist or fix, map
- the Perforce user to some dummy defect tracker user (see <a
- href="#section-4.8">section 4.8</a>). You can tell that you're translating a
- changelist or fix rather than an issue because the <code
- class="source">issue0</code> argument to the <a
- href="#translator.translate_1_to_0"><code
- class="source">translate_1_to_0</code></a> method is <code
- class="source">None</code>. </p></li>
- <li><p> Otherwise, you're translating a user field in an issue and you
- can't find a match either by e-mail address or by name. Raise an
- error. </p></li>
- </ol>
- <p> Each subclass of <code
- class="source">translator.user_translator</code> must define the
- following method: </p>
- <h4> <a id="user_translator.unmatched_users" name="user_translator.unmatched_users"><code class="source">unmatched_users(self)</code></a> </h4>
- <p> This method should examine all the users in the defect tracker and
- Perforce and return a report on the users in each system that have no
- corresponding userid in the other. </p>
- <p> It must return a tuple. The first four elements of the tuple must
- be as follows: </p>
- <ol>
- <li><p> A dictionary of users in the defect tracker that have no
- corresponding userid in Perforce. The keys of the dictionary are
- strings naming the defect tracker userids; the values of the
- dictionary are the e-mail addresses of the defect tracker
- users. </p></li>
- <li><p> A dictionary of users in Perforce that have no corresponding
- userid in the defect tracker. The keys of the dictionary are the
- Perforce userids; the values of the dictionary are the e-mail
- addresses of the Perforce users. </p></li>
- <li>
- <p> A comment (a string or message) about the users in the first
- dictionary explaining how they are treated by this user
- translator. </p>
- <blockquote><p> <i>Example.</i> The Bugzilla integration says, "A
- user field containing one of these users will be translated to the
- user's e-mail address in the corresponding Perforce job
- field."</p></blockquote>
- </li>
- <li>
- <p> A comment (a string or message) about the users in the second
- dictionary explaining how they are treated by this user
- translator. </p>
- <blockquote><p> <i>Example.</i> The Bugzilla integration says "It
- will not be possible to use Perforce to assign bugs to these users.
- Changes to jobs made by these users will be ascribed in Bugzilla to
- the replicator user." </p></blockquote>
- </li>
- </ol>
- <p> Optionally, the returned tuple may have four additional elements:
- </p>
- <ol start="5">
- <li><p> A dictionary of users in the defect tracker that have
- duplicate e-mail addresses, and which therefore may have been matched
- to the wrong user in Perforce. The keys of the dictionary are strings
- naming the defect tracker userids; the values of the dictionary are
- the e-mail addresses of the defect tracker users. </p></li>
- <li><p> A dictionary of users in Perforce that have duplicate e-mail
- addresses, and which therefore may have been matched to the wrong user
- in the defect tracker. The keys of the dictionary are the Perforce
- userids; the values of the dictionary are the e-mail addresses of the
- Perforce users. </p></li>
- <li><p> A comment (a string or message) about the defect tracker users
- with duplicate e-mail addresses, explaining what the problem is. If
- there are no such users, then you may specify <code
- class="source">None</code> here. </p>
- <blockquote><p> <i>Example.</i> The Bugzilla integration says,
- "These Bugzilla users have duplicate e-mail addresses (when
- converted to lower case). They may have been matched with the wrong
- Perforce user."</p></blockquote></li>
- <li><p> A comment (a string or message) about the Perforce users with
- duplicate e-mail addresses, explaining what the problem is. If there
- are no such users, then you may specify <code
- class="source">None</code> here. </p>
- <blockquote><p> <i>Example.</i> The Bugzilla integration says,
- "These Perforce users have duplicate e-mail addresses. They may
- have been matched with the wrong Bugzilla user."
- </p></blockquote></li>
- </ol>
- <p> This method is called each time the replicator is started. The
- results are used to compose an e-mail to the <abbr title="Perforce
- Defect Tracking Integration">P4DTI</abbr> administrator reporting on
- unmatched users. </p>
- <h3><a id="section-7.6" name="section-7.6">7.6. Cursors</a></h3>
- <p> The <a href="#defect_tracker.all_issues"><code
- class="source">all_issues</code></a> and <a
- href="#defect_tracker.changed_entities"><code
- class="source">changed_entities</code></a> methods return cursors. A
- cursor is a representation of the result set of a query into a database.
- It has the following method: </p>
- <h4> <a id="cursor.fetchone" name="cursor.fetchone"><code class="source">fetchone(self)</code></a> </h4>
- <p> Return the next item in the result set, or <code
- class="source">None</code> if there are no more items. </p>
- <h2><a id="section-8" name="section-8">8. Configuration</a></h2>
- <p> This section describes how to configure the <abbr title="Perforce
- Defect Tracking Integration">P4DTI</abbr> to work with your extension.
- To understand how the configuration works, see [<a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/design/replicator/#section-5">GDR
- 2000-09-13, 5</a>]. </p>
- <h3><a id="section-8.1" name="section-8.1">8.1. The configuration generator</a></h3>
- <p> You must write a configuration generator for your defect tracker.
- This must be a module called <code
- class="filename">config_<i>defect_tracker</i>.py</code>, where
- <i>defect_tracker</i> is the name you chose for your defect tracker (see
- <a href="#section-3">section 3</a>), converted to lower case. </p>
- <p> It must provide the following function: </p>
- <h4><a id="configure_dt.configuration" name="configure_dt.configuration"><code class="source">configuration(config)</code></a></h4>
- <p> The <code class="source">config</code> argument is a module whose
- members are the configuration parameters specified by the <abbr
- title="Perforce Defect Tracking Integration">P4DTI</abbr> administrator
- in <a href="http://www.ravenbrook.com/project/p4dti/version/2.2/code/replicator/config.py"><code
- class="filename">config.py</code></a>. </p>
- <p> It must check all the user configuration parameters that are
- specific to your defect tracker. </p>
- <p> It must return a revised configuration module, which should include
- all the configuration parameters in the <code
- class="source">config</code> argument, plus the configuration parameters
- required by your defect tracker module, by the replicator (see <a
- href="#section-8.3">section 8.3</a>), and by the Perforce interface (see
- <a href="#section-8.2">section 8.2</a>). It's OK to modify the
- configuration module that you were passed and return that. </p>
- <h3><a id="section-8.2" name="section-8.2">8.2. Perforce interface configuration</a></h3>
- <p> The revised configuration module must include the following
- parameter for the Perforce interface. (This is in addition to the
- parameters <a
- href="../ag/index.html#config-p4_client_executable"><code
- class="source">p4_client_executable</code></a>, <a
- href="../ag/index.html#config-p4_password"><code
- class="source">p4_password</code></a>, <a
- href="../ag/index.html#config-p4_port"><code
- class="source">p4_port</code></a>, and <a
- href="../ag/index.html#config-p4_user"><code
- class="source">p4_user</code></a> which came from the user
- configuration.) </p>
- <h4><a id="config-logger" name="config-logger"><code class="source">logger</code></a></h4>
- <p> This is a logger object (see <a href="#section-5.3">section 5.3</a>)
- to which log messages are written. It must log to <a
- href="../ag/index.html#config-log_file"><code
- class="source">log_file</code></a> if that is specified, to standard
- output, and to any appropriate system logging facility. It must respect
- the <a
- href="../ag/index.html#config-log_level"><code
- class="source">log_level</code></a>. </p>
- <h3><a id="section-8.3" name="section-8.3">8.3. Replicator configuration</a></h3>
- <p> The revised configuration module must include the following
- parameters for the replicator. (These are in addition to the <a
- href="../ag/index.html#config-administrator_address"><code
- class="source">administrator_address</code></a>, <a
- href="../ag/index.html#config-p4_user"><code
- class="source">p4_user</code></a>, <a
- href="../ag/index.html#config-poll_period"><code
- class="source">poll_period</code></a>, <a
- href="../ag/index.html#config-replicate_p"><code
- class="source">replicate_p</code></a>, <a
- href="../ag/index.html#config-replicator_address"><code
- class="source">replicator_address</code></a>, <a
- href="../ag/index.html#config-rid"><code
- class="source">rid</code></a>, and <a
- href="../ag/index.html#config-smtp_server"><code
- class="source">smtp_server</code></a> parameters which came from the
- user configuration.) </p>
- <h4><a id="config-date_translator" name="config-date_translator"><code class="source">date_translator</code></a></h4>
- <p> A date translator instance (see <a href="#section-7.5.1">section
- 7.5.1</a>). </p>
- <h4><a id="config-field_map" name="config-field_map"><code class="source">field_map</code></a></h4>
- <p> A description of how fields map from the defect tracker to Perforce
- and back again. It is a list of tuples, one for each field to be
- replicated. Each tuple has three elements: </p>
- <ol>
- <li><p> The name of the field in the defect tracker. </p></li>
- <li><p> The name of the field in Perforce. </p></li>
- <li><p> A translator instance (see <a href="#section-7.5">section
- 7.5</a>) that can be used to translate between values in the two
- fields. </p></li>
- </ol>
- <p> The field map must match the defect tracker database and the <a
- href="#config-jobspec"><code class="source">jobspec</code></a>
- configuration parameter. </p>
- <h4><a id="config-job_owner_field" name="config-job_owner_field"><code class="source">job_owner_field</code></a></h4>
- <p> The name of the field in the Perforce jobspec which contains the
- owner of the job. </p>
- <blockquote><p> <i>Example.</i> In the TeamTrack integration, this was
- <code class="source">"Owner"</code>. In the Bugzilla integration, this is
- <code class="source">"Assigned_To"</code>. </p></blockquote>
- <h4><a id="config-job_status_field" name="config-job_status_field"><code class="source">job_status_field</code></a></h4>
- <p> The name of the field in the Perforce jobspec which contains the
- status of the job. </p>
- <blockquote><p> <i>Example.</i> In the TeamTrack integration, this was
- <code class="source">"State"</code>. In the Bugzilla integration, this
- is <code class="source">"Status"</code>. </p></blockquote>
- <h4><a id="config-jobspec" name="config-jobspec"><code class="source">jobspec</code></a></h4>
- <p> The Perforce jobspec which the replicator is going to use, or
- <code class="source">None</code> if the Perforce jobspec is left
- unchanged. See also <a
- href="../ag/index.html#config-keep_jobspec"><code
- class="source">keep_jopspec</code></a>.</p>
- <p> The jobspec must be in the format described in <a
- href="#section-8.4">section 8.4</a> and must match the <a
- href="#config-field_map"><code class="source">field_map</code></a>
- configuration parameter. </p>
- <h4><a id="config-replicator.logger" name="config-replicator.logger"><code class="source">logger</code></a></h4>
- <p> This must be the same as the <a href="#config-logger">logger object
- for the Perforce interface</a>. </p>
- <h4><a id="config-prepare_issue_advanced" name="config-prepare_issue_advanced"><code class="source">prepare_issue_advanced(config, dt, p4, issue, job)</code></a></h4>
- <p> (The <code class="source">prepare_issue_advanced</code> function
- belongs to the <a href="#feature-new_issues">new_issues</a> feature.)
- </p>
- <p> A function to complete the transformation of a new job in Perforce
- to an issue in the defect tracker. The function takes 5 arguments:
- </p>
- <dl>
- <dt><code class="source">config</code></dt>
- <dd><p> A Python module containing the replicator
- configuration. </p></dd>
- <dt><code class="source">dt</code></dt>
- <dd><p> Your defect tracker: an instance of your subclass of <a
- href="#section-7.1"><code
- class="source">dt_interface.defect_tracker</code></a>. </p></dd>
- <dt><code class="source">p4</code></dt>
- <dd><p> Perforce (represented by an instance of a subclass of <a
- href="#section-7.1"><code
- class="source">dt_interface.defect_tracker</code></a>). </p></dd>
- <dt><code class="source">issue</code></dt>
- <dd><p> The partly-constructed issue, in the form of a Python
- dictionary mapping field name (string) to field value. (The values in
- the dictionary are the result of applying the translators in the <a
- href="#config-field_map"><code class="source">field_map</code></a> to
- the fields in the <code class="source">job</code>.) </p></dd>
- <dt><code class="source">job</code></dt>
- <dd><p> The newly-created job, in the form of a Python dictionary
- mapping field name (string) to field value (string). </p></dd>
- </dl>
- <p> The function must modify <code class="source">issue</code> so that
- it is a valid issue for creation in the defect tracker, by supplying
- values for the defect tracker's required fields. The function should do
- so by modifying <code class="source">issue</code> as far as possible
- automatically, then calling the function given by the <a
- href="../ag/index.html#config-prepare_issue"><code
- class="source">prepare_issue</code></a> configuration parameter, passing
- the modified <code class="source">issue</code> and <code
- class="source">job</code> arguments. </p>
- <p> You need not supply this function in the replicator configuration if
- you don't support replication of jobs from Perforce to the defect
- tracker. </p>
- <h4><a id="config-text_translator" name="config-text_translator"><code class="source">text_translator</code></a></h4>
- <p> A text translator instance (see <a href="#section-7.5.3">section 7.5.3</a>). </p>
- <h4><a id="config-translate_jobspec_advanced" name="config-translate_jobspec_advanced"><code class="source">translate_jobspec_advanced(config, dt, p4, job)</code></a></h4>
- <p> (The <code class="source">translate_jobspec_advanced</code> function
- belongs to the <a href="#feature-migrate_issues">migrate_issues</a>
- feature.) </p>
- <p> A function to translate a job from the old jobspec (before
- migration) to the new jobspec (after migration, suitable for
- replication). The function takes 4 arguments; the <code
- class="source">config</code>, <code class="source">dt</code> and <code
- class="source">p4</code> arguments are the same as for <a
- href="#config-prepare_issue_advanced"><code
- class="source">prepare_issue_advanced</code></a>. The <code
- class="source">job</code> argument is the old job, in the form of a
- dictionary mapping field name to field value. The new job must be
- returned in the same form (it's OK to update the argument and return
- that). </p>
- <p> You need not supply this function in the replicator configuration if
- you don't support migration of jobs from Perforce to the defect
- tracker. </p>
- <h4><a id="config-user_translator" name="config-user_translator"><code class="source">user_translator</code></a></h4>
- <p> A user translator instance (see <a href="#section-7.5.4">section 7.5.4</a>). </p>
- <h3><a id="section-8.4" name="section-8.4">8.4. Perforce jobspecs</a></h3>
- <p> The configuration generator must build a Perforce jobspec that
- matches the <a href="#config-field_map"><code
- class="source">field_map</code></a> configuration parameter that it
- generates. This must be communicated to the replicator as the <a
- href="#config-jobspec"><code class="source">jobspec</code></a>
- configuration parameter. </p>
- <p> The jobspec must be represented by a tuple with two elements: </p>
- <ol>
- <li><p> An introductory comment, in the form of a string starting with
- <code class="source">"#"</code>. </p></li>
- <li><p> A list of field definitions. Each field definition must be a
- tuple of eight elements. See [<a title="Perforce 2001.1 System
- Administrator's Guide"
- href="http://www.perforce.com/perforce/doc.031/manuals/p4sag/05_jobspec.html">Perforce
- 2003-07-15b, 5</a>] for the full details of job specifications. </p>
- <ol type="a">
- <li><p> A unique integer identifier by which this field is indexed.
- Must be between 101 and 199. </p></li>
- <li><p> The name of the field as it appears in the job
- form. </p></li>
- <li><p> The field datatype (<code class="source">"word"</code>, <code
- class="source">"text"</code>, <code class="source">"line"</code>,
- <code class="source">"select"</code>, or <code
- class="source">"date"</code>). </p></li>
- <li><p> The recommended size of the field's text box as displayed in
- P4Win. </p></li>
- <li><p> The field disposition: </p>
- <ul>
- <li><p><code class="source">"optional"</code>: field can take any
- value or can be deleted. </p></li>
- <li><p><code class="source">"default"</code>: a default value is
- provided, but it can be changed or erased. </p></li>
- <li><p><code class="source">"required"</code>: a default is given;
- it can be changed but the field can't be left empty. </p></li>
- <li><p><code class="source">"once"</code>: read-only; the field is
- set once to a default value and is never changed. </p></li>
- <li><p><code class="source">"always"</code>: read-only; the field
- value is reset to the default value when the job is saved. </p></li>
- </ul></li>
- <li><p> The default value for the field, if any, or <code
- class="source">None</code> if there is no default value (this is
- called "Preset" in the Perforce jobspec). </p></li>
- <li><p> The legal values for the field, if type is <code
- class="source">"select"</code>, or <code class="source">None</code>
- for other types. Join the values into a string, separating them with
- slashes. For example, <code
- class="source">"open/closed/suspended"</code>. </p></li>
- <li><p> A string describing the field, or <code
- class="source">None</code> if you have nothing to say about the field.
- Don't start it with a <code class="source">"#"</code>. </p></li>
- </ol></li>
- </ol>
- <p> Perforce requires that five fields be present in the jobspec: </p>
- <ol>
- <li><p> The jobname <code class="source">(101, "Job", "word", 32,
- "required", None, None, "The job name.")</code>. This must not be
- replicated. </p></li>
- <li><p> The status of the job (field 102). This should be replicated
- from the defect tracker. It should have type <code
- class="source">"select"</code>. Its values should include all the
- statuses for issues in the defect tracker, converted using the state
- translator (see <a href="#section-7.5.2">section 7.5.2</a>). </p></li>
- <li><p> The owner of the job (field 103). This should be replicated
- from the defect tracker. It should have type <code
- class="source">"word"</code>. </p></li>
- <li><p> The date the job was last modified <code class="source">(104,
- "Date", "date", 20, "always", "$now", None, "The date this job was
- last modified.")</code>. This must not be replicated. </p></li>
- <li><p> The title (field 105). This should be replicated from the
- defect tracker. It should have type <code
- class="source">"line"</code> or <code
- class="source">"text"</code>. </p></li>
- </ol>
- <blockquote><p> <i>Example.</i> In the Bugzilla integration, Perforce's
- five required fields are specified in the jobspec like this:
- </p></blockquote>
- <blockquote><pre class="source">
- (101, "Job", "word", 32, "required", None, None, "The job name."),
- (102, "Status", "select", 11, "required", "unconfirmed", "unconfirmed/bugzilla_new/assigned/reopened/closed/verified/bugzilla_closed", " The bug's status."),
- (103, "Assigned_To", "word", 255, "required", "$user", None, "User to which the bug is assigned."),
- (104, "Date", "date", 20, "always", "$now", None, "The date this job was last modified."),
- (105, "Summary", "text", 0, "required", "$blank", None, "The bug's summary"),
- </pre></blockquote>
- <p> The replicator requires that four fields be present [<a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/design/replicator/#section-4">GDR
- 2000-09-13, 4</a>]. These should appear in the jobspec as follows: </p>
- <blockquote><pre class="source">
- (191, "P4DTI-filespecs", "text", 0, "optional", None, None, "Associated filespecs."),
- (192, "P4DTI-rid", "word", 32, "required", "None", None, "P4DTI replicator identifier. Do not edit!"),
- (193, "P4DTI-issue-id", "word", 32, "required", "None", None, "Bugzilla issue database identifier. Do not edit!"),
- (194, "P4DTI-user", "word", 32, "always", "$user", None, "Last user to edit this job. You can't edit this!"),
- </pre></blockquote>
- <p> These fields have high numbers so that they appear at the bottom of
- the jobspec where people don't have to look at them. </p>
- <p> The remainder of the jobspec should be filled in with the fields
- that the <abbr title="Perforce Defect Tracking Integration">P4DTI</abbr>
- administrator has specified for replication in the <a
- href="../ag/index.html#config-replicated_fields-Bugzilla"><code
- class="source">replicated_fields</code></a> configuration parameter.
- Make sure that the values for "select" fields are legal in Perforce (see
- <a href="#section-7.5.2">section 7.5.2</a>). </p>
- <p> For more information about jobspecs, see Chapter 5, "Customizing
- Perforce: Job Specifications", in the <cite>Perforce System
- Administrator's Guide</cite> [<a
- href="http://www.perforce.com/perforce/doc.031/manuals/p4sag/05_jobspec.html">Perforce
- 2003-07-15b, 5</a>]. </p>
- <h3><a id="section-8.5" name="section-8.5">8.5. Adapting the configuration module</a></h3>
- <p> If your defect tracker module (see <a href="#section-7">section
- 7</a>) requires the <abbr title="Perforce Defect Tracking
- Integration">P4DTI</abbr> administrator to specify any configuration
- parameters (such as the name of the host on which the defect tracker
- runs, or the user to connect to the database as), then you must adapt
- the <a href="http://www.ravenbrook.com/project/p4dti/version/2.2/code/replicator/config.py"><code
- class="filename">config.py</code></a> module, as follows. </p>
- <ol>
- <li><p> Add a new <code class="source"># dt_name =
- "<i>Defect_Tracker</i>"</code> line near the start of section 2, to
- indicate that your defect tracker integration is available. </p></li>
- <li><p> Add a new subsection to section 3, starting <code
- class="source">elif dt_name == "<i>Defect_Tracker</i>":</code>. This
- should contain default values for the configuration parameters
- required only by your integration. </p></li>
- <li><p> Add a history entry to Appendix B explaining what you've
- done. </p></li>
- </ol>
- <h3><a id="section-8.6" name="section-8.6">8.6. Making your own configurations</a></h3>
- <p><strong>Warning: The configuration methods in this section are not
- supported by Perforce or TeamShare.</strong></p>
- <p> This section describes techniques you can use if you want to adapt a
- supported integration to do something that's not supported. Here are
- some of the things that are possible by making your own
- configuration. </p>
- <ul>
- <li> Connecting a defect tracker to multiple Perforce servers. </li>
- <li> Fine control over which defect tracker issues are replicated to
- Perforce. </li>
- <li> Arbitrary translation of issue data between the defect tracker and
- Perforce (see <a href="#section-8.6.2">section 8.6.2</a>). </li>
- <li> Queries based on combined defect tracker and Perforce data. </li>
- <li> Working with locally customized versions of Bugzilla. </li>
- <li> Redirection or fine control of logging. </li>
- <li> Arbitrary mappings between Perforce and defect tracker user
- names. </li>
- <li> Alternative policies for handling conflicts between defect tracker
- and Perforce changes to issues. </li>
- </ul>
- <h4><a id="section-8.6.1" name="section-8.6.1">8.6.1. Steps to making your own configuration</a></h4>
- <p> Here's are the steps you need to follow to make your own
- configuration: </p>
- <ol>
- <li><p> Choose a name for your configuration: <i>my_configuration</i>,
- say. </p></li>
- <li><p> Edit <code class="filename">config.py</code>, adding the
- line</p>
- <blockquote><code
- class="source">configure_name='<i>my_configuration</i>'</code></blockquote></li>
- <li><p> Make a new module <code
- class="filename">configure_<i>my_configuration</i>.py</code>.
- </p></li>
- <li><p> Make your new module into a configuration generator (see <a
- href="#section-8.1">section 8.1</a>). See below for some
- examples. </p></li>
- </ol>
- <p> The best approach to making a configuration generator is to use an
- existing one and modify its output. That way, you benefit from
- improvements and corrections to the configuration generator in future
- releases of the <abbr title="Perforce Defect Tracking
- Integration">P4DTI</abbr>. </p>
- <h4><a id="section-8.6.2" name="section-8.6.2">8.6.2. Example: custom
- jobspec and translators</a></h4>
- <p> Suppose that you want to use the Bugzilla integration, but you
- have many existing tools and documents that refer to your current
- Perforce jobspec, so don't want the <abbr title="Perforce Defect
- Tracking Integration">P4DTI</abbr> to change your Perforce
- jobspec, or the meaning of values in the job fields. </p>
- <p> First, you must add the fields required by the <abbr title="Perforce
- Defect Tracking Integration">P4DTI</abbr> [<a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/design/replicator/#section-4">GDR
- 2000-09-13, 4</a>] to your Perforce jobspec by hand. The following
- configuration generator achieves this: </p>
- <blockquote><pre class="source">
- import configure_bugzilla
- import message
- import translator
- product = "My configuration"
- error = "My configuration error."
- catalog = {
- 1: (message.ERR, "Unknown Bugzilla status '%s'."),
- 2: (message.ERR, "Unknown Perforce status '%s'."),
- }
- factory = <a href="#section-5.2">message.catalog_factory</a>(catalog, product)
- # A map from state in Bugzilla to status in Perforce.
- state_pairs = [
- ('NEW', 'new'),
- ('ASSIGNED', 'open'),
- ('RESOLVED', 'resolved'),
- ('CLOSED', 'closed'),
- ] # No support for UNCONFIRMED, REOPENED, or VERIFIED.
- class my_state_translator(<a href="#section-7.5">translator.translator</a>):
- def translate_0_to_1(self, value, dt0, dt1, issue0 = None, issue1 = None):
- assert isinstance(value, types.StringType)
- for (t,p) in state_pairs:
- if value == t:
- return p
- raise error, factory.new(1, value)
- def translate_1_to_0(self, value, dt0, dt1, issue0 = None, issue1 = None):
- assert isinstance(value, types.StringType)
- for (t,p) in state_pairs:
- if value == p:
- return t
- raise error, factory.new(2, value)
- def <a href="#configure_dt.configuration">configuration</a>(config):
- config = configure_bugzilla.<a href="#configure_dt.configuration">configuration</a>(config)
- # Tell the replicator not to update the jobspec.
- config.jobspec = None
- # Make a field_map that works with my existing jobspec.
- config.field_map = [
- ('bug_status, 'Status', my_state_translator()),
- ('assigned_to'', 'User', config.<a href="#config-user_translator">user_translator</a>),
- ('summary', 'Description', <a href="#section-7.5">translator.translator</a>()),
- ('longdesc', 'User_Impact', config.<a href="#config-text_translator">text_translator</a>),
- ]
- return config
- </pre></blockquote>
- <p> Note the use of coding conventions in this example: message catalogs
- (see <a href="#section-5.2">section 5.2</a>) and raising exceptions when
- a value can't be translated (see <a href="#section-5.4">section
- 5.4</a>). </p>
- <p> <b>Warning.</b> If you leave your Perforce jobspec unchanged, you
- must check that it is compatible with the <abbr title="Perforce Defect
- Tracking Integration">P4DTI</abbr>. See <a
- href="../ag/index.html#section-5.2.3">section 5.2.3,
- "Handle Perforce jobs and jobspec"</a>, of the <cite><a
- href="../ag/index.html">Perforce Defect Tracking
- Integration Administrator's Guide</a></cite>.</p>
- <p> Check that the "Presets" for each select field is valid for that
- field (that is, it appears as one of the "Values" for that field). </p>
- <p> Some organizations set up a jobspec with a field like this: </p>
- <blockquote><code class="source">
- Fields: 120 Severity select 20 required <br />
- Values: Severity critical/essential/optional <br />
- Presets: Severity setme
- </code></blockquote>
- <p> Their intention is that since "setme" is not a legal value for the
- Severity field, the person submitting the job must give it a value; they
- can't just ignore it and leave it with the default value. </p>
- <p> However, this won't work with the <abbr title="Perforce Defect
- Tracking Integration">P4DTI</abbr>, because the command <code
- class="command">p4 -G job -o</code> won't even give you a blank job
- form; instead it gives you an error message. </p>
- <h2><a id="section-9" name="section-9">9. Building and testing</a></h2>
- <p> To build the <abbr title="Perforce Defect Tracking
- Integration">P4DTI</abbr>, follow the release build procedure [<a
- title="Perforce Defect Tracking Integration Release Build Procedure"
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/procedure/release-build/">GDR
- 2000-10-17</a>]. This procedure uses automated support from the <a
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/tool/build.py"><code
- class="filename">build.py</code></a> tool; this is documented in [<a
- title="Build automation design"
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/design/build/">GDR 2001-07-13</a>]. </p>
- <p> You may adapt these three documents so that your new integration
- built by the same procedure as the other integrations in the <abbr
- title="Perforce Defect Tracking Integration">P4DTI</abbr>. </p>
- <p> To test the <abbr title="Perforce Defect Tracking
- Integration">P4DTI</abbr>, follow the release test procedure [<a
- title="Release test procedure"
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/procedure/release-test/">RB
- 2001-03-21</a>]. This uses the sample data and automated tests in the
- <a href="http://www.ravenbrook.com/project/p4dti/version/2.2/test/"><code
- class="filename">test/</code></a> directory of the integration kit. See
- [<a title="Test design"
- href="http://www.ravenbrook.com/project/p4dti/version/2.2/design/test/">GDR 2001-07-02</a>] for
- the test design. </p>
- <p> You may adapt the existing tests so that they test your
- integration. </p>
- <h2><a id="section-10" name="section-10">10. Providing a defect tracker interface to Perforce relations</a></h2>
- <p> The defect tracker should display, for each issue that is
- replicated, a description of the Perforce server to which the issue is
- replicated. Use the configuration parameter <a
- href="../ag/index.html#config-p4_server_description"><code
- class="source">p4_server_description</code></a> which you should have
- stored in a table in the defect tracker (see <a
- href="#section-4.5">section 4.5</a>). </p>
- <p> The defect tracker should display the jobname of the job to which
- the issue is replicated. The jobname should be a link to the <abbr
- title="Universal Resource Locator">URL</abbr> given by the <a
- href="../ag/index.html#config-job_url"><code
- class="source">job_url</code></a> configuration parameter, with the
- jobname inserted. This configuration parameter is defined in the
- <cite>Administrator's Guide</cite> as being suitable for passing to
- <code class="source">sprintf</code> as the format string: it must have
- one <code class="source">%s</code> format specified (for which the
- jobname is substituted) and it may have any number of doubled percent
- signs <code class="source">%%</code> (which must become single percent
- signs in the resulting <abbr title="Universal Resource
- Locator">URL</abbr>) [<a
- href="../ag/index.html#section-5.1">RB 2000-08-10a,
- 5.1</a>]. </p>
- <p> The defect tracker should display on each issue description page a
- table of fixes for that issue (if there are any). The table should look
- like the table below. </p>
- <table border="1" cellspacing="0" cellpadding="5">
- <tr valign="top" align="left">
- <th>Change</th>
- <th>Effect</th>
- <th>Date</th>
- <th>User</th>
- <th>Description</th>
- </tr>
- <tr valign="top">
- <td><a href="http://info.ravenbrook.com/infosys/cgi/perfbrowse.cgi?@describe+5493">5493</a></td>
- <td>open</td>
- <td>2000-12-05</td>
- <td>GDR</td>
- <td>Added replicator method mail_concerning_job for e-mailing people about a job.</td>
- </tr>
- <tr valign="top">
- <td><a href="http://info.ravenbrook.com/infosys/cgi/perfbrowse.cgi?@describe+5524">5524</a></td>
- <td>open</td>
- <td>2000-12-06</td>
- <td>GDR</td>
- <td>Fixed the replicator's user_email_address method so that it really returns None when there is no such user.</td>
- </tr>
- <tr valign="top">
- <td><a href="http://info.ravenbrook.com/infosys/cgi/perfbrowse.cgi?@describe+5541">5541</a></td>
- <td>open</td>
- <td>2000-12-06</td>
- <td>GDR</td>
- <td>If the owner of a job and the person who last changed it are the same, include them only once in any e-mail sent by the replicator about that job.</td>
- </tr>
- <tr valign="top">
- <td><a href="http://info.ravenbrook.com/infosys/cgi/perfbrowse.cgi?@describe+5634">5634</a> (pending)</td>
- <td>closed</td>
- <td>2000-12-07</td>
- <td>GDR</td>
- <td>Merging back to master sources.</td>
- </tr>
- </table>
- <p> Points to note about this table: </p>
- <ol>
- <li><p> Pending changelists are distinguished from submitted
- changelists. This is important because the effect of a pending
- changelist does not happen until the changelist is submitted. So in
- the above table the status of the job is still "open" but it is
- understood that when changelist 5634 is submitted it becomes
- "closed". </p></li>
- <li><p> The user and date are for the change (not for the fix).
- Knowing when the change was made and by whom is much more important
- than knowing when the change was linked with the job. </p></li>
- <li><p> The user is the defect tracker user who corresponds to the
- Perforce user who made the change. </p></li>
- <li><p> The change number is a link to the <abbr title="Universal
- Resource Locator">URL</abbr> given by the <a
- href="../ag/index.html#config-changelist_url"><code
- class="source">changelist_url</code></a> configuration parameter, with
- the change number inserted. This configuration parameter is defined
- in the <cite>Administrator's Guide</cite> as being suitable for
- passing to <code class="source">sprintf</code> as the format string:
- it must have one <code class="source">%d</code> format specified (for
- which the change number is substituted) and it may have any number of
- doubled percent signs <code class="source">%%</code> (which must
- become single percent signs in the resulting <abbr title="Universal
- Resource Locator">URL</abbr>) [<a
- href="../ag/index.html#section-5.1">RB
- 2000-08-10a, 5.1</a>]. </p></li>
- <li><p> All the fixes for an issue are replicated by the same
- replicator and from the same Perforce server as the issue itself. So
- when building this table you only need to select records with the same
- replicator identifier and Perforce server identifier as the
- issue. </p></li>
- <li><p> A single defect tracker may replicate issues to several
- Perforce servers (see <a href="#section-4">section 4</a>). Each
- Perforce server has a different changelist URL. So it is important to
- select the URL for the correct Perforce server (namely the one to
- which the issue is replicated) when making this table. </p></li>
- </ol>
- <h2><a id="section-11" name="section-11">11. Adapting the manuals</a></h2>
- <p> When adding material relating to your defect tracker to the manuals,
- surround each section with the <abbr title="Hypertext Markup Language">HTML</abbr> tags <code class="source"><div
- class="<i>defect_tracker</i>"></code> and <code
- class="source"></div></code>. This makes the material for a
- particular defect tracker easy to find, extract and check, to meet <a
- href="http://www.ravenbrook.com/project/p4dti/req/#req-32">requirement 32</a>. </p>
- <p> You must adapt the <cite>Perforce Defect Tracking Integration
- Administrator's Guide</cite> [<a href="../ag/index.html">RB 2000-08-10a</a>] to
- describe your integration, as described in the list below. </p>
- <ol>
- <li><p> Add a new subsection to section 3, specifying the software and
- procedural prerequisites for using your defect tracker with the <abbr
- title="Perforce Defect Tracking Integration">P4DTI</abbr>. </p></li>
- <li><p> If your integration requires a new installation procedure, or
- installs on a new platform, update section 4. </p></li>
- <li><p> Add your new configuration parameters to section
- 5.1. </p></li>
- <li><p> Add a new subsection to section 5, explaining how to configure
- your defect tracker for the <abbr title="Perforce Defect Tracking
- Integration">P4DTI</abbr>. </p></li>
- <li><p> Add a new item to the list in section 10, explaining how to
- uninstall your integration and return your defect tracker to its
- original state. </p></li>
- <li><p> Add the error messages that your code can produce to section
- 11.2 (include the product, message identifier and check digit just
- like the other errors messages in that section). </p></li>
- <li><p> Add likely error messages from systems with which your code
- interacts to section 11.3 (for example, errors from the defect
- tracker, or from your database interface). </p></li>
- <li><p> Add references to documentation for your defect tracker, and
- any other supporting materials that you referred to, to appendix
- A. </p></li>
- <li><p> Add a history entry to appendix B explaining what you've
- done. </p></li>
- </ol>
- <p> If you provided an interface from your defect tracker to the
- Perforce fixes relation (see <a href="#section-10">section 10</a>), then you must
- adapt the <cite>Perforce Defect Tracking Integration User's Guide</cite>
- [<a href="../ug/index.html">RB 2000-08-10b</a>] to describe your integration, as
- follows: </p>
- <ol start="10">
- <li><p> Add a paragraph to section 10.3 explaining how to access
- Perforce fixes from the defect tracker. </p></li>
- </ol>
- <h2><a id="section-12" name="section-12">12. Making your work available to the community</a></h2>
- <h3><a id="section-12.1" name="section-12.1">12.1. Reporting defects</a></h3>
- <p> Defects in the <abbr title="Perforce Defect Tracking Integration">P4DTI</abbr> Kit include (but aren't limited
- to): </p>
- <ul>
- <li><p> An essential piece of information can't be found in this
- manual or in the design documents it refers to. </p></li>
- <li><p> Inconsistencies between this manual, the design documents it
- refers to, and the sources they document. </p></li>
- <li><p> Defects in the <abbr title="Perforce Defect Tracking Integration">P4DTI</abbr> sources or in the test
- cases. </p></li>
- </ul>
- <p> Please report any defects you find to <a
- href="http://www.perforce.com/perforce/support.html">Perforce support</a>, so
- that they can be fixed and the product improved. </p>
- <p> Please provide the following information with your defect report:
- </p>
- <ol>
- <li><p> The release of the <abbr title="Perforce Defect Tracking
- Integration">P4DTI</abbr> Kit you are using (look in the <code
- class="filename">readme.txt</code> that came with the <abbr
- title="Perforce Defect Tracking Integration">P4DTI</abbr> Kit to
- identify the release). </p></li>
- <li><p> The name and release of the defect tracker you are integrating
- with. </p></li>
- <li><p> If you're reporting a defect in documentation: </p>
- <ol type="a">
- <li><p> What you're trying to do. </p></li>
- <li><p> The information you need. </p></li>
- <li><p> Where you expected to find it. </p></li>
- <li><p> Where else you looked for it. </p></li>
- </ol></li>
- <li><p> If you're reporting a defect in the code: </p>
- <ol type="a">
- <li><p> What you did immediately prior to the defect's
- occurrence. </p></li>
- <li><p> What you think should have happened. </p></li>
- <li><p> What actually happened. </p></li>
- <li><p> The Perforce release you are using. </p></li>
- <li><p> Any source code you've added or modified, including your
- <code class="filename">config.py</code> file. </p></li>
- <li><p> A section of the <abbr title="Perforce Defect Tracking
- Integration">P4DTI</abbr> log that includes the error that you're
- reporting and some context around that error. </p></li>
- <li><p> Copies of any related e-mail messages generated by the <abbr
- title="Perforce Defect Tracking Integration">P4DTI</abbr>. </p></li>
- </ol></li>
- </ol>
- <h3><a id="section-12.2" name="section-12.2">12.2. Making a contribution</a></h3>
- <p> Please send your contributions (fixes, adaptions and extensions) to
- <a href="http://www.perforce.com/perforce/support.html">Perforce
- support</a>. Please include the following: </p>
- <ol>
- <li><p> A description of your contribution: what it is designed to
- achieve; which files you've changed; which files you've
- added. </p></li>
- <li><p> The release of the <abbr title="Perforce Defect Tracking
- Integration">P4DTI</abbr> Kit you have been developing against (look
- in the <code class="filename">readme.txt</code> that came with the
- <abbr title="Perforce Defect Tracking Integration">P4DTI</abbr> Kit to
- identify the release). </p></li>
- <li><p> The complete <abbr title="Perforce Defect Tracking
- Integration">P4DTI</abbr> Kit, including your modifications and
- additions. Make a tarball or a ZIP archive of the whole <abbr
- title="Perforce Defect Tracking Integration">P4DTI</abbr> Kit
- directory. (Please do this even if you've only changed a couple of
- files. This allows us to add your contribution to Perforce and use
- <code class="command">p4 diff2</code> to see exactly what changes
- you've made.) </p></li>
- <li><p> What you are prepared for us to do with your contribution.
- Are you willing for us to make it available for distribution from
- Perforce or Ravenbrook's web site? Are you willing for us to
- incorporate it into the <abbr title="Perforce Defect Tracking
- Integration">P4DTI</abbr> and maintain and support it? Have you made
- it available under an open source license? </p></li>
- </ol>
- <h2><a id="section-13" name="section-13">13. Changes since previous releases</a></h2>
- <p> This section lists significant changes in the specification that a
- defect tracker has to meet. Changes are upwards compatible (in the
- sense that a defect tracker module that worked with the previous release
- of the integration kit will work with the new release) unless stated
- otherwise. </p>
- <h3><a id="section-13.1" name="section-13.1">13.1. Changes since release 1.1.1</a></h3>
- <ul>
- <li><p> The <a href="#defect_tracker.all_issues"><code
- class="source">all_issues</code></a> and <a
- href="#defect_tracker.changed_entities"><code
- class="source">changed_entities</code></a> methods of the <code
- class="source">defect_tracker</code> class (see <a
- href="#section-7.1">section 7.1</a>) must now return cursors (see <a
- href="#section-7.6">section 7.6</a>), not lists of issues. </p>
- <p> The purpose of this change is to allow the replicator to work if
- there are more issues in the defect tracker than fit into memory, thus
- fixing <a
- href="http://www.ravenbrook.com/project/p4dti/issue/job000277/">job000277</a>. </p>
- <p> The release 1.1.1 specification for these two methods (returning
- lists of issues) is still supported in version 1.4 of the <abbr
- title="Perforce Defect Tracking Integration">P4DTI</abbr>, but this
- support will be removed in later releases. </p></li>
- <li><p> The <a href="#defect_tracker.all_issues"><code
- class="source">all_issues</code></a> method of the <code
- class="source">defect_tracker</code> class (see <a
- href="#section-7.1">section 7.1</a>) must return all issues replicated
- by this replicator, regardless of when they were last modified. </p>
- <p>The purpose of this change is to fix <a
- href="http://www.ravenbrook.com/project/p4dti/issue/job000340/">job000340</a>.
- </p>
- <p> This is an incompatible change. </p></li>
- </ul>
- <h3><a id="section-13.2" name="section-13.2">13.2. Changes since release 1.1.6</a></h3>
- <ul>
- <li><p> The <a href="#user_translator.unmatched_users"><code
- class="source">unmatched_users</code></a> method in the <a
- href="#section-7.5.4">user translator class</a> may return an 8-tuple
- instead of a 4-tuple. The extra elements of the tuple allow the
- replicator to report duplicate e-mail addresses. </p>
- <p> The purpose of this change is to fix <a
- href="http://www.ravenbrook.com/project/p4dti/issue/job000308/">job000308</a>. </p></li>
- </ul>
- <h3><a id="section-13.3" name="section-13.3">13.3. Changes since release 1.2.1</a></h3>
- <ul>
- <li><p> The <a href="#section-7.1"><code
- class="source">defect_tracker</code></a> class has six new methods:
- <a href="#defect_tracker.add_user"><code
- class="source">add_user</code></a>, <a
- href="#defect_tracker.new_issue"><code
- class="source">new_issue</code></a>, <a
- href="#defect_tracker.new_issues_start"><code
- class="source">new_issues_start</code></a>, <a
- href="#defect_tracker.new_issues_end"><code
- class="source">new_issues_end</code></a>, <a
- href="#defect_tracker.poll_start"><code
- class="source">poll_start</code></a>, and <a
- href="#defect_tracker.poll_end"><code
- class="source">poll_end</code></a>. </p>
- <p> The <a href="#section-7.2"><code
- class="source">defect_tracker_issue</code></a> class has the new
- methods: <a href="#defect_tracker_issue.delete"><code
- class="source">delete</code></a>. </p>
- <p> The purpose of this change is to support migration from Perforce
- jobs and users (<a
- href="http://www.ravenbrook.com/project/p4dti/issue/job000022/">job000022</a>), creation of new
- issues in Perforce (<a
- href="http://www.ravenbrook.com/project/p4dti/issue/job000036/">job000036</a>), and releasing
- of defect tracker locks (<a
- href="http://www.ravenbrook.com/project/p4dti/issue/job000306/">job000306</a>). </p>
- <p> These methods are optional: you may omit them if you don't support
- migration or creation of new issues in Perforce. </p></li>
- <li><p> The replicator configuration (<a href="#section-8.3">section
- 8.3</a>) has two new parameters: <a
- href="#config-prepare_issue_advanced"><code
- class="source">prepare_issue_advanced</code></a> and <a
- href="#config-translate_jobspec_advanced"><code
- class="source">translate_jobspec_advanced</code></a>.
- </p>
- <p> The purpose of this change is to support migration from Perforce
- jobs (<a href="http://www.ravenbrook.com/project/p4dti/issue/job000022/">job000022</a>). </p>
- <p> These methods are optional: you may omit them if you don't support
- migration of jobs from Perforce to the defect tracker. </p></li>
- <li><p> The <a href="#configure_dt.configuration"><code
- class="source">configuration</code></a> function in the configuration
- generator must return the revised configuration module only (not a
- tuple of a jobspec description and the revised configuration). The
- jobspec description must instead be added to the replicator
- configuration as the <a href="#config-jobspec"><code
- class="source">jobspec</code></a> parameter, in the format described
- in <a href="#section-8.4">section 8.4</a>.
- </p>
- <p> This is an incompatible change. </p></li>
- </ul>
- <h3><a id="section-13.4" name="section-13.4">13.4. Changes since release 1.3.3</a></h3>
- <ul>
- <li><p> The <a href="#section-7.1"><code
- class="source">defect_tracker</code></a> class has the new method <a
- href="#defect_tracker.supports"><code
- class="source">supports</code></a>. </p>
- <p> In version 1.4 of the <abbr title="Perforce Defect Tracking
- Integration">P4DTI</abbr>, if you don't provide this method, then the
- <abbr title="Perforce Defect Tracking Integration">P4DTI</abbr> will
- assume that you support <a href="#feature-filespecs">filespecs</a> and
- <a href="#feature-fixes">fixes</a> (always), <a
- href="#feature-new_issues">new_issues</a> (if you implement the <a
- href="#defect_tracker.new_issue"><code
- class="source">new_issue</code></a>, <a
- href="#defect_tracker.new_issues_start"><code
- class="source">new_issues_start</code></a>, and <a
- href="#defect_tracker.new_issues_end"><code
- class="source">new_issues_end</code></a> methods and provide the <a
- href="#config-prepare_issue_advanced"><code
- class="source">prepare_issue_advanced</code></a> function in the
- replicator configuration), <a
- href="#feature-migrate_issues">migrate_issues</a> (if you support the
- new_issues feature and provide the <a
- href="#config-translate_jobspec_advanced"><code
- class="source">translate_jobspec_advanced</code></a> function in the
- replicator configuration), and <a
- href="#feature-new_users">new_users</a> (if you implement the <a
- href="#defect_tracker.add_user"><code
- class="source">add_user</code></a> method) features. In later
- versions, the <abbr title="Perforce Defect Tracking
- Integration">P4DTI</abbr> will fail if you don't provide this
- method. </p></li>
- <li><p> The <a href="#section-7.2"><code
- class="source">defect_tracker_issue</code></a> class no longer needs a
- <code class="source">replicate_p</code> method (this comes from the user
- configuration and the replicator now calls it directly). </p></li>
- </ul>
- <h3><a id="section-13.5" name="section-13.5">13.5. Changes since release 1.5.3</a></h3>
- <ul>
- <li><p> The <a href="#section-7.1"><code
- class="source">defect_tracker</code></a> class has the new method <a
- href="#defect_tracker.add_replicator_user"><code
- class="source">add_replicator_user</code></a>. </p></li>
- </ul>
- <h2><a id="section-A" name="section-A">A. References</a></h2>
- <table>
- <tr valign="top">
- <td>[<a id="ref-GDR-2000-05-03" name="ref-GDR-2000-05-03" href="http://www.ravenbrook.com/project/p4dti/doc/2000-05-03/reqs-and-use-cases/">GDR 2000-05-03</a>]</td>
- <td>
- "Requirements and Use Cases for Perforce/Defect Tracking Integration";
- <a href="mailto:gdr@ravenbrook.com">Gareth Rees</a>;
- <a href="http://www.ravenbrook.com/">Ravenbrook Limited</a>;
- 2000-05-03.
- </td>
- </tr>
- <tr valign="top">
- <td>[<a id="ref-GDR-2000-05-24" name="ref-GDR-2000-05-24" href="http://www.ravenbrook.com/project/p4dti/req/">GDR 2000-05-24</a>]</td>
- <td>
- "Perforce Defect Tracking Integration Project Requirements";
- <a href="mailto:gdr@ravenbrook.com">Gareth Rees</a>;
- <a href="http://www.ravenbrook.com/">Ravenbrook Limited</a>;
- 2000-05-24.
- </td>
- </tr>
- <tr valign="top">
- <td>[<a id="ref-GDR-2000-05-30" name="ref-GDR-2000-05-30" href="http://www.ravenbrook.com/project/p4dti/doc/2000-05-30/arch-analysis/">GDR 2000-05-30</a>]</td>
- <td>
- "Analysis of architectures for defect tracking integration";
- <a href="mailto:gdr@ravenbrook.com">Gareth Rees</a>;
- <a href="http://www.ravenbrook.com/">Ravenbrook Limited</a>;
- 2000-05-30.
- </td>
- </tr>
- <tr valign="top">
- <td>[<a id="ref-GDR-2000-08-08" name="ref-GDR-2000-08-08" href="http://www.ravenbrook.com/project/p4dti/version/2.2/design/python-teamtrack-interface/">GDR 2000-08-08</a>]</td>
- <td>
- "Python interface to TeamTrack: design";
- <a href="mailto:gdr@ravenbrook.com">Gareth Rees</a>;
- <a href="http://www.ravenbrook.com/">Ravenbrook Limited</a>;
- 2000-08-08.
- </td>
- </tr>
- <tr valign="top">
- <td>[<a id="ref-GDR-2000-09-04" name="ref-GDR-2000-09-04" href="http://www.ravenbrook.com/project/p4dti/version/2.2/design/teamtrack-p4dti-schema/">GDR 2000-09-04</a>]</td>
- <td>
- "TeamTrack database schema extensions for integration with Perforce";
- <a href="mailto:gdr@ravenbrook.com">Gareth Rees</a>;
- <a href="http://www.ravenbrook.com/">Ravenbrook Limited</a>;
- 2000-09-04.
- </td>
- </tr>
- <tr valign="top">
- <td>[<a id="ref-GDR-2000-09-13" name="ref-GDR-2000-09-13" href="http://www.ravenbrook.com/project/p4dti/version/2.2/design/replicator/">GDR 2000-09-13</a>]</td>
- <td>
- "Replicator design";
- <a href="mailto:gdr@ravenbrook.com">Gareth Rees</a>;
- <a href="http://www.ravenbrook.com/">Ravenbrook Limited</a>;
- 2000-09-13.
- </td>
- </tr>
- <tr valign="top">
- <td>[<a id="ref-GDR-2000-10-17" name="ref-GDR-2000-10-17" href="http://www.ravenbrook.com/project/p4dti/version/2.2/procedure/release-build/">GDR 2000-10-17</a>]</td>
- <td>
- "Perforce Defect Tracking Integration Release Build Procedure";
- <a href="mailto:gdr@ravenbrook.com">Gareth Rees</a>;
- <a href="http://www.ravenbrook.com/">Ravenbrook Limited</a>;
- 2000-10-17.
- </td>
- </tr>
- <tr valign="top">
- <td>[<a id="ref-GDR-2001-07-02" name="ref-GDR-2001-07-02" href="http://www.ravenbrook.com/project/p4dti/version/2.2/design/test/">GDR 2001-07-02</a>]</td>
- <td>
- "Test design";
- <a href="mailto:gdr@ravenbrook.com">Gareth Rees</a>;
- <a href="http://www.ravenbrook.com/">Ravenbrook Limited</a>;
- 2001-07-02.
- </td>
- </tr>
- <tr valign="top">
- <td>[<a id="ref-GDR-2001-07-13" name="ref-GDR-2001-07-13" href="http://www.ravenbrook.com/project/p4dti/version/2.2/design/build/">GDR 2001-07-13</a>]</td>
- <td>
- "Build automation design";
- <a href="mailto:gdr@ravenbrook.com">Gareth Rees</a>;
- <a href="http://www.ravenbrook.com/">Ravenbrook Limited</a>;
- 2001-07-13.
- </td>
- </tr>
- <tr valign="top">
- <td>[<a id="ref-GDR-2001-11-14" name="ref-GDR-2001-11-14" href="../aag/index.html">GDR 2001-11-14</a>]</td>
- <td>
- "Perforce Defect Tracking Integration Advanced Administrator's Guide";
- <a href="mailto:gdr@ravenbrook.com">Gareth Rees</a>;
- <a href="http://www.ravenbrook.com/">Ravenbrook Limited</a>;
- 2001-11-14.
- </td>
- </tr>
- <tr valign="top">
- <td>[<a id="ref-ISO-2108" name="ref-ISO-2108">ISO 2108</a>]</td>
- <td>
- "ISO 2108: International standard book number (ISBN)";
- <a href="http://www.iso.ch/">ISO</a>.
- </td>
- </tr>
- <tr valign="top">
- <td>[<a id="ref-Lutz-1996" name="ref-Lutz-1996">Lutz 1996</a>]</td>
- <td>
- "Programming Python"; Mark Lutz; O'Reilly; 1996-10; ISBN 1-56592-197-6.
- </td>
- </tr>
- <tr valign="top">
- <td>[<a id="ref-NB-2000-11-14a" name="ref-NB-2000-11-14a" href="http://www.ravenbrook.com/project/p4dti/tool/cgi/bugzilla-schema/">NB 2000-11-14a</a>]</td>
- <td>
- "Bugzilla database schema";
- <a href="mailto:nb@ravenbrook.com">Nick Barnes</a>;
- <a href="http://www.ravenbrook.com/">Ravenbrook Limited</a>;
- 2000-11-14.
- </td>
- </tr>
- <tr valign="top">
- <td>[<a id="ref-NB-2000-11-14b" name="ref-NB-2000-11-14b" href="http://www.ravenbrook.com/project/p4dti/version/2.2/design/bugzilla-p4dti-schema/">NB 2000-11-14b</a>]</td>
- <td>
- "Bugzilla database schema extensions for integration with Perforce";
- <a href="mailto:nb@ravenbrook.com">Nicholas Barnes</a>;
- <a href="http://www.ravenbrook.com/">Ravenbrook Limited</a>;
- 2000-11-14.
- </td>
- </tr>
- <tr valign="top">
- <td>[<a id="ref-NB-2000-11-14c" name="ref-NB-2000-11-14c" href="http://www.ravenbrook.com/project/p4dti/version/2.2/design/python-bugzilla-interface/">NB 2000-11-14c</a>]</td>
- <td>
- "Python interface to Bugzilla: design";
- <a href="mailto:nb@ravenbrook.com">Nicholas Barnes</a>;
- <a href="http://www.ravenbrook.com/">Ravenbrook Limited</a>;
- 2000-11-14.
- </td>
- </tr>
- <tr valign="top">
- <td>[<a id="ref-Perforce-2003-07-15a" name="ref-Perforce-2003-07-15a" href="http://www.perforce.com/perforce/doc.031/manuals/p4guide/">Perforce 2003-07-15a</a>]</td>
- <td>
- "Perforce 2003.1 User's Guide";
- <a href="http://www.perforce.com/">Perforce Software</a>;
- 2003-07-15;
- <<a href="http://www.perforce.com/perforce/doc.031/manuals/p4guide/">http://www.perforce.com/perforce/doc.031/manuals/p4guide/</a>>, <<a href="http://www.perforce.com/perforce/doc.031/manuals/p4guide/p4guide.pdf">http://www.perforce.com/perforce/doc.031/manuals/p4guide/p4guide.pdf</a>>.
- </td>
- </tr>
- <tr valign="top">
- <td>[<a id="ref-Perforce-2003-07-15b" name="ref-Perforce-2003-07-15b" href="http://www.perforce.com/perforce/doc.031/manuals/p4sag/">Perforce 2003-07-15b</a>]</td>
- <td>
- "Perforce 2003.1 System Administrator's Guide";
- <a href="http://www.perforce.com/">Perforce Software</a>;
- 2003-07-15;
- <<a
- href="http://www.perforce.com/perforce/doc.031/manuals/p4sag/">http://www.perforce.com/perforce/doc.031/manuals/p4sag/</a>>,
- <<a
- href="http://www.perforce.com/perforce/doc.031/manuals/p4sag/p4sag.pdf">http://www.perforce.com/perforce/doc.031
- /manuals/p4sag/p4sag.pdf</a>>.
- </td>
- </tr>
- <tr valign="top">
- <td>[<a id="ref-Purcell-2001-02-12" name="ref-Purcell-2001-02-12" href="http://pyunit.sourceforge.net/">Purcell 2001-02-12</a>]</td>
- <td>
- "PyUnit — a unit testing framework for Python";
- <a href="mailto:stephen_purcell@yahoo.com">Steve Purcell</a>;
- 2001-02-12.
- </td>
- </tr>
- <tr valign="top">
- <td>[<a id="ref-RB-2000-08-10a" name="ref-RB-2000-08-10a" href="../ag/index.html">RB 2000-08-10a</a>]</td>
- <td>
- "Perforce Defect Tracking Integration Administrator's Guide";
- <a href="mailto:rb@ravenbrook.com">Richard Brooksby</a>;
- <a href="http://www.ravenbrook.com/">Ravenbrook Limited</a>;
- 2000-08-10.
- </td>
- </tr>
- <tr valign="top">
- <td>[<a id="ref-RB-2000-08-10b" name="ref-RB-2000-08-10b" href="../ug/index.html">RB 2000-08-10b</a>]</td>
- <td>
- "Perforce Defect Tracking Integration User's Guide";
- <a href="mailto:rb@ravenbrook.com">Richard Brooksby</a>;
- <a href="http://www.ravenbrook.com/">Ravenbrook Limited</a>;
- 2000-08-10.
- </td>
- </tr>
- <tr valign="top">
- <td>[<a id="ref-RB-2000-08-10c" name="ref-RB-2000-08-10c" href="http://www.ravenbrook.com/project/p4dti/version/2.2/design/architecture/">RB 2000-08-10c</a>]</td>
- <td>
- "Perforce Defect Tracking Integration Architecture";
- <a href="mailto:rb@ravenbrook.com">Richard Brooksby</a>;
- <a href="http://www.ravenbrook.com/">Ravenbrook Limited</a>;
- 2000-08-10.
- </td>
- </tr>
- <tr valign="top">
- <td>[<a id="ref-RB-2001-03-07" name="ref-RB-2001-03-07" href="http://www.ravenbrook.com/project/p4dti/procedure/contribution/">RB 2001-03-07</a>]</td>
- <td>
- "P4DTI Project Contributions Procedure";
- <a href="mailto:rb@ravenbrook.com">Richard Brooksby</a>;
- <a href="http://www.ravenbrook.com/">Ravenbrook Limited</a>;
- 2001-03-07.
- </td>
- </tr>
- <tr valign="top">
- <td>[<a id="ref-RB-2001-03-21" name="ref-RB-2001-03-21" href="http://www.ravenbrook.com/project/p4dti/version/2.2/procedure/release-test/">RB 2001-03-21</a>]</td>
- <td>
- "Release test procedure";
- <a href="mailto:rb@ravenbrook.com">Richard Brooksby</a>;
- <a href="http://www.ravenbrook.com/">Ravenbrook Limited</a>;
- 2001-03-21.
- </td>
- </tr>
- <tr valign="top">
- <td>[<a id="ref-van-Rossum-2000-10-16" name="ref-van-Rossum-2000-10-16" href="http://www.python.org/doc/current/tut/tut.html">van Rossum 2000-10-16</a>]</td>
- <td>
- "Python Tutorial";
- <a href="mailto:python-docs@python.org">Guido van Rossum</a>;
- 2000-10-16.
- </td>
- </tr>
- </table>
- <h2><a id="section-B" name="section-B">B. Document History</a></h2>
- <table>
- <tr valign="top">
- <td>2000-10-16</td>
- <td><a href="mailto:rb@ravenbrook.com">RB</a></td>
- <td>Created placeholder after meeting with <a href="mailto:lmb@ravenbrook.com">LMB</a>.</td>
- </tr>
- <tr valign="top">
- <td>2000-12-10</td>
- <td><a href="mailto:gdr@ravenbrook.com">GDR</a></td>
- <td>Drafted sections 3 and 4.</td>
- </tr>
- <tr valign="top">
- <td>2000-12-11</td>
- <td><a href="mailto:gdr@ravenbrook.com">GDR</a></td>
- <td>Drafted sections 2, 5, and 8 and outlined sections 6 and 7.</td>
- </tr>
- <tr valign="top">
- <td>2000-12-31</td>
- <td><a href="mailto:gdr@ravenbrook.com">GDR</a></td>
- <td>The table of fixes in section 8 now distinguishes pending from submitted changes.</td>
- </tr>
- <tr valign="top">
- <td>2001-01-02</td>
- <td><a href="mailto:gdr@ravenbrook.com">GDR</a></td>
- <td>Added section 7.1 (configuration architecture), figure 1, section 7.5 (customized configuration). Moved text from appendix D of the Administrator's Guide to section 7.5.</td>
- </tr>
- <tr valign="top">
- <td>2001-02-04</td>
- <td><a href="mailto:gdr@ravenbrook.com">GDR</a></td>
- <td>Updated definition of <code class="source">defect_tracker.all_issues</code> method.</td>
- </tr>
- <tr valign="top">
- <td>2001-02-23</td>
- <td><a href="mailto:gdr@ravenbrook.com">GDR</a></td>
- <td>Added <code class="source">corresponding_id</code> method; revised definition of <code class="source">readable_name</code> method.</td>
- </tr>
- <tr valign="top">
- <td> 2001-03-02 </td>
- <td> <a href="mailto:rb@ravenbrook.com">RB</a> </td>
- <td> Transferred copyright to Perforce under their license. </td>
- </tr>
- <tr valign="top">
- <td>2001-03-13</td>
- <td><a href="mailto:gdr@ravenbrook.com">GDR</a></td>
- <td>Deleted the recording of conflicts and the need for manual conflict resolution. Conflict resolution is always immediate.</td>
- </tr>
- <tr valign="top">
- <td>2001-03-20</td>
- <td><a href="mailto:gdr@ravenbrook.com">GDR</a></td>
- <td>Added overviews of requirements, architecture and design. Included replicator block diagram. Improved links.</td>
- </tr>
- <tr valign="top">
- <td>2001-03-21</td>
- <td><a href="mailto:gdr@ravenbrook.com">GDR</a></td>
- <td>Wrote specifications of the defect tracker and translator
- classes. Described messages, catalogs, logging and errors. Moved
- logging and errors to new section 5 because it's important; renumbered
- remaining sections; moved configuration adaption to new section
- 8.6.</td>
- </tr>
- <tr valign="top">
- <td>2001-03-22</td>
- <td><a href="mailto:gdr@ravenbrook.com">GDR</a></td>
- <td>Specified the configuration generator; explained how to make your own configuration (with example code); explained how to adapt the manuals. Gave warning about incompatible jobspecs. Added prerequisites and where to get help. Added section on testing. Added section on code layout. Explained how to report defects and submit contributions.</td>
- </tr>
- <tr valign="top">
- <td> 2001-03-29 </td>
- <td> <a href="mailto:rb@ravenbrook.com">RB</a> </td>
- <td> Changed internal and external cross-references to conform with our other documents. Tidied up references to requirements. Removed claims about assigning copyright. Removed section promising to do particular things with contributions. Updated references to Perforce manuals to (latest) release 2000.2. Validated and fixed some broken links. Sorted references section. </td>
- </tr>
- <tr valign="top">
- <td>2001-05-17</td>
- <td><a href="mailto:gdr@ravenbrook.com">GDR</a></td>
- <td>Updated signatures of <code class="source">all_issues</code> and <code class="source">changed_entities</code>: these methods return cursors, not lists, to work around <a href="http://www.ravenbrook.com/project/p4dti/issue/job000277">job000277</a>.</td>
- </tr>
- <tr valign="top">
- <td>2001-05-19</td>
- <td><a href="mailto:gdr@ravenbrook.com">GDR</a></td>
- <td>Added section on making changes.</td>
- </tr>
- <tr valign="top">
- <td>2001-05-22</td>
- <td><a href="mailto:gdr@ravenbrook.com">GDR</a></td>
- <td>Noted that a message catalog must not have an entry for message id 0.</td>
- </tr>
- <tr valign="top">
- <td>2001-06-11</td>
- <td><a href="mailto:gdr@ravenbrook.com">GDR</a></td>
- <td>Added warning about field values in Perforce. Added section listing significant changes since previous releases.</td>
- </tr>
- <tr valign="top">
- <td>2001-06-27</td>
- <td><a href="mailto:nb@ravenbrook.com">NB</a></td>
- <td>Fix interface to <code class="source">all_issues</code> method to fix <a href="http://www.ravenbrook.com/project/p4dti/issue/job000340/">job000340</a>.</td>
- </tr>
- <tr valign="top">
- <td>2001-06-28</td>
- <td><a href="mailto:gdr@ravenbrook.com">GDR</a></td>
- <td>Added note on timezones.</td>
- </tr>
- <tr valign="top">
- <td>2001-07-09</td>
- <td><a href="mailto:nb@ravenbrook.com">NB</a></td>
- <td>Added <code class="source">job_url</code> configuration parameter.</td>
- </tr>
- <tr valign="top">
- <td>2001-07-14</td>
- <td><a href="mailto:gdr@ravenbrook.com">GDR</a></td>
- <td>Added image map to figure 1. Updated references to Perforce manuals from 2000.2 to 2001.1, since we now support the later version.</td>
- </tr>
- <tr valign="top">
- <td>2001-10-02</td>
- <td><a href="mailto:gdr@ravenbrook.com">GDR</a></td>
- <td>Extended the <a href="#user_translator.unmatched_users"><code
- class="source">unmatched_users</code></a> method so that the
- replicator can report users with duplicate e-mail addresses.</td>
- </tr>
- <tr valign="top">
- <td>2001-10-23</td>
- <td><a href="mailto:gdr@ravenbrook.com">GDR</a></td>
- <td>Added migration methods to defect tracker class.</td>
- </tr>
- <tr valign="top">
- <td>2001-11-01</td>
- <td><a href="mailto:nb@ravenbrook.com">NB</a></td>
- <td>Added <a href="#defect_tracker.poll_start"><code class="source">poll_start</code></a> and <a href="#defect_tracker.poll_end"><code class="source">poll_end</code></a> methods to defect tracker class.</td>
- </tr>
- <tr valign="top">
- <td>2001-11-05</td>
- <td><a href="mailto:gdr@ravenbrook.com">GDR</a></td>
- <td>Added <a href="#config-prepare_issue_advanced"><code class="source">prepare_issue_advanced</code></a> to replicator configuration.</td>
- </tr>
- <tr valign="top">
- <td>2001-11-20</td>
- <td><a href="mailto:gdr@ravenbrook.com">GDR</a></td>
- <td>Added <a href="#config-translate_jobspec_advanced"><code
- class="source">translate_jobspec_advanced</code></a> and <a
- href="#config-jobspec"><code class="source">jobspec</code></a> to
- replicator configuration. Defined representation of job
- specifications.</td>
- </tr>
- <tr valign="top">
- <td> 2001-11-22 </td>
- <td> <a href="mailto:rb@ravenbrook.com">RB</a> </td>
- <td> Cross-referenced section on <code class="source">replicate_p</code> to the <cite><a href="../aag/index.html">Perforce Defect Tracking Integration Advanced Administrator's Guide</a></cite>. </td>
- </tr>
- <tr valign="top">
- <td>2001-12-04</td>
- <td><a href="mailto:gdr@ravenbrook.com">GDR</a></td>
- <td>Added missing <a href="#defect_tracker_issue.add_filespec"><code class="source">add_filespec</code></a> method. Added optional features and the <a href="#defect_tracker.supports"><code class="source">supports</code></a> method.</td>
- </tr>
- <tr valign="top">
- <td>2002-01-31</td>
- <td><a href="mailto:gdr@ravenbrook.com">GDR</a></td>
- <td>Include <a href="#defect_tracker.replicate_changelist"><code>replicate_changelist</code></a> method in the <a href="#feature-fixes">fixes</a> feature.</td>
- </tr>
- <tr valign="top">
- <td>2002-02-01</td>
- <td><a href="mailto:gdr@ravenbrook.com">GDR</a></td>
- <td>Removed <code class="source">replicate_p</code> method from <a href="#section-7.2"><code class="source">defect_tracker_issue</code></a> class.</td>
- </tr>
- <tr valign="top">
- <td>2002-02-03</td>
- <td><a href="mailto:gdr@ravenbrook.com">GDR</a></td>
- <td>Added missing method <a href="#defect_tracker_issue.delete"><code class="source">delete</code></a> to the <a href="#section-7.2"><code class="source">defect_tracker_issue</code></a> class.</td>
- </tr>
- <tr valign="top">
- <td>2003-06-02</td>
- <td><a href="mailto:nb@ravenbrook.com">NB</a></td>
- <td>Updated for version 2.0: converted TeamTrack examples to
- Bugzilla examples, rewrote some TeamTrack references, added the <a
- href="#defect_tracker.add_replicator_user"><code class="source">add_replicator_user</code></a> method.</td>
- </tr>
- <tr valign="top">
- <td>2003-12-17</td>
- <td><a href="mailto:nb@ravenbrook.com">NB</a></td>
- <td>Updated Perforce manual references to 2003.1.</td>
- </tr>
- </table>
- <hr />
- <p> <small>This document is copyright © 2001 Perforce Software, Inc. All rights reserved.</small> </p>
- <p> <small>Redistribution and use of this document in any form, with or without modification, is permitted provided that redistributions of this document retain the above copyright notice, this condition and the following disclaimer.</small> </p>
- <p> <small> <strong> This document 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 document, even if advised of the possibility of such damage. </strong> </small> </p>
- <div align="center">
- <p><code class="perforce-keyword">$Id: //info.ravenbrook.com/project/p4dti/version/2.2/manual/ig/index.html#3 $</code></p>
- </div>
- </body>
- </html>
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 5093 | Hari Krishna Dara |
Populating perforce branch. I will be adding p4admin files to it. |
20 years ago | |
//guest/perforce_software/p4dti/release/2.2.2/ig/index.html | |||||
#1 | 4861 | richard_brooksby | Upload P4DTI 2.2.2 to the Perforce Public Depot. | 20 years ago |