What is the correct way to access ADO yaml parameters in bash script? - azure-devops

I have a template that is called and passed a set of parameters. I would like to use these in a bash script. When I define an inline bash script I can easily print the parameters out with ${{ parameter.foo }}. However if I define a bash script as a file and call it I'm unable to access the parameters.
Here is a sample template, 'Inline Test' will spit out the parameters where as 'File Test' wont. So far two possible solutions I can see are, defining the parameter value as a 'task variable' and accessing it as $foo (example Inline Test), or potentially pass the parameter in as an argument to the 'File Test' task (example File Test 2). Is there an option to access yaml template parameters in an existing bash script from file and not one that is defined inline?
parameters:
- name: webappName #webappName
type: string
default: webappName #set default for testing
- name: resourceGroup #resourceGroup
type: string
default: resourceGroupName #set default for testing
- name: subscription #subscription
type: string
default: s #set default for testing
- name: preprod
type: boolean
default: false #default to false
- name: env
type: string
default: test
- name: role
type: string
default: s
steps:
- checkout: 'x' #the repo that test.sh lives in
- task: Bash#3
inputs:
displayName: 'Inline test'
targetType: 'inline'
script: |
echo "-----"
echo ${{ parameters.webappName }}
echo "-----"
echo ${{ parameters.resourceGroup }}
echo "-----"
echo ${{ parameters.subscription }}
echo "-----"
echo ${{ parameters.preprod }}
echo "-----"
echo ${{ parameters.env }}
echo "-----"
echo ${{ parameters.role }}
echo "-----"
echo "##vso[task.setvariable variable=TESTROLE]${{ parameters.role }}"
echo "-----"
- task: Bash#3
displayName: 'File test'
inputs:
filePath: './test.sh'
- task: Bash#3
displayName: 'File test 2'
inputs:
arguments: ${{ parameters.role }}
filePath: './test.sh'

AzDev just substitute values in the inline scripts, so the ${{ name }} is some kind of placeholder. And AzDev doesn't read script files, so doesn't substitute values there.
You can use environment variables for bash task:
- task: Bash#3
displayName: 'File test 2'
inputs:
filePath: './test.sh'
env:
APP_ROLE: ${{ parameters.role }}
And then you could use this env variable in your script file:
echo $APP_ROLE

Related

using pipeline parameters in template

