DEV Community

Cover image for Shared Workflows: minha experiência definindo pipelines reutilizáveis
Marcos Vilela
Marcos Vilela

Posted on

Shared Workflows: minha experiência definindo pipelines reutilizáveis

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 }}
Enter fullscreen mode Exit fullscreen mode

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 }}
Enter fullscreen mode Exit fullscreen mode

Decisões arquiteturais chave

  • Reusable workflows via workflow_call favorecem 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

  1. Parametrização é essencial. Trabalhei com working_directory, app_path, image_tag e outros inputs para permitir que projetos com monorepos ou estruturas diferentes reutilizem os mesmos workflows.

  2. Teste local e validação estática. Ferramentas como actionlint, shellcheck e checkov evitaram regressões e problemas de segurança antes do merge.

  3. 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.

  4. 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_directory diferente).

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)