Continuous Integration (CI)

GitBeginner
Jetzt üben

Einführung

Stellen Sie sich vor, Sie schreiben gemeinsam mit einem großen Team ein Buch. Jedes Mal, wenn jemand ein neues Kapitel einreicht, müssen Sie es auf Rechtschreibfehler und Widersprüche in der Handlung prüfen. Das manuell zu erledigen, ist anstrengend.

In der Softwareentwicklung lösen wir dieses Problem mit Continuous Integration (CI). CI prüft Änderungen automatisch und frühzeitig. Dazu werden normalerweise Abhängigkeiten installiert, Tests ausgeführt und das Projekt nach jeder Aktualisierung validiert.

Die zentrale Idee ist schnelles Feedback. Probleme lassen sich leichter beheben, wenn sie unmittelbar nach einer Änderung erkannt werden und nicht erst Tage später.

Diese Geschwindigkeit ist der Grund, warum CI für Teams meist die erste Automatisierungsebene ist. CI schützt den Haupt-Branch, indem jeder Push automatisch eine Qualitätsprüfung auslöst.

In diesem Lab bauen Sie dieses Sicherheitsnetz für eine einfache Node.js-Anwendung. Sie werden:

  • eine kleine Anwendung erstellen, die grundlegende mathematische Berechnungen ausführt;
  • einen Test schreiben, der die Richtigkeit der Berechnung bestätigt;
  • GitHub Actions so konfigurieren, dass dieser Test bei jedem Push automatisch ausgeführt wird;
  • den Code absichtlich fehlerhaft machen, um zu sehen, wie das Sicherheitsnetz den Fehler erkennt.

Voraussetzungen

Dieses Lab baut auf dem vorherigen Lab auf. Wir verwenden weiterhin das Repository github-actions-basics, das Sie dort erstellt haben.

Das Node.js-Projekt vorbereiten

Zuerst benötigen wir Code, den wir testen können. Wir erstellen eine kleine Node.js-Anwendung. Falls Sie noch nicht programmieren, müssen Sie sich keine Sorgen machen – wir stellen den gesamten benötigten Code bereit.

Wechseln Sie in das Projektverzeichnis. Da dies eine neue Lab-Umgebung ist, müssen Sie das Repository erneut herunterladen.

cd ~/project
git clone https://github.com/your-username/github-actions-basics.git
cd github-actions-basics

Hinweis: Ersetzen Sie your-username durch Ihren tatsächlichen GitHub-Benutzernamen.

Wir erstellen drei Dateien, um ein echtes Projekt zu simulieren. Dazu verwenden wir den Befehl cat. Damit können Sie schnell Dateien mit Inhalt direkt über die Befehlszeile erstellen.

1. Das „Rezept“ (package.json)

Diese Datei teilt dem Computer mit, um welches Projekt es sich handelt und welche Werkzeuge es benötigt. Wir geben an, dass unser Projekt vom Testwerkzeug jest abhängt.

cat > package.json << EOF
{
  "name": "ci-demo",
  "version": "1.0.0",
  "scripts": {
    "test": "jest"
  },
  "dependencies": {
    "jest": "^29.7.0"
  }
}
EOF

2. Die „Speise“ (index.js)

Dies ist der eigentliche Anwendungscode. Er enthält eine einfache Funktion, die zwei Zahlen addiert.

cat > index.js << EOF
function sum(a, b) {
  return a + b;
}
module.exports = sum;
EOF

3. Die „Geschmacksprüfung“ (index.test.js)

Dies ist unser automatisierter Test. Er stellt sicher, dass das Ergebnis der Addition von 1 und 2 3 ist.

cat > index.test.js << EOF
const sum = require('./index');

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});
EOF

Nachdem Sie die Dateien erstellt haben, müssen Sie sie auf GitHub speichern. Führen Sie die üblichen Git-Befehle aus, um Ihre Änderungen hochzuladen.

git add .
git commit -m "Add Node.js project files"
git push

Möglicherweise werden Sie erneut aufgefordert, sich bei GitHub anzumelden. Verwenden Sie wie zuvor Ihren Benutzernamen und Ihr Personal Access Token (PAT).

Den CI-Workflow erstellen

Jetzt müssen wir unserem Roboterassistenten mitteilen, wie er diesen Code testen soll. Dazu erstellen wir eine neue Workflow-Datei mit dem Namen ci.yml im Standardverzeichnis .github/workflows.

touch .github/workflows/ci.yml

Öffnen Sie diese Datei im Editor nano.

nano .github/workflows/ci.yml

Fügen Sie die folgende Konfiguration ein. Die neuen Bestandteile erklären wir im Anschluss.

name: Node.js CI

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 16

Hier führen wir ein wichtiges neues Schlüsselwort ein: uses.

Dies ist ein zentrales Muster in GitHub Actions. Anstatt jeden Shell-Schritt manuell zu schreiben, kombinieren Workflows häufig wiederverwendbare Actions. Diese kapseln typische Aufgaben wie das Auschecken des Codes, das Einrichten einer Programmiersprache oder das Hochladen von Artefakten.

