Testes automatizados so tem valor quando rodam de forma consistente em cada mudanca de codigo. CI/CD (Continuous Integration / Continuous Delivery) garante que cada commit seja testado automaticamente antes de ser aceito. Neste artigo final da serie, configuramos pipelines completos para projetos Zig usando GitHub Actions.
Continuacao do artigo sobre testes de integracao em Zig.
GitHub Actions para Zig
Pipeline Basico
O workflow mais simples para testar um projeto Zig:
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Instalar Zig
uses: mlugg/setup-zig@v1
with:
version: 0.14.0
- name: Executar testes
run: zig build test
- name: Build
run: zig build -Doptimize=ReleaseSafe
Pipeline Completo com Matrix
Teste em multiplas plataformas e versoes do Zig:
name: CI Completo
on:
push:
branches: [main]
pull_request:
jobs:
test:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
zig-version: ["0.14.0", "master"]
fail-fast: false
runs-on: ${{ matrix.os }}
name: "${{ matrix.os }} - Zig ${{ matrix.zig-version }}"
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Instalar Zig
uses: mlugg/setup-zig@v1
with:
version: ${{ matrix.zig-version }}
- name: Verificar formatacao
run: zig fmt --check src/
- name: Testes unitarios
run: zig build test --summary all
- name: Testes em modo Debug
run: zig build test -Doptimize=Debug
- name: Testes em modo ReleaseSafe
run: zig build test -Doptimize=ReleaseSafe
- name: Testes em modo ReleaseFast
run: zig build test -Doptimize=ReleaseFast
- name: Testes em modo ReleaseSmall
run: zig build test -Doptimize=ReleaseSmall
- name: Build de producao
run: zig build -Doptimize=ReleaseSafe
- name: Upload artefatos
uses: actions/upload-artifact@v4
with:
name: build-${{ matrix.os }}-${{ matrix.zig-version }}
path: zig-out/
Configurando build.zig para CI
O build.zig deve expor steps claros para a CI:
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
// Executavel principal
const exe = b.addExecutable(.{
.name = "minha-app",
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
b.installArtifact(exe);
// === TESTES ===
// Testes unitarios
const unit_tests = b.addTest(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
const run_unit_tests = b.addRunArtifact(unit_tests);
// Testes de integracao
const integration_tests = b.addTest(.{
.root_source_file = b.path("tests/integration.zig"),
.target = target,
.optimize = optimize,
});
integration_tests.root_module.addImport(
"app",
exe.root_module,
);
const run_integration_tests = b.addRunArtifact(integration_tests);
// Step "test" roda tudo
const test_step = b.step("test", "Executar todos os testes");
test_step.dependOn(&run_unit_tests.step);
test_step.dependOn(&run_integration_tests.step);
// Steps individuais
const unit_step = b.step("test-unit", "Apenas testes unitarios");
unit_step.dependOn(&run_unit_tests.step);
const int_step = b.step("test-integration", "Apenas testes de integracao");
int_step.dependOn(&run_integration_tests.step);
// === FORMATACAO ===
const fmt_step = b.step("fmt", "Formatar codigo");
const fmt = b.addFmt(.{
.paths = &.{ "src/", "tests/" },
});
fmt_step.dependOn(&fmt.step);
// === CHECK (compilacao sem gerar binario) ===
const check_step = b.step("check", "Verificar compilacao");
const check = b.addTest(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
check_step.dependOn(&check.step);
}
Cross-Platform Testing
Build e Teste para Multiplos Targets
name: Cross-Platform Build
on:
push:
branches: [main]
jobs:
cross-build:
runs-on: ubuntu-latest
strategy:
matrix:
target:
- x86_64-linux-musl
- aarch64-linux-musl
- x86_64-macos
- aarch64-macos
- x86_64-windows
steps:
- uses: actions/checkout@v4
- name: Instalar Zig
uses: mlugg/setup-zig@v1
with:
version: 0.14.0
- name: Cross-compile para ${{ matrix.target }}
run: zig build -Dtarget=${{ matrix.target }} -Doptimize=ReleaseSafe
- name: Upload binario
uses: actions/upload-artifact@v4
with:
name: app-${{ matrix.target }}
path: zig-out/bin/
Testando em ARM com QEMU
test-arm:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Instalar Zig
uses: mlugg/setup-zig@v1
with:
version: 0.14.0
- name: Instalar QEMU
run: sudo apt-get install -y qemu-user-static
- name: Testes cross-compiled para ARM64
run: |
zig build test -Dtarget=aarch64-linux-musl --summary all
Code Coverage
Gerando Relatorios de Coverage
Zig suporta instrumentacao para code coverage compativel com LLVM:
coverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Instalar Zig
uses: mlugg/setup-zig@v1
with:
version: 0.14.0
- name: Instalar ferramentas LLVM
run: sudo apt-get install -y llvm
- name: Compilar testes com coverage
run: |
zig build test \
-Doptimize=Debug \
--summary all
- name: Gerar relatorio de coverage
run: |
# Usando kcov para coverage de binarios Zig
sudo apt-get install -y kcov
kcov --include-path=./src coverage-report ./zig-out/bin/test
- name: Upload coverage
uses: codecov/codecov-action@v4
with:
directory: coverage-report
Script Local de Coverage
#!/bin/bash
# coverage.sh — gerar relatorio de coverage localmente
set -e
echo "Compilando testes..."
zig build test -Doptimize=Debug
echo "Executando com kcov..."
kcov --include-path=./src ./coverage-report ./zig-out/bin/test
echo "Relatorio disponivel em: coverage-report/index.html"
# Extrair percentual
PERCENT=$(cat coverage-report/zig-out/bin/test/coverage.json | jq '.percent_covered' 2>/dev/null || echo "N/A")
echo "Coverage: ${PERCENT}%"
Pipeline de Release Automatizado
Workflow Completo de Release
name: Release
on:
push:
tags:
- 'v*'
jobs:
test:
uses: ./.github/workflows/ci.yml
release:
needs: test
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Instalar Zig
uses: mlugg/setup-zig@v1
with:
version: 0.14.0
- name: Build para todas as plataformas
run: |
for target in x86_64-linux-musl aarch64-linux-musl x86_64-macos aarch64-macos x86_64-windows; do
echo "Building para $target..."
zig build -Dtarget=$target -Doptimize=ReleaseSafe
tar czf "minha-app-${target}.tar.gz" -C zig-out/bin/ .
rm -rf zig-out
done
- name: Criar release no GitHub
uses: softprops/action-gh-release@v2
with:
files: "*.tar.gz"
generate_release_notes: true
Linting e Qualidade de Codigo
Verificacao de Formatacao
// No build.zig, adicionar step de verificacao de formato
const fmt_check = b.addFmt(.{
.paths = &.{ "src/", "tests/" },
.check = true, // Verificar sem modificar
});
const fmt_step = b.step("fmt-check", "Verificar formatacao");
fmt_step.dependOn(&fmt_check.step);
Analise Estatica com Zig
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Instalar Zig
uses: mlugg/setup-zig@v1
with:
version: 0.14.0
- name: Verificar formatacao
run: zig fmt --check src/ tests/
- name: Verificar compilacao em todos os modos
run: |
zig build check -Doptimize=Debug
zig build check -Doptimize=ReleaseSafe
zig build check -Doptimize=ReleaseFast
zig build check -Doptimize=ReleaseSmall
- name: Verificar docs
run: zig build-lib src/main.zig -femit-docs
Monitorando Resultados
Badge de Status no README
# Meu Projeto Zig
[](https://github.com/usuario/projeto/actions/workflows/ci.yml)
[](https://codecov.io/gh/usuario/projeto)
Notificacoes de Falha
notify:
needs: [test]
if: failure()
runs-on: ubuntu-latest
steps:
- name: Notificar falha
uses: 8398a7/action-slack@v3
with:
status: failure
text: "CI falhou no branch ${{ github.ref }}"
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
Boas Praticas de CI/CD para Zig
1. Fail Fast
Execute verificacoes rapidas primeiro:
steps:
# Rapido: verificar formato (segundos)
- run: zig fmt --check src/
# Medio: compilar (dezenas de segundos)
- run: zig build check
# Lento: testes completos (minutos)
- run: zig build test --summary all
2. Cache de Dependencias
- name: Cache Zig
uses: actions/cache@v4
with:
path: |
~/.cache/zig
zig-cache
key: ${{ runner.os }}-zig-${{ hashFiles('build.zig.zon') }}
3. Testes Paralelos
Separe testes rapidos de lentos:
jobs:
unit-tests:
runs-on: ubuntu-latest
steps:
- run: zig build test-unit
integration-tests:
runs-on: ubuntu-latest
steps:
- run: zig build test-integration
# So faz release se ambos passarem
release:
needs: [unit-tests, integration-tests]
Conclusao
CI/CD transforma testes de uma pratica manual em uma rede de seguranca automatica. Com Zig, a configuracao e particularmente simples: sem dependencias de runtime, cross-compilation nativa e build system integrado significam que seus pipelines sao rapidos, reproduziveis e faceis de manter. A combinacao de testes unitarios, de integracao, fuzz testing e CI/CD cria um sistema robusto de garantia de qualidade para qualquer projeto Zig.
Serie Completa
Esta e a conclusao da serie Testes Avancados em Zig:
- Fundamentos de Unit Tests
- Test Patterns
- Fuzz Testing
- Testes de Integracao
- CI/CD e Automacao (este artigo)
Conteudo Relacionado
- Zig Build System — Sistema de build
- Ferramentas de Desenvolvimento Zig — Tooling
- Zig e Docker — Containers
- Checklist de Code Review — Code review
- Otimização de Performance — Performance