Jenkins continuous delivery pipeline skip stage based on input - jenkins

A simplified pipeline will look something like:
1. build
2. unit test
3. deploy to dev
4. integration tests
5. deploy to prod
For step #5 I've setup a Jenkins pipeline input command. We won't be deploying to prod on every commit so if we abort all those jobs it will have a big list of grey builds. Is it possible to have a skip option so the build can still be shown as green blue?

There is a better solution I just found. You can access the result of the input like by using the return value. The user has to check the checkbox, to run the optional stage. Otherwise the steps of the stage are skipped. If you skipp the whole stage, the stage will disappear and that "cleans" the stage view history.
stage('do optional stuff?') {
userInput = input(
id: 'userInput', message: "Some important question?", parameters: [
booleanParam(defaultValue: false, description: 'really?', name: 'myValue')
])
}
stage('optional: do magic') {
if (userInput) {
echo "do magic"
} else {
// do what ever you want when skipping this build
currentBuild.result = "UNSTABLE"
}
}

How about:
stage('Deploy') {
when { branch 'master' }
steps {
sh '...'
}
}
}
the stage will be skipped for commits on other branches and will be green.

Can't you do something like this, it will be blue/green whatever you choose from input, and you can then run the deployment depending on it too?
def deployToProduction = true
try{
input 'Deploy to Production'
}catch(e){
deployToProduction = false
}
if(deployToProduction){
println "Deploying to production"
}

Instead of using pipeline as a code Jenkins2 feature, you can setup Jobs with downstream/upstream configuration.
Build -> Unit test -> Deploy to Dev -> Integration tests -> Promote to Prod -> Deploy to Prod
At present it gives more control to choose which version of pipeline you wish to Prod.
For greater visibility you can configure Delivery Pipeline using Delivery-Pipeline-Plugin.

Related

Jenkins: Schedule Particular Stage with single pipeline

