2

Background

In my project pull request on bitbucket are verified by Jenkins builds. Building and testing takes about 50 minutes. This works quite nicely.

Problem

There are some changes which do not have impact on working code (front-end related). So if pull request touches only one of two sub-directories there is no point to do build and running tests. The aim is to save time (less time to release minor not harmful changes) and resources (do not occupy build machine for useless jobs).

I do not want to split project (one of possible solutions), since quite often changes in front-end require changes in actual back-end code, so in such case testing is required.

Possible solution

I found the way to stop Jenkins build with a success on first step which fetches new code.

Problem is how to ask git if branch (change) touches only two sub-directories. This probably will require something like this:

git diff master...featureBranch  <some other options> 

Possible alternatives

Or maybe there are other ways to tackle this issue? Using some features of bitbucket or Jenkins?

AElMehdi
  • 572
  • 4
  • 12
Marek R
  • 32,568
  • 6
  • 55
  • 140
  • So what are the rules where you don't want to build exactly? – Liam Oct 04 '19 at 09:28
  • If `diff` shows that touched paths are only under `FrontendA` and `FrontendB`. If change touches anything else verification is required. Basically I do not what to waist recurses if I know that vitrifaction is not needed. – Marek R Oct 04 '19 at 09:32
  • You can get the list of commits in a [branch here](https://stackoverflow.com/questions/53569/how-to-get-the-changes-on-a-branch-in-git). You could then conivably parse the response to run a regex (or something)over the file names to see where they lived in the file structure – Liam Oct 04 '19 at 09:38
  • @Liam I do not care about list of commits. The touched `path` is only important. – Marek R Oct 04 '19 at 09:47
  • 1
    Well...ok....I was only trying to suggest a possible course of action. I think I'll leave you figure this out on you own then – Liam Oct 04 '19 at 09:49

2 Answers2

2

Probably the easiest way to achieve what you want is with git log or git diff, as both can take rev range and path:

git log [<options>] [<revision range>] [[--] <path>…​]
git diff [<options>] <commit> <commit> [--] [<path>…​]

For example, to test if the latest commit touches directory1 and/or directory2, you can use:

git log --oneline HEAD^..HEAD directory1 directory2

For negative match, exclude pathspec should do the trick:

git log --oneline HEAD^..HEAD -- '.' ':(exclude)./directory1'

Or similarly with diff:

git diff HEAD^..HEAD '.' ':(exclude)directory'
sbat
  • 1,453
  • 10
  • 21
  • Interesting concept, I will do some experiments. Note I need negative so if there is some changes outside specific paths. Probably I can list all other paths (not very handy). – Marek R Oct 04 '19 at 09:54
  • @MarekR Ah, missed that in your original question! (exclude) pathspec should do the trick then. Updated my answer. – sbat Oct 04 '19 at 09:56
  • 1
    Very nice! It should do the job. Only have to find to count lines on Windows since exit code is always zero. – Marek R Oct 04 '19 at 09:58
  • Hmm, you know what? git diff also takes pathspec. :) Can you test if "git diff HEAD^..HEAD -- directory" does what you need? I haven't tested it fully. Then I can update my answer with that option as well. :) – sbat Oct 04 '19 at 10:06
  • `':(exclude)directory'` is exactly what I need. I approved it sine I'm sure it will work. I have to just polish details. After that I will post own answer. – Marek R Oct 04 '19 at 10:23
  • where can I find documentation about that `':(exclude)directory'`? google give lots of noise and I've failed to find manually it in official documentation? – Marek R Oct 04 '19 at 10:32
  • 1
    https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-aiddefpathspecapathspec - but it is lacking any good examples. I find unofficial guides more useful https://medium.com/@lilylakshi/the-path-to-git-pathspec-47141b333c58 – sbat Oct 04 '19 at 10:36
1

To solve it git feature :(exclude)directory' (thanks @sbat). Details of this feature is described here.

This is how it can be done in details (Jenkins pipeline for windows platform):

// inside some step:
node('master') {
    def diffStat = "undetermined"
    try {
        diffStat = bat (
            returnStdout: true, 
            script: """@ECHO OFF
                cd $repoDirecory
                git diff ${PULL_REQUEST_TO_BRANCH} --shortstat --  "." ":(exclude)./FrontendA" ":(exclude)./FrontendB"
                """).trim()

        if (!diffStat) {
            currentBuild.description = "Frontend only"
            error("There is no significant changes, build is not required!")
        }
    } finally {
        if (diffStat) {
            echo diffStat
        } else {
            currentBuild.result = 'SUCCESS'
        }
        notifyBitbucket(commitSha1: PULL_REQUEST_FROM_HASH, ignoreUnverifiedSSLPeer: true)
    }
}

Since there is no exit code from: git diff --shortstat <....>, butgit prints nothing, if there is no visible changes. So by using bat returnStdout: true in groovy, output of git is assign to variable. Then in groovy script proper action can be taken depending if variable diffStat is empty or not.

Now if only unimportant changes has been found (diffStat is empty), error is reported, which later is treated as a success. Bitbucket see this build as a success (this was the aim). On Jenkins all build steps are failed (red), but this is not problem for me.

If significant changes were found, Jenkins prints difference statistics (real example):

6 files changed, 62 insertions(+), 48 deletions(-)

On Windows there is a trap: ' (single quote character) can't be used, but as you can see above " (double quote) do the job.

Marek R
  • 32,568
  • 6
  • 55
  • 140