loading...
Cover image for GitHub Actions - Elixir
Ingresse

GitHub Actions - Elixir

vitorleal profile image Vitor Leal ・5 min read

O Actions é uma ferramenta integrada aos seus repositórios do GitHub para automatizar os seus workflows de CI/CD (continuous delivery / continuous deploy). Você consegue rodar esses workflows baseado em diversos eventos do GitHub, como um novo push em uma branch a criação de uma nova issue ou uma nova release publicada.

Contexto

Desde que o GitHub lançou a versão beta do Actions, a Ingresse vem a testando. No final do ano passado o Actions saiu da versão beta e a gente decidiu finalmente migrar nossos workflows para lá.

Já que Elixir é a nossa linguagem principal na Ingresse, começamos a migrar primeiro os workflows dos serviços em Elixir para o Actions e aqui tem algumas dicas de como a gente faz.

Básico


Antes de tudo vou apresentar um pouco do básico do GitHub Actions, se você já tem familiaridade pode seguir passar direto essa seção.


O Actions vai ler os arquivos .yml ou .yaml dentro da pasta .github/workflows na raiz do seu projeto.

Primeiro vamos criar a pasta .github com a pasta workflows dentro:

mkdir -p .github/workflows

Agora vamos criar um arquivo que a gente pode chamar de ci.yml:

touch .github/workflows/ci.yml

Agora vamos adicionar o seguinte conteúdo nele:

name: Meu Workflow

on: push

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v1

Vamos aos detalhes do conteúdo desse arquivo.

name

O nome do seu workflow. É um campo opcional.


on

O nome do evento do GitHub que vai iniciar esse workflow.

Pode ser um evento apenas:

# Vai rodar sempre que alguém realizar um push no repositório
on: push

Pode ser uma lista de eventos:

# Vai rodar sempre que alguém realizar um push no repositório
# e quando for criado um novo pull request
on: [push, pull_request]

Pode ser customizado por evento:

on:
  # Vai rodar sempre que um pull request for criado
  pull_request:
    # Mas quando estiver apontando para a master
    branches:
      - master

  # Vai rodar sempre que uma release for criada
  release:
    # Mas se ela estiver com o status de publicada
    types: 
      - published

jobs

Um workflow pode ter um ou mais jobs. Por padrão, múltiplos jobs rodam em paralelo.


jobs.<id-do-job>.run-on

Em que tipo de máquina o job vai ser executado.

Pode ser em um tipo de máquina:

jobs:
  test:
    runs-on: ubuntu-latest

Podem ser em múltiplos tipos de máquinas, incluindo ubuntu, macos e windows:

jobs:
  test:
    strategy:
      matrix:
        platform: [ubuntu-latest, macos-latest, windows-latest]

    runs-on: ${{ matrix.platform }}

jobs.<id-do-job>.steps

Um job pode ter uma ou mais tarefas que vão ser executadas. Uma tarefa pode executar comandos, rodar setups ou rodar outras actions. O próprio GitHub tem uma série de actions publicadas que facilitam muitos trabalhos. Nesse exemplo estamos usando a action actions/checkout na versão v1 para clonar o repositório do projeto.

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      # Primeira tarefa a ser executada vai ser clonar o repositório
      - uses: actions/checkout@v1

Próximos passos

Bom agora que a gente já sabe um pouco mais sobe a estrutura básica de um workflow do GitHub Actions vamos começar a moldar ele para executar por exemplo uma tarefa de mix format e uma tarefa de mix test em um projeto Elixir.

Para evitar ter que instalar o Elixir no processo de build, vamos utilizar o atributo container para baixar uma imagem Docker já existente.

name: Meu Workflow

on: push

jobs:
  test:
    runs-on: ubuntu-latest

    container:
      image: elixir:1.10

    steps:
      - uses: actions/checkout@v1

jobs.<id-do-job>.container

Em qual imagem Docker vai rodar as tarefas desse job.

jobs:
  test:
    container:
      image: elixir:1.10

Agora que nosso ambiente já tem Elixir, podemos criar as tarefas para executar o mix format e mix test.

name: Meu Workflow

on: push

jobs:
  test:
    runs-on: ubuntu-latest

    container:
      image: elixir:1.10

    steps:
      - uses: actions/checkout@v1

      - name: Formatar
        run: mix format --check-formatted

      - name: Instalar as dependências
        run: mix deps.get

      - name: Testar
        run: mix test

