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
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 "/plugins/com.altep.teamcity.runner.DotNet/dotNetRunParams.jsp" 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 "/plugins/com.altep.teamcity.runner.DotNet/dotNetRunParams.jsp" 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)
Please sign in to leave a comment.
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.
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 "/plugins/com.altep.teamcity.runner.DotNet/plugins/altepTeamcityPlugin/dotNetRunParams.jsp" 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
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.
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'?
RunType#getType should return the same name as the name of the folder.
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.
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?
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.