Last Changes

The simplest way to know what has changed on your Jenkins builds!

Build Status (Travis CI) last changes

Last Changes is a Jenkin plugin that shows rich VCS diffs between builds.

Only Git and Svn based projects are supported.

1. Introduction

The plugin uses diff2html to show last changes of a given build, example:

last changes03

Or using side-by-side configuration:

last changes05
ℹ️
Last changes means compare current repository revision with an old revision. By default the plugin will diff current and previous revision.

2. Objectives

The main objective of this plugin is to have fast access to what has changed on a Jenkins build.

Another interesting aspect is that it can easily help to find the root cause of a failing build by highlighting what has changed.

And finally the plugin shines in a continuous delivery environment, where each commit generates a release candidate.

3. How it works?

  1. This plugin expects .git or .svn folders present on your build workspace and will use it to retrieve repository information .

  2. While your job runs the plugin reads your build workspace to retrieve the current VCS revision;

  3. The diff between actual and a previous revision will be stored; Note that the previous revision can be:

    • A provided revision id;

    • Revision of Last successful build;

    • Revision of an specific build;

    • Revision of Last tag;

      ℹ️
      By default previous revision is current revision -1.
      💡
      You can use parameters in specificRevision parameter. In case of git, expressions like HEAD^{tree} or HEAD^^ can be used.
  4. The diff for each build can be viewed later in html format.

To get most from this plugin use periodically SCM polling to trigger your builds, more details here.

4. Usage

After installation just activate the post build action named Publish Last Changes.

  1. Activate build action

    last changes activation

  2. Last changes menu should be available

    last changes01

  3. Build changes history

    last changes02

  4. Last changes menu is available for builds that published changes

    last changes04

💡

Since version 2.3 the commits between revisions are listed as below:

commits

You can also see what has changed on a specific commit by clicking on it:

commit changes

5. Configuration

The setup is done via build configuration:

last changes config

The possible values for Since attribute is Previous revision (the default), Last successful build and Last tag.

If SpecificRevision parameter is provided then Since configuration will be ignored and the diff will be done with provided revision id.

Advanced configuration reflects diff2html options:

last changes config2

6. Jenkins pipeline step

Following is an example of pipeline step using this plugin:

node {
      stage ('Build') {
           svn 'https://subversion.assembla.com/svn/cucumber-json-files/trunk/'
           step([$class: 'LastChangesPublisher', since:'PREVIOUS_REVISION',specificRevision: '', format: 'LINE', matchWordsThreshold: '0.25', matching: 'NONE', matchingMaxComparisons: '1000', showFiles: true, synchronisedScroll: true])

      }

}

6.1. Pipeline DSL

Since version 1.0.10 it is possible to use the lastChanges() shortcut in pipeline DSL:

node {
     git 'https://github.com/jenkinsci/last-changes-plugin.git'
     lastChanges() //will use defaults
}

Parameters should be declared as key: 'value' as example below:

node {
     git 'https://github.com/jenkinsci/last-changes-plugin.git'
     lastChanges format:'SIDE',matching: 'WORD', specificRevision: 'c546ec31e854de3f27755273d3e1db6185aee4b4'
}
pipeline {
    agent any
    stages {
        stage('Checkout') {
            steps {
                git 'https://github.com/jenkinsci/last-changes-plugin.git'
                lastChanges since: 'LAST_SUCCESSFUL_BUILD', format:'SIDE',matching: 'LINE'
            }
        }
    }
}

Or using build params for specificRevision:

pipeline {
    agent any
    stages {
        stage('Checkout') {
            steps {
                git 'https://github.com/jenkinsci/last-changes-plugin.git'
                lastChanges format:'SIDE',matching: 'WORD', specificRevision: "${REV}"
            }
        }
    }
}
💡
Refer to parameterized builds to use parameters.

6.2. Pipeline scripting

Since v2.5 is possible to invoke LastChanges inside groovy script, instead of just declaring it as we saw above. See example below:

