No mundo acelerado do desenvolvimento web, a integração contínua e a implantação contínua (CI/CD) tornaram-se práticas indispensáveis para o fornecimento eficiente de software de alta qualidade. A CI/CD permite que os desenvolvedores automatizem o processo de criação, teste e implantação de alterações de código, reduzindo o risco de erro humano e permitindo iterações mais rápidas.

Este artigo explica a importância da CI/CD, como criar um pipeline CI e como configurar a implantação contínua em seu pipeline CI com a API da Kinsta de forma programática – tudo com o GitHub Actions em seu repositório GitHub.

Por que usar CI/CD?

A plataforma de Hospedagem de Aplicativos da Kinsta sempre ofereceu uma opção para implantação automática, acionada sempre que há uma alteração em uma branch específica no seu repositório Git hospedado. No entanto, isso pode não ser ideal para grandes projetos com vários membros da equipe. Muitos desenvolvedores tendem a evitar a ativação da implantação automática por uma variedade de razões.

Um dos motivos é que, em um ambiente colaborativo onde vários desenvolvedores estão trabalhando no mesmo projeto, implantações automáticas acionadas por uma alteração no repositório por parte de um desenvolvedor podem levar a instabilidade e problemas imprevistos. Sem testes e validação adequados, até mesmo uma pequena alteração no código poderia interromper o site de produção, causando potencialmente tempo de inatividade e experiências negativas para os usuários.

É nesse ponto que um pipeline CI/CD entra em ação. Ao criar um fluxo de CI/CD job cuidadosamente orquestrado, os desenvolvedores podem garantir que as alterações de código passem por testes e validação antes de serem implantadas no site ativo. Há muitas ferramentas disponíveis para implementar a CI/CD no desenvolvimento de software; usaremos o GitHub Actions neste tutorial.

O que é GitHub Actions?

O GitHub Actions é uma poderosa ferramenta de automação fornecida pelo GitHub. Ele oferece aos desenvolvedores a capacidade de automatizar várias tarefas, processos e fluxos de trabalho em seus projetos de desenvolvimento de software. Ele se integra aos repositórios do GitHub, tornando fácil de usar.

Com o GitHub Actions e a API da Kinsta, você pode definir fluxos de trabalho personalizados que atendam aos requisitos do seu projeto. Você pode configurar um pipeline  CI que testa seu aplicativo e aciona a implantação na Kinsta.

Primeiros passos com o GitHub Actions

O GitHub Actions opera com base no conceito de fluxos de trabalho, que são conjuntos de tarefas automatizadas acionadas por eventos específicos ou programadas em intervalos regulares. Esses eventos podem incluir push de código, pull requests, criação de problemas e muito mais. Quando um desses eventos ocorre, o GitHub Actions executa automaticamente um fluxo de trabalho associado, executando uma série de etapas predefinidas.

Cada etapa do fluxo de trabalho representa uma ação específica, como a criação do código, a execução de testes, a implantação ou o envio de notificações. Vamos criar um fluxo de trabalho com três tarefas:

  1. Verificar a sintaxe com o ESLint
  2. Executar testes
  3. Reimplantar o aplicativo

Etapa 1: Configure o seu repositório GitHub

Para começar a usar o GitHub Actions, você precisa de um repositório GitHub.

Aqui, estamos usando este repositório do GitHub, desenvolvido para o tutorial Como criar e implantar um aplicativo clone do ChatGPT com React e API OpenAI.

Sinta-se à vontade para usar o repositório você mesmo, navegando até ele no GitHub e selecionando: Use this template > Create a new repository.

Nesse aplicativo React, são criados testes de unidade para testar cada componente. O ESLint também é usado para reforçar a sintaxe perfeita e a formatação do código. O pipeline CI bloqueará uma implantação se um pull request ou código mesclado enviado para o repositório falhar nos testes de fluxo de trabalho.

Etapa 2: crie um arquivo de fluxo de trabalho

Defina seu fluxo de trabalho criando um arquivo YAML no diretório .github/workflows do seu repositório. Esse diretório deve estar no nível raiz do seu repositório. A convenção de nomenclatura para arquivos de fluxo de trabalho é name-of-the-workflow.yml.

  1. Em seu repositório, crie um diretório .github.
  2. Dentro do diretório .github, crie um novo diretório chamado workflows.
  3. Dentro do diretório de fluxos de trabalho, crie um novo arquivo com um nome como build-test-deploy.yml.

