Having issues with variables and outputs - github-actions

I started learning Github Actions a few days ago and I am playing around with it. I am having issues with defining outputs and using them in variables or as input values in another workflow step. I am not sure what I am doing wrong.
name: Demo
on:
workflow_dispatch:
jobs:
build:
runs-on: [ ubuntu-latest ]
outputs:
paths: ${{ steps.find_path.outputs.paths }}
steps:
- name: Code Checkout
uses: actions/checkout#v2
- name: Find Paths
id: find_path
run: |
all_paths=$(cat document.txt)
# some code
echo "::set-output name=paths::$(echo ${all_paths})"
- name: List
id: list_path
run: |
var_paths=${{ steps.find_path.outputs.paths }}
for part in ${var_paths[#]}; do
# parent_dir=$(cat...)
# ....
# some code
echo $part
done
I have a text file with some paths in it
/home/ubuntu
/home/ubuntu/docs
/home/ariel/code
I want to use the output from find_path step in another list_path step. There is some other code I didn't include as it's irrelevant to my question. So I defined the paths output in find_path step and it is basically a space-separated string /home/ubuntu /home/ubuntu/docs /home/ariel/code and that's format I want to have.
But I don't know how to use outputs from one step as input value in another step.
Basically,
var_paths=/home/ubuntu /home/ubuntu/docs /home/ariel/code
But when I loop var_paths I get weird errors like no such file or directory.

You're missing the quotes when assigning the output from the step to the variable:
name: Demo
on:
workflow_dispatch:
jobs:
build:
runs-on: [ ubuntu-latest ]
steps:
- name: Code Checkout
uses: actions/checkout#v3
- name: Find Paths
id: find_path
run: |
all_paths=$(cat document.txt)
# some code
echo "::set-output name=paths::$(echo ${all_paths})"
- name: List
id: list_path
run: |
# add quotes here
var_paths="${{ steps.find_path.outputs.paths }}"
for part in ${var_paths[#]}; do
# parent_dir=$(cat...)
# ....
# some code
echo $part
done
Misc comments:
You don't need to declare the outputs on the job level unless the output from a step should also be the output from the job. In your case, you're only using the output between steps.
The checkout action is available in v3

Related

Use an array in workflow level env variable?

You can set env vars available across the entire workflow e.g. like in this post.
(From solution on linked post)
name: Git Pull Request Workflow
on:
workflow_dispatch:
pull_request:
branches:
- master
env:
one: 1
two: zwei
three: tres
jobs:
first-job:
runs-on: ubuntu-latest
steps:
- run: |
echo "${{ env.one }}"
echo "${{ env.two }}"
echo "${{ env.three }}"
I have a workflow that uses a matrix strategy and I have to update it in each job if I ever change it. I tried to make it a global variable like above:
name: Model Multipliers
on:
push:
branches:
- main
env:
FRUIT: ["Apple", "Pear", "Banana", "Orange"]
jobs:
ssql-get:
runs-on: ubuntu-latest
strategy:
matrix:
FRUIT: ${{ env.FRUIT }}
name: Get data
steps:
- name: Checkout cum-rev repo
But this gives error:
The workflow is not valid. .github/workflows/main.yml (Line: 12, Col:
9): A sequence was not expected .github/workflows/main.yml (Line: 19,
Col: 15): Unrecognized named-value: 'env'. Located at position 1
within expression: env.FRUIT
Is what I'm trying to do possible by any other means?
If you're using bash, you can create a regular array (like in bash) to use in your steps or inside github expressions -
Example:
env:
MAIN_BRANCHES: ("develop" "main")
Now you can use the array in any step. In the run property, as an environment variable with "${MAIN_BRANCHES}", or inside if conditions with Github expression syntax.
...
- name: Tag build
if: ${{ github.event_name == 'push' && contains(env.MAIN_BRANCHES, steps.calculate_changed_services.outputs.diff_dest) }}
run: echo "my main branches ${MAIN_BRANCHES}"
...
You can find the full Workflow File here - gitversion.yml
if you remove the double quotes in the values it should work

Can I define a global across jobs

I have a workflow with 2 jobs:
on: [push]
jobs:
ssql:
runs-on: ubuntu-latest
### bunch of steps in between ###
- name: Upload data as artifact
uses: actions/upload-artifact#v2
with:
name: ${{ env.GAME }} + "-" + "data"
path: output_data/training-data.csv
env:
GAME: "FunGame"
Rtrain:
runs-on: ubuntu-latest
name: Train model
needs: ssql
steps:
- name: checkout current repo
uses: actions/checkout#v2
- name: Retreive data from ssql job
uses: actions/download-artifact#v2
with:
name: ${{ env.GAME }} + "-" + "data"
env:
GAME: "FunGame"
I had to set env variable $GAME twice, once in each job. Is there any syntax where I can e.g. add this at the top to make it truly global across jobs, e.g. something like:
on: [push]
env:
GAME: "FunGame"
jobs: ...
You can set an env variable exactly as you described at the workflow level.
Just note that it can conflict with env variables set at the job level, or at the step level, if they have the same name. In that case, the variable used is the most specific one: STEP over JOB over WORKFLOW.
Reference 1 + Reference 2
Here is an example of how to use env variables at different levels (without conflict):
name: Environment Workflow
on:
workflow_dispatch:
env:
WORKFLOW_VARIABLE: WORKFLOW
jobs:
job1:
runs-on: ubuntu-latest
env:
JOB_VARIABLE: JOB
steps:
- name: Run Commands with various variables
if: ${{ env.WORKFLOW_VARIABLE == 'WORKFLOW' }}
env:
STEP_VARIABLE: STEP
run: |
echo "Hello World"
echo "This is the $WORKFLOW_VARIABLE environment variable"
echo "This is the $JOB_VARIABLE environment variable"
echo "This is the $STEP_VARIABLE environment variable"
Full workflow implementation (if you want to reproduce)
Previous workflow run display

Check whether environment variable is empty

What is the nicest approach to check if environment variable is empty on Github action as a condition to a step? I've tried the trivial approach but it doesn't seem to work.
For example:
name: SimpleWorkflow
on:
push:
env:
MULTI_LINE_ARG: |
ARG1: value
jobs:
update:
runs-on: ubuntu-latest
steps:
- name: Fetching Local Repository
uses: actions/checkout#master
- name: run step if multiline not null
if: ${{env.MULTI_LINE_ARG}} != ""
run: echo multiline not null
No matter how I've tried this I fail to properly check if env is empty.
Updated to new GitHub syntax (as of 2022-12)
Background: The issue of secrets not available to forks is known to GitHub folks, but no concrete activity announced: https://github.community/t/github-workflow-not-running-from-pull-request-from-forked-repository/16379/41?u=koppor
One can use output variables of steps to determine whether a secret is available.
The name of the secret in GitHub is SECRET.
- name: Check secrets presence
id: checksecrets
shell: bash
run: |
if [ "$SECRET" == "" ]; then
echo "secretspresent=NO" >> $GITHUB_OUTPUT
else
echo "secretspresent=YES" >> $GITHUB_OUTPUT
fi
env:
SECRET: ${{ secrets.SECRET}}
- name: run step if secret is present
if: (steps.checksecrets.outputs.secretspresent == 'YES')
run: echo secret is present
Note: Solution adapted from https://github.community/t/if-expression-with-context-variable/16558/6?u=koppor.

Use dynamic input value for Environment in GitHub Actions workflow job

I'm trying to make a GitHub Actions workflow where one job has a dynamic value to its environment setting. https://docs.github.com/en/actions/reference/environments I have two jobs in this workflow. The first job determines which environment the second job will run in, and this is in turn based on which git branch the Actions job is run from.
This is my naive attempt to make it work, but I get an error which says
(Line: 29, Col: 18): Unrecognized named-value: 'needs'. Located at position 1 within expression: needs.get-environment.outputs.environment_name
name: Environments
on:
push:
workflow_dispatch:
jobs:
get-environment:
runs-on: ubuntu-latest
outputs:
environment_name: ${{ steps.get_environment.outputs.environment_name }}
steps:
- id: get_environment
run: |
if [ "$GITHUB_REF" = "refs/heads/test" ]
then
echo "::set-output name=environment_name::test"
elif [ "$GITHUB_REF" = "refs/heads/qa" ]
then
echo "::set-output name=environment_name::qa"
elif [ "$GITHUB_REF" = "refs/heads/master" ]
then
echo "::set-output name=environment_name::production"
fi
use-environment:
runs-on: ubuntu-latest
needs: [get-environment]
environment: ${{ needs.get-environment.outputs.environment_name }}
steps:
- uses: actions/checkout#v2
- name: Run a one-line script
run: echo ${{ secrets.ENV_DEPENDENT_SECRET }}
Is it possible to achieve what I'm trying to do? My end goal is to have a single workflow file for three different app environments (test, QA and prod), where each app environment uses a separate Actions environment. (terminology gets confusing, I know)
I actually had to solve this issue for the place I work. You can use a matrix with the list of your env names and dynamically set the environment name. Take a look at the link for the workflow file.
Have you tried
> use-environment:
> runs-on: ubuntu-latest
> needs: [get-environment]
> environment:
> name: ${{ needs.get-environment.outputs.environment_name }}

GitHub Actions expression functions: string manipulation?

In a GitHub Actions workflow definition file, there's a set of built-in functions that you can use in expressions.
For example: ${{ toJson(github) }}
Are there any string manipulation functions that can be used in an expression, such as toLowerCase?
The documentation page doesn't mention any. However, I'm wondering if Github uses some sort of standard templating / expression eval library under the hood which has provides a larger set of functions out of the box.
Impossible. GitHub expressions doesn't allow string modification, only concatenation.
You could do almost the same with a custom step in a build job, but this means that you won't be able to use that variable everywhere (for example "processed" environment name is out of the question).
env:
UPPERCASE_VAR: "HELLO"
steps:
- id: toLowerCase
run: INPUT=${{ env.UPPERCASE_VAR }} echo "::set-output name=lowerCaseValue::${INPUT,,}"
- run: echo ${{steps.toLowerCase.outputs.lowerCaseValue}}
I wanted to replace some chars in git version strings and was able to make a step like so:
- name: prepare version string
id: prep_version
run: |
export test_version=$(echo ${{ steps.tag_version.outputs.new_version }} | sed 's/[^0-9,a-z,A-Z]/\-/g')
echo ::set-output name=version::$test_version
that worked pretty good for me... so really we have anything that we could put on a cmd line
I usually start by setting all global variables that I will use throughout the workflow.
jobs:
variables:
outputs:
tag_name: ${{ steps.var.outputs.tag_name}}
runs-on: "ubuntu-latest"
steps:
- name: Setting global variables
uses: actions/github-script#v6
id: var
with:
script: |
core.setOutput('tag_name', '${{ github.head_ref }}'.toLowerCase().replaceAll(/[/.]/g, '-').trim('-'));
Usage:
deploy:
needs: [build, variables]
runs-on: [ self-hosted, preview ]
env:
TAG_NAME: ${{ needs.variables.outputs.tag_name }}
step:
-name: Echo variables
run: |
echo ${{ needs.variables.outputs.tag_name }}
echo ${{ env.TAG_NAME}}