Nos últimos meses trabalhei na definição de um modelo padrão de shared workflows para projetos de backend Node.js e recursos de infraestruturas implantados na AWS. Neste artigo descrevo a motivação, decisões de arquitetura, trechos de código e aprendizados que considero úteis para quem quer adotar um modelo similar.
Problema e motivação
Em organizações com múltiplos times e repositórios, cada projeto costuma inventar seu pipeline (lint, test, build, deploy). Isso gera retrabalho, inconsistências de segurança e custo de manutenção alto. Minha meta foi criar um conjunto de workflows reutilizáveis — fáceis de configurar por repositórios consumidores — que reduzissem duplicação e padronizassem boas práticas.
Abordagem
Optei por usar reusable workflows do GitHub Actions (on: workflow_call) e separar claramente responsabilidades, exemplo:
- CI: lint, install, cache, unit/integration tests, security scan (yarn audit).
- Infra CI: Terraform fmt/init/plan (shared-terraform-ci).
- CD: build/push para ECR, deploy blue/green em ECS (shared-backend-deploy-ecs).
-
Release: criação automática de branch de release e PR para
main(shared-release-workflow).
Essa separação facilita reaproveitamento: um repositório pode chamar apenas o CI shared, ou o deploy shared, ou ambos através de wrappers.
Trechos de consumo (exemplos)
Consumo do shared CI num projeto:
jobs:
ci:
uses: ./.github/workflows/shared-backend-ci.yml
with:
working_directory: app
node_version: '20'
enable_security_scan: true
secrets:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Wrapper que executa deploy em staging e, em seguida, chama o workflow de release se o deploy teve sucesso:
jobs:
deploy:
uses: ./.github/workflows/shared-backend-deploy-ecs.yml
with:
environment: staging
tf_backend_bucket: my-staging-state
tf_var_file: envs/staging/variables.tfvars
secrets:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
promote:
needs: deploy
if: ${{ needs.deploy.result == 'success' }}
uses: ./.github/workflows/shared-release.yml
secrets:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Decisões arquiteturais chave
- Reusable workflows via
workflow_callfavorecem versão e rollback centralizado. Consumidores apontam para uma tag (@v1) no repositório de shared workflows. - Segreguei permissões por job (princípio de menor privilégio): jobs de lint/test usam
contents: read; jobs de release/deploy recebem permissões mais elevadas apenas quando estritamente necessário.
Aprendizados e recomendações
Parametrização é essencial. Trabalhei com
working_directory,app_path,image_tage outros inputs para permitir que projetos com monorepos ou estruturas diferentes reutilizem os mesmos workflows.Teste local e validação estática. Ferramentas como actionlint, shellcheck e checkov evitaram regressões e problemas de segurança antes do merge.
Documente uso e exemplos. Consumidores adotam shared workflows muito mais rápido quando encontram exemplos práticos e um README conciso com nomes de secrets esperados.
Tenha um piloto. Validar o modelo em um projeto piloto permitiu ajustar inputs e detectar diferenças (por exemplo, onde o monorepo precisava de um
working_directorydiferente).
Riscos & mitigação
- Diferenças entre repositórios: mitigação com inputs configuráveis e exemplos detalhados.
- Permissões excessivas: mitigação com revisão de permissões por job e uso de roles para operações AWS.
- Dependência central: documentar SLA de alterações e versionar via tags semânticas para evitar breaking changes.
Conclusão
Criar um modelo de shared workflows traz retorno rápido em escala: menos esforço duplicado, pipelines padronizados e melhorias de segurança centralizadas. A chave do sucesso foi manter o design simples, parametrizável e bem documentado, além de validar por meio de um piloto real.
Se você estiver começando, recomendo iniciar pelo shared CI (lint/test) e, em seguida, evoluir para um shared deploy com validações de infraestrutura (Terraform) e deploys controlados.
Top comments (0)