node {
      stage("checkout") {
        git url: 'https://github.com/jenkinsci/last-changes-plugin.git'
      }

      stage("last-changes") {
        def publisher = LastChanges.getLastChangesPublisher "PREVIOUS_REVISION", "SIDE", "LINE", true, true, "", "", "", "", ""
              publisher.publishLastChanges()
              def changes = publisher.getLastChanges()
              println(changes.getEscapedDiff())
              for (commit in changes.getCommits()) {
                  println(commit)
                  def commitInfo = commit.getCommitInfo()
                  println(commitInfo)
                  println(commitInfo.getCommitMessage())
                  println(commit.getChanges())
              }
      }

}
ℹ️
See model classes to know what can be accessed in pipeline script. Note that only attributes annotated with @Whitelisted are visible to be accessed in pipeline script.
💡
If you use declarative pipeline you can use script section.

7. Download the diff

You can also download the diff as DIFF or HTML. The download links are on the bottom right corner of the page:

diff download

8. Sending the diff as email

Using email ext plugin and Pipeline scripting we can send the diff as an email attachment, see example below:

  1. Diff in plain text

    pipeline {
        agent any
        stages {
            stage('Checkout') {
                steps {
                    git url: 'https://github.com/jenkinsci/last-changes-plugin'
                }
            }
            stage("send diff") {
                steps {
                    script {
                        def publisher = LastChanges.getLastChangesPublisher null, "SIDE", "LINE", true, true, "", "", "", "", ""
                        publisher.publishLastChanges()
                        def diff = publisher.getDiff()
                        writeFile file: 'build.diff', text: diff
                        emailext (
                          subject: "Jenkins - changes of ${env.JOB_NAME} #${env.BUILD_NUMBER}",
                          attachmentsPattern: '**/*.diff',
                          mimeType: 'text/html',
                          body: """<p>See attached diff of <b>${env.JOB_NAME} #${env.BUILD_NUMBER}</b>.</p>
                            <p>Check build changes on Jenkins <b><a href="${env.BUILD_URL}/last-changes">here</a></b>.</p>""",
                          to: "YOUR-EMAIL@gmail.com"
                        )
    
                   }
    
                }
            }
        }
    }
  2. Diff in Html format

    pipeline {
        agent any
        stages {
            stage('Send html diff') {
                steps {
                    git 'https://github.com/jenkinsci/last-changes-plugin.git'
                    script {
                      def publisher = LastChanges.getLastChangesPublisher "PREVIOUS_REVISION", "SIDE", "LINE", true, true, "", "", "", "", ""
                      publisher.publishLastChanges()
                      def htmlDiff = publisher.getHtmlDiff()
                      writeFile file: 'build-diff.html', text: htmlDiff
                        emailext (
                          subject: "Jenkins - changes of ${env.JOB_NAME} #${env.BUILD_NUMBER}",
                          attachmentsPattern: '**/*build-diff.html',
                          mimeType: 'text/html',
                          body: """<p>See attached diff of build <b>${env.JOB_NAME} #${env.BUILD_NUMBER}</b>.</p>
                            <p>Check build changes on Jenkins <b><a href="${env.BUILD_URL}/last-changes">here</a></b>.</p>""",
                          to: "YOUR-EMAIL@gmail.com" )
                    } //end script
                }
            }
        }
    }

9. Docker

An easy way to test this plugin is using a docker container, here are the steps (assuming you have docker installed):

  1. Run the image:

    docker run -it -p 8080:8080 rmpestano/jenkins-last-changes
  2. Access localhost:8080/ and create a job

  3. Configure this svn repository: https://subversion.assembla.com/svn/cucumber-json-files/trunk/

  4. Add the Publish last changes post build action;

  5. Just run the job

Job output should look like:

last changes docker

10. Running it locally

Following are the steps to run, debug and test this plugin on your machine:

  1. Clone this repository

    git clone http://github.com/jenkinsci/last-changes-plugin
  2. Import it on your IDE

  3. Run the command mvnDebug hpi:run -DskipTests

  4. Configure the remote debugging on your IDE to use port 8000, as in image below:

    last changes debug

  5. Access http://localhost:8080/jenkins

Now create jobs using last-changes and debug them.

For testing run any class on src/test/java folder as JUnit test.

ℹ️
Tests with IT suffix will start a Jenkins instance before the test.
💡

To generate the binary of the plugin run:

mvn clean package -DskipTests

It will generate last-changes.hpi in target folder. You can install it on jenkins via upload in jenkins/pluginManager.

11. Contributing

12. Change Log

Please follow releases page for details of each release.