GitHub Actions
Workflows detalhados de CI/CD com GitHub Actions.
Workflow: CI (Continuous Integration)
.github/workflows/ci.yml:
name: CI
on:
pull_request:
push:
branches: [dev, main]
jobs:
lint-and-test:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'
- name: Install Python dependencies
run: |
pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-dev.txt
- name: Lint Python
run: |
ruff check .
black --check .
- name: Test Python
run: |
pytest --cov --cov-report=xml --cov-report=term
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
files: ./coverage.xml
flags: backend
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install Node dependencies
run: npm ci
- name: Lint Frontend
run: npm run lint
- name: Test Frontend
run: npm test -- --coverage --watchAll=false
- name: Upload frontend coverage
uses: codecov/codecov-action@v3
with:
files: ./coverage/lcov.info
flags: frontend
- name: Setup SAM CLI
uses: aws-actions/setup-sam@v2
- name: Validate SAM templates
run: sam validate --lint
- name: Security scan (Python)
run: |
pip install bandit
bandit -r app/ -f json -o bandit-report.json || true
- name: Security scan (Node)
run: npm audit --audit-level=moderate
Workflow: Deploy to Staging
.github/workflows/deploy-staging.yml:
name: Deploy to Staging
on:
push:
branches: [dev]
workflow_dispatch: # Manual trigger
concurrency:
group: deploy-staging
cancel-in-progress: false
jobs:
deploy:
runs-on: ubuntu-latest
timeout-minutes: 20
environment:
name: staging
url: https://staging.seuapp.com
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Setup SAM CLI
uses: aws-actions/setup-sam@v2
- name: Configure AWS credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/GitHubActionsRole
aws-region: ${{ secrets.AWS_REGION }}
- name: Install dependencies
run: pip install -r requirements.txt
- name: Run database migrations
env:
DATABASE_URL: ${{ secrets.STAGING_DATABASE_URL }}
run: |
pip install alembic
alembic upgrade head
- name: Verify migration
env:
DATABASE_URL: ${{ secrets.STAGING_DATABASE_URL }}
run: |
alembic current
python scripts/verify_schema.py
- name: SAM Build
run: sam build --use-container
- name: SAM Deploy
run: |
sam deploy \
--config-env staging \
--no-confirm-changeset \
--no-fail-on-empty-changeset \
--parameter-overrides \
Environment=staging \
DatabaseUrl=${{ secrets.STAGING_DATABASE_URL }}
- name: Run smoke tests
run: |
pip install pytest httpx
pytest tests/smoke/ --env=staging -v
- name: Notify team (Success)
if: success()
uses: slackapi/slack-github-action@v1
with:
webhook-url: ${{ secrets.SLACK_WEBHOOK }}
payload: |
{
"text": "✅ Deploy to staging completed successfully!",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Deploy to Staging Success* ✅\n\n*Commit:* `${{ github.sha }}` \n*Author:* ${{ github.actor }}\n*URL:* https://staging.seuapp.com"
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {"type": "plain_text", "text": "View Logs"},
"url": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
}
]
}
]
}
- name: Notify team (Failure)
if: failure()
uses: slackapi/slack-github-action@v1
with:
webhook-url: ${{ secrets.SLACK_WEBHOOK }}
payload: |
{
"text": "❌ Deploy to staging FAILED!",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Deploy to Staging Failed* ❌\n\n*Commit:* `${{ github.sha }}`\n*Author:* ${{ github.actor }}\n\n<!channel> Please check!"
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {"type": "plain_text", "text": "View Logs"},
"url": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}",
"style": "danger"
}
]
}
]
}
Workflow: Deploy to Production
.github/workflows/deploy-production.yml:
name: Deploy to Production
on:
push:
branches: [main]
workflow_dispatch:
inputs:
skip_tests:
description: 'Skip smoke tests (emergency only)'
required: false
default: 'false'
concurrency:
group: deploy-production
cancel-in-progress: false
jobs:
deploy:
runs-on: ubuntu-latest
timeout-minutes: 30
environment:
name: production
url: https://seuapp.com
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Setup SAM CLI
uses: aws-actions/setup-sam@v2
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/GitHubActionsRole
aws-region: ${{ secrets.AWS_REGION }}
- name: Backup production database
run: |
aws rds create-db-snapshot \
--db-instance-identifier prod-db \
--db-snapshot-identifier "pre-deploy-$(date +%Y%m%d-%H%M%S)" \
--tags Key=Type,Value=PreDeployment Key=Commit,Value=${{ github.sha }}
echo "✅ Database snapshot created"
- name: Run database migrations
env:
DATABASE_URL: ${{ secrets.PROD_DATABASE_URL }}
run: |
pip install alembic psycopg2-binary
alembic -c alembic.prod.ini upgrade head
- name: Verify migration
env:
DATABASE_URL: ${{ secrets.PROD_DATABASE_URL }}
run: |
alembic -c alembic.prod.ini current
python scripts/verify_schema.py
- name: SAM Build
run: sam build --use-container
- name: SAM Deploy to Production
run: |
sam deploy \
--config-env production \
--no-confirm-changeset \
--no-fail-on-empty-changeset \
--parameter-overrides \
Environment=production \
DatabaseUrl=${{ secrets.PROD_DATABASE_URL }}
- name: Create release tag
run: |
VERSION=$(date +%Y.%m.%d-%H%M)
git tag "v$VERSION"
git push origin "v$VERSION"
echo "✅ Created tag: v$VERSION"
- name: Run smoke tests
if: github.event.inputs.skip_tests != 'true'
run: |
pip install pytest httpx
pytest tests/smoke/ --env=production -v
- name: Notify team (Success)
if: success()
uses: slackapi/slack-github-action@v1
with:
webhook-url: ${{ secrets.SLACK_WEBHOOK }}
payload: |
{
"text": "✅ Deploy to PRODUCTION completed successfully!",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Deploy to Production Success* ✅\n\n*Version:* `v${{ github.sha }}` \n*Author:* ${{ github.actor }}\n*URL:* https://seuapp.com\n\n🎉 Great job team!"
}
}
]
}
- name: Rollback on failure
if: failure()
run: |
echo "❌ Deploy failed, initiating rollback..."
sam deploy \
--config-env production \
--no-confirm-changeset \
--parameter-overrides PreviousVersion=true
- name: Notify team (Failure)
if: failure()
uses: slackapi/slack-github-action@v1
with:
webhook-url: ${{ secrets.SLACK_WEBHOOK }}
payload: |
{
"text": "❌ Deploy to PRODUCTION FAILED!",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Deploy to Production Failed* ❌\n\n*Commit:* `${{ github.sha }}`\n*Author:* ${{ github.actor }}\n\n<!channel> URGENT: Production deploy failed!"
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {"type": "plain_text", "text": "View Logs"},
"url": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}",
"style": "danger"
}
]
}
]
}
OIDC Authentication
Setup IAM Role
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::ACCOUNT_ID:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
},
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:seu-org/backend-api:*"
}
}
}
]
}
Permissions
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"cloudformation:*",
"s3:*",
"lambda:*",
"apigateway:*",
"iam:GetRole",
"iam:PassRole",
"logs:*",
"rds:CreateDBSnapshot"
],
"Resource": "*"
}
]
}
Troubleshooting
Workflow Failed
- Ver logs no GitHub Actions
- Rodar localmente se possível
- Verificar secrets configurados
- Checar AWS permissions
Deploy Timeout
- Aumentar
timeout-minutes - Verificar se Lambda está respondendo
- Checar CloudWatch logs