Implementing a TeamCity Plugin

Total: 1 Average: 5

Steps for implementing a TeamCity Plugin include:
• Preparing the development environment
• Generating a Maven project
• Implementing the plugin’s UI
• Organizing the business logic of the plugin.

A plugin in TeamCity is a zip file containing a Java class file, JSP files, resources, and plugin descriptor files.

The basic structure of the plugin

• Build module (contains only configuration files and defines how the plugin is compiled)

◦ plugin-assembly.xml

◦ plugin-agent-assembly.xml

◦ pom.xml

• Agent module (encapsulates logic that will be run on the agent side)

◦ java code

◦ resources

◦ pom.xml

• Common module (a module with shared code)

◦ java code

◦ resources

◦ pom.xml

• Server module (encapsulates logic that will be run on the server side)

◦ java code

◦ resources

◦ pom.xml

• pom.xml (plugin’s main POM file).

Preparing the development environment

Before you start developing a plugin for TeamCity, you must first prepare your environment. Please, make sure that you have:
• JDK 8 installed and JAVA_HOME variable set (the variable contains a path to the JDK software)
• Apache Maven installed
• An IDE that allows developing TeamCity plugins on Java installed (e.g., IntelliJ IDEA).

Generating a Maven project

To develop the Maven plugin for TeamCity, TeamCity Open API is available as a set of Maven artifacts residing in the JetBrains Maven repository. Add the following fragment to the <repositories> section of your pom file to access it:

To deploy your plugin project faster and more conveniently, you can use one of the three Maven archetypes in the org.jetbrains.teamcity.archetypes group

teamcity-plugin: an empty plugin, includes both the server and the agent plugin parts
teamcity-server-plugin: an empty plugin, includes the server plugin part only
teamcity-sample-plugin: the plugin with the sample code (adds a “Click me” button to the bottom of the TeamCity project Overview page).

The Maven commands to generate projects for different plugins depending on the TeamCity version are given below:

Server-side-only plugin:

Plugin with both the server and agent parts:

Sample plugin:

Regardless of the TeamCity version you’ve selected, you will be asked to enter the Maven groupId, artifactId and the version for your plugin. Please note, that artifactId will be used as your plugin name. After the project is generated, you can update teamcity-plugin.xml in the root directory by entering the display name of the plugin, its description, author email address, and other information.
You can also use the TeamCity SDK Maven plugin, that allows controlling a TeamCity instance from the command line when installing, updating and debugging a new plugin. You can find more information about developing the Maven plugin for TeamCity here.

Implementing the plugin’s UI

The UI for the plugin is typically based on JSP technology. JSP files are usually located in the server-side part of the plugin, just like all other resources necessary for the user interface. A simple example of a JSP file to create a button and process a click is given below.

This file can be used to embed JavaScript, refer to Java classes (for example, constants are often used to connect the business logic and the UI), add CSS styles and other resources for the UI. For instance:

• the 1st line of code specifies page encoding for the JSP page
• the 2nd line sets the controller class for the JSP page
• the 3rd line registers Java class with constants to connect the business logic and the UI
• the 4th and 5th lines comprise variables declaration
• the 6th and 7th lines link CSS и JSPF files
• the 8th line and rest of the code comprise JS functions declaration and implementation.

This is not a complete list of the JSP pages features. Refer to the tutorials on JSP development to find more information.
There are several approaches to registering and linking JSP pages with Java code, depending on the type of plugin. For example, for Build Runner plugins, it is necessary to implement the inheritance of the RunType class, in the methods of which the JSP pages are indicated (one for the edit mode, one for the view mode).
For example:

Let’s consider the basic moments of this class implementation:
PluginDescriptor is a Maven entity used to describe the process of plugin compilation. We’ll use it to register JSP pages.
RunTypeRegistry comprises an entity to register a plugin step.
getType(), getDisplayName(), getDescription() methods are used to describe basic parameters of the plugin step being implemented.
getEditRunnerParamsJspFilePath() and getViewRunnerParamsJspFilePath() methods are overridden to register JSP pages.
getRunnerPropertiesProcessor(), getDefaultRunnerProperties() and transformParameters methods serve to manipulate step parameters.
This class has many overriding methods that can be useful when developing a plugin. You can find more information about the RunType class here.

Organizing the business logic of the plugin

The plugin’s business logic can be implemented both on the server side and on the agent side (most often). The TeamCity Open API has a set of entities the implementation of which is necessary when developing the business logic of any TeamCity plugin. Let’s consider the example of a Build Runner plugin earnings. Its business logic comes down to implementing the factory interface – CommandLineBuildServiceFactory and extending the BuildServiceAdapter class.

This interface has two methods: createService () and getBuildRunnerInfo (). The first method is used to register a child from the BuildServiceAdapter, and the second one –  to create a AgentBuildRunnerInfo class object. You can find more detailed information here.

An example of this factory implementation:


BuildServiceAdapter comprises the main entity for implementing the business logic of the plugin step. This class has many methods and these methods overriding allows you to add preliminary logic, validate parameters before executing a step, execute directly the main logic of the step and post build logic. More information can be found here.
Consider an example of implementing the child of this class:


Artem Kravets

Artem Kravets is a software development team leader at Devart with a bachelor's degree in Computer Engineering and extensive .NET knowledge.
He is a ICAgile Certified Professional (ICP) with good experience in .NET desktop development, add-in integration, development of Maven plugins in Java and implementation of CI/CD processes.
Artem Kravets

Latest posts by Artem Kravets (see all)