Custom Build Runner Issue

I am trying to develop a custom build runner, but I am running into the following issue.

  • I have a RunType implementation called com.altep.teamcity.runner.DotNet.DotNetRunType.
  • I have the following in my build-server-plugin-altep.xml: <bean id="AltepDotNetRunType" />
  • DotNetRunType#getEditRunnerParamsJspFilePath() returns "dotNetRunParams.jsp"
  • I have a dotNetRunParams.jsp file in buildServerResources

I place the files in the TeamCityConfig\plugins directory:
plugins\altepTeamcityPlugin
teamcity-plugin.xml
server\
teamcity-0.0.1-SNAPSHOT.jar

teamcity-plugin.xml has /teamcity-plugin/info/name set to altepTeamcityPlugin

When I select my build runner from the combo box in the "Runner" tab of a build configuration, I get the following error:

Error message: File &quot;/plugins/com.altep.teamcity.runner.DotNet/dotNetRunParams.jsp&quot; not found

If I rename TeamCityInstall\webapps\ROOT\plugins\altepTeamcityPlugin to TeamCityInstall\webapps\ROOT\plugins\com.altep.teamcity.runner.DotNet, everything works as expected.

I also tried packing the plugin as a zip file, rather than just a directory, but I get the same result.

I did find a short term solution. I changed DotNetRunType#getEditRunnerParamsJspFilePath() to return "../altepTeamcityPlugin/dotNetRunParams.jsp" and TeamCity loads the JSP.

Stack trace:
Trace: javax.servlet.ServletException: File &quot;/plugins/com.altep.teamcity.runner.DotNet/dotNetRunParams.jsp&quot; not found
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:319)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
at jetbrains.spring.web.TeamCityJSPServletImpl.service(TeamCityJSPServletImpl.java:2)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at jetbrains.spring.web.JspController.doHandle(JspController.java:4)
at jetbrains.buildServer.controllers.BaseController.handleRequestInternal(BaseController.java:73)
at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:153)
at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:511)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at jetbrains.buildServer.rootDispatcher.TeamCityDispatcherServlet.service(TeamCityDispatcherServlet.java:79)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:646)
at org.apache.catalina.core.ApplicationDispatcher.doInclude(ApplicationDispatcher.java:551)
at org.apache.catalina.core.ApplicationDispatcher.include(ApplicationDispatcher.java:488)
at org.apache.jasper.runtime.JspRuntimeLibrary.include(JspRuntimeLibrary.java:968)
at org.apache.jsp.admin.editRunParams_jsp._jspService(editRunParams_jsp.java:161)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:374)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
at jetbrains.spring.web.TeamCityJSPServletImpl.service(TeamCityJSPServletImpl.java:2)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at jetbrains.spring.web.JspController.doHandle(JspController.java:4)
at jetbrains.buildServer.controllers.BaseController.handleRequestInternal(BaseController.java:73)
at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:153)
at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:511)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at jetbrains.buildServer.rootDispatcher.TeamCityDispatcherServlet.service(TeamCityDispatcherServlet.java:79)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:646)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:436)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:374)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:302)
at org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:236)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:257)
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1183)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:902)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:511)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at jetbrains.buildServer.rootDispatcher.TeamCityDispatcherServlet.service(TeamCityDispatcherServlet.java:79)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at jetbrains.buildServer.web.SetThreadNameFilter.runChainWithModifiedThreadName(SetThreadNameFilter.java:14)
at jetbrains.buildServer.web.SetThreadNameFilter.doFilter(SetThreadNameFilter.java:12)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at jetbrains.buildServer.web.ResponseFragmentFilter.doFilter(ResponseFragmentFilter.java:5)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)
at java.lang.Thread.run(Thread.java:595)
8 comments
Comment actions Permalink

Originally from TW-11115.

getEditRunnerParamsJspFilePath should actually return absolute path (JavaDoc should really be improved). To get the absolute path from a relative one you can request PluginDescriptor in the constructor and then use PluginDescriptor.getPluginResourcesPath mathod.

0
Comment actions Permalink

See: http://confluence.jetbrains.net/display/TCD5/Build+Runner+Plugin

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.

----------------

I did modify the RunType class to the following:

     return _pluginDesc.getPluginResourcesPath("dotNetRunParams.jsp");

I got the following error:

Error message: File &quot;/plugins/com.altep.teamcity.runner.DotNet/plugins/altepTeamcityPlugin/dotNetRunParams.jsp&quot; not found

I then modifieds the RunType class to the following, just in case getPluginResourcesPath was returning a relative path:

     return "/" + _pluginDesc.getPluginResourcesPath("dotNetRunParams.jsp");


and I get the same error

0
Comment actions Permalink

#permalink
I've found that the mentioned fix is only on TeamCity 5.1. For TeamCity 5.0 there was no such workaround.

To make it work, please make plugin name equal to 'run type'. Plugin name is the name of plugin .zip file or plugin folder. This name should be also used in teamcity-plugin.xml (info/name element).

All plugin resources are unpacked to /plugins/<plugin name> folder path, thus generated paths would work.
0
Comment actions Permalink

So I would need to make my plugin name 'com.altep.teamcity.runner.dotnet' or I would need to change the package of the build type class to be 'altepTeamcityPlugin'?

0
Comment actions Permalink

RunType#getType should return the same name as the name of the folder.

0
Comment actions Permalink

I see. You are saying that the build runner type id has to be the same as the plugin name, but wouldn't that limit my plugin to defining only a single build runner? Each build runner would require its own separate plugin. That really isn't ideal, but not impossible.

I did manage to get my build runner working and it works very well. It's basically a wrapper around the NAnt build runner, but the runner GUI provides all the necessary configuration options and switches. One nice advantage of this is that the runner can calculate the agent requirements based on how the build is configured (i.e. if code coverage is enabled, the agent must have the correct version of the coverage tool, etc).

Outside of the sometimes deficient and incorrect documentation, it wasn't too difficult. Only took about two days to implement. The biggest help, I think, were the XCode, Rake, and FXCop runner sources.

0
Comment actions Permalink

Starting from TeamCity 5.1 EAP it is possible to define as much RunTypes as you need inside a single plugin.

Just curious, do you use NAnt runner classes inside your plugin on server or agent?

0
Comment actions Permalink

On the server side I inject the NAntRunType into my run type and use that to get the default runner properties and the agent specific requirements. On the agent side, the easiest thing I found to do was to extend NAntBuildRunner. That's probably not the best thing to do, but it was the easiest thing to do. The only thing I do with that is override getType to return my run type id string.

0

Please sign in to leave a comment.