Skip to content

Release-Kette: Packaging-Skript und Workflow - #4

Merged
GodModeAI2025 merged 8 commits into
mainfrom
release/welle-4
Sep 4, 2026
Merged

GodModeAI2025 merged 8 commits into
mainfrom
release/welle-4

Conversation

@GodModeAI2025

Copy link
Copy Markdown
Owner

Release-Kette fuer das erste Release

Das Konto hat ueber 56 Repos hinweg kein einziges Release. Dieser Branch legt die Kette, die daraus eines macht: ein Skript, das das Artefakt baut, ein Workflow, der es an ein Tag haengt, eine Versionsquelle, eine Doku, die zum Artefakt passt, und ein CI-Schritt, der das alles bei jedem Push nachprueft. Getaggt und veroeffentlicht wird nichts, das macht der Owner.

Was das Artefakt ist

Nicht die ZIP, die nightshift/scripts/build_zip.py und 24x7/scripts/build_zip.py erzeugen. Die bauen ein Setup fuer ein konkretes Projekt eines Nutzers. Das Release liefert den Skill selbst aus, also das, was jemand nach ~/.claude/skills/ legt.

Zwei Artefakte, nightshift.skill und 24x7.skill, je ein ZIP mit SKILL.md, scripts/build_zip.py, der Lizenz und der Version. Zwei und nicht eins, weil die Skills einzeln installiert werden, die Landingpage zwei getrennte Quickstarts hat und es vier getrennte Guides gibt.

Die Namen sind nicht frei gewaehlt. main nennt in der README und auf der Landingpage schon heute releases/latest/download/nightshift.skill und releases/latest/download/24x7.skill und den Befehl unzip nightshift.skill -d ~/.claude/skills/. Diese Links liefern 404. Mit dem ersten Tag treffen sie das Artefakt, ohne dass dieser PR gemergt sein muss.

Die sechs Commits

  1. Packaging-Skript (scripts/build_release.py). Laeuft lokal, ohne Netz, ohne git, ohne GitHub, nur Standardbibliothek, Python 3.9. Bewusst ein Skript und keine Shell-Logik im Workflow: was im Workflow steht, laesst sich erst nach dem Tag pruefen, ein Skript jederzeit. Die Dateiliste ist eine Allowlist, kein Filter, damit gar nichts hineingeraten kann, was nicht namentlich dasteht. Zwei Laeufe ergeben byteweise dasselbe Archiv (fester Zeitstempel, feste Rechte, create_system=3, sortierte Eintraege).
  2. Release-Workflow (.github/workflows/release.yml). push: tags: v*, permissions: contents: write, ruft das Skript auf und haengt das Ergebnis mit softprops/action-gh-release@v2 an. Keine Packaging-Logik im Workflow. Vorher ein Vergleich von Tag und VERSION, der abbricht, wenn beides auseinanderlaeuft. fail_on_unmatched_files: true, damit ein fehlendes Artefakt den Lauf scheitern laesst statt ein leeres Release zu veroeffentlichen.
  3. Versionsquelle. VERSION im Wurzelverzeichnis, dazu ein CHANGELOG.md. Das Skript liest sie, der Release-Workflow prueft das Tag dagegen, die CI prueft CHANGELOG und Fuss der Landingpage dagegen. 1.0.0, weil die Landingpage vor Welle 2 oeffentlich v1.0 behauptet hat und die Reparaturen aus Welle 2 und die CI aus Welle 3 diese Behauptung inzwischen decken. Eine Nummer darunter waere eine Aussage ueber den Reifegrad, keine ueber den Stand.
  4. Doku. Welle 2 hatte die Download-URLs entfernt, weil sie 404 lieferten. Jetzt stehen sie wieder da, mit genau den Namen, die das Skript baut, in README, den vier Guides und der Landingpage. Der Klon-Weg und der Rohdatei-Download aus main bleiben als Rueckfall stehen, samt Hinweis, woran man erkennt, dass noch kein Tag existiert. Solange nicht getaggt ist, ist damit keine Zeile falsch.
  5. CI-Pruefschritt (tests/test_paket.py). Baut bei jedem Push dieselben Archive, die der Release-Workflow spaeter anhaengt, und schaut hinein: existieren, nicht leer, genau die erwarteten Dateien, kein .git, kein .github, kein index.html, keine .pyc. Dazu drei Pruefungen, die es vorher nicht gab: zwei Laeufe muessen byteweise dasselbe ergeben, jeder Eintrag muss den festen Zeitstempel tragen, und jede in README, Guides oder Landingpage dokumentierte releases-URL muss auf einen Dateinamen zeigen, den das Skript wirklich baut. Damit faellt ein kaputtes Paket vor dem Tag auf, nicht danach.
  6. Korrektur im CHANGELOG. Ein Eintrag nannte Python 3.10 und beide Generatoren. Nachgesehen in c7d7e78: betroffen war nur der Nightshift-Generator, Ursache war ein Backslash im Ausdruck eines f-Strings, den erst 3.12 erlaubt.

