Usando o GitHub CI para projetos Elixir

Em outubro, o Github lançou ações que permitem executar o IC sem sair do caixa no qual esse código está armazenado. É realmente muito conveniente. Assim que alguém envia uma solicitação pull , ou simplesmente carrega novas alterações no servidor, ou algo especial (uma lista de eventos nos quais as ações podem ser fixadas pode ser encontrada na documentação oficial ), a montagem é iniciada. Também são suportadas tarefas recorrentes agendadas ( baseadas em cron ).


Você pode criar pipelines de ação chamados fluxos de trabalho . E tudo isso é lindo e parece um futuro brilhante - com exceção da documentação.


Levei mais de uma hora para descobrir como criar um contêiner com serviços de terceiros para testar o aplicativo. Aqui está o que eu consegui descobrir. Observe que a documentação oficial é francamente desajeitada, incompleta e muitas vezes simplesmente incorreta.


A ação padrão do IC usa arquivos de configuração com sintaxe muito semelhante à usada pelo CircleCI . Essa é apenas a boa e velha YAML , que permite configurar o SO, o ambiente, os comandos de execução, etc. As ações recebem nomes exclusivos , o que permite que você se refira a outras ações e dependa delas.


Além disso, a configuração permite especificar serviços . Os serviços devem estar em execução em algum lugar da nuvem, e o GH mapeará as portas do contêiner para as portas que esses serviços expõem, de acordo com a configuração. Esta parte é pouco abordada na documentação oficial e mesmo o que está descrito contém erros.


Aqui está um exemplo de configuração funcional para um projeto Elixir que requer serviços RabbitMQ e Redis para teste.


 name: Tests for My Project on: [push, pull_request] jobs: build: runs-on: ubuntu-latest container: image: elixir:1.9.1-slim services: rabbitmq: image: rabbitmq ports: - 5672:5672 env: RABBITMQ_USER: guest RABBITMQ_PASSWORD: guest RABBITMQ_VHOST: "/" redis: image: redis ports: - 6379:6379 steps: - uses: actions/checkout@v1 - name: Install Dependencies run: | MIX_ENV=ci mix local.rebar --force MIX_ENV=ci mix local.hex --force MIX_ENV=ci mix deps.get - name: Run All Tests run: | MIX_ENV=ci mix test env: RABBITMQ_HOST: rabbitmq RABBITMQ_PORT: ${{ job.services.rabbitmq.ports[5672] }} REDIS_HOST: redis REDIS_PORT: ${{ job.services.redis.ports[6379] }} 

Como você pode ver, os testes serão executados no Ubuntu usando o Elixir v1.9.1. Os serviços são descritos nos principais serviços e aqui começa uma história de detetive pura. A porta física à qual a porta de serviço será vinculada é selecionada aleatoriamente pelo mecanismo de contêiner no tempo de execução e armazenada em uma variável de shell interna chamada job.services.rabbitmq.ports[5672] . rabbitmq é o nome do serviço, conforme indicado neste arquivo na seção de serviços e 5672 é a porta de origem. A variável interna possui a sintaxe $ {{foo}} e é passada para a variável de ambiente RABBITMQ_PORT (o último bloco de configuração, na chave env ). Em RABBITMQ_HOST - você precisa colocar o nome do serviço, exatamente como na chave de serviços . Agora o aplicativo pode ler variáveis ​​de ambiente como de costume e as portas serão roladas corretamente.


É assim que vamos ler essas variáveis ​​de ambiente a partir do ambiente (esta é uma configuração para o Elixir , para outros idiomas, haverá algo muito semelhante).


 import Config config :my_app, rabbitmq: [ host: System.get_env("RABBITMQ_HOST"), password: "guest", port: String.to_integer(System.get_env("RABBITMQ_PORT", "5672")), username: "guest", virtual_host: "/", x_message_ttl: "4000" ] 

No arquivo do projeto, crio um ambiente especial :ci , para distinguir entre a configuração dos testes realizados no ambiente local e os mesmos testes realizados em algum lugar na nuvem.


Além disso, no pipeline de IC , eu corro o dialyzer em minhas fontes. Como ela é executada no contêiner, a tarefa leva algum tempo, porque você precisa reconstruir as plts do zero todas as vezes. É por isso que faço isso uma vez por dia usando a opção de configuração de schedule .


 name: Dialyzer for My Project on: schedule: - cron: "0 1 * * *" jobs: build: runs-on: ubuntu-latest container: image: elixir:1.9.1-slim steps: - uses: actions/checkout@v1 - name: Install Dependencies run: | MIX_ENV=ci mix local.rebar --force MIX_ENV=ci mix local.hex --force MIX_ENV=ci mix deps.get - name: Run All Tests run: | MIX_ENV=ci mix code_quality 

aqui code_quality é um alias de tarefa declarado em mix.exs


 defp aliases do [ code_quality: ["format", "credo --strict", "dialyzer"] ] end 

Aqui, em geral, é tudo o que precisamos para um teste feliz de um projeto com dependências externas no novo fluxo de trabalho do Github .


Integração contínua com sucesso!

Source: https://habr.com/ru/post/pt481846/


All Articles