Etapa 3: Escreva o fluxo de CI/CD job

Agora que você criou o arquivo de fluxo de trabalho, defina um fluxo de trabalho com as etapas necessárias para verificar a sintaxe com o ESLint, executar testes e implantar o aplicativo.

Crie evento CI

Ao criar um pipeline CI, a primeira etapa é dar um nome ao fluxo de trabalho e, em seguida, definir o evento que acionaria o fluxo de trabalho. Neste exemplo, dois eventos (pull request e push) para a branch principal.

name: Build, Test, and Deploy

on:
  push:
    branches: "main"
  pull_request:
    branches: "main"

Se quiser agendar tarefas recorrentes (CRON jobs) para tarefas específicas, você poderá adicioná-los ao fluxo de trabalho. Por exemplo, você pode querer executar determinadas tarefas como backups de banco de dados, limpeza de dados ou outras tarefas de manutenção periódica.

Aqui está um exemplo de como você pode adicionar um Cron jobs ao fluxo de trabalho:

on:
  # Existing event triggers for push and pull_request

  # Add a schedule for CRON jobs
  schedule:
    - cron: "0 0 * * *"

O exemplo acima acionará o fluxo de trabalho todos os dias à meia-noite (horário UTC), já que a programação do cron está definida como 0 0 * * *. Você pode personalizar a programação do cron para atender às suas necessidades específicas.

Como outro exemplo, suponha que você queira programar o fluxo de CI/CD job para ser executado todas as segundas-feiras às 8h. Podemos configurar um Cron job usando o evento schedule:

name: Build, Test, and Deploy

on:
  push:
    branches: "main"
  pull_request:
    branches: "main"

  # Schedule the workflow to run every Monday at 8 a.m. (UTC time)
  schedule:
    - cron: "0 8 * * 1"

jobs:
 # Add jobs

A sintaxe de agendamento usada no evento schedule para fluxos de trabalho do GitHub Actions é baseada na sintaxe cron do UNIX. Ela permite que você defina horários ou intervalos específicos para que o seu fluxo de trabalho seja executado automaticamente. A sintaxe consiste em cinco campos que representam diferentes aspectos do cronograma. Cada campo é separado por um espaço. O formato geral da sintaxe do cronograma é o seguinte:

* * * * *
┬ ┬ ┬ ┬ ┬
│ │ │ │ │
│ │ │ │ └─ Day of the week (0 - 7) (Sunday to Saturday, where both 0 and 7 represent Sunday)
│ │ │ └─── Month (1 - 12)
│ │ └───── Day of the month (1 - 31)
│ └─────── Hour (0 - 23)
└───────── Minute (0 - 59)

Agora, vamos detalhar cada campo:

  • Minuto (0 – 59): O minuto em que o cron job será acionado. Por exemplo, 15 significa que o fluxo de trabalho será acionado no 15º minuto da hora.
  • Hora (0 – 23): A hora em que o cron job será acionado. Por exemplo, 8 significa que o fluxo de trabalho será acionado às 8 horas da manhã.
  • Dia do mês (1 – 31): O dia do mês em que o cron job será acionado. Por exemplo, 1 significa que o fluxo de trabalho será acionado no primeiro dia do mês.
  • Mês (1 – 12): O mês em que o cron job será acionado. Por exemplo, 6 significa que o fluxo de trabalho será acionado em junho.
  • Dia da semana (0 – 7): O dia da semana em que o cron job será acionado. Aqui, 0 e 7 representam domingo, enquanto 1 representa segunda-feira, e assim por diante. Por exemplo, 4 significa que o fluxo de trabalho será acionado na quinta-feira.

Caracteres especiais:

  • * (asterisco): Corresponde a qualquer valor desse campo. Por exemplo, * no campo minuto significa que o fluxo de trabalho será acionado a cada minuto.
  • */n (barra): Especifica um intervalo. Por exemplo, */5 no campo de minuto significa que o fluxo de trabalho será acionado a cada 5 minutos.
  • , (vírgula): Especifica vários valores específicos. Por exemplo, 1,15,30 no campo de minuto significa que o fluxo de trabalho será acionado no 1º, 15º e 30º minutos da hora.
  • - (hífen): Especifica um intervalo de valores. Por exemplo, 1-5 no campo de dia da semana significa que o fluxo de trabalho será acionado de segunda a sexta-feira (1 a 5).
  • ? (ponto de interrogação): Usado para especificar nenhum valor específico. É comumente usado no campo dia da semana quando o dia do mês é especificado. Por exemplo, ? no campo do dia da semana e 15 no campo do dia do mês significa que o fluxo de trabalho será acionado no 15º dia do mês, independentemente do dia da semana.

