Dev Notes

Tecnologia, infraestrutura e desenvolvimento de software.

← Todos os posts

CI/CD na prática com GitHub Actions

Integração contínua e entrega contínua existem para resolver um problema simples: código que fica na máquina do desenvolvedor não tem valor. O valor está no software rodando em produção. CI/CD é o conjunto de práticas e ferramentas que encurta o caminho entre esses dois pontos — e GitHub Actions é hoje uma das formas mais acessíveis de colocar isso em prática.

Neste post vamos construir um pipeline real: do push no repositório até o deploy automatizado, entendendo cada etapa pelo caminho.

O que é CI e o que é CD

Integração contínua (CI) é a prática de integrar código com frequência — idealmente várias vezes por dia — e verificar automaticamente que cada integração não quebrou nada. Isso inclui compilar o projeto, rodar os testes e checar formatação ou lint.

Entrega contínua (CD) vai além: cada mudança que passa pela CI está pronta para ser enviada para produção. Em alguns times isso é manual — um clique aprova o deploy. Em outros é totalmente automatizado, e qualquer push na branch principal vai direto para produção.

GitHub Actions oferece infraestrutura para os dois. Você escreve um arquivo YAML descrevendo o que deve acontecer em resposta a eventos — um push, um pull request, um merge — e o GitHub executa em máquinas gerenciadas por eles.

Como GitHub Actions funciona

Tudo parte de um arquivo dentro de .github/workflows/ no seu repositório. Cada arquivo define um workflow. Um workflow tem gatilhos (on), e quando o gatilho dispara, ele executa um ou mais jobs. Cada job roda em uma máquina virtual e é composto de steps — comandos shell ou actions reutilizáveis publicadas por terceiros.

Jobs diferentes rodam em paralelo por padrão. Se um job depende de outro, você declara essa dependência com needs, e o segundo só começa quando o primeiro terminar com sucesso.

Um pipeline de CI básico

Para uma aplicação Node.js, um pipeline de CI mínimo faz três coisas: instala as dependências, roda o lint e executa os testes. Isso deve acontecer em todo pull request, para que o time saiba se uma mudança quebra algo antes de fazer o merge.

O gatilho pull_request faz o workflow rodar sempre que um PR é aberto ou atualizado. O runner ubuntu-latest é a máquina virtual onde tudo vai rodar — é gratuita para repositórios públicos e tem uma cota mensal para repositórios privados.

actions/checkout é uma action oficial que faz o clone do repositório na máquina virtual. actions/setup-node instala a versão do Node que você especificar. Depois disso, são comandos shell normais.

Adicionando o deploy

O deploy entra como um job que depende do job de CI. Ele só roda se o CI passou, e somente na branch main — não faz sentido fazer deploy de todo branch de feature.

Credenciais nunca devem aparecer no YAML. GitHub Actions tem um sistema de Secrets: você adiciona um segredo nas configurações do repositório e acessa via secrets.NOME_DO_SEGREDO no workflow. Eles aparecem mascarados nos logs.

Cache de dependências

Instalar dependências a cada execução é lento e desnecessário quando o package-lock.json não mudou. A action actions/cache salva o diretório node_modules entre execuções usando um hash do arquivo de lock como chave. Quando o hash é o mesmo, o cache é restaurado e o npm install termina em segundos.

Essa otimização muda o tempo de um pipeline de 3–4 minutos para menos de 1 minuto em repositórios com dependências pesadas.

Estratégia de matrix

Se você precisa garantir que sua aplicação funciona em múltiplas versões do Node ou em múltiplos sistemas operacionais, a estratégia matrix do GitHub Actions faz isso sem duplicar código. Você declara as combinações e o Actions cria um job para cada uma, rodando em paralelo.

Isso é especialmente útil para bibliotecas que precisam suportar múltiplos ambientes. Para aplicações com um ambiente de produção definido, geralmente não é necessário.

O que não fazer

Alguns erros comuns em pipelines GitHub Actions valem mencionar. Não use @latest em actions de terceiros — use sempre uma versão fixa com o hash do commit para evitar que uma mudança remota quebre seu pipeline silenciosamente. Não coloque segredos em variáveis de ambiente globais quando só um step precisa deles — reduza o escopo. E não ignore falhas de lint: se o pipeline deixa o lint passar sem falhar o job, ele não tem utilidade.

Conclusão

Um pipeline de CI/CD bem configurado transforma o processo de desenvolvimento. Code review fica mais objetivo quando o pipeline já verificou que os testes passam. Deploy vira um evento rotineiro e não estressante. E o time ganha confiança para fazer mudanças com frequência, porque sabe que qualquer regressão vai aparecer rapidamente — não em produção às três da manhã.

GitHub Actions tem uma curva de aprendizado pequena comparada ao valor que entrega. O investimento de algumas horas configurando um pipeline decente retorna muitas vezes em produtividade e confiabilidade.