waffensachkunde

Waffensachkunde – Lernsoftware für die Sachkundeprüfung nach § 7 WaffG. Barrierefrei, offline, EUPL-1.2.

/ .github workflows gate.yml

7,8 KB Rohdatei
.github/workflows/gate.yml — 176 Zeilen
1 # =====================================================================
2 # Fortlaufende Prüfung (CI) – VORBEREITET, läuft derzeit nirgends.
3 #
4 # Dieses Projekt hat noch kein Fernarchiv. Diese Datei behauptet also
5 # nicht, es gebe CI – sie liegt bereit, damit nach dem ersten `git push`
6 # in ein GitHub-Repository die Prüfung ohne weiteren Handgriff
7 # anspringt. Einrichtung und Begründung: docs/fernarchiv.md.
8 #
9 # Die CI erfindet kein zweites Regelwerk: Der Job „gate“ ruft exakt
10 # `npm run gate` auf – dieselbe Vollstufe wie am Arbeitsplatz (Typen,
11 # Linter, Vitest, Bau, Playwright-E2E samt axe je Ansicht). Ändert sich
12 # das Gate in app/package.json, folgt die CI automatisch; ein zweiter,
13 # hier abgeschriebener Befehlssatz würde genau dann auseinanderlaufen,
14 # wenn es darauf ankommt.
15 #
16 # windows-latest, weil die Anwendung für Windows gebaut und ausgeliefert
17 # wird: Die E2E-Läufe messen Kontrast und Zielgrößen im echten
18 # Electron-Fenster, und nur der Windows-Lauf prüft die Plattform, die
19 # tatsächlich bei Anwendern steht. (Unter Linux käme zusätzlich die
20 # Frage nach einer Bildschirmumgebung für Electron dazu – hier nicht.)
21 # =====================================================================
22 name: Gate
23
24 on:
25 push:
26 pull_request:
27 branches: [main]
28 workflow_dispatch:
29
30 # Der Lauf liest nur den Quellstand. Kein Schreibrecht, weil die CI hier
31 # nichts veröffentlicht – gebaut und ausgeliefert wird am Arbeitsplatz
32 # (docs/veroeffentlichen.md).
33 permissions:
34 contents: read
35
36 # Wer zweimal kurz hintereinander schiebt, braucht den ersten Lauf nicht
37 # mehr. Windows-Läufer zählen auf das Freikontingent doppelt.
38 concurrency:
39 group: ${{ github.workflow }}-${{ github.ref }}
40 cancel-in-progress: true
41
42 jobs:
43 gate:
44 name: Gate (Vollstufe)
45 runs-on: windows-latest
46 timeout-minutes: 40
47 defaults:
48 run:
49 working-directory: app
50 steps:
51 - name: Quellstand holen
52 uses: actions/checkout@v4
53
54 # `engines` in app/package.json verlangt Node >= 22.12.0. Bewusst die
55 # 22er-Linie fest verdrahtet statt `node-version-file`: ein „>=“-Bereich
56 # würde dort stillschweigend auf die jeweils neueste Hauptversion
57 # springen, und die CI soll dieselbe Linie prüfen wie der Arbeitsplatz.
58 - name: Node einrichten
59 uses: actions/setup-node@v4
60 with:
61 node-version: 22
62 cache: npm
63 cache-dependency-path: app/package-lock.json
64
65 # `npm ci` genügt: `better-sqlite3` liefert N-API-Prebuilds, die unter
66 # Node wie unter Electron ohne Neubau laufen (deshalb steht in
67 # electron-builder.yml `npmRebuild: false`; Näheres in app/README.md,
68 # Abschnitt „Native Module“). `npm run rebuild` gehört hier also nicht
69 # hin. Über `prepare` läuft auch hooks:einrichten – im Runner
70 # wirkungslos, aber harmlos: hier committet niemand.
71 - name: Abhängigkeiten installieren
72 run: npm ci
73
74 # Nachgesehen: Keine Suite unter e2e/ startet einen Browser. Alle laufen
75 # über `_electron` gegen das Electron aus node_modules, und axe-core wird
76 # als Quelltext in die Seite injiziert (e2e/axe-hilfe.ts) – gerade weil
77 # `@axe-core/playwright` in Electron scheitert. Dieser Schritt lädt also
78 # einen Chromium herunter, den heute kein Test benutzt. Er bleibt
79 # trotzdem stehen: Er ist der versionierte Befehl aus package.json, und
80 # ein künftiger browserbasierter Test soll an seiner Sache scheitern,
81 # nicht an einer fehlenden Installation. Wer Minuten sparen will,
82 # streicht ihn.
83 - name: Playwright-Browser installieren
84 run: npm run test:e2e:install
85
86 # CI=true (von GitHub gesetzt) schaltet in playwright.config.ts
87 # forbidOnly, einen Wiederholungsversuch und den HTML-Bericht ein.
88 # `gepackt.spec.ts` übergeht sich hier mit Grund – die CI baut kein
89 # Installationspaket, und der Stempelbericht am Ende sagt das
90 # ausdrücklich, statt grün zu melden, was nicht geprüft wurde.
91 - name: Vollstufe des Gates
92 run: npm run gate
93
94 # Anlage 4 des Prüfplans (docs/barrierefreiheit-pruefplan.md) verlangt
95 # die axe-Ausgaben der CI-Läufe „mit Datum und Commit-Kennung“ – als
96 # Anlage, nicht als Ergebnis. Der Artefaktname trägt die Commit-Kennung,
97 # Datum und Auslöser stehen am Lauf.
98 #
99 # Was der Bericht NICHT hergibt: dieselbe Anlage verlangt die Ausgaben
100 # auch „je Farbschema“, und die E2E-Suiten prüfen axe bisher nur im
101 # voreingestellten Schema. Der Upload erledigt diesen Punkt also nicht,
102 # er belegt nur den geprüften Teil.
103 #
104 # `if: always()`, weil gerade der rote Lauf den Bericht braucht: Die
105 # axe-Befunde stehen im Fehlertext der jeweiligen Prüfung.
106 - name: Playwright-Bericht als Anlage sichern
107 if: always()
108 uses: actions/upload-artifact@v4
109 with:
110 name: playwright-bericht-${{ github.sha }}
111 path: app/playwright-report/
112 if-no-files-found: warn
113
114 # Spuren (Traces) entstehen nur bei Fehlschlägen (retain-on-failure) –
115 # deshalb `ignore` statt `warn`: Ein grüner Lauf ohne Spuren ist der
116 # Normalfall und keine Meldung wert.
117 - name: Fehlspuren sichern
118 if: always()
119 uses: actions/upload-artifact@v4
120 with:
121 name: testspuren-${{ github.sha }}
122 path: app/test-results/
123 if-no-files-found: ignore
124
125 # Eigener Job, weil die Inhaltsprüfung nichts mit dem App-Gate teilt:
126 # reine Python-Standardbibliothek, kein npm, kein Fenster. Ubuntu, weil
127 # die Skripte plattformunabhängig lesen (Ein- und Ausgabe ausdrücklich
128 # UTF-8) und der Runner schneller startet als Windows.
129 #
130 # Nachgesehen für alle drei Skripte: importiert werden nur io, json, re,
131 # sys, collections, dataclasses und pathlib – pruefe_glossar.py zusätzlich
132 # pruefe_erklaerungen.py, dessen Fundstellenprüfung es erbt. Kein pip-Schritt
133 # nötig. `diagnose_kreuze.py` gehört deshalb ausdrücklich NICHT hierher: Es
134 # braucht PyMuPDF und das nicht versionierte Katalog-PDF.
135 #
136 # Die Skripte lösen ihre Pfade über __file__ auf und brauchen deshalb kein
137 # bestimmtes Arbeitsverzeichnis. Sie lesen nur Eingechecktes:
138 # content/katalog/katalog.json, content/erklaerungen.json,
139 # content/glossar.json und den Gesetzesindex content/gesetze/index.json –
140 # die rohen Gesetzes-XML sind nicht versioniert und werden hier auch nicht
141 # gebraucht.
142 inhalte:
143 name: Inhalte prüfen (Katalog, Erklärungen, Glossar)
144 runs-on: ubuntu-latest
145 timeout-minutes: 10
146 steps:
147 - name: Quellstand holen
148 uses: actions/checkout@v4
149
150 - name: Python einrichten
151 uses: actions/setup-python@v5
152 with:
153 python-version: "3.12"
154
155 - name: Katalog gegen Sollwerte prüfen
156 run: python data-pipeline/validate_catalog.py
157
158 - name: Erklärungen gegen Katalog und Gesetzesindex prüfen
159 run: python data-pipeline/pruefe_erklaerungen.py
160
161 # Aus demselben Grund wie unten beim Glossar: Der Prüfer erzeugt jede
162 # seiner 23 Fehlerarten einmal absichtlich und fällt durch, sobald eine
163 # davon unbemerkt bliebe.
164 - name: Erklärungsprüfung selbst prüfen
165 run: python data-pipeline/pruefe_erklaerungen.py --selbsttest
166
167 - name: Glossar gegen Katalog und Gesetzesindex prüfen
168 run: python data-pipeline/pruefe_glossar.py
169
170 # Die Prüfung der Prüfung: Sie verletzt jede Glossarregel einmal
171 # absichtlich und fällt durch, sobald eine Verletzung unbemerkt bliebe.
172 # Ohne diesen Schritt wäre der vorige nicht mehr wert als seine
173 # Rückgabe – eine Regel, die stumm nichts mehr prüft, meldet dort
174 # weiterhin grün.
175 - name: Glossarprüfung selbst prüfen
176 run: python data-pipeline/pruefe_glossar.py --selbsttest