In a yml step template I'm using the DownloadPipelineArtifact@2 to download a specific artifact produced from my build pipeline.
Since the artifact is quite big and, depending on the cases, I don't need all the whole artifact content, I'm providing the itemPattern property as input parameter to my step template and passing as it is to the DownloadPipelineArtifact@2 task to perform some filtering operations and speed up the build.
Below a simplified version of the step template I've implemented, called filteredDownloadArtifact:
parameters:
artifactItemPattern: '**'
steps:
- task: DownloadPipelineArtifact@2
displayName: 'Download artifact'
inputs:
buildType: 'current'
artifactName: 'MyArtifact'
itemPattern: |
${{ parameters.artifactItemPattern}}
It seems it's working fine when I provide just one pattern but I'm experiencing some issue when I provided multiple item patterns to be downloaded.
For example, in another yml step template I've a pwsh task used to determine which folders should be downloaded
- powershell: |
$itemPattern= (("$(fileCollection)" -split ' ') | ForEach-Object {
$dllName = [System.IO.Path]::GetFileName($_)
$_.replace($dllName, '**')
}) -join "`r`n"
Write-Host "##vso[task.setvariable variable=_itemPattern]$itemPattern"
and then I consume the filteredDownloadArtifact this way:
- template: filteredDownloadArtifact.yml
parameters:
artifactItemPattern: |
$(_itemPattern)
But it doesn't seem to work. Only one item pattern is provided to my step template.
So, is there a different way to consume multiline parameters when passed to an Azure DevOps step template? Thanks
I have checked your YAML sample. Here are the two limitations:
1.When you use the setvariable logging command to create the variable, it only supports One line string. If you need to use multiple lines string, you need to hardcode the variable with the following format:
variables:
- name: files
value: |
file1
file2
2.The setvariable logging command will set the variable at runtime, but the parameter: artifactItemPattern
in the template will read the value at compile time. In this case, the variable value can not passed to the template successfully.
To use parameters to pass the multiple line string, you can use the following format:
parameters:
- name: artifactItemPattern
type: object
default: |
file1
file2
steps:
....
- task: DownloadPipelineArtifact@2
displayName: 'Download artifact'
inputs:
buildType: 'current'
artifactName: 'MyArtifact'
itemPattern: ${{ parameters.artifactItemPattern}}
Based on your description, you need to use PowerShell to set the variable and download the files based on the variable value.
To meet this requirement, I suggest that you can split the Pipelines into two. One is used to set the files value and use Rest API to trigger Pipeline two. Pipeline two is used to collect the input value and download artifacts.
Here is an example:
Pipeline One:
variables:
- name: fileCollection
value: value1 value2
steps:
- powershell: |
$itemPattern= (("$(fileCollection)" -split ' ') | ForEach-Object {
$dllName = [System.IO.Path]::GetFileName($_)
$_.replace($dllName, '**')
}) -join "\n "
echo $itemPattern
$token = "$(pat)"
$url="https://dev.azure.com/{organizationname}/{ProjectName}/_apis/pipelines/{PipelineID}/runs?api-version=5.1-preview"
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($token)"))
$JSON = "
{
`"resources`": {
`"repositories`": {
`"self`": {
`"ref`": `"refs/heads/main`"
}
}
},
`"templateParameters`": {
`"InputartifactItemPattern`":`"|\n $itemPattern`"
},
}"
$response = Invoke-RestMethod -Uri $url -Headers @{Authorization = "Basic $token"} -Method Post -Body $JSON -ContentType application/json
Pipeline Two
Pipeline Two Template:
parameters:
- name: artifactItemPattern
type: object
steps:
....
- task: DownloadPipelineArtifact@2
displayName: 'Download artifact'
inputs:
buildType: 'current'
artifactName: 'MyArtifact'
itemPattern: ${{ parameters.artifactItemPattern}}
- script: |
cd $(pipeline.workspace)
ls
Pipeline Two Main Yaml:
parameters:
- name: InputartifactItemPattern
type: object
jobs:
- template: filteredDownloadArtifact.yml
parameters:
artifactItemPattern: ${{parameters.InputartifactItemPattern}}
Update:
To hardcode the variables or parameters to pass the multiline string, we can use the following format:
Parameters:
parameters:
- name: InputartifactItemPattern
type: object
default: |
file1
file2
jobs:
- template: filteredDownloadArtifact.yml
parameters:
artifactItemPattern: ${{parameters.InputartifactItemPattern}}
Template YAML:
parameters:
- name: artifactItemPattern
type: object
steps:
....
- task: DownloadPipelineArtifact@2
displayName: 'Download artifact'
inputs:
buildType: 'current'
artifactName: 'MyArtifact'
itemPattern: ${{ parameters.artifactItemPattern}}
Variables:
variables:
- name: _itemPattern
value: |
file1
file2
- template: filteredDownloadArtifact.yml
parameters:
artifactItemPattern: $(_itemPattern)
Template YAML:
parameters:
artifactItemPattern: '**'
steps:
- task: DownloadPipelineArtifact@2
displayName: 'Download artifact'
inputs:
buildType: 'current'
artifactName: 'MyArtifact'
itemPattern: |
${{ parameters.artifactItemPattern}}