GitHub Actions Day 15: Sharing Data Between Steps

December 15, 2019

This is day 15 of my GitHub Actions Advent Calendar. If you want to see the whole list of tips as they're published, see the index.

Within a job in GitHub Actions, you can have multiple steps that run one after another. Each step could be invoking an action -- like checking out the code in your repository or installing a particular version of Node.js -- or it could be a run step that simply runs a script that you provide.

But often you want to interact with the steps that ran before you -- for example, you might want to run one step that updates the version number of your software, to get it ready to publish. Then you might want to use that version number in the actual publishing step.

But how do you get that data back and forth? GitHub Actions runs each of your steps within its own process. That means that you can't just set an environment variable in one step and then refer to it in another. In other words, this won't work:

  # This will NOT work.  These two `run` steps are written
  # as different scripts and run by different shells, so
  # the `FOO` variable will NOT persist between them.
  - run: export FOO=bar
  - run: echo $FOO

However, GitHub Actions does give you tools to persist data in the execution environment itself. You can write commands to GitHub Actions by writing to standard output (ie, just using echo) -- including a command to instruct GitHub Actions to set environment variables in subsequent run steps.

After setting the environment variable within the current shell, you can use the set-env command to GitHub Actions, which will cause the environment variable to be injected into future steps:

  # This will set the FOO environment variable within the
  # first `run` script, then instruct GitHub Actions to make
  # it available within subsequent `run` steps as well.
  - run: |
      export FOO=bar
      echo "::set-env name=FOO::$FOO"
  - run: echo $FOO

Now I can actually get the data in the FOO environment variable in my subsequent steps.

set-env in action

GitHub Actions runs these steps as individual scripts -- which means running in individual shell invocations and getting a pristine environment each time. But using the development tools within the GitHub Actions platform, you can share data between the invocations.