Deine erste GitHub Action schreibn
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ügon: workflow_dispatchzu 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.