Verwenden von GitHub CI für Elixir-Projekte

Im Oktober startete Github Aktionen , mit denen Sie CI ausführen können, ohne die Kasse zu verlassen, an der dieser Code gespeichert ist. Es ist wirklich sehr praktisch. Sobald jemand eine Pull-Anfrage sendet oder einfach neue Änderungen auf den Server hochlädt oder etwas anderes Besonderes (eine Liste von Ereignissen, mit denen Aktionen verknüpft werden können, finden Sie in der offiziellen Dokumentation ), beginnt die Assembly. Geplante wiederkehrende Aufgaben ( Cron-basiert ) werden ebenfalls unterstützt.


Sie können Aktions-Pipelines erstellen, die als Workflows bezeichnet werden . Und das alles ist schön und sieht aus wie eine glänzende Zukunft - mit Ausnahme der Dokumentation.


Ich habe mehr als eine Stunde gebraucht, um herauszufinden, wie ein Container mit Diensten von Drittanbietern zum Testen der Anwendung erstellt werden kann. Folgendes habe ich herausgefunden. Bitte beachten Sie, dass die offizielle Dokumentation offen gesagt umständlich, unvollständig und oft einfach falsch ist.


Die Standardaktion CI ( action ) verwendet Konfigurationsdateien mit einer Syntax, die der von CircleCI sehr ähnlich ist. Dies ist nur die gute alte YAML , mit der Sie das Zielbetriebssystem, die Umgebung, die auszuführenden Befehle usw. konfigurieren können. Die Aktionen selbst erhalten eindeutige Namen , mit denen Sie auf andere Aktionen verweisen und von diesen abhängig sind.


Darüber hinaus können Sie in der Konfiguration Dienste angeben. Dienste müssen irgendwo in der Cloud ausgeführt werden, und GH ordnet die Containerports den Ports zu, die diese Dienste je nach Konfiguration verfügbar machen. Dieser Teil wird in der offiziellen Dokumentation nur unzureichend behandelt, und selbst die Beschreibung enthält Fehler.


Hier ist ein funktionierendes Konfigurationsbeispiel für ein Elixir- Projekt, für dessen Test RabbitMQ- und Redis- Dienste erforderlich sind.


 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] }} 

Wie Sie sehen können, laufen die Tests unter Ubuntu mit Elixir v1.9.1. Dienstleistungen werden unter den Schlüsseldiensten beschrieben, und hier beginnt eine reine Detektivgeschichte. Der physische Port, an den der Service-Port gebunden wird, wird von der Container-Engine zur Laufzeit zufällig ausgewählt und in einer internen Shell-Variablen namens job.services.rabbitmq.ports[5672] gespeichert. rabbitmq ist der Name des Dienstes, wie in dieser Datei im Abschnitt " Dienste " angegeben, und 5672 ist der Quellport. Die interne Variable hat die Syntax $ {{foo}} und wird an die Umgebungsvariable RABBITMQ_PORT (den letzten Einstellungsblock unter dem Schlüssel env ) übergeben. In RABBITMQ_HOST Sie den Namen des Dienstes genau wie unter den Diensteschlüssel RABBITMQ_HOST . Jetzt kann die Anwendung wie gewohnt Umgebungsvariablen lesen und die Ports werden korrekt gescrollt.


So werden wir diese Umgebungsvariablen aus der Umgebung lesen (dies ist eine Konfiguration für Elixir , für andere Sprachen wird es etwas sehr Ähnliches geben).


 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" ] 

In der Projektdatei erstelle ich eine spezielle Umgebung :ci , um zwischen der Konfiguration für Tests, die in der lokalen Umgebung ausgeführt werden, und der Konfiguration für Tests zu unterscheiden, die irgendwo in der Cloud ausgeführt werden.


Außerdem führe ich in der CI- Pipeline einen dialyzer für meine Quellen aus. Da die Aufgabe im Container ausgeführt wird, dauert es einige Zeit, da Sie die plts jedes Mal von Grund auf neu plts . Deshalb mache ich das einmal am Tag mit der Option zur 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 

Hier ist code_quality ein in mix.exs deklarierter Task-Alias


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

Das ist im Allgemeinen alles, was wir zum Testen eines Projekts mit externen Abhängigkeiten im neuen Github Workflow benötigen.


Erfolgreiche kontinuierliche Integration!

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


All Articles