GitHub Actions permite automatizar workflows de desenvolvimento diretamente no GitHub. É uma ferramenta poderosa para CI/CD (Integração Contínua/Entrega Contínua).
# Workflow completo para uma aplicação Node.js
name: CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
schedule:
- cron: '0 0 * * *' # Execução diária à meia-noite
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install Dependencies
run: npm ci
- name: Lint
run: npm run lint
- name: Type Check
run: npm run type-check
- name: Test
run: npm test -- --coverage
- name: Upload Coverage
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}name: Deploy Application
env:
# Variáveis globais
APP_NAME: minha-aplicacao
jobs:
deploy:
runs-on: ubuntu-latest
# Variáveis por ambiente
environment:
name: production
url: ${{ steps.deploy.outputs.url }}
env:
# Variáveis do job
DEPLOY_ENV: production
steps:
- uses: actions/checkout@v3
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Deploy to ECS
id: deploy
env:
# Variáveis do step
CONTAINER_IMAGE: ${{ secrets.ECR_REGISTRY }}/${{ env.APP_NAME }}:${{ github.sha }}
run: |
aws ecs update-service --cluster prod-cluster \
--service ${{ env.APP_NAME }} \
--force-new-deploymentname: Cross-Platform Tests
jobs:
test:
strategy:
fail-fast: false # Continua mesmo se um job falhar
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [16, 18, 20]
include:
# Configurações extras para casos específicos
- os: ubuntu-latest
node-version: 18
experimental: true
npm-flags: '--legacy-peer-deps'
exclude:
# Excluir combinações problemáticas
- os: windows-latest
node-version: 16
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: Install Dependencies
run: npm ci ${{ matrix.npm-flags }}
- name: Run Tests
run: npm testname: Optimized Build
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
# Cache do Node.js
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
# Cache do build
- name: Cache Build
uses: actions/cache@v3
with:
path: |
dist
.next
build
public/build
key: ${{ runner.os }}-build-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }}
restore-keys: |
${{ runner.os }}-build-
# Cache do ESLint
- name: Cache ESLint
uses: actions/cache@v3
with:
path: .eslintcache
key: ${{ runner.os }}-eslint-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }}
- name: Install Dependencies
run: npm ci
- name: Build
run: npm run buildname: Production Deploy
on:
push:
tags:
- 'v*'
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: production
url: https://minha-app.com
steps:
- uses: actions/checkout@v3
- name: Create GitHub Release
id: release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
draft: false
prerelease: false
- name: Deploy to Production
id: deploy
uses: my-org/deploy-action@v1
with:
environment: production
token: ${{ secrets.DEPLOY_TOKEN }}
- name: Verify Deployment
run: |
./scripts/verify-deployment.sh
- name: Rollback on Failure
if: failure()
run: |
./scripts/rollback.sh ${{ github.event.before }}name: Multi-Service Integration
jobs:
integrate:
runs-on: ubuntu-latest
steps:
# Docker Build e Push
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and Push
uses: docker/build-push-action@v4
with:
push: true
tags: user/app:latest
# Deploy no Kubernetes
- name: Setup kubectl
uses: azure/setup-kubectl@v3
- name: Deploy to K8s
run: |
kubectl apply -f k8s/
kubectl rollout status deployment/minha-app
# Integração com AWS
- name: Configure AWS
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
# Monitoramento com Datadog
- name: Notify Datadog
run: |
curl -X POST "https://api.datadoghq.com/api/v1/events" \
-H "Content-Type: application/json" \
-H "DD-API-KEY: ${DD_API_KEY}" \
-d @- << EOF
{
"title": "Deployment Completed",
"text": "Version ${{ github.sha }} deployed",
"tags": ["env:prod", "service:api"]
}
EOF# .github/workflows/reusable-build.yml
name: Reusable Build Workflow
on:
workflow_call:
inputs:
node-version:
required: false
type: string
default: '18'
secrets:
npm-token:
required: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: ${{ inputs.node-version }}
registry-url: 'https://registry.npmjs.org'
- name: Build and Test
run: |
npm ci
npm run build
npm test
env:
NODE_AUTH_TOKEN: ${{ secrets.npm-token }}
# Uso do workflow reutilizável
name: Main Pipeline
on: [push]
jobs:
call-build:
uses: ./.github/workflows/reusable-build.yml
with:
node-version: '20'
secrets:
npm-token: ${{ secrets.NPM_TOKEN }}name: Debug Workflow
jobs:
monitor:
runs-on: ubuntu-latest
steps:
- name: Setup tmate session
if: ${{ failure() }}
uses: mxschmitt/action-tmate@v3
- name: Setup Problem Matchers
run: |
echo "::add-matcher::.github/problem-matchers/tsc.json"
echo "::add-matcher::.github/problem-matchers/eslint.json"
- name: Annotate Build
run: |
echo "::warning file=src/app.ts,line=10,col=5::Possível memory leak"
echo "::error file=src/api.ts,line=15::Endpoint inseguro detectado"
- name: Notify Slack
if: always()
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
fields: repo,message,commit,author,action,eventName,ref,workflow,job,took
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
- name: Export Metrics
run: |
echo "workflow_duration_seconds{status=\"${{ job.status }}\"} ${{ steps.measure.outputs.duration }}" >> metrics.txt
- name: Upload Logs
if: always()
uses: actions/upload-artifact@v3
with:
name: workflow-logs
path: |
./**/*.log
./metrics.txt