Sum expression in github action run-name - github

I am trying to set dynamic name to workflow run that has a number. The number should be calculated using an expression.
run-name: Perform Operation with ID [SOME_GITHUB_VAR + 1]
Is there a way to perform the above sum operation?
Thanks,

The run-name can include some expressions and can reference only the github and inputs contexts:
run-name: Deploy to ${{ inputs.deploy_target }} by #${{ github.actor }}
Unfortunately, GitHub Actions don't support math operations inside expressions. So, it's impossible to perform such a calculation for the value of the run-name option.
It's possible for the name value for a job step. You can add up these two numbers in a script and then set it as an environment variable.
Example:
name: 'Sum expression'
on:
workflow_dispatch:
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: run number with offset
env:
NUM: ${{ github.run_number }}
run: |
echo "GITHUB_RUN_NUMBER_WITH_OFFSET=$(($NUM + 200))" >> $GITHUB_ENV
- name: 'Perform Operation with ID ${{ env.GITHUB_RUN_NUMBER_WITH_OFFSET }}'
run: echo "Success!"
Result:
For more details, read the Setting an environment variable article.
Reference: How to add two numbers.

Related

Cannot retrieve and display Github env setup in previous step

I am trying to setup a variable in my CI pipeline that I will reuse later (eventually in another job, which I don't know if possible since I don't know if jobs shares variables.. but this is another problem). My pipeline is:
name: CI
on:
pull_request:
branches:
- main
jobs:
test-job:
runs-on: ubuntu-latest
name: test-job
steps:
- name: setup env variable
run: |
BRANCH_NAME=`echo "${{github.head_ref}}"'`
echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV
echo ${{ env.BRANCH_NAME }}
that last echo doesn't show anything unfortunately. I am sure that BRANCH_NAME is correctly set because before pushing it into the $GITHUB_ENV" I did echo it and it contains data. Plus you can see the name of the branch in the console logs.
Console logs from Github are the following:
1. Run BRANCH_NAME=`echo "test_branch"'`
2. BRANCH_NAME=test_branch >> /home/runner/work/_temp/_runner_file_commands/set_env_9eeeac39-f573-4079-ba62-e1c2019f7aff
3.
So, that final echo ${{ env.BRANCH_NAME }} gives no result. What am I missing?
UPDATE:
As suggested in the comments, I started using workflow variables, in such a way that they are available throughout all the jobs.
The initial setup becomes:
name: CI
on:
pull_request:
branches:
- main
env:
BRANCH_NAME: ""
jobs:
...
I don't like the fact I need to give those variables an empty string value as placeholder and would have preferred declaring and assigning them in one of the jobs itself.. but still. So, now variables are declared before the jobs section, how do I assign a value to them in one of my steps? Meaning, I need to replace the
echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV
tried already
echo "BRANCH_NAME=$BRANCH_NAME >> ${{ env.BRANCH_NAME }}
or
${{ env.BRANCH_NAME }}=$BRANCH_NAME
but both ways don't work.

GitHub Actions Set Output - Assure Parallel Job Access is Safe

I have configured my github actions which runs tests in parallel for different platforms. At the end of my tests I want the status to be saved to the outputs. Once all jobs complete I have another job that runs to send the results to a slack webhook.
I am having difficulty determining a method to save the output for multiple jobs and assuring there is no issues when they are running in parallel.
For example this is my code snippet
name: Test Notify
on:
push:
jobs:
build:
strategy:
matrix:
config:
- name: 'Ubuntu 18.04'
runner: 'ubuntu-18.04'
id: 'u18'
- name: 'Ubuntu 20.04'
runner: 'ubuntu-20.04'
fail-fast: false
runs-on: ${{ matrix.config.runner }}
outputs:
# Prefer to have one general output I can append to
global: ${{ steps.status.outputs.global }}
# I can output to separate outputs but I rather have a single one as shown above
u18: ${{ steps.status.outputs.u18 }}
u20: ${{ steps.status.outputs.u20 }}
steps:
- name: Test Failure u18
id: step1
if: ${{ matrix.config.id == 'u18' }}
run: |
exit 1
- name: Doing Step 2
id: step2
run: |
echo "DO NOTHING"
- name: Output Status
id: status
if: always()
env:
JOB_STATUS: "${{ job.status }}"
run: |
# This works, but is it safe since I have u18 and u20 running in parallel ?
echo "${{ matrix.config.id }}=$JOB_STATUS" >> $GITHUB_OUTPUT
# Is there a safe way to have a single status string that I add to, for example;
# echo "global=${{ github_output.global}}$JOB_STATUS" >> $GITHUB_OUTPUT
webhook:
needs: build
runs-on: 'ubuntu-20.04'
if: always()
steps:
- name: Send webhook update for all jobs
env:
JSON_RESULTS: "${{ toJSON(needs.build-and-test) }}"
run: |
# Will add code to properly send the information
echo $JSON_RESULTS
Currently, there is no easy way to reference all outputs of matrix jobs. Moreover combining it into a single output.
The issue is that only a single value is available for future jobs that need the strategy.matrix job’s output because even if the output is set by multiple matrix variations of the job, only one is retained.
For more detail, see the Community discussion.
TL;DR:
There are several workarounds:
defining separate outputs for a job with strategy.matrix by letting the job variations set different outputs
then process these outputs in a separate step that can provide single output for further steps
use artifacts to store the matrix jobs' outputs and then post-process it (discussioncomment-3814009)

