Build runner plugin consists of two parts: agent-side and server-side. Server side part of the plugin provides meta information about build runner, web UI for build runner settings and build runner properties validator. Agent side part launches build.
Build runner can have various settings which must be edited by the user on the web UI and passed to the agent. These settings are called runner parameters (or runner properties) and provided as a Map<String, String> to the agent part of the runner.
Server side part of the runner
The main entry point for the runner on the server side is jetbrains.buildServer.serverSide.RunType. Build runner plugin must provide its' own RunType and register it in the jetbrains.buildServer.serverSide.RunTypeRegistry.
RunType has a type which should be unique among all build runners and correspond to type returned by agent-side part of the runner (see jetbrains.buildServer.agent.AgentBuildRunnerInfo).
Methods getEditRunnerParamsJspFilePath and getViewRunnerParamsJspFilePath shall return paths to JSP files for editing and viewing runner settings. These JSP files should be bundled with plugin in buildServerResources subfolder, read more. Paths should be relative to the buildServerResources folder.
When user fills in your runner settings and submits form a jetbrains.buildServer.serverSide.PropertiesProcessor returned by getRunnerPropertiesProcessor method will be called. This processor will be able to verify user settings and indicate which of them are invalid.
Usually JSP page is simple and does not provide much controls except for fields, checkboxes and so on. But if you need more control on how the page is processed on the server side, then you should register your own extension to the runner editing controller: jetbrains.buildServer.controllers.admin.projects.EditRunTypeControllerExtension.
And finally if you need to prefill some settings with default values you can do this with help of getDefaultRunnerProperties method.
Agent side part of the runner
The main interface for agent side runners is jetbrains.buildServer.agent.AgentBuildRunner. However if your custom runner runs external process it is simpler to use the following classes:
You should implement factory interface CommandLineBuildServiceFactory and make your class a Spring bean. Factory also provides some meta information about runner via jetbrains.buildServer.agent.AgentBuildRunnerInfo.
CommandLineBuildService is an abstract class which simplifies external processes launching and allows to listen for process events (output, finish and so on). Your runner should extend this class. Starting from TeamCity 6.0 we introduced jetbrains.buildServer.agent.runner.BuildServiceAdapter class that extends CommandLineBuildService and provides could utility methods to access build and runner context parameters.
AgentBuildRunnerInfo has two methods: getType which must return the same type returned by the server side part of the plugin, and canRun which is called to determine whether custom runner can run on the agent (in the agent environment).
If command line build service is not suitable for your needs you can still implement AgentBuildRunner interface and defined it in the Spring context. Then it will be loaded automatically.
Logging to build log
Usually build runner starts external process and logging is performed from that process. The simplest way to log messages in this case is to use service messages, read more. In brief service message is a specially formatted text with attributes, when such text is logged to the process output it is parsed and associated processing is performed. With help of these messages you can create TeamCity hierarchical build log, report tests, errors and so on.
If external process launched by your runner is Java and you can't use service messages it is possible to obtain jetbrains.buildServer.agent.BuildProgressLogger in the class running in this JVM. For this the following jar files must be added in the classpath of external Java process: runtime-util.jar, server-logging.jar. Then you should use jetbrains.buildServer.agent.ant.LoggerFactory method to construct logger: LoggerFactory.createBuildProgressLogger(parentClassloader). Since this way is more involved it is recommended to use service messages instead.
If logging of the messages is done in the agent JVM (not from within the external process started by your runner) you can obtain jetbrains.buildServer.agent.BuildProgressLogger from the jetbrains.buildServer.agent.AgentRunningBuild#getBuildLogger method.
Extending Ant runner
TeamCity Ant runner while being a plugin itself can also be extended with help of jetbrains.buildServer.agent.ant.AntTaskExtension. This extension works in the same JVM where Ant is running. With help of this extension you can watch for Ant tasks, modify/patch them and log various messages to the build log.
Your class implementing AntTaskExtension interface must be defined in the Spring bean and it will be picked up by Ant runner automatically. You need to add a dependency to <teamcity>/webapps/ROOT/WEB-INF/plugins/ant/agent/antPlugin.zip!antPlugin/ant-runtime.jar jar.