Error running reusable workflows - Github actions - azure

I want to use reusable workflows and invoke two other actions, below is the snippet of both caller and called workflows:
az-dev-img-ops-reusable.yml (called workflow1)
on:
workflow_call:
inputs:
cloudProvider:
required: true
type: string
imgAction:
required: true
type: string
envName:
required: true
type: string
productImage:
required: true
type: string
jobs:
image-actions:
runs-on: self-hosted
steps:
- uses: actions/checkout#v2
- uses: ./.github/workflows/manage_images
with:
imgAction: ${{ inputs.imgAction }}
cloudProvider: ${{ inputs.cloudProvider }}
envName: ${{ inputs.envName }}
productImage: ${{ inputs.productImage }}
az-dev-tenant-ops-reusable.yml (called workflow2)
on:
workflow_call:
inputs:
cloudProvider:
required: true
type: string
envName:
required: true
type: string
action:
required: true
type: string
jobs:
tenant-actions:
runs-on: self-hosted
steps:
- uses: actions/checkout#v2
- uses: ./.github/workflows/refresh_tenant
with:
cloudProvider: azure
envName: az-dev
action: pod_refresh
az-dev-cicd.yml (caller workflow)
on:
workflow_dispatch:
jobs:
init:
runs-on: self-hosted
steps:
- uses: actions/checkout#v2
image-operations:
uses: ./.github/workflows/az-dev-img-ops-reusable.yml
with:
imgAction: check
cloudProvider: azure
envName: az-dev
productImage: my-server
tenant-operations:
needs: image-operations
uses: ./.github/workflows/az-dev-tenant-ops-reusable.yml
with:
cloudProvider: azure
envName: az-dev
action: pod_refresh
But while running, it throws error as below:
Can't find 'action.yml', 'action.yaml' or 'Dockerfile' under '/opt/my-runner/_work/my-images/my-images/.github/workflows/manage_images'. Did you forget to run actions/checkout before running your local action?
Checked over the web for solutions and tried all i.e.
Have a actions/checkout.
Make sure the caller function makes use of "uses" and not steps.
Tried both absolute path of repo/yaml and relative path.
But haven't been able to resolve it. Any hints/help would be highly appreciated.

Your issue is that you used the following syntax:
uses: ./.github/workflows/manage_images
... that refers to a directory.
When used that way, the Github Action interpreter expect a local action (using an action in the same repo).
However, to use local actions, you need to create a action.yaml file in a directory, but in your case, the image you shared in the comment shows that you actually have a manage_images.yaml file, that refers to a workflow, not a manage_images folder with an action.yml file in it.
To resolve your issue, if this manage_images.yaml is a reusable workflow (reusing the same workflow in different workflows), you need to add .yaml at the end of uses step, like this:
uses: ./.github/workflows/manage_images.yaml
Or, if you actually want to use a local action, convert this manage_images.yaml workflow to an action.yaml file, and put it inside a .github/workflows/manage_images directory.
Note that this answer could also give you more context about local actions and reusable workflows.

Related

YAML - Execute template in Deploymentjob

I'm currently trying to setup my complete build/release pipeline with yaml files.
First I tried with different stages (dev/staging/prod) and it worked.
Now I wanted to add an approval that the deploy doesn't not happen automatically on each system.
Therefore I added an environment in the TFS with an approval check.
But when I try to setup the yaml file I always get an error.
I don't know how to setup this properly.
This is my main yaml file called release-pipeline.yaml
trigger:
- master
pool:
name: POOL
stages:
- stage: BuildSolution
jobs:
- job: BuildSolutionJob
displayName: Build
workspace:
clean: all
steps:
- template: yaml/BuildSolution.yml
- template: yaml/CopyFiles.yml
- template: yaml/PublishArtifact.yml
- stage: DeployOn_STAGING_System
dependsOn: BuildSolution
jobs:
- job: Deploy_STAGING
- template: yaml/Deploy.yml
parameters:
Environment: 'SITE'
Staging: 1
- stage: Deploy_DEV_System
dependsOn: BuildSolution
jobs:
- deployment: Deploy_DEV
environment: ENVCHECK_DEV
strategy:
runOnce:
deploy:
steps:
- template: yaml/Deploy.yml
parameters:
Environment: 'SITE'
ViewDeploy: 1
This is my Deploy.yml file which i want to execute (only some snips):
parameters:
- name: Environment
type: string
- name: ProdSystem
type: number
default: 0
- name: Staging
type: number
default: 0
- name: ViewDeploy
type: number
default: 0
jobs:
- job:
variables:
artifactName: $[stageDependencies.BuildSolution.BuildSolutionJob.outputs['SetVariables.artifactName']]
version: $[stageDependencies.BuildSolution.BuildSolutionJob.outputs['SetVariables.version']]
steps:
- task: PowerShell#2
displayName: Display given parameters
inputs:
targetType: inline
script: >
Write-Host "ArtifaceName: " $(artifactName)
Write-Host "Environment for Deploy: " ${{ parameters.Environment }}
Write-Host "##vso[task.setvariable variable=isStaging]${{ parameters.Staging }}"
failOnStderr: true
When I try to execute I get the following error:
/release-pipeline.yml: Unexpected value 'parameters'.
How do I need to change this that it will work with the template in both cases, with and without the environment approval check?
I tried https://samlearnsazure.blog/2020/02/05/approvals-in-environments/
and of course different structure for the calling. But nothing helped.
In the tutorials they always have steps below the "deploy" but because I have different sites and environments I want/need the template file to save work.
I found another post which goes in the same direction.
I reworked my complete template so that I can use the approach of this: DevOps template with conditional manual approval job
It's not the same as I wanted, but it works.
My goal was that I don't want to create a environment if I have no checks on this site. Only for sites where I wanted the approval check.
With the above mentioned solution I need to create an environment for each site, independent if I have checks or not.

