docs/matrix.md
Rama main · réplica de lectura del repositorio original.
# Matrix Testing with Reusable Workflows
This document explains how to use a matrix strategy with reusable workflows to run isolated test environments on AWS. Each reusable workflow manages its own `start -> test -> always-cleanup` lifecycle. This ensures that instance mappings are not lost through matrix job outputs and that each matrix job runs on its own isolated runner labels.
## Prerequisites
Before starting, complete the [AWS setup](aws.md) to configure the OIDC provider and IAM role. You also need the `AWS_ROLE` and `GH_PAT` secrets configured in your repository. Replace `<The name of your AMI you want to use>` with the name of your AMI.
## Overview
When using ephemeral runners with a matrix, each matrix job must have its own lifecycle. If runner startup is itself a matrix job, its outputs (such as instance mappings) can be overwritten by another matrix entry. Keeping the start, test, and stop jobs together within the reusable workflow avoids this problem.
Save the caller workflow as `.github/workflows/matrix-test.yaml` and the reusable workflow as `.github/workflows/reusable-matrix-test.yaml` so the relative `uses: ./.github/workflows/reusable-matrix-test.yaml` path resolves correctly.
The recommended pattern is:
1. A **caller workflow** defines the matrix and invokes a reusable workflow for each matrix entry.
2. The **reusable workflow** contains the complete lifecycle: `start-aws-runner`, `test`, and `stop-aws-runner`.
3. The instance mapping is passed directly from the start job to the stop job within the reusable workflow, so it is never lost.
## Caller Workflow
The caller workflow uses a matrix strategy and calls the reusable workflow. It preserves secret passing with `secrets: inherit` and grants the necessary OIDC permissions.
```yaml
name: Matrix Test Caller
on:
workflow_dispatch:
jobs:
matrix-test:
name: Run Matrix Test
strategy:
fail-fast: false
matrix:
# Add the GPU-capable instance types you want to test.
instance_type: ["g4dn.xlarge", "g4dn.2xlarge"]
uses: ./.github/workflows/reusable-matrix-test.yaml
permissions:
id-token: write
contents: read
with:
instance_type: ${{ matrix.instance_type }}
secrets: inherit
```
## Reusable Workflow
The reusable workflow contains the full lifecycle. It accepts the `instance_type` as an input, starts the runner, runs the test on the isolated runner labels, and always stops the runner, even if the test fails.
```yaml
name: Reusable Matrix Test
on:
workflow_call:
inputs:
instance_type:
required: true
type: string
jobs:
start-aws-runner:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
outputs:
mapping: ${{ steps.aws-start.outputs.mapping }}
instances: ${{ steps.aws-start.outputs.instances }}
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@e1253824e5c10ff9df46874f81ed3ec929e19cfd # v6.3.0
with:
role-to-assume: ${{ secrets.AWS_ROLE }}
aws-region: us-east-1
- name: Create cloud runner
id: aws-start
uses: omsf/start-aws-gha-runner@8523c3b2474a899636f06e6cab4829c853e107dc # v1.4.0
with:
aws_image_name: <The name of your AMI you want to use>
aws_image_id: latest
aws_instance_type: ${{ inputs.instance_type }}
aws_home_dir: /home/ubuntu
env:
GH_PAT: ${{ secrets.GH_PAT }}
test:
runs-on: ${{ fromJSON(needs.start-aws-runner.outputs.instances) }}
needs:
- start-aws-runner
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Run test
run: |
# Replace this with your project's test commands.
nvidia-smi
stop-aws-runner:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
needs:
- start-aws-runner
- test
if: ${{ always() }}
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@e1253824e5c10ff9df46874f81ed3ec929e19cfd # v6.3.0
with:
role-to-assume: ${{ secrets.AWS_ROLE }}
aws-region: us-east-1
- name: Stop instances
uses: omsf/stop-aws-gha-runner@a3d2e34cba8571eaf9b40ae00705d6b2b77402f6 # v1.0.0
with:
instance_mapping: ${{ needs.start-aws-runner.outputs.mapping }}
env:
GH_PAT: ${{ secrets.GH_PAT }}
```
## Key Considerations
- **fail-fast: false**: The matrix strategy uses `fail-fast: false` so that a failure in one matrix job does not cancel other jobs. Each job manages its own lifecycle independently.
- **Cleanup after test failure**: The `stop-aws-runner` job uses `if: ${{ always() }}` to ensure cleanup happens even if the test fails.
- **Isolated runner labels**: The `test` job uses `runs-on: ${{ fromJSON(needs.start-aws-runner.outputs.instances) }}` to run on the specific instances provisioned for that matrix job.
- **No lost mappings**: The `mapping` output is used directly within the reusable workflow. It is never passed as an output of the matrix job, so it cannot be lost or overwritten by other matrix jobs.
- **Secrets**: The caller uses `secrets: inherit` to pass the required secrets to the reusable workflow. The reusable workflow accesses `secrets.AWS_ROLE` and `secrets.GH_PAT`.
- **OIDC permissions**: Both the start and stop jobs have `id-token: write` permissions to allow the AWS actions to assume the role via OIDC.
- **Pinned SHAs**: All third-party actions are pinned to specific commit SHAs for security and reproducibility.
- **GPU-only tests**: Use GPU-capable instance types for GPU-only tests. Running GPU tests on CPU instances will fail.