Stellen Sie sich uses so vor, als würden Sie dem Roboter eine Fähigkeit hinzufügen. Statt komplexe Skripte von Grund auf neu zu schreiben, können Sie bereits erstellte Actions anderer Entwickler verwenden.

  • actions/checkout@v4: Diese Standard-Action weist den Roboter an: „Lade meinen Code herunter.“ Ohne diese Action wäre sein Arbeitsbereich leer.
  • actions/setup-node@v3: Diese Action installiert Node.js auf dem Runner. Außerdem übergeben wir eine bestimmte Version (16), damit die Umgebung einheitlich bleibt.

Speichern Sie die Datei und verlassen Sie den Editor (Ctrl+X, Y, Enter).

Installations- und Testschritte hinzufügen

Der Code ist ausgecheckt und die Werkzeuge – einschließlich Node.js – sind eingerichtet. Jetzt müssen wir den Test tatsächlich ausführen.

In der Node.js-Welt gibt es dafür zwei standardmäßige Befehle:

  1. npm install: Lädt alle in Ihrer package.json aufgeführten Abhängigkeiten herunter, zum Beispiel das Testwerkzeug jest.
  2. npm test: Führt das in Ihrer package.json definierte Testskript aus.

Zusammen bilden diese Schritte den Kern von CI: Die Umgebung wird vorbereitet, Abhängigkeiten werden installiert und der Code wird in einem sauberen Runner validiert, bevor die Änderung als fehlerfrei akzeptiert wird.

Fügen wir diese Schritte nun dem Workflow hinzu. Öffnen Sie .github/workflows/ci.yml erneut.

nano .github/workflows/ci.yml

Fügen Sie diese beiden Schritte am Ende der Datei ein. Achten Sie darauf, dass die Einrückung mit den vorherigen Schritten übereinstimmt.

- name: Install dependencies
  run: npm install

- name: Run tests
  run: npm test

Ihre vollständige Datei sollte anschließend so aussehen:

name: Node.js CI

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 16

      - name: Install dependencies
        run: npm install

      - name: Run tests
        run: npm test

Speichern Sie die Datei und verlassen Sie den Editor.

Aktivieren Sie nun Ihr Sicherheitsnetz, indem Sie diese Datei auf GitHub pushen.

git add .
git commit -m "Add CI pipeline"
git push

Öffnen Sie Ihr Repository auf GitHub und klicken Sie auf den Tab Actions. Dort sollte ein neuer Workflow mit dem Namen „Node.js CI“ ausgeführt werden. Nach Abschluss sehen Sie ein grünes Häkchen. Das bedeutet, dass Ihr Code funktioniert.

CI Pipeline

Den Build absichtlich fehlschlagen lassen

Ein Sicherheitsnetz ist nur dann nützlich, wenn es Sie beim Fallen auffängt. Lassen Sie uns den Code absichtlich „kaputtmachen“, um das CI-System in Aktion zu sehen.

Wir bearbeiten die Testdatei und machen darin im Grunde eine falsche Aussage. Wir behaupten, dass 1 + 2 gleich 4 sein sollte.

Öffnen Sie index.test.js mit nano.

nano index.test.js

Ändern Sie die erwartete Zahl im Test von 3 zu 4.

const sum = require("./index");

test("adds 1 + 2 to equal 3", () => {
  expect(sum(1, 2)).toBe(4); // CHANGED 3 to 4
});

Speichern Sie die Datei und verlassen Sie den Editor. Committen und pushen Sie anschließend diesen „Fehler“.

git add .
git commit -m "Intentionally break the test"
git push

Wechseln Sie auf GitHub sofort zurück zum Tab Actions. Beobachten Sie, wie der neue Workflow ausgeführt wird.

Nach kurzer Zeit sollte der Lauf fehlschlagen. Neben dem Commit sehen Sie ein rotes X. Das bedeutet, dass das CI-System lautstark meldet: „Stopp! Etwas stimmt nicht!“

Klicken Sie auf den fehlgeschlagenen Lauf und anschließend auf den Job build. Klappen Sie den Schritt Run tests auf, um das Fehlerprotokoll anzuzeigen:

Error: expect(received).toBe(expected) // Object.is equality

Expected: 4
Received: 3

Dieses einfache rote X erspart Entwicklern unzählige Arbeitsstunden, weil es Fehler sofort erkennt und nicht erst Tage oder Wochen später.

CI Pipeline Failed

Zusammenfassung

In diesem Lab haben Sie eine professionelle Continuous-Integration-Pipeline erstellt.

Sie haben gelernt:

  • wie Sie mit package.json das „Rezept“ eines Projekts definieren;
  • wie Sie das Schlüsselwort uses verwenden, um leistungsfähige Werkzeuge wie actions/checkout und actions/setup-node einzubinden;
  • wie Sie Tests automatisieren, damit jede Codeänderung von einem Roboter überprüft wird;
  • warum das „rote X“ als Sicherheitsnetz für Ihren Code wichtig ist.

Im nächsten Lab lernen Sie, wie Sie funktionierenden Code für die Veröffentlichung verpacken.