0
votes

I have a classic Release Pipeline that has a few custom variables set that are used periodically throughout the release.

The first two steps in the release are two PowerShell scripts. In the first one, I basically take one of the variables, and assign a value to it. I then output what the variable was updated to so I can make sure it is correct (it always is). The second script does basically the same thing but to a different variable, and when I output the value, it is always correct.

Now, as the release is going, if I switch to the Variables tab, I can see the variable was never updated. It is still set at the value from the previous release. This is a major issue for me because about half way down the release, I have a "Copy Files" step, where it copies files to a folder path that is created from those variables. Since the variables are from the previous release, they are put into an improperly named folder path.

After the release pipeline is completed finished and succeeds, the Pipeline Variables are then correctly updated on the Variables tab.

Is there a way that I can update these variables DURING the release, instead of them updating after the release has completed? I would prefer to update them properly in my PowerShell scripts, or as a setting in the pipeline.

This is basically what my scripts looks like:

$url = "$($env:SYSTEM_TEAMFOUNDATIONSERVERURI)$env:SYSTEM_TEAMPROJECTID/_apis/Release/definitions/$($env:RELEASE_DEFINITIONID)?api-version=5.0-preview.3"

$pipeline = Invoke-RestMethod -Uri $url -Headers @{Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"}
Write-Host "Pipeline = $($pipeline | ConvertTo-Json -Depth 100)"

$buildNumber = $env:BUILD_BUILDNUMBER
$pipeline.variables.ReleaseVersion.value = $buildNumber

####****************** update the modified object **************************
$json = @($pipeline) | ConvertTo-Json -Depth 99

$updatedef = Invoke-RestMethod -Uri $url -Method Put -Body $json -ContentType "application/json" -Headers @{Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"}

write-host "=================================" 
write-host "The value of ReleaseVersion updated to " $updatedef.variables.ReleaseVersion.value
write-host "================================="

My variable (ReleaseVersion in the script above) is set in the Variables tab, it's scope is 'Release', and 'Settable at release time' is checked. I have also tried using Write-Host '##vso[task.setvariable variable=ReleaseVersion]$(Build.BuildNumber)' to set my variable, but I get the same outcome.

UPDATE ADDING NEW SCRIPT AND LOG DESCRIPTION

So I just pushed new code through my pipeline. The build was numbered v2.1.0.16 (which is correct). I have the build number set to the branch name, plus a (:.rev) variable at the end.

The first script in the pipeline sets a custom pipeline variable called ReleaseVersion. It is set to the build number. This is the script:

 $url = "https://vsrm.dev.azure.com/{organization}/$env:SYSTEM_TEAMPROJECTID/_apis/Release/definitions/$($env:RELEASE_DEFINITIONID)?api-version=5.0-preview.3"

$pipeline = Invoke-RestMethod -Uri $url -Headers @{Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"}
Write-Host "Pipeline = $($pipeline | ConvertTo-Json -Depth 100)"

$buildNumber = $env:BUILD_BUILDNUMBER
$pipeline.variables.ReleaseVersion.value = $buildNumber

####****************** update the modified object **************************
$json = @($pipeline) | ConvertTo-Json -Depth 99

$updatedef = Invoke-RestMethod -Uri $url -Method Put -Body $json -ContentType "application/json" -Headers @{Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"}

write-host "=================================" 
write-host "The value of ReleaseVersion updated to " $updatedef.variables.ReleaseVersion.value
write-host "================================="

and my output:

2020-05-11T03:02:21.5631557Z     "id":  #,
2020-05-11T03:02:21.5632209Z     "name":  "#",
2020-05-11T03:02:21.5632816Z     "path":  "#",
2020-05-11T03:02:21.5633410Z     "projectReference":  null,
2020-05-11T03:02:21.5634223Z     "url":  "https://vsrm.dev.azure.com/{organization}/{project}/_apis/Release/definitions/{definitionId}",
2020-05-11T03:02:21.5635058Z     "_links":  {
2020-05-11T03:02:21.5635643Z                    "self":  {
2020-05-11T03:02:21.5636500Z                                 "href":  "https://vsrm.dev.azure.com/{organization}/{project}/_apis/Release/definitions/{definitionId}"
2020-05-11T03:02:21.5637445Z                             },
2020-05-11T03:02:21.5641618Z                    "web":  {
2020-05-11T03:02:21.5643197Z                                "href":  "https://vsrm.dev.azure.com/{organization}/{project}/_apis/Release/definitions/{definitionId}"
2020-05-11T03:02:21.5644085Z                            }
2020-05-11T03:02:21.5647518Z                }
2020-05-11T03:02:21.5648322Z }
2020-05-11T03:02:22.4291104Z =================================
2020-05-11T03:02:22.4456531Z The value of ReleaseVersion updated to  v2.1.0.15
2020-05-11T03:02:22.4483349Z =================================
2020-05-11T03:02:23.0643676Z ##[section]Finishing: Update Release Version

It says the value has been updated to v2.1.0.15, which is one revision behind the current build. I then have a script to make a folder path based on the above variable. It checks for a folder with that name (v2.1.0.15 for example), and will attach a -1 if it was already found, and a -2 if the -1 was already found, and so-on. It sets that folder name to a custom pipeline variable called RootDirectory. This is the script:

$url = "https://vsrm.dev.azure.com/{organization}/$env:SYSTEM_TEAMPROJECTID/_apis/Release/definitions/$($env:RELEASE_DEFINITIONID)?api-version=5.0-preview.3"

$pipeline = Invoke-RestMethod -Uri $url -Headers @{Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"}
write-host "Pipeline = $($pipeline | ConvertTo-Json -Depth 100)"

$rootDirectory = $pipeline.variables.BuildDirectory.value + "\" + $pipeline.variables.ReleaseVersion.value

if (test-path $rootDirectory) {
    $newDirectory=$rootDirectory
    $index=0
    while (test-path $newDirectory) {
        $index += 1
        $newDirectory=$rootDirectory + "-" + $index
    } 
}

$pipeline.variables.RootDirectory.value = $newDirectory

####****************** update the modified object **************************
$json = @($pipeline) | ConvertTo-Json -Depth 99

$updatedef = Invoke-RestMethod -Uri $url -Method Put -Body $json -ContentType "application/json" -Headers @{Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"}

write-host "=================================" 
write-host "The value of Root Directory updated to " $updatedef.variables.RootDirectory.value
write-host "================================="

The BuildDirectory variable is a hardcoded variable that never changes. And it's output:

2020-05-11T15:32:45.7255688Z     "id":  #,
2020-05-11T15:32:45.7255852Z     "name":  "#",
2020-05-11T15:32:45.7256001Z     "path":  "#",
2020-05-11T15:32:45.7256166Z     "projectReference":  null,
2020-05-11T15:32:45.7256379Z     "url":  "https://vsrm.dev.azure.com/{organization}/{project}/_apis/Release/definitions/{definitionId}",
2020-05-11T15:32:45.7256556Z     "_links":  {
2020-05-11T15:32:45.7256698Z                    "self":  {
2020-05-11T15:32:45.7256903Z                                 "href":  "https://vsrm.dev.azure.com/{organization}/{project}/_apis/Release/definitions/{definitionId}"
2020-05-11T15:32:45.7257174Z                             },
2020-05-11T15:32:45.7257331Z                    "web":  {
2020-05-11T15:32:45.7257537Z                                "href":  "https://vsrm.dev.azure.com/{organization}/{project}/_apis/Release/definitions/{definitionId}"
2020-05-11T15:32:45.7257721Z                            }
2020-05-11T15:32:45.7257862Z                }
2020-05-11T15:32:45.7258016Z }
2020-05-11T15:32:46.6474274Z =================================
2020-05-11T15:32:46.6481861Z The value of Root Directory updated to  
2020-05-11T15:32:46.6491120Z =================================
2020-05-11T15:32:46.7209281Z ##[section]Finishing: Create Root Directory

Notice how the output of that script is blank, it does not show what the variable was updated to.

A few steps later in my pipeline, is where I actually use those variables. It is in a "Copy files" pipeline task. The target folder is set to $(RootDirectory)/Debug, but since the RootDirectory variable isn't updated, it just copies the files to the root c: drive.

2
How about the issue? Does the answer below resolved your question, If not, would you please let me know the latest information about this issue?Leo Liu-MSFT
I've had a lot going on and haven't gotten back to this. I will have an update for you tomorrow. Thanks for checking in.dotnetdev

2 Answers

0
votes

When I used code above with REST API ReleaseVersion remained the same as it was. However, I used logging command Write-Host '##vso[task.setvariable variable=ReleaseVersion]$(Build.BuildNumber)' and ReleaseVersion was updated but a new value was available in next step. So the new value should be available in Copy Files as it is a next step.

0
votes

Updating Azure DevOps Release Pipeline Variable During Release

First, the reason why the logging command not work for you is that:

The variable set by the logging command can only be used inside the current agent, and will not modify the value of the web potral variable.

So, we could use the set variable in the next task, but if you want to update the variable on the Variables tab, you could use the REST API (Definitions - Update) to update the value of the release definition variable from a release pipeline:

PUT https://vsrm.dev.azure.com/{organization}/{project}/_apis/release/definitions/{definitionId}?api-version=5.0

Then, I have checked your scripts, it is close to the correct answer. The reason why it doesn't work for you is that you use variable $($env:SYSTEM_TEAMFOUNDATIONSERVERURI) in your url.

The default value of that variable is https://dev.azure.com/YourOrganization/. However, the API we use is that https://vsrm.dev.azure.com/{organization}, missing vsrm in the Url.

You could check my previous thread for some more details.

Hope this helps.