We try to pass some env variables using a workaround to the reusable workflow as follows, but no variables are passed.
Workflow YAML is:
name: "call my_reusable_workflow"
on:
workflow_dispatch:
env:
env_branch: ${{ github.head_ref }}
env_workspace: ${{ github.workspace }}
jobs:
call_reusable_workflow_job:
uses: my_github/my-reusable-workflow-repo/.github/workflows/used_wf_test.yml#master
with:
env_vars: |
hello-to=Meir
branch_name=${{ env.env_branch }}
secrets:
my_token: ${{secrets.ENVPAT}}
and the reusable workflow YAML is:
name: my_reusable_workflow
on:
workflow_call:
inputs:
env_vars:
required: true
type: string
description: list of vars and values
secrets:
giraffe_token:
required: true
jobs:
reusable_workflow_job:
runs-on: ubuntu-latest
steps:
- name: set environment variables
if: ${{ inputs.env_vars }}
run: |
for env in "${{ inputs.env_vars }}"
do
printf "%s\n" $env >> $GITHUB_ENV
done
When the action is running it gets the value of hello-to=Meir but doesn't get the value branch_name=${{ env.env_branch }}.
I tried to pass the value also as branch_name=${{ github.head_ref }} but with no success.
According to the Limitations of Reusing workflows:
Any environment variables set in an env context defined at the workflow level in the caller workflow are not propagated to the called workflow. For more information, see "Variables" and "Contexts."
So, the env context is not supported in reusable workflow callers at the moment.
However, you can pass the Default Environment Variables to reusable workflow callers.
For example, in your particular scenario, you want to use these contexts:
github.head_ref
github.workspace
The equivalent default environment variables are:
GITHUB_HEAD_REF
GITHUB_WORKSPACE
And, your reusable workflow (e.g. reusable_workflow_set_env_vars.yml) will be called by its caller (e.g. reusable_workflow_set_env_vars_caller.yml) like this:
name: reusable_workflow_set_env_vars_caller
on:
workflow_dispatch:
jobs:
set-env-vars:
uses: ./.github/workflows/reusable_workflow_set_env_vars.yml
with:
env_vars: |
TEST_VAR='test var'
GITHUB_HEAD_REF=$GITHUB_HEAD_REF
GITHUB_WORKSPACE=$GITHUB_WORKSPACE
GITHUB_REF=$GITHUB_REF
Apart from that, regarding your implementation of the reusable workflow (e.g. reusable_workflow_set_env_vars.yml):
As the env_vars is of string type, you need to somehow solidify it against YAML multiline whitespace variants e.g. >.
You can visualize and observe whitespace on this online utility (https://yaml-multiline.info/).
With the current implementation, there may be word splitting for variable values containing spaces in them. So, you might need to iterate per line i.e. up to the newline character. This thread (https://superuser.com/questions/284187/bash-iterating-over-lines-in-a-variable) might be helpful for this.
Related
I'm trying to call a reusable workflow from another one, passing it some input variables. In the caller workflow I have some environment variables that I want to pass as input to the reusable one, like so:
env:
SOME_VAR: bla_bla_bla
ANOTHER_VAR: stuff_stuff
jobs:
print:
runs-on: ubuntu-latest
steps:
- name: Print inputs passed to the reusable workflow
run: |
echo "some var: $SOME_VAR"
echo "another var: $ANOTHER_VAR"
call_reusable:
uses: ...
with:
input_var: $SOME_VAR
another_input_var: $ANOTHER_VAR
the reusable workflow:
on:
workflow_dispatch:
workflow_call:
inputs:
input_var:
required: true
type: string
another_input_var:
required: true
type: string
jobs:
the_job:
runs-on: ubuntu-latest
steps:
- name: Print inputs
run: |
echo "input_var: ${{ inputs.input_var }}"
echo "another_input_var: ${{ inputs.another_input_var }}"
The Print inputs passed to the reusable workflow step works fine - all variables are correctly printed. However, the Print inputs step in the reusable workflow (the callee) does not work as expected - all the variables are empty.
I couldn't find anything in the docs suggesting that there is something wrong with my approach so, the way I see it, this should be working. Still, looking at the logs there is something wrong, as in the reusable workflow (callee) I can see:
Run echo "input_var: $SOME_VAR"
echo "another_input_var: $ANOTHER_VAR"
shell: /usr/bin/bash -e {0}
input_var:
another_input_var:
I tried wrapping the values in the with: block in $(echo) but that didn't work.
Any ideas?
After some researches, I found this thread explaining that:
You can’t pass ENV variables to the reusable workflow, so they are almost useless in this pattern.
Moreover, on the official documentation, it is stated that:
Any environment variables set in an env context defined at the workflow level in the caller workflow are not propagated to the called workflow.
Therefore, in your case, you wont be able to achieve what you want using directly the env variable, but there are workarounds.
Note: It would be great if GitHub comes up with a better way to assign values inline or pass them into reusable workflows, as handling each parameter many times just to pass it into a reusable workflow is cumbersome.
A workaround could be to use outputs from a first job, and use those outputs as the reusable workflow inputs.
Here is an example of how it could be done:
env:
SOME_VAR: bla_bla_bla
ANOTHER_VAR: stuff_stuff
jobs:
print:
runs-on: ubuntu-latest
outputs:
some_var: ${{ steps.step1.outputs.some_var }}
another_var: ${{ steps.step1.outputs.another_var }}
steps:
- name: Print inputs passed to the reusable workflow
id: step1
run: |
echo "some var: $SOME_VAR"
echo "::set-output name=some_var::$SOME_VAR"
echo "another var: $ANOTHER_VAR"
echo "::set-output name=another_var::$ANOTHER_VAR"
call_reusable:
needs:
- print
uses: ...
with:
input_var: ${{ needs.print.outputs.some_var }}
another_input_var: ${{ needs.print.outputs.another_var }}
That way, without updating the reusable workflow implementation, the inputs would be filled with the expected values.
Here are the workflow I used to test: main + reusable
And you can check the workflow run with the expected outcome here.
The use of ::set-output is now deprecated.
See https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/.
Now recommended:
- name: Save state
run: echo "{name}={value}" >> $GITHUB_STATE
- name: Set output
run: echo "{name}={value}" >> $GITHUB_OUTPUT
The bounty expires in 3 days. Answers to this question are eligible for a +50 reputation bounty.
IronSean wants to draw more attention to this question.
I'd like to exclude certain parts of my build matrix on certain branches. Something conceptually like the following, which doesn't work because branches is not a matrix variable.
name: Tests
on:
pull_request:
push:
branches: [hackage, develop]
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
resolver: [lts-3.22 , lts-17, lts-18, lts, nightly]
exclude:
- branches: [hackage]
resolver: [nightly, lts]
Is there a way to do this idiomatically. Here, for example to exclude nightly and lts resolvers on the hackage branch?
You can use if with github.ref_name to identify the branch and the contains() function to check for matrix.resolver for the parts that you want to exclude.
Example:
if: github.ref_name == 'hackage' && contains(fromJSON('["nightly", "lts"]'), matrix.resolver)
if could be for jobs i.e. jobs.<job_id>.if or steps i.e. jobs.<job_id>.steps[*].if.
I have the following env definition for a job in Github Actions:
jobs:
build-test-deploy:
runs-on: ubuntu-latest
env:
FOO : foobar-${{ github.sha }}
BAR : BAZ
However the github.sha remains identical when the same workflow is re-run without any commit in between. I need the FOO to be unique for every run (even if it's technically a re-run), independently of commits.
Two options I'm thinking of:
either generate a random string
or get the current unix timestamp
I don't know how to get either of these values in the context of the env: directive. There are some actions available to use within steps but how is it possible to get this kind of unique values right from the env directive instead?
There is a github.run_attempt variable now (not sure since when) that increments on re-runs. So by combing that with e.g. github.run_id you can generate per-run fully unique strings.
jobs:
build-test-deploy:
runs-on: ubuntu-latest
env:
FOO : foobar-${{ github.run_id }}-${{ github.run_attempt }}
BAR : BAZ
Make sure to put a delimiter inbetween (- in the example above) as you might get duplicates otherwise. Without it, e.g. 123 could result from both run 12 attempt 3 or run 1 attempt 23.
Quick link to the relevant docs for further reading.
jobs:
build-test-deploy:
runs-on: ubuntu-latest
env:
BAR : BAZ
steps:
- name: generate FOO unique variable based on timestamp
run: echo FOO=foobar--$(date +%s) >> $GITHUB_ENV
- name: other step that needs FOO
run: echo ${{ env.FOO }}
In the github action for Google app engine deploy there is a reference to the id in a github action:
- id: Deploy
uses: google-github-actions/deploy-appengine#main
with:
credentials: ${{ secrets.GCP_SA_KEY }}
But the Github Actions examples don't refer to id, rather it refers to the name as the id:
Each job must have an id to associate with the job. The key job_id is a string and its value is a map of the job's configuration data. You must replace <job_id> with a string that is unique to the jobs object. The <job_id> must start with a letter or _ and contain only alphanumeric characters, -, or _.
jobs:
my_first_job:
name: My first job
my_second_job:
name: My second job
What's the difference?
I believe you are confusing between a step definition, and a job definition.
This is a step:
steps:
- id: deploy
uses: google-github-actions/deploy-appengine#main
with:
credentials: ${{ secrets.gcp_credentials }}
as can be seen in the Usage section of the deploy-appengine repository.
The GitHub Actions workflow syntax documentation is the definitive guide - if you see something written elsewhere that is not mentioned in this guide, it is either a mistake or a misunderstanding.
As for the difference between ID and Name (both in jobs and steps):
ID is used as a reference, from other jobs or steps (for example, in jobs.<job_id>.needs).
Name is used for display purposes on GitHub.
Finally, for completeness, here are the ID/name related entries in the GitHub workflow syntax:
name: Test # <- Workflow name
jobs:
test: # <- Job ID
name: Run test suite # <- Optional Job Name
steps:
- id: checkout # <- Optional step ID
name: Checkout code # <- Optional step name
How can I trim a string in a condition in GitHub actions workflow?
In the following example, the comment can contains accidentally spaces and new lines. I want to trim the spaces in github.event.comment.body:
steps:
- name: "Check CLA signed"
if: github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA'
NOTE: Skip to the end for a better answer.
I believe GitHub Actions expressions are very limited to checking basic things in a workflow, rather than offering programming capabilities.
If you need to go the route of checking different ways of writing a message, your best option is to run a check against the string in a step:
steps:
...
- name: Check if person has accepted and signed CLA
shell: python
run: |
import sys
def check_user_accepted_and_signed(text):
"""Some complex natural language processing will go here"""
comment = '''${{ github.event.comment.body }}'''
if not check_user_accepted_and_signed(comment):
sys.exit(1) # This will abort the job
- name: Not accepted or signed
if: ${{ failure() }}
run: optionally do something if the check fails
- name: Move on if the check passed
run: ...
In the code above, you could also replace the inline Python snippet with a script call from your code base, for a cleaner code:
steps:
- uses: actions/checkout#v3
- name: Check if person has accepted and signed CLA
run: ./scripts/check-accepted-signed-cla.sh '${{ toJSON(github.event.comment.body) }}'
# Single quotes and JSON string prevents bad whitespace interpretation
Simpler is usually better
IMHO though, you'd be better off -- and safer! -- doing simple things. Here's an idea:
Set up your GitHub repository with a default pull request body containing a checkbox, for example:
Write your description.
---
- [ ] I have read the CLA and hereby sign it.
In your workflow, check for that checkbox and fail if it's not checked. Shopify/task-list-checker can be of great help here!
You can find all functions that github actions support here
I think you can use contains function for cover your case