Jenkins-maven-plugin
From Evgeny Goldin
Contents |
Introduction
Managing Jenkins jobs is not easy when there are many of them, especially if certain parameters should be identical among many jobs. "jenkins-maven-plugin" allows to generate Jenkins jobs, one "config.xml" per job, from a simple Maven POM. This way we can have all Jenkins jobs controlled in one place, reusing any amount of configuration between them.
Details
| Provided By | ||
|---|---|---|
| Mailing List | Nabble | |
| Source Code | GitHub | |
| License | ||
| Tests | GitHub | |
| GroovyDoc | <groovydoc>
| |
| Issue Tracker | YouTrack |
|
| Build Server | Maven TeamCity | |
| Maven Coordinates |
| |
| Goal |
| |
| Default Phase |
| |
| Maven Repository | Artifactory Online |
Supported Plugins
| Plugin | Used In (see <job> configuration reference) |
|---|---|
| CVS Plugin | <scmType>
|
| Subversion Plugin | <scmType>
|
| Git Plugin | <scmType>
|
| Mercurial Plugin | <scmType>
|
| Gradle Plugin | <tasks>, <prebuildersTasks>, <postbuildersTasks>
|
| Groovy Plugin | <groovy>, <tasks>, <prebuildersTasks>, <postbuildersTasks>
|
| GitHub Plugin | <gitHubUrl>, "github" trigger
|
| Artifactory Plugin | <artifactory>
|
| Parameterized Trigger Plugin | <invoke>
|
Examples
Simple Example
A typical usage would look like following (see complete POM at GitHub):
<plugin> <groupId>com.github.goldin</groupId> <artifactId>jenkins-maven-plugin</artifactId> <version>0.2.5</version> <executions> <execution> <id>generate-jenkins-jobs</id> <phase>compile</phase> <goals> <goal>generate</goal> </goals> <configuration> <generationPom>http://github.com/evgeny-goldin/maven-plugins-test/blob/master/jenkins-maven-plugin/standalone/pom.xml</generationPom> <jenkinsUrl>http://evgeny-goldin.org/jenkins/</jenkinsUrl> <outputDirectory>${user.home}/.jenkins/jobs</outputDirectory> <jobs> <job> <id>JBoss EJB 3</id> <scmType>git</scmType> <mavenName>apache-maven-3</mavenName> <jdkName>jdk1.6.0</jdkName> <repository> <remote>git://gitorious.org/jboss-ejb3/jboss-ejb3-context.git</remote> </repository> </job> <job> <id>google-guice</id> <mavenName>apache-maven-3</mavenName> <jdkName>jdk1.6.0</jdkName> <repository> <remote>http://google-guice.googlecode.com/svn/trunk/</remote> </repository> </job> <job> <id>simple-wicket</id> <scmType>cvs</scmType> <mavenName>apache-maven-3</mavenName> <jdkName>jdk1.6.0</jdkName> <repository> <remote>:pserver:anonymous@simple-wicket.cvs.sourceforge.net:/cvsroot/simple-wicket</remote> <cvsModule>simple-wicket</cvsModule> </repository> </job> </jobs> </configuration> </execution> </executions> </plugin>
to generate the following jobs: JBoss-EJB-3, google-guice, simple-wicket.
Inheritance and Jobs Invocation Example
Another example involving properties reuse and job invocation would look like following (see complete POM at GitHub):
<configuration> ... <jobs> <job> <id>base</id> <abstract>true</abstract> <jdkName>jdk1.6.0_21</jdkName> <mavenName>apache-maven-3</mavenName> <mavenOpts>-Xmx256m -XX:MaxPermSize=128m</mavenOpts> <daysToKeep>3</daysToKeep> <numToKeep>7</numToKeep> <useUpdate>true</useUpdate> <mavenGoals>-e clean test</mavenGoals> <mail> <recipients>evgenyg@gmail.com evgeny.goldin@gmail.com</recipients> </mail> </job> <job> <id>google-guice-2.0-maven</id> <parent>base</parent> <repository> <remote>http://google-guice.googlecode.com/svn/branches/2.0-maven/</remote> </repository> <trigger> <type>timer</type> <description>Runs every midnight except Saturday</description> <expression>0 0 * * 0-5</expression> </trigger> <invoke> <jobs>google-guice-2.0, google-guice-1.0-maven</jobs> <always>true</always> </invoke> </job> <job> <id>google-guice-2.0</id> <parent>base</parent> <repository> <remote>http://google-guice.googlecode.com/svn/tags/2.0/</remote> </repository> </job> <job> <id>google-guice-1.0-maven</id> <parent>base</parent> <repository> <remote>http://google-guice.googlecode.com/svn/tags/1.0-maven/</remote> </repository> </job> </jobs> </configuration>
to generate the following jobs: google-guice-2.0-maven, google-guice-2.0, google-guice-1.0-maven.
This example demonstrates:
- There's an abstract
"base"job. It contains most of configurations shared by other jobs:<jdkName>,<mavenName>,<mavenOpts>,<mavenGoals>, number of days to keep old jobs, mail recipients, etc. - Other jobs extend it with
"<parent>base</parent>", adding missing configurations like<repository>location and job triggers. Each job can override properties inherited and specify its own value for, say,<mavenOpts>or<useUpdate>. -
"google-guice-2.0-maven"job is triggered by"0 0 * * 0-5"cron expression - Every time it completes two other jobs are invoked, regardless of results:
"google-guice-2.0","google-guice-1.0-maven"
In short, "jenkins-maven-plugin" allows you to:
- Create any kind of hierarchies between the jobs, sensibly "inheriting" configurations from "super" jobs
- Keep all jobs you manage in one POM
It provides a solution to a challenging situation when one needs to manage and configure manually more than 5 Jenkins jobs, not to mention 30 or 100 of them which isn't uncommon.
Description Table
As a bonus, each job generated gets the following description table created as well:
This table provides a brief summary of job's definition: Maven goals and SVN update policy, SVN repositories and POM to run, mail recipients and "Invokes" / "Invoked By" list of jobs - the kind of data you usually need to know about the job.
There's no need to go into job's "Configure" section any more, for which you may not even have sufficient permissions.
<configuration>
See JenkinsMojo Groovydoc for all options available. Plugin's <configuration> requires 2 parameters, a number of optional ones and collection of <job> or <jobs>:
<configuration> <jenkinsUrl>http://server/jenkins</jenkinsUrl> <generationPom>http://svn.repo.com/projects/path/JenkinsConfigs/pom.xml</generationPom> <job> ... </job> </configuration>
Or
<configuration> <jenkinsUrl>http://server/jenkins</jenkinsUrl> <generationPom>http://svn.repo.com/projects/path/JenkinsConfigs/pom.xml</generationPom> <jobs> <job> ... </job> <job> ... </job> ... </jobs> </configuration>
| Name | Required | Default value | Description |
|---|---|---|---|
<runIf>
| false | Controls whether or not plugin should be executed, accepts a Groovy expression. | |
<jenkinsUrl>
| true | URL of your Jenkins server. Needed to provide "Invokes" / "Invoked By" job links in description table.
| |
<generationPom>
| true | URL of the POM containing jobs generation, the POM you're editing. Needed to provide a link from job description back to its "origin" POM, for people to see where job definition actually came from. | |
<outputDirectory>
| false | "${project.build.directory}"
| Directory where all config files will be generated. "${user.home}/.jenkins/jobs" value will write the files right into Jenkins's home directory.
|
<svnRepositoryLocalBase>
| false | "svn"
| Remote SVN repository URL partial path, serving as a base for its local path.
It is best explained with an example: having job's remote repository equal to Otherwise, Jenkins will use
|
<endOfLine>
| false | "windows"
| Line ending used in "config.xml" files generated: "\r\n" if "windows", "\n" otherwise.
|
<timestamp>
| false | "true"
| Whether or not a generation timestamp is written to "config.xml" file and description table, like in "JBoss-EJB-3" job.
|
<timestampFormat>
| false | "MMMM dd, yyyy (HH:mm:ss, 'GMT'Z)"
| Timestamp format, if enabled. Default value produces "September 13, 2010 (22:17:09, GMT+0200)"-like timestamps.
|
Some notes:
- See
<job>options below for complete reference of all available<job>parameters.
- If a single
<job>is specified,<jobs>can be omitted.
- When ran,
"<job id>/config.xml"is created in<outputDirectory>.
- After generation step and optional copying of files generated to your Jenkins instance (if they are not written to its home directory already) Jenkins needs to be restarted.
A better option is"Manage Jenkins"=>"Reload Configuration from Disk". It is planned to provide a plugin option for auto-reloading Jenkins configs by sending a corresponding HTTP request automatically.
<job>
The table below provides a reference of the currently available <job> options and you can also reference Job Groovydoc. "Inherited" column means whether property is inherited from a <parent> job when it's not defined (when property is defined - <parent> value is ignored).
| Name | Inherited | Default value | Example | Description |
|---|---|---|---|---|
<id>
| false | <id>NightlyJob</id>
| Job name.
| |
<abstract>
| false | false
| <abstract>true</abstract>
| Whether current <job> is abstract, i.e., it is used for inheritance only and no "config.xml" should be generated for it.
|
<parent>
| false | <parent>NightlyJob</parent>
| "Base" job(s) to inherit, should specify an <id> of another job(s).
| |
<disabled>
| true | false
| <disabled>true</disabled>
| Whether current job is disabled. |
<description>
| true |
| <description>Nightly job</description>
| Job description, appears above description table, HTML is allowed. |
<jobType>
| true | "maven"
| <jobType>free</jobType><jobType>maven</jobType>
| Job type: free-style job or maven job, see <tasks> below for free-style job actions.
|
<pom>
| true | "pom.xml"
| <pom>parent/pom.xml</pom>
| "Root POM" Jenkins option, location of POM to run when job is invoked.It is relative to the first remote <repository> specified.
|
<scmType>
| true | "svn"
| <scmType>git</scmType><scmType>svn</scmType>
| SCM system to fetch project sources and updates from. <scmType> values supported are:
|
|
| true |
CVS: <scmType>cvs</scmType> <repositories> <repository> <remote> :pserver:anonymous@simple-wicket.host.net:/cvsroot/simple-wicket </remote> <!-- Default is false --> <cvsTag>false</cvsTag> <!-- Default is true --> <cvsUpdate>true</cvsUpdate> <!-- Default is false --> <cvsLegacy>false</cvsLegacy> </repository> </repositories> Subversion: <scmType>svn</scmType> <repositories> <repository> <remote>http://v8.googlecode.com/svn/trunk/</remote> <!-- Jenkins's default is last remote path --> <local>trunk</local> </repository> <repository> <remote> http://dropthings.googlecode.com/svn/trunk/ </remote> </repository> </repositories> Git: <scmType>git</scmType> <repositories> <repository> <remote> git@github.com:evgeny-goldin/maven-plugins.git </remote> <!-- Default is "origin" --> <gitName>origin</gitName> <!-- Default is "+refs/heads/*:refs/remotes/origin/*" --> <gitRefspec> +refs/heads/*:refs/remotes/origin/* </gitRefspec> <!-- Default is "master" --> <gitBranch>master</gitBranch> </repository> <repository> <remote>git://gitorious.org/qt/qt.git</remote> <gitBranch>4.7</gitBranch> </repository> </repositories> Mercurial: <scmType>hg</scmType> <repository> <remote>https://bitbucket.org/kotarak/i18n</remote> <repoBrowser>bitbucket</repoBrowser> <repoBrowserUrl> https://bitbucket.org/kotarak/i18n </repoBrowserUrl> <hgClean>true</hgClean> </repository> | SCM repositories to checkout or update the files from.
| |
|
| true |
| Jenkins "Advanced Project Options". Note that <displayName> is not inherited.
| |
<jdkName>
| true | <jdkName>jdk1.6.0_24</jdkName>
| JDK to use, should correspond to the JDK specified in"Manage Jenkins => Configure System => JDK installations"
| |
<mavenName>
| true | <mavenName>apache-maven-3</mavenName>
| Maven to use, should correspond to the Maven specified in"Manage Jenkins => Configure System => Maven installations"
| |
<mavenGoals>
| true | "-B -e clean install"
| <mavenGoals>-B -U -e clean install</mavenGoals>
| Maven goals to execute.
Consider using |
<mavenOpts>
| true | <mavenOpts>-Xmx1024m -XX:MaxPermSize=512m</mavenOpts>
| "MAVEN_OPTS" for the job.
Consider increasing default memory settings with | |
<archivingDisabled>
| true | false
| <archivingDisabled>true</archivingDisabled>
| Whether current <job> artifacts are archived by Jenkins.
Required to be |
<buildOnSNAPSHOT>
| true | false
| <buildOnSNAPSHOT>false</buildOnSNAPSHOT>
| "Build whenever a SNAPSHOT dependency is built" Jenkins option.
|
<useUpdate>
| true | false
| <useUpdate>true</useUpdate>
| For SVN - "Use update" Jenkins option, whether "svn update" is used instead of "svn checkout" to update the project.
|
<doRevert>
| true | false
| <doRevert>true</doRevert>
| For SVN - "Revert" Jenkins option, whether "svn revert" is run before project is updated.
|
<authToken>
| true | <authToken>AuthenticationToken</authToken>
| "Trigger builds remotely" authentication token. | |
<descriptionTable>
| true |
<descriptionTable> <row> <key>Project in Sonar</key> <value> <![CDATA[<code><a href="..."> .. </a></code>]]> </value> <escapeHTML>false</escapeHTML> <bottom>true</bottom> </row> <row> <key>Anything else</key> <value>Anything else's value</value> </row> </descriptionTable> | Job's automatically-generated description table can have manually added rows which may be placed on the top or the bottom of the default table.
| |
<daysToKeep>
| true | -1
| <daysToKeep>14</daysToKeep>
| "Days to keep builds" option. Used only if greater than zero.
|
<numToKeep>
| true | -1
| <numToKeep>5</numToKeep>
| "Max # of builds to keep" option. Used only if greater than zero.
|
<artifactDaysToKeep>
| true | -1
| <artifactDaysToKeep>14</artifactDaysToKeep>
| "Days to keep artifacts" option. Used only if greater than zero.
|
<artifactNumToKeep>
| true | -1
| <artifactNumToKeep>5</artifactNumToKeep>
| "Max # of builds to keep with artifacts" option. Used only if greater than zero.
|
<node>
| true | "master"
| <node>ci</node>
| "Tie this project to a node" Jenkins option, a node to tie the job to. Can be a node name or node label.
|
|
| true |
<tasks> <ant> <antName>ant-1.8.3</antName> <!-- Default is 'build.xml' --> <buildFile>build.xml</buildFile> <targets>clean build</targets> <antOpts>-Xmx128m</antOpts> <properties> a = b c = d </properties> </ant> <batchFile> <command>dir</command> </batchFile> <gradle> <gradleName>1.0-rc-3</gradleName> <!-- Default is 'build' --> <tasks>build install</tasks> <!-- Default is '.' --> <rootBuildScriptDir>.</rootBuildScriptDir> <!-- Default is 'build.gradle' --> <buildFile>build.gradle</buildFile> <!-- Default is 'false' --> <useWrapper>true</useWrapper> </gradle> <groovy> <groovyName>groovy-1.8.6</groovyName> <command>println " .. "</command> </groovy> <groovy> <groovyName>groovy-1.8.6</groovyName> <file>script.groovy</file> <javaOpts>-Xmx128m</javaOpts> </groovy> <maven> <!-- Default is '(Default)' --> <mavenName>apache-maven-3</mavenName> <!-- Default is '-B -e clean install' --> <targets>clean install</targets> <!-- Default is 'pom.xml', not used if 'false' --> <pom>pom.xml</pom> <!-- Default is 'false' --> <usePrivateRepository>true</usePrivateRepository> <jvmOptions>-Xmx512m</jvmOptions> </maven> <shell> <command>pwd; ls -al; du -hs *</command> </shell> <xml> <!-- Raw XML content for unsupported tasks --> <content> <![CDATA[ ... ]]> </content> </xml> </tasks> | One or more <tasks> (for free-style jobs) or <prebuildersTasks> / <postbuildersTasks> (for Maven jobs) to perform:
| |
<appendTasks>
| true | false
| <appendTasks>true</appendTasks>
| Whether current job <tasks> / <prebuildersTasks> / <postbuildersTasks> should be appended to the tasks inherited from the <parent> job instead of replacing them. Default behavior is to replace parent tasks.
|
<runPostStepsIfResult>
| true | "all"
| <runPostStepsIfResult>success</runPostStepsIfResult>
| Controls execution of <postbuildersTasks> and <postbuilders> in Maven jobs. Possible values are:
|
|
| true |
<groovys> <groovy> <!-- Whether it's a pre- or post-step --> <!-- Default is 'false' --> <pre>true</pre> <command>println " .. "</command> <javaOpts>-Xms128m</javaOpts> </groovy> <groovy> <file>script.groovy</file> <groovyName>groovy-1.8.6</groovyName> </groovy> </groovys> | Groovy code snippet or external script to invoke as a pre- or post-step in Maven jobs, requires Groovy Plugin. For a single <groovy> invocation <groovys> can be omitted.
| |
<gitHubUrl>
| true |
<gitHubUrl> https://github.com/evgeny-goldin/maven-plugins </gitHubUrl> | GitHub project URL, requires Github Plugin. | |
<incrementalBuild>
| true | false
| <incrementalBuild>true</incrementalBuild>
| "Incremental build - only build changed modules" advanced Maven option.
|
<localRepoBase>
| true | <localRepoBase>/.m2/repository</localRepoBase>
| Base directory where local Maven repo is located. It can be useful to define one <localRepoBase> in the base job.
| |
<localRepo>
| true | <localRepo>ci</localRepo>
| Local Maven repo name, provides job an option to have its own local Maven repository:
| |
<privateRepository>
| true | false
| <privateRepository>true</privateRepository>
| "Use private Maven repository" Jenkins option equal to "Local to the workspace".
|
<privateRepositoryPerExecutor>
| true | false
|
<privateRepositoryPerExecutor> true </privateRepositoryPerExecutor> | "Use private Maven repository" Jenkins option equal to "Local to the executor".
|
<deploy>
| true |
<deploy> <url>http://maven-repo</url> <id>maven-repo-id</id> <!-- Default --> <uniqueVersion>false</uniqueVersion> <!-- Default --> <evenIfUnstable>false</evenIfUnstable> </deploy> | "Deploy artifacts to Maven repository" Jenkins option, as an alternative to "mvn deploy".
| |
<artifactory>
| true |
<artifactory> <name>http://host/artifactory</name> <user>deployer</user> <scrambledPassword> .. </scrambledPassword> <!-- Default --> <repository>libs-releases-local</repository> <!-- Default --> <snapshotsRepository> libs-snapshots-local </snapshotsRepository> <!-- Default --> <deployArtifacts>false</deployArtifacts> <!-- Default --> <skipBuildInfoDeploy>false</skipBuildInfoDeploy> <!-- Default --> <includeEnvVars>false</includeEnvVars> <!-- Default --> <evenIfUnstable>false</evenIfUnstable> <!-- Default --> <runChecks>false</runChecks> <violationRecipients>email1 email2</violationRecipients> </artifactory> <artifactory> <name>http://host/artifactory</name> <user>deployer</user> <scrambledPassword> .. </scrambledPassword> </artifactory> | Artifactory deployment configuration, requires Artifactory Plugin.
| |
<mail>
| true |
<mail> <recipients>user@mail user2@mail</recipients> <!-- Send e-mail for every unstable build --> <!-- Default: true --> <sendForUnstable>true</sendForUnstable> <!-- Send e-mails to individuals who broke the build --> <!-- Default: true --> <sendToIndividuals>true</sendToIndividuals> </mail> | "E-mail Notification" Jenkins option, whitespace-separated list of recipients.
It is possible to define | |
<triggers>
| true |
<triggers> <trigger> <type>scm</type> <description> Every 10 min, 08:00-21:00, Sun-Thu </description> <expression>*/10 08-21 * * 0-4</expression> </trigger> <trigger> <type>timer</type> <expression>00 23 * * *</expression> </trigger> <trigger> <type>github</type> </trigger> </triggers> | "Build Triggers" Jenkins option.
| |
<parameters>
| true |
<parameters> <parameter> <type>string</type> <name>stringParamName</name> <value>1</value> <description>String param description</description> </parameter> <parameter> <type>choice</type> <name>choiceParamName</name> <value>A, B, C</value> <description>Choice param description</description> </parameter> </parameters> | Job parameters, "This build is parameterized" Jenkins option.
| |
<invoke>
| true |
<invoke> <!-- Jobs to invoke --> <jobs>JobA, JobB, JobC</jobs> <!-- Always invoke? --> <!-- Default is 'false' --> <always>false</always> <!-- Invoke if build is stable? --> <!-- Default is 'true' --> <stable>true</stable> <!-- Invoke if build is unstable? --> <!-- Default is 'false' --> <unstable>false</unstable> <!-- Invoke if build has failed? --> <!-- Default is 'false' --> <failed>false</failed> <!-- Trigger build without parameters --> <!-- Default is 'false' --> <triggerWithoutParameters>false</triggerWithoutParameters> <!-- Current build parameters --> <!-- Default is 'false' --> <currentBuildParams>false</currentBuildParams> <!-- "Subversion revision" parameter --> <!-- Default is 'false' --> <subversionRevisionParam>false</subversionRevisionParam> <!-- Whether to pass-through Git Commit that was built --> <!-- Default is 'false' --> <gitCommitParam>false</gitCommitParam> <!-- Predefined parameters --> <params> paramName = paramValue </params> <!-- Parameters from properties file --> <propertiesFileParams> file.properties </propertiesFileParams> </invoke> | Other jobs to invoke when this one has finished, "Trigger parameterized build on other projects" Jenkins option.
| |
|
| true |
<scm> <![CDATA[ ... ]]> </scm> <publishers> <![CDATA[ ... ]]> </publishers> | Raw XML "extension points".
| |
<process>
| true |
<process> {{ def scm = node.scm[0] scm.appendNode( 'localBranch', 'dev' ) assert scm.remove( scm.clean[0] ) scm.appendNode( 'clean', 'true' ) }} </process> Or <process>job-update.groovy</process> | Groovy code snippet or external script allowing to "patch" the resulting XML config. The following variables are passed to the script: "config", "node", and "file". See the relevant issue for more details and examples.
|
Undoing inheritance
In certain scenarios you might want not to inherit <parent> properties. For example, a <parent> job may have Artifactory deploy defined while your job doesn't need this functionality. Currently, the only way to disable inherited property is to re-define it again with an empty value:
<artifactory> <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <!-- Disabling Artifactory deploy inherited from "base" job --> <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <name></name> </artifactory>
Or
<artifactory> <name><!-- No Artifactory --></name> </artifactory>