I have a single pipeline where it' declarative and I've several stages such as below triggers via webhook.
I would like to execute and scheduled Stage B at a certain time which can also run without trigger via webhook. Clearly it needs to run when triggers via webhook and also run when it will be schedule. Can I handle this without creating seperate job or pipeline in Jenkins ?
stage('A'){
when{
beforeAgent true
expression{return env.GIT_BRANCH == "origin/development"}
}
steps{
script{
//Do something
}
stage ('B'){
when {
beforeAgent true
expression{return env.GIT_BRANCH == "origin/development"}
steps {
script {
//Run Tests
}
}
}
stage('C'){
when{
beforeAgent true
expression{return env.GIT_BRANCH == "origin/development"}
}
steps{
script{
//Do something
}
You can discover what caused your pipeline to run. This may be cron trigger, manual trigger, code commit trigger, webhook trigger, comment on GitHub, upstream job, etc. (depending on plugins installed, the list may be long.)
Here's and example of code to understand what the trigger was. This example sets the environment variable TRIGGERED_BY.
def checkForTrigger() {
def timerCause = currentBuild.rawBuild.getCause(hudson.triggers.TimerTrigger.TimerTriggerCause)
if (timerCause) {
echo "Build reason: Build was started by timer"
env.TRIGGERED_BY = 'timer'
return
}
def userCause = currentBuild.rawBuild.getCause(hudson.model.Cause$UserIdCause)
if (userCause) {
echo "Build reason: Build was started by user"
env.TRIGGERED_BY = 'user'
return
}
def remoteCause = currentBuild.rawBuild.getCause(hudson.model.Cause$RemoteCause)
if (remoteCause) {
echo "Build reason: Build was started by remote script"
env.TRIGGERED_BY = 'webhook'
return
}
// etc.
println "We haven't caught any of triggers, might be a new one, here is the dump"
def causes = currentBuild.rawBuild.getCauses()
println causes.dump()
}
I think that a build might have more than one trigger, if so the order of your clauses is important.
Once you have this figured out, you can run your stages only when the trigger fits your definition.
stage ('B'){
when {
beforeAgent true
anyOf {
expression{return env.GIT_BRANCH == "origin/development"}
environment name: 'TRIGGERED_BY', value: 'timer'
environment name: 'TRIGGERED_BY', value: 'webhook'
}
Not in a clean or first-class manner, but yes you can do it effectively.
For any job which has been run at least once, you can click "replay" for the previous run.
You will then be presented with the Jenkinsfile in a text edit box. At this point you can perform any edit you want to the Jenkinsfile (including pasting in a completely unrelated Jenkinsfile if you wanted) and Jenkins will execute the modified version. For your specific case, you can delete all the stages you don't want to re-run and just leave behind the one (or two, etc) you want.

Jenkins / How to deploy with one click

I am working on a project with git and jenkins (pipeline).
I want to build the project at every commit but only deploy it when the chief wants.
So I would like to have like, two pipelines, one that run at every commit and only build / test and one that I can run by clicking on a button labelled "click me to deploy" that do the job.
Do I must create 2 jenkins jobs or is there a plugin or a way to do this with 1 job.
I have searched but I found nothing about this.
You can achieve with 1job using Input Step (Pipeline). As part of your pipeline, after the build and test execution, add input step (Wait for Interactive input) and then add the deployment related stages.
So for each check-in, Jenkins build will trigger. But it will complete only build and test stages after that it will wait for chief approval to proceed for deployment.
reference: https://jenkins.io/doc/pipeline/steps/pipeline-input-step
This is an example on how to build a pipeline that builds, waits for input, and deploys when input is yes. If input timeout is exceeded then the job will exit. If one does not need the timeout then it can be ommited and the pipeline will wait indefinately without consuming an executor (note the agent annotation in the top pipeline and in each stage)
pipeline {
agent none
stages {
stage('Build') {
agent { label 'master' }
steps {
sh 'build something'
}
}
stage('Production deploy confirmation') {
options {
timeout(time: 60, unit: 'SECONDS')
}
input {
message "Deploy to production?"
ok "Yes"
}
steps {
echo 'Confirmed production deploy'
}
}
stage('Deploy Production') {
stage('internal') {
agent { label 'master' }
steps {
sh 'deploy something'
}
}
}
}
}
Try a parametrized Job with a Boolean parameter and two separate stages for Build and Deploy:
pipeline{
parameters {
booleanParam(name: 'deploy_param', defaultValue: false, description: 'Check if want to deploy')
}
stages{
stage("Build"){
steps{
// build steps
}
}
stage("Deploy"){
when {
environment name: 'deploy_param', value: 'true'
}
steps{
// deploy steps
}
}
}
}
In this way yo can have a CI build with "Deploy" stage turned off, as the deploy_param is set to false by default. And also a manual build ("when the chief wants") with "Deploy" stage turned on by manually setting the deploy_param to true.

Is there a way to insert a manual approval for Build pipeline 1.5.8 version in jenkins 2

I am using jenkins 2.89.2 version.
For deployment into production system it's often useful to require manual approval; is there a way to insert a manual button to press inside a pipeline?
I tried using Build other Project(manual Step) in post build action but still i don't see any approval button or manual intervention at prod build in build pipeline.. And as i can see that In Build pipeline ---> Manually trigger downstream projects is no more avail in Build pipeline version 1.5.8.
I want to use build pipeline for my project.
Can anyone help on this how to do? Thanks in advance.
That's how I'm doing using Slack integration.
slackSend (channel: "#slack-channel", color: '#4286f4', message: "Deploy Approval: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.JOB_DISPLAY_URL})")
script {
try {
timeout(time:30, unit:'MINUTES') {
env.APPROVE_PROD = input message: 'Deploy to Production', ok: 'Continue',
parameters: [choice(name: 'APPROVE_PROD', choices: 'YES\nNO', description: 'Deploy from STAGING to PRODUCTION?')]
if (env.APPROVE_PROD == 'YES'){
env.DPROD = true
} else {
env.DPROD = false
}
}
} catch (error) {
env.DPROD = true
echo 'Timeout has been reached! Deploy to PRODUCTION automatically activated'
}
}
I have not done this yet but one way to add approvals could be by using "Input Step"
It is documented here:
https://jenkins.io/doc/pipeline/steps/pipeline-input-step/

Jenkins continue pipeline on failed stage

I have a jenkins setup with a bunch of pipelines.
I wrote a new pipeline which can start all pipelines at once.
I would like to build other stages, even if one of them fails.
The script currently looks like this
stage 'CentOS6'
build 'centos6.testing'
stage 'CentOS7'
build 'centos7.testing'
stage 'Debian7'
build 'debian7-x64.testing'
stage 'Debian8'
build 'debian8-x64.testing'
The build scripts itself contain the node they should run on.
How can the script continue with the following stages even if one of them fails.
Cheers
If they should be run in a sequence you can do something like this:
def buildResult= 'success'
try{
build 'centos6.testing'
}catch(e){
buildResult = 'failure'
}
currentBuild.result = buildResult
If they should be run in parallell you just run them:
https://www.cloudbees.com/blog/parallelism-and-distributed-builds-jenkins
If you use the parallel step, this should work as you expect by default, as the failFast option, which aborts the job if any of the parallel branches fail, defaults to false.
For example:
parallel(
centos6: { build 'centos6.testing' },
centos7: { build 'centos7.testing' },
debian7: { build 'debian7-x64.testing' },
debian8: { build 'debian8-x64.testing' }
)
What worked for me:
'Task' : {
build( job : "DemoJob-2", wait: false )
build( job : "DemoJob-3", wait: false )
}

Jenkins 2 Pipelines - How to model a continuous delivery pipeline

I am completely new to Jenkins 2 pipelines.
I had played with Jenkins 1 pipelines with the following view:
You could start a certain stage directly, let's say that I could choose to start running from the release stage, skipping Test.
I have a pretty simple Jenkins 2 pipeline definition:
stage('Preparation'){
echo """
Preparing
something
"""
}
stage('Greeting') {
parallel 'hello1':{
node{
echo 'hello world 1'
}
}, 'hello2':{
node{
echo 'hello world 2'
}
}
}
In the pipeline page I have "Build now" which runs all stages starting from Preparation.
My questions are:
How can I run the stage I prefer? For instance Greeting instead of starting from Preparation?
How do you define the dependencies between stages? I mean the stage called after another one completes
Is there a way to limit the stages that a certain user can start? Imagine that I only want a specific user to launch the Greeting stage.
How do you setup manual stages?
UPDATE: The real goal behind my questions is the modelling of a continuous delivery pipeline like the following with Jenkins 2 pipelines:
Build stage --> AUTO --> Acceptance Stage --> MANUAL --> Production Stage
--> MANUAL --> QA Stage
This is the behaviour I want:
Build Stage (any user can start it) when it finishes it triggers automatically the Acceptance Stage. This one can't be lauched manually, only automatically after succesfully finishing the Build Stage.
From Acceptance Stage I need that only authorized users can manually trigger QA Stage and Production Stage.
The business flow would be: a developer hits Build Stage, its code is built and packaged. Acceptance Stage begins, using the packaged code to run a bunch of automated tests.
At this point, when Acceptance Stage has finished OK, two things can happen:
Maybe QA Stage is needed to run more tests (Cucumber, manual, etc.). Some some authorized user would fire this stage.
When the product owner is happy, he can decice to launch the Production Stage to deploy the code in a production environment.
I am struggling to model this with Jenkins 2 pipelines.
There is no direct answer to some of your questions but they can be achieved with some additional coding. While certain people might find some other way to achieve but let me try with what I have in my mind:
1) How can I run the stage I prefer? For instance Greeting instead of starting from Preparation?
This could be achieved by adding a Boolean parameter FASTFORWARD_TO_GREETING and than using the value provided while executing build to manipulate the flow of your build. So your code will now look like :
if (FASTFORWARD_TO_GREETING == 'false') {
stage('Preparation'){
echo """
Preparing
something
"""
}
}
stage('Greeting') {
parallel 'hello1':{
node{
echo 'hello world 1'
}
}, 'hello2':{
node{
echo 'hello world 2'
}
}
}
2) How do you define the dependencies between stages? I mean the stage called after another one completes
Stages are executed serially, so if a stage is defined first it'll be started and completed first before moving to the next stage. However in parallel step this does not hold true, as all the steps will be executed in parallel. So in your example code the dependency you have defined is that stage "Preparation" will be executed first and than only "hello1" and "hello2" step will be executed in parallel. However there is no guarantee as to which "hello world1" or "hello world 2" would be printed.
3) Is there a way to limit the stages that a certain user can start? Imagine that I only want a specific user to launch the Greeting stage.
You can have an manual approval step just before some stage. For example, in your code you want stage Preparation to be executed and than you want it to go with manual approval before executing stage Greeting, your code will look something like this:
stage('Preparation'){
echo """
Preparing
something
"""
}
stage concurrency: 1, name: 'approve-greeting'
input id: 'greeting-deploy', message: 'Proceed to Greeting?', ok: 'Deploy'
stage('Greeting') {
parallel 'hello1':{
node{
echo 'hello world 1'
}
}, 'hello2':{
node{
echo 'hello world 2'
}
}
}
What will happen after this is when you execute the build the stage preparation will get executed but after that the job would wait for a manual approval to proceed. In the Jenkins Pipeline view the stage would be called "approve-greeting" and it'll wait until someone approves the build by clicking on it in the view.
4) How do you setup manual stages?
I believe this is answered in answer 3?
Please let me know in case you need further information/explanation.
EDIT:: Please find the further answers below:
Build Stage (any user can start it) when it finishes it triggers
automatically the Acceptance Stage.
Clearly Both the Build Stage and Acceptance Stage will be defined as normal stage in Jenkins pipeline. So your code would be simple like :
node {
//define any variable here
// Get source code from repo using checkout to directory say stackoverflow
// Get source code from repo for acceptance test using checkout to directory say stackoverflow-test
//Define any tool like Maven etc. location if required.
dir('stackoverflow') {
stage name: 'build'
//Do required steps
}
dir('stackoverflow-test') {
stage name: 'Acceptance'
//Do required steps here
}
At this point, when Acceptance Stage has finished OK, two things can
happen:
Maybe QA Stage is needed to run more tests (Cucumber, manual, etc.).
Some some authorized user would fire this stage.
When the product owner is happy, he can decide to launch the Production Stage to deploy the code in a production environment.
This you can do by having input option so after the above piece of code you could now write:
stage 'promotion'
def userInput = input(
id: 'userInput', message: 'Let\'s promote?', parameters: [
[$class: 'BooleanParameterDefinition', defaultValue: false, description: 'Production', name: 'prod'],
[$class: 'BooleanParameterDefinition', defaultValue: false, description: 'ManualQA', name: 'qa']
])
echo ("Env: "+userInput['prod'])
echo ("Target: "+userInput['qa'])
Than you can take the value from above and manipulate the flow again. Like :
If the value of prod is true than proceed to Production stage,
If the value of qa is true than proceed to QA-Manual stage much like my above example code of FASTFORWARD_TO_GREETING.
EDIT 2
Further answering questions on the comment section:
1) How or where do I specify parameters like FASTFORWARD_TO_GREETING
Parameters like FASTFORWARD_TO_GREETING will be defined as Job level parameter
2) In the promotion stage you have to choose between ManualQA and
Production. If the user chooses ManualQA it runs that Stage skipping
Production. After it I want the user to be promted if he wants to
promote to production stage. If you could provide a full definition of
the pipeline it'd be great.
This you could manipulate after MaualQA stage with another input step but this time with only one parameter. So after stage Promotion, there would be stage ManualQA and than after that this below input step:
def userInput1 = input(
id: 'userInput', message: 'Let\'s promote?', parameters: [
[$class: 'BooleanParameterDefinition', defaultValue: false, description: 'Production', name: 'prod']
])
3) How can I determine if a user has permissions to run a stage or
not. Ideally I would like to do it based on roles
I am not sure about how to do it with roles but I believe anyone with administrator access or running that job would have access to run/approve that stage, but I am not 100% sure if it could be somehow modified.
This is a full continuous delivery pipeline built with the indications I got from the accepted anwer:
node{
def user
def userInput
def mvnHome = tool 'M3'
wrap([$class: 'BuildUser']) {
user = env.BUILD_USER_ID
}
stage('Commit Stage'){
echo 'Downloading from Git...'
git 'https://github.com/codependent/spring-nio-rest.git'
'Building project...'
sh "${mvnHome}/bin/mvn clean install -DskipTests"
}
stage('Acceptance Stage') {
echo """
Getting image from Nexus...OK
Deploying image...OK
Executing tests...OK
"""
userInput = input(id: 'userInput', message: 'Select the next stage:', parameters: [
[$class: 'BooleanParameterDefinition', defaultValue: false, description: 'Run QA tests', name: 'QA'],
[$class: 'BooleanParameterDefinition', defaultValue: false, description: 'Run performance tests', name: 'performance']
])
}
if(userInput['QA']){
stage('QA Stage') {
echo """
Getting image from Nexus...OK
Deploying image...OK
Executing QA tests...OK
"""
}
}
if(userInput['performance']){
stage('Performance Stage') {
echo """
Getting image from Nexus...OK
Deploying image...OK
Executing Performance tests...OK
"""
}
}
stage('Production Stage') {
input message: 'Are you sure you want to deploy to Production?', submitter: 'codependent'
echo 'Deploying to Production...OK'
}
}

Resources