Configurando pipeline com github actions para um projeto React

Fazia tempo que não configurava um serviço de ci/cd e esses dias fui fazer isso no github usando o github actions e percebi ser bem simples, e podemos fazer várias rotinas, é bem legal, mesmo se você estiver trabalhando sozinho, pois consegue que todo commit seja verificado para saber se não quebrou nada.

Vou mostrar uma configuração simples e você pode adaptar para o que você vai precisar no seu dia-a-dia

Primeiro passo, dentro da raiz do seu projeto, crie uma pasta .github dentro dessa pasta crie outra pasta chamada workflows e dentro crie o seu arquivo para rodar sempre que um commit entrar na sua branch main ou sempre que abrir Pull Request. Vou chamar o arquivo de build.yaml para o exemplo:

name: Build and Deploy

on:
  push:
    branches: 'main'
  pull_request:
    branches: 'main'

jobs:
  tests:
    name: Run Tests
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Use Node.js 20.x
        uses: actions/setup-node@v3
        with:
          node-version: 20.x
          cache: 'yarn'

      - name: Install Dependencies
        run: yarn install

      - name: Run Tests
        run: yarn test

  deploy:
    name: Build and Deploy
    needs: [tests]
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Use Node.js 20.x
        uses: actions/setup-node@v3
        with:
          node-version: 20.x
          cache: 'yarn'

      - name: Install Dependencies
        run: yarn install

      - name: Run Build
        run: yarn build

Bora para uma simples explicação

1 On nessa propriedade dizemos quando a action deve rodar, no caso, quando acontecer um commit ou um PR para a branch main.

2 Jobs nessa rotina dizemos quais scripts que queremos que nosso action execute no meu caso só tem dois o de tests e deploy o primeiro argumento é nome da tarefa no meu caso são Run Tests e Build and Deploy, depois temos runs-on que vai ser o ambiente que vamos querer que o nossa pipe rode, ou seja, vamos querer uma máquina virtual ubuntu na última versão, antes de entrar nos steps nosso job de build tem uma instrução chamada needs passando o argumento [tests], ou seja, para o nosso deploy rodar, precisa rodar os testes antes sem que nada quebre.

3 Steps temos algumas rotinas aqui dentro, no primeiro name e uses as actions fazem checkout do seu código e “pedem autorização” para seguir com as próximas rotinas:

- name: Checkout code
    uses: actions/checkout@v3

Depois podemos declarar qual versão do node ele vai usar para rodar os scripts do nosso projeto:

- name: Use Node.js 20.x
    uses: actions/setup-node@v3
      with:
        node-version: 20.x
        cache: 'yarn'

Normalmente você vai ver essa propriedade cache com npm, mas eu preferi usar o yarn, pois estava usando ele localmente também.

Por último pedimos para de fato ele rodar o script de instalação e logo em seguida o de testes:

- name: Install Dependencies
    run: yarn install

- name: Run Tests
    run: yarn test

O de build é o mesmo, porém só muda de yarn test para yarn build.

Bem é isso, é algo bem simples de se construir, é legal implementar em ambientes diferentes e fazer vários testes. Espero que tenham gostado e qualquer feedback será muito bem-vindo, muito obrigado.

Cuidado com os custos escondidos

Se você verificar nesta página os custos do github actions é cobrado por MINUTO

Ok, mas o que acontece se a action demorar 5 segundos para executar? Vai ser cobrado um minuto inteiro

Lendo o seu workflow vemos que tem diversos passos que se repetem entre os jobs:

 steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Use Node.js 20.x
        uses: actions/setup-node@v3
        with:
          node-version: 20.x
          cache: 'yarn'

      - name: Install Dependencies
        run: yarn install

essas ações vão consumir tempo desnecessário!

Otimizando essa action

Porquê não fazer em um único job o teste e o deploy?

name: Build and Deploy

on:
  push:
    branches: 'main'
  pull_request:
    branches: 'main'

jobs:
  tests:
    name: Run Tests
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Use Node.js 20.x
        uses: actions/setup-node@v3
        with:
          node-version: 20.x
          cache: 'yarn'

      - name: Install Dependencies
        run: yarn install

      - name: Run Tests
        run: yarn test

      - name: Run Build
        run: yarn build

Isso irá diminuir MUITO o tempo para rodar o flow, se ocorrer em uma organização grande pode ter certeza que fará diferença no orçamento mensal

Erro 1: O que está sendo feito com o build?

No último passo é executado o build:

- name: Run Build
  run: yarn build

mas cadê o commit?

Esse build simplesmente será descartado assim que a action terminar de executar.

Erro 2: O mesmo fluxo ocorrendo em 2 momentos diferentes

Ok, não chega a ser um erro, mais uma sugestão pessoal

on:
  push:
    branches: 'main'
  pull_request:
    branches: 'main'

Porque o mesmo fluxo ocorre nesses 2 momentos? se o teste passou no Pull request não precisa testar novamente na main! Assim como buildar no pull request pode remover uma build de uma main mais atualizada.

Vou tentar exclarecer melhor:

Main        Branch A         Branch B
  |
  |-------------+----------------+
  |             |                |
  |             | Commit 1       |
  |             |                |
  | <-----------+ PR 1           |
  |                              | Commit 2
  |                              |
  | <----------------------------+ PR 2
  |

No momento que é solicitado o PR 2 vai gerar uma nova build. Se esse PR for aceito vai acontecer uma das situações:

  • A build do PR 2 vai apagar totalmente o PR 1 por um momento
  • Vai dar conflito de merge
  • Vai ficar inconsistente com arquivos de cada build misturados

Solução que utilizo

Deploy apenas quando foi aprovado o PR

# DEPLOY
on:
  push:
    branches: 'main'

Testes apenas no pull request

# TESTES
on:
  pull_request:
    branches: 'main'
Cara muito obrigado pelas sugestões, nesse exemplo eu usei para um projeto pessoal, queria realmente testar as actions, então é por isso que não tem custo. Sim concordo com você totalmente, rodar a pipe quando tem commit na main é ruim, mas no meu caso como estou trabalhando sozinho no projeto eu faço commits direto na main, mas vou alterar aqui no meu projeto para deixar optimizado. Vou adicionar aqui na minha pipe.

Muito obrigado por esse artigo, graças a ele eu tive a curiosidade de descobrir o que é pipeline.

Eu sou novo no ramo e fico meio perdido com alguns termos, e ver as pessoas usando me da curiosidade pra saber o que... Valeu mesmo!!

Boa mano isso aí, sempre evoluindo, sei que é difícil entender de todo ecossistema, mas pelo menos o básico é legal entender.