Passing env variable inputs to a reusable workflow
Asked Answered
M

6

22

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?

Messmate answered 10/8, 2022 at 11:1 Comment(0)
C
29

After some researches, I found this thread explaining that:

  1. Because you can’t pass ENV variables to the reusable workflow, they are almost useless in this pattern.

Moreover, on the official documentation, it is stated that (emphasis mine):

  • 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 won't be able to achieve what you want using directly the env variable, but there are workarounds. You could 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 "some_var=$SOME_VAR" >> $GITHUB_OUTPUT
          echo "another var: $ANOTHER_VAR"
          echo "another_var=$ANOTHER_VAR" >> $GITHUB_OUTPUT
  
  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 workflows I used to test: main + reusable

And you can check the workflow run with the expected outcome here.

Calchas answered 10/8, 2022 at 11:31 Comment(6)
This work-around is extremely complex for achieving such a simple action. Also, it is unusable for passing secrets because they are automatically removed from outputs.Moria
In reusable workflows, you can inherit secrets, or you have to send them to the workflow as secrets anyway. Therefore, this workaround only makes sense in this context for inputs and env, not for secrets.Calchas
Is there a way to unpack all secrets into the current step's env? Combining that with secrets: inherit in the calling workflow seems like it would solve the problem.Indorse
What do you mean by unpack? What do you want to achieve?Calchas
Is there anyway I could do this dynamically? say - i have a list of 15-20 environment variablesSweetening
You could eventually use an env file as input to the reusable workflow. And have a first job in the reusable workflow that would read this file and set output for each value set into it.Calchas
S
8

Lately GitHub introduced a feature to support variables in environment (very basic and the long awaited feature, I must say).
So other solution could be to create an environment in GitHub, create some variables under it with desired values and use the environment as needed.

Caller workflow:

jobs:
  Dev-Deployment:
    uses: ./.github/workflows/reusable-workflow.yml
    with:
        environment: Development

  QA-Deployment:
    uses: ./.github/workflows/reusable-workflow.yml
    with:
        environment: QA

Reusable workflow:

on:
 workflow_call:
  inputs:
    environment:
      type: string
      required: true

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: ${{ inputs.environment }}
    steps:
      - name: Print variables - ${{ vars.SOME_VAR }} - ${{ vars.ANOTHER_VAR }}
        run: |
            echo ${{ vars.SOME_VAR }}
            echo ${{ vars.ANOTHER_VAR }}

GitHub environment:

enter image description here

Straightjacket answered 16/9, 2023 at 5:18 Comment(2)
I think they might have changed it.... vars.<ID> gets changed to secrets.<ID> when the workflow is run. I can't find this documentation anywhere, but it works....Zicarelli
Can confirm that this works as of 31.07.2024 👍Squid
A
2

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
Auburn answered 3/2, 2023 at 18:16 Comment(0)
S
2

A simple experiment shows that it is not necessary to echo variable to the $GITHUB_OUTPUT and it is enough to define it just in the outputs

name: Test outputs

on:
  workflow_dispatch:

env:
  BRANCH: main

jobs:
  variables:
    name: Compute outputs
    runs-on: ubuntu-latest
    outputs:
      branch: ${{ env.BRANCH }}
      # branch: ${{ steps.variables.outputs.branch }}
    steps:
      - name: Echo
        if: false
        run: echo

      # - name: Set outputs variables
      #   id: variables
      #   run: echo
      #     echo "branch=${{ env.BRANCH }}" >> "$GITHUB_OUTPUT"

  show:
    name: Show outputs
    needs: variables
    runs-on: ubuntu-latest
    steps:
      - name: Echo outputs
        run: |
          echo "branch: ${{ needs.variables.outputs.branch }}"

This simplify variables pass, especially when we have a lot of them. It can be used for simple cases when we need just to pass variable value, but not for computations.

A single cons is that we need at least one step in the first job, but we can set a dummy one or disable it.

Sibylsibylla answered 19/11, 2023 at 20:18 Comment(0)
E
1

If you are looking to retrieve a variable defined at the GitHub repository settings level, here is how I accessed this value:

name: Decrypt env.enc file to .env and load in variable ENV content

on:
  workflow_call:
    secrets:
      MAIN_SECRET_KEY_SOPS:
        required: true

env:
  env_exemple: ${{ vars.REPOSITORY_API_PATH }}

jobs:
  testVars:
    runs-on: ubuntu-latest
    steps:
      - name: Print example value created in GitHub repository variable:API_PATH
        run: echo ${{ env.env_exemple }}

vars contexte : https://docs.github.com/en/actions/learn-github-actions/variables

With the vars context, you don't need to pass the value to workflow_call; it's already accessible

Explain answered 15/5 at 14:57 Comment(0)
H
0

You can access your workflow_dispatch (defined in caller workflow) inputs via ${{github.event.inputs}} from the reusable workflow

Note: your workflow_dispatch must be in the default (master) branch``

Handmaid answered 19/4 at 18:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.