Criar um CI job para verificar a sintaxe com o ESLint

Para configurar o processo de Integração Contínua (CI), criaremos as tarefas ou trabalhos necessários. Cada trabalho deve ter um nome claro e compreensível. Vamos nomear o primeiro trabalho de eslint, já que ele envolverá a verificação da sintaxe do código utilizando o ESLint.

Além disso, podemos fornecer uma descrição legível por humanos, embora essa parte seja opcional. Em seguida, especificamos que o trabalho deve ser executado em um ambiente Ubuntu e utilizar uma estratégia de array para testar o código em duas versões do Node.js: 18.x e 20.x.

jobs:
  eslint:
    name: Check Syntax with ESLint
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [18.x, 20.x]

Em seguida, defina as etapas que o trabalho “ESLint” executará. Essas etapas incluem a verificação do código, a configuração da versão específica do Node.js para executar o ESLint, o armazenamento em cache dos pacotes npm, a instalação das dependências do projeto e, por fim, a execução do ESLint para verificar a sintaxe do código.

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

      - name: Use Node.js ${{ matrix.node-version }} to Check Lint
        uses: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'

      - name: Install Dependencies
        run: npm ci

      - name: Run ESLint
        run: npm run lint

No fluxo de trabalho acima, cada etapa recebe uma descrição com um nome para facilitar a identificação da fonte de erros ou bugs ao inspecionar o fluxo de trabalho a partir do GitHub Actions. Notavelmente, na terceira etapa, usamos o comando npm ci para instalar dependências, que é preferível a npm install, pois ele executa uma instalação limpa. Além disso, a última etapa, executar o ESLint usando npm run lint, pressupõe que você tenha configurado esse comando no arquivo package.json.

Abaixo você encontra o trabalho completo para verificar a sintaxe do código com o ESLint:

jobs:
  eslint:
    name: Check Syntax with ESLint
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [18.x, 20.x]

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

      - name: Use Node.js ${{ matrix.node-version }} to Check Lint
        uses: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'

      - name: Install Dependencies
        run: npm ci

      - name: Run ESLint
        run: npm run lint

Crie CI job para executar testes

Para adicionar o CI job para executar testes, comece definindo o trabalho e fornecendo um nome descritivo, como tests. Também especificaremos que esse trabalho depende do eslint job, o que significa que o eslint job será executado primeiro, antes que a tarefa tests seja executado. Essa dependência garante que o código seja verificado quanto a erros de sintaxe antes de executar os testes.

  tests:
    name: Run Tests
    needs: eslint
    runs-on: ubuntu-latest

Em seguida, defina as etapas para o trabalho tests. Da mesma forma que o trabalho anterior, verificaremos o código, configuraremos a versão do Node.js 18.x para executar os testes, instalaremos as dependências do projeto usando npm ci e, em seguida, executaremos os testes usando o comando npm run test.

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

      - name: Use Node.js 18.x to run Test
        uses: actions/setup-node@v3
        with:
          node-version: 18.x
          cache: 'npm'

      - name: Install Dependencies
        run: npm ci

      - name: Run Tests
        run: npm run test

Crie CI job para implantar com a API da Kinsta

Para criar o CI job para implantação na Kinsta usando a API da Kinsta, definiremos o trabalho e o nomearemos deploy. Esse trabalho terá dependências nos trabalhos eslint e tests, garantindo que a implantação seja executada somente depois que o código tiver sido verificado quanto a erros de sintaxe e passado nos testes. Configuraremos o trabalho para ser executado em um ambiente Ubuntu usando a versão mais recente disponível.

  deploy:
    name: Re-Deploy Application
    needs: [eslint, tests]
    runs-on: ubuntu-latest

Em seguida, defina as etapas. Nesse caso, você executará um comando cURL para interagir com a API da Kinsta de forma programática e acionar uma reimplantação. Primeiro, vamos entender a API da Kinsta, as várias informações necessárias para interagir com a API e como obter/armazenar informações importantes associadas à API – como a chave API – com segurança no GitHub.

Entendendo a API da Kinsta