I have defined parameters in both pipeline YAML file and template file. How can I access the parameters defined in pipeline within the template ??
Pipeline file
parameters:
- name: LIQUIBASE_DATABASE_URL
displayName: JDBC Connection String
type: string
default: ''
- name: LIQUIBASE_COMMAND_USERNAME
displayName: Liquibase user name
type: string
default: ''
- name: LIQUIBASE_COMMAND_PASSWORD
displayName: Liquibase password
type: string
default: ''
trigger: none
stages:
- stage: VersionUpgrade
jobs:
Template file
# File Name : run-upgrade-template.yml
parameters:
- name: upgradeVersionList
type: object
default: [2,3,4]
steps:
- task: Bash#3
inputs:
targetType: 'inline'
script: |
echo "changeLogFile: $(Pipeline.Workspace)/database/db-changelog.sql" > liquibase.properties
echo "url: ${{ LIQUIBASE_DATABASE_URL }}" >> liquibase.properties
echo "username: ${{ LIQUIBASE_COMMAND_USERNAME }}" >> liquibase.properties
echo "password: ${{ LIQUIBASE_COMMAND_PASSWORD }}" >> liquibase.properties
cat liquibase.properties
I am getting error
pipeline-templates/run-upgrade-template.yml (Line: 12, Col: 13): Unrecognized value: 'LIQUIBASE_DATABASE_URL'. Located at position 264 within expression: format('echo "changeLogFile: $(Pipeline.Workspace)/database/db-changelog.sql" > liquibase.properties
echo "url: {0}" >> liquibase.properties
echo "username: {1}" >> liquibase.properties
echo "password: {2}" >> liquibase.properties
cat liquibase.properties
', LIQUIBASE_DATABASE_URL, LIQUIBASE_COMMAND_USERNAME, LIQUIBASE_COMMAND_PASSWORD).
Appreciate any pointers to resolve this issue.
There are a bunch of issues here.
Your template also needs a parameters block with those parameters defined, and those parameters need to be passed in to the template.
Your syntax for accessing parameters is incorrect. ${{ LIQUIBASE_COMMAND_USERNAME }} should be ${{ parameters.LIQUIBASE_COMMAND_USERNAME }}

Azure Dev Ops replace function not working on \\

I have a template like
parameters:
Server: ''
steps:
- powershell: echo "${{ parameters.Server }}"
- powershell: echo "${{ replace(parameters.Server, '\\', '\') }}"
- powershell: echo "${{ replace(parameters.Server, '\\\\', '\') }}"
- powershell: echo "${{ replace(parameters.Server, '\\\\', '\\') }}"
- powershell: echo "${{ replace(parameters.Server, '\', '\\') }}"
- powershell: echo "${{ replace(parameters.Server, 'parameters', 'xxx') }}"
and use it like
- template: 'path'
parameters:
Server: $(Server.Variable)
where the variable Server.Variable is defined on the stage level as host\\path
but the output is
host\\path
host\\path
host\\path
host\\path
host\\path
host\\path
so what am I doing wrong.
My solution now is to create a new variable at the job level which is defined using a runtime expression and give the changed variable into the template
jobs:
- job:
variables:
Changed.Server.Variable: $[ replace(variables['Server.Variable'], '\\', '\') ]
steps:
...
- template: 'path'
parameters:
Server: $(Changed.Server.Variable)
but I would like a solution more where we can change the value in the template, but I don't know how.

Azure DevOps Pipeline decorator error on - ${{ each step in job.steps }}:

I have a simple pipeline decorator :
steps:
- ${{ each step in job.steps }}:
- ${{ if eq(step.task.id, '2ff763a7-ce83-4e1f-bc89-0ae63477cebe') }}:
- task: powershell#2
displayName: '(injected) Verify Publish Artifact task parameters'
inputs:
targetType: inline
script: |
$s = #'
${{convertToJson(step)}}
'#
$step = ConvertFrom-Json $s
Write-Host "todo: validate the step parameters"
It raises an error.
Here is the log :
Begin evaluating template 'BuildPreJob.yml#'
Evaluating: job['steps']
Result: Object
[error]BuildPreJob.yml# (Line: 2, Col: 5):
Finished evaluating template 'BuildPreJob.yml#'
Doesn't matter what else is in the yaml file. It doesn't work as long as it contains this
- ${{ each step in job.steps }}:
For example this one doesnt work as well
steps:
- ${{ each step in job.steps }}:
- task: powershell#2
displayName: '(injected) Verify each step'
inputs:
targetType: inline
script: |
Write-Host "todo: validate the step parameters"
It raises the same error.
Is there any suggestion ?
Do you know where I can find a full documentation?
here is the log :
Begin evaluating template 'BuildPreJob.yml#'
Evaluating: job['steps']
Result: Object
[error]BuildPreJob.yml# (Line: 2, Col: 5):
Finished evaluating template 'BuildPreJob.yml#'
Is that the whole template file? You need a parameters section, where you would declare jobs/steps passed to your template.
Here's a working example (based on templates docs):
# decorator.yaml
parameters:
- name: "jobs"
type: jobList
default: []
jobs:
- ${{ each job in parameters.jobs }}: # Each job
- ${{ each pair in job }}: # Insert all properties other than "steps"
${{ if ne(pair.key, 'steps') }}:
${{ pair.key }}: ${{ pair.value }}
steps:
- ${{ each step in job.steps }}:
- pwsh: |
$s = #'
${{convertToJson(step)}}
'#
write-host "step as json:"
Write-Host $s
displayName: "(injected) debug step"
- ${{ step }}
# pipeline.yaml
variables:
system.debug: true
stages:
- stage: decorated
jobs:
- template: decorator.yaml
parameters:
jobs:
- job: A
steps:
- script: echo something really fancy.
- job: B
steps:
- script: echo and another!

Azure DevOps variable empty between steps

I am trying to read a text file using bash in a AZDO pipeline template, but for some reason the variable containing the name of the file is empty:
##deploy-to-env.yml
parameters:
- name: env
type: string
default: ""
- name: envLong
type: string
default: ""
stages:
- stage: "deployTo${{ parameters.envLong }}"
displayName: "Deploy to ${{ parameters.env }}"
variables:
- name: releasesFile
value: ""
jobs:
- deployment:
environment: "${{ parameters.env }}"
displayName: "Deploy to ${{ parameters.env }}"
strategy:
runOnce:
deploy:
steps:
- task: Bash#3
name: FindReleaseFile
displayName: "Find the releases.txt file"
inputs:
targetType: 'inline'
script: |
echo "##vso[task.setvariable variable=releasesFile;isOutput=true]$(find $(Build.SourcesDirectory) -name releases.txt -maxdepth 1 -type f 2>/dev/null)"
- task: Bash#3
name: DownloadUsingArtifactTool
displayName: "Download Using Artifact Tool"
inputs:
targetType: 'inline'
script: |
echo "$(FindReleaseFile.releasesFile)"
The pipeline looks like this:
trigger:
branches:
include:
- azure-pipelines
paths:
include:
- "releases.txt"
stages:
- template: deploy-to-env.yml
parameters:
env: "tst"
envLong: "Test"
How can I pass the releasesFile variable to the 2nd task in deploy-to-env.yml template?
The problem was the the repository was not cloned, adding checkout: self in the steps fixed it

Is it possible to use aliases for pipeline parameters in Azure DevOps?

Let's say I have the following parameters in my pipeline:
parameters:
- name: environment
displayName: 'Environment'
default: 'SERVER_0562'
type: string
values:
- 'SERVER_0562'
- 'SERVER_5149'
- 'SERVER_1892'
But I don't want whoever is running the pipeline to see these names when selecting the Environment from the dropdown list. I want then to see the following names:
- QA Server
- DEV Server
- PROD Server
Is there any "easy" way to do so or the only way would be to deal with conditionals?
${{ if eq(parameters.environment, 'DEV Server') }}:
Please check this:
parameters:
- name: image
displayName: Pool Image
type: string
default: Ubuntu
values:
- Windows
- Ubuntu
- MacOS
trigger: none
jobs:
- job: build
displayName: build
pool:
${{ if eq(parameters.image, 'Ubuntu') }}:
vmImage: 'ubuntu-latest'
${{ if eq(parameters.image, 'Windows') }}:
vmImage: 'windows-latest'
${{ if eq(parameters.image, 'MacOS') }}:
vmImage: 'macOS-latest'
steps:
- script: echo building $(Build.BuildNumber) with ${{ parameters.image }}
After you changed a question I think this may help you
parameters:
- name: environment
displayName: 'Environment'
default: 'QA Server'
type: string
values:
- 'QA Server'
- 'DEV Server'
- 'PROD Server'
trigger: none
variables:
- name: QA
value: 'SERVER_0562'
- name: DEV
value: 'SERVER_5149'
- name: PROD
value: 'SERVER_1892'
jobs:
- job: build
displayName: build
pool:
vmImage: 'windows-latest'
steps:
- script: echo building $(Build.BuildNumber) with ${{ parameters.environment }}
- powershell: |
If('${{ parameters.environment }}' -eq 'QA Server') {
Write-Host '##vso[task.setvariable variable=folderName;isOutput=true]$(QA)'
} ElseIf('${{ parameters.environment }}' -eq 'DEV Server') {
Write-Host '##vso[task.setvariable variable=folderName;isOutput=true]$(DEV)'
} ElseIf('${{ parameters.environment }}' -eq 'PROD Server') {
Write-Host '##vso[task.setvariable variable=folderName;isOutput=true]$(PROD)'
} Else {
Write-Host 'I am here'
}
name: setFolderName
- powershell: |
Write-Host '$(setFolderName.folderName)'
Inspired by the contribution of #Krzysztof Madej, I ended up solving my own issue by conditionally assigning variables:
parameters:
- name: environment
displayName: 'Environment'
default: 'QA Server'
type: string
values:
- 'QA Server'
- 'DEV Server'
- 'PROD Server'
trigger: none
variables:
${{ if eq(parameters.environment, 'QA Server') }}:
bacon: SERVER_0562
${{ if eq(parameters.environment, 'DEV Server') }}:
bacon: SERVER_5149
${{ if eq(parameters.environment, 'PROD Server') }}:
bacon: SERVER_1892
jobs:
- job: build
displayName: build
steps:
- script: echo building $(Build.BuildNumber) with ${{ variables.bacon }}
I believe this is an easier implementation since I'm not dependent on a PowerShell script.