Testar seu código em apenas uma versão de Node.js, Python ou Ruby é arriscado. E se seu código quebrar no Python 3.9 mas funcionar no 3.12? E se houver bugs específicos do Windows que você não detecta no Linux? Matrix Strategy do GitHub Actions resolve isso de forma elegante.
O Problema: Compatibilidade Multi-Versão
Imagine este cenário comum:
# Workflow simples jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20' - run: npm test
Problemas: - ❌ Só testa em Node.js 20 - ❌ Só testa em Ubuntu - ❌ Usuários com Node 16 ou 18 podem ter problemas - ❌ Bugs específicos do Windows ou macOS passam despercebidos
Para testar em 3 versões do Node × 3 SOs = 9 combinações, você precisaria de 9 jobs separados. Muito código duplicado!
A Solução: Matrix Strategy
Matrix Strategy permite definir múltiplas dimensões de teste em um único job:
jobs: test: runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] node-version: [16, 18, 20] steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - run: npm test
Resultado: 9 jobs executados em paralelo automaticamente! 🚀
Como Funciona a Matrix
Sintaxe Básica
strategy: matrix: # Cada chave define uma dimensão language: [node, python, go] version: [latest, stable]
GitHub Actions cria produto cartesiano de todas as combinações: - language: node, version: latest - language: node, version: stable - language: python, version: latest - language: python, version: stable - language: go, version: latest - language: go, version: stable
Total: 3 × 2 = 6 jobs
Acessando Valores da Matrix
Use ${{ matrix.variavel }} para acessar o valor atual:
steps: - name: Print current combination run: | echo "Testing ${{ matrix.language }} version ${{ matrix.version }}"
Exemplos Práticos
1. Teste Multi-Versão Node.js
name: Node.js CI on: [push, pull_request] jobs: test: runs-on: ubuntu-latest strategy: matrix: node-version: [16.x, 18.x, 20.x, 21.x] steps: - uses: actions/checkout@v4 - name: Setup Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - name: Install dependencies run: npm ci - name: Run tests run: npm test - name: Run lint run: npm run lint
Resultado: Testa em Node 16, 18, 20 e 21 simultaneamente.
2. Teste Cross-Platform
name: Cross-Platform Tests on: [push, pull_request] jobs: test: strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] python-version: ['3.9', '3.10', '3.11', '3.12'] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - name: Setup Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt - name: Run tests run: pytest
Resultado: 3 SOs × 4 versões Python = 12 jobs em paralelo
3. Matrix com Múltiplas Dimensões
strategy: matrix: os: [ubuntu-latest, windows-latest] node-version: [18, 20] database: [postgres, mysql, sqlite] include: # Adiciona combinação específica - os: macos-latest node-version: 20 database: postgres steps: - name: Start database run: | echo "Starting ${{ matrix.database }} on ${{ matrix.os }}"
Resultado: (2 × 2 × 3) + 1 = 13 jobs
Recursos Avançados
1. Include - Adicionar Combinações Específicas
strategy: matrix: os: [ubuntu-latest] node-version: [18, 20] include: # Testa Node 16 apenas no Ubuntu - os: ubuntu-latest node-version: 16 # Testa Node 20 no macOS também - os: macos-latest node-version: 20 # Adiciona variáveis extras para combinação específica - os: ubuntu-latest node-version: 20 experimental: true
2. Exclude - Remover Combinações Indesejadas
strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] node-version: [16, 18, 20] exclude: # Node 16 não suportado no Windows - os: windows-latest node-version: 16 # Economizar runners - pular macOS para Node 18 - os: macos-latest node-version: 18
Resultado: (3 × 3) - 2 = 7 jobs ao invés de 9
3. Fail-Fast (Padrão: true)
strategy: fail-fast: false # Continua outros jobs mesmo se um falhar matrix: version: [1, 2, 3, 4, 5]
fail-fast: true (padrão): Cancela todos os jobs se um falhar
fail-fast: false: Roda todos independentemente
4. Max-Parallel - Limitar Execuções Simultâneas
strategy: max-parallel: 3 # Apenas 3 jobs por vez matrix: version: [1, 2, 3, 4, 5, 6, 7, 8]
Útil para: - Economizar minutos de CI - Evitar rate limiting de APIs externas - Limitar uso de recursos
Casos de Uso Reais
1. Biblioteca NPM Multi-Versão
name: NPM Package CI on: [push, pull_request] jobs: test: strategy: matrix: node-version: [16, 18, 20, 22] os: [ubuntu-latest, windows-latest, macos-latest] exclude: # Node 22 ainda experimental - os: windows-latest node-version: 22 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - run: npm ci - run: npm test - run: npm run build - name: Test installation run: | npm pack npm install -g *.tgz
2. Aplicação com Múltiplos Bancos
strategy: matrix: database: - type: postgres version: '14' port: 5432 - type: postgres version: '15' port: 5432 - type: mysql version: '8.0' port: 3306 - type: mariadb version: '10.11' port: 3306 steps: - name: Start ${{ matrix.database.type }} run: | docker run -d \ -p ${{ matrix.database.port }}:${{ matrix.database.port }} \ ${{ matrix.database.type }}:${{ matrix.database.version }} - name: Run migrations env: DATABASE_URL: ${{ matrix.database.type }}://localhost:${{ matrix.database.port }}/test run: npm run migrate - name: Run tests run: npm test
3. Build Multi-Arquitetura
strategy: matrix: include: - arch: amd64 os: ubuntu-latest - arch: arm64 os: ubuntu-latest - arch: armv7 os: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Build for ${{ matrix.arch }} run: | docker buildx build \ --platform linux/${{ matrix.arch }} \ -t myapp:${{ matrix.arch }} \ .
Naming e Identificação
Nome Dinâmico do Job
jobs: test: name: Test on ${{ matrix.os }} with Node ${{ matrix.node-version }} strategy: matrix: os: [ubuntu-latest, windows-latest] node-version: [18, 20] runs-on: ${{ matrix.os }}
Resultado na UI: - Test on ubuntu-latest with Node 18 - Test on ubuntu-latest with Node 20 - Test on windows-latest with Node 18 - Test on windows-latest with Node 20
Matrix com Outputs
Você pode usar outputs de uma matrix em jobs subsequentes:
jobs: build: strategy: matrix: version: [v1, v2, v3] outputs: # Não funciona diretamente - precisa workaround artifact-name: myapp-${{ matrix.version }} steps: - run: echo "Building ${{ matrix.version }}" # Alternativa: usar artefatos nomeados deploy: needs: build steps: - uses: actions/download-artifact@v4 with: pattern: myapp-*
Performance e Custos
Minutos de Consumo
Exemplo: Matrix com 12 combinações, cada uma rodando 5 minutos.
fail-fast: true (se nenhum falhar): 5 minutos × 12 = 60 minutos de runner
fail-fast: true (se um falhar em 2min): ~2-5 minutos (cancela os outros)
fail-fast: false: Sempre 60 minutos
Otimizações
- Use cache agressivamente:
- uses: actions/cache@v4 with: path: ~/.npm key: ${{ runner.os }}-node-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }}
- Priorize combinações importantes:
include: - os: ubuntu-latest node-version: 20 priority: high # Rode isso primeiro
- Use max-parallel para controlar custo:
strategy: max-parallel: 2 # Máximo 2 jobs por vez em contas free
Debugging Matrix
Ver Todas as Combinações
jobs: debug: strategy: matrix: os: [ubuntu, windows, macos] version: [1, 2, 3] steps: - name: Print matrix run: | echo "OS: ${{ matrix.os }}" echo "Version: ${{ matrix.version }}" echo "Runner: ${{ runner.os }}"
Testar Uma Combinação
Use workflow_dispatch com inputs:
on: workflow_dispatch: inputs: os: type: choice options: [ubuntu-latest, windows-latest, macos-latest] node-version: type: choice options: [16, 18, 20] jobs: test: runs-on: ${{ inputs.os }} steps: - uses: actions/setup-node@v4 with: node-version: ${{ inputs.node-version }}
Best Practices
- ✅ Sempre teste versões LTS + latest
- ✅ Use fail-fast: false em PRs para ver todos os problemas
- ✅ Documente quais combinações são obrigatórias
- ✅ Use exclude para economizar em combinações não importantes
- ✅ Nomeie jobs descritivamente
- ❌ Evite matrices muito grandes (>20 combinações)
- ❌ Não duplique lógica - use matrix
Conclusão
Matrix Strategy transforma:
# De 100+ linhas de código duplicado test-node-16-ubuntu: ... test-node-18-ubuntu: ... test-node-20-ubuntu: ... test-node-16-windows: ... # ... etc
Para:
# 20 linhas elegantes strategy: matrix: os: [ubuntu, windows, macos] node: [16, 18, 20]
Benefícios: - ⏱️ Economia de tempo - testes em paralelo - 🎯 Mais cobertura - múltiplas combinações facilmente - 🔧 Manutenção simples - um lugar para atualizar - 💰 Controle de custos - max-parallel e exclude
Já usa Matrix Strategy? Compartilhe nos comentários quantas combinações você testa!