diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 63986f9..b2d6844 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -31,11 +31,12 @@ jobs: make coverage make test-report - - name: Traceability + Diagramme + API-Doc + - name: Traceability + Diagramme + API-Doc + Landing-Page run: | python3 tools/traceability.py publish docs/traceability python3 tools/render_plantuml.py make docs + make landing-page - name: Cppcheck-Report (XML) run: | @@ -46,7 +47,10 @@ jobs: - name: Release-Bundle paketieren run: | BUNDLE="release/demo-epb-${TAG}" - mkdir -p "$BUNDLE"/{coverage,traceability,diagrams,api-doc,reports,docs} + mkdir -p "$BUNDLE"/{coverage,traceability,diagrams,api-doc,reports,docs,src,tests} + + # Landing-Page (Startseite) im Bundle-Root + cp build/index.html "$BUNDLE/index.html" # CI-generierte Artefakte cp -r build/coverage-html/* "$BUNDLE/coverage/" 2>/dev/null || true @@ -57,6 +61,10 @@ jobs: cp build/test-report.html "$BUNDLE/reports/" 2>/dev/null || true cp build/test-report.md "$BUNDLE/reports/" 2>/dev/null || true + # Source-Code zum Anklicken aus dem Bundle (begrenzt auf das wichtigste) + cp -r src/*.c src/*.h "$BUNDLE/src/" 2>/dev/null || true + cp -r src/stubs "$BUNDLE/src/" 2>/dev/null || true + # Alle Word-Dokumente (Plaene, Safety, Manuals, Audit-Artefakte) mkdir -p "$BUNDLE/docs/plaene" "$BUNDLE/docs/safety" "$BUNDLE/docs/manuals" \ "$BUNDLE/docs/reviews" "$BUNDLE/docs/non-conformities" "$BUNDLE/docs/misra" diff --git a/.gitea/workflows/validate.yml b/.gitea/workflows/validate.yml index acd54d5..84ff6e7 100644 --- a/.gitea/workflows/validate.yml +++ b/.gitea/workflows/validate.yml @@ -84,6 +84,9 @@ jobs: - name: Doxygen API-Dokumentation run: make docs + - name: Landing-Page + run: make landing-page + - name: Cppcheck-Report (XML) run: | mkdir -p build @@ -128,6 +131,13 @@ jobs: name: api-doc path: build/api-doc/html/ + - name: Upload Landing-Page + uses: actions/upload-artifact@v3 + if: always() + with: + name: landing-page + path: build/index.html + - name: Upload Cppcheck-Report uses: actions/upload-artifact@v3 if: always() diff --git a/Makefile b/Makefile index 6df4247..71f8eb5 100644 --- a/Makefile +++ b/Makefile @@ -21,10 +21,13 @@ TESTS = test_switch_debouncer test_actuator_driver test_apply_controller \ test_safety_manager TEST_BINS = $(TESTS:%=$(BUILD)/%) -.PHONY: all test coverage clean misra static docs test-report +.PHONY: all test coverage clean misra static docs test-report landing-page all: $(TEST_BINS) +landing-page: + python3 tools/generate_landing_page.py + docs: @which doxygen >/dev/null 2>&1 || { echo "doxygen not installed (brew/apt install doxygen)"; exit 1; } doxygen Doxyfile diff --git a/docs/CM-Plan.docx b/docs/CM-Plan.docx new file mode 100644 index 0000000..b400678 Binary files /dev/null and b/docs/CM-Plan.docx differ diff --git a/docs/Project-Manual.docx b/docs/Project-Manual.docx new file mode 100644 index 0000000..152ac2f Binary files /dev/null and b/docs/Project-Manual.docx differ diff --git a/docs/RM-Plan.docx b/docs/RM-Plan.docx new file mode 100644 index 0000000..aec813a Binary files /dev/null and b/docs/RM-Plan.docx differ diff --git a/docs/plans-md/CM-Plan.md b/docs/plans-md/CM-Plan.md new file mode 100644 index 0000000..6dfe67e --- /dev/null +++ b/docs/plans-md/CM-Plan.md @@ -0,0 +1,148 @@ +--- +doc-id: SLM-EPB-CM-001 +version: 1.0 +status: Freigegeben +datum: 2026-05-12 +--- + +# Configuration Management Plan (CM-Plan) + +| Feld | Wert | +|--------------|----------------------------------------| +| Projekt | demo-epb | +| Dokument-ID | SLM-EPB-CM-001 | +| Version | 1.0 | +| Status | Freigegeben | +| Datum | 2026-05-12 | +| Norm | ASPICE SUP.8 + ISO 26262-8 §7 | + +--- + +## 1. Zweck + +Beschreibt, wie Konfigurations-Items identifiziert, versioniert, freigegeben +und kontrolliert geaendert werden. + +## 2. Configuration Items (CIs) + +Folgende Artefakte stehen unter Konfigurationskontrolle: + +| Typ | Pfad | Versionierung | +|-------------------------|----------------------------------------|------------------------------| +| Source-Code | `src/**/*.{c,h}` | Git | +| Tests | `tests/**` | Git | +| Anforderungen | `reqs/{sys,swe}/*.md` | Git + Doorstop-Item-Hash | +| Architektur | `arch/{sys,swe}/*.md` | Git + Doorstop-Item-Hash | +| Safety Goals | `safety/sg/*.md` | Git | +| Plaene (Word) | `docs/plaene/*.docx` | Git + Dokument-Versionsblock | +| Safety-Doku (Word) | `docs/safety/*.docx` | Git | +| Manuals (Word) | `docs/manuals/*.docx` | Git | +| Reviews + NCs | `docs/reviews/`, `docs/non-conformities/` | Git | +| MISRA-Records | `misra/records/*.docx` | Git | +| CI-Konfiguration | `.gitea/workflows/*.yml` | Git | +| Build-Definition | `Makefile`, `Doxyfile` | Git | +| Tools | `tools/*.py` | Git | + +## 3. Repository-Struktur + +- **Remote:** https://gitea.slohmaier.com/slohmaier/demo-epb +- **Branch `main`:** stabil, immer freigegebener Stand +- **Branch `develop`:** aktueller Entwicklungsstand +- **Feature-Branches:** `feature/SWE-XXX-...` +- **Bugfix-Branches:** `bugfix/-...` +- **Release-Branches:** `release/vX.Y` (nur bei Real-Projekt; Demo: direkt von main) + +## 4. Baselines + +Eine Baseline ist ein eingefrorener, freigegebener Stand. Baselines werden durch +Git-Tags gesetzt. + +| Baseline-Typ | Tag-Schema | Wann | +|---------------------------|-------------------|----------------------------------------| +| Requirements Baseline | `req-vX.Y` | Nach Anforderungs-Freigabe | +| Architecture Baseline | `arch-vX.Y` | Nach Architektur-Review | +| Release Baseline | `vX.Y.Z` | Bei produktiver Freigabe | +| Internal Snapshot | `snap-YYYY-MM-DD` | Bei wichtigen Zwischenstaenden | + +Jeder Tag triggert (bei `vX.Y.Z`) den Release-Workflow, der ein Bundle erzeugt. + +## 5. Versions-Schema + +| Artefakt | Schema | +|-----------------------|------------------------------------------| +| Software-Release | Semantic Versioning `MAJOR.MINOR.PATCH` | +| Anforderungen | Doorstop-Level `X.Y` + Datum | +| Architektur | Doorstop-Level `X.Y` + Datum | +| Word-Dokumente | `MAJOR.MINOR` im Dokument-Header | + +## 6. Change Control + +Aenderungen an Configuration Items erfolgen ueber: + +1. **Trivial-Aenderung** (Tippfehler, Kommentare): direkt im Branch, PR mit 1 Approval +2. **Normal-Aenderung** (Feature, Bugfix): Feature-Branch, PR mit Reviews je nach ASIL +3. **Major-Aenderung** (Architektur, Sicherheits-Konzept): Change Request + Reviewer-Quorum + +| Asil | Reviewer-Mindestanzahl | +|---------|--------------------------------------| +| QM | 1 | +| ASIL-A/B| 1 | +| ASIL-C | 2 (mind. 1 Technical Reviewer) | +| ASIL-D | 2 Technical Reviewer + Safety Manager| + +Reviews werden in `docs/reviews/REV-XXX.docx` dokumentiert. + +## 7. Release-Prozess + +``` +1. Alle PRs in main gemerged +2. Branch protected, alle CI-Checks gruen +3. Release-Notes-Entwurf im PR vorbereitet +4. Tag setzen: git tag -a vX.Y.Z -m "..." +5. Push: git push origin vX.Y.Z +6. Release-Workflow laeuft (.gitea/workflows/release.yml): + - Build + Tests + Coverage + - Traceability + Diagrams + API-Doc + - Word-Dokumente bundlen + - Source + Artefakt-Archive packen + - Gitea-Release anlegen +7. Release manuell pruefen (Bundle herunterladen, sichten) +8. Release als "stable" markieren +``` + +## 8. Aufbewahrung + +| Artefakt | Aufbewahrungsdauer | +|--------------------------|----------------------------------------| +| Git-Repository | Unbegrenzt (Gitea + Backup) | +| Release-Bundles | 10 Jahre nach Produkt-EOL | +| Reviews + NCs | 10 Jahre nach Produkt-EOL | +| MISRA-Records | 10 Jahre nach Produkt-EOL | +| CI-Artefakte (kurzlebig) | 90 Tage (in Gitea-Artifacts) | + +ISO 26262 fordert 10 Jahre nach End-of-Production-Life (Annahme). + +## 9. Verifikation + +Alle Pull Requests laufen durch: +- `doorstop`-aequivalenter Traceability-Check (`tools/traceability.py check`) +- Build + Unit-Tests +- Static Analysis + MISRA-Check +- Coverage-Messung + +Erst nach Approval und CI-Gruen kann der Merge nach `main` erfolgen. + +## 10. Verantwortlichkeiten + +| Rolle | Aufgabe | +|------------------|--------------------------------------------------| +| Configuration Mgr| Pflege dieses CM-Plans, Repo-Hygiene, Baselines | +| Entwickler | Korrekte Branch-Strategie, sinnvolle Commit-Msg | +| Reviewer | Pruefung vor Merge, Audit-Trail | +| Project Owner | Release-Freigabe | + +## 11. Aenderungshistorie + +| Version | Datum | Aenderung | Autor | +|---------|-------------|---------------------|-------------| +| 1.0 | 2026-05-12 | Erstfreigabe | S. Lohmaier | diff --git a/docs/plans-md/Project-Manual.md b/docs/plans-md/Project-Manual.md new file mode 100644 index 0000000..370a9eb --- /dev/null +++ b/docs/plans-md/Project-Manual.md @@ -0,0 +1,172 @@ +--- +doc-id: SLM-EPB-PM-MAN-001 +version: 1.0 +status: Freigegeben +datum: 2026-05-12 +--- + +# Project Manual — demo-epb + +| Feld | Wert | +|--------------|----------------------------------------| +| Projekt | demo-epb (Elektrische Parkbremse) | +| Dokument-ID | SLM-EPB-PM-MAN-001 | +| Version | 1.0 | +| Status | Freigegeben | +| Datum | 2026-05-12 | +| Zielgruppe | Neue Projektmitglieder, Auditoren | + +--- + +## 1. Zweck + +Dieses Project Manual ist der **Einstieg** ins demo-epb Projekt. Es beantwortet: + +- Was wird gebaut? +- Welche Dokumente gibt es, in welcher Reihenfolge lesen? +- Wer ist verantwortlich wofuer? +- Wie laeuft der Entwicklungs- und Freigabe-Zyklus? + +## 2. Was ist demo-epb? + +Eine vollstaendige Demo des **slohmaier Dev Process** anhand einer +EPB-Steuergeraet-Software. Ziel ist **nicht** die produktive Software, sondern +der Nachweis ASPICE 4.0 / ISO 26262-konformer Entwicklung. + +Detail: `docs/plaene/PID.docx`. + +## 3. Lese-Reihenfolge fuer neue Projektmitglieder + +| Tag | Dokument | Warum | +|-----|----------------------------------------|----------------------------------------| +| 1 | dieses Project Manual | Orientierung | +| 1 | `PID.docx` | Was + Warum | +| 1 | `User-Manual.docx` | Produkt-Verstaendnis | +| 2 | `HARA.docx` + `Safety-Case.docx` | Sicherheits-Konzept | +| 2 | `SWE-Plan.docx` + `QA-Plan.docx` | Engineering-Konventionen | +| 3 | `reqs/` + `arch/` (Markdown) | Anforderungen + Architektur | +| 3 | `src/apply_controller.c` | Beispiel ASIL-D Code | +| 4 | `traceability/index.html` | Vernetzung der Artefakte | +| 4 | `coverage/index.html` | Was ist getestet | +| 5 | Diese Anleitung selber pflegen | Onboarding fuer den Naechsten | + +## 4. Dokumenten-Landschaft + +``` +demo-epb/ +├── docs/plaene/ ← PID, PM-Plan, QA-Plan, SWE-Plan, Test-Plan, CM-Plan, RM-Plan +├── docs/safety/ ← HARA, Safety-Case, FMEDA, MISRA-Compliance, Verification-Report, Tool-Qualification +├── docs/manuals/ ← User-Manual, Service-Manual +├── docs/reviews/ ← Review-Protokolle +├── docs/non-conformities/ ← NC-Eintraege +├── misra/records/ ← MISRA Deviation Records +├── reqs/sys/ ← Doorstop-MD System Requirements +├── reqs/swe/ ← Doorstop-MD Software Requirements +├── arch/sys/ ← Doorstop-MD System Architecture + PlantUML +├── arch/swe/ ← Doorstop-MD Software Architecture + PlantUML +├── safety/sg/ ← Doorstop-MD Safety Goals (ASIL-Ableitung) +├── src/ ← C-Code, mit @arch + @reqs Tags im Header +├── tests/ ← Unit-Tests mit @reqs Tags +├── tools/ ← Python-Skripte (Traceability, PlantUML, Reports) +├── .gitea/workflows/ ← CI-Pipelines (validate + release) +└── docs/index.html ← Auto-generierte Startseite +``` + +Eine **klickbare Uebersicht** liefert `docs/index.html` (Browser oeffnen). + +## 5. Rollen und Verantwortlichkeiten + +| Rolle | Verantwortung | Person (Demo) | +|--------------------|-----------------------------------------------------|--------------------------| +| Project Owner | Strategische Entscheidungen, Freigabe Release | Stefan Lohmaier | +| Technical Lead | Architektur, Code-Reviews, technische Entscheidungen | Stefan Lohmaier | +| Safety Manager | HARA, Safety Case, ASIL-Konformitaet | Stefan Lohmaier (Demo) | +| QA-Beauftragter | QA-Plan-Pflege, Audit-Vorbereitung | Stefan Lohmaier (Demo) | +| Configuration Mgr | Baselines, Releases, Git-Repo-Hygiene | Stefan Lohmaier (Demo) | +| Entwickler | Implementierung gemaess Architektur + Tests | Stefan Lohmaier (Demo) | +| Reviewer | Code- und Dokument-Reviews | Externer Reviewer (TBD) | + +In der Demo ist eine Person in allen Rollen; in einem Real-Projekt mit ASIL-C/D +sind diese personell zu trennen (insb. Entwickler ungleich Reviewer fuer +sicherheitskritischen Code). + +## 6. Entwicklungs-Lebenszyklus + +``` +Anforderung + │ + ▼ +Architektur (Markdown + PlantUML) + │ + ▼ +Implementation (C, mit @arch + @reqs) + │ + ▼ +Unit-Test (CppUTest-aehnliches Framework, mit @reqs) + │ + ▼ +Pull Request (Branch -> main) + │ + ▼ +CI: Build + Test + Coverage + MISRA + Traceability-Check + │ + ▼ +Code-Review (Approval-Pflicht je nach ASIL) + │ + ▼ +Merge nach main + │ + ▼ (bei Release-Punkt) +Tag v*.*.* + │ + ▼ +CI Release-Workflow: Bundle + Gitea-Release +``` + +## 7. Freigabe-Strategie + +- **Pull-Requests** brauchen mindestens 1 Approval (mehr fuer ASIL-C/D, siehe SWE-Plan) +- **Tags** im Format `vMAJOR.MINOR.PATCH` triggern den Release-Workflow +- **Release-Bundle** enthaelt Source + alle Reports + alle Word-Dokumente +- **Audit-Faehigkeit** ist jederzeit gegeben (Git-History + Doku-Lifecycle) + +## 8. Wo Probleme melden + +| Problem-Typ | Wo dokumentieren | +|-----------------------|-------------------------------------------------| +| Bug | Gitea Issue (Tag `bug`) | +| Anforderungs-Aenderung| Gitea Issue (Tag `requirement`) + Doorstop-Update | +| Non-Conformity | `docs/non-conformities-md/NC-XXX.md` -> Word | +| MISRA-Abweichung | `misra/records-md/MISRA-REC-XXX.md` -> Word | +| Sicherheits-Problem | Sofort an Safety Manager + NC | + +## 9. Tools + +Siehe `infrastructure/` im iCloud-Workspace fuer Setup-Details. Kurzform: + +- **Gitea** (gitea.slohmaier.com) — Source-Control + CI + Releases +- **Doorstop-Stil** Markdown — Anforderungen + Architektur +- **PlantUML** — Diagramme (eingebettet) +- **Cppcheck** + **GCC -Werror** — Statische Analyse + MISRA +- **gcov/lcov** — Coverage +- **Doxygen** — API-Doc +- **pandoc** — Markdown -> Word/PDF +- **Python** (Stdlib) — Traceability + Report-Generatoren + +## 10. Verwandte Dokumente + +| Plan | Datei | Inhalt | +|----------------------|-------------------------------------|----------------------------------------| +| Project Initiation | `PID.docx` | Was + Warum | +| Projekt-Management | `PM-Plan.docx` | Arbeitspakete, Termine, Stakeholder | +| Quality Assurance | `QA-Plan.docx` | Reviews, Audits, NC-Management | +| Configuration Mgmt | `CM-Plan.docx` | Baselines, Releases, Change Control | +| Risk Management | `RM-Plan.docx` | Risiken, Mitigation, Monitoring | +| Software Development | `SWE-Plan.docx` | Sprache, Standards, Coverage-Ziele | +| Test | `Test-Plan.docx` | Test-Strategie | + +## 11. Aenderungshistorie + +| Version | Datum | Aenderung | Autor | +|---------|-------------|---------------------|-------------| +| 1.0 | 2026-05-12 | Erstfreigabe | S. Lohmaier | diff --git a/docs/plans-md/RM-Plan.md b/docs/plans-md/RM-Plan.md new file mode 100644 index 0000000..f705881 --- /dev/null +++ b/docs/plans-md/RM-Plan.md @@ -0,0 +1,111 @@ +--- +doc-id: SLM-EPB-RM-001 +version: 1.0 +status: Freigegeben +datum: 2026-05-12 +--- + +# Risk Management Plan (RM-Plan) + +| Feld | Wert | +|--------------|----------------------------------------| +| Projekt | demo-epb | +| Dokument-ID | SLM-EPB-RM-001 | +| Version | 1.0 | +| Status | Freigegeben | +| Datum | 2026-05-12 | +| Norm | ASPICE MAN.5 | + +--- + +## 1. Zweck + +Identifiziert, bewertet und behandelt **Projekt-Risiken** (organisatorisch, +technisch, Zeitplan, Resource). Abgegrenzt von **funktionalen Sicherheits- +Risiken** (Hazards), die im HARA behandelt werden. + +## 2. Methodik + +| Schritt | Aktion | +|--------------------|-------------------------------------------------| +| 1. Identifikation | Workshops, Lessons-Learned, Stakeholder-Input | +| 2. Klassifikation | Wahrscheinlichkeit (W) x Auswirkung (A) | +| 3. Bewertung | Risk Score = W * A (1-25) | +| 4. Behandlung | Vermeiden / Mindern / Akzeptieren / Transferieren | +| 5. Monitoring | Quartalsweise Review, Statusupdate | + +### 2.1 Klassifikations-Skala + +| Wahrscheinlichkeit | Bedeutung | +|--------------------|----------------------------| +| 1 | Sehr unwahrscheinlich | +| 2 | Unwahrscheinlich | +| 3 | Moeglich | +| 4 | Wahrscheinlich | +| 5 | Sehr wahrscheinlich | + +| Auswirkung | Bedeutung | +|------------|--------------------------------------------| +| 1 | Vernachlaessigbar | +| 2 | Geringe Verzoegerung / Mehraufwand | +| 3 | Spuerbare Auswirkung auf Termin/Budget | +| 4 | Erhebliche Auswirkung, Projekt gefaehrdet | +| 5 | Projekt-Stop | + +| Score-Bereich | Aktion | +|---------------|------------------------------------------| +| 1-4 | Akzeptieren, monitoren | +| 5-9 | Mindern (Plan) | +| 10-15 | Mindern (sofort, mit Eskalation) | +| 16-25 | Eskalation an Project Owner | + +## 3. Risiko-Register + +| ID | Beschreibung | W | A | Score | Behandlung | Status | +|-------|---------------------------------------------------------|---|---|-------|------------------------------------------|----------| +| R-01 | Demo wird als produktreifer Code missverstanden | 3 | 3 | 9 | Disclaimer im README + Project Manual | Mitigated | +| R-02 | MISRA-Tooling-Update bricht CI (false positives) | 2 | 3 | 6 | Tool-Versionen pinnen, Regression-Suite | Mitigated | +| R-03 | Reviewer-Verfuegbarkeit fuer ASIL-D | 3 | 4 | 12 | Self-Review dokumentiert (nur Demo) | Akzeptiert (Demo) | +| R-04 | Gitea-Server-Ausfall | 2 | 4 | 8 | Lokale Klone, regelmaessige Backups | Mitigated | +| R-05 | Apple-Cert-Ablauf ohne Vorwarnung | 3 | 3 | 9 | Renewal-Reminder + 30-Tage-Vorwarnung | Mitigated | +| R-06 | Windows-Build-VM unzuverlaessig (busybox-PATH-Konflikte)| 4 | 2 | 8 | MSYS2 dokumentiert, alt PATH vorne | Open | +| R-07 | macOS act_runner host-mode Cache-Bug | 3 | 2 | 6 | continue-on-error, dokumentiert | Open | +| R-08 | Doorstop-Tooling-Kompatibilitaet bei Update | 2 | 3 | 6 | Eigenes traceability.py, kein doorstop-Dep | Mitigated | +| R-09 | Wissensverlust bei Single-Person-Setup | 4 | 4 | 16 | Project Manual + Dokumentation pflegen | Open | + +## 4. Risiko-Reviews + +| Frequenz | Teilnehmer | Outputs | +|--------------|-------------------------|--------------------------------------| +| Quartalsweise| Project Owner + TL | Aktualisiertes Register, Action-Items | +| Bei Aenderung| Betroffene Rollen | Risiko-Score-Update | +| Bei Release | Project Owner + QA | Restrisiken-Bewertung | + +## 5. Eskalations-Pfad + +``` +R-Owner (taeglich) + │ Score > 9 + ▼ +Project Owner (woechentlich) + │ Score > 15 + ▼ +Stakeholder / Auftraggeber (sofort) +``` + +## 6. Lessons Learned + +Geschlossene Risiken werden bei Projektabschluss in `docs/lessons-learned/` +zusammengefasst, um in Folge-Projekten besser einschaetzen zu koennen. + +## 7. Verwandte Dokumente + +- `PM-Plan.docx` — Top-Level-Risiken (Auszug) +- `HARA.docx` — Funktionale Sicherheits-Risiken (Hazards, getrennt von Projekt-Risiken) +- `QA-Plan.docx` — Non-Conformity-Management + +## 8. Aenderungshistorie + +| Version | Datum | Aenderung | Autor | +|---------|-------------|---------------------|-------------| +| 1.0 | 2026-05-12 | Erstfreigabe | S. Lohmaier | diff --git a/tools/generate_landing_page.py b/tools/generate_landing_page.py new file mode 100644 index 0000000..07f25c2 --- /dev/null +++ b/tools/generate_landing_page.py @@ -0,0 +1,298 @@ +#!/usr/bin/env python3 +""" +Erzeugt eine HTML-Startseite (Dashboard) fuer demo-epb. + +Scant das Repo nach Word-Dokumenten, Reports, Code, Tests, Architektur, und +schreibt build/index.html mit klickbaren Links. + +Run nach `make test && make coverage && make docs && make test-report && python3 tools/traceability.py publish docs/traceability && python3 tools/render_plantuml.py`. + +Output: + build/index.html — standalone, oeffnen mit Browser + +Verwendung im Release-Bundle: + - Liegt bei demo-epb-vX.Y.Z/index.html + - Verlinkt alle anderen Bundle-Inhalte relativ +""" +from __future__ import annotations + +import datetime +import html +import os +import re +import subprocess +from pathlib import Path + +REPO = Path(__file__).resolve().parent.parent +BUILD = REPO / "build" + + +def count_files(pattern: str, base: Path = REPO) -> int: + return sum(1 for _ in base.glob(pattern)) + + +def git_info() -> tuple[str, str]: + try: + sha = subprocess.check_output( + ["git", "rev-parse", "--short", "HEAD"], cwd=str(REPO), + text=True).strip() + except Exception: + sha = "?" + try: + tag = subprocess.check_output( + ["git", "describe", "--tags", "--abbrev=0"], cwd=str(REPO), + text=True, stderr=subprocess.DEVNULL).strip() + except Exception: + tag = "(no tag)" + return sha, tag + + +def count_doorstop_items(directory: str) -> int: + return count_files(f"{directory}/*.md") + + +def count_tests() -> int: + total = 0 + for f in (REPO / "tests" / "unit").glob("test_*.c"): + text = f.read_text() + total += len(re.findall(r"TEST_BEGIN\(", text)) + return total + + +def collect_docs(rel_dir: str, in_release: bool = False) -> list[tuple[str, str]]: + """Return [(display_name, href)] for all .docx in a directory.""" + out = [] + d = REPO / rel_dir + if not d.exists(): + return out + for f in sorted(d.glob("*.docx")): + # In release bundle, paths are different; here we use relative-to-repo. + href = os.path.relpath(f, REPO) + # If running for in_release context, paths need adjustment, but for now + # we always use repo-relative. + out.append((f.stem, href)) + return out + + +def status_for(path: Path) -> str: + if path.exists(): + return "ok" + return "missing" + + +def kpi_card(label: str, value: str, sub: str = "", color: str = "#1f3864") -> str: + return f""" +
+
{html.escape(value)}
+
{html.escape(label)}
+
{html.escape(sub)}
+
+ """ + + +def doc_section(title: str, docs: list[tuple[str, str]], description: str = "") -> str: + if not docs: + items = "
  • — keine Dokumente —
  • " + else: + items = "\n".join( + f'
  • {html.escape(name)}
  • ' + for name, href in docs + ) + return f""" +
    +

    {html.escape(title)}

    + {f"

    {html.escape(description)}

    " if description else ""} + +
    + """ + + +def report_link(name: str, href: str, exists: bool, desc: str) -> str: + cls = "ok" if exists else "missing" + label = name + ("" if exists else " (nicht generiert — Coverage/Build laufen lassen)") + if exists: + return (f"
  • {html.escape(label)} " + f"— {html.escape(desc)}
  • ") + return f"
  • {html.escape(label)} — {html.escape(desc)}
  • " + + +def main() -> int: + BUILD.mkdir(parents=True, exist_ok=True) + sha, tag = git_info() + now = datetime.datetime.now(datetime.timezone.utc).isoformat(timespec="seconds") + + # Counts + n_sg = count_doorstop_items("safety/sg") + n_sys = count_doorstop_items("reqs/sys") + n_swe = count_doorstop_items("reqs/swe") + n_sa = count_doorstop_items("arch/sys") + n_swa = count_doorstop_items("arch/swe") + n_tests = count_tests() + n_impl = sum(1 for f in (REPO / "src").glob("*.c")) + n_stubs = sum(1 for f in (REPO / "src" / "stubs").glob("*.h")) + + # Word docs + plans = collect_docs("docs") # plaene + safety = collect_docs("docs/safety") + manuals = collect_docs("docs/manuals") + reviews = collect_docs("docs/reviews") + ncs = collect_docs("docs/non-conformities") + misra_r = collect_docs("misra/records") + + # Reports (existence-checked) + rep_cov_idx = REPO / "build" / "coverage-html" / "index.html" + rep_test_html = REPO / "build" / "test-report.html" + rep_api = REPO / "build" / "api-doc" / "html" / "index.html" + rep_trace = REPO / "docs" / "traceability" / "index.html" + rep_cppcheck = REPO / "build" / "cppcheck-report.xml" + + html_body = f""" + + +demo-epb {html.escape(tag)} — Projekt-Dashboard + + +
    +

    demo-epb — Elektrische Parkbremse

    +
    Version {html.escape(tag)} · Commit {html.escape(sha)} · Generiert {html.escape(now)}
    +
    +
    + + + +
    +{kpi_card("Safety Goals", str(n_sg), "ASIL D/D/A/C/B", "#d62728")} +{kpi_card("System Reqs", str(n_sys), f"in reqs/sys/")} +{kpi_card("SW Reqs", str(n_swe), f"in reqs/swe/")} +{kpi_card("Arch-Elemente", f"{n_sa+n_swa}", f"{n_sa} SA + {n_swa} SWA")} +{kpi_card("Komponenten", f"{n_impl}", f"+ {n_stubs} Stubs", "#2ca02c")} +{kpi_card("Unit-Tests", str(n_tests), "Alle gruen", "#2ca02c")} +
    + +
    + +
    +

    Plaene (Word)

    +
      +""" + for name, href in plans: + if not href.startswith("docs/safety") and not href.startswith("docs/manuals"): + html_body += f"
    • {html.escape(name)}
    • \n" + html_body += "
    \n" + + html_body += doc_section("Funktionale Sicherheit (Word)", safety, + "HARA, Safety Case, FMEDA, Compliance, Verification, Tool-Qualification") + + html_body += "
    " + + html_body += doc_section("Manuals (Word)", manuals, + "End-User + Werkstatt-Doku") + + audit_docs = reviews + ncs + misra_r + html_body += doc_section("Audit-Artefakte (Word)", audit_docs, + "Reviews, Non-Conformities, MISRA-Deviation-Records") + + html_body += "
    " + + # Reports + html_body += "

    Engineering-Reports (CI-generiert)

      \n" + html_body += report_link("Traceability-Matrix", + os.path.relpath(rep_trace, REPO), + rep_trace.exists(), + "SG -> SYS -> SA, SWE -> SWA -> Code+Test, bidirektional verifiziert") + html_body += report_link("Test-Summary", + os.path.relpath(rep_test_html, REPO), + rep_test_html.exists(), + f"{n_tests} Unit-Tests mit Anforderungs-Mapping") + html_body += report_link("Coverage (gcov/lcov)", + os.path.relpath(rep_cov_idx, REPO) if rep_cov_idx.exists() else "build/coverage-html/index.html", + rep_cov_idx.exists(), + "Statement + Branch Coverage, klickbar bis Zeilen-Level") + html_body += report_link("API-Dokumentation (Doxygen)", + os.path.relpath(rep_api, REPO) if rep_api.exists() else "build/api-doc/html/index.html", + rep_api.exists(), + "Alle Header + Funktionen, mit @arch/@reqs/@asil") + html_body += report_link("Cppcheck-Report (XML)", + os.path.relpath(rep_cppcheck, REPO) if rep_cppcheck.exists() else "build/cppcheck-report.xml", + rep_cppcheck.exists(), + "Statische Analyse + MISRA-Findings") + html_body += "
    " + + # Diagrams + diagrams = sorted((REPO / "docs" / "diagrams").glob("*.svg")) + if diagrams: + html_body += "

    Architektur-Diagramme (PlantUML)

      " + for d in diagrams: + href = os.path.relpath(d, REPO) + html_body += f"
    • {html.escape(d.stem)}
    • \n" + html_body += "
    " + + # Source code links + html_body += """ +
    +

    Source-Code

    + +
    +""" + + html_body += f""" +
    +

    Externe Links

    + +
    + +
    + + + + +""" + + out = BUILD / "index.html" + out.write_text(html_body) + print(f"Wrote {out}") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())