0

I want to run a series of tests on multiple platforms (AIX, pi, macOS, Windows, Linux). Obviously that level can be executed in parallel.

    pipeline {
      agent any
      stages {
        stage ("Run Tests") {
          steps {
            parallel (
                     pi:{...}
                     aix: {...}
etc.

But the tests for "pi" can not run on any pi - I am testing against multiple versions of the software and need to select the specific platform per test, so the pi-Test (as well as aix) then goes on:

                     catchError(buildResult: "UNSTABLE", stageResult: "FAILURE") {
                       script{
                         def E="" // define some variables per platform
                         def res=""  
                         stage ("pi&&Version1") {
                           agent {
                             label "pi&&Version1"
                           }
                           script {
                             echo "NODE_NAME = ${env.NODE_NAME}"            
                             ...intense code to test V1...
                           }
                         }
                         stage ("pi&&Version2") {
                           agent {
                             label "pi&&Version2"
                           }
                           script {
                             echo "NODE_NAME = ${env.NODE_NAME}"            
                             ...intense code to test V2...
                           }
                         }
                       }
                     }

So each test on a platform needs an agent with a specific label which means that the agent is selected "deeper" within the code. And I haven't seen any examples doing this - maybe I read the wrong doc or did not understand it well enough - but I just can't find a way to structure my scripts in a way which would allow me doing this.

The script fails with Invalid step "stage" used - not allowed in this context - The stage step cannot be used in Declarative Pipelines

Any suggestions how to get this working will be much appreciated.

MBaas
  • 7,248
  • 6
  • 44
  • 61

1 Answers1

1

It seems like you are mixing up declarative pipeline syntax and scripted pipeline syntax.
At first it looks like you are suing the old style parallel syntax for your pipeline which has since been replaced with a more declarative parallel syntax which will look something like the following:

pipeline {
    agent any
    stages {
       stage ("Run Tests") {
           parallel {
              stage('pi') {
                 ...
              }
              stage('aix') {
                 ...
              }
           }
        }
    }
}

Regardless of which syntax you use, in the code block inside the parallel stage you are using scripted pipeline syntax (implied by the script directive) which allows you to use more advance code but prevents you from using declarative keywords like the agent directive.
So what you need to to is to convert the code in your stage into scripted syntax which means using node directives for your agent allocation.
It will look like:

script{
   catchError(buildResult: "UNSTABLE", stageResult: "FAILURE") {
       def E="" // define some variables per platform
       def res=""
       stage ("pi&&Version1") {
           node("pi&&Version1") {
               echo "NODE_NAME = ${env.NODE_NAME}"
               ...intense code to test V1...
           }
       }
       stage ("pi&&Version2") {
           node("pi&&Version2"){
               echo "NODE_NAME = ${env.NODE_NAME}"
               ...intense code to test V2...
           }
       }
   }
}

The script directive (that implies a fallback to scripted pipeline syntax) is needed only once to wrap the script, and is not needed agin within the sub stages.

The full pipeline will look something like:

pipeline {
   agent any
   stages {
       stage ("Run Tests") {
           parallel {
               stage('pi') {
                   steps {
                      script {
                          catchError(buildResult: "UNSTABLE", stageResult: "FAILURE") {
                              def E = "" // define some variables per platform
                              def res = ""
                              stage("pi&&Version1") {
                                  node("pi&&Version1") {
                                      echo "NODE_NAME = ${env.NODE_NAME}"
                                      ... intense code to test V1 ...
                                  }
                              }
                              ... other stages ...
                          }
                      }
                  }
                  stage('aix') {
                      ...
                  }
               }
           }
       }
   }
}
Noam Helmer
  • 5,310
  • 1
  • 9
  • 29
  • Thank you - most helpful! I must admit the difference between declarative/scripted pipelines (and the fact that some commands can appear in both, but with different syntax) is quite a hurdle for me as a n00b ;) BTW, I had to inject a `steps{` after `stage("pi")` to get it working... – MBaas Sep 02 '21 at 13:04
  • 1
    You are correct ill update my answer. Check out the [Syntax Compare](https://www.jenkins.io/doc/book/pipeline/syntax/#compare) from the official Jenkins site for the differences between both pipelines types, and also this useful [Answer](https://stackoverflow.com/questions/43484979/jenkins-scripted-pipeline-or-declarative-pipeline) for more info that might help to sort thing out. – Noam Helmer Sep 02 '21 at 13:26