title: Declarative Pipeline with dynamic matrix axis values
body: <p>Hi I am trying to get a Jenknis-Declarative-Pipeline-Job work.</p>
  
  <p>The Use-Case should be pretty simple:<br>
  I want to build multiple Plugins with the same Jenkins-pipeline. To do so I wrote a "JenkinsLibrary" with an interface the Plugins can use for parameters. One of this parameters is the axis-values.  </p>
  
  <p>The Problem I have is pretty similar to <a href="https://www.reddit.com/r/jenkinsci/comments/epjgqu/declarative_pipeline_dynamic_matrix_axis_values/" rel="noreferrer">this reddist post</a>. </p>
  
  <p>I want to set the "values" of the "axis" of the matrix-build from a variable.
  I am out of Ideas, is this even possible?</p>
  
  <p>So here is my example:<br>
  a "JenkinsLibrary" with a file my_library.groovy</p>
  
  <pre><code>def call(Map i_options)
  {
  // later I will parse the options to set the values, but currently the step before already crashes ...
  
      def axis_1_values = "axis_1_value_A"
  // already tried the following alternatives ...
  //    def axis_1_values = 'axis_1_value_A'
  //    def axis_1_values = '''axis_1_value_A'''
  //    def axis_1_values = ["axis_1_value_A", "axis_2_value_A"]
      pipeline
      {
          agent any
          stages { stage("stage A") { matrix {
              axes {
                  axis {
                      name "axis_1"
                      // values "axis_1_value_A" // &lt;- of course this works ...
                      // but I want to read it from a variable
                      values "${axis_1_values}" 
                      // I already tried more variants
                      // values ${axis_1_values}
                      // values axis_1_values
                  }
                  axis {
                      name "axis_2"
                      values "axis_2_value_A", "axis_2_value_B"
                  }
              }
              stages {
                  stage("another stage") { steps {
                      echo "hello world from ${axis_1} &amp;&amp; ${axis_2}"
                  } }
              }
          } } }
      }
  }
  </code></pre>
  
  <p>A Plugin with a file "Jenkinsfile":</p>
  
  <pre><code>@Library("JenkinsLibrary") _
  
  def options = [
      axis_values: "a_axis_value"
  ]
  
  my_library(options)
  </code></pre>
  
  <p>I am getting the following error:</p>
  
  <pre><code>[...] Expected string literal but got "${axis_1_values}"
  </code></pre>
  
  <p>complete log:</p>
  
  <pre><code>    19: Expected string literal but got "${axis_1_values}" @ line 19, column 28.
                         values "${axis_1_values}" 
                                ^
  
  1 error
  
      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.GroovyClassLoader.parseClass(GroovyClassLoader.java:254)
      at groovy.lang.GroovyClassLoader.recompile(GroovyClassLoader.java:761)
      at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:718)
      at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:787)
      at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:775)
      at org.jenkinsci.plugins.workflow.cps.global.UserDefinedGlobalVariable.getValue(UserDefinedGlobalVariable.java:57)
      at org.jenkinsci.plugins.workflow.cps.CpsScript.invokeMethod(CpsScript.java:113)
      at sun.reflect.GeneratedMethodAccessor729.invoke(Unknown Source)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:498)
      at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
      at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
      at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1213)
      at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1022)
      at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:42)
      at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
      at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
      at org.kohsuke.groovy.sandbox.impl.Checker$1.call(Checker.java:160)
      at org.kohsuke.groovy.sandbox.GroovyInterceptor.onMethodCall(GroovyInterceptor.java:23)
      at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onMethodCall(SandboxInterceptor.java:157)
      at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onMethodCall(SandboxInterceptor.java:142)
      at org.kohsuke.groovy.sandbox.impl.Checker$1.call(Checker.java:158)
      at org.kohsuke.groovy.sandbox.impl.Checker.checkedCall(Checker.java:162)
      at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.methodCall(SandboxInvoker.java:17)
      at WorkflowScript.run(WorkflowScript:21)
      at ___cps.transform___(Native Method)
      at com.cloudbees.groovy.cps.impl.ContinuationGroup.methodCall(ContinuationGroup.java:86)
      at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.dispatchOrArg(FunctionCallBlock.java:113)
      at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.fixArg(FunctionCallBlock.java:83)
      at sun.reflect.GeneratedMethodAccessor500.invoke(Unknown Source)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:498)
      at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
      at com.cloudbees.groovy.cps.impl.LocalVariableBlock$LocalVariable.get(LocalVariableBlock.java:39)
      at com.cloudbees.groovy.cps.LValueBlock$GetAdapter.receive(LValueBlock.java:30)
      at com.cloudbees.groovy.cps.impl.LocalVariableBlock.evalLValue(LocalVariableBlock.java:28)
      at com.cloudbees.groovy.cps.LValueBlock$BlockImpl.eval(LValueBlock.java:55)
      at com.cloudbees.groovy.cps.LValueBlock.eval(LValueBlock.java:16)
      at com.cloudbees.groovy.cps.Next.step(Next.java:83)
      at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:174)
      at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:163)
      at org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:129)
      at org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:268)
      at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:163)
      at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.access$001(SandboxContinuable.java:18)
      at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.run0(SandboxContinuable.java:51)
      at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:185)
      at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:405)
      at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$400(CpsThreadGroup.java:96)
      at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:317)
      at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:281)
      at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:67)
      at java.util.concurrent.FutureTask.run(FutureTask.java:266)
      at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:131)
      at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)
      at jenkins.security.ImpersonatingExecutorService$1.run(ImpersonatingExecutorService.java:59)
      at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
      at java.util.concurrent.FutureTask.run(FutureTask.java:266)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
      at java.lang.Thread.run(Thread.java:748)
  Finished: FAILURE
  </code></pre>
  
  <p>My System:
  Jenkins-Version: Jenkins ver. 2.190.1<br>
  Declarative-Plugin-Version 1.5.0<br>
  Declarative Agent API: 1.1.1<br>
  Declarative Extension Points API: 1.5.0<br>
  (many other plugins, I think this are the important ones)</p>
  
  <p><strong>UPDATE</strong><br>
  I still do not have a solution. But when I define a variable like this, I understand that I try to insert a "GStringImpl" to that. But I am unable to cast it as java-string.</p>
  
  <pre><code>def _str_1 = "a string"
  def _str_2 = "${_str_1}"
  println _str_1.class             // -&gt; class java.lang.String
  println _str_2.class             // -&gt; class org.codehaus.groovy.runtime.GStringImpl
  def _str_3 = "${_str_1}" as java.lang.String  
  println _str_3.class             // -&gt; class java.lang.String
  </code></pre>
  
  <p>But I still don't know how I can add a single value, because if I do</p>
  
  <pre><code>values "${axis_1_values}" as as java.lang.String     // error-msg: Expected string literal but got ${as}  
  values ("${axis_1_values}" as java.lang.String)      // error-msg: Expected string literal but got ${"${axis_1_values}"  
  values axis_1_values.toString()                      // error-msg: Method calls on objects not allowed outside "script" blocks.
  values "${axis_1_values}".toString()                 // error-msg: Expected a symbol @ line 26, column 28.
  </code></pre>
  
  <p>This casting stuff may work for a single value, but I want to be able to add a list of values, like its possible in the default example which works ...<br>
  <code>values "axis_2_value_A", "axis_2_value_B"</code>  </p>
  
  <p>I am wondering, that this works in the "docker-agent"-part of the declarative pipeline.</p>
  
  <pre><code>agent { 
      docker {
          image "${_image}:latest"
          label "${_label}"
      }
  }
  </code></pre>
  
  <p>But I in the code, I realized that the parsing of the docker-label is implemented separately ...</p>
  
  <p>I have still no Ideas how to reach that goal within the matrix / axis features of the declarative pipeline.  </p>
  
  <p>(funfact: one of the main reasons why even doing this that the visualisation in the blue-ocean view for scripted-pipelines is still buggy and the issue seems to be ignored ...<br>
  <a href="https://issues.jenkins-ci.org/browse/JENKINS-53751" rel="noreferrer">https://issues.jenkins-ci.org/browse/JENKINS-53751</a> )</p>