Create MSBuild arguments string based on a set of boolean parameters - azure-devops

As a AzureDevops user I want to be able to manually pass different MSBuild constants (via DefineConstants) by turning checkboxes on and off on the "Run Pipeline" UI.
Example:
I achieve that by defining two boolean parameters for the current pipeline:
parameters:
- name: enableDebugErrorMessages
displayName: 'Enable debug error messages'
type: boolean
default: false
- name: enableAnalytics
displayName: 'Enable analytics'
type: boolean
default: true
Now I want to generate a string for MSBuild containing enabled constants. Examples:
/p:DefineConstants="ENABLE_ANALYTICS"
/p:DefineConstants="ENABLE_DEBUG_MESSAGES;ENABLE_ANALYTICS"
so I can pass them for MSBuild this way:
- task: XamariniOS#2
inputs:
args: '<HERE>'
I've tried all possible combination of expressions from the documentation I could think of except I want to do something that is not supported by expressions.

UPDATED: I took (another) crack at it on a trivial pipeline and came up with this:
pool: MyBuildPool
parameters:
- name: ENABLE_ANALYTICS
displayName: "Analytics"
type: boolean
default: false
- name: ENABLE_DEBUG_MESSAGES
displayName: "Debug Messages"
type: boolean
default: true
- name: ENABLE_SOMETHING_ELSE
displayName: "Something Else"
type: boolean
default: false
variables:
- ${{ each p in parameters }}:
- name: "DEFINECONSTANT_${{p.key}}"
value: ${{ p.value }}
steps:
- pwsh: |
$constantVars = Get-ChildItem -Path Env:\ | Where-Object Name -like "DEFINECONSTANT_*"
$constantList = ""
$constantVars | ForEach-Object {
$constantList += "$($_.Name.Replace('DEFINECONSTANT_', ''))=$($_.Value);"
}
Write-Host "/p:DefineConstants=`"$constantList`""
displayName: 'Combine parameter values'
When I have Azure Pipelines expand that file, I get:
parameters:
- name: ENABLE_ANALYTICS
displayName: "Analytics"
type: boolean
default: false
- name: ENABLE_DEBUG_MESSAGES
displayName: "Debug Messages"
type: boolean
default: true
- name: ENABLE_SOMETHING_ELSE
displayName: "Something Else"
type: boolean
default: false
variables:
- name: DEFINECONSTANT_ENABLE_ANALYTICS
value: False
- name: DEFINECONSTANT_ENABLE_DEBUG_MESSAGES
value: True
- name: DEFINECONSTANT_ENABLE_SOMETHING_ELSE
value: False
stages:
- stage: __default
jobs:
- job: Job
pool:
name: MyPoolName
steps:
- task: PowerShell#2
displayName: 'Combine parameter values'
inputs:
targetType: inline
script: |
$constantVars = Get-ChildItem -Path Env:\ | Where-Object Name -like "DEFINECONSTANT_*"
$constantList = ""
$constantVars | ForEach-Object {
$constantList += "$($_.Name.Replace('DEFINECONSTANT_', ''))=$($_.Value);"
}
Write-Host "/p:DefineConstants=`"$constantList`""
pwsh: true
Is that closer to what you want? You can have checkboxes with different constant names, descriptions, and default values.

You could use If expression to set the value of the corresponding variable based on the value of the boolean parameter.
Here is the sample:
variables:
${{ if and(parameters.enableDebugErrorMessages, 'true', ne(parameters.enableAnalytics, 'true')) }}:
DefineConstants: ENABLE_DEBUG_MESSAGES
${{ if and(parameters.enableDebugErrorMessages, 'true', eq(parameters.enableAnalytics, 'true')) }}:
DefineConstants: ENABLE_DEBUG_MESSAGES;ENABLE_ANALYTICS
${{ if and(parameters.enableAnalytics, 'true', ne(parameters.enableDebugErrorMessages, 'true')) }}:
DefineConstants: ENABLE_ANALYTICS
parameters:
- name: enableDebugErrorMessages
displayName: 'Enable debug error messages'
type: boolean
default: false
- name: enableAnalytics
displayName: 'Enable analytics'
type: boolean
default: true
pool:
vmImage: ubuntu-latest
steps:
...
In MSbuild argument, you could use the following format: /p:DefineConstants= "$(DefineConstants)".
select enableDebugErrorMessages -> $(DefineConstants) =
ENABLE_DEBUG_MESSAGES
select enableAnalytics -> $(DefineConstants) = ENABLE_ANALYTICS
select both -> $(DefineConstants) =
ENABLE_DEBUG_MESSAGES;ENABLE_ANALYTICS

Related

Azure devops yaml, filter parameter with string

