Theme:
Tidbit
  • devops|
  • productivity

GitHub Actions step outputs

Guy Waldman's ProfileGuy Waldman
July 12, 2024
Time to read:
3 minutes
So you've created a GitHub Actions workflow and you want to reuse the output of one step in another step.
I present an easy way to do that.
Suppose we have the following workflow:
Note
This is a simplified example with better ways to do this, but it should hopefully convey the main idea.
1name: My workflow 2 3on: 4 pull_request: 5 branches: [dev, main, release-*] 6 7jobs: 8 test: 9 name: Run tests 10 steps: 11 # ... (omitted) 12 13 - name: Run tests 14 run: npm test 15 env: 16 CPU_CORES: 8 # TODO: Get this from the actual CI environment. 17 18 # ... (omitted) 19
OK, and now you want to handle that TODO, and populate CPU_CORES according to the actual system you're running the test on.
So you write a small script that does this in a cross-platform way (let's say only UNIX-like systems) and call it get-cpu-cores.sh.
1# ... (omitted) 2 3jobs: 4 test: 5 name: Run tests 6 steps: 7 # ... (omitted) 8 9 - name: Get CPU cores 10 run: ./get-cpu-cores.sh 11 12 - name: Run tests 13 run: npm test 14 env: 15 CPU_CORES: ??? # TODO: Get this from the actual CI environment. 16 17 # ... (omitted) 18
So now how do we get the output of the get-cpu-cores.sh script? If you want to run it and retain the output, you could do it in a number of ways, but GitHub Actions has a nice built-in way to pass along the outputs of a step:
1# ... (omitted) 2 3jobs: 4 test: 5 name: Run tests 6 steps: 7 # ... (omitted) 8 9 - name: Get CPU cores 10 id: get-cpu-cores 11 run: ./get-cpu-cores.sh | { read cores; echo "cpu-cores=$cores" } >> $GITHUB_OUTPUT 12 13 - name: Run tests 14 run: npm test 15 env: 16 CPU_CORES: ${{ steps.get-cpu-cores.outputs.cpu-cores }} 17 18 # ... (omitted) 19
As you can see, we're reading the output of the get-cpu-cores.sh script, and appending cpu-cores=<OUTPUT> (that's what the | { read cores; echo "cpu-cores=$cores" } part does) to the $GITHUB_OUTPUT variable.
You can think of this as an .env file which contains a key-value mapping of outputs from different stpes, and you can append to that. GitHub knows how to parse it and use it as an output for the step with the ID get-cpu-cores.
You can also get more sophisticated! This can now be used as other variables in GitHub Actions, for example only runing steps according to the output of the script:
1# ... (omitted) 2 3jobs: 4 test: 5 name: Run tests 6 steps: 7 # ... (omitted) 8 9 - name: Get CPU cores 10 id: get-cpu-cores 11 run: ./get-cpu-cores.sh | { read cores; echo "cpu-cores=$cores" } >> $GITHUB_OUTPUT 12 13 - name: Run tests 14 run: npm test 15 env: 16 CPU_CORES: ${{ steps.get-cpu-cores.outputs.cpu-cores }} 17 18 - name: Run heavy tests 19 run: npm run heavy-tests 20 if: steps.get-cpu-cores.outputs.cpu-cores > 8 21 22 # ... (omitted) 23
This is an example scenario where you run the CI on a matrix of different machines and you want to run the "heavy tests" only on more bulky ones.

Related content

    • productivity|
    • ai
    Introducing: magic-cli
    Post
    July 16, 2024
    A command line utility that will make you a magician in the terminal
    • technical|
    • productivity
    Git hooks for fun & profit
    Post
    August 9, 2022
    Using git hooks for developer workflow automation
    • opinion|
    • productivity|
    • ai
    The future of software development
    Post
    June 29, 2021
    What will the future of software tooling look like?
    • technical|
    • productivity
    Loading .env files with no dependencies
    Tidbit
    July 26, 2024
    Loading .env files easily in *NIX shells with no dependencies
    • ide|
    • productivity
    Quickfix in VS Code
    Tidbit
    July 18, 2024
    How to create a VS Code shortcut or vim binding to apply the first quickfix suggestion