Checkout different Repository as per input in Azure Pipeline

I am trying to checkout repository in Azure pipeline which is different then self repo but in same Organization. Here repository name and project name will be passed as input parameter .
I have tried by following example in https://learn.microsoft.com/en-us/azure/devops/pipelines/repos/multi-repo-checkout?view=azure-devops but not able to pass with parameter.
I have tried with syntex as below, but not get success.
resources:
repositories:
- repository: MyAzureReposGitRepository
type: git
name: $(project)/$(repo)
ref: $(branch)
Also have tried like
- checkout: git://${{ variables.repoName}}#${{ variables.branchRef }}
But here getting error at time of running pipeline
The String must have at least one character. Parameter name:repositoryName
Please help if you have any other way to make it success.
Checkout different Repository as per input in Azure Pipeline
According to this thread Pipeline resource Version property as a variable:
While we can’t allow variables in that field, this is an excellent use case for runtime parameters.
So, we could not use variable $(project)/$(repo) in the resources.
To resolve this issue, we could use the Checking out a specific ref:
parameters:
- name: ProjectName
displayName: Project Name
type: string
default: LeoTest
values:
- LeoTest
- name: repoName
displayName: repo Name
type: string
default: TestRepo
values:
- TestRepo
- name: branchRef
displayName: Branch Name
type: string
default: Dev
values:
- Dev
And
- checkout: git://${{ parameters.ProjectName}}/${{ parameters.repoName}}#refs/heads/${{ parameters.branchRef}}
The test result:
Since you are talking about parameters I'm assuming you are using templates. I was able to achieve the desired result with the following code
# File: template.yml
parameters:
- name: project
type: string
- name: repo
type: string
- name: branch
type: string
stages:
- stage: A
displayName: Checkout
jobs:
- job: Checkout
steps:
- checkout: git://${{ parameters.project }}/${{ parameters.repo }}#${{ parameters.branch }}
# File: pipeline.yml
extends:
template: template.yml
parameters:
project: ProjectName
repo: RepoName
branch: BranchName

Azure Pipeline Get Template name from variable

Please consider the following:
- job: Backend
steps:
- template: $(ClassLibraryTemplate)
parameters:
projectName: 'Core'
solutionPath: 'Source/Core.sln'
ClassLibraryTemplate is defined as a pipeline variable. But when I run the build, it fails because the variable is not replaced by its value and the template is not found.
Is it not possible to store the template name in a variable ?
For Azure DevOps YAML pipeline, the template get processed at compile time. However, the $(ClassLibraryTemplate) get processed at the runtime. That's why it fails.
More information: Understand variable syntax
You could define variable or parameter in your YAML pipeline, then use template expression. For parameter, you could specify value when queue/run pipeline in pop-up window.
For example:
parameters:
- name: temName
displayName: template name
type: string
default: steps/test.yml
trigger:
- none
variables:
- name: tem
value: steps/build.yml
jobs:
- job: Linux
pool:
vmImage: 'ubuntu-16.04'
steps:
- template: ${{ variables.tem }}
- template: ${{ parameters.temName }}

Azure yaml pipeline using "extends"