Short question: how do I do the "enable" part in the pipeline below?
Long question: I have 3 jobs that I need to generate dynamically based on the parameters "params" due to business requirements. The job generated only works if the Job1, Job2 or Job3 is selected as true. Can I access parameters using string like dynamic in c#? ie: parameters["Job1"] or parameters["Job2"] or parameters["Job3"] ?
trigger: none
#Package Parameter
parameters:
- name: Job1
displayName: 'Job1'
type: boolean
default: false
- name: Job2
displayName: 'Job2'
type: boolean
default: false
- name: Job3
displayName: 'All Teams'
type: boolean
default: false
- name: 'params'
type: object
default: ["Job1",
"Job2",
"Job3"]
pool:
vmImage: ubuntu-latest
stages:
- stage: Build_dev
dependsOn:
jobs:
- ${{ each testJob in parameters.params }}:
- job:
enable: **If(parameters[testJob] == true) then enable this job**
displayName: Build ${{ testJob }}
steps:
- script: Build ${{ testJob }}
This is one way you can disable the jobs that are not set as true in the parameters. You can also use conditions for your jobs to skip them
azure-pipeline.yml
trigger: none
#Package Parameter
parameters:
- name: Job1
displayName: 'Job1'
type: boolean
default: false
- name: Job2
displayName: 'Job2'
type: boolean
default: false
- name: Job3
displayName: 'All Teams'
type: boolean
default: false
pool:
vmImage: ubuntu-latest
stages:
- stage: Build_dev
dependsOn: []
jobs:
- ${{ each parameter in parameters }}:
- ${{ if eq(parameter.Value, 'true') }}:
- template: job-template.yml
parameters:
jobName: ${{ parameter.Key }}
job-template.yml
parameters:
jobName: ''
jobs:
- job: ${{ parameters.jobName }}
displayName: Build ${{ parameters.jobName }}
steps:
- script: echo "Build ${{ parameters.jobName }}"

How to convert string variable to object and pass it to another pipeline?

I have two Azure Devops pipelines: 'Starter' and 'Processing'. 'Starter' triggers 'Processing' and passes some parameters to it.
Starter:
trigger: none
pool:
vmImage: 'windows-2019'
stages:
- stage: A
jobs:
- template: Processing.yml
parameters:
products: $(Products)
creds: $(Creds)
Processing:
parameters:
- name: products
type: object
default: []
- name: creds
default: ''
jobs:
- ${{ each product in parameters.products }}:
- task: PowerShell#2
displayName: Importing ${{ product }} solution
inputs:
targetType: 'inline'
script: |
#Code
Key detail here is opportunity to loop through 'products' variable (each product in parameters.products), which must be setted in 'Starter' variables:
In other words, starting my pipeline I must pass list of products as 'string' and then loop through this list in second pipeline. 'Is it generally possible? Maybe products should be another type? I tried some work around but didn't get appropriate solution:
- job: Prepare_Products_Array
steps:
- task: PowerShell#2
inputs:
targetType: 'inline'
script: |
# Write your PowerShell commands here.
$productsArray = []
$productsArray = $(Products)
$productsArray = $productsArray.Split(',')
Write-Host ("##vso[task.setvariable variable=productsArray;]$productsArray")
- template: Processing.yml
parameters:
products: $env:productsArray
Exception:
From your yaml sample, you are defining the variable in YAML Pipeline UI and using parameters in YAML Template.
In this case, the variables defined on the UI will be assigned at runtime, but the parameters and expressions in the YAML template will be expanded at compile time.
Therefore, YAML UI variables cannot be passed to the Pipeline YAML Template.
And it will show the error:
Expected a...... Actual value $(Product)
This means that the pipeline variable not expanded at compile time.
I am afraid that there is no such method can pass the UI Pipeline variable to YAML Template.
Here are the workarounds:
Method 1 : You can use parameters in Starter yaml to pass the Object type parameters to YAML template.
Starter:
trigger: none
parameters:
- name: products
type: object
default: []
- name: creds
default: ''
pool:
vmImage: 'windows-2019'
stages:
- stage: A
jobs:
- template: Processing.yml
parameters:
products: ${{ parameters.products }}
creds: ${{ parameters.creds }}
Processing:
parameters:
- name: products
type: object
default: []
- name: creds
default: ''
jobs:
- job: test
steps:
- ${{ each product in parameters.products }}:
- task: PowerShell#2
displayName: Importing ${{ product }} solution
inputs:
targetType: 'inline'
script: |
echo ${{ product }}
Result: You can input the value when you run the pipeline.
Method2: You need to define the variable in Starter pipeline and change the products parameters as String type. Then you can use the expression - ${{ each product in split(parameters.products, ',')}}: to split the string.
Starter:
pool:
vmImage: 'windows-2019'
variables:
products: '1,2,3'
creds: test
stages:
- stage: A
jobs:
- template: Processing.yml
parameters:
products: ${{ variables.products }}
creds: ${{ variables.creds }}
Processing:
parameters:
- name: products
type: string
default: ''
- name: creds
default: ''
jobs:
- job: test
steps:
- ${{ each product in split(parameters.products, ',')}}:
- task: PowerShell#2
displayName: Importing ${{ product }} solution
inputs:
targetType: 'inline'
script: |
echo ${{ product }}

