Dein erstes .forgejo/workflows/ci.yaml – eine echte App testet sich selbst.
Statt „Hello World" begleitet uns durch den ganzen Kurs eine kleine, echte App: eine FastAPI-„Tasks"-API in Python – ein Service, der Aufgaben verwaltet. Das Repo enthält ungefähr das hier:
tasks-api/
├── app/
│ └── main.py # die FastAPI-App
├── tests/
│ └── test_main.py # pytest-Tests
├── requirements.txt
└── .forgejo/
└── workflows/
└── ci.yaml # ← darum geht es
Jedes Mal, wenn jemand Code pusht, soll Forgejo automatisch prüfen: Ist der Code sauber formatiert? Laufen die Tests durch? Diesen automatisierten Ablauf nennt Forgejo einen Workflow – umgangssprachlich eine Pipeline.
Bevor wir YAML schreiben, brauchst du ein mentales Modell – es erklärt später fast jedes „Warum läuft das nicht?":
${{ … }}-Ausdrücke
wie GitHub Actions. Vieles, das du dort findest, gilt analog. Die gezielten Unterschiede
markieren wir im Kurs immer mit dem ★ Forgejo-Besonderheit-Kasten.
Ein Workflow besteht aus vier Bausteinen. Mehr brauchst du fürs Erste nicht:
.forgejo/workflows/; der ganze Ablauf, der bei einem Ereignis startet.runs-on + Label gewählt.stages:. Forgejo/GitHub kennt das nicht: Jobs laufen parallel,
und die Reihenfolge stellst du mit needs: her (Lektion 2). Innerhalb
eines Jobs laufen die Steps immer sequenziell.
ci.yaml
Die ganze Pipeline lebt in einer YAML-Datei unter .forgejo/workflows/. Hier ist
sie – Zeile für Zeile danach erklärt:
name: CI
on: [push]
jobs:
lint:
runs-on: docker
container: python:3.12-slim
steps:
- uses: actions/checkout@v4
- run: pip install ruff
- run: ruff check app tests
test:
runs-on: docker
container: python:3.12-slim
needs: [lint]
steps:
- uses: actions/checkout@v4
- run: pip install -r requirements.txt
- run: pytest -q
on: [push] – der Trigger: der Workflow läuft bei jedem Push.lint: und test: sind zwei Jobs – die Namen sind frei wählbar.runs-on: docker – wähle einen Runner mit dem Label docker.container: python:3.12-slim – alle Steps des Jobs laufen in diesem Image.needs: [lint] – test startet erst, wenn lint grün ist. Ohne needs liefen beide parallel.steps: – pro Schritt entweder ein uses: (eine Action) oder ein run: (Shell-Befehl).actions/checkout@v4 – eine fertige Action, die dein Repo in den Job klont.lint, führt es mit act im
Container aus – und nur wenn das grün ist, danach test.
Viele kommen aus der GitLab-Welt. Die guten Nachrichten: die Konzepte sind fast dieselben, nur anders benannt und etwas anders verdrahtet. Diese Übersetzungstabelle begleitet uns durch den ganzen Kurs:
Eine Datei: .gitlab-ci.yml
Ordnung über stages:
Job hat ein script:
Wiederverwenden: include / extends
Runner-Auswahl über tags
Vordefiniert: CI_COMMIT_SHA …
GitLab-Server-Runner führt aus
Mehrere: .forgejo/workflows/*.yaml
Ordnung über needs: (kein stages)
Step ist run: oder uses:
Wiederverwenden: uses / reusable workflows
Runner-Auswahl über runs-on + Label
Vordefiniert: FORGEJO_SHA …
Externer Runner + act führt aus
uses: eingebundener Baustein (wie actions/checkout).
GitLab hat dafür kein direktes Gegenstück. Wie Forgejo solche Actions auflöst, ist eine
eigene Besonderheit (Lektion 6).
runs-on:-Label zu
keinem registrierten Runner. Das Label ist freie Wahl bei der Runner-Registrierung –
docker ist nur Konvention, kein Zauberwort.
.forgejo/workflows/ liegen, Endung .yaml oder
.yml. Forgejo liest aus Kompatibilität auch .github/workflows/ – im
Workshop nutzen wir aber konsequent .forgejo/.
uses: actions/checkout@v4 bindet eine fertige Action ein. Wie Forgejo
diese Adresse auflöst (ohne Marketplace!) ist eine echte Besonderheit – die schauen wir uns
in Lektion 6 genau an. Fürs Erste: es klont dein Repo.
Nicht spicken – Abrufen aus dem Gedächtnis ist genau die Übung, die hängen bleibt.
Wer führt die Steps einer Forgejo-Pipeline tatsächlich aus?
Forgejo speichert & verteilt nur. Ein eigenständiger Runner holt den Job ab und führt ihn mit act (meist im Container) aus. Kein Runner mit passendem Label ⇒ kein Lauf.
Wie stellst du in Forgejo eine Reihenfolge zwischen Jobs her?
Forgejo kennt kein stages:. Jobs laufen parallel; needs: macht einen
Job von einem anderen abhängig. Die Position im File ist egal.
Wozu dient das Label in runs-on: docker genau?
runs-on matcht den Job auf Runner mit demselben Label. Labels vergibt man
bei der Runner-Registrierung – docker ist Konvention, nicht vorgeschrieben.