2

I need to create a build pipeline which consists of multiple projects that depend on each other. Here is a simplified illustration:

SVN A --> build A --\
                    |
SVN B --> build B --|
                    |
SVN C ----------------> build C

The pipeline should work so that when a change is committed to the SVN repository of any of the projects, then that project is build automatically. Additionally, after either A or B has been built, it triggers the building of C.

Each build produces binaries with a unique version number ("X.Y.BuildNumber") and C must get as a parameter the version numbers of both A and B, so that C can be built using those versions. C should default to using the latest successful builds of A and B, but it should also be possible to trigger C manually using an older version of A or B (e.g. if we want to deploy an older version of one of the projects).

Creating a pipeline like this can be done out-of-the-box on Go, but my company considers it too expensive. (Update 2014-02-27: Go is not open source and free!) So now I'm trying to find out how to achieve the same thing using Jenkins, but have not yet found a way. I've only found instructions for creating simple linear and diamond shaped pipelines in Jenkins, but not pipelines with multiple independent upstream projects.

Esko Luontola
  • 73,184
  • 17
  • 117
  • 128
  • 1
    ThoughtWorks just announced that they would be making Go free & open-source. http://www.thoughtworks.com/news/go-continuous-delivery-now-available-as-free-open-source. So may be you can give it a try again. – Srinivas Feb 25 '14 at 15:45
  • Yup. I heard about that too. :) – Esko Luontola Feb 27 '14 at 12:05

2 Answers2

1

It's possible to pass the version numbers from upstream jobs to downstream jobs by using the Copy Artifact Plugin. Write the version number to a file in the upstream job, archive it, and then use that plugin to read it in a downstream job. Select the Upstream build that triggered this project and Use “Last successful build” as fallback options in the plugin configuration.

For more details, see Interdependent Build Pipelines with Jenkins.

Esko Luontola
  • 73,184
  • 17
  • 117
  • 128
0

We use the build-pipeline-plugin for something similar and what we do is we provide a groovy script that stores runtime build information to be passed on to downstream projects:

A bit verbose, because we include SVN info for downstream builds:

import hudson.model.*
def thr = Thread.currentThread()
def build = thr?.executable

def workspace = build.getWorkspace()

def ant = new AntBuilder() 
ant.exec(executable: "svn", outputproperty: "output", dir: workspace){ 
    arg(line: "info") 
}
svnInfo = ant.project.getProperty("output")
print svnInfo 

def pattern = /Last\s+Changed\s+Author:\s+(\w+)/ 
def matcher = (svnInfo =~ pattern)
def user = matcher[0][1]

def langs = new XmlParser().parseText(build.getParent().getWorkspace().child('pom.xml').readToString())
def appVer = langs.properties.release.text()
def artifactId = langs.artifactId.text()

def params = [
new StringParameterValue('PL_SVN_REVISION', build.getEnvVars()['SVN_REVISION']),
new StringParameterValue('PL_BUILD_NUMBER', build.getEnvVars()['BUILD_NUMBER']),
new StringParameterValue('PL_APP_NAME', 'FooApp'),
new StringParameterValue('PL_COMMITTER_NAME',user ),
new StringParameterValue('PL_APP_VERSION',appVer),
new StringParameterValue('PL_ARTIFACT_ID',artifactId) 
]
build.addAction(new ParametersAction(params))

Then in the downstream build they should be available like so:

Example 1, Set Build Name input:

#${BUILD_NUMBER} - ${ENV,var="PL_APP_NAME"} - ${ENV,var="PL_APP_VERSION"} - ${ENV,var="PL_SVN_REVISION"}

Example 2, Invoke Ant target input:

deploy
  -Denvironment=ONT-base
  -DWAR-LOCATION=%war-repo%/%PL_APP_NAME%/%PL_BUILD_NUMBER%-%PL_SVN_REVISION%/
  -DWAR-NAME=%PL_ARTIFACT_ID%-%PL_APP_VERSION%.%PL_BUILD_NUMBER%-%PL_SVN_REVISION%.war

Beware however, when reusing a downstream project in multiple upstream projects, as there is an outstanding bug with variables not being passed down correctly.

Benny Bottema
  • 11,111
  • 10
  • 71
  • 96
  • This looks useful for an issue I'm having, but it's not really clear what exactly you're doing or why. Could you clarify your explanation a bit (maybe add some comments to the code)? – Jared Jun 12 '14 at 14:28