**Beim Überprüfen oder Rebasen eines Branches immer verifizieren**, dass der Image-Name und die Version in `docker-compose.yml` mit dem übereinstimmen, was die Build-Dateien tatsächlich erzeugen. Abweichungen sind Implementierungsfehler und müssen gekennzeichnet und korrigiert werden.
-## Skripte im Scripting-Branch
+## Verwaltungsskripte
-Alle Skripte binden `lib.sh` ein, das seinerseits `branches.sh` lädt und gemeinsame Funktionen bereitstellt.
+### Skripte im `scripting`-Branch
+
+Alle Skripte binden `lib.sh` ein, das seinerseits `branches.sh` lädt und gemeinsame Funktionen bereitstellt. Alle Skripte unterstützen `--help`.
| Skript | Zweck |
|--------|-------|
| `branches.sh` | Definiert alle Branch-Namen als Variablen und die Iterationsliste `$BRANCHES` |
-| `lib.sh` | Shared Library: bindet `branches.sh` ein, stellt `$BRANCH_NAMES`-Array (alle Branches inkl. `grundlagen/docker`) sowie `find_common_tag_suffixes()` und `reset_branches_to_remote()` bereit |
-| `push.sh` | Force-pusht alle Branches zu origin. Prüft vorab, ob umzuschreibende Remote-Stände bereits Tags im Remote haben; fehlt ein Tag, werden TIMESTAMP-Backup-Tags für alle Remote-Stände direkt im Remote angelegt. Existiert lokal ein gemeinsames Tag-Suffix für alle Branches (z.B. `--claude-5`), wird es ebenfalls gepusht, sofern noch nicht im Remote vorhanden. |
-| `reset.sh` | Ohne Argument: setzt alle Branches auf `origin/<branch>` zurück. Mit Argument: auf Tag `<branch>--<prefix>` |
-| `diff.sh` | Ohne Arg: lokaler Branch gegen `origin/<branch>`. Ein Arg: gegen `<branch>--<suffix>`. Zwei Args: `<branch>--<suffix1>` gegen `<branch>--<suffix2>` |
-| `build.sh` | Baut alle Branches (erkennt Maven/Gradle automatisch); `--vorlage`-Branches werden übersprungen. Mit `--publish`: Docker-Images veröffentlichen |
-| `copy.sh` | Kopiert Branches anhand ihres Suffix in `../training-exercises/vorlagen/`, `../training-exercises/livecoding/` oder `../training-exercises/spickzettel/` (siehe Suffix-Tabelle oben); `--livecoding--schritte`-Branches werden übersprungen. `rsync --delete` ist immer aktiv. Verzeichnisse zu nicht mehr gelisteten Branches werden automatisch bereinigt. Ohne Schalter: aktualisiert zuerst alle Branches auf Remote-Stand (erfordert Remote-Zugriff). Mit `--local`: kopiert lokale Branch-HEADs ohne Remote-Aktualisierung. Mit `--tag=<suffix>`: kopiert den jeweiligen Tag-Stand. Mit `--nexus-url=<url>` werden Gradle-Setups anschließend für einen internen Nexus gepatcht |
-| `patch-nexus.sh` | Patcht `build.gradle` (Nexus als Repository), `settings.gradle` (pluginManagement) und optional mit `--gradle-dist-url=<url>` auch `gradle-wrapper.properties`. Wird aus dem Zielverzeichnis (`../vorlagen/`) aufgerufen |
+| `lib.sh` | Shared Library mit `$BRANCH_NAMES`-Array und den Funktionen `find_common_tag_suffixes()` und `reset_branches_to_remote()` |
+| `push.sh` | Force-pusht alle Branches und gemeinsame Tags zu origin; legt bei Bedarf TIMESTAMP-Backup-Tags an |
+| `reset.sh` | Setzt alle Branches zurück — auf `origin/<branch>` oder auf einen Tag-Stand |
+| `diff.sh` | Zeigt Diffs aller Branches an — lokal gegen origin, gegen einen Tag-Stand, oder zwei Tag-Stände gegeneinander |
+| `copy.sh` | Kopiert alle Branches in die Übungsverzeichnisse (`vorlagen/`, `livecoding/`, `spickzettel/`); bereinigt veraltete Verzeichnisse automatisch |
Nach Massenoperationen immer zu `scripting` zurückkehren — Skripte führen am Ende `git checkout scripting` aus.
### Skripte im `springkafka/technik-check--vorlage`-Branch
-Dieser Branch enthält zwei zusätzliche Skripte für die Schulungs-Initialisierung:
+Diese Skripte operieren auf den **kopierten** Übungsverzeichnissen (nicht auf den Quell-Branches) und liegen daher im `technik-check`-Branch. Nach einem Aufruf von `copy.sh` stehen sie unter `../training-exercises/vorlagen/springkafka/technik-check/` bereit. Alle Skripte unterstützen `--help`.
| Skript | Zweck |
|--------|-------|
-| `init-exercises.sh` | Initialisiert die mit `copy.sh` kopierten Übungsverzeichnisse (`training-exercises/vorlagen/`, `training-exercises/livecoding/`, `training-exercises/spickzettel/`). Standard: `--maven` (entfernt Gradle-Artefakte). Mit `--gradle`: verteilt Gradle-Wrapper (JAR, properties, gradlew) und entfernt Maven-Artefakte. Beide Modi löschen Build-Ausgaben und Caches. Scheitert mit Fehler, wenn `--gradle` verwendet wird, aber der Wrapper noch nicht bereit ist — dann zuerst `README-gradle.sh` ausführen. |
-| `README-gradle.sh` | Technik-Check für Gradle: stellt Gradle-Wrapper bereit (lädt ihn herunter, falls fehlend) und führt Build-Test durch. Ohne Schalter: scheitert laut, wenn installierte Version nicht zur benötigten passt. Mit `--update`: ersetzt veralteten Wrapper durch die benötigte Version. |
+| `README-maven.sh` | Technik-Check für Maven: führt vollständigen Build- und Starttest durch |
+| `README-gradle.sh` | Technik-Check für Gradle: stellt Gradle-Wrapper bereit und führt Build- und Starttest durch |
+| `init-exercises.sh` | Initialisiert alle kopierten Übungsverzeichnisse für die Schulung (Maven- oder Gradle-Modus) |
+| `build.sh` | Baut alle Musterlösungen aus `spickzettel/`; erkennt Maven/Gradle anhand des vorhandenen Build-Setups |
+| `patch-nexus.sh` | Patcht Gradle-Setups für einen internen Nexus-Mirror; Aufruf aus dem Vorlagen-Wurzelverzeichnis |
`gradle-wrapper.jar` ist absichtlich nicht im Repository (wird von Unternehmens-Mail-Filtern blockiert). `gradlew` und `gradle/wrapper/gradle-wrapper.properties` sind versioniert und definieren die maßgebliche Gradle-Version für alle Übungen der Schulung. Der Versions-Marker `gradle/wrapper/.gradle-version` ist gitignoriert.
## Wesentliche Einschränkungen
- `push.sh` force-pusht — das ist für diesen Schulungsworkflow absichtlich und erwartet.
-- `--vorlage`-Branches werden von Build-Skripten übersprungen (sie sind absichtlich unvollständig).
+- `--vorlage`-Branches werden von `copy.sh` in `vorlagen/` kopiert; das neue `build.sh` in `technik-check` baut nur Musterlösungen aus `spickzettel/` und überspringt diese damit automatisch.
- Der `grundlagen/docker`-Branch ist nicht in `$BRANCHES`, ist aber in `$BRANCH_NAMES` (aus `lib.sh`) enthalten und wird so automatisch von `push.sh`, `diff.sh`, `reset.sh` und `copy.sh` mitbehandelt.
+++ /dev/null
-#!/bin/bash
-set -e
-
-source lib.sh
-
-# Ohne --publish: nur bauen (kein Docker-Image veröffentlichen)
-# Mit --publish: bauen und Docker-Image in die Registry schieben
-PUBLISH=false
-[ "$1" = "--publish" ] && PUBLISH=true
-
-for i in $BRANCHES; do
- declare -n branch=${i}
- git checkout "$branch"
-
- if [[ "$branch" == *--vorlage ]]; then
- echo -e "\nIgnoriere Vorlage: $branch\n"
- continue
- fi
-
- if [ -e 'pom.xml' ]; then
- echo -e "\nBaue $branch (Maven)"
- mvn clean install
- if $PUBLISH; then
- echo -e "\nVeröffentliche Docker-Image für $branch"
- if [[ "$branch" == grundlagen/* ]]; then
- mvn jib:build
- else
- mvn spring-boot:build-image -Dspring-boot.build-image.publish=true
- fi
- fi
- elif [ -e 'build.gradle' ]; then
- echo -e "\nBaue $branch (Gradle)"
- [ -f bootstrap-gradle.sh ] && ./bootstrap-gradle.sh
- ./gradlew build
- if $PUBLISH; then
- echo -e "\nVeröffentliche Docker-Image für $branch"
- ./gradlew bootBuildImage --publishImage
- fi
- else
- echo -e "\nIgnoriere Branch ohne Build-Dateien: $branch\n"
- fi
-done
-
-git checkout scripting
source lib.sh
-# --tag=<suffix>: Kopiert den jeweiligen Tag-Stand statt den aktuellen Branch-HEAD
-# --local: Kopiert lokale Branch-HEADs ohne Remote-Aktualisierung
-# --nexus-url=<url>: Ruft patch-nexus.sh auf die Vorlagen an
TAG_SUFFIX=""
-NEXUS_URL=""
LOCAL=false
-for arg in "$@"; do
- case "$arg" in
- --tag=*) TAG_SUFFIX="${arg#--tag=}" ;;
- --nexus-url=*) NEXUS_URL="${arg#--nexus-url=}" ;;
- --local) LOCAL=true ;;
- *) echo "Unbekannter Parameter: $arg"; exit 1 ;;
+while [ $# -gt 0 ]; do
+ case "$1" in
+ --tag)
+ [ -n "$2" ] || { echo "Fehler: --tag erfordert einen Wert" >&2; exit 1; }
+ TAG_SUFFIX="$2"; shift 2 ;;
+ --local)
+ LOCAL=true; shift ;;
+ --help)
+ echo "Kopiert alle Branches in die Übungsverzeichnisse."
+ echo ""
+ echo "Verwendung: ./copy.sh [OPTIONEN] [--help]"
+ echo ""
+ echo " --tag <suffix> Kopiert den jeweiligen Tag-Stand statt den Branch-HEAD"
+ echo " --local Kopiert lokale Branch-HEADs ohne Remote-Aktualisierung"
+ echo " --help Diese Hilfe anzeigen"
+ echo ""
+ echo "Ohne --tag und ohne --local: Aktualisiert alle Branches zuerst auf Remote-Stand"
+ echo "(erfordert Remote-Zugriff und einheitliche Tags über alle Branches)."
+ exit 0 ;;
+ *) echo "Unbekannter Parameter: $1" >&2; exit 1 ;;
esac
done
-SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
-
RSYNC_OPTS=(
rsync -av
--delete
--exclude=gradle/wrapper/.gradle-version
--exclude=branches.sh
--exclude=lib.sh
- --exclude=build.sh
--exclude=copy.sh
--exclude=diff.sh
- --exclude=patch-nexus.sh
--exclude=push.sh
--exclude=reset.sh
)
}
if [ "$TAG_SUFFIX" = "" ] && ! $LOCAL; then
- echo "Kein Tag-Suffix angegeben — prüfe einheitliche Tags vor der Aktualisierung auf Remote-Stände..."
+ echo "Kein --tag angegeben — prüfe einheitliche Tags vor der Aktualisierung auf Remote-Stände..."
_common_suffixes=$(find_common_tag_suffixes) || {
echo " Alle Branches müssen einheitlich getagged sein, bevor auf Remote-Stände aktualisiert wird." >&2
exit 1
done < <(find "$base" -mindepth 2 -maxdepth 2 -type d | sort)
done
-if [ "$NEXUS_URL" != "" ]; then
- echo -e "\nPatche Gradle-Setups für Nexus: $NEXUS_URL"
- (cd "$VORLAGEN" && "$SCRIPT_DIR/patch-nexus.sh" "$NEXUS_URL")
-fi
-
git checkout scripting
source lib.sh
-# Kein Argument: lokaler Branch gegen origin/<branch>
-# Ein Argument: lokaler Branch gegen <branch>--<suffix>
-# Zwei Argumente: <branch>--<suffix1> gegen <branch>--<suffix2>
+TAG=""
+FROM=""
+TO=""
+while [ $# -gt 0 ]; do
+ case "$1" in
+ --tag)
+ [ -n "$2" ] || { echo "Fehler: --tag erfordert einen Wert" >&2; exit 1; }
+ TAG="$2"; shift 2 ;;
+ --from)
+ [ -n "$2" ] || { echo "Fehler: --from erfordert einen Wert" >&2; exit 1; }
+ FROM="$2"; shift 2 ;;
+ --to)
+ [ -n "$2" ] || { echo "Fehler: --to erfordert einen Wert" >&2; exit 1; }
+ TO="$2"; shift 2 ;;
+ --help)
+ echo "Zeigt Diffs aller Branches an."
+ echo ""
+ echo "Verwendung: ./diff.sh [OPTIONEN] [--help]"
+ echo ""
+ echo " Ohne Optionen: lokaler Branch gegen origin/<branch>"
+ echo " --tag <suffix> lokaler Branch gegen <branch>--<suffix>"
+ echo " --from <suffix1> --to <suffix2> <branch>--<suffix1> gegen <branch>--<suffix2>"
+ echo " --help Diese Hilfe anzeigen"
+ exit 0 ;;
+ *) echo "Unbekannter Parameter: $1" >&2; exit 1 ;;
+ esac
+done
+
+if [ -n "$FROM" ] && [ -z "$TO" ]; then
+ echo "Fehler: --from erfordert auch --to" >&2; exit 1
+fi
+if [ -n "$TO" ] && [ -z "$FROM" ]; then
+ echo "Fehler: --to erfordert auch --from" >&2; exit 1
+fi
+if [ -n "$TAG" ] && [ -n "$FROM" ]; then
+ echo "Fehler: --tag und --from/--to schließen sich aus" >&2; exit 1
+fi
for branch in "${BRANCH_NAMES[@]}"; do
- if [ "$1" != "" ] && [ "$2" != "" ]; then
- echo -e "\nDiff ${branch}--${1} gegen ${branch}--${2}\n"
- git diff "${branch}--${1}" "${branch}--${2}"
- elif [ "$1" != "" ]; then
- echo -e "\nDiff $branch gegen ${branch}--${1}\n"
- git diff "${branch}--${1}" "$branch"
+ if [ -n "$FROM" ]; then
+ echo -e "\nDiff ${branch}--${FROM} gegen ${branch}--${TO}\n"
+ git diff "${branch}--${FROM}" "${branch}--${TO}"
+ elif [ -n "$TAG" ]; then
+ echo -e "\nDiff $branch gegen ${branch}--${TAG}\n"
+ git diff "${branch}--${TAG}" "$branch"
else
echo -e "\nDiff $branch gegen origin/$branch\n"
git diff "origin/$branch" "$branch"
+++ /dev/null
-#!/bin/bash
-set -e
-
-# Passt Gradle-Setups an einen internen Nexus-Mirror an.
-# Aufruf (aus dem Zielverzeichnis, z.B. ../vorlagen/):
-#
-# patch-nexus.sh <nexus-maven-url> [--gradle-dist-url=<url>]
-#
-# Ohne --gradle-dist-url bleibt gradle-wrapper.properties unverändert.
-# Falls Gradle-Distributionen ebenfalls über Nexus bereitgestellt werden,
-# muss dort ein "raw proxy"-Repository auf services.gradle.org/distributions/
-# eingerichtet sein.
-
-if [ "$1" = "" ]; then
- echo "Aufruf: $(basename "$0") <nexus-maven-url> [--gradle-dist-url=<url>]"
- echo ""
- echo "Beispiel:"
- echo " $(basename "$0") https://nexus.example.com/repository/maven-public/"
- echo " $(basename "$0") https://nexus.example.com/repository/maven-public/ \\"
- echo " --gradle-dist-url=https://nexus.example.com/repository/gradle-distributions/"
- exit 1
-fi
-
-NEXUS_URL="$1"
-GRADLE_DIST_URL=""
-for arg in "${@:2}"; do
- case "$arg" in
- --gradle-dist-url=*) GRADLE_DIST_URL="${arg#--gradle-dist-url=}" ;;
- *) echo "Unbekannter Parameter: $arg"; exit 1 ;;
- esac
-done
-
-TMP_REPO_BLOCK=$(mktemp)
-TMP_PLUGIN_BLOCK=$(mktemp)
-
-cat > "$TMP_REPO_BLOCK" <<EOF
- maven {
- url '$NEXUS_URL'
- }
- maven {
- name 'gradle plugins'
- url 'https://plugins.gradle.org/m2/'
- }
-EOF
-
-cat > "$TMP_PLUGIN_BLOCK" <<EOF
-pluginManagement {
- repositories {
- maven {
- name 'Nexus-Internal Access'
- url '$NEXUS_URL'
- }
- }
-}
-
-EOF
-
-echo "Bearbeite build.gradle-Dateien..."
-for file in */*/build.gradle; do
- [ -f "$file" ] || continue
- echo " $file"
- sed -i '/mavenCentral()/d' "$file"
- if grep -q 'repositories *{' "$file"; then
- awk -v insert="$(cat "$TMP_REPO_BLOCK")" '
- BEGIN { added=0 }
- /repositories[[:space:]]*{/ {
- print
- if (!added) { print insert; added=1; next }
- }
- { print }
- ' "$file" > "$file.tmp" && mv "$file.tmp" "$file"
- else
- cat "$TMP_REPO_BLOCK" "$file" > "$file.tmp" && mv "$file.tmp" "$file"
- fi
-done
-
-echo "Bearbeite settings.gradle-Dateien..."
-for file in */*/settings.gradle; do
- [ -f "$file" ] || continue
- echo " $file"
- if ! grep -q 'pluginManagement' "$file"; then
- cat "$TMP_PLUGIN_BLOCK" "$file" > "$file.tmp" && mv "$file.tmp" "$file"
- else
- echo " (pluginManagement bereits vorhanden -- uebersprungen)"
- fi
-done
-
-if [ "$GRADLE_DIST_URL" != "" ]; then
- echo "Bearbeite gradle-wrapper.properties-Dateien..."
- for file in */*/gradle/wrapper/gradle-wrapper.properties; do
- [ -f "$file" ] || continue
- echo " $file"
- # In .properties-Dateien muss ':' als '\:' escaped werden; awk erledigt das sauber
- awk -v url="$GRADLE_DIST_URL" '
- BEGIN { gsub(/:/, "\\:", url) }
- /^distributionUrl=/ { print "distributionUrl=" url; next }
- { print }
- ' "$file" > "$file.tmp" && mv "$file.tmp" "$file"
- done
-fi
-
-rm -f "$TMP_REPO_BLOCK" "$TMP_PLUGIN_BLOCK"
-echo "Fertig."
source lib.sh
+for arg in "$@"; do
+ case "$arg" in
+ --help)
+ echo "Force-pusht alle Branches zu origin."
+ echo "Prüft vorab, ob umzuschreibende Remote-Stände bereits gesichert sind;"
+ echo "fehlt ein Tag, werden TIMESTAMP-Backup-Tags für alle Remote-Stände im Remote angelegt."
+ echo "Gemeinsame lokale Tag-Suffixe (z.B. --claude-5 für alle Branches) werden ebenfalls gepusht,"
+ echo "sofern noch nicht im Remote vorhanden."
+ echo ""
+ echo "Verwendung: ./push.sh [--help]"
+ echo ""
+ echo " --help Diese Hilfe anzeigen"
+ exit 0
+ ;;
+ *) echo "Unbekannter Parameter: $arg" >&2; exit 1 ;;
+ esac
+done
+
# Fetch remote tags once to avoid repeated network calls
remote_tags=$(git ls-remote --tags origin)
source lib.sh
-if [ "$1" = "" ]; then
- echo "No Tag-Prefix specified: Resetting to remote branches"
+TAG=""
+while [ $# -gt 0 ]; do
+ case "$1" in
+ --tag)
+ [ -n "$2" ] || { echo "Fehler: --tag erfordert einen Wert" >&2; exit 1; }
+ TAG="$2"; shift 2 ;;
+ --help)
+ echo "Setzt alle Branches zurück."
+ echo ""
+ echo "Verwendung: ./reset.sh [--tag <suffix>] [--help]"
+ echo ""
+ echo " --tag <suffix> Setzt alle Branches auf <branch>--<suffix> zurück"
+ echo " Ohne --tag: Setzt auf origin/<branch> zurück (erfordert Remote-Zugriff)"
+ echo " --help Diese Hilfe anzeigen"
+ exit 0 ;;
+ *) echo "Unbekannter Parameter: $1" >&2; exit 1 ;;
+ esac
+done
+
+if [ -z "$TAG" ]; then
+ echo "Kein --tag angegeben: Setze alle Branches auf Remote-Stand zurück"
reset_branches_to_remote
else
for branch in "${BRANCH_NAMES[@]}"; do
- echo -e "\nResetting $branch to ${branch}--$1"
+ echo -e "\nResetting $branch to ${branch}--${TAG}"
git checkout "$branch"
- git reset --hard "${branch}--$1"
+ git reset --hard "${branch}--${TAG}"
done
git checkout scripting
fi