Workflow-Vorlagen


Dieses Dokument erklärt, wie du mit GitHub Actions (GHA) Continuous-Integration-(CI-)Workflows für einen Exercism-Sprach-Track einrichtest. Es bietet Best Practices und Beispiele, mit denen du deine eigenen schnellen, zuverlässigen und robusten CI-Workflows erstellen kannst. Die GHA-Workflows in diesem Ordner lassen sich an jede CI anpassen, weil die Grundstruktur gleich bleibt.

Es wird:

  • den idealen CI-Workflow umreißen
  • Überlegungen und Empfehlungen besprechen
  • dir einige Vorlagen an die Hand geben
  • dir einen Leitfaden zur Migration von Travis hinterlassen

Eine Beispielumsetzung dieser Workflow-Dateien findest du in exercism/javascript.

HILFE: Das sieht nach sehr viel Arbeit aus 😓

Der Rest des Dokuments erklärt, wie die Workflows funktionieren. Wenn du es eilig hast und nur von Travis oder Circle zu GHA wechseln möchtest, ohne die PR-Skripte zu optimieren, schau dir unseren ~10-Minuten-Leitfaden zur Migration von Travis an.

CI-Aktionen für den Track

Die empfohlenen Aktionen, mit denen du prüfst, ob der Inhalt deines Repositorys integer ist, sind folgende:

  1. configlet-Linting, um config.json zu prüfen
  2. nach Stubs suchen
  3. nach Dokumentation suchen (v3 erfordert neue Dateien; das könnte zu configlet wandern)
  4. die Übungen mit einer „Maintainer“-Konfiguration linten
  5. die Übungen mit den Beispiel- und Exemplardateien testen (kann einen Build-Schritt enthalten)

Es kann auch trackspezifische Aktionen geben. Zum Beispiel:

  1. die Integrität der Übungskonfigurationen prüfen
  2. die Formatierung der Übungsdateien prüfen

Und vielleicht möchtest du weitere Quality-of-Life-Prüfungen, wie zum Beispiel:

  1. sicherstellen, dass CONTRIBUTING existiert
  2. sicherstellen, dass es eine vernünftige Lockfile für Abhängigkeiten gibt
  3. sicherstellen, dass die Links in Markdown-Dateien gültig sind
  4. ...

Empfehlungen

Häufigkeit der Prüfungen

Überlege bei jeder Aktion, wie oft sie laufen sollte.

  • Das configlet-Linting ist so wichtig (denn ein Track kann kaputtgehen, wenn config.json kaputtgeht), dass es wahrscheinlich immer laufen sollte, aber es muss nur einmal pro Commit laufen.
  • Die Prüfung der Existenz oder Integrität von Dateien muss nur einmal pro Commit laufen.
  • Wenn ein Track unter mehreren Runtime- oder Compiler-Versionen laufen soll, sollten die Übungen für jede unterstützte Version gebaut und getestet werden
  • PRs müssen wahrscheinlich nur Aktionen für hinzugefügte oder geänderte Dateien ausführen, aber da eine Datei eine Übung beeinflussen kann, ist es sicherer, die Aktionen für die Übung auszuführen, wenn sich eine ihrer Dateien ändert.

Es kann sehr hilfreich sein, die Aktionen, die laufen sollen, auch lokal verfügbar zu machen. Das bedeutet, dass die Skripte, die die eigentliche Arbeit erledigen, auch manuell ausführbar sind. Um das zu erreichen, bette die Aktion nicht direkt in die Workflow-Dateien ein, sondern erstelle ein eigenständiges Skript. Zum Beispiel lässt sich die Prüfung auf Stubs komplett im Workflow-File mit Bash erledigen, aber die Empfehlung hier ist, stattdessen ein neues ausführbares Skript scripts/ci-check zu erstellen.

„Aber der Befehl ist doch sehr kurz, z. B. eslint . --ext ts --ext tsx“.

Wenn dieser Befehl aktualisiert werden muss, muss er jetzt an allen Stellen aktualisiert werden: in der Dokumentation, den Workflow-Dateien und in den Köpfen der Maintainer. Das alles löst du, wenn du ihn in ein Skript auslagerst. Eine Workflow-Datei zu lesen, kann außerdem sehr einschüchternd sein.

Prüfungen bei PRs, in denen sich Übungen ändern

Die Skripte scripts/pr und scripts/pr-check (siehe Vorlagen) werden mit mehreren Argumenten aufgerufen, eines für jede Datei, die in diesem PR geändert oder hinzugefügt wurde. Wenn zum Beispiel two-fer aktualisiert wurde, sieht ein Aufruf etwa so aus:

scripts/pr exercises/two-fer/README.md exercises/two-fer/.meta/example.ext

Es wird empfohlen, alle Aktionen auf die geänderte Übung und nicht auf die geänderte Datei anzuwenden. Denn eine geänderte Datei löst wahrscheinlich Änderungen für die gesamte Übung aus (denk an: Konfiguration, Pakete).

Noch nicht bereit? / Zu komplex?

Bevor du diese Optimierung umsetzt, kannst du sie getrost ignorieren! Der Migrationsleitfaden deutet an, sie zu einem späteren Zeitpunkt hinzuzufügen. Wenn die Eingabeargumente ignoriert werden, laufen alle Prüfungen für alle Übungen. Das ist völlig in Ordnung. Es dauert nur länger.

Integritätsprüfungen

