Architektur¶
Repo Blueprint ist ein Repository, das sein eigener erster Nutzer ist: Die Workflows, die ihn prüfen, veröffentlichen und aktualisieren, sind die Vorlagen der Workflows jedes Repositorys, das aus ihm entsteht, und jedes seiner Releases erreicht sie alle als Pull Request. Diese Seite zeigt, wie er aufgebaut ist und welchen Weg ein Release nimmt. Die Automatisierung beschreibt jeden Workflow, das Sicherheitsdesign (englisch), was der Blueprint schützt und wem er vertraut, die Referenz (englisch) jede Frage, Variable und jedes Secret, und die Entscheidungen (englisch), warum er so arbeitet.
Wie der Blueprint funktioniert¶
---
config:
flowchart:
wrappingWidth: 400
---
flowchart TB
accTitle: Wie der Blueprint funktioniert
accDescr: Copier rendert ein neues Repository aus den Fragen in copier.yml und den Dateien in template/, die die Workflows aus .github/workflows/, die Manifeste aus stacks/ und blueprint.py aufnehmen. Renovate hält die Workflows und die Stacks aktuell.
renovate(["Renovate"])
subgraph here ["Dieses Repository"]
workflows[".github/workflows/<br>laufen hier und sind<br>die Vorlagen"]
stacks["stacks/<br>Manifeste und<br>Lock-Dateien"]
tool["blueprint.py<br>Einstellungen · Checkliste<br>Bots"]
template["template/<br>die Dateien eines<br>neuen Repositorys"]
questions["copier.yml<br>die Fragen"]
end
copier(["Copier"])
repo["Ein neues Repository"]
renovate -. "hält aktuell" .-> workflows
renovate -.-> stacks
workflows --> template
stacks --> template
tool --> template
template --> copier
questions --> copier
copier --> repo
classDef bot fill:#526cfe2e,stroke:#526cfe,stroke-width:2px
classDef done fill:#16a34a2e,stroke:#16a34a,stroke-width:2px
class renovate bot
class repo done
copier.ymlenthält die Fragen.template/enthält die Dateien eines neuen Repositorys; ein Datei- oder Ordnername wie[% if stack == 'php' %]composer.json[% endif %]trägt seine Bedingung, und ein Name, der leer gerendert wird, entfällt. Die Trennzeichen{= =}und[% %]kommen in keinem Workflow, Skript oder Manifest vor; so bleiben${{ }}von GitHub Actions und[[ ]]von Bash und TOML unverändert.- Die Workflows in
.github/workflows/laufen in diesem Repository und sind zugleich die Vorlagen der Workflows jedes neuen Repositorys: actionlint prüft sie, und Renovate hält ihre Actions hier aktuell. Eine Zeile mit Not in the blueprint itself schaltet einen Job in diesem Repository ab und fehlt in neuen. blueprint.pystartet das Werkzeug der Einstellungen als Code, der Checkliste und der Bots. Sein Code liegt inblueprint/, ein Modul für jede Aufgabe, mit einer eigenenruff.toml, damit die Ruff-Einstellungen eines Projekts nicht für ihn gelten.stacks/enthält Manifeste und Lock-Dateien jeder Projektart, die Renovate aktuell hält; ein neues Projekt startet von ihnen.tests/prüftblueprint.pygegen ein simuliertes GitHub und rendert jede Projektart; der Variants-Workflow rendert jede einzelne und führt ihre eigenen Prüfungen mit den echten Werkzeugen aus. Außerdem bringt er ein Repository jeder Art vom letzten Release auf den Commit; das muss jede Datei des Blueprints so bekommen, wie ein neues Repository sie hat, und dieselben Prüfungen bestehen: in jedem Pull Request außer dem Release-Pull-Request, und jede Woche. Ebenso aktualisiert er eines mit den Antworten jedes Repositorys, das den Blueprint übernimmt, austests/answers/: ohne den Beispielcode und mit dessen Lizenz, Sprachen und Discussions; dessen Website und Lint müssen ebenfalls bestehen. Der Downstream-Workflow klont jedes dieser Repositories und aktualisiert es wie sein Blueprint-Bot, aufmainund auf den Pull Request: Seine Zusammenfassung nennt die Dateien, deren Update der Pull Request ändert, und jeden Konflikt, bevor das Release sie dorthin bringt, und ein Konflikt in einer Datei, die keine Textseite ist, etwa einem Workflow, einem Skript oder einer Konfiguration, lässt ihn scheitern (downstream.py). Der Windows-Workflow führtscripts/check.shaußerdem unter Windows aus, in Git Bash wie auf dem Rechner eines Mitwirkenden, jede Woche und für jeden Pull Request, der den Code oder die Tests ändert. Der Workflow Next runner führt die Variants jede Woche auf dem Runner aus, auf den die Jobs als Nächstes umziehen.docs/macht diese Dokumentation zur Website des Blueprints: ihre Seiten binden die READMEs ein, und der Dashboard-Workflow veröffentlicht sie mit dem Dashboard unterdashboard/.reference.pyschreibt die Referenz der Website auscopier.yml, den Workflows und den Einstellungen als Code der Vorlage, sodass jede Frage, Variable und jedes Secret dort beschrieben ist, wo man sie sucht;tests/test_reference.pyscheitert, solange eine Seite von ihnen abweicht.
---
config:
flowchart:
wrappingWidth: 400
---
flowchart TB
accTitle: Wie eine Änderung der Vorlage die Repositories vor ihrem Release trifft
accDescr: Ein Pull Request ändert, was die Repositories vom Blueprint bekommen. Der Variants-Workflow erzeugt ein neues Repository jeder Art, bringt eines jeder Art vom letzten Release auf den Stand und eines mit den Antworten jedes Repositorys aus tests/answers, das jede Datei so bekommen muss wie ein neues Repository mit diesen Antworten und den Bau seiner Website und den Lint seiner Workflows und seines Markdowns bestehen muss. Der Downstream-Workflow klont jedes Repository und aktualisiert es wie sein Blueprint-Bot, auf main und auf den Pull Request, und nennt die Dateien, deren Update der Pull Request ändert, und jeden Konflikt; ein Konflikt, den der Pull Request in einen Workflow oder ein Skript bringt, lässt ihn scheitern. Dann wird der Pull Request gemergt, und das Release und der Rollout bringen ihn in jedes Repository.
change(["Ein Pull Request ändert die Vorlage"])
variants["Variants: ein neues Repository jeder Art,<br>eines vom letzten Release aktualisiert<br>und eines mit den Antworten jedes Repositorys<br>aus tests/answers/"]
downstream["Downstream: jedes Repository geklont<br>und wie von seinem Blueprint-Bot aktualisiert,<br>auf main und auf den Pull Request"]
summary["Die Zusammenfassung: die Dateien, deren Update<br>der Pull Request ändert, und jeder Konflikt"]
conflict{"Ein Konflikt, den der Pull Request<br>in einen Workflow oder ein Skript bringt?"}
fix(["Die Vorlage korrigieren oder im Changelog sagen,<br>wie ein Repository ihn löst"])
merge["Der Pull Request wird gemergt"]
rollout(["Das Release und der Rollout bringen ihn<br>in jedes Repository"])
change --> variants & downstream
downstream --> summary --> conflict
conflict -- "ja: die Prüfung scheitert" --> fix --> change
conflict -- "nein" --> merge
variants -- "jede Variante besteht" --> merge
merge --> rollout
classDef bot fill:#526cfe2e,stroke:#526cfe,stroke-width:2px
classDef person fill:#f59e0b2e,stroke:#f59e0b,stroke-width:2px
classDef result fill:#16a34a2e,stroke:#16a34a,stroke-width:2px
class variants,downstream,summary bot
class change,fix person
class rollout result
Der Weg eines Releases¶
---
config:
flowchart:
wrappingWidth: 400
---
flowchart TB
accTitle: Der Weg eines Releases des Blueprints
accDescr: Ein Pull Request wird in main des Blueprints gemergt, und der Release-Workflow hält den Release-Pull-Request mit der nächsten Version. Sein Merge, durch den Maintainer oder von selbst, wenn er nur Updates enthält, veröffentlicht das Release mit einem signierten Tag und prüft es. Der Rollout-Workflow startet dann den Blueprint-Bot jedes Repositorys, das den Blueprint übernimmt, heute fünf. Jeder Bot prüft das Release, führt copier update aus und hält einen Update-Pull-Request als Release-App, damit die Prüfungen des Repositorys laufen. Ohne Konflikte merged er sich selbst, sobald sie bestehen; mit Konflikten oder mit BLUEPRINT_AUTOMERGE auf off wartet er auf den Maintainer. Das Dashboard zeigt das Release des Blueprints, auf dem jedes Repository steht.
merge(["Ein Pull Request wird<br>in main des Blueprints gemergt"])
release["Release-Workflow<br>hält den Release-Pull-Request<br>mit der nächsten Version"]
publish["Sein Merge veröffentlicht das Release<br>signiert seinen Tag und prüft es"]
rollout["Rollout-Workflow<br>startet den Blueprint-Bot<br>jedes Repositorys"]
bot["Blueprint-Bot, in jedem der fünf<br>prüft das Release<br>und führt copier update aus"]
pull["Ein Update-Pull-Request<br>als Release-App"]
checks["Die Prüfungen des Repositorys<br>testen das Update"]
merged["Er merged sich selbst,<br>sobald jede Prüfung besteht"]
wait(["Er wartet auf den Maintainer<br>mit Konflikten oder mit<br>BLUEPRINT_AUTOMERGE auf off"])
dashboard(["Das Dashboard zeigt das Release,<br>auf dem jedes Repository steht"])
merge --> release --> publish --> rollout --> bot --> pull --> checks
checks --> merged --> dashboard
checks -. "Konflikte" .-> wait
wait -. "gelöst und gemergt" .-> dashboard
classDef bot fill:#526cfe2e,stroke:#526cfe,stroke-width:2px
classDef person fill:#f59e0b2e,stroke:#f59e0b,stroke-width:2px
classDef done fill:#16a34a2e,stroke:#16a34a,stroke-width:2px
class release,publish,rollout,bot,pull,checks,merged bot
class merge,wait person
class dashboard done
- Ein Merge in
maindes Blueprints startet den Release-Workflow, dessen release-please einen Release-Pull-Request mit der nächsten Version hält, bestimmt aus den Titeln der gemergten Pull Requests, und mit den Einträgen des Changelogs als Notizen. - Das Release: Der Maintainer merged den Release-Pull-Request, oder er merged sich selbst, sobald seine Prüfungen bestehen, wenn er nur Updates enthält. Der Release-Workflow signiert seinen Tag mit gitsign, veröffentlicht das Release mit seinen SBOMs und seiner signierten Herkunft und prüft es so, wie es seine Nutzer können.
- Der Rollout-Workflow startet den Blueprint-Bot jedes Repositorys der Release-App gleich nach dem Release, und der wöchentliche Lauf der Bots bleibt als Sicherheitsnetz, damit ein Fix jedes Repository in Minuten erreicht (Entscheidungen 0052 und 0010, englisch).
- Der Blueprint-Bot jedes Repositorys prüft das Release, bevor er etwas ändert: Das Release muss unveränderlich sein, sein Tag muss auf einen Commit von
maindes Blueprints zeigen, und der Release-Workflow des Blueprints muss den Tag signiert haben (Entscheidung 0020, englisch). Dann führt ercopier updatedarauf aus und hält einen Pull Request auf dem Branchblueprint/update, als Release-App, damit die Prüfungen des Repositorys laufen. - Die Prüfungen des Repositorys testen das Update wie jeden Pull Request. Ohne Konflikte merged sich der Pull Request selbst, sobald jede Prüfung besteht; mit Konflikten oder mit
BLUEPRINT_AUTOMERGEaufoffwartet er auf den Maintainer, wie die Fehlerbehebung zeigt. - Das Dashboard zeigt das Release des Blueprints, auf dem jedes Repository steht, und den Update-Pull-Request in der Farbe seiner Prüfungen, unter dennis-otto.github.io/repo-blueprint/dashboard.