I am trying to use extends as part of my pipeline. I am trying to get the first basic step working from Azure docs ie
# pythonparameter-template.yml
parameters:
- name: usersteps
type: stepList
default: []
steps:
- ${{ each step in parameters.usersteps }}
- ${{ step }}
# azure-pipelines.yml
trigger: none
resources:
repositories:
- repository: CI-CD-Templates
type: git
name: /CI-CD-Templates
ref: refs/heads/master
extends:
template: /pythonparameter-template.yml#CI-CD-Templates
parameters:
usersteps:
- script: echo This is my first step
- script: echo This is my second step
I keep getting the below error:
The directive 'each' is not allowed in this context. Directives are not supported for expressions that are embedded within a string. Directives are only supported when the entire value is an expression
Unexpected value '${{ each step in parameters.usersteps }} - ${{ step }}'
Also after I extend from a template can azure-pipelines.yml also have it's own custom steps ie
# azure-pipelines.yml
resources:
repositories:
- repository: templates
type: git
name: MyProject/MyTemplates
ref: tags/v1
extends:
template: template.yml#templates
parameters:
usersteps:
- script: echo This is my first step
- script: echo This is my second step
steps:
- template: /validation-template.yml#CI-CD-Templates
parameters:
commitMessage: $(commitMessage)
- template: /shared-template.yml#CI-CD-Templates
parameters:
buildArtifactDir: $(buildArtifactDir)
Update
Please refer the response in this DC link-- Yaml extends feature erroring out when looping through steps.
​The YAML has a validation task in #pythonparameter-template.yml
Comment out these 2 lines and your YAML will succeed. The template shown here is preventing any tasks to be used. This could be a scenario for someone with specific security requirements.
${{ if eq(pair.key, 'task') }}:
'${{ pair.value }}': error
Are you trying to combine two yml pythonparameter-template.yml azure-pipelines.yml in the same file? It's not supported.
parameters:
- name: usersteps
type: stepList
default: []
steps:
- ${{ each step in parameters.usersteps }}
- ${{ step }}
According to the error Directives are not supported for expressions that are embedded within a string. Directives are only supported when the entire value is an expression Unexpected value '${{ each step in parameters.usersteps }} - ${{ step }}'
You maybe use the wrong format. About the formats you could refer our official doc here--
Template types & usage
Besides, you can make azure-pipelines.yml also have it's own custom steps. But you need to put them under parameters in the pipeline, not like the way you use.
azure-pipelines.yml
trigger:
- master
extends:
template: pythonparameter-template.yml
parameters:
buildSteps:
- bash: echo Test #Passes
displayName: succeed
- bash: echo "Test"
displayName: succeed
- script: echo "Script Test"
displayName: Fail

How to use an array in a condition for Azure DevOps YAML

I have a template that defines an array of branches for each environment, so that I can control which branches cause a deploy to a particular environment. For example, the only branch I want deployed to production is master, but for UAT I want release, hotfix, and master. I've set-up a parent template that calls downstream templates in an 'each' loop. Inside the deploy template, I want to compare the array of allowed branches against the current branch to determine whether to proceed or not. Here's part of the parent template that passes the branches arrays:
- template: pipeline-templates/environment-pipeline.yml
parameters:
envs:
- name: devtest
branches:
- 'refs/heads/master'
- 'refs/heads/develop'
- 'refs/heads/hotfix/'
- 'refs/heads/release/'
- name: nightly
branches:
- 'refs/heads/master'
- 'refs/heads/develop'
- 'refs/heads/hotfix/'
- 'refs/heads/release/'
- name: qa
branches:
- 'refs/heads/master'
- 'refs/heads/hotfix/'
- 'refs/heads/release/'
- name: prod
branches:
- 'refs/heads/master'
The environment-pipeline.yml below then calls the deploy template for each environment.
parameters:
- name: envs # collection of environments to create/deploy
type: object
default:
env:
name: ''
branches: []
stages:
- ${{ each env in parameters.envs }}:
- template: deploy.yml
parameters:
environmentName: ${{ env.name }}
onlyForBranches: ${{ env.branches }}
The above all works fine (note, I've deleted a lot of the YAML to simplify the example). The next stage is to use a condition with the array of branches in the deploy template. This is how I was hoping it would work, but doesn't.
parameters:
environmentName: ''
onlyForBranches: []
stages:
- stage: branch_gate
condition: and(succeeded(), in(variables['Build.SourceBranch'], ${{ parameters.onlyForBranches }}))
# then the deploy stages go here if above condition passes
This results in the following error:
Unable to convert from Array to String.
Is there some way to make this work, or should I use a different approach?
in is not the function to use. It takes n arguments and is true if the first argument equals any of the rest: in('B', 'A', 'B', 'C') => true
Try containsvalue instead:
condition: and(succeeded(), containsvalue(${{ parameters.onlyForBranches }}, variables['Build.SourceBranch']))
I agree with schummar on the use of containsValue, however the suggested approach did not work for me either.
Instead try this:
condition: and(succeeded(), ${{ containsValue(parameters.onlyForBranches, variables['Build.SourceBranch']) }})

Resources