GitHub Actions é uma plataforma de automação que permite criar pipelines de integração contínua (CI) e entrega contínua (CD) diretamente no seu repositório GitHub. Com ela, você pode automatizar testes, builds, deploys e qualquer outra tarefa que faça parte do seu fluxo de desenvolvimento. As pipelines são definidas em arquivos YAML dentro do diretório .github/workflows do repositório.

Nesta aula, vamos explorar os conceitos fundamentais: workflows, YAML, jobs, steps, actions reutilizáveis e secrets. Ao final, você será capaz de criar seu primeiro workflow e entender como expandir para cenários mais complexos.

Workflows e YAML

Um workflow é um processo automatizado composto por um ou mais jobs. Ele é definido em um arquivo YAML com extensão .yml ou .yaml. O YAML é uma linguagem de serialização de dados legível por humanos, usada para configurar o workflow de forma declarativa.

Todo workflow começa com a chave name (opcional) e a chave on, que especifica o evento que dispara o workflow. Por exemplo, push ou pull_request. Dentro de on, é possível filtrar branches, tags ou caminhos.

name: Exemplo de Workflow
on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

O workflow também pode ser executado manualmente via workflow_dispatch ou em agendamento com schedule. Além disso, é possível definir variáveis de ambiente globais com env.

Jobs e steps

Um workflow é composto por jobs, que são unidades de execução que rodam em um runner (máquina virtual). Os jobs podem ser executados em paralelo por padrão, ou sequencialmente se houver dependências (needs). Cada job roda em um ambiente isolado e pode conter vários steps.

Steps são comandos individuais executados dentro de um job. Eles podem ser comandos shell ou ações reutilizáveis. Cada step é executado sequencialmente dentro do job. Exemplo:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout do código
        uses: actions/checkout@v4
      - name: Rodar script
        run: echo "Hello, world!"

O campo runs-on define o sistema operacional do runner. Opções comuns: ubuntu-latest, windows-latest, macos-latest. Também é possível usar runners auto-hospedados.

Actions reutilizáveis

Actions são blocos de código reutilizáveis que podem ser baixados do GitHub Marketplace ou criados por você. Eles encapsulam tarefas comuns como checkout de repositório, instalação de dependências, deploy em nuvem, etc. O uso de actions evita repetição de código e simplifica os workflows.

Para usar uma action, utilize a palavra-chave uses seguida do identificador da action (formato autor/nome@versão). Exemplo:

- name: Configurar Node.js
  uses: actions/setup-node@v4
  with:
    node-version: 18

Você também pode criar suas próprias actions em um repositório separado ou no mesmo repositório (actions locais). Actions locais são referenciadas com ./caminho/para/action. É uma boa prática versionar actions com tags semânticas ou SHAs para garantir estabilidade.

Secrets

Secrets são variáveis de ambiente criptografadas que permitem armazenar informações sensíveis como tokens de API, senhas ou chaves SSH. Elas são configuradas nas configurações do repositório (Settings > Secrets and variables > Actions) e não são exibidas nos logs.

Para usar um secret no workflow, referencie-o com ${{ secrets.NOME_DO_SECRET }}. Exemplo:

- name: Deploy
  run: |
    echo "Deploying..."
    curl -X POST -H "Authorization: Bearer ${{ secrets.DEPLOY_TOKEN }}" https://api.exemplo.com/deploy

Importante: nunca coloque secrets diretamente no código ou nos logs. O GitHub Actions automaticamente mascara secrets nos logs, mas evite imprimi-los. Além disso, existem boas práticas como usar OIDC para autenticação sem secrets.

Boas práticas e observações finais

Ao criar workflows, prefira usar ações oficiais e bem mantidas. Sempre especifique a versão da action (tag ou SHA) para evitar mudanças inesperadas. Organize workflows em arquivos separados para cada finalidade (testes, deploy, lint). Use if condicional para controlar a execução de steps ou jobs. E, por fim, monitore seus workflows através da aba "Actions" do repositório.

Referências

Exercícios

  1. Crie um workflow que seja disparado ao fazer push na branch main e execute um job que imprime "Hello, GitHub Actions!" usando um step com run.
  2. ✓ Resposta:
    name: Hello Workflow
    on:
      push:
        branches: [ main ]
    jobs:
      hello:
        runs-on: ubuntu-latest
        steps:
          - name: Imprimir saudação
            run: echo "Hello, GitHub Actions!"
  3. Adicione um segundo job ao workflow anterior, chamado "test", que dependa do job "hello" e execute um step com o comando echo "Running tests".
  4. ✓ Resposta:
    jobs:
      hello:
        runs-on: ubuntu-latest
        steps:
          - run: echo "Hello, GitHub Actions!"
      test:
        needs: hello
        runs-on: ubuntu-latest
        steps:
          - run: echo "Running tests"
  5. Utilize a action actions/checkout@v4 para fazer checkout do código em um job e depois liste os arquivos do repositório com ls -la.
  6. ✓ Resposta:
    jobs:
      list:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
          - name: Listar arquivos
            run: ls -la
  7. Crie um secret chamado MY_SECRET no seu repositório (simule) e use-o em um workflow para imprimir uma mensagem mascarada. (Não se preocupe, o GitHub mascara automaticamente.)
  8. ✓ Resposta:
    jobs:
      show-secret:
        runs-on: ubuntu-latest
        steps:
          - name: Exibir secret
            run: echo "O secret é ${{ secrets.MY_SECRET }}"
  9. Modifique o workflow para ser executado manualmente usando workflow_dispatch e permita que o usuário informe um parâmetro de entrada chamado name com valor padrão "Mundo". Imprima "Olá, !" no step.
  10. ✓ Resposta:
    name: Saudação Manual
    on:
      workflow_dispatch:
        inputs:
          name:
            description: 'Nome a ser saudado'
            required: true
            default: 'Mundo'
    jobs:
      saudacao:
        runs-on: ubuntu-latest
        steps:
          - name: Saudar
            run: echo "Olá, ${{ inputs.name }}!"