How can I have one pipeline executed even if the other has failed in jenkins - jenkins

I have the following (part of a) pipeline
stages {
stage('bootstrap') {
parallel {
stage("Linux") {
agent { label 'linux' }
steps {
sh 'bootstrap.sh'
}
}
stage("Windows") {
agent { label 'Windows' }
steps {
bat 'bootstrap.bat'
}
}
}
}
stage('devenv') {
parallel {
stage('Linux') {
agent { label 'linux' }
steps {
sh 'devenv.sh'
}
}
stage('Windows') {
agent { label 'Windows' }
steps {
bat 'devenv.bat'
}
}
}
}
}
post {
always {
echo "Done"
}
}
The problem is that when bootstrap.bat fails on windows, the devenv step is now considered failed, and the linux devenv won't continue. I would like to have the results of the linux pipeline even if the windows one fails early.
An option would be to separate the stages so that linux full pipeline is on one branch of the parallel execution, and windows is on the other, but maybe there's a trick I am not aware of, because I tried it and it does not seem to be acceptable syntax.
Edit
Suggested fix does not work. This is the pipeline
pipeline {
agent none
parallel {
stage('Linux') {
agent { label 'linux' }
stages {
stage('bootstrap') {
sh "ls"
}
stage('devenv') {
sh "ls"
}
}
}
stage('windows') {
agent { label 'Windows' }
stages {
stage('bootstrap') {
bat 'dir'
}
stage('devenv') {
bat 'dir'
}
}
}
}
}
This is the error message
WorkflowScript: 8: Undefined section "parallel" # line 8, column 5.
parallel {
^
WorkflowScript: 1: Missing required section "stages" # line 1, column 1.
pipeline {
^

Related

Declarative Jenkins pipeline - How to set agent any only when condition is met?

Is it possible to specify agent 'any' only when a condition is met?
Context: I have a parallel pipeline with some common steps. The pipeline runs tests on Linux and Windows on two different agents. There are parameter defining if both, or only Linux, or only Windows should run. I want to use as little agents as possible.
With the following pipeline, the Linux tests are executed on the main agent. The Windows tests on a different agent. So if only Linux needs to run, I only use 1 agent, which is good. But if only Windows needs to run, the main agent will be blocked until the Windows agent finishes.
pipeline {
agent any // main agent
parameters {
booleanParam( name: 'RUN_WINDOWS' )
booleanParam( name: 'RUN_LINUX' )
}
stages {
stage('Common step') {
...
}
stage("Test") {
parallel {
stage('Windows') {
agent any
when {
expression { return params.RUN_WINDOWS }
}
stages {
stage('Test Windows') {
...
}
}
}
stage('Linux') { // no agent specified, so will use the main agent
when {
expression { return params.RUN_LINUX }
}
stages {
stage('Test Linux') {
...
}
}
}
}
post {
...
}
}
}
}
I'd need something like this for the Windows stage, where it only specifies an agent based on a condition:
if (params.RUN_WINDOWS && params.LINUX) { agent any }
EDIT: I'm looking for a solution without using labels.
As a workaround, instead of setting any you can set agent labels conditionally. Something like below.
def labels = "Windows"
if (params.RUN_WINDOWS && params.LINUX) {
labels = "windows || linux"
}
pipeline {
agent any // main agent
parameters {
booleanParam( name: 'RUN_WINDOWS' )
booleanParam( name: 'RUN_LINUX' )
}
stages {
stage('Common step') {
...
}
stage("Test") {
parallel {
stage('Windows') {
agent {
label "${labelSelected}"
}
when {
expression { return params.RUN_WINDOWS }
}
stages {
stage('Test Windows') {
...
}
}
}
stage('Linux') { // no agent specified, so will use the main agent
when {
expression { return params.RUN_LINUX }
}
stages {
stage('Test Linux') {
...
}
}
}
}
post {
...
}
}
}
}

Jenkins Error: "Unknown stage section "stage". Starting with version 0.5, steps in a stage must be in a 'steps' block

Per my header, I'm receiving the following error for my jenkins setup:
Unknown stage section "stage". Starting with version 0.5, steps in a stage must be in a 'steps' block. #line xxx, column xx.
stage('First Parallel Stage') {
^
My configuration:
pipeline {
stages {
stage('Header_1'){
steps{}
}
stage('Header_2'){
steps{}
}
parallel{
stage('First Parallel Stage'){
environment{}
}
stages {
stage('Another_One'){
steps{}
}
}
}
}
}
I've tried putting an empty steps{} in stage('First Parallel Stage') and tried putting it inside steps. I'm unsure what could be wrong.
You'll need to put stages that are grouped together into a stage and parallel must be within a stage too. Full working example:
pipeline {
agent any
stages {
stage('Header_1') {
steps {
echo '1'
}
}
stage('Header_2') {
steps {
echo '2'
}
}
stage('Parallel') { // add this
parallel {
stage('First Parallel Stage') {
environment {
TEST = 3
}
steps {
echo "$TEST"
}
}
stage('Execute this together') { // add this
stages {
stage('Another_One') {
steps {
echo "4"
}
}
stage('Yet Another_One') {
steps {
echo "5"
}
}
}
}
}
}
}
}
Please note that you can't have parallel{} inside of parallel{}, but you can chain them.
On BlueOcean it then looks like the following:

How to nest multiple stages within a stage with a "when" clause

I am trying to accomplish the following but getting the following error: Unknown stage section "stage".
I have a few stages that I am trying to nest under one stage with a when block to build/deploy on a certain branch. I tried using stages as the parent but got another error since I already have a stages stage somewhere else in the file. How do I accomplish this?
stage("Build and deploy") {
when{branch "feature branch"}
stage("Dev"){
}
stage("Test"){
}
stage("Prod"){
}
}
Here's a self-contained pipeline that works for me:
pipeline {
agent any
stages {
stage('doing something') {
when { expression { 2 > 1 } } // "branch" should work too
stages {
stage ('a') {
steps {
script {echo "a"}
}
}
stage ('b') {
steps {
script {echo "b"}
}
}
stage ('c') {
steps {
script {echo "c"}
}
}
}
}
}
}
Output:

How to lock multiple stages of declarative Jenkins pipeline?

I want to run multiple stages inside a lock within a declarative Jenkins pipeline:
pipeline {
agent any
stages {
lock(resource: 'myResource') {
stage('Stage 1') {
steps {
echo "my first step"
}
}
stage('Stage 2') {
steps {
echo "my second step"
}
}
}
}
}
I get the following error:
Started by user anonymous
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
WorkflowScript: 10: Expected a stage # line 10, column 9.
lock(resource: 'myResource') {
^
WorkflowScript: 10: Stage does not have a name # line 10, column 9.
lock(resource: 'myResource') {
^
WorkflowScript: 10: Nothing to execute within stage "null" # line 10, column 9.
lock(resource: 'myResource') {
^
3 errors
at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:310)
at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1085)
at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:603)
at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:581)
at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:558)
at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298)
at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:268)
at groovy.lang.GroovyShell.parseClass(GroovyShell.java:688)
at groovy.lang.GroovyShell.parse(GroovyShell.java:700)
at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.reparse(CpsGroovyShell.java:116)
at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.parseScript(CpsFlowExecution.java:430)
at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.start(CpsFlowExecution.java:393)
at org.jenkinsci.plugins.workflow.job.WorkflowRun.run(WorkflowRun.java:257)
at hudson.model.ResourceController.execute(ResourceController.java:97)
at hudson.model.Executor.run(Executor.java:405)
Finished: FAILURE
What's the problem here? The documentation explicitly states:
lock can be also used to wrap multiple stages into a single
concurrency unit
It should be noted that you can lock all stages in a pipeline by using the lock option:
pipeline {
agent any
options {
lock resource: 'shared_resource_lock'
}
stages {
stage('will_already_be_locked') {
steps {
echo "I am locked before I enter the stage!"
}
}
stage('will_also_be_locked') {
steps {
echo "I am still locked!"
}
}
}
}
This has since been addressed.
You can lock multiples stages by grouping them in a parent stage, like this :
stage('Parent') {
options {
lock('something')
}
stages {
stage('one') {
...
}
stage('two') {
...
}
}
}
(Don't forget you need the Lockable Resources Plugin)
The problem is that, despite the fact that declarative pipelines were technically available in beta in September, 2016, the blog post you reference (from October) is documenting scripted pipelines, not declarative (it doesn't say as much, so I feel your pain). Lockable resources hasn't been baked in as a declarative pipeline step in a way that would enable the feature you're looking for yet.
You can do:
pipeline {
agent { label 'docker' }
stages {
stage('one') {
steps {
lock('something') {
echo 'stage one'
}
}
}
}
}
But you can't do:
pipeline {
agent { label 'docker' }
stages {
lock('something') {
stage('one') {
steps {
echo 'stage one'
}
}
stage('two') {
steps {
echo 'stage two'
}
}
}
}
}
And you can't do:
pipeline {
agent { label 'docker' }
stages {
stage('one') {
lock('something') {
steps {
echo 'stage one'
}
}
}
}
}
You could use a scripted pipeline for this use case.
If the resource is only used by this pipeline you could also disable concurrent builds:
pipeline {
agent any
options {
disableConcurrentBuilds()
}
stages {
stage('will_already_be_locked') {
steps {
echo "I am locked before I enter the stage!"
}
}
stage('will_also_be_locked') {
steps {
echo "I am still locked!"
}
}
}
}
Altho the options{} block offers this functionality it is not posible to use it in some use cases.
Lets say that you have to name your lock() with a specific name depending on a branch or an environment. You have a pipeline which you dont want to be block by disableConcurrentBuilds() and lock resources depending on a discriminator. You can not name your lock() inside the options{} block by using a environment variable or any other variable from the pipeline because the block is evaluated outside the agent.
The best solution in my opinion is the following:
pipeline {
agent { label 'docker' }
stages {
stage('Wrapper') {
steps {
script {
lock(env.BRANCH_NAME) {
stage('Stage 1') {
sh('echo "stage1"')
}
stage('Stage 2') {
sh('echo "stage2"')
}
}
}
}
}
}
}
Keep in mind that the script {} block takes a block of Scripted Pipeline and executes that in the Declarative Pipeline so no steps{} are allowed inside.
I run multiple build and test containers on the same build nodes. The test containers must lock up the node name as db username for the tests.
lock(resource: "${env.NODE_NAME}" as String, variable: 'DBUSER')
Locks in options are computed at load time, but NODE_NAME is unknown that early. In order to lock multiple stages for visual effect, we can create stages inside script block, i.e. 'run test' stage in the snippet. The stage visualization is just as good as other stage blocks.
pipeline {
agent any
stages {
stage('refresh') {
steps {
echo "freshing on $NODE_NAME"
lock(resource: "${env.NODE_NAME}" as String, variable: 'DBUSER') {
sh '''
printenv | sort
'''
script {
stage('run test')
sh '''
printenv | sort
'''
}
}
}
}
}
}

Use a lightweight executor for a declarative pipeline stage (agent none)

I'm using Jenkins Pipeline with the declarative syntax, currently with the following stages:
Prepare
Build (two parallel sets of steps)
Test (also two parallel sets of steps)
Ask if/where to deploy
Deploy
For steps 1, 2, 3, and 5 I need and agent (an executor) because they do actual work on the workspace. For step 4, I don't need one, and I would like to not block my available executors while waiting for user input. This seem to be referred to as either a "flyweight" or "lightweight" executor for the classic, scripted syntax, but I cannot find any information on how to achieve this with the declarative syntax.
So far I've tried:
Setting an agent directly in the pipeline options, and then setting agent none on the stage. This has no effect, and the pipeline runs as normalt, blocking the executor while waiting for input. It is also mentioned in the documentation that it will have no effect, but I thought I'd give it a shot anyway.
Setting agent none in the pipeline options, and then setting an agent for each stage except #4. Unfortunately, but expectedly, this allocates a new workspace for every stage, which in turn requires me to stash and unstash. This is both messy and gives me further problems in the parallel stages (2 and 3) because I cannot have code outside the parallel construct. I assume the parallel steps run in the same workspace, so stashing/unstashing in both would have unfortunate results.
Here is an outline of my Jenkinsfile:
pipeline {
agent {
label 'build-slave'
}
stages {
stage("Prepare build") {
steps {
// ...
}
}
stage("Build") {
steps {
parallel(
frontend: {
// ...
},
backend: {
// ...
}
)
}
}
stage("Test") {
steps {
parallel(
jslint: {
// ...
},
phpcs: {
// ...
},
)
}
post {
// ...
}
}
stage("Select deploy target") {
steps {
script {
// ... code that determines choiceParameterDefinition based on branch name ...
try {
timeout(time: 5, unit: 'MINUTES') {
deployEnvironment = input message: 'Deploy target', parameters: [choiceParameterDefinition]
}
} catch(ex) {
deployEnvironment = null
}
}
}
}
stage("Deploy") {
when {
expression {
return binding.variables.get("deployEnvironment")
}
}
steps {
// ...
}
}
}
post {
// ...
}
}
Am I missing something here, or is it just not possible in the current version?
Setting agent none at the top level, then agent { label 'foo' } on every stage, with agent none again on the input stage seems to work as expected for me.
i.e. Every stage that does some work runs on the same agent, while the input stage does not consume an executor on any agent.
pipeline {
agent none
stages {
stage("Prepare build") {
agent { label 'some-agent' }
steps {
echo "prepare: ${pwd()}"
}
}
stage("Build") {
agent { label 'some-agent' }
steps {
parallel(
frontend: {
echo "frontend: ${pwd()}"
},
backend: {
echo "backend: ${pwd()}"
}
)
}
}
stage("Test") {
agent { label 'some-agent' }
steps {
parallel(
jslint: {
echo "jslint: ${pwd()}"
},
phpcs: {
echo "phpcs: ${pwd()}"
},
)
}
}
stage("Select deploy target") {
agent none
steps {
input message: 'Deploy?'
}
}
stage("Deploy") {
agent { label 'some-agent' }
steps {
echo "deploy: ${pwd()}"
}
}
}
}
However, there are no guarantee that using the same agent label within a Pipeline will always end up using the same workspace, e.g. as another build of the same job while the first build is waiting on the input.
You would have to use stash after the build steps. As you note, this cannot be done normally with parallel at the moment, so you'd have to additionally use a script block, in order to write a snippet of Scripted Pipeline for the stashing/unstashing after/before the parallel steps.
There is a workaround to use the same build slave in the other stages.
You can set a variable with the node name and use it in the others.
ie:
pipeline {
agent none
stages {
stage('First Stage Gets Agent Dynamically') {
agent {
node {
label "some-agent"
}
}
steps {
echo "first stage running on ${NODE_NAME}"
script {
BUILD_AGENT = NODE_NAME
}
}
}
stage('Second Stage Setting Node by Name') {
agent {
node {
label "${BUILD_AGENT}"
}
}
steps {
echo "Second stage using ${NODE_NAME}"
}
}
}
}
As of today (2021), you can use nested stages (https://www.jenkins.io/doc/book/pipeline/syntax/#sequential-stages) to group all the stages that must run in the same workspace before the input step, and all the stages that must be run in the same workspace after the input step. Of course, you need to stash or to store artifacts in some external repository before the input step, because the second workspace may not be the same than the first one:
pipeline {
agent none
stages {
stage('Deployment to Preproduction') {
agent any
stages {
stage('Stage PRE.1') {
steps {
echo "StagePRE.1"
sleep(10)
}
}
stage('Stage PRE.2') {
steps {
echo "Stage PRE.2"
sleep(10)
}
}
}
}
stage('Stage Ask Deploy') {
steps {
input message: 'Deploy to production?'
}
}
stage('Deployment to Production') {
agent any
stages {
stage('Stage PRO.1') {
steps {
echo "Stage PRO.1"
sleep(10)
}
}
stage('Stage PRO.2') {
steps {
echo "Stage PRO.2"
sleep(10)
}
}
}
}
}
}

Resources