aws-toolkit-azure-devops
aws-toolkit-azure-devops copied to clipboard
Task "Output Variables" are not available to Dependent Stages
Summary
When reading the documentation regarding output variables (such as the Elastic Beanstalk Create App Version task), I got the impression the variable would be available as other output variables, such as in this example from the Azure documentation. That documentation shows this example:
stages:
- stage: One
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
- stage: Two
- job: B
variables:
# map the output variable from A into this job
varFromA: $[ stageDependencies.One.A.outputs['ProduceVar.MyVar'] ]
steps:
- script: echo $(varFromA) # this step uses the mapped-in variable
In this example, the output variable from stage One, task ProduceVar is available to the second stage through the stageDependencies object. I assumed the AWS Toolkit output variables would behave this way, too, given their names as "output variables".
When I ran some tests, however, I found the values passed to the task's output variable was not available to other stages. Here's a simple pipeline I ran to exercise this task:
stages:
- stage: build
jobs:
- job: CI_Build
steps:
# a few tasks to build the zipped artifact
- task: BeanstalkCreateApplicationVersion@1
name: createNewEbAppVer
inputs:
awsCredentials: 'AWS CI/CD Admin'
regionName: 'us-east-1'
applicationName: 'my-api'
applicationType: 's3'
deploymentBundleBucket: 'my-bucket'
deploymentBundleKey: 'build/$(Build.BuildId).zip'
outputVariable: 'versionLabel'
- bash: echo "##vso[task.setvariable variable=testStageOutputVar;isOutput=true]this is a stage output var"
name: setVarTest
- task: Bash@3
name: OutputTest
inputs:
targetType: 'inline'
script: |
echo versionLabel: $(versionLabel) # outputs something like 'v1637798886271'
echo buildStageVar: $(buildStageVar) # outputs 'this is a stage output var'
- stage: deploy
dependsOn: build
variables:
buildStageVar: $[ stageDependencies.build.CI_Build.outputs['setVarTest.testStageOutputVar'] ]
versionLabel: $[ stageDependencies.build.CI_Build.outputs['createNewEbAppVer.versionLabel'] ]
jobs:
- job: deploy
steps:
- task: Bash@3
name: OutputTest
inputs:
targetType: 'inline'
script: |
echo versionLabel: $(versionLabel) # outputs ''
echo buildStageVar: $(buildStageVar) # outputs 'this is a stage output var'
Notice in the OutputTest task, the versionlabel variable outputs an empty string. I wanted to understand why. Upon a closer inspection of the BeanstalkCreateApplicationVersion/TaskOperations code (see this line), I found a call to the azure-pipelines-task-lib/task.js: setVariable function. In all usages of this function in the AWS Toolkit project, the isOutput parameter is not passed, and so it is set to false by default. Thus, the task "output variable" is only exposed to the job and is not available to dependent stages.
Suggestions
I see two possible paths forward:
- Clarify in the AWS Toolkit for Azure DevOps user guide the true scope of the task output variables. Ensure that future developers know that the output not available to other stages.
- Modify the various tasks' call to
setVariableto passisOutput = trueso the variable will be available as an output to dependent
Workaround
Here's a possible workaround to expose the variable to other stages:
stages:
- stage: build
jobs:
- job: CI_Build
steps:
# a few tasks to build the zipped artifact
- task: BeanstalkCreateApplicationVersion@1
name: createNewEbAppVer
inputs:
awsCredentials: 'AWS CI/CD Admin'
regionName: 'us-east-1'
applicationName: 'my-api'
applicationType: 's3'
deploymentBundleBucket: 'my-bucket'
deploymentBundleKey: 'build/$(Build.BuildId).zip'
outputVariable: 'versionLabel'
- bash: echo "##vso[task.setvariable variable=versionLabel;isOutput=true]$(versionLabel)"
displayName: 'Set stage output variables'
name: setOutputs
- stage: deploy
dependsOn: build
variables:
versionLabel: $[ stageDependencies.build.CI_Build.outputs['setOutputs.versionLabel'] ]
jobs:
- job: deploy
steps:
- bash: echo 'versionLabel: $(versionLabel)' # outputs something like 'v1637798886271'
name: VariableTest
In the above example, the setOutputs step loads the local task variable into a stage output variable so it can be referenced in the next stage.
I have the same problem using "ECRPushImage@1", it seems to expose the variable using isOutput=false; which doesn't allow the variable to be propagated in future jobs.
Here the DevOps doc about this: Set a multi-job output variable
example:
trigger:
- main
pool:
vmImage: ubuntu-latest
jobs:
- job: Build
steps:
- task: ECRPushImage@1
name: EcrPushImage
displayName: 'Push to AWS ECR'
inputs:
awsCredentials: 'AWS-Prod'
regionName: 'us-east-1'
imageSource: 'imagename'
sourceImageName: 'myImageRepository'
repositoryName: 'myImageRepository'
pushTag: '$(Build.BuildId)'
outputVariable: 'imageName'
- script: echo $(imageName) # output the full image name with tag
- job: Deploy
dependsOn: Build
variables:
imageName: $[ dependencies.Build.outputs['EcrPushImage.imageName'] ]
steps:
- script: echo $(imageName) # output an empty string
The EcrPushImage task will print the following in the console:
##vso[task.setvariable variable=imageName;isOutput=false;issecret=false;]ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/myImageRepository:x
Note the isOutput=false which prevents the variable from being propagated to future jobs.