In my previous post, I had demonstrated how to configure a Jenkins Server using Docker. The next step is to create a Jenkins job to build some software. Now, we could just do a simple freestyle job, or a basic Maven build – but that will require configuration of Jenkins every time we want to make a new project, and that makes managing the Jenkins Server via Docker more annoying. So, instead, I’m going to use the Cloudbees Bitbucket Branch Source Plugin and create a Bitbucket Team/Project job that will create the rest of my Jenkins jobs automagically for me. A similar plugin exists for GitHub, though I haven’t looked into it.
Steps
Add the Plugin
You’ll need to install the plugin first. This can be done via the “Manage Jenkins -> Manage Plugins” screen, like any other Jenkins plugin. Once you’ve done this, I would suggest updating the list of managed plugins in your Docker container, so that you won’t need to do this step again.
Create the Job
Once the plugin is installed, you can make the job via the “New Item” menu on the Jenkins dashboard. Enter a name for the job, and select “Bitbucket Team/Project” for the Job type. You’ll then be directed to the Job Configuration Page.
The official docs probably describe this page better than I can, but a quick rundown of the important options are:
Bitbucket Team/Project
- Owner – the name of the team in Bitbucket cloud. Jenkins will look in every repository that this team has access to.
- Scan Credentials – the credentials Jenkins will use to scan for repositories. This must be HTTP-compatible, so username & password. I’d suggest having a build-server user in the team, unless that would tip your team over to a new pricing tier, in which case I still recommend have a build-server user. You can, if needed specify a different set of credentials for checking the code out, under the ‘Advanced’ options
Project Recognizers
Determines how Jenkins will know to create a Job for a repository. The default (and, in fact, the only option available in my setup) is to look for a Pipeline Jenkinsfile. If you’ve got one of these at the top of your repository, then Jenkins will try and make a build for it. If you’ve got a branch with it in, Jenkins will make a build for that too.
Build Triggers
The most important part! The ‘right’ way to configure a build trigger is to use webhooks, or to have the build be triggered by changes in the repository. If you’ve got a publicly accessible Jenkins server, with a proper DNS and all, you can have this configured for you automatically. Otherwise, you’ll need to do this by hand. For my test purposes, I’ve got it set up to build “Periodically if not otherwise run”, with an interval of 1 day; the web hooks will come in when/if I deploy this build server to a production environment.
This also becomes the default build trigger for the generated jobs.
Orphaned Item Strategy
When you delete branches (or repositories), Jenkins will clean up the jobs. You can allow Jenkins to keep jobs around for a while, if you want.
Automatic branch project triggering
How will Jenkins know what branches to build? You will tell it, of course. We use a git-flow
variant for our branches, so I want to build the master
branch, and any branch starting with story/
, so I use the regex (master|story\/.*)
And that’s it. Save & Apply, and if you’ve done everything correctly, you will see a “Folder Computation” job running that’s finding all of your Jenkinsfiles. But you probably don’t have any yet, so let’s go make you one.
Add a Maven build tool
My Jenkinsfile
is going to end up building a basic Maven project. So before I do that, I need to make sure Maven is available in my build server. Fortunately, Jenkins has an easy way to do that – Tools.
From the Jenkins Dashboard, select “Manage Jenkins”, and then “Global Tool Configuration”. From this page, you can then create a Maven tool. Personally, I give my installations version-specific names, so I’ve made a tool called ‘maven-3.3.9’ to install, surprisingly, Maven 3.3.9. You need to get the name right in the Jenkinsfile later, so you may prefer to leave the version out; YMMV.
Create your Jenkinsfile
#!groovy | |
node { | |
// Need to replace the '%2F' used by Jenkins to deal with / in the path (e.g. story/...) | |
// because tests that do getResource will escape the % again, and the test files can't be found. | |
// See https://issues.jenkins-ci.org/browse/JENKINS-34564 for more. | |
ws("workspace/${env.JOB_NAME}/${env.BRANCH_NAME}".replace('%2F', '_')) { | |
// Mark the code checkout 'stage'.... | |
stage 'Checkout' | |
checkout scm | |
// Mark the code build 'stage'.... | |
stage 'Build' | |
def mvnHome = tool 'maven-3.3.9' | |
sh "${mvnHome}/bin/mvn clean verify -B" | |
junit testResults: '**/surefire-reports/*.xml' | |
} | |
} |
This is a pretty basic build – it checkouts the code, builds it, and then archives the test results.
One key part to note is the creation of a custom workspace, on line 6. The workspace is simply where Jenkins will check the code out to. You could use the default – but if your branch has a slash in it (e.g. story/MyStory), then the slash will get replaced with %2F, which can break a lot of stuff downstream. This is a known problem, and this is the simplest workaround. I was lucky that I was doing my experiment on a story branch instead of master, or I probably wouldn’t have found out about this problem for a while.
Once you commit and push this file, you’ll probably need to run the Folder Computation task for your Jenkins job again (or just wait until it’s run periodically again). Again, if all is going well, it should find your newly added Jenkinsfile and create a sub-job to build it.
UPDATED: I have also built and tested a version that uses the S3 Plugin to copy the build artefacts to S3 for later deployment. Sadly, I’m still lacking a lead on a good tool to manage the deployment (and subsequent promotions through deployment regions) itself – it’s possible I’ll need to build one.
Wrap-up
This covers making a basic Jenkinsfile to do a very basic job – simply running a Maven build and packaging the test results. This would be an opportune time to make a backup of your Jenkins data volume container.
For the next article in this series, I’ll look at what’s involved in creating a real pipeline, where I can promote build artefacts to test environments and release candidates.
After that, I want to explore building a dependency tree – ProjectA -> ProjectB -> ProjectC – and to look at how to do this with branch builds – where BranchA can see builds from BranchA and master, but not from BranchB.