Jenkins Pipeline throws "syntax error: bad substitution" when Passing in Parameter - shell

I have a Terraform project that I was trying to use Jenkin's Custom Checkbox plugin (Custom Checkbox Parameter) with so that I can build separate applications dynamically using the same IaC, however, I'm getting the following error when passing in the name parameter for that plugin into the Terraform plan and apply commands.
syntax error: bad substitution
The idea for all this is just to click on "select all" or each individual app and run the build, and this will create the IaC for the given application(s).
I have a terraform plan that I am running as a smoke test to verify the parameters above are being passed in correctly before running the apply. This looks like the following:
sh 'terraform plan -var-file="terraform-dev.tfvars" -var "app_name=[${params[${please-work}]}]" -input=false'
The documentation for the plugin states that you can reference the items checked by using this format: "${params['please-work']}" which is what I've done above. That said, one caveat to this is that Im having to set the values in quotes for this to work since the variables are being set in the Terraform using list(string).
NOTE: I have tested that all this works if I just hardcode the app names with the escapes as following:
sh 'terraform plan -var-file="terraform-dev.tfvars" -var "app_name=[\\"app-1\\",\\"app-2\\"]" -input=false'
Again, what I need is for this to work with the -var "app_name=[${params[${please-work}]}]" without throwing that error.
If needed, here is the setup for the JSON that the plugin is using:
Additionally, I can see the values are being set the way I need them to be set when running the echo of echo "${params['please-work']}" on the initial build step. So these are coming back as "app-1", "app-2"
Again, all but that one bit is working and I've tried various ways to escape the needed strings to get this work and I need insight on a path forward. This would be greatly appreciated.

You are casting the script argument in your sh step method as a literal string, and therefore it will not interpolate the pipeline variable of type object params within the Groovy pipeline interpreter. You also are passing the variable value for the app_name with [] syntax (attempted list constructor?), which is not syntactically valid for shell, Terraform, or JSON, but is for Jenkins Pipeline and Groovy with undesired behavior (unclear what is desired here). Finally, please-work is a literal string and not a Jenkins Pipeline or Groovy variable, and since params is technically an object and not a Map, you must use the . syntax and not the [] syntax for accessors. You must update with:
sh(label: 'Execute Terraform Plan', script: "terraform plan -var-file='terraform-dev.tfvars' -var 'app_name=${params.please-work}' -input=false")
If another issue arises after fixing all of this, then it would be recommended to convert the plugin usage to the pipeline with a parameters directive, and also to probably remove the unusual characters e.g. - from the parameter name.

Thanks for helping me think through this, Matt. I was able to resolve the issue with the following shell script in the declarative pipeline:
sh "terraform plan -var-file='terraform-dev.tfvars' -var 'app_name=[${params['please-work']}]' -input=false"
This is working now.

Related

How to pass arguments / parameters to the npm-script using npmExecuteScripts?

I'm trying to run the npm-script from the Jenkins pipeline via the SAP Project Piper's npmExecuteScripts:
npmExecuteScripts:
runScripts: ["testScript"]
That works! Now, I want to pass some arguments to my script.
According to the Project Piper documentation, there is a property scriptOptions, which cares about passing arguments to the called script:
Options are passed to all runScripts calls separated by a --. ./piper npmExecuteScripts --runScripts ci-e2e --scriptOptions --tag1 will correspond to npm run ci-e2e -- --tag1
Unfortunately, I can't figure out what is the proper syntax for that command.
I've tried several combinations of using scriptOptions, e.g.:
scriptOptions: ["myArg"]
scriptOptions: ["myArg=myVal"]
and many others, but still no desired outcome!
How can I call an npm-script and pass arguments / parameters to the script using the Project Piper's npmExecuteScripts?
To solve the issue, it's important to bear in mind that in contrast to the regular argument-value mapping via the npm_config_-prefix, the SAP Project Piper scriptOptions doesn't perform a mapping and passes an array of argument-value pairs «as is» instead, and then this array can be picked up via process.argv.
The Jenkins pipeline configuration:
npmExecuteScripts:
runScripts: ["testScript"]
scriptOptions: ["arg1=Val1", "arg2=Val2"]
package.json:
"scripts": {
"testScript": "node ./testScript.mjs"
}
The server-side script:
/**
* #param {Array.<String>} args - array of console input arguments to be parsed
*/
const testScript = function testScript(args) {…}
testScript(process.argv.slice(2));
P.S. Just to compare, the regular way to pass an argument's value to the npm-script looks like:
npm run testScript --arg=Val
and the server-side script:
"testScript": "echo \"*** My argument's value: ${npm_config_arg} ***\""
The output:
*** My argument's value: Val ***
The npm-script engine performs an argument-value mapping under the hood by using the npm_config_-prefix.

