Skip to main content

GitHub Action: matrix-outputs-write

Workaround implementation - Write matrix jobs outputs

Introduction

GitHub actions have an Jobs need a way to reference all outputs of matrix jobs issue. If there is a job that runs multiple times with strategy.matrix only the latest iteration's output availiable for reference in other jobs.

There is a workaround to address the limitation. We implement the workaround with two GitHub Actions:

v1 - What's new

[!IMPORTANT] cloudposse/github-action-matrix-outputs-write@v1+ is not currently supported on GHES yet. If you are on GHES, you must use v0.

The release of cloudposse/github-action-matrix-outputs-write@v1 and cloudposse/github-action-matrix-outputs-read@v1 are major changes to the backend architecture of Artifacts. They have numerous performance and behavioral improvements.

For more information, see the @actions/artifact documentation.

Breaking Changes

  1. On self hosted runners, additional firewall rules may be required.
  2. Outputs writen with cloudposse/github-action-matrix-outputs-write@v1 can not be read by cloudposse/github-action-matrix-outputs-read@v0and below versions.

Usage

Example how you can use workaround to reference matrix job outputs.

  name: github-action-matrix-outputs-write
on:
pull_request:
branches: [ 'main' ]
types: [opened, synchronize, reopened, closed, labeled, unlabeled]

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
platform: ["i386", "arm64v8"]
steps:
- name: github-action-matrix-outputs-write
uses: actions/checkout@v3

- name: github-action-matrix-outputs-write
id: build
uses: cloudposse/github-action-docker-build-[email protected]
with:
registry: registry.hub.docker.com
organization: "${{ github.event.repository.owner.login }}"
repository: "${{ github.event.repository.name }}"
build-args: |-
PLATFORM=${{ matrix.platform }}

## Write for matrix outputs workaround
- uses: cloudposse/github-action-matrix-outputs-write@v1
id: out
with:
matrix-step-name: github-action-matrix-outputs-write
matrix-key: ${{ matrix.platform }}
outputs: |-
image: ${{ steps.build.outputs.image }}:${{ steps.build.outputs.tag }}
## Multiline string
tags: ${{ toJson(steps.build.outputs.image) }}

## Read matrix outputs
read:
runs-on: ubuntu-latest
needs: [build]
steps:
- uses: cloudposse/github-action-matrix-outputs-read@v1
id: read
with:
matrix-step-name: github-action-matrix-outputs-write

outputs:
result: "${{ steps.read.outputs.result }}"

## This how you can reference matrix output
assert:
runs-on: ubuntu-latest
needs: [read]
steps:
- uses: nick-fields/assert-action@v1
with:
expected: ${{ registry.hub.docker.com }}/${{ github.event.repository.owner.login }}/${{ github.event.repository.name }}:i386
## This how you can reference matrix output
actual: ${{ fromJson(needs.read.outputs.result).image.i386 }}

- uses: nick-fields/assert-action@v1
with:
expected: ${{ registry.hub.docker.com }}/${{ github.event.repository.owner.login }}/${{ github.event.repository.name }}:arm64v8
## This how you can reference matrix output
actual: ${{ fromJson(needs.read.outputs.result).image.arm64v8 }}

Reusable workflow example

Reusable workflow that support matrix outputs

./.github/workflow/build-reusabled.yaml

name: github-action-matrix-outputs-write
on:
workflow_call:
inputs:
registry:
required: true
type: string
organization:
required: true
type: string
repository:
required: true
type: string
platform:
required: true
type: string
matrix-step-name:
required: false
type: string
matrix-key:
required: false
type: string
outputs:
image:
description: "Image"
value: ${{ jobs.write.outputs.image }}

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: github-action-matrix-outputs-write
uses: actions/checkout@v3

- name: github-action-matrix-outputs-write
id: build
uses: cloudposse/github-action-docker-build-[email protected]
with:
registry: ${{ inputs.registry }}
organization: ${{ inputs.organization }}
repository: ${{ inputs.repository }}
build-args: |-
PLATFORM=${{ inputs.platform }}
outputs:
image: ${{ needs.build.outputs.image }}:${{ needs.build.outputs.tag }}

write:
runs-on: ubuntu-latest
needs: [build]
steps:
## Write for matrix outputs workaround
- uses: cloudposse/github-action-matrix-outputs-write@v1
id: out
with:
matrix-step-name: github-action-matrix-outputs-write
matrix-key: ${{ inputs.matrix-key }}
outputs: |-
image: ${{ needs.build.outputs.image }}

outputs:
image: ${{ fromJson(steps.out.outputs.result).image }}
image_alternative: ${{ steps.out.outputs.image }}

Then you can use the workflow with matrix

name: github-action-matrix-outputs-write
on:
pull_request:
branches: [ 'main' ]
types: [opened, synchronize, reopened, closed, labeled, unlabeled]

jobs:
build:
usage: ./.github/workflow/build-reusabled.yaml
strategy:
matrix:
platform: ["i386", "arm64v8"]
with:
registry: registry.hub.docker.com
organization: "${{ github.event.repository.owner.login }}"
repository: "${{ github.event.repository.name }}"
platform: ${{ matrix.platform }}
matrix-step-name: github-action-matrix-outputs-write
matrix-key: ${{ matrix.platform }}

## Read matrix outputs
read:
runs-on: ubuntu-latest
needs: [build]
steps:
- uses: cloudposse/github-action-matrix-outputs-read@v1
id: read
with:
matrix-step-name: github-action-matrix-outputs-write

outputs:
result: "${{ steps.read.outputs.result }}"

## This how you can reference matrix output
assert:
runs-on: ubuntu-latest
needs: [read]
steps:
- uses: nick-fields/assert-action@v1
with:
expected: ${{ registry.hub.docker.com }}/${{ github.event.repository.owner.login }}/${{ github.event.repository.name }}:i386
## This how you can reference matrix output
actual: ${{ fromJson(needs.read.outputs.result).image.i386 }}

- uses: nick-fields/assert-action@v1
with:
expected: ${{ registry.hub.docker.com }}/${{ github.event.repository.owner.login }}/${{ github.event.repository.name }}:arm64v8
## This how you can reference matrix output
actual: ${{ fromJson(needs.read.outputs.result).image.arm64v8 }}

or as a simple job

name: github-action-matrix-outputs-write
on:
pull_request:
branches: [ 'main' ]
types: [opened, synchronize, reopened, closed, labeled, unlabeled]

jobs:
build:
usage: ./.github/workflow/build-reusabled.yaml
with:
registry: registry.hub.docker.com
organization: "${{ github.event.repository.owner.login }}"
repository: "${{ github.event.repository.name }}"
platform: "i386"

## This how you can reference single job output
assert:
runs-on: ubuntu-latest
needs: [build]
steps:
- uses: nick-fields/assert-action@v1
with:
expected: ${{ registry.hub.docker.com }}/${{ github.event.repository.owner.login }}/${{ github.event.repository.name }}:i386
## This how you can reference matrix output
actual: ${{ needs.build.outputs.image }}

Inputs

NameDescriptionDefaultRequired
matrix-keyMatrix keyN/Afalse
matrix-step-nameMatrix step nameN/Afalse
outputsYAML structured map of outputsN/Afalse

Outputs

NameDescription
resultOutputs result (Deprecated!!!)