so

Computed values in GitHub actions

Volume 7, Issue 3; 05 Jan 2023

TIL: How to setup the configuration of a GitHub actions workflow so that steps can refer to values computed during the action.

In a couple of workflows, I’ve wanted to be able to read some configuration file or otherwise compute a value and then have that value available in the job that runs. AFAICT, the input of one step can’t read the output of another step (in the same job), so how can we do this?

Today,I didn’t actually learn it today, but I had to find my notes and re-learn it today, so I’m trying to make some better notes. I wanted to write a workflow to build DocBook: The Definitive Guide. In order to know where to put the output, I have to know the DocBook version being documented.

The canonical place to look for that is in the gradle.properties file:

docbookBaseVersion=5.2

(There are other things in there, but they aren’t relevant.)

The document being formatted is, by definition, documenting that version of DocBook.

The trick in the GitHub workflow is to use two jobs. You can declare that the output of one job is available in subsequent jobs. Here’s the workflow:

name: build-specs
on: push
jobs:
  load_config:
    runs-on: ubuntu-latest
    outputs:
      dbversion: ${{ steps.load.outputs.version }}

The first job is named load_config and has an outputs section where we declare what names this job will output. I’m declaring that this job will produce a value called dbversion and that the value will come from the version output of the step named load in this job.

    steps:
      - name: Checkout
        uses: actions/checkout@v3

I have to checkout the branch to read the property file.

      - name: Load the configuration
        id: load
        run: |
          echo version=`cat gradle.properties \
               | grep "^docbookBaseVersion" \
               | cut -f2 -d=` >> $GITHUB_OUTPUT

And here’s the magic. This step has the id load (that’s the “load” part of steps.load.outputs.version above). When it runs, it writes name/value pairs by appending them to the magic file $GITHUB_OUTPUT. You can output as many pairs as you want, but you must declare them all in the outputs: section.

That’s the end of this job. Now the next job:

  build-and-deploy:
    runs-on: ubuntu-latest
    needs: load_config

We begin by saying this job “needs” the load_config job. In this job, we can refer to the version number computed by the load_config job using the special expression needs.load_config.outputs.dbversion.

    env:
      DBVERSION: ${{ needs.load_config.outputs.dbversion }}

I’m copying the computed value into an environment variable. This isn’t strictly necessary, but it’s easier to type env.DBVERSION than needs.load_config.outputs.dbversion and having these kinds of computed values in environment variables is conceptually familiar.

    steps:
      - name: Checkout the specifications
        uses: actions/checkout@v3

This job checks out the sources too, though I’m not actually using them in this example.

      - name: What version is this?
        run: |
          echo DocBook version ${{ env.DBVERSION }}

Finally, this task prints the DocBook version, demonstrating that we computed it successfully!

Here’s the complete workflow, for reference:

name: build-specs
on: push
jobs:
  load_config:
    runs-on: ubuntu-latest
    outputs:
      dbversion: ${{ steps.load.outputs.version }}
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Load the configuration
        id: load
        run: |
          echo version=`cat gradle.properties \
               | grep "^docbookBaseVersion" \
               | cut -f2 -d=` >> $GITHUB_OUTPUT

  build-and-deploy:
    runs-on: ubuntu-latest
    needs: load_config
    env:
      DBVERSION: ${{ needs.load_config.outputs.dbversion }}

    steps:
      - name: Checkout the specifications
        uses: actions/checkout@v3

      - name: What version is this?
        run: |
          echo DocBook version ${{ env.DBVERSION }}

#TIL#GitHub#GitHubActions

Please provide your name and email address. Your email address will not be displayed and I won’t spam you, I promise. Your name and a link to your web address, if you provide one, will be displayed.

Your name:

Your email:

Homepage:

Do you comprehend the words on this page? (Please demonstrate that you aren't a mindless, screen-scraping robot.)

What is six times four?   (e.g. six plus two is 8)

Enter your comment in the box below. You may style your comment with the CommonMark flavor of Markdown.

All comments are moderated. I don’t promise to preserve all of your formatting and I reserve the right to remove comments for any reason.