Search code examples
azure-devopsazure-pipelinesazure-devops-rest-apiazure-devops-server-2019

How to update current stage release variable in Azure DevOps Server 2019 using the REST API?


I want to update the value of a release (not the release definition) scoped variable while the stage is running but every time I try I receive following error message.

How can I do this please?

##[error]Invoke-RestMethod : {"$id":"1","innerException":null,"message":"VS402898: Stage 'dev' cannot be modified as it is 
in-progress or completed. Changes were detected in the following properties: 
'Variables'","typeName":"Microsoft.VisualStudio.Services.ReleaseManagement.Data.Exceptions.InvalidRequestException, Mic
rosoft.VisualStudio.Services.ReleaseManagement2.Data","typeKey":"InvalidRequestException","errorCode":0,"eventId":3000}
At line:263 char:5

+     Invoke-RestMethod -Uri $url -Method Put -ContentType "application ...

+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebExc 

   eption

    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
2020-11-03T06:45:48.2096034Z ##[error]PowerShell exited with code '1'.

Example script:

$url = "{0}{1}/_apis/Release/releases/{2}?api-version=5.0" -f $env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI, $env:SYSTEM_TEAMPROJECTID, $env:RELEASE_RELEASEID

$pipeline = Invoke-RestMethod -Uri $url -Method Get -Headers @{
    Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
}

# Update an existing scoped variable named TestVar
# Just for StackOverflow we assume that the currently running stage in Azure DevOps Server
# matches this environment[0] below
$pipeline.environments[0].variables.TestVar.value = "NewValue"

$body = $pipeline | ConvertTo-Json -Depth 99

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

Just in case there is another solution out there... What I'm trying to achieve is to have the variable output of a PowerShell script later be used in a separate 'Substitute Files' JSON transformation step to populate the value within an appsettings.json file for a web application. The problem is that the variable is being created in one job, and isn't being used by the Substitute Files step as I assume it needs to be a release variable, not just task variable.


Solution

  • It seems that you are using this REST API, according to the error message VS402898: Stage 'dev' cannot be modified as it is in-progress or completed and doc description. We could only use it to update a complete release.

    As a workaround, we could change the variable value when we create release.

    My test steps: Create a release variable->name it test and set value to 55->Enable the option Settable at release time->add task power shell to print variable test value

    Then call the rest API to create release and update runtime release variable.

    Note: It will not change the release definition variable.

    API:

    POST https://{instance}/{collection}/{project}/_apis/release/releases?api-version=5.0
    

    Request Body:

    {
      "definitionId": {Release definition ID},
      "artifacts": [
      ],
      "variables": {
        "test": {
          "value": "99"
        }
      }
    }
    

    Result:

    enter image description here

    Update1

    It seems that you want to pass variable between agent jobs, we cannot do this in the classic mode, we could use output variables in the YAML mode, please refer to this doc and blog for more details.

    Sample code.

    jobs:
    - job: A
      steps:
      - task: MyTask@1  # this step generates the output variable
        name: ProduceVar  # because we're going to depend on it, we need to name the step
    - job: B
      dependsOn: A
      variables:
        # map the output variable from A into this job
        varFromA: $[ dependencies.A.outputs['ProduceVar.MyVar'] ]
      steps:
      - script: echo $(varFromA) # this step uses the mapped-in variable