Do primeiro workflow ao pipeline completo — automatize testes, build e deploy direto no GitHub com exemplos reais.
O GitHub Actions é uma plataforma de CI/CD (Integração Contínua / Entrega Contínua) integrada ao GitHub — permite automatizar tarefas diretamente no repositório.
Rodar testes automaticamente
Buildar o projeto a cada push
Deploy automático para produção
Executar scripts e automações
Arquivo .yml que define toda a automação. Fica em .github/workflows/.
O que dispara o workflow: push, pull_request, schedule...
Conjunto de steps que roda em uma máquina (runner). Jobs podem rodar em paralelo.
Cada ação dentro de um job — um comando run ou uma action reutilizável.
Máquina virtual que executa o job: ubuntu-latest, windows-latest, macos-latest.
Variável sensível (token, senha) armazenada com segurança no GitHub.
Os workflows ficam em arquivos .yml dentro de .github/workflows/ na raiz do repositório:
name: Meu primeiro workflow
on: [push]
jobs:
exemplo:
runs-on: ubuntu-latest
steps:
- name: Clonar repositório
uses: actions/checkout@v4
- name: Rodar comando
run: echo "Hello World!"
O campo on define quando o workflow é executado. Pode ter múltiplos triggers ao mesmo tempo.
on:
push:
branches: [main, develop]
paths: # opcional: só se mudar esses arquivos
- 'src/**'
- 'package.json'
on:
pull_request:
branches: [main]
types: [opened, synchronize, reopened]
on:
workflow_dispatch: # botão manual na aba Actions
schedule:
- cron: "0 2 * * *" # todo dia às 02:00 UTC
- cron: "0 9 * * 1" # toda segunda às 09:00 UTC
| Evento | Quando dispara |
|---|---|
| push | A cada push em branches configuradas |
| pull_request | Criação ou atualização de PR |
| workflow_dispatch | Manualmente pelo botão na UI do GitHub |
| schedule | Em horários definidos (cron) |
| release | Quando uma release é publicada |
| workflow_call | Chamado por outro workflow |
Actions são blocos reutilizáveis criados pela comunidade — use com uses: owner/action@versão. Encontre em marketplace.github.com.
# Essencial — clona o repo (sempre o primeiro step!)
- uses: actions/checkout@v4
# Configura Node.js
- uses: actions/setup-node@v4
with:
node-version: 18
cache: 'npm' # cache automático do npm
# Configura Python
- uses: actions/setup-python@v5
with:
python-version: '3.11'
# Configura PHP
- uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
# Cache genérico
- uses: actions/cache@v4
# Upload de artefato
- uses: actions/upload-artifact@v4
# Download de artefato
- uses: actions/download-artifact@v4
actions/checkout@v4 em vez de @main. Isso evita quebrar seu pipeline com mudanças inesperadas.name: Node CI
on:
push:
branches: [main]
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 18
cache: 'npm'
- name: Instalar dependências
run: npm ci
- name: Rodar testes
run: npm test
- name: Build
run: npm run build
name: PHP CI
on: [push, pull_request]
jobs:
php:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Instalar PHP 8.2
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
extensions: mbstring, intl, pdo_mysql
coverage: none
- name: Instalar dependências
run: composer install --no-progress --prefer-dist
- name: Rodar testes
run: php artisan test
npm ci em vez de npm install em CI — ele é mais rápido e determinístico, instalando exatamente o que está no package-lock.json.Secrets armazenam dados sensíveis (tokens, senhas, chaves de API) com segurança — nunca aparecem nos logs.
Repositório → Settings → Secrets and variables → Actions → New repository secret
# Exemplos de secrets úteis:
# DEPLOY_KEY → chave SSH para deploy
# DATABASE_URL → URL de banco de dados
# API_TOKEN → token de API externa
# DOCKER_PASSWORD → senha do Docker Hub
env:
APP_ENV: production # variável global do workflow
jobs:
deploy:
runs-on: ubuntu-latest
env:
DB_HOST: localhost # variável do job
steps:
- name: Deploy
env:
TOKEN: ${{ secrets.MEU_TOKEN }} # secret
SSH_KEY: ${{ secrets.DEPLOY_KEY }} # secret
run: |
echo "Token: $TOKEN"
echo "Env: $APP_ENV"
${{ secrets.NOME }} # secrets do repositório
${{ github.ref }} # branch/tag atual
${{ github.sha }} # hash do commit
${{ github.actor }} # quem fez push
${{ runner.os }} # sistema operacional
${{ matrix.node }} # valor da matrix atual
${{ steps.STEP_ID.outputs.NOME }} # output de step anterior
.yml fica público no repositório.Execute o mesmo job em várias combinações de versões ou sistemas automaticamente:
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node: [16, 18, 20]
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- run: npm ci && npm test
- name: Cache node_modules
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Cache Composer
uses: actions/cache@v4
with:
path: vendor
key: ${{ runner.os }}-composer-${{ hashFiles('composer.lock') }}
Use needs para criar dependências entre jobs — o deploy só roda se o build passar:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run build
test:
needs: build # só roda após build
runs-on: ubuntu-latest
steps:
- run: npm test
deploy:
needs: [build, test] # só roda após build E test
runs-on: ubuntu-latest
steps:
- run: echo "Deploy!"
# Job só roda em push na main
deploy:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
# Step só roda se anterior falhar
- name: Notificar falha
if: failure()
run: echo "Build falhou!"
# Step só roda em push (não em PR)
- name: Deploy
if: github.event_name == 'push'
run: ./deploy.sh
- name: Build e test
run: |
echo "Instalando..."
npm ci
echo "Buildando..."
npm run build
echo "Testando..."
npm test
# Job 1: gera o build e faz upload
build:
steps:
- run: npm run build
- uses: actions/upload-artifact@v4
with:
name: build-files
path: dist/
retention-days: 7
# Job 2: baixa e usa o artefato
deploy:
needs: build
steps:
- uses: actions/download-artifact@v4
with:
name: build-files
- run: ls -la # arquivos do dist/ disponíveis aqui
docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Login no Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build e push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: meu-usuario/minha-app:latest
Um pipeline completo de CI/CD para uma aplicação Node.js — lint, testes, build e deploy:
name: CI/CD Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: '18'
jobs:
##──── 1. Lint e testes ────##
test:
name: 🧪 Lint & Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npm test
##──── 2. Build ────##
build:
name: 🏗️ Build
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- run: npm ci && npm run build
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
##──── 3. Deploy (só na main) ────##
deploy:
name: 🚀 Deploy
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
steps:
- uses: actions/download-artifact@v4
with:
name: dist
- name: Deploy via SSH
env:
SSH_KEY: ${{ secrets.DEPLOY_KEY }}
SSH_HOST: ${{ secrets.SERVER_HOST }}
run: |
echo "Deploying to $SSH_HOST..."
# rsync -avz dist/ user@$SSH_HOST:/var/www/app
Jobs diferentes, responsabilidades diferentes — mais fácil debugar.
Reduz o tempo de build de minutos para segundos em projetos grandes.
Nunca hardcode senhas, tokens ou chaves no YAML.
Facilita identificar onde falhou nos logs da aba Actions.
# ❌ Esquecer o checkout — NADA funciona sem ele!
steps:
- run: npm test # o repositório não foi clonado!
# ✅ Checkout SEMPRE como primeiro step
steps:
- uses: actions/checkout@v4
- run: npm test
# ❌ Indentação errada (YAML é sensível!)
steps:
- run: echo "ok" # 4 espaços em vez de 2 — erro!
# ❌ Não usar cache = builds lentos
# Sempre adicione cache para npm, pip, composer, etc.
# ❌ Segredo hardcoded
run: curl -H "Token: abc123secreto" api.exemplo.com
# Workflow → arquivo .yml em .github/workflows/
# on → quando o workflow dispara
# jobs → tarefas paralelas ou sequenciais
# steps → comandos dentro de um job
# uses → action pronta do marketplace
# run → comando shell
# secrets → dados sensíveis seguros
# needs → dependência entre jobs
# matrix → roda em múltiplas versões
# cache → acelera o build