deploy: „fertig" wird erst beim Deploy „in Produktion" (D30)
Der mitgelieferte Werkbaum-Plan behauptete [^] für Funktionen, die nur auf der
automatisch deployten Pages-Instanz lagen, nicht auf werkbaum.javagil.de
(manueller Deploy, D16). Ausgerechnet das Dokument, das den Stand beschreiben
soll, war ungenau — und „Was ist neu?" (D28) meldete Dinge als live, die es
dort nicht waren.
Die Unterscheidung gibt es längst: SPEC §4 trennt [x] fertig von [^] in
Produktion. Der Plan hat sie für sich selbst nie benutzt. Konvention ab jetzt:
beim Mergen [x], der Deploy befördert — nur er weiß, wann die Aussage wahr wird.
- scripts/promote-shipped.sh schreibt Statusboxen am Zeilenanfang von [x] auf
[^] und hält das als eigenen Commit fest (-n zeigt nur, -y ohne Rückfrage).
Bricht ab, wenn die Plandatei uncommittete Änderungen hat; committet nur
diesen einen Pfad; pusht nicht.
- deploy-prod.sh ruft es als Schritt 0 auf (--no-promote schaltet es ab) und
warnt, wenn HEAD noch nicht auf origin liegt — der Footer-Versionslink zeigt
sonst auf einen Commit, den GitHub nicht kennt.
Warum ein Commit und kein Rewrite beim Bauen: Ein Rewrite macht GENAU EINE
Installation ehrlich; Pages untertriebe dauerhaft und die Neu-Anzeige wäre dort
für immer stumm. Der Commit wird von beiden Pipelines gesehen (Pages beim Push,
prod beim rsync), das Artefakt bleibt inhaltsgleich mit dem Repo — die
vorhandenen sed-Regeln (D16) fassen nur Pfade und Version an, Infrastruktur,
kein Rewrite dessen, was das Dokument aussagt. Außerdem Präzedenzfall D16:
VERSION per bewusstem Bump-Commit, „vollständig aus dem Repo reproduzierbar".
Einmalige Nachholung, exakt statt geschätzt: Der Footer der stabilen Instanz
verlinkt den deployten Commit (4061362); alles danach ist dort nicht drin. Es
sind GENAU ZWEI Knoten — „Optional nodes" (D29) und „Show what is new since
your last visit" (D28) —, nicht das Dutzend, das ich vorher grob geschätzt
hatte. Beide stehen jetzt auf [x] und leuchten beim nächsten Prod-Deploy als
neu auf. Eine Demotion [^]→[x] löst kein Falschleuchten aus: freshProdSet
meldet nur Knoten, die JETZT [^] sind (test-abgedeckt).
Umfang: nur example-werkbaum.werkbaum. Die übrigen Beispieldateien sind
erfunden und sagen nichts über ein Deployment aus.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
56c18cb8cb
commit
6836352e84
@@ -27,3 +27,8 @@ Integrations-Backend.
|
|||||||
- Keine neuen Laufzeit-Abhängigkeiten ohne Rückfrage (gilt in beiden Teilen).
|
- Keine neuen Laufzeit-Abhängigkeiten ohne Rückfrage (gilt in beiden Teilen).
|
||||||
- Der Notationstext ist das führende Datenformat; kein Teil erfindet ein
|
- Der Notationstext ist das führende Datenformat; kein Teil erfindet ein
|
||||||
eigenes Speicherformat für die Struktur.
|
eigenes Speicherformat für die Struktur.
|
||||||
|
- Im mitgelieferten Plan `docs/examples/example-werkbaum.werkbaum` bekommt eine
|
||||||
|
fertige Funktion beim Mergen **`[x]`**, nicht `[^]`. Auf „in Produktion"
|
||||||
|
befördert erst der Deploy der stabilen Instanz
|
||||||
|
(`scripts/promote-shipped.sh`, von `deploy-prod.sh` aufgerufen) — nur er macht
|
||||||
|
die Aussage wahr. Siehe D30; SPEC §4 trennt beide Zustände ohnehin.
|
||||||
|
|||||||
@@ -197,6 +197,23 @@ repository, while the **version number** links to that exact commit
|
|||||||
"GitHub Actions". The repo must be **public** for this (GitHub Pages via Actions
|
"GitHub Actions". The repo must be **public** for this (GitHub Pages via Actions
|
||||||
is only available for private repos on a paid plan).
|
is only available for private repos on a paid plan).
|
||||||
|
|
||||||
|
### Stable instance
|
||||||
|
|
||||||
|
`scripts/deploy-prod.sh` mirrors a badge-free production build to a server over
|
||||||
|
SSH (target in `.env`, template `.env.example`). Unlike Pages this is a
|
||||||
|
**deliberate** step, so it is also the moment a feature actually goes live.
|
||||||
|
|
||||||
|
The script therefore starts by running `scripts/promote-shipped.sh`, which turns
|
||||||
|
`[x]` (done) into `[^]` (in production) in `docs/examples/example-werkbaum.werkbaum`
|
||||||
|
— the shipped plan describing Werkbaum itself — and records that as its own
|
||||||
|
commit. The convention is: mark a finished feature `[x]` when it is merged and
|
||||||
|
let the deploy promote it. That keeps the plan honest on both instances and
|
||||||
|
keeps the "what's new" highlighting meaningful. Skip it with `--no-promote`; see
|
||||||
|
[docs/DECISIONS.md](docs/DECISIONS.md) D30.
|
||||||
|
|
||||||
|
The commit is **not** pushed automatically — run `git push` afterwards, or the
|
||||||
|
footer version link points at a commit GitHub does not know yet.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT — see [LICENSE](LICENSE). © 2026 Michael Hönnig. The bundled IBM Plex fonts
|
MIT — see [LICENSE](LICENSE). © 2026 Michael Hönnig. The bundled IBM Plex fonts
|
||||||
|
|||||||
@@ -904,3 +904,62 @@ wie am Bildschirm.
|
|||||||
Geprüft wurde im Browser — auch der Moduswechsel hin und zurück, mehrfach: Die
|
Geprüft wurde im Browser — auch der Moduswechsel hin und zurück, mehrfach: Die
|
||||||
Gruppe entsteht und löst sich rückstandsfrei auf, Knotenzahl und Dokumentordnung
|
Gruppe entsteht und löst sich rückstandsfrei auf, Knotenzahl und Dokumentordnung
|
||||||
bleiben in allen drei Modi gleich.
|
bleiben in allen drei Modi gleich.
|
||||||
|
|
||||||
|
## D30 — `[x]` → `[^]` per Beförderungs-Commit vor dem Deploy
|
||||||
|
Der mitgelieferte Werkbaum-Plan (D27) behauptete `[^]` („in Produktion") für
|
||||||
|
Funktionen, die nur auf der automatisch deployten Pages-Instanz lagen, nicht auf
|
||||||
|
der stabilen Installation `werkbaum.javagil.de` (manueller Deploy, D16). Damit
|
||||||
|
war ausgerechnet das Dokument ungenau, das den Stand beschreiben soll — und die
|
||||||
|
„Was ist neu?"-Anzeige (D28) meldete Dinge als live, die es dort nicht waren.
|
||||||
|
|
||||||
|
**Die Unterscheidung gibt es längst.** SPEC §4 trennt `[x]` fertig
|
||||||
|
(abgeschlossen) von `[^]` in Produktion (deployed/live). Der Plan hat diese
|
||||||
|
Trennung ausgerechnet für sich selbst nie benutzt und sprang direkt auf `[^]`.
|
||||||
|
Die Konvention lautet daher ab jetzt: **beim Mergen `[x]`**, und der Deploy
|
||||||
|
befördert. Nur der Deploy weiß, wann die Aussage wahr wird.
|
||||||
|
|
||||||
|
**Umgesetzt als Commit, nicht als Rewrite beim Bauen.** `scripts/promote-shipped.sh`
|
||||||
|
schreibt die Statusboxen am Zeilenanfang von `[x]` auf `[^]` und hält das in
|
||||||
|
einem eigenen Commit fest; `scripts/deploy-prod.sh` ruft es als Schritt 0 auf
|
||||||
|
(abschaltbar mit `--no-promote`). Gründe:
|
||||||
|
|
||||||
|
- Ein Rewrite beim Bauen macht **genau eine** Installation ehrlich. Pages
|
||||||
|
untertriebe dauerhaft, und die Neu-Anzeige wäre dort **für immer stumm** —
|
||||||
|
das Feature ließe sich nur noch künstlich prüfen. Der Commit dagegen wird von
|
||||||
|
**beiden** Pipelines gesehen: Pages baut ihn beim Push, prod beim nächsten
|
||||||
|
rsync.
|
||||||
|
- Das Deployment-Artefakt bleibt **inhaltsgleich mit dem Repo**. Die
|
||||||
|
vorhandenen `sed`-Regeln (D16) fassen nur Pfade und die Versionsnummer an —
|
||||||
|
Infrastruktur. Ein Status-Rewrite wäre der erste Schritt, der ändert, was das
|
||||||
|
Dokument *aussagt*; die per `?sourceUrl=` geladene Rohdatei wäre dann eine
|
||||||
|
dritte, wieder abweichende Fassung.
|
||||||
|
- Es folgt dem Präzedenzfall aus D16: Die Version wird per **bewusstem
|
||||||
|
Bump-Commit** gepflegt, „vollständig aus dem Repo reproduzierbar". Ein Deploy
|
||||||
|
ist ein bewusster Akt; ihn in der Historie festzuhalten passt dazu — und der
|
||||||
|
Plan bekommt nebenbei eine Chronik, wann was live ging.
|
||||||
|
|
||||||
|
**Verworfen:** Rewrite nur im Prod-Deploy (siehe oben) und Rewrite in **beiden**
|
||||||
|
Pipelines. Letzteres wäre testbar, aber `[^]` hieße auf Pages faktisch nur
|
||||||
|
„gemerged", und das kollidiert damit, dass D16 die Pages-Instanz bewusst als
|
||||||
|
nicht-produktiven Build markiert (🚧-Badge).
|
||||||
|
|
||||||
|
**Bekannter Preis:** Zwischen Beförderungs-Commit und rsync sagt Pages `[^]` für
|
||||||
|
etwas, das auf prod noch nicht liegt. Das Fenster ist kurz und liegt in der Hand
|
||||||
|
dessen, der deployt — gegenüber einer *dauerhaften* Ungenauigkeit bei der
|
||||||
|
Build-Rewrite-Variante der bessere Tausch.
|
||||||
|
|
||||||
|
**Einmalige Nachholung.** Welche Knoten zu früh `[^]` trugen, ließ sich exakt
|
||||||
|
bestimmen statt zu schätzen: Der Footer der stabilen Instanz verlinkt den
|
||||||
|
deployten Commit (`4061362`), und alles danach ist dort nicht enthalten. Es
|
||||||
|
waren **genau zwei** Knoten — „Optional nodes" (D29) und „Show what is new since
|
||||||
|
your last visit" (D28) —, nicht das Dutzend, das vorher grob geschätzt worden
|
||||||
|
war. Beide stehen jetzt auf `[x]` und leuchten beim nächsten Prod-Deploy als neu
|
||||||
|
auf, was genau der Wahrheit entspricht.
|
||||||
|
|
||||||
|
**Umfang:** Nur `docs/examples/example-werkbaum.werkbaum`. Die übrigen
|
||||||
|
Beispieldateien sind erfunden und sagen nichts über ein Deployment aus.
|
||||||
|
|
||||||
|
**Nicht gepusht.** Das Skript committet, pusht aber nicht — Veröffentlichen
|
||||||
|
bleibt eine bewusste Handlung. `deploy-prod.sh` warnt stattdessen, wenn HEAD
|
||||||
|
noch nicht auf `origin` liegt: der Footer-Versionslink zeigt sonst auf einen
|
||||||
|
Commit, den GitHub nicht kennt.
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
- [^] T-shirt size and the "decompose from M" rule (S)
|
- [^] T-shirt size and the "decompose from M" rule (S)
|
||||||
- [^] People tags, bare URLs, %% comments (XS)
|
- [^] People tags, bare URLs, %% comments (XS)
|
||||||
- [^] And/or decomposition (S)
|
- [^] And/or decomposition (S)
|
||||||
- [^] Optional nodes — neither required nor an alternative (S)
|
- [x] Optional nodes — neither required nor an alternative (S)
|
||||||
- [-] A separate storage format for the structure (L) %% the text is the format
|
- [-] A separate storage format for the structure (L) %% the text is the format
|
||||||
- [ ] Ticket references #123 (S)
|
- [ ] Ticket references #123 (S)
|
||||||
- [?] Benefit per node, not only cost (M)
|
- [?] Benefit per node, not only cost (M)
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
- [^] Load a document from ?sourceUrl= (S)
|
- [^] Load a document from ?sourceUrl= (S)
|
||||||
- [^] Jump between diagram and text (S)
|
- [^] Jump between diagram and text (S)
|
||||||
- [ ] Open and save .werkbaum files (S)
|
- [ ] Open and save .werkbaum files (S)
|
||||||
+ [^] Show what is new since your last visit (S)
|
+ [x] Show what is new since your last visit (S)
|
||||||
+ [?] A pastel colour per person (S)
|
+ [?] A pastel colour per person (S)
|
||||||
- [?] Dates and milestones (M)
|
- [?] Dates and milestones (M)
|
||||||
| [?] An attribute in the line (S)
|
| [?] An attribute in the line (S)
|
||||||
|
|||||||
+32
-8
@@ -2,16 +2,21 @@
|
|||||||
#
|
#
|
||||||
# Werkbaum — Produktions-Deploy via rsync/SSH.
|
# Werkbaum — Produktions-Deploy via rsync/SSH.
|
||||||
#
|
#
|
||||||
# Baut das badge-freie Prod-Bundle (`npm run build:prod`, ohne den
|
# Befördert zuerst die fertigen Knoten des mitgelieferten Werkbaum-Plans auf
|
||||||
# Entwicklungs-Hinweis hinter dem Titel), stellt es lokal genauso zusammen wie
|
# „in Produktion" (scripts/promote-shipped.sh, D30 — genau dieser Deploy macht
|
||||||
# der GitHub-Pages-Workflow (LICENSE-Link geradeziehen + Footer-Version/Commit)
|
# die Aussage `[^]` wahr), baut dann das badge-freie Prod-Bundle
|
||||||
# und spiegelt es per rsync in ein Zielverzeichnis. `--delete`: am Ziel bleibt
|
# (`npm run build:prod`, ohne den Entwicklungs-Hinweis hinter dem Titel), stellt
|
||||||
# nichts Altes stehen.
|
# es lokal genauso zusammen wie der GitHub-Pages-Workflow (LICENSE-Link
|
||||||
|
# geradeziehen + Footer-Version/Commit) und spiegelt es per rsync in ein
|
||||||
|
# Zielverzeichnis. `--delete`: am Ziel bleibt nichts Altes stehen.
|
||||||
#
|
#
|
||||||
# Verwendung:
|
# Verwendung:
|
||||||
# scripts/deploy-prod.sh [-y] [rsync-ziel]
|
# scripts/deploy-prod.sh [-y] [--no-promote] [rsync-ziel]
|
||||||
#
|
#
|
||||||
# -y ohne Rückfrage spiegeln (sonst erst Vorschau via --dry-run + Nachfrage)
|
# -y ohne Rückfrage befördern und spiegeln (sonst erst Vorschau
|
||||||
|
# via --dry-run + Nachfrage)
|
||||||
|
# --no-promote Beförderungsschritt überspringen (z. B. Wiederholung eines
|
||||||
|
# Deploys, der schon befördert hat)
|
||||||
#
|
#
|
||||||
# Das Ziel ist entweder das Argument ODER — wenn keins angegeben ist — die
|
# Das Ziel ist entweder das Argument ODER — wenn keins angegeben ist — die
|
||||||
# Variable DEPLOY_TARGET aus der git-ignorierten Datei .env im Repo-Wurzelordner
|
# Variable DEPLOY_TARGET aus der git-ignorierten Datei .env im Repo-Wurzelordner
|
||||||
@@ -26,16 +31,18 @@
|
|||||||
# ACHTUNG: Das Zielverzeichnis wird als exklusiv für Werkbaum angenommen —
|
# ACHTUNG: Das Zielverzeichnis wird als exklusiv für Werkbaum angenommen —
|
||||||
# `--delete` entfernt dort ALLES, was nicht zum Bundle gehört.
|
# `--delete` entfernt dort ALLES, was nicht zum Bundle gehört.
|
||||||
#
|
#
|
||||||
# Siehe README (Abschnitt Deployment) und docs/DECISIONS.md D16/D19.
|
# Siehe README (Abschnitt Deployment) und docs/DECISIONS.md D16/D19/D30.
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
# ---- Argumente ----
|
# ---- Argumente ----
|
||||||
YES=0
|
YES=0
|
||||||
|
PROMOTE=1
|
||||||
TARGET=""
|
TARGET=""
|
||||||
for arg in "$@"; do
|
for arg in "$@"; do
|
||||||
case "$arg" in
|
case "$arg" in
|
||||||
-y|--yes) YES=1 ;;
|
-y|--yes) YES=1 ;;
|
||||||
|
--no-promote) PROMOTE=0 ;;
|
||||||
-h|--help)
|
-h|--help)
|
||||||
awk 'NR>2 { if ($0 ~ /^#/) { sub(/^# ?/, ""); print } else exit }' "$0"
|
awk 'NR>2 { if ($0 ~ /^#/) { sub(/^# ?/, ""); print } else exit }' "$0"
|
||||||
exit 0 ;;
|
exit 0 ;;
|
||||||
@@ -72,6 +79,17 @@ if [ -z "$TARGET" ]; then
|
|||||||
exit 2
|
exit 2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ---- 0) Fertiges auf „in Produktion" befördern (D30) ----
|
||||||
|
# MUSS vor dem Build laufen: der Plan ist Build-Eingabe (?raw-Import, D27), und
|
||||||
|
# der Commit soll derjenige sein, auf den der Footer-Versionslink zeigt.
|
||||||
|
if [ "$PROMOTE" -eq 1 ]; then
|
||||||
|
PROMOTE_ARGS=()
|
||||||
|
[ "$YES" -eq 1 ] && PROMOTE_ARGS+=(-y)
|
||||||
|
"$ROOT/scripts/promote-shipped.sh" "${PROMOTE_ARGS[@]+"${PROMOTE_ARGS[@]}"}"
|
||||||
|
else
|
||||||
|
echo "==> Beförderung übersprungen (--no-promote)"
|
||||||
|
fi
|
||||||
|
|
||||||
# ---- 1) Prod-Build (ohne Build-Hinweis) ----
|
# ---- 1) Prod-Build (ohne Build-Hinweis) ----
|
||||||
if [ ! -d frontend/node_modules ]; then
|
if [ ! -d frontend/node_modules ]; then
|
||||||
echo "==> node_modules fehlt — npm ci"
|
echo "==> node_modules fehlt — npm ci"
|
||||||
@@ -100,6 +118,12 @@ if git -C "$ROOT" rev-parse HEAD >/dev/null 2>&1; then
|
|||||||
BUILD_VERSION="${MAJORMINOR}.${MICRO}"
|
BUILD_VERSION="${MAJORMINOR}.${MICRO}"
|
||||||
COMMIT_URL="https://github.com/mhoennig/werkbaum/commit/$(git -C "$ROOT" rev-parse HEAD)"
|
COMMIT_URL="https://github.com/mhoennig/werkbaum/commit/$(git -C "$ROOT" rev-parse HEAD)"
|
||||||
echo "==> Footer-Version ${BUILD_VERSION} -> ${COMMIT_URL}"
|
echo "==> Footer-Version ${BUILD_VERSION} -> ${COMMIT_URL}"
|
||||||
|
# Der Link zeigt ins Leere, solange der Commit nicht auf GitHub liegt — nach
|
||||||
|
# einer Beförderung (Schritt 0) ist das der Normalfall.
|
||||||
|
if [ -z "$(git -C "$ROOT" branch -r --contains HEAD 2>/dev/null)" ]; then
|
||||||
|
echo " ! HEAD liegt noch nicht auf origin — der Footer-Versionslink läuft" >&2
|
||||||
|
echo " ins Leere, bis 'git push' nachgeholt ist." >&2
|
||||||
|
fi
|
||||||
SED_ARGS+=(-e "s#\(<a class=\"ver\" href=\"\)[^\"]*#\1${COMMIT_URL}#")
|
SED_ARGS+=(-e "s#\(<a class=\"ver\" href=\"\)[^\"]*#\1${COMMIT_URL}#")
|
||||||
SED_ARGS+=(-e "s#\(<a class=\"ver\"[^>]*>\)[0-9.]\+</a>#\1${BUILD_VERSION}</a>#")
|
SED_ARGS+=(-e "s#\(<a class=\"ver\"[^>]*>\)[0-9.]\+</a>#\1${BUILD_VERSION}</a>#")
|
||||||
else
|
else
|
||||||
|
|||||||
Executable
+99
@@ -0,0 +1,99 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Werkbaum — „fertig" auf „in Produktion" befördern.
|
||||||
|
#
|
||||||
|
# Der mitgelieferte Plan docs/examples/example-werkbaum.werkbaum beschreibt
|
||||||
|
# Werkbaum selbst. SPEC §4 unterscheidet `[x]` fertig (abgeschlossen) von `[^]`
|
||||||
|
# in Produktion (deployed/live) — und die zweite Aussage kann erst der Deploy
|
||||||
|
# wahr machen. Konvention deshalb: beim Mergen `[x]`, unmittelbar VOR dem
|
||||||
|
# Deploy dieser Lauf, der daraus `[^]` macht und das als Commit festhält.
|
||||||
|
#
|
||||||
|
# Warum ein Commit und kein Rewrite beim Bauen: siehe docs/DECISIONS.md D30.
|
||||||
|
# Kurz — der Commit wird von BEIDEN Pipelines gesehen (GitHub Pages baut ihn
|
||||||
|
# beim Push, prod beim nächsten rsync), das Deployment-Artefakt bleibt
|
||||||
|
# inhaltsgleich mit dem Repo, und die „Was ist neu?"-Anzeige (D28) bleibt auf
|
||||||
|
# der Pages-Instanz erlebbar statt dort für immer stumm zu sein.
|
||||||
|
#
|
||||||
|
# Verwendung:
|
||||||
|
# scripts/promote-shipped.sh [-n] [-y]
|
||||||
|
#
|
||||||
|
# -n, --dry-run nur zeigen, was befördert würde
|
||||||
|
# -y, --yes ohne Rückfrage befördern und committen
|
||||||
|
#
|
||||||
|
# Ohne zu befördernde Knoten endet der Lauf mit 0 und ändert nichts.
|
||||||
|
# Gepusht wird NICHT — das bleibt eine bewusste Handlung.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DRY=0
|
||||||
|
YES=0
|
||||||
|
for arg in "$@"; do
|
||||||
|
case "$arg" in
|
||||||
|
-n|--dry-run) DRY=1 ;;
|
||||||
|
-y|--yes) YES=1 ;;
|
||||||
|
-h|--help)
|
||||||
|
awk 'NR>2 { if ($0 ~ /^#/) { sub(/^# ?/, ""); print } else exit }' "$0"
|
||||||
|
exit 0 ;;
|
||||||
|
*) echo "Unbekannte Option: $arg" >&2; exit 2 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
cd "$ROOT"
|
||||||
|
|
||||||
|
PLAN="docs/examples/example-werkbaum.werkbaum"
|
||||||
|
[ -f "$PLAN" ] || { echo "Plan nicht gefunden: $PLAN" >&2; exit 1; }
|
||||||
|
|
||||||
|
# Nur Statusboxen am Zeilenanfang (nach optionalem Zeichen -/+/|), damit ein
|
||||||
|
# „[x]" mitten im Label unangetastet bleibt. `x` auch als `X` (SPEC §4).
|
||||||
|
MATCH='^([[:space:]]*([-+|][[:space:]]*)?)\[[xX]\]'
|
||||||
|
|
||||||
|
mapfile -t HITS < <(grep -nE "$MATCH" "$PLAN" || true)
|
||||||
|
|
||||||
|
if [ "${#HITS[@]}" -eq 0 ]; then
|
||||||
|
echo "==> Nichts zu befördern — kein [x] im Plan."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "==> ${#HITS[@]} Knoten würden auf [^] befördert:"
|
||||||
|
printf ' %s\n' "${HITS[@]}"
|
||||||
|
|
||||||
|
[ "$DRY" -eq 1 ] && exit 0
|
||||||
|
|
||||||
|
# Der Commit fasst genau diese eine Datei an. Ist sie schon geändert, lässt sich
|
||||||
|
# die Beförderung nicht sauber von der Änderung trennen — dann lieber abbrechen.
|
||||||
|
if git rev-parse HEAD >/dev/null 2>&1 && [ -n "$(git status --porcelain -- "$PLAN")" ]; then
|
||||||
|
echo " ! $PLAN hat uncommittete Änderungen — erst committen, dann befördern." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$YES" -ne 1 ]; then
|
||||||
|
printf '==> Befördern und committen? [y/N] '
|
||||||
|
read -r ANS
|
||||||
|
case "$ANS" in y|Y|j|J) : ;; *) echo "Abgebrochen."; exit 1 ;; esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Labels für den Commit-Text sammeln (ohne Zeichen, Statusbox und Größe).
|
||||||
|
mapfile -t LABELS < <(printf '%s\n' "${HITS[@]}" \
|
||||||
|
| sed -E 's/^[0-9]+:[[:space:]]*([-+|][[:space:]]*)?\[[xX]\][[:space:]]*//' \
|
||||||
|
| sed -E 's/[[:space:]]*\((XS|S|M|L|XL|XXL)\)[[:space:]]*$//')
|
||||||
|
|
||||||
|
sed -i -E "s/$MATCH/\1[^]/" "$PLAN"
|
||||||
|
|
||||||
|
if ! git rev-parse HEAD >/dev/null 2>&1; then
|
||||||
|
echo "==> Kein Git-Repo — Datei geändert, nicht committet."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
{
|
||||||
|
echo "docs: Werkbaum-Plan — ${#HITS[@]} Knoten in Produktion"
|
||||||
|
echo
|
||||||
|
echo "Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4"
|
||||||
|
echo "unterscheidet [x] fertig von [^] in Produktion (D30):"
|
||||||
|
echo
|
||||||
|
printf -- '- %s\n' "${LABELS[@]}"
|
||||||
|
} | git commit -q -F - -- "$PLAN"
|
||||||
|
|
||||||
|
echo "==> Committet: $(git log --oneline -1)"
|
||||||
|
echo " Hinweis: nicht gepusht. Ohne Push zeigt der Footer-Versionslink des"
|
||||||
|
echo " Deploys auf einen Commit, den GitHub noch nicht kennt."
|
||||||
Reference in New Issue
Block a user