Dieser Post setzt den dreiundzwanzigsten Teil fort. Ein Architekturmodell das nur lokal validiert wird, ist erst halb abgesichert. Sobald mehrere Personen am Modell arbeiten, braucht es CI: automatische Prüfung bei jedem Push, sichtbarer Diff bei jedem Pull Request.
Bausteinsicht in der Pipeline installieren
GitHub Actions stellt keine Bausteinsicht-Action bereit — die Installation erfolgt manuell per curl:
- name: Install Bausteinsicht
run: |
curl -Lo bausteinsicht.tar.gz \
https://github.com/docToolchain/Bausteinsicht/releases/latest/download/bausteinsicht_linux_amd64.tar.gz
tar xzf bausteinsicht.tar.gz
sudo mv bausteinsicht /usr/local/bin/
bausteinsicht --versionFür reproduzierbare Builds empfiehlt sich eine fixe Version statt latest:
https://github.com/docToolchain/Bausteinsicht/releases/download/v0.5.0/bausteinsicht_linux_amd64.tar.gzvalidate als Build-Gate
bausteinsicht validate gibt Exit-Code 1 zurück wenn das Modell Fehler enthält — GitHub Actions bricht den Job ab:
name: Architecture Validation
on: [push, pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Bausteinsicht
run: |
curl -Lo bausteinsicht.tar.gz \
https://github.com/docToolchain/Bausteinsicht/releases/latest/download/bausteinsicht_linux_amd64.tar.gz
tar xzf bausteinsicht.tar.gz && sudo mv bausteinsicht /usr/local/bin/
- name: Validate architecture model
run: bausteinsicht validate --format json
working-directory: architecture/Mit --format json landet die Ausgabe als strukturiertes JSON auf stdout — leichter zu parsen wenn man die Fehlerliste weiterverarbeiten will.
Was validate prüft (→ Teil 8):
Alle Element-IDs in Beziehungen und Views existieren im Modell
Alle verwendeten Tag-IDs sind in
specification.tagsdefiniertKein Element referenziert einen unbekannten Typen
Views haben keinen leeren
include-Block
diff im Pull Request
bausteinsicht diff vergleicht zwei Modellzustände und zeigt welche Elemente, Beziehungen und Views sich geändert haben.
Im PR-Kontext ist HEAD~1 vs HEAD der sinnvolle Vergleich:
- name: Compute model diff
id: diff
working-directory: architecture/
run: |
DIFF=$(bausteinsicht diff HEAD~1 HEAD --format json 2>/dev/null || echo '{}')
echo "result=$DIFF" >> $GITHUB_OUTPUT
- name: Comment diff on PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const diff = JSON.parse('${{ steps.diff.outputs.result }}');
if (!diff.changes || diff.changes.length === 0) return;
const body = [
'## 🏗 Architektur-Änderungen',
diff.changes.map(c => `- **${c.type}** \`${c.id}\`: ${c.description}`).join('\n')
].join('\n');
github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body
});Für das allererste Commit im Branch (HEAD~1 existiert nicht) gibt diff einen Fehler zurück — der || echo '{}' fängt das ab. |
SVG-Export nach jedem Push
Architekturdiagramme als SVG im Repository zu haben bedeutet: Previews in GitHub, direkte Einbindung in Dokumentation, keine lokale Installation nötig um die Diagramme zu sehen.
- name: Export architecture diagrams
run: bausteinsicht export --format svg --output out/
working-directory: architecture/
- name: Upload SVG artifacts
uses: actions/upload-artifact@v4
with:
name: architecture-diagrams
path: architecture/out/*.svg
retention-days: 30Optional: die exportierten SVGs direkt zurück in den Branch committen:
- name: Commit exported SVGs
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add architecture/out/*.svg
git diff --staged --quiet || git commit -m "chore: update architecture diagrams [skip ci]"
git pushDas [skip ci] verhindert eine Endlosschleife: der Commit durch Actions triggert keinen neuen CI-Lauf.
Vollständiger Workflow
name: Architecture CI
on:
push:
paths:
- 'architecture/**'
pull_request:
paths:
- 'architecture/**'
jobs:
architecture:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2 # für diff HEAD~1
- name: Install Bausteinsicht
run: |
curl -Lo bausteinsicht.tar.gz \
https://github.com/docToolchain/Bausteinsicht/releases/latest/download/bausteinsicht_linux_amd64.tar.gz
tar xzf bausteinsicht.tar.gz && sudo mv bausteinsicht /usr/local/bin/
- name: Validate model
run: bausteinsicht validate --format json
working-directory: architecture/
- name: Compute diff (PR only)
if: github.event_name == 'pull_request'
id: diff
working-directory: architecture/
run: |
DIFF=$(bausteinsicht diff HEAD~1 HEAD --format json 2>/dev/null || echo '{}')
echo "result=$DIFF" >> $GITHUB_OUTPUT
- name: Comment diff on PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const diff = JSON.parse('${{ steps.diff.outputs.result }}');
if (!diff.changes || diff.changes.length === 0) return;
const body = [
'## 🏗 Architektur-Änderungen',
diff.changes.map(c => `- **${c.type}** \`${c.id}\`: ${c.description}`).join('\n')
].join('\n');
github.rest.issues.createComment({
owner: context.repo.owner, repo: context.repo.repo,
issue_number: context.issue.number, body
});
- name: Export SVGs
run: bausteinsicht export --format svg --output out/
working-directory: architecture/
- name: Commit SVGs to main
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add architecture/out/*.svg
git diff --staged --quiet || git commit -m "chore: update architecture diagrams [skip ci]"
git pushpaths: ['architecture/**'] sorgt dafür dass der Workflow nur läuft wenn tatsächlich etwas am Modell geändert wurde — nicht bei jedem Commit. |
Beispiel-Modell
Das Beispiel für diesen Teil (Modell mit Developer- und CI/CD-Aktoren) liegt unter teil_24.jsonc.
So sieht das Ergebnis in draw.io aus (bausteinsicht sync):
Das draw.io-File dafür findest du hier: teil_24.drawio
Generierte PNG-Dateien via bausteinsicht export --image-format png:


Generierte PlantUML-Diagramme via bausteinsicht export-diagram:
Weiter geht es mit Migration
CI sichert das bestehende Modell ab. Aber was ist wenn man von einem anderen Tool kommt? Im nächsten Teil geht es darum wie man von draw.io, PlantUML und Structurizr zu Bausteinsicht migriert — was automatisch geht und was manuell überführt werden muss.
Offizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org