GitHub Actions - Reuse outputs from other reusable workflows

I'm not sure if it's possible, but I'm attempting to use outputs from one reusable workflow, in another, that's part of the same caller workflow. For reference, please see the configs below:
Caller Workflow:
jobs:
call-workflow-calver:
uses: ./.github/workflows/called-workflow1.yaml
secrets: inherit
call-workflow-echo:
needs: call-workflow-calver
uses: ./.github/workflows/called-workflow2.yaml
secrets: inherit
Job for creating the CalVer tag (it outputs as $VERSION as part of the action)
Called Workflow 1:
...
jobs:
calver:
name: Create CalVer tag
...
steps:
- name: Calver tag
uses: StephaneBour/actions-calver#1.4.4
if: ${{ github.ref == 'refs/heads/main' }}
id: calVer
with:
date_format: "%Y-%m-%d"
release: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
...
Trying to use the CalVer $VERSION output from another caller workflow
Called Workflow 2:
...
- name: Echo
run: |
echo ${{needs.calver.outputs.VERSION}}
...
The basic concept is I'm trying to use outputs from one reusable workflow in another for setting CalVer versions in workflow 1, calling that in workflow 2 so I can set it as an image version. I will eventually use in a 3rd reusable workflow to deploy said image. If this is possible, that would be great!
Hopefully, this all makes a bit of sense, but if anything needs clarifying, please do let me know!
Many thanks in advance!
According to the official documentation, you can now declare outputs to reusable workflows.
These work just like job outputs and are available via needs.<reusable>.outputs.<output> format once you declare the output.
Example
1. Reusable workflow configuration:
name: Reusable workflow
on:
workflow_call:
# Map the workflow outputs to job outputs
outputs:
firstword:
description: "The first output string"
value: ${{ jobs.example_job.outputs.output1 }}
secondword:
description: "The second output string"
value: ${{ jobs.example_job.outputs.output2 }}
jobs:
example_job:
name: Generate output
runs-on: ubuntu-latest
# Map the job outputs to step outputs
outputs:
output1: ${{ steps.step1.outputs.firstword }}
output2: ${{ steps.step2.outputs.secondword }}
steps:
- id: step1
run: echo "::set-output name=firstword::hello"
- id: step2
run: echo "::set-output name=secondword::world"
2. Workflow using the reusable:
name: Call a reusable workflow and use its outputs
on:
workflow_dispatch:
jobs:
job1:
uses: octo-org/example-repo/.github/workflows/called-workflow.yml#v1
job2:
runs-on: ubuntu-latest
needs: job1
steps:
- run: echo ${{ needs.job1.outputs.firstword }} ${{ needs.job1.outputs.secondword }}
Note that if a reusable workflow that sets an output is executed with a matrix strategy, the output will be the output set by the last successful completing reusable workflow of the matrix which actually sets a value. That means if the last successful completing reusable workflow sets an empty string for its output, and the second last successful completing reusable workflow sets an actual value for its output, the output will contain the value of the second last completing reusable workflow.
I used this workflow as example here if you want to check the logs of the workflow run.

In a GitHub Action how to conditionalize a step based off the previous step's output?

Building a GitHub action based on the commit message I'm trying to base a step on whether the commit message contains a particular string, set it to a variable and then in the next step check with a condition.
My current implementation of my action works:
name: Smoke Test
on:
push:
branches:
- main
permissions:
contents: read
issues: write
jobs:
smoking:
runs-on: [ubuntu-latest]
steps:
- name: Run smoke tests
if: ${{ !contains(github.event.head_commit.message, 'smoke_test') }}
run: |
echo 'Smoke Test not requested'
exit 1
stuff:
needs: smoking
runs-on: ubuntu-latest
steps:
- uses: actions/checkout#v2
- uses: JasonEtco/create-an-issue#v2
env:
GITHUB_TOKEN: ${{ secrets.TOKEN }}
with:
filename: .github/ISSUE_TEMPLATE/smoke-test.md
id: create-issue
- run: 'echo Created issue number ${{ steps.create-issue.outputs.number }}'
- run: 'echo Created ${{ steps.create-issue.outputs.url }}'
but with the implementation of:
exit 1
causes the action to indicate it error'ed out in the action panel and while that works that isn't technically accurate because I don't need it to error I just don't want the remaining steps to run.
I've tried setting a variable:
if: ${{ contains(github.event.head_commit.message, 'smoke_test') }}
with:
run-smoke-test: true
run: |
echo 'Smoke Test requested'
but it's not passing to the next step.
Research
Use environment variable in github action if
How to pass variable between two successive GitHub Actions jobs?
github-action: does the IF have an ELSE?
How to fail a job in GitHub Actions?
GitHub Actions - trigger another action after one action is completed
Without relying on another GitHub action is there a way in step smoking to set an env variable that step stuff would need to validate for before running the step?
Edit
After reading the answer and implementing job outputs I've written:
name: Smoke Test
on:
push:
branches:
- main
permissions:
contents: read
issues: write
jobs:
commitMessage:
runs-on: ubuntu-latest
outputs:
output1: ${{ steps.isSmoke.outputs.test }}
steps:
- id: isSmoke
if: ${{ contains(github.event.head_commit.message, 'smoke_test') }}
run: echo "::set-output name=test::true"
smokeTest:
runs-on: ubuntu-latest
needs: commitMessage
steps:
- uses: actions/checkout#v2
- uses: JasonEtco/create-an-issue#v2
if: steps.isSmoke.output.test == true
env:
GITHUB_TOKEN: ${{ secrets.DEV_TOKEN }}
with:
filename: .github/ISSUE_TEMPLATE/smoke-test.md
but when the commit message of smoke_test is used it bypasses create-an-issue:
and I'm basing my condition after reading "Run github actions step based on output condition" and reading:
Contexts
Expressions
Using conditions to control job execution
Can a condition come before a step and/or what is the correct way to run a step based off the previous step?
You are looking for job outputs, which allow you to send data to the following jobs.

