Avoid building actions that won't be needed?

Lets say I have the following within a workflow:

    steps:
    - name: Checkout repo
      if: matrix.runner == 'runner1'
      uses: actions/checkout@v2

    - name: Do something
      if: matrix.runner == 'runner2'
      uses: some_name/some-action@master

where runner1 and runner2 refer to two different self hosted runners - we have some suitable, e.g., runs-on: ${{ matrix.tags }} at the start of the job which, lets say here, results in two jobs. So job 1 only needs checkout and job 2 only needs some-action. But at the start of both jobs both actions will be downloaded and built. If some-action relies on, e.g., docker which is not installed on runner 1 the workflow fails, we get a Build some_name/some-action@master: ##[error]File not found: 'docker'. But since this action won’t be needed on this machine we shouldn’t need to install docker just to get past this step.

Is there currently anyway around this without separating steps at a higher level?

@rhodrin,

Two actions “owner/action1@v2” and “owner/action2@master”.
If you want ‘action1’ only is downloaded and build to run on ‘runner1’, and ‘action2’ only on ‘runner2’, you can try to set your matrix like as this:

jobs:
  job1:
    name: Test
    runs-on: ${{ matrix.runner }}
    strategy:
      matrix:
        include:
          - { runner: runner1, action_repos: 'owner/action1', action_ref: 'v2', s_name: 'step name to run action1' }
          - { runner: runner2, action_repos: 'owner/action2', action_ref: 'master', s_name: 'step name to run action2' }
    steps:
      - name: Checkout action code
        uses: actions/checkout@v2.3.2
        with:
          repository: ${{ matrix.action_repos }}
          ref: ${{ matrix.action_ref }}
          path: 'uses_action'

      - name: ${{ matrix.s_name }}
        uses: ./uses_action

In this way, the source code of the action will be downloaded via the checkout action. If the the action is docker action, the docker build will be executed in the step when running the action, it will not do the docker build before this step.

In your case, you also can set the matrix like this:

jobs:
  job1:
    name: Test
    runs-on: ${{ matrix.runner }}
    strategy:
      matrix:
        include:
          - { runner: runner1 }
          - { runner: runner2, action_repos: 'some_name/some-action', action_ref: 'master', s_name: 'Do something' }
    steps:
      - name: Checkout repo
        if: matrix.runner == 'runner1'
        uses: actions/checkout@v2.3.2

      - name: Checkout action code
        if: matrix.runner == 'runner2'
        uses: actions/checkout@v2.3.2
        with:
          repository: ${{ matrix.action_repos }}
          ref: ${{ matrix.action_ref }}
          path: 'uses_action'

      - name: ${{ matrix.s_name }}
        if: matrix.runner == 'runner2'
        uses: ./uses_action

@brightran

Thanks for the reply and suggestion. Modifying the matrix to contain information about which runner requires which actions is not really an ideal solution in this instance for a variety of reasons, but I’ll have a think re. the best way forward.

Having a more ‘intelligent’ download and build phase based on if statements present would of course be the ideal solution.

@rhodrin,

Modifying the matrix to contain information about which runner requires which actions is not really an ideal solution in this instance for a variety of reasons

Yes, you’re right.
When a runner requires multiple specific actions, this workaround indeed is not good enough.

In your case, when the runner does not require the Docker action, the main thing you need to do is avoiding downloading and building the Docker action so that avoiding the error caused by the docker build.

For the JavaScript and Composite actions, they generally do not need to build before execute the actions. Normally it will not have much effect to download the source files of the actions, even if the runner may do not require the actions.

Alternatively, I have another workaround for your case that you do not need to change the configurations of the matrix. It uses the if statements to skip downloading, building and executing the Docker action.
Theoretically, this workaround is similar to the previous one.

jobs:
  job1:
    runs-on: ${{ matrix.runner }}
    strategy:
      matrix:
        runner: [runner1, runner2]
    steps:
      - name: Checkout repo
        if: matrix.runner == 'runner1'
        uses: actions/checkout@v2.3.2

      - name: Checkout action code
        if: matrix.runner == 'runner2'
        uses: actions/checkout@v2.3.2
        with:
          repository: some_name/docker-action
          ref: master
          path: 'docker-action'

      - name: Execute docker-action
        if: matrix.runner == 'runner2'
        uses: ./docker-action

@brightran Ok, I see - that could potentially work nicely, will try it out. Thanks again for the help.