Release-Kette: Packaging-Skript und Workflow - #4
Merged
Merged
Conversation
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.pyund24x7/scripts/build_zip.pyerzeugen. 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.skillund24x7.skill, je ein ZIP mitSKILL.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.
mainnennt in der README und auf der Landingpage schon heutereleases/latest/download/nightshift.skillundreleases/latest/download/24x7.skillund den Befehlunzip 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
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)..github/workflows/release.yml).push: tags: v*,permissions: contents: write, ruft das Skript auf und haengt das Ergebnis mitsoftprops/action-gh-release@v2an. Keine Packaging-Logik im Workflow. Vorher ein Vergleich von Tag undVERSION, der abbricht, wenn beides auseinanderlaeuft.fail_on_unmatched_files: true, damit ein fehlendes Artefakt den Lauf scheitern laesst statt ein leeres Release zu veroeffentlichen.VERSIONim Wurzelverzeichnis, dazu einCHANGELOG.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.mainbleiben als Rueckfall stehen, samt Hinweis, woran man erkennt, dass noch kein Tag existiert. Solange nicht getaggt ist, ist damit keine Zeile falsch.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, keinindex.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 dokumentiertereleases-URL muss auf einen Dateinamen zeigen, den das Skript wirklich baut. Damit faellt ein kaputtes Paket vor dem Tag auf, nicht danach.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.ymllaufen 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 mitv1.0.0(exit 0),v1.0undv2.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.htmlim Artefakt und eine auseinanderlaufende Version faellt jeweils mit einer benannten Fehlermeldung durch.index.htmlist nur inhaltlich geaendert, nicht verschoben.Was der Owner danach tun muss
Nach dem Merge das Tag setzen, genau
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.0lehnt die Wache ab.Danach zur Kontrolle:
Wenn der Tag nicht heute landet: das Datum im CHANGELOG-Abschnitt
## [1.0.0] - 2026-09-04anpassen.🤖 Generated with Claude Code
https://claude.ai/code/session_01BL7UoPomBp2Luhg89R6fYk
Gestapelt. Dieser PR sitzt auf
ci/welle-3. GitHub haengt ihn automatisch aufmainum, 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.