reusing GitHub workflows

Today I learned a bunch about reusing workflows in #github actions...

uses has a different meaning when in a job vs. in a step

If you want to reuse a workflow you already had, the uses: must be set in a job, like this:

# ...
jobs:
  pr_trigger:
    # ...
    
  trigger_cd_test:
    name: Trigger 'CD - Test' workflow
    needs: pr_trigger
    
    # this 'uses' here refers to a file
    #####################################
    uses: ./.github/workflows/cd_test.yml
    #####################################
    
    with:
      environment: "staging"

This does not work:

# ...
jobs:
  pr_trigger:
    # ...
    steps:
      - name: Trigger 'CD - Test' workflow

        # this does NOT work!
        #####################################
        uses: ./.github/workflows/cd_test.yml
        #####################################
        
        with: # ...

The uses: in a step MUST refer to a GitHub Action (not a workflow file).

passing secrets to a reusable workflow

(I already have some notes about GitHub Actions - Udemy#Reusable Workflows)

I learned this secrets thing in the official documentation.

First, highlight in your reusable workflow that the secret is required:

on:
  workflow_call:
    inputs:
      # ...
    # list the secrets here!
    ########################
    secrets:
      TAILSCALE_AUTHKEY:
        required: true
    ########################

# ...

jobs:
  reusable_workflow_job:
    # ...
    steps:
    # ...
    - name: '[auth] VPN'
      run: |
        chmod +x ./app/scripts/tailscale.sh
        ./app/scripts/tailscale.sh
      # actually using the secret
      #####################################################
      env:
        TAILSCALE_AUTHKEY: ${{ secrets.TAILSCALE_AUTHKEY }}
      #####################################################

And in the caller of the reusable workflow, you can simply use secret: inherit to get the repository's secrets (assuming both files are in the same repo).

# ...
jobs:
  pr_trigger:
    # ...

  trigger_cd_test:
    name: Trigger 'CD - Test' workflow
    needs: pr_trigger
    uses: ./.github/workflows/cd_test.yml
    with:
      environment: "staging"
      # ...
    # here is the trick!
    ####################
    secrets: inherit
    ####################

passing variables from a job to another

This is my (current) chosen way to pass variables from a job to another.

The job where the variable is created should have this:

# ...
jobs:
  pr_trigger:
    # ...
    
    # listing the variables we need to pass to the next jobs
    # note how I'm explicitly saying the vars are being set
    # in a step called `setup` (that's the name I chose)
    outputs:
      ANDROID: ${{ steps.setup.outputs.ANDROID }}
      IOS: ${{ steps.setup.outputs.IOS }}
      SOURCE_BRANCH: ${{ steps.setup.outputs.SOURCE_BRANCH }}
      DESCRIPTION: ${{ steps.setup.outputs.DESCRIPTION }}

    steps:
      - name: Setup variables
        # here's where I define the name to be used in the 
        # outputs section above
        ##################################################
        id: setup
        ##################################################
        # ...
        run: |
          # ...
          # passing variable to the next jobs
          echo "ANDROID=${ANDROID}" >> $GITHUB_OUTPUT
          echo "IOS=${IOS}" >> $GITHUB_OUTPUT
          echo "SOURCE_BRANCH=${SOURCE_BRANCH}" >> $GITHUB_OUTPUT
          echo "DESCRIPTION=${DESCRIPTION}" >> $GITHUB_OUTPUT
          
    # ...

  # in a later job...
  trigger_cd_test:
    name: Trigger 'CD - Test' workflow
    # this 'needs:' is important!
    #############################
    needs: pr_trigger
    #############################
    uses: ./.github/workflows/cd_test.yml
    with:
      # ...
      # here's how I get the vars from the previous job.
      # pattern: `needs.<previous_job_name>.outputs.<VAR>`
      branch: ${{ needs.pr_trigger.outputs.SOURCE_BRANCH }}
      description: ${{ needs.pr_trigger.outputs.DESCRIPTION }}
      #######################################################

a trick to pass the variable contents as a boolean (rather than stringg)

If you reusable workflow expects a boolean, like in here:

# ...

on:
  workflow_call:
    inputs:
      # ...
      ios:
        type: boolean
        required: false
      android:
        type: boolean
        required: false

Then in the caller you need this trick to prevent passing a string when you need a boolean.

# ...
jobs:
  pr_trigger:
    # ...

  trigger_cd_test:
    name: Trigger 'CD - Test' workflow
    needs: pr_trigger
    uses: ./.github/workflows/cd_test.yml
    with:
      environment: "staging"
      # the " == 'true'" is mandatory to pass the values as a boolean
      ###############################################################
      ios: ${{ needs.pr_trigger.outputs.IOS == 'true' }}
      android: ${{ needs.pr_trigger.outputs.ANDROID  == 'true' }}
      ###############################################################

references