Nachgefahren

Alle vier Schritte aus ci.yml laufen lokal unter Python 3.9.6, derselben Version wie auf dem Runner: py_compile ok, 7 Generator-Tests ok, 4 Hook-Tests ok, 11 Paket-Tests ok. Beide Workflow-Dateien parsen. Die Tag-Wache lokal mit v1.0.0 (exit 0), v1.0 und v2.0.0 (beide exit 1) durchgespielt.

Drei Gegenproben in einer Wegwerfkopie, damit die neue Pruefung nicht nur gruen aussieht: ein falscher Dateiname in der README, ein eingeschmuggeltes index.html im Artefakt und eine auseinanderlaufende Version faellt jeweils mit einer benannten Fehlermeldung durch.

index.html ist nur inhaltlich geaendert, nicht verschoben.

Was der Owner danach tun muss

Nach dem Merge das Tag setzen, genau v1.0.0:

git tag v1.0.0
git push origin v1.0.0

Der Workflow baut die Artefakte und haengt sie an. Ein Release ueber die Oberflaeche mit demselben Tag geht ebenso, die Dateien kommen in beiden Faellen dazu. v1.0 lehnt die Wache ab.

Danach zur Kontrolle:

curl -fLO https://github.com/GodModeAI2025/NightShift/releases/latest/download/nightshift.skill
curl -fLO https://github.com/GodModeAI2025/NightShift/releases/latest/download/24x7.skill

Wenn der Tag nicht heute landet: das Datum im CHANGELOG-Abschnitt ## [1.0.0] - 2026-09-04 anpassen.

🤖 Generated with Claude Code

https://claude.ai/code/session_01BL7UoPomBp2Luhg89R6fYk


Gestapelt. Dieser PR sitzt auf ci/welle-3. GitHub haengt ihn automatisch auf main um, sobald der darunterliegende PR gemergt ist. Vorher zeigt der Diff nur die Welle-3-Aenderungen, das ist so gewollt.

Teil von Welle 4 des Haerteplans: Release und Packaging. Jede Aenderung wurde von einem zweiten Durchgang abgenommen, der das Artefakt selbst gebaut, entpackt und den Installationsweg durchgegangen ist.

GodModeAI2025 and others added 8 commits September 4, 2026 16:46
Das Release soll den Skill selbst ausliefern, nicht das Setup, das
nightshift/scripts/build_zip.py und 24x7/scripts/build_zip.py fuer ein
konkretes Projekt erzeugen. scripts/build_release.py packt deshalb je
Skill ein Archiv mit SKILL.md, scripts/build_zip.py, der Lizenz und der
Version. Zwei Artefakte, weil ein Nutzer die Skills einzeln unter
~/.claude/skills/ ablegt und README und Landingpage genau so zwei
Dateien nennen.

Die Namen nightshift.skill und 24x7.skill sind die, die die README seit
jeher unter releases/latest/download nennt. Bisher liefern die URLs 404,
mit dem ersten Tag treffen sie das Artefakt.

Das Skript laeuft ohne Netz und ohne GitHub, damit dasselbe lokal und in
der CI passiert. Es liegt bewusst nicht als Shell-Logik im Workflow: was
im Workflow steht, laesst sich erst nach dem Tag pruefen, ein Skript
jederzeit.

Zwei Laeufe ergeben byteweise dasselbe Archiv. Die Dateiliste ist eine
Allowlist, jeder Eintrag bekommt festen Zeitstempel, feste Rechte und
create_system 3. Damit kann weder ein __pycache__ noch die Uhrzeit des
Laufs ins Ergebnis geraten.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BL7UoPomBp2Luhg89R6fYk
Ein Push auf ein Tag v* baut die Artefakte und haengt sie mit
softprops/action-gh-release@v2 an das Release. permissions: contents:
write, mehr braucht der Job nicht.

Die Packaging-Logik steht im Skript, der Workflow ruft es nur auf.
Genau dieses Skript laeuft auch in der CI und lokal, der Release-Lauf
macht also nichts, was vorher nicht schon jemand gesehen hat.

Vor dem Bauen vergleicht der Job das Tag mit VERSION und bricht ab, wenn
beides auseinanderlaeuft. Das ist die einzige Pruefung, die vor dem Tag
niemand machen kann.