A API da Kinsta é uma ferramenta poderosa que permite que você interaja com os serviços da Kinsta de forma programática. Para usar a API, você deve ter uma conta com pelo menos um site WordPress, aplicativo ou banco de dados no MyKinsta. Você também precisa gerar uma chave API para autenticar e acessar sua conta através da API.

Para gerar uma chave API:

  1. Vá para o painel MyKinsta.
  2. Navegue até a página Chaves API (Seu nome > Configurações da empresa > Chaves API).
  3. Clique em Criar chave API.
  4. Escolha uma expiração ou defina uma data de início personalizada e o número de horas para a chave expirar.
  5. Dê à chave um nome exclusivo.
  6. Clique em Gerar.
Criar chave de API no MyKinsta.
Criar chave de API no MyKinsta.

Após criar uma chave de API, copie e armazene em um local seguro (recomendamos que você use um gerenciador de senhas), pois essa é a única vez que ela é revelada no MyKinsta.

Como acionar a implantação com a API da Kinsta

Para implantar um aplicativo na Kinsta usando a API, você precisa de dois parâmetros obrigatórios: o ID do aplicativo e a branch. Você pode recuperar programaticamente o ID do seu aplicativo buscando primeiro a lista de seus aplicativos, que fornecerá detalhes sobre cada aplicativo, incluindo seu ID.

Após obter as informações necessárias, você pode fazer uma solicitação POST para o endpoint /applications/deployments da API. Para o pipeline CI, usaremos o cURL, uma ferramenta de linha de comando para interagir com URLs.

curl -i -X POST 
  https://api.kinsta.com/v2/applications/deployments 
  -H 'Authorization: Bearer <YOUR_TOKEN_HERE>' 
  -H 'Content-Type: application/json' 
  -d '{
    "app_id": "<YOUR_APP_ID>",
    "branch": "main"
  }'

Acionando a implementação do cURL no pipeline CI/CD

Para acionar a implantação com a API da Kinsta, adicione o comando cURL ao comando run do seu pipeline CI. No entanto, é importante que você armazene sua chave de API e o ID do aplicativo de forma segura.

Para armazenar segredos no GitHub e usá-los no GitHub Actions, siga estas etapas:

  1. Navegue até o repositório onde você deseja configurar o segredo.
  2. Clique na aba Settings no menu do repositório.
  3. Na barra lateral esquerda, selecione Secrets na categoria Options.
  4. Clique em New repository secret.
  5. Forneça um nome para o seu segredo (como KINSTA_API_KEY) e insira sua chave de API da Kinsta no campo Value.
  6. Depois que você digitar o nome e o valor, clique no botão Add secret para salvá-lo. Repita o processo para outros segredos.
  7. Repita o processo para outros segredos.
Armazenando segredos no GitHub.
Armazenando segredos no GitHub.

Após adicionar os segredos, você pode fazer referência a eles no seu fluxo de trabalho do GitHub Actions usando a sintaxe ${{ secrets.SECRET_NAME }}.

Agora, vamos concluir o deploy para o pipeline CI/CD do GitHub Actions. Defina as etapas exatamente como antes, com uma única etapa para implantar na Kinsta. Primeiro, defina os segredos no comando env e, em seguida, adicione o comando cURL para executar a implantação.

    steps:
      - name: Deploy to Kinsta
        env:
          KINSTA_API_KEY: ${{ secrets.KINSTA_API_KEY }}
          APP_ID: ${{ secrets.APP_ID }}
        run: |
          curl -i -X POST 
            https://api.kinsta.com/v2/applications/deployments 
            -H "Authorization: Bearer $KINSTA_API_KEY" 
            -H "Content-Type: application/json" 
            -d '{
              "app_id": "'"$APP_ID"'",
              "branch": "main"
            }'

No comando cURL, você perceberá que as variáveis de ambiente são adicionadas ao comando, permitindo que os segredos sejam acessados com segurança durante o processo de implantação.

É assim que você verá o fluxo de trabalho final de CI/CD:

name: Build, Test, and Deploy

on:
  push:
    branches: "main"
  pull_request:
    branches: "main"

