Thursday, April 27, 2017

Death by Jenkins - Really difficult bits to find out about Declarative Pipeline DSL (Part 1)

I haven't written in a long while, but I've been working with Jenkins for the past 4 weeks (yes, I've been working for over 2 years now! no, I am not a build engineer), and I found it so excruciatingly painful to find answers about Jenkins Pipeline syntax on the Internet, that I thought I needed to update my blog and save others from a similar fate x)

Some context:

I've been working on converting our myriad of Jenkins jobs into the new Jenkins Pipeline job.
Jenkins Pipeline, if you don't already know what it is, is a new way of setting up CI. Every time you push code, it goes through different stages (Build, Unit Test, Integration Test, etc) so that by the end of the pipeline, if it all passes, you should be super confident about the code you committed, that it can be released automatically.


Commit => Build => Test => Deploy



It had been on my mind for a while that our Jenkins jobs were getting out of hand and we needed to migrate to using the DSL. Once you have two sets of 10 jobs, it starts to become unmanageable...

But wasn't sure if I should use a Pipeline or standard DSL linked to a job. In the end, I decided to go for the Pipeline because Jenkinsfile scanning using github enterprise and workspace management came with existing Pipeline plugins and it would tidy up all the jobs we had into one job per branch. I still don't know if this was the correct decision because I find that having only one job makes it more difficult to look through workspaces because the pipeline UI is a bit clunky.
Anyway, I'm rambling, let's get to the code.

The most annoying thing I could not find on the web was to re-assign/reset a global variable set in the environment block.


Here is a simple boolean environment variable:


Now I want to change this value when the Step succeeds within a try-catch block:


This doesn't even error but if I do an echo isSuccess before and after, I get false both times.

So after hours of Googling, I finally found out you need to override the environment variable. 
But how? 
The documentation merely says the below, and I couldn't find any examples anywhere!

So I after a few trial and error, I finally got it. The correct syntax is:
But this didn't work either. Now I was getting a type mismatch. Because when you defined isSuccess = false in the environment, it was kindly casting it to a string "false"!

Soooooo:


Finally, it was setting the correct value and now in my next stage, I could check if(isSuccess=="true")

Maybe you can properly define a boolean variable using: def  isSuccess = true

but I didn't have the patience to try this out so let me know if you try and it works!

After all of this, turns out I didn't want a try catch and so I didn't need to set a global variable but hey at least I know something now and I've shared it here so I hope this is helpful to someone out there, so my efforts weren't for nothing! 

Part 2 coming up with my finding about:
- loaded groovy script method cannot have the same name
- @NonCPS doesn't let you load scripts - problem with using .each