fail_on_unmatched_files laesst den Lauf scheitern, statt ein Release
ohne Anhang zu veroeffentlichen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BL7UoPomBp2Luhg89R6fYk
Die Version stand bisher nirgends ausser als v1.0 im Fuss der
Landingpage. Jetzt ist VERSION die Quelle: das Packaging-Skript liest
sie, der Release-Workflow prueft das Tag dagegen, und die CI prueft,
dass CHANGELOG und Landingpage dieselbe Zahl nennen.

1.0.0 und nicht 0.1.0, weil die Landingpage vor Welle 2 oeffentlich v1.0
behauptet hat und die Reparaturen aus Welle 2 und die CI aus Welle 3
diese Behauptung inzwischen decken. Eine Nummer darunter waere eine
Aussage ueber den Reifegrad, keine ueber den Stand.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BL7UoPomBp2Luhg89R6fYk
Welle 2 hat die Download-URLs entfernt, weil sie 404 lieferten, und den
Klon als Weg hingeschrieben. Mit dem Release-Skript stimmt der Download
wieder, also steht er wieder da, mit genau den Dateinamen, die das
Skript erzeugt: nightshift.skill und 24x7.skill.

Betroffen sind README, die vier Guides und die Landingpage. Die Guides
luden den Skill bisher als Rohdateien aus main, also den jeweils
aktuellen Stand statt eines Releases. Dieser Weg bleibt als Rueckfall
stehen, samt Hinweis, woran man erkennt, dass noch kein Tag gesetzt ist.

Der Fuss der Landingpage nennt wieder eine Version, diesmal die aus
VERSION. Der Roadmap-Punkt zu den Release-Assets faellt weg, er ist
erledigt.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BL7UoPomBp2Luhg89R6fYk
Ein kaputtes Paket faellt sonst erst nach dem Tag auf, und dann steht es
schon im Release. tests/test_paket.py baut deshalb bei jedem Push
dieselben Archive, die der Release-Workflow spaeter anhaengt, und schaut
hinein: existieren, nicht leer, genau die erwarteten Dateien, kein .git,
kein .github, kein index.html, keine .pyc, keine Pfade mit fuehrendem
Schraegstrich oder Punktpunkt.

Dazu drei Pruefungen, die vorher niemand hatte: zwei Laeufe muessen
byteweise dasselbe ergeben, jeder Eintrag muss den festen Zeitstempel
tragen, und jede in README, Guides oder Landingpage dokumentierte
releases-URL muss auf einen Dateinamen zeigen, den das Skript wirklich
baut. Umgekehrt muss jedes Artefakt irgendwo verlinkt sein.

Ausserdem gleicht der Test VERSION gegen den CHANGELOG-Abschnitt und
gegen den Fuss der Landingpage ab, damit die Version nicht doch wieder
an drei Stellen gepflegt wird.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BL7UoPomBp2Luhg89R6fYk
Der Eintrag nannte Python 3.10 und beide Generatoren. Nachgesehen in
c7d7e78: betroffen war nur der Nightshift-Generator, und die Ursache war
ein Backslash im Ausdruck eines f-Strings, den erst 3.12 erlaubt.

Der 24x7-Punkt nennt jetzt, was tatsaechlich passierte: der ZIP-Bau auf
Modulebene schrieb auf einen festen Pfad und liess jeden Import mit
FileNotFoundError scheitern.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BL7UoPomBp2Luhg89R6fYk
Der Kopierschritt nannte /mnt/skills/user/<name>/scripts/build_zip.py. Den
Pfad gibt es auf claude.ai, nicht in einer Installation unter
~/.claude/skills/, und genau dorthin fuehren README und Landingpage. Wer
die Zeile woertlich ausfuehrte, bekam "No such file or directory" und
Exit 1. Beide Dateien suchen den Generator jetzt erst neben der
installierten SKILL.md und fallen auf das Mount zurueck, damit der Block
auf beiden Zielen laeuft, fuer die die Landingpage den Skill verkauft.

Dazu fehlte in der Variablenliste die Zielvariable. Ohne NIGHTSHIFT_OUT
beziehungsweise CLAUDE_24X7_OUT schreibt der Generator nach
/mnt/user-data/outputs/ und bricht ausserhalb von claude.ai mit
"Read-only file system: '/mnt'" ab. Beim Nightshift-Generator faellt das
besonders spaet auf, der Abbruch kommt erst nach der vollen Meldung
"Validierung: 15/15 bestanden" und sieht bis dahin nach Erfolg aus. Beide
Variablen stehen jetzt in der Liste, mit einem lokalen Beispielwert.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BL7UoPomBp2Luhg89R6fYk
@GodModeAI2025
GodModeAI2025 changed the base branch from ci/welle-3 to main September 4, 2026 19:08
@GodModeAI2025 GodModeAI2025 reopened this Sep 4, 2026
@GodModeAI2025
GodModeAI2025 merged commit b72f61a into main Sep 4, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant