Jenkins: Schedule Particular Stage with single pipeline - jenkins

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.

Related

Prevent Jenkins job from building from another jenkins file

We have 2 jenkins job AA and BB.
Is there a way to allow BB only to be trigger from AA after it completes?
Basically, you can use build triggers to do this. More about build triggers can be found here. There are two ways to add build triggers. Following is how you can add triggers using the UI. By going to Configure Job you can add triggers. Please refer to the following image.
In a declarative pipeline, you can add triggers as shown below.
pipeline {
agent any
triggers { upstream(upstreamProjects: 'AA', threshold: hudson.model.Result.SUCCESS) }
stages {
stage('Hello') {
steps {
echo 'Hello World BB'
}
}
}
}
Here you can specify the threshold on when to trigger the build based on the status of the upstream build. There are 4 different thresholds.
hudson.model.Result.ABORTED: The upstream build was manually aborted.
hudson.model.Result.FAILURE: The upstream build had a fatal error.
hudson.model.Result.SUCCESS: The upstream build had no errors.
hudson.model.Result.UNSTABLE: The upstream build had an unstable result.
Update 02
If you want to restrict all other jobs/users from triggering this job you will have to restructure your Job. You can wrap your stages with a parent Stage and conditionally check who triggered the Job. But note that the Job will anyway trigger but the stages will be skipped. Please refer the following pipeline.
pipeline {
agent any
triggers { upstream(upstreamProjects: 'AA', threshold: hudson.model.Result.SUCCESS) }
stages{
stage('Parent') {
// We will restrict triggering this Job for everyone other than Job AA
when { expression {
print("Checking if the Trigger is allowed to execute this job")
print('AA' in currentBuild.buildCauses.upstreamProject)
}
}
stages {
stage('Hello') {
steps {
echo 'Hello World BB'
}
}
}
}
}
}

Jenkins - How to run a stage/function before pipeline starts?

We are using a Jenkins multibranch pipeline with BitBucket to build pull request branches as part of our code review process.
We wanted to abort any queued or in-progress builds so that we only run and keep the latest build - I created a function for this:
def call(){
def jobName = env.JOB_NAME
def buildNumber = env.BUILD_NUMBER.toInteger()
def currentJob = Jenkins.instance.getItemByFullName(jobName)
for (def build : currentJob.builds){
def exec = build.getExecutor()
if(build.isBuilding() && build.number.toInteger() != buildNumber && exec != null){
exec.interrupt(
Result.ABORTED,
new CauseOfInterruption.UserInterruption("Job aborted by #${currentBuild.number}")
)
println("Job aborted previously running build #${build.number}")
}
}
}
Now in my pipeline, I want to run this function when the build is triggered by the creation or push to a PR branch.
It seems the only way I can do this is to set the agent to none and then set it to the correct node for each of the subsequent stages. This results in missing environment variables etc. since the 'environment' section runs on the master.
If I use agent { label 'mybuildnode' } then it won't run the stage until the agent is free from the currently in-progress/running build.
Is there a way I can get the 'cancelpreviousbuilds()' function to run before the agent is allocated as part of my pipeline?
This is roughly what I have currently but doesn't work because of environment variable issues - I had to do the skipDefaultCheckout so I could do it manually as part of my build:
pipeline {
agent none
environment {
VER = '1.2'
FULLVER = "${VER}.${BUILD_NUMBER}.0"
PROJECTPATH = "<project path>"
TOOLVER = "2017"
}
options {
skipDefaultCheckout true
}
stages {
stage('Check Builds') {
when {
branch 'PR-*'
}
steps {
// abort any queued/in-progress builds for PR branches
cancelpreviousbuilds()
}
}
stage('Checkout') {
agent {
label 'buildnode'
}
steps {
checkout scm
}
}
}
}
It works and aborts the build successfully but I get errors related to missing environment variables because I had to start the pipeline with agent none and then set each stage to agent label 'buildnode' to.
I would prefer that my entire pipeline ran on the correct agent so that workspaces / environment variables were set correctly but I need a way to trigger the cancelpreviousbuilds() function without requiring the buildnode agent to be allocated first.
You can try combining the declarative pipeline and the scripted pipeline, which is possible.
Example (note I haven't tested it):
// this is scripted pipeline
node('master') { // use whatever node name or label you want
stage('Cancel older builds') {
cancel_old_builds()
}
}
// this is declarative pipeline
pipeline {
agent { label 'buildnode' }
...
}
As a small side comment, you seem to use: build.number.toInteger() != buildNumber which would abort not only older builds but also newer ones. In our CI setup, we've decided that it's best to abort the current build if a newer build has already been scheduled.

Jenkins stage not triggered even if changeset is correct

My jenkins file looks something like this:
options {
skipDefaultCheckout()
}
stages{
stage("Unit Test"){
when {
allOf{
expression {params.REPOSITORY_CREDENTIALS != null && params.TRG_BRANCH != null}
anyOf {
changeset pattern: "([a-zA-Z]*_cli|clarity_xml_tools)\\/.*", comparator: "REGEX"
changeset pattern: "jenkins\\/pipeline_scripts\\/.*", comparator: "REGEX"
}
}
}
steps{
container('omics-build-agent'){
echo "Stage triggered.."
}
}
post{
always{
echo "Stage completed.."
}
success{
echo "Unit Test completed successfully.."
}
failure{
echo "Unit Test Failed!!"
}
}
}
I checked the Changes in my jenkins build info:
jenkins/pipeline_scripts/build-Build_Python-clarity_xml_tools.sh
But my stage is still not getting triggered. What am I missing?
Note: I cannot remove skipDefaultCheckout() because I have 2 different repos who should be triggering my job when changes are pushed and they should be checked out to 2 different sub folders.
So my pipeline gets triggered by the Generic Webhook Plugin (which is working fine) from either of the 2 repo. So I had to force stop the default checkout and then use the checkout plugin for gitSCM to get my repos inside the stage.
Could it be because of this?

How to fetch Build ID of Job triggered from another job

I have the following situation in a Jenkinsfile of Job A:
...
... // Some execution
...
call Job B
// When Job B runs successfully
params.some_var_used_in_Job_C = BUILD ID of Job B
call Job C
I have to know the BUILD ID of Job B after it succeeds and I need to pass it as a params to Job C. Can anyone suggest how I can do this?
Also is it possible that I can pass some variable from Job B to Job A (so that I can send that value to Job C later) ?
Should be as simple as this:
node {
stage('Test') { // for display purposes
def jb = build wait: true, job: 'JobB'
println jb.fullDisplayName
println jb.id
//this will show everything available but needs admin privs to execute
println jb.properties
}
}
If you want to pass a simple string from job B to Job A then in Job B you can set an env variable
env.someVar = "some value"
then back in job A
println jb.buildVariables.someVar
#Kaus Untwale answer is correct. I've copied his answer into a declarative pipeline and added error handling.
From a upstream job:
pipeline {
agent any
stages {
stage('Run job') {
steps {
// make build as unstable on error
// remove this if not needed
catchError(buildResult: 'UNSTABLE') {
script {
def jb = build wait: true, job: 'test2', propagate: false
println jb
println jb.fullDisplayName
println jb.id
// throw an error if build failed
// this still allows you to get the job infos you need
if (jb.result == 'FAILURE') {
error('Downstream job failed')
}
}
}
}
}
}
}
Get the build within a downstream job:
# job: test2
pipeline {
agent any
stages {
stage('Upstream') {
steps {
script {
// upstream build if available
def upstream = currentBuild.rawBuild.getCause(hudson.model.Cause$UpstreamCause)
echo upstream?.shortDescription
// the run of that cause holds more infos
def upstreamRun = upstream?.getUpstreamRun()
echo upstreamRun?.number.toString()
}
}
}
}
}
See the api docs for the run class. You'll also need to allow some calls from the downstream example as approved scripts or disable the Groovy Sandboxo on that job.

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.

Resources