gradle and luiquibase run diffchangelog task from command line with arguments

I would like to execute a gradle luqibase plugin diffChangelog task with my custom arguments from command line.
I DO NOT want to add/modify any of the project files, no modifications of build.gradle, no gradle.properties or such i just want to run a task and pass its parameters from command line and i am so far unable to do so i would like to distribute my script that executes this task in one bash file.
I have a problem even figuring out how to pass parameters to a gradle task, moreover even the format of the arguments is confusing - there are documentation snippets pointing that i should use camelCase or hyphenated version also zero/one/two hyphens are possible in the beginning . Additionally can either use -P or -D to pass arguments to gradle so far none of it seem to work it looks like the arguments are not being passed at all.
I would like to execute something like:
./gradlew diffChangelog --url=AA --username=BB --password=CC --reference-username=DD --reference-password=EE --reference-url=FF --changelog-gile=GG
Of course proper values will be provided by inline.
Is there a concise way to do so? So far googling up for the solution results in multiple complex explanations requiring modification of existing files and then passing arguments, is there really no way of just running a gradle task with arguments or am i missing something?
Update:
The error i am alyways getting is:
liquibase.exception.CommandValidationException: Invalid argument '--reference-url': missing required argument
You should check what end of line you have. This can sometimes be resolved by changing the end of line from from windows eol to linux.
Reference:
Unexpected error running Liquibase: Unexpected value [...] (options must start with a '--') && howTo? diff w/ properties file

How to check if pipeline parameter is empty [duplicate]

We used to be able to check if a parameter is available via:
binding.variables.containsKey()
or
getBinding().hasVariable()
But that no longer works at least as of Jenkins v 2.39. (These functions work for variables set within the groovy script but not the parameters from 'Build with Parameters'.)
Instead of using binding.variables.containsKey() to check, you should use:
params.containsKey()

Bamboo: Access script variable in subsequent maven task

I have seen many posts where people asking to access Bamboo variables in script but this is not about that.
I am defining a variable in Shell Script task, as below, and then I would like to access that variable in the subsequent maven task.
#!/bin/sh
currentBuildNumber=${bamboo.buildNumber}
toSubtract=1
newVersion=$(( currentBuildNumber - toSubtract ))
echo "Value of newVersion: ${newVersion}"
This one goes perfectly fine. However I have a subsequent maven 3 task where I try to access this variable by typing ${newVersion} I get below error
error 07-Jun-2019 14:12:20 Exception in thread "main" java.lang.StackOverflowError
simple 07-Jun-2019 14:12:21 Failing task since return code of [mvn --batch-mode -Djava.io.tmpdir=/tmp versions:set -DnewVersion=1.0.${newVersion}] was 1 while expected 0
Basically, I would like to automate the version number of the built jar files just by using ${bamboo.buildNumber} and subtracting some number so that I won't have to enter the new version number every time I run a build.
Appreciate your help... thanks,
EDIT: I posted the same question on Atlassian forum too... I will update this post when I get an answer there... https://community.atlassian.com/t5/Bamboo-questions/Bamboo-Access-script-variable-in-subsequent-maven-task/qaq-p/1104334
Generally, the best solution I have found is to output the result to a file and use the Inject Variables task to read the variable into the build.
For example, in some builds I need a SUFFIX variable, so in a bash script I end up doing
SUFFIX=suffix=-beta-my-feature
echo $SUFFIX >> .suffix.cfg
Then I can use the Inject Variables Task to read that file
Inject Variables Task
Make sure it is a Result variable and you should be able to get to it using ${bamboo.NAMESPACE.name} for the suffix one, it would be ${bamboo.VERSION.suffix}

How can I configure Jenkins to take a parameter, change it and pass to an Ant script? (!)

I realise this is probably a sub-optimal way to achieve what I'm trying to, but there are limitations I can't get round...
Given an existing Jenkins build runs a script after a maven war build, that script is an ant script to which parameters are passed.
Now I want to change the value of one of those Ant properties, using the value passed in to the build as a Jenkins parameter.
So when I call the Ant script, I want to be able to do something like:
my.ant.property = $build-parameter + "a constant string"
At the moment the errors in the log suggest $build-parameter isn't being parsed to its value, instead the value passed to the Ant script is the literal '$build-parameter'
EDIT:
I've since discovered the reason the value didn't end up in Ant script was because of a hyphen ( '-' ) in the Jenkins build parameter name.
So now the question is how do I concat that with a constant String prior to passing to Ant?
my.ant.property = $buildparameter + "a constant string"
I ended up using "Inject environment variables to the build process".
ANEWVAR=${builderparameter}aStringToAppend
Then, in the Invike Ant task:
ant.someprop=$ANEWVAR

Resources