Plugins Packaging
This page describes how plugins should be packaged by plugin developers. See Installing Additional Plugins for instruction on plugin installation.
To write TeamCity plugin it is beneficial to have some knowledge about Spring Framework. Server-side and agent-side TeamCity plugins are initialized in their own Spring container. This means that every plugin should have a Spring bean definition file describing main plugin services.
TeamCity allows to have plugins for server-side and agent-side. Note, TeamCity server-side plugin may contain a number of agent-side plugins that will be automatically distributed to all build agents.
There is a convention how bean definition file MUST be named:
build-server-plugin-<plugin name>*.xml — for server side plugins
build-agent-plugin-<plugin name>*.xml — for agent side plugins
where an asterisk can be replaced with any text, for example: build-server-plugin-cvs.xml. Bean definition files should be placed into the META-INF
folder of the JAR archive containing plugin classes.
Web resources packaging (server only)
In most cases plugin is just a number of classes packed into a JAR file, but if you wish to write custom page for TeamCity, most likely you'll need to place images, CSS, JavaScript, JSP files or binaries somewhere. Files that you want to access via hyperlinks and JSP pages you should place into the buildServerResources subfolder of plugin .jar file. Upon server startup these files will be extracted from the archive. You may use jetbrains.buildServer.web.openapi.PluginDescriptor
spring bean to get paths to extracted resources (Web UI Extensions on how to construct paths to your JSP files). It is a good practice to put all resources into a separate.jar file.
Installation of TeamCity plugins (server only)
TeamCity is able to load plugin from the following directories:
<TeamCity data directory> /plugins
– Installing Additional Plugins plugins< TeamCity web application >/WEB-INF/plugins
— default directory for bundled TeamCity plugins
Plugins with the same name (for example, newer version) put into < TeamCity data directory >/plugins
will override plugins put into < TeamCity web application >/WEB-INF/plugins
directory.
You can put plugin into plugins
directory as a separate folder or as a zip archive. Note that server must be restarted to load your plugin.
If you use a separate folder:
TeamCity will use the folder name as plugin name
If you use a zip file:
TeamCity will use name of the zip file as the plugin name
Plugin zip file will be automatically unpacked to temporary directory on server startup
Inside plugin directory there should be the following structure:
agent | --> <agent plugin zip files> (see below) server | --> <server plugin jar files> teamcity-plugin.xml
agent directory must contain one file only: <agent plugin zip> which should be prepared so that all files and directories are placed into the single root directory. That is, there must be one root folder in the archive (<plugin top level directory> in the diagram below), and there should not be other files at the top level. Usually for convenience the name of <plugin top level directory> is the same as the plugin name. All .jar files required by the plugin on the agent must be placed to the lib subfolder:
<plugin top level directory> | --> lib | --> <jar files>
server folder contains server side part of the plugin, that is, a bunch of jar files.
teamcity-plugin.xml contains some meta information about plugin, like its name and version, see below.
Plugins Loading
TeamCity creates a child Spring Framework context per plugin. There are two options to load plugins classes: standalone and shared:
Shared classloading allows to load all plugins into same classloader. It is not allowed to override any libraries here.
recommeneded Standalone classloading allows to load every pluging to a fresh classloader. This approach allows plugin to have additional libraries without a risk to affect server or another plugins.
You may specify desired classloading mode in teamcity-plugin.xml
file.
Agent upgrade
TeamCity server monitors all agent plugins .zip files for a change (plugin files change, add or remove). Once change is detected, agents receive upgrade command from the server and download updated files automatically. In practice it means that if you want to deploy updated agent part of your plugin without server restart you can put your agent plugin to this folder.
After successful upgrade your plugin will be unpacked into the < Agent home >/plugins/
or < Agent home >/tools/
folders. Note that if agent is busy running build it won't upgrade until the build finishes. Also no new builds will start on the agent if it should be updated.
Plugin Descriptor (teamcity-plugin.xml) (server-side only)
teamcity-plugin.xml
file should be placed to the root of plugin folder or .zip file. You can refer to XSD schema for this file which is unpacked to <TeamCity data directory> /config/teamcity-plugin-descriptor.xsd
An example of teamcity-plugin.xml:
<?xml version="1.0" encoding="UTF-8"?> <teamcity-plugin xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:shemas-jetbrains-com:teamcity-plugin-v1-xml"> <info> <name>PluginName</name> <!-- the name of plugin used in teamcity --> <display-name>This name may be used for UI</display-name> <description>Some description goes here</description> <version>0.239.42</version> </info> <deployment use-separate-classloader="true" /> <!-- load server plugin's classes in separate classloader--> <parameters> <parameter name="key">value</parameter> <!-- ... --> </parameters> </teamcity-plugin>
Please, note that use-separate-classloader="true"
parameter is for server-side plugins only, it does not affect agent-side plugins. Until you are using some libraries which clash with TeamCity libraries, it is recommended to leave default behavior, that is, to use shared classloader.
Plugin parameters can be accessed via jetbrains.buildServer.web.openapi.PluginDescriptor#getParameterValue(String) method.
Agent-side plugin structure
TeamCity build agent supports 3 type plugins:
old plugin type (with plugin name folder in .zip)
new plugin (with teamcity-plugin.xml)
tool plugin (with teamcity-plugin.xml)
Starting from pre 1.0 versions old plugin schema was widely used. Every plugin must be packaged in .zip
file with the following structure inside:
agent-plugin-name.zip | - agent-plugin-name | - lib | - plugin.jar - plugin-lib.jar
There should be no other items in the root of .zip but folder with plugin name. TeamCity build agent detects and loads such plugins using shared classloader.
Starting from 6.5 we added new plugin schema of packing. For now, every plugin may be packed in more flexible structure:
agent-plugin-name.zip | - teamcity-plugin.xml - lib | plugin.jar plugin.lib
Agent plugin name now is obtained from plugin .zip
file name. There is no plugin named root folder inside a plugin archive. The main change is that now it's required to have teamcity-plugin.xml
file under the root of agent plugin .zip
file.
This file provides description of plugin (same as it is done on the server-side):
<?xml version="1.0" encoding="UTF-8"?> <teamcity-agent-plugin xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:shemas-jetbrains-com:teamcity-agent-plugin-v1-xml"> <plugin-deployment use-separate-classloader="true"/> </teamcity-agent-plugin>
In TeamCity 6.5 we introduced tool plugin for agent. This is a kind of plugin without any classes that are loaded into runtime. We use it to redistibute binaries to agents. If you like to deploy a tool, use the following teamcity-plugin.xml
file:
<?xml version="1.0" encoding="UTF-8"?> <teamcity-agent-plugin xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:shemas-jetbrains-com:teamcity-agent-plugin-v1-xml"> <tool-deployment/> </teamcity-agent-plugin>
Tool plugins for agent may be useful if you need to distribute a binary files only, i.e. git binaries or some other tool. For example: NuGet plugin for TeamCity creates a tool plugin for agent to distribute downloaded NuGet.exe to agents.
Agent tries to validate plugin-provided teamcity-plugin.xml
file against xml schema. If teamcity-plugin.xml
is not valid plugin will be loaded, but some data from the descriptor may be lost