Wenn der Track eine einzelne „Top-Level“-Abhängigkeitsdatei und/oder andere Konfigurationsdateien hat, füge einen Schritt zur Integritätsprüfung hinzu (der neben einem scripts/sync oder bin/sync existiert, das alle Konfigurationsdateien in alle Übungen kopiert), der sicherstellt, dass die Top-Level-/Basisdateien mit der in die Übungsverzeichnisse kopierten Datei identisch sind. Jetzt können Abhängigkeiten aktualisiert und im ganzen Repository synchronisiert werden, und wir können sicherstellen, dass alle Übungen dieselbe Konfiguration haben.

Ein üblicher Weg dafür ist eine Prüfsumme. Ubuntu (und diverse andere Linux-Distributionen) bringt ein Tool namens sha1sum mit, aber welche Methode auch immer du verwendest, um die Konfigurationsdatei zu hashen oder auf einen Prüfsummenwert zu reduzieren (md5, sha1, crc32), würde funktionieren:

$ sha1sum README.md
cd58091c5043bf21f00d39ff1740d8b2976deeff *README.md

Sicherheitsprüfungen

Wenn der Track zusätzliche Workflows verwendet, die Zugriff auf das GitHub-Token oder andere Secrets benötigen, gehört es zu den Best Practices, alle im Workflow verwendeten Aktionen an einen bestimmten Commit zu binden. Einzelheiten findest du in GitHubs Leitfaden zur Sicherheitshärtung.

Zum Beispiel:

- uses: julia-actions/setup-julia@v1
+ uses: julia-actions/setup-julia@d26d1111976eae5f00db04f0515ab744ec9cd79e # 1.3.1

Wenn das Tooling Lockfiles für die Abhängigkeitsverwaltung hat, solltest du sie ins Repository einchecken und innerhalb der Workflow-Dateien ein „frozen lockfile“ verwenden. Zum Beispiel: npm ci, yarn install --frozen-lockfile und bundle install --frozen. Das stellt sicher, dass die Lockfile beim Ändern von Abhängigkeiten aktuell ist, und verhindert, dass bösartige Pakete eindringen.

Vorlagen

In diesem Verzeichnis gibt es mindestens die folgenden Vorlagen:

  • configlet.yml: Dieser Workflow holt die neueste configlet-Binary und lintet dieses Repository. Läuft bei jedem Commit. Bei PRs läuft er auf dem tatsächlichen Commit und einem „After-Merge“-Tree.
  • ci.yml: Dieser Workflow läuft nur auf dem Main-Branch, einmal bei jedem Commit.
    1. Führe einen „Pre-Check“-Befehl (Prüfung auf Stubs, Linting, Doku usw.) für alle Übungen aus
    2. Führe einen „CI“-Befehl (Build und Test) für mehrere Versionen und alle Übungen aus
  • pr.ci.yml: Dieser Workflow läuft nur bei PRs, einmal bei jedem Commit.
    1. Führe einen „Pre-Check“-Befehl (Prüfung auf Stubs, Linting, Doku usw.) für geänderte Dateien aus
    2. Führe einen „CI“-Befehl (Build und Test) für mehrere Versionen und geänderte Übungen aus

Die Nicht-PR-Workflows können auch über workflow_dispatch ausgelöst werden.

In jeder Datei steht oben, welche „Skripte“ verfügbar sein sollten. Wenn du sie als Binaries haben möchtest, ersetze scripts/xxx durch bin/xxx. Manches Tooling erfordert, dass Binaries in einem bin-Ordner liegen.

  • scripts/ci: ein Skript, das alle Übungen bauen und mit den Beispiellösungen gegen die Tests testen sollte
  • scripts/ci-check: ein Skript, das alle Übungen linten und optional auf Stubs, Konfigurationsintegrität und mehr prüfen sollte
  • scripts/pr: wie scripts/ci, aber es sollte nur Übungen ausführen, die aus den als Eingabe angegebenen Pfaden aufgelöst wurden
  • scripts/pr-check: wie scripts/ci-check, aber es sollte nur für Dateien oder Übungen ausgeführt werden, die aus den als Eingabe angegebenen Pfaden aufgelöst wurden

Fehlerbehebung

Wenn du auf Probleme stößt oder möchtest, dass jemand deine Workflows prüft, tagge bitte das Team @exercism/github-actions.

Eine Top-Level-Datei geändert, die einen CI-Lauf für alle Übungen auslösen sollte

Zum Zeitpunkt des Schreibens erlaubt pr.ci.yml nur „Extension“-Tests. Idealerweise wird das so aktualisiert, dass es immer ausgelöst wird, wenn bestimmte Dateien geändert werden (zum Beispiel die Binary zum Ausführen der Tests). Diese Änderungen sind jedoch oft selten und werden von Maintainern vorgenommen, sodass die Tatsache, dass ci.yml auf main immer für alles läuft, wahrscheinlich sicher genug ist.

Eine scripts/xxx-Datei unter Windows erstellt und jetzt funktioniert sie unter {anderem OS} nicht

Standardmäßig haben unter Windows erstellte Dateien keine Metadaten im git-index eingebettet, die ihre Ausführbarkeit betreffen, weil das Berechtigungsmodell unter Windows anders ist. Git verwendet standardmäßig die git-index-Metadaten, um zu entscheiden, ob die Datei auf POSIX-basierten Systemen ausführbar sein sollte, und macht die Datei scripts/xxx dadurch NICHT ausführbar.

git update-index --chmod=+x scripts/xxx
git commit -m "Make scripts/xxx executable"