Parameterize `runs-on` value for GitHub action
Asked Answered
N

3

5

I have this GitHub workflow that I need to parameterize on which runners runs. So in the YAML file I tried:

# ... 
jobs: 
  process:
    name: Process
    runs-on: ${{ secrets.GH_RUNNER_TAG }}
# ...

However, I get this error:

The workflow is not valid. .github/workflows/action.yml (Line: 12, Col: 14): Unrecognized named-value: 'secrets'. Located at position 1 within expression: secrets.GH_RUNNER_TAG

Is the secrets injection not available for this element? Is there some other alternative? The value does not need to be a secret but I need to have it in one place and not edit hundreds of YAML files everytime the runner tag would change...


EDIT1: I've tried, as GuiFalourd suggested, to create an environment variable at the workflow level which would hold the secret:

env:
  RUNNER_LABEL: ${{ secrets.GH_RUNNER_TAG }}

jobs:
  analyze:
    name: Analyze
    runs-on: $RUNNER_LABEL

And it doesn't work. The action gets stuck. I tried using:

$RUNNER_LABEL -> gets stuck "$RUNNER_LABEL" -> gets stuck, too ${{ env.RUNNER_LABEL }} -> action does not start, outputs error:

The workflow is not valid. .github/workflows/action.yml (Line: 14, Col: 14): Unrecognized named-value: 'env'. Located at position 1 within expression: env.RUNNER_LABEL

Furthermore, I've checked that the env var is properly assigned, by placing a valid, hard-coded value for runs-on and setting first step as:

steps:
  - name: Test
    run: echo "$RUNNER_LABEL"

which produces "***" - proof that a secret has been output and redacted automatically by GitHub.

Noncompliance answered 15/6, 2022 at 14:18 Comment(5)
The secret syntax can't be used directly at every workflow / job level (example). Did you try setting it as a env variable at the workflow level, and then use runs-on: ${{ env.GH_RUNNER_TAG }} instead of directly using the secret? – Infrequent
Thanks @Infrequent ! I've tried several combintions (see the "EDIT1" in my question) but couldn't get anything to work.. – Mind
It was a good try, too bad it didn't work. I tried different implementations as well (such as mixing matrix secrets and envs). Unfortunately, it seems the Github actions workflow interpreter doesn't support using secrets or envs at the runs-on job level at the moment 🫀 – Infrequent
@GuiFalourd: Indeed, and thanks for your effort! – Mind
could you Try this ? : ``` env: RUNNER_LABEL: ${{ secrets.GH_RUNNER_TAG }} jobs: analyze: name: Analyze runs-on: ${{ env.RUNNER_LABEL }} ``` – Damson
R
5

This is achievable using Reusable Workflow by configuring the "called" workflow to accept inputs from the caller.

The main pipeline which we can name it as "process" will use a shared codebase/pipeline lets call it "common" which can accept inputs, one of these inputs can be the runs-on value.

For example

# common.yml
name: parameterized job
on:
  workflow_call:
    inputs:
      runner:
        required: true
        type: string
jobs:
  common:
    name: Common
    runs-on: ${{ inputs.runner }}
    steps:
      - run: echo "Hello World"
# process.yml
name: process
on:
  push:

jobs:
  process:
    uses: username/repo/.github/workflows/common.yml@branch
    with:
      runner: machine_with_specific_label # using ${{ env.MY_RUNNER_LABEL }} is possible as well


Retool answered 21/12, 2022 at 18:36 Comment(0)
S
4

Found an alternative without using parameterized workflows. This works while using vars directly as documented in the example does not.

  1. In your workflow, create a prerequisite job that takes a workflow input on a hosted runner and sets the runner name as its output.
  2. Use the output from the prerequisite job to set the runner name on subsequent jobs.

The final workflow will look something like this:

name: Example Workflow

on:
  workflow_dispatch:
    inputs:
      runner:
        required: false
        description: 'Runner name'
        default: 'dev-runner'

jobs:
  prereq:
    runs-on: ubuntu-latest
    steps:
      - name: Provision step # at least one step is required in a job
        run: |
          echo "Provisioning ${{ github.event.inputs.runner }}"
    outputs:
      runner: ${{ github.event.inputs.runner }}
  actualjob:
    needs: prereq
    runs-on: ${{ needs.prereq.outputs.runner }}
    steps:
      - name: Ta-da
        run: echo "success!"
Shaffer answered 9/2 at 19:46 Comment(2)
Commenting here , in case if it helps someone in future. My Scenario : I wanted GH workflow to choose github hosted runner if it is triggered on github cloud vs self hosted runner if triggered on github enterprise server(I have cloned same github.com cloud repo to github server). runs-on: ${{ contains(github.server_url, 'https://github.com') && 'ubuntu-latest' || format('{0}-{1}', vars.MYCONFIGVAR, 'general') }} PS : MYCONFIGVAR is custom configuration variable configured at repository level at github server side. – Necrosis
@sjethvani, you should post it as a separate answer. It's really helpful – Crescantia
D
-1

Try this :

env:
  RUNNER_LABEL: ${{ secrets.GH_RUNNER_TAG }}

jobs:
  analyze:
    name: Analyze
    runs-on: ${{ env.RUNNER_LABEL }}
Damson answered 2/5, 2023 at 0:17 Comment(3)
In my understanding, this proposal has been tested in the original question and the test did not succeed. See "EDIT 1" section of the question. – Duplicity
Since January this should be possible using repository variables, see github.blog/changelog/… – Argillaceous
@Argillaceous I tried and it doesn't work; if you cook a new answer for this SO question I might vote you up :) – Lillie

© 2022 - 2024 β€” McMap. All rights reserved.