jobs:
  eslint:
    name: Check Syntax with ESLint
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [18.x, 20.x]

    steps:
      - name: Checkout code
        uses: actions/checkout@v3
        
      - name: Use Node.js ${{ matrix.node-version }} to Check Lint
        uses: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'
          
      - name: Install Dependencies
        run: npm ci
        
      - name: Run ESLint
        run: npm run lint

  tests:
    name: Run Tests
    needs: eslint
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v3
        
      - name: Use Node.js 18.x to run Test
        uses: actions/setup-node@v3
        with:
          node-version: 18.x
          cache: 'npm'
          
      - name: Install Dependencies
        run: npm ci
        
      - name: Run Tests
        run: npm run test

  deploy:
    name: Re-Deploy Application
    needs: [eslint, tests]
    runs-on: ubuntu-latest

    steps:
      - name: Deploy to Kinsta
        env:
          KINSTA_API_KEY: ${{ secrets.KINSTA_API_KEY }}
          APP_ID: ${{ secrets.APP_ID }}
        run: |
          curl -i -X POST 
            https://api.kinsta.com/v2/applications/deployments 
            -H "Authorization: Bearer $KINSTA_API_KEY" 
            -H "Content-Type: application/json" 
            -d '{
              "app_id": "'"$APP_ID"'",
              "branch": "main"
            }'

Copie o fluxo de trabalho fornecido e cole-o em seu arquivo build-test-deploy.yml. Em seguida, inicie um pull request para adicionar esse arquivo ao branch principal do seu repositório. Lembre-se de que essa pull request acionará automaticamente o fluxo de trabalho.

Isso possibilita que você analise as mudanças realizadas no seu repositório e assegure que quaisquer novas alterações na solicitação de pull (pull request) cumpram com as verificações especificadas. Assim, você pode decidir se deve ou não integrar essas alterações na sua base de código.

Armazene segredos no GitHub.
Armazene segredos no GitHub.

Quando você realizar a integração da solicitação de pull (pull request), navegue até a aba Actions do seu repositório do GitHub e você verá o fluxo de CI/CD job em execução.

Resumo das ações do GitHub.
Resumo das ações do GitHub.

Você pode clicar em cada tarefa para ver mais detalhes sobre o job (é por isso que você precisa dar a cada etapa do seu trabalho uma descrição significativa).

Detalhes das etapas de CI.
Detalhes das etapas de CI.

Aplicação do fluxo de trabalho de pull request no GitHub

Para garantir o gerenciamento eficaz do código e a colaboração nos repositórios do GitHub, é útil que você aplique um fluxo de trabalho de pull request e bloqueie os commits diretos no branch principal. Essa abordagem estabelece um processo de desenvolvimento controlado e organizado, exigindo que todas as alterações passem por pull requests e revisões antes de serem mescladas na branch principal.

Ao adotar essa prática, as equipes de desenvolvimento podem melhorar a qualidade do código, minimizar o risco de introdução de bugs e manter um histórico transparente das alterações.

Veja como configurar a aplicação do fluxo de trabalho de pull request:

  1. Clique na aba Settings em seu repositório do GitHub.
  2. Em Code and Automation, selecione Branches nas opções da barra lateral.
  3. Se não houver regras, clique em Add branch protection rule.
  4. Forneça um nome para a regra e marque a caixa Require a pull request before merging merge. Isso exibirá mais opções de configuração.
  5. Além disso, marque a caixa Require status checks to pass before merging.
  6. Personalize as opções adicionais com base em suas preferências e requisitos.
  7. Clique no botão Create para salvar a regra.
Aplicando o fluxo de trabalho pull request no GitHub.
Aplicando o fluxo de trabalho pull request no GitHub.

Ao seguir esses passos, você configurou com sucesso uma regra para aplicar o fluxo de trabalho de solicitação de pull (pull request) no seu repositório GitHub. Isso garante que todas as alterações sejam submetidas à revisão e verificações automatizadas antes de serem integradas à branch principal, promovendo um ambiente de desenvolvimento mais confiável e colaborativo.

Resumo

Ao combinar o poder do GitHub Actions e da API da Kinsta, você pode simplificar o fluxo de trabalho de desenvolvimento e promover um ambiente colaborativo e eficiente para à sua equipe de desenvolvimento.

Os desenvolvedores podem contribuir com o código com confiança, sabendo que ele será testado minuciosamente antes de chegar à produção, e as partes interessadas podem ficar tranquilas sabendo que o processo de implantação é bem controlado e resistente a erros.

Como você está usando a API da Kinsta? Quais Endpoints você gostaria de ver adicionados à API? Qual tutorial relacionado à API da Kinsta você gostaria de ler a seguir?

Joel Olawanle Kinsta

Joel is a Frontend developer working at Kinsta as a Technical Editor. He is a passionate teacher with love for open source and has written over 200 technical articles majorly around JavaScript and it's frameworks.