Zruck zum Blog, du Zniachtl
Juli 2026·3 Min. zum LesnVo da KI gmocht

Deine erste GitHub Action schreibn

#ci-cd#github#devops

De meisten Teams fangen mit GitHub Actions o, indem's an Workflow aus am ondern Repo einekopiern und hoffen, dass er no passt. Des geht gut, bis zu dem Tag, wo's ned mehr geht, und ma wirklich vastehn muass, wos an Lauf auslöst, wos a Job und a Step sand und wia ma Daten dazwischen weitergibt. Do wird a echter Workflow von Null aufgbaut - Tests bei jedem Pull Request ausführn und bei getaggten Releases a Package veröffentlichn.

De Anatomie von an Workflow

A Workflow is a YAML-Datei in .github/workflows/. Er hot drei Kernstücke: Trigger (on) entscheidn, wann er lauft, Jobs sand Gruppen von Steps, de jeweils auf ana eigenen virtuellen Maschin laufn, und Steps sand de einzelnen Befehle oda Actions in am Job.

name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npm test

actions/checkout@v4 klont dein Repo in den Runner - ohne des is da Runner a leere VM ohne Zugriff auf deinen Code. actions/setup-node installiert a bestimmte Node-Version. npm ci (ned npm install) is in da CI wichtig: Es installiert genau des, wos in da package-lock.json steht, und scheitert, wenn s'Lockfile ned synchron is, statt's still zum aktualisiern.

Jobs parallel laufn lassn mit ana Matrix

Wennst gegn mehrere Node-Versionen oda Betriebssysteme testn muasst, expandiert a Matrix oane Job-Definition in mehrere parallele Läufe:

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18, 20, 22]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
      - run: npm ci
      - run: npm test

Des startet drei unabhängige Jobs, oan pro Node-Version, olle parallel. ${{ matrix.node-version }} is die Expression-Syntax von GitHub Actions - sie setzt den aktuellen Matrix-Wert in den Step ein.

Abhängigkeiten cachen

Jeder Job startet auf ana frischen VM, drum ladt npm ci bei jedem Lauf olle Packages neu runter, außer du cachst sie:

- uses: actions/setup-node@v4
  with:
    node-version: '20'
    cache: 'npm'

Die eingbaute cache-Option von setup-node erledigt des für npm, yarn und pnpm - sie bindet den Cache an den Hash vom Lockfile, drum gibt's nur an Cache-Treffer, wenn si de Abhängigkeiten ned gändert hom.

Daten zwischen Steps weitergebn

Steps im söbn Job teiln si s'Dateisystem, aber ka Variablen - um an Wert vom oan Step zum nächsten zum gebn, schreibst in a spezielle Output-Datei:

steps:
  - id: get_version
    run: echo "version=$(node -p "require('./package.json').version")" >> "$GITHUB_OUTPUT"

  - run: echo "Building version ${{ steps.get_version.outputs.version }}"

Mit id: get_version kriagt da Step an Nama, den du später ois steps.get_version.outputs.version referenziern kannst. Des Muster - wos lesn, in $GITHUB_OUTPUT schreibn, downstream referenziern - is, wia de meisten nicht-trivialen Workflows Daten herumschiebn.

Secrets

Schreib nie Zugangsdaten fest in a Workflow-Datei - sie wird ins Repo committed und is für jeden mit Lesezugriff sichtbar. Speicher sie unter Repo-Settings → Secrets and variables → Actions und referenzier sie über den secrets-Kontext:

- name: Publish package
  run: npm publish
  env:
    NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

Secrets wern in Logs automatisch maskiert - wenn a Step irrtümlich oans ausgibt, ersetzt GitHub es in da Ausgabe durch ***.

Nur bei getaggten Releases auslösn

Kombinier on.push.tags mit am bedingten Job, um nur zu veröffentlichn, wennst an Versions-Tag pushst, und trotzdem bei jedem Push Tests laufn zu lassn:

name: Release

on:
  push:
    tags:
      - 'v*'

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          registry-url: 'https://registry.npmjs.org'
          cache: 'npm'
      - run: npm ci
      - run: npm test
      - run: npm publish
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

Wennst an Tag wia v1.2.0 pushst, lauft dieser Workflow; a normaler Commit auf main ned, weil da Trigger auf tags eingschränkt is, ned auf branches.

if:-Bedingungen für feinere Kontrolle

Manchmoi is a Trigger alloa ned präzise gnua. Mit if: kannst an Step oda Job an an Ausdruck knüpfn:

- name: Notify on failure
  if: failure()
  run: echo "Build failed on ${{ github.ref }}"

failure() is oane von mehreren eingbauten Funktionen (neben success(), always(), cancelled()), de das Ergebnis vorheriger Steps im Job prüfn - nützlich, um nur dann a Benachrichtigung zum schickn, wenn wos kaputtgeht, ohne separaten Workflow.

An Workflow debuggn

Zwoa Sochn sparn am meisten Zeit, wenn a Workflow spinnt:

  • act - lasst GitHub-Actions-Workflows lokal in Docker laufn, damit du iterieren kannst, ohne für jeden Tippfehler an Commit zu pushn.
  • workflow_dispatch-Trigger - füg on: workflow_dispatch zu jedem Workflow dazu, um in da GitHub-Oberfläche an "Run workflow"-Button zu kriagn, damit du ihn manuell neu startn kannst, ohne neuen Push:
on:
  workflow_dispatch:
  push:
    branches: [main]

Fazit

A GitHub-Actions-Workflow is nur YAML, des Trigger, Jobs und Steps beschreibt und auf kurzlebigen VMs lauft, de mit nix starten außer dem, wos actions/checkout ihnen gibt. Sobois du on:, jobs:, steps: und de ${{ }}-Expression-Syntax flüssig lesn kannst, schaut jeder Workflow, den du online findst, nimma wia Zauberei aus, sondern wia a Config-Datei, de du wirklich ändern kannst.

NeicherDatenbank-Connection-Pooling vastehnElterDen JavaScript Event Loop vastehn