Pronto já temos um workflow que clona nosso repositório, verifica se nosso código está formatado de acordo com as configurações do projeto, instala as dependências e roda nossos testes.


Utilizando serviços

O cenário anterior funciona perfeitamente para quando a gente tem um lib escrita em Elixir, mas para casos que a gente esteja trabalhando em um projeto com Phoenix por exemplo, a gente vai precisar provavelmente conectar em um banco de dados para poder executar alguns testes.

Nesse momento a gente consegue utilizar os services para criar containers de um banco de dados Postgres, por exemplo, para que os nossos jobs possam ter onde se conectar.

jobs.<id-do-job>.services

services:
  postgres:
    image: postgres

    # Mapeia a porta 5432 no container Docker para a porta 5432 no container do Postgres
    ports:
      - 5432:5432

    # Configura os dados de acesso ao banco de teste
    env:
      POSTGRES_USER: usuario
      POSTGRES_PASSWORD: senha
      POSTGRES_DB: banco

Agora que o nosso workflow vai criar o banco de dados pra gente poder conectar, tem um detalhe que temos que alterar nas nossas tarefas que vão rodar para conectar nesse banco. No caso, a nossa tarefa mix test tem que receber uma variável de ambiente para poder conectar corretamente no banco criado pelo Actions.

- name: Testar
  run: mix test
   env:
     POSTGRES_HOST: postgres
     POSTGRES_PORT: $❴❴ job.services.postgres.ports[5672] ❵❵

O exemplo completo fica assim:

name: Meu Workflow

on: push

jobs:
  test:
    runs-on: ubuntu-latest

    container:
      image: elixir:1.10

    services:
      postgres:
        image: postgres

        ports:
          - 5432:5432

        env:
          POSTGRES_USER: usuario
          POSTGRES_PASSWORD: senha
          POSTGRES_DB: banco

    steps:
      - uses: actions/checkout@v1

      - name: Formatar
        run: mix format --check-formatted

      - name: Instalar as dependências
        run: mix deps.get

      - name: Testar
        run: mix test
        env:
          POSTGRES_HOST: postgres
          POSTGRES_PORT: $❴❴ job.services.postgres.ports[5432] ❵❵

Agora basta alterar as configurações da nosso ambiente de teste para receber utilizar as variáveis de ambiente:

import Config

config :meu_app, Meu.Repo,
  adapter: Ecto.Adapters.Postgres,
  username: "usuario",
  password: "senha",
  database: "banco",
  port: String.to_integer(System.get_env("POSTGRES_PORT", "5432"))
  hostname: System.get_env("POSTGRES_HOST"),
  pool: Ecto.Adapters.SQL.Sandbox

Docker Compose

Se você já utiliza Docker Compose nos seus projetos você não precisa criar os services no arquivo do Actions e pode criar esses serviços direto no seu arquivo do Docker Compose de teste.

Exemplo do arquivo docker-compose-test.yml:

version: "3.3"
services:
  meu_servico:
    build: .
    depends_on:
      - meu_postgres
    ports:
      - "4000:4000"
    environment:
      - MIX_ENV=test
    command: mix phx.server

  postgres:
    image: postgres
    container_name: meu_postgres
    environment:
      - POSTGRES_DB=banco
      - POSTGRES_USER=usuario
      - POSTGRES_PASSWORD=senha
    ports:
      - "5433:5432"

Para rodar os testes com o Docker Compose, o ideal é mudar a imagem que roda no Actions para uma imagem que tenha já tenha o compose instalado.

jobs:
    container:
      image: docker/compose

O exemplo completo fica assim:

name: Meu Workflow

on: push

jobs:
  test:
    runs-on: ubuntu-latest

    container:
      image: docker/compose

    steps:
      - uses: actions/checkout@v1

      - name: Formatar
        run: docker-compose -f docker-compose-test.yml run meu_servico mix format --check-formatted

      - name: Testar
        run: docker-compose -f docker-compose-test.yml run meu_servico mix test

Espero que tenha ajudado vocês a entender um pouco melhor como rodar projetos Elixir no GitHub Actions.

Até a próxima!

Ingresse

Construindo tecnologia para modernizar e melhorar o mercado de eventos

Discussion

markdown guide