Jenkins Workflow in 5 Minutes

Jenkins Workflow in 5 Minutes

This is a 5min guide about how to build a project from Git repo and deploy it to a server with Jenkins workflow.

To help you through, I will provide all the commands/VMs you need to run.

What You Need

Project Structure

As you see, the pipeline is a relatively complex one, with branching (7) and human intervention (9).

Steps

Go to where you checked out the code. Read the README.md files to see what you need to change. Then start the VMs by running

$ cd jenkins-vm
$ vagrant up
$ cd tomcat-vm
$ vagrant up

Once the VMs are up, open a browser and go to 192.168.2.4:8080. You should see a job workflow-demo-01. Click on it and click “configure”.

First change the “tomcat_username” and “tomcat_password” to the value you’ve configured for tomcat-vm.

Then modify the workflow script. The comments point out where the line corresponds to in the diagram.

node {
  def mvnHome = tool 'Maven'
  def devHost = '192.168.2.3'
  def prodHost = '192.168.2.3'

  dir('dev') {
    stage 'Dev build'
    # 1
    git url: 'https://github.com/ryan-ju/resteasy-demo-01.git'
    // Print version
    def v = version()
    if (v) {
      echo "Building version ${v}"
    }

    # 2
    sh "${mvnHome}/bin/mvn clean install"

    stage 'Dev deploy'
    # 3
    deploy("resteasy-demo-01-server/target/resteasy-demo-01-*.war", devHost, "/dev")
  }

  dir('dev-test') {
    stage 'Dev QA'
    # 4
    git url: 'https://github.com/ryan-ju/resteasy-demo-01-test.git'
    # 5
    sh "${mvnHome}/bin/mvn -Dhost=http://${devHost} -Dport=8080 -Dcontext=/dev/api clean install"
  }

  dir('dev') {
      stage 'Upload artifact'
      // Print version
      def v = version()
      if (v) {
        echo "Uploading version ${v}"
      }

      # 6
      sh "${mvnHome}/bin/mvn -Dmaven.test.skip=true -P nexus deploy"
  }

  # 7
  if (release.toString().toBoolean()) {
      dir('dev') {
         stage 'Release build'
         sh "git checkout master"
         sh "git pull origin master"

         def rv = releaseVersion()

         # 8
         sh "${mvnHome}/bin/mvn -P nexus -Darguments=\"-DskipTests\" release:prepare release:perform"

         if (rv) {
             // Ask for manual permission to continue
             # 9
             input "Ready to update prod?"
             # 10
             sh "curl -L -o resteasy-server.war https://oss.sonatype.org/service/local/repositories/releases/content/org/itechet/resteasy-demo-01-server/${rv}/resteasy-demo-01-server-${rv}.war"
             # 11
             deploy("resteasy-server.war", prodHost, "/resteasy")
         } else {
             error "Failed to get release version from pom.xml"
         }
      }
  }
}

// Get version from pom.xml
def version() {
    def matcher = readFile('pom.xml') =~ '<version>(.+)</version>'
    matcher ? matcher[0][1] : null
}

// Get release version from snapshot pom.xml
def releaseVersion() {
    def matcher = readFile('pom.xml') =~ '<version>(.+)-SNAPSHOT</version>'
    matcher ? matcher[0][1] : null
}

// Deploy file to tomcat
def deploy(file, host, context) {
    sh "curl -T ${file} -u \"${tomcat_username}:${tomcat_password}\" http://${host}:8080/manager/text/deploy?path=${context}&update=true"
}

Explanations

Jenkins workflow script is a DSL. The most important ones are:

node keyword specifies a chunk of task that should be scheduled on a node. It comes with a workspace (you can’t specify it).

dir keyword allows you to create a work dir under the node’s workspace.

stage is used to control the concurrency of a section of code. For example, you only want one build to deploy to Tomcat at a time, so should set this value to 1.

input asks for user intervention.

parallel allows multiple actions to run in parallel.

sh executes commands.

Output

At the moment, this is all the visualization you get:

Pretty ugly right? You’ll have to wait till the Cloudbees’ visualization plugin is open sourced, which will be early 2016.

Conclusion

Jenkins workflow is pretty painful to set up (totally my option, you’re welcome to disagree). The official tutorial doesn’t tell enough, neither does the Cloudbees doc. I personally found stackoverflow more informative.

To make matters worse, there are certain important features that are only available in Cloudbees enterprise, like workflow visualization and checkpoint (also, I still haven’t figured out how to wipe out the workspace, other than logging in and rm the whole dir. Indeed, such important functionality isn’t implemented yet!).