How can I invoke a YAML pipeline that has both variables and runtime parameters?

I have a scenario where I need to have both:
runtime parameters, so that the pipeline can be triggered manually from the UI, where users triggering it can choose from a predefined set of options (defined in YAML)
variables, so that the pipeline can be invoked via REST APIs
Regarding runtime parameters, I was able to create the following sample pipeline:
parameters:
- name: image
displayName: Pool Image
type: string
default: ubuntu-latest
values:
- windows-latest
- ubuntu-latest
trigger: none
stages:
- stage: A
jobs:
- job: A
steps:
- pwsh: |
echo "This should be triggering against image: $MY_IMAGE_NAME"
env:
MY_IMAGE_NAME: ${{ parameters.image }}
When I run it, I can see the dropdown list where I can choose the image name and it is reflected in the output message of the PowerShell script.
Regarding variables, I have defined one called "image" here (notice the value is empty):
The idea now is to invoke the pipeline from REST APIs and have the image name replaced by the value coming from the variable:
{
"definition": {
"id": 1
},
"sourceBranch": "master",
"parameters": "{\"image\": \"windows-latest\" }"
}
In order to make the step print the value I'm passing here, I need to correct the environment variable in some way. I thought it would be sufficient to write something like:
env:
MY_IMAGE_NAME: ${{ coalesce(variables.image, parameters.image) }}
That's because I want to give the priority to the variables, then to parameters, so that in case none is specified, I always have a default value the pipeline can use.
However, this approach doesn't work, probably because we're dealing with different expansion times for variables, but I don't really know what I should be writing instead (if there is a viable option, of course).
What I also tried is:
env:
MY_IMAGE_NAME: ${{ coalesce($(image), parameters.image) }}
MY_IMAGE_NAME: ${{ coalesce('$(image)', parameters.image) }}
MY_IMAGE_NAME: $[ coalesce(variables.image, parameters.image) ]
MY_IMAGE_NAME: $[ coalesce($(image), parameters.image) ]
None of those are working, so I suspect this may not be feasible at all.
There is a workaround that I'm currently thinking of, which is to create two different pipelines so that those can be invoked independently, but while this is quite easy for me to accomplish, given I'm using a lot of templates, I don't find it the right way to proceed, so I'm open to any suggestion.
I tested and found you might need to define a variable and assign the parameter's value to it (eg. Mimage: ${{parameters.image}}). And define another variable(eg. Vimage) and assign $[coalesce(variables.image, variables.Vimage)] to it. Then refer to $(Vimage) in the env field of powershell task. Please check out below yaml.
parameters:
- name: image
displayName: Pool Image
type: string
default: ubuntu-latest
values:
- windows-latest
- ubuntu-latest
trigger: none
stages:
- stage: A
jobs:
- job: A
variables:
Mimage: ${{parameters.image}}
Vimage: $[coalesce(variables.image, variables.Mimage)]
steps:
- pwsh: |
echo "This should be triggering against image: $env:MY_IMAGE_NAME"
env:
MY_IMAGE_NAME: $(Vimage)
Env field of powershell task is usually for mapping secret variables. You can directly refer to $(Vimage) in the powershell script: echo "This should be triggering against image: $(Vimage).
Note: To queue a build via REST API with provided parameters, you need to check Let users override this value when running this pipeline to make the varilabe to be settable at queue time.
Update:
You can try passing the variables to the parameters of the template to make the parameters for template dynamic. Please check below simple yaml.
jobs:
- template: template.yaml
parameters:
MTimage: ${{parameters.image}}
VTimage: $(Vimage)
template.yaml:
parameters:
MTimage:
VTimage:
jobs:
- job: buildjob
steps:
- powershell: |
echo "${{parameters.VTimage}}"
echo "${{parameters.MTimage}}"