Skip to end of metadata
Go to start of metadata

TeamCity offers integration with several issue trackers and a custom plugin can provide support for other systems.

Issue tracker integration

To create a TeamCity plugin for custom issue tracking system (ITS), you have to implement the following interfaces (all from jetbrains.buildServer.issueTracker package):

The main entity is a provider (i.e. connection to the ITS), responsible for parsing, extracting and fetching issues from the ITS.

Here is a brief description of the strategy used in TeamCity in respect to ITS integration:
When the server is going to render the user comment (VCS commit, or build comment), it invokes all registered providers to parse the comment. This operation is performed by the IssueProvider.getRelatedIssues() method, which analyzes the comment and returns the list of the issue mentions ( jetbrains.buildServer.issueTracker.IssueMention). IssueMention just holds the information that is enough to render a popup arrow near the issue id. When the user points the mouse cursor on the arrow, the server requests the full data for this issue calling IssueProvider.findIssueById() method, and then displays the data in a popup. The data can be taken from the provider's cache.

The provider has a number of parameters, configured from admin UI. These parameters are passed using the properties map (a map string -> string). Commonly used properties include provider name, credentials to communicate with ITS, or regular expression to parse issue ids. You don't have to worry about storing the properties in XML files, server does that.

Provider registration is done by the TeamCity administrator in the web UI, and the responsibility for it lies mostly on TeamCity server. The plugin must only provide a JSP used for creation/editing of the provider (see details below).

Plugin development overview

A brief summary of steps to be done to create and add a plugin to TeamCity.

Reusing default implementation

Common code of Jira, Bugzilla and YouTrack plugins can be found in Abstract* classes in the same package:

AbstractIssueProvider implements a simple caching provider able to extract the issues from the string based on a regexp. In most cases you just need to derive from it and override few methods. A simple derived provider class can look like this:

Providers like Bugzilla might need to override extractId method, because the mention of issue id (in comment) and the id itself can differ. For instance, suppose the issues are referenced by a hash with a number, e.g. #1234; the regexp is "#(\d{4})" (configurable); but the issues in ITS are represented as plain integers. Then the provider must extract the substrings matching "#(\d{4})" and return the first groups only. You should implement it in extractId method:

The factory code is very simple as well, for example:

IssueFetcher is usually the central class performing plugin-specific logic. You have to implement getIssue method, which connects to the ITS remotely (via HTTP, XML-RPC, etc), passes authentication, retrieves the issue data and returns it, or reports an error. Example:

You need to implement how to compose the server URL and how do you parse the data out of XML (HTML). AbstractIssueFetcher will take care about caching, errors reporting and everything else.

Plugin UI

The only mandatory JSP required by TeamCity is editIssueProvider.jsp (the full path must be /plugins/myName/admin/editIssueProvider.jsp, that is, the plugin should have the jsp available /admin/editIssueProvider.jsp of its resources). This JSP is requested when the user opens the dialog for editing (or creating) the issue provider. In most cases it just renders the provider properties, or returns the form for filling them.

You can see the example in /plugins/youtrack/admin/editIssueProvider.jsp.

  • No labels


  1. Let's consider adding an example plugin into our external Subversion repository.
    Let's add an overview note that covers all that should be done for the plugin to work (implement interfaces, add jsp, use appropriate layout in the plugin, deploy the plugin).

    I also believe plugin name should be consistently referenced in all the places.
    Should "myName", "MyName" and "<plugin-name>" (these are references on this page) all be the same?

    1. I agree, an example would be nice.
      As we've discussed we're not ready for now to support Trac. Redmine is a good candidate, but it has a limited doc.

      Overview - ok.

      Considering names: it's just a convention that plugin name ('myName') starts with a lowercase char, and type name ('MyName') starts with uppercase char, because it is shown in UI. The strict requirements are described in javadoc.