IMO, Jenkins workflow does work, but if you to make your life easier and have some fortune to spare, probably Cloudbees is a better choice to run Jenkins.

Next time I’ll have a look at GoCD, the new CD tool that’s getting lots of attention and is supposed to be much better.

Please leave a comment if you like this post or want anything improved.

References

Jenkins installation: https://wiki.jenkins-ci.org/display/JENKINS/Installing+Jenkins+on+Ubuntu
Git integration: http://jakubstas.com/github-and-jenkins-integration/
Github plugin installation: https://www.cloudbees.com/blog/better-integration-between-jenkins-and-github-github-jenkins-plugin
Java keytool: https://docs.oracle.com/cd/E19159-01/819-3671/ablra/index.html
Tomcat 8 connector config: https://tomcat.apache.org/tomcat-8.0-doc/ssl-howto.html#Configuration
Jenkins workflow plugin tutorial: https://github.com/jenkinsci/workflow-plugin/blob/master/TUTORIAL.md
Jenkins workflow guide by Cloudbees: https://documentation.cloudbees.com/docs/cookbook/_continuous_delivery_with_jenkins_workflow.html

Written with StackEdit.

Maven Release in 5 Minutes

Maven Release in 5 Minutes

This is a very short summary of how Maven release works and how to configure it.

Prerequisite

You should know what Maven lifecycle, phase, goal and plugin is.

Release Life Cycle

maven-release-plugin does not bind to any phase. This means your project won’t be released when you run a phase. Instead, you have to explicitly run the goals of the plugin.

The two most important goals are:

  • release:prepare - create a release tag in the scm, create a release.properties file and backup files, and update the project version. Full description
  • release:perform - checkout the release tag and upload to a repository. Full description

Note
release:prepare is idempotent, so multiple runs doesn’t change anything. To re-prepare, add command line option -Dresume=false, which will delete release.properties and backup files.
Alternatively, you can run mvn release:clean release:prepare.

Perform Release

What is performed during release can be configured with the goals configuration.

E.g., if you want to upload artifacts to Sonatype, you can add nexus-staging-maven-plugin, which will perform the upload in deploy phase and release (to Maven central) with nexus-staging:release, like this:

<plugin>
  <groupId>org.sonatype.plugins</groupId>
  <artifactId>nexus-staging-maven-plugin</artifactId>
  <version>1.6.6</version>
  <!-- This plugin is an extension to the deploy phase, adding a new deployment type -->
  <extensions>true</extensions>
  <configuration>
    <!-- The server ID configured in settings.xml  -->
    <serverId>ossrh-server</serverId>
    <nexusUrl>https://oss.sonatype.org/</nexusUrl>
    <!-- Not important for snapshots -->
    <autoReleaseAfterClose>false</autoReleaseAfterClose>
  </configuration>
</plugin>
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-release-plugin</artifactId>
  <version>2.5.3</version>
  <configuration>
    <autoVersionSubmodules>true</autoVersionSubmodules>
    <useReleaseProfile>false</useReleaseProfile>
    <releaseProfiles>release</releaseProfiles>
    <!-- This will release the artifacts after staging them -->
    <goals>deploy nexus-staging:release</goals>
  </configuration>
</plugin>

Configure SCM Provider

Maven already supports many scm systems. The only thing you need to do is to make sure the <scm> tag is configured correctly. The release plugin uses it to pull and push changes.

Here’s an example for git:

<scm>
  <connection>scm:git:git@github.com:ryan-ju/resteasy-demo-01.git</connection>
  <developerConnection>scm:git:git@github.com:ryan-ju/resteasy-demo-01.git</developerConnection>
  <url>git@github.com:ryan-ju/resteasy-demo-01.git</url>
  <tag>HEAD</tag>
</scm>
Tag Meaning
<connection> read-only
<developerConnection> read-write
<url> publicly visible
<tag> the tag to checkout to make the release

Rollback Release

release:rollback allows you to rollback a release, but only if you haven’t run release:clean. More details

Generate Release POM

release:prepare-with-pom generates a release-pom.xml, which contains all resolved dependencies, so all dependencies (including transitive) are explicitly defined.

Dry Run

All goals can be dry run with -DdryRun=true. This will still generate the properties and backup files, but won’t change any code or commit anything.

References

maven-release-plugin doc: http://maven.apache.org/maven-release/maven-release-plugin/index.html
Maven scm overview: https://maven.apache.org/scm/scms-overview.html
Maven scm providers: https://maven.apache.org/scm/maven-scm-providers
Maven <scm><tag>: http://stackoverflow.com/a/23719418/842860
Maven <scm> tag: http://stackoverflow.com/a/9518682/842860

Written with StackEdit.