Azure Pipelines YAML parameter inside parameter name (dynamic parameter name)

I have a YAML template with parameters:
- name: Deploy_Test1
type: boolean
default: false
- name: Tests
type: object
default:
- "Test1"
- "Test2"
After that I iterate the Tests with each:
- ${{ each test in parameters.Tests}}:
Inside the each I can get the test value with ${{test}}.
I want to use the parameter Deploy_Test1 but dynamically, for example:
echo ${{ parameters.Deploy_${{test}} }}
In the above syntax I get an error that is invalid.
Is there is a way or a workaround to do it?
You need to use two loops here and check if you find your key.
parameters:
- name: Deploy_Test1
type: boolean
default: false
- name: Tests
type: object
default:
- "Test1"
- "Test2"
trigger: none
pool:
vmImage: ubuntu-latest
steps:
- ${{ each test in parameters.Tests}}:
- ${{ each parameter in parameters }}:
- ${{ if eq(parameter.key, format('Deploy_{0}', test)) }}:
- script: echo ${{ parameter.value }}
And then you will get:

How to Pass Azure Devops Parameters to pscore script

parameters:
- name: BlobURL
type: string
default: ""
stages:
- stage: ProcessMetaDataFile
displayName: 'Process'
jobs:
- job: Upload
displayName: upload
steps:
- checkout: self
- pwsh: ./psscript.ps1
env: { Cont: "my Test",BlobURL: ???BlobURL }
Above is the script:
I want to pass yaml parameter to pwsh script.
tried ${{parameters.BlobURL}} ${parameters.BlobURL}
$[parameters.BlobURL] '${parameters.BlobURL}'
None worked so far
Tried this as well https://daniel-krzyczkowski.github.io/Parameters-In-Azure-DevOps-Pipelines/ but no success
Both '${{ parameters.BlobURL }}' and "${{ parameters.BlobURL }}" are correct. Just make sure the expression is inside of a string.
Also check your indentation: "steps" needs to be on the same column as "displayName":
parameters:
- name: BlobURL
type: string
default: ""
stages:
- stage: ProcessMetaDataFile
displayName: 'Process'
jobs:
- job: Upload
displayName: upload
steps:
- checkout: self
- pwsh: ./psscript.ps1
env: { Cont: "my Test", BlobURL: '${{ parameters.BlobURL }}' }

azure devOps yml pipeline: pass Boolean value to task prisma-cloud-compute-scan#2 written in template

I want to send Boolean value to task 'prisma-cloud-compute-scan#2' written in a template file.
It always gives below error.
Error: The 'prisma_continue_on_error' parameter value '$(prismaContinueOnError)' is not a valid Boolean.
Main pipeline abc.yml
resources:
repositories:
- repository: templates
type: git
name: my_projects/my-build-templates
ref: refs/heads/features/add-build-template
variables:
name: prismaContinueOnError
value: false
isMainBranch: $[eq(variables['Build.SourceBranch'], 'refs/heads/master')]
stages:
- stage: "Build"
displayName: Build
jobs:
- template: my_build_stage/my_template.yml#templates
parameters:
prisma_continue_on_error: $(prismaContinueOnError)
Template my_template.yml
parameters:
- name: prisma_continue_on_error
type: boolean
default: false
- name: pool_name
type: string
default: abc_pool
jobs:
- job: Build
pool:
name: ${{parameters.pool_name}}
steps:
- task: prisma-cloud-compute-scan#2
inputs:
scanType: 'images'
twistlockService: 'SERVICE_CONNECTIONM_NAME'
artifact: ...
continueOnError: ${{parameters.prisma_continue_on_error}}
You mixed syntaxes here
variables:
name: prismaContinueOnError
value: false
isMainBranch: $[eq(variables['Build.SourceBranch'], 'refs/heads/master')]
it should be:
variables:
prismaContinueOnError: false
isMainBranch: $[eq(variables['Build.SourceBranch'], 'refs/heads/master')]
But this will not solve the issue, because variables are just string. You can't have variable of type boolean. You need to pass there runtime expression which delay type evaluation:
stages:
- stage: "Build"
displayName: Build
jobs:
- template: my_build_stage/my_template.yml#templates
parameters:
prisma_continue_on_error: ${{ variables.prismaContinueOnError }}