Expose runner version in the runner context

Request:

In the runner context object, add version to allow jobs to access the version of actions/runner that the job currently being run with.

Use case:

I have a job that runs on macOS-latest and produces an artifact containing code coverage results (lcov.info). The coverage payload contains absolute file paths.

For example, in a GitHub repo named foo where one of the source files is src/bar.ts, the LCOV report would include something like:

SF:/Users/runner/runners/2.164.0/work/foo/foo/src/bar.ts

Later in the workflow, another job (running on ubuntu-latest) collects the lcov.info file(s) produced from earlier jobs, formats & merges them together into a single coverage report, and uploads them them to my code analysis service of choice (CodeClimate).

The issue is that CodeClimate’s CLI utility for formatting raw LCOV files needs to strip the prefix from absolute paths in the coverage payload, making them relative to the project root.

The command provides a --prefix argument that can be used to specify the prefix to strip.

An example of what the format command currently looks like is:

jobs:
job1:
runs-on: macOS-latest
steps:
...

job2:
    runs-on: ubuntu-latest
    needs: job1
    steps:
      - run: ./cc-test-reporter format-coverage --prefix /Users/runner/runners/2.164.0/work/foo/foo --input-type lcov --output coverage.json lcov.info

The problem is the runner version (2.164.0) hardcoded into the above command.  Every few weeks the workflow YAML needs to be updated when a new actions/runner version is released.

Ideally, I’d like to be able to do something like:

jobs:
  job1:
    runs-on: macOS-latest
    steps:
      ...

  job2:
    runs-on: ubuntu-latest
    needs: job1
    steps:
      - run: ./cc-test-reporter format-coverage --prefix /Users/runner/runners/${{ runner.version }}/work/foo/foo --input-type lcov --output coverage.json lcov.info

…replacing the hardcoded version number with a ${{ runner.version }} expression.

This assumes that the runner version for all virtual environments is the same (so a job running on macOS-latest and another job running on ubuntu-latest would share the same runner version). I’m not sure if that is the case or not.

Unfortunately, the runner context doesn’t expose the current version number as far as I can tell.

Workaround:
An alternative may be to add an output in the macOS job to save the current working directory; and reference that output later:

jobs:
  job1:
    runs-on: macOS-latest
    steps:
      - run: echo "::set-output name=prefix::$PWD"

  job2:
    runs-on: ubuntu-latest
    needs: job1
    steps:
      - run: ./cc-test-reporter format-coverage --prefix ${{ needs.job1.outputs.prefix }} --input-type lcov --output coverage.json lcov.info

@scottohara ,

The directory " /Users/runner/runners/2.164.0/work/foo/foo" actually is the workspace (the default working directory, github.workspace ) for the job1 that runs on macos-latest in your workflow, and you can easily use the property " github.workspace" of the github context to access this directory.

So, on job2 , you do not need to set this directory as a hardcoded in the command line, as you mentioned you can use the outputs.

You can do as the following steps:
1) On job1 , use the syntax “jobs.<jobs_id>.outputs” to set a job-level output to store the workspace of job1.

2) On job2 , because job2 needs job1 must complete successfully before job2 will run, you should use the syntax “jobs.<job_id>.needs” on job2.

3) In the steps of job2 , you can use property " needs.<job id>.outputs.<output name>" of the needs context to access the job-level output set on job1.

A simple demo:

jobs:
  job1:
    name: Job 1
    outputs:
      prefix: ${{ github.workspace }}
    runs-on: macos-latest
    steps:
     . . .

  job2:
    name: Job 2
    needs: [job1]
    runs-on: ubuntu-latest
    steps:
      - name: view the output of job1
        run: echo "needs.job1.outputs.prefix = ${{ needs.job1.outputs.prefix }}"

NOTE: if you set the output in a step of  job1 , you can’t directly access this output on job2 , you still need to set a job-level output on job1 , and pass the step-level output to the job-level output.

jobs:
  job1:
    name: Job 1
    outputs:
      prefix: ${{ steps.set_output.outputs.dir_prefix }}
    runs-on: macos-latest
    steps:
      - name: set output
id: set_output
run: echo "::set-output name=dir_prefix::${{ github.workspace }}"

  job2:
    name: Job 2
    needs: [job1]
    runs-on: ubuntu-latest
    steps:
      - name: view the output of job1
        run: echo "needs.job1.outputs.prefix = ${{ needs.job1.outputs.prefix }}"
1 Like

Thanks so much @brightran !

I’ll give this a try.

I may have been too quick to mark this as the correct solution.

Unfortunately, when attempting to use ${{ github.workspace }} as a job output, the following warning appears at the end of job1:

Complete job
  Evaluate and set job outputs
  ##[warning]Skip output 'workspace' since it may contain secret.
  Cleaning up orphan processes

Later in job2, the output is not available (empty).

According to the documentation (emphasis mine):

Job outputs are strings, and job outputs containing expressions are evaluated on the runner at the end of each job. Outputs containing secrets are redacted on the runner and not sent to GitHub Actions.

I’m assuming that the ‘secret’ is the name of the repo that appears in the workspace path, as I can see in other logs that this is masked out:

Uploading artifact 'lcov.info' from '/Users/runner/runners/2.169.1/work/ ***/*** /coverage/frontend/lcov.info' for run #43

Any other suggestions?

@scottohara ,

No, by default the workspace directory and the repository name will not be set as secrets , they are public and you can explicitly view their values from the github context.
I just tested again minutes ago, I did not get any warning or error when I passed the ${{ github.workspace }} to the job-level output and step-level output. And I also can fetch the correct value of the outputs in the subsequent job.
I tested this on my public repository and private repository, all of them can work fine as expected.
The example I tested on my side: https://github.com/BrightRan/TestOutputs/actions/runs/92016491/workflow

You can try to check if you have set some secrets in your repository, and the value of a secret contains or equals the  repository name.

Hi @brightran,

You are absolutely right…I do have a secret whose value matches the name of the repository, so that’s exactly what looks to be happening.

Luckily, I should be able to change the secret value to something else (it was only the same as the repo name for convenience); so I’ll give this a try.

(I’ll wait until I’ve confirmed this works before marking your earlier response as the solution, just to be sure :slight_smile:

Thanks again.