diff --git a/.devcontainer/01-echoes-lost-in-orbit_beginner/post-create.sh b/.devcontainer/01-echoes-lost-in-orbit_beginner/post-create.sh index ecaceb66..be345edd 100644 --- a/.devcontainer/01-echoes-lost-in-orbit_beginner/post-create.sh +++ b/.devcontainer/01-echoes-lost-in-orbit_beginner/post-create.sh @@ -1,6 +1,12 @@ #!/usr/bin/env bash set -e -lib/shared/init.sh -lib/kubernetes/init.sh -lib/argocd/init.sh --read-only +lib/shared/init.sh --version v0.17.0 # https://github.com/charmbracelet/gum/releases +# kind: https://github.com/kubernetes-sigs/kind/releases | kubectl: https://dl.k8s.io | kubens: https://github.com/ahmetb/kubectx/releases | k9s: https://github.com/derailed/k9s/releases | helm: https://github.com/helm/helm/releases +lib/kubernetes/init.sh \ + --kind-version v0.30.0 \ + --kubectl-version v1.34.1 \ + --kubens-version v0.9.5 \ + --k9s-version v0.50.16 \ + --helm-version v4.0.1 +lib/argocd/init.sh --read-only --version v3.2.0 # https://github.com/argoproj/argo-cd/releases diff --git a/.devcontainer/01-echoes-lost-in-orbit_expert/post-create.sh b/.devcontainer/01-echoes-lost-in-orbit_expert/post-create.sh index 2fd3dc01..f8c8bcc3 100644 --- a/.devcontainer/01-echoes-lost-in-orbit_expert/post-create.sh +++ b/.devcontainer/01-echoes-lost-in-orbit_expert/post-create.sh @@ -1,9 +1,15 @@ #!/usr/bin/env bash set -e -lib/shared/init.sh -lib/kubernetes/init.sh -lib/argocd/init.sh --read-only -lib/argo-rollouts/init.sh -lib/prometheus/init.sh -lib/jaeger/init.sh \ No newline at end of file +lib/shared/init.sh --version v0.17.0 # https://github.com/charmbracelet/gum/releases +# kind: https://github.com/kubernetes-sigs/kind/releases | kubectl: https://dl.k8s.io | kubens: https://github.com/ahmetb/kubectx/releases | k9s: https://github.com/derailed/k9s/releases | helm: https://github.com/helm/helm/releases +lib/kubernetes/init.sh \ + --kind-version v0.30.0 \ + --kubectl-version v1.34.1 \ + --kubens-version v0.9.5 \ + --k9s-version v0.50.16 \ + --helm-version v4.0.1 +lib/argocd/init.sh --read-only --version v3.2.0 # https://github.com/argoproj/argo-cd/releases +lib/argo-rollouts/init.sh --version v1.8.3 # https://github.com/argoproj/argo-rollouts/releases +lib/prometheus/init.sh --version 29.1.0 # https://artifacthub.io/packages/helm/prometheus-community/prometheus +lib/jaeger/init.sh --version 4.1.5 # https://artifacthub.io/packages/helm/jaegertracing/jaeger \ No newline at end of file diff --git a/.devcontainer/01-echoes-lost-in-orbit_intermediate/post-create.sh b/.devcontainer/01-echoes-lost-in-orbit_intermediate/post-create.sh index dd7c38b5..8103d440 100644 --- a/.devcontainer/01-echoes-lost-in-orbit_intermediate/post-create.sh +++ b/.devcontainer/01-echoes-lost-in-orbit_intermediate/post-create.sh @@ -1,9 +1,15 @@ #!/usr/bin/env bash set -e -lib/shared/init.sh -lib/kubernetes/init.sh -lib/argocd/init.sh --read-only -lib/argo-rollouts/init.sh -lib/kube-state-metrics/init.sh -lib/prometheus/init.sh \ No newline at end of file +lib/shared/init.sh --version v0.17.0 # https://github.com/charmbracelet/gum/releases +# kind: https://github.com/kubernetes-sigs/kind/releases | kubectl: https://dl.k8s.io | kubens: https://github.com/ahmetb/kubectx/releases | k9s: https://github.com/derailed/k9s/releases | helm: https://github.com/helm/helm/releases +lib/kubernetes/init.sh \ + --kind-version v0.30.0 \ + --kubectl-version v1.34.1 \ + --kubens-version v0.9.5 \ + --k9s-version v0.50.16 \ + --helm-version v4.0.1 +lib/argocd/init.sh --read-only --version v3.2.0 # https://github.com/argoproj/argo-cd/releases +lib/argo-rollouts/init.sh --version v1.8.3 # https://github.com/argoproj/argo-rollouts/releases +lib/kube-state-metrics/init.sh --version 7.0.0 # https://artifacthub.io/packages/helm/prometheus-community/kube-state-metrics +lib/prometheus/init.sh --version 29.1.0 # https://artifacthub.io/packages/helm/prometheus-community/prometheus \ No newline at end of file diff --git a/.devcontainer/02-building-cloudhaven_01-beginner/post-create.sh b/.devcontainer/02-building-cloudhaven_01-beginner/post-create.sh index 8f53f938..1ea5675e 100644 --- a/.devcontainer/02-building-cloudhaven_01-beginner/post-create.sh +++ b/.devcontainer/02-building-cloudhaven_01-beginner/post-create.sh @@ -8,7 +8,7 @@ source "$REPO_ROOT/lib/scripts/tracker.sh" set_tracking_context "02-building-cloudhaven" "beginner" track_codespace_created -"$REPO_ROOT/lib/shared/init.sh" +"$REPO_ROOT/lib/shared/init.sh" --version v0.17.0 # https://github.com/charmbracelet/gum/releases -"$REPO_ROOT/lib/open-tofu/init.sh" -"$REPO_ROOT/lib/gcp-api-mock/init.sh" +"$REPO_ROOT/lib/open-tofu/init.sh" --version v1.11.2 # https://github.com/opentofu/opentofu/releases +"$REPO_ROOT/lib/gcp-api-mock/init.sh" --version v1.1.4 # https://github.com/KatharinaSick/gcp-api-mock/releases diff --git a/.devcontainer/02-building-cloudhaven_02-intermediate/post-create.sh b/.devcontainer/02-building-cloudhaven_02-intermediate/post-create.sh index aeed3744..ac19bdc9 100644 --- a/.devcontainer/02-building-cloudhaven_02-intermediate/post-create.sh +++ b/.devcontainer/02-building-cloudhaven_02-intermediate/post-create.sh @@ -8,7 +8,7 @@ source "$REPO_ROOT/lib/scripts/tracker.sh" set_tracking_context "02-building-cloudhaven" "intermediate" track_codespace_created -"$REPO_ROOT/lib/shared/init.sh" +"$REPO_ROOT/lib/shared/init.sh" --version v0.17.0 # https://github.com/charmbracelet/gum/releases -"$REPO_ROOT/lib/open-tofu/init.sh" -"$REPO_ROOT/lib/gcp-api-mock/init.sh" \ No newline at end of file +"$REPO_ROOT/lib/open-tofu/init.sh" --version v1.11.2 # https://github.com/opentofu/opentofu/releases +"$REPO_ROOT/lib/gcp-api-mock/init.sh" --version v1.1.4 # https://github.com/KatharinaSick/gcp-api-mock/releases \ No newline at end of file diff --git a/.devcontainer/02-building-cloudhaven_03-expert/post-create.sh b/.devcontainer/02-building-cloudhaven_03-expert/post-create.sh index f9248874..c7961541 100644 --- a/.devcontainer/02-building-cloudhaven_03-expert/post-create.sh +++ b/.devcontainer/02-building-cloudhaven_03-expert/post-create.sh @@ -8,8 +8,8 @@ source "$REPO_ROOT/lib/scripts/tracker.sh" set_tracking_context "02-building-cloudhaven" "expert" track_codespace_created -"$REPO_ROOT/lib/shared/init.sh" +"$REPO_ROOT/lib/shared/init.sh" --version v0.17.0 # https://github.com/charmbracelet/gum/releases -"$REPO_ROOT/lib/github-cli/init.sh" -"$REPO_ROOT/lib/open-tofu/init.sh" -"$REPO_ROOT/lib/gcp-api-mock/init.sh" +"$REPO_ROOT/lib/github-cli/init.sh" --version v2.86.0 # https://github.com/cli/cli/releases +"$REPO_ROOT/lib/open-tofu/init.sh" --version v1.11.2 # https://github.com/opentofu/opentofu/releases +"$REPO_ROOT/lib/gcp-api-mock/init.sh" --version v1.1.4 # https://github.com/KatharinaSick/gcp-api-mock/releases diff --git a/.devcontainer/03-the-ai-observatory_01-beginner/post-create.sh b/.devcontainer/03-the-ai-observatory_01-beginner/post-create.sh index 98279ec3..fb49f9dd 100644 --- a/.devcontainer/03-the-ai-observatory_01-beginner/post-create.sh +++ b/.devcontainer/03-the-ai-observatory_01-beginner/post-create.sh @@ -8,8 +8,14 @@ source "$REPO_ROOT/lib/scripts/tracker.sh" set_tracking_context "03-the-ai-observatory" "beginner" track_codespace_created -"$REPO_ROOT/lib/shared/init.sh" -"$REPO_ROOT/lib/kubernetes/init.sh" -"$REPO_ROOT/lib/jaeger/init.sh" -"$REPO_ROOT/lib/otel-collector/init.sh" -"$REPO_ROOT/lib/ollama/init.sh" +"$REPO_ROOT/lib/shared/init.sh" --version v0.17.0 # https://github.com/charmbracelet/gum/releases +# kind: https://github.com/kubernetes-sigs/kind/releases | kubectl: https://dl.k8s.io | kubens: https://github.com/ahmetb/kubectx/releases | k9s: https://github.com/derailed/k9s/releases | helm: https://github.com/helm/helm/releases +"$REPO_ROOT/lib/kubernetes/init.sh" \ + --kind-version v0.30.0 \ + --kubectl-version v1.34.1 \ + --kubens-version v0.9.5 \ + --k9s-version v0.50.16 \ + --helm-version v4.0.1 +"$REPO_ROOT/lib/jaeger/init.sh" --version 4.1.5 # https://artifacthub.io/packages/helm/jaegertracing/jaeger +"$REPO_ROOT/lib/otel-collector/init.sh" --version 0.148.0 # https://github.com/open-telemetry/opentelemetry-collector-releases/releases +"$REPO_ROOT/lib/ollama/init.sh" --version 1.40.0 # https://artifacthub.io/packages/helm/otwld/ollama diff --git a/.devcontainer/03-the-ai-observatory_02-intermediate/post-create.sh b/.devcontainer/03-the-ai-observatory_02-intermediate/post-create.sh index 1737b735..817d8655 100644 --- a/.devcontainer/03-the-ai-observatory_02-intermediate/post-create.sh +++ b/.devcontainer/03-the-ai-observatory_02-intermediate/post-create.sh @@ -8,11 +8,17 @@ source "$REPO_ROOT/lib/scripts/tracker.sh" set_tracking_context "03-the-ai-observatory" "intermediate" track_codespace_created -"$REPO_ROOT/lib/shared/init.sh" -"$REPO_ROOT/lib/kubernetes/init.sh" -"$REPO_ROOT/lib/jaeger/init.sh" -"$REPO_ROOT/lib/otel-collector/init.sh" -"$REPO_ROOT/lib/prometheus/init.sh" --operator -"$REPO_ROOT/lib/ollama/init.sh" -"$REPO_ROOT/lib/qdrant/init.sh" +"$REPO_ROOT/lib/shared/init.sh" --version v0.17.0 # https://github.com/charmbracelet/gum/releases +# kind: https://github.com/kubernetes-sigs/kind/releases | kubectl: https://dl.k8s.io | kubens: https://github.com/ahmetb/kubectx/releases | k9s: https://github.com/derailed/k9s/releases | helm: https://github.com/helm/helm/releases +"$REPO_ROOT/lib/kubernetes/init.sh" \ + --kind-version v0.30.0 \ + --kubectl-version v1.34.1 \ + --kubens-version v0.9.5 \ + --k9s-version v0.50.16 \ + --helm-version v4.0.1 +"$REPO_ROOT/lib/jaeger/init.sh" --version 4.1.5 # https://artifacthub.io/packages/helm/jaegertracing/jaeger +"$REPO_ROOT/lib/otel-collector/init.sh" --version 0.148.0 # https://github.com/open-telemetry/opentelemetry-collector-releases/releases +"$REPO_ROOT/lib/prometheus/init.sh" --operator --version 82.1.1 # https://artifacthub.io/packages/helm/prometheus-community/kube-prometheus-stack +"$REPO_ROOT/lib/ollama/init.sh" --version 1.40.0 # https://artifacthub.io/packages/helm/otwld/ollama +"$REPO_ROOT/lib/qdrant/init.sh" --version 1.16.3 # https://artifacthub.io/packages/helm/qdrant/qdrant diff --git a/.devcontainer/03-the-ai-observatory_03-expert/post-create.sh b/.devcontainer/03-the-ai-observatory_03-expert/post-create.sh index 3032f4fb..6011f8c3 100644 --- a/.devcontainer/03-the-ai-observatory_03-expert/post-create.sh +++ b/.devcontainer/03-the-ai-observatory_03-expert/post-create.sh @@ -8,9 +8,15 @@ source "$REPO_ROOT/lib/scripts/tracker.sh" set_tracking_context "03-the-ai-observatory" "expert" track_codespace_created -"$REPO_ROOT/lib/shared/init.sh" -"$REPO_ROOT/lib/kubernetes/init.sh" -"$REPO_ROOT/lib/jaeger/init.sh" -"$REPO_ROOT/lib/otel-collector/init.sh" -"$REPO_ROOT/lib/ollama/init.sh" -"$REPO_ROOT/lib/qdrant/init.sh" +"$REPO_ROOT/lib/shared/init.sh" --version v0.17.0 # https://github.com/charmbracelet/gum/releases +# kind: https://github.com/kubernetes-sigs/kind/releases | kubectl: https://dl.k8s.io | kubens: https://github.com/ahmetb/kubectx/releases | k9s: https://github.com/derailed/k9s/releases | helm: https://github.com/helm/helm/releases +"$REPO_ROOT/lib/kubernetes/init.sh" \ + --kind-version v0.30.0 \ + --kubectl-version v1.34.1 \ + --kubens-version v0.9.5 \ + --k9s-version v0.50.16 \ + --helm-version v4.0.1 +"$REPO_ROOT/lib/jaeger/init.sh" --version 4.1.5 # https://artifacthub.io/packages/helm/jaegertracing/jaeger +"$REPO_ROOT/lib/otel-collector/init.sh" --version 0.148.0 # https://github.com/open-telemetry/opentelemetry-collector-releases/releases +"$REPO_ROOT/lib/ollama/init.sh" --version 1.40.0 # https://artifacthub.io/packages/helm/otwld/ollama +"$REPO_ROOT/lib/qdrant/init.sh" --version 1.16.3 # https://artifacthub.io/packages/helm/qdrant/qdrant diff --git a/.devcontainer/post-create.sh b/.devcontainer/post-create.sh index aa256854..990b2d23 100644 --- a/.devcontainer/post-create.sh +++ b/.devcontainer/post-create.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euo pipefail -lib/shared/init.sh +lib/shared/init.sh --version v0.17.0 # https://github.com/charmbracelet/gum/releases echo "→ Installing mkdocs-material..." pip install --quiet mkdocs-material mkdocs-monorepo-plugin diff --git a/.github/workflows/lint-init-versions.yaml b/.github/workflows/lint-init-versions.yaml new file mode 100644 index 00000000..2dd8519f --- /dev/null +++ b/.github/workflows/lint-init-versions.yaml @@ -0,0 +1,51 @@ +# This check exists to catch missing --version flags at PR time rather than when a +# contributor's Codespace silently fails to start. Failing fast here gives a much +# better experience than debugging a broken environment after the fact. +name: Lint init script versions + +on: + pull_request: + paths: + - '.devcontainer/**/post-create.sh' + - 'lib/**/init.sh' + +jobs: + check-versions-pinned: + name: All init.sh calls have pinned versions + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Check that every init.sh call has a version flag + run: | + set -euo pipefail + + failed=0 + + while IFS= read -r file; do + while IFS= read -r line; do + # Skip blank lines, comments, and lines that don't reference an init script + [[ "$line" =~ ^[[:space:]]*# ]] && continue + [[ "$line" =~ init\.sh ]] || continue + + + # Skip continuation lines (they carry the version flags for kubernetes/init.sh) + [[ "$line" == *\\ ]] && continue + [[ "$line" =~ ^[[:space:]]+-- ]] && continue + + # The line calls an init script — check it carries a version flag + if ! grep -qE '(--version|--kind-version|--kubectl-version|--kubens-version|--k9s-version|--helm-version)' <<< "$line"; then + echo "ERROR: $file: missing version flag on: $line" + failed=1 + fi + done < "$file" + done < <(find .devcontainer -name 'post-create.sh') + + if [[ $failed -eq 1 ]]; then + echo "" + echo "Every lib/**/init.sh call must pass a pinned --version flag." + echo "Run the script with --help to see available flags." + exit 1 + fi + + echo "✅ All init.sh calls have pinned version flags." diff --git a/docs/contributing/adventures.md b/docs/contributing/adventures.md index 7eac8751..f5e0a5d8 100755 --- a/docs/contributing/adventures.md +++ b/docs/contributing/adventures.md @@ -77,10 +77,18 @@ Open the generated `.devcontainer/00-adventure-name_NN-level/` files and fill in For Kubernetes-based adventures, [Adventure 01](../../adventures/01-echoes-lost-in-orbit/) is a good reference for what features and setup scripts to use. **post-create.sh** runs once when the container is created: -- Install CLI tools using setup scripts from `lib/` +- Install CLI tools using setup scripts from `lib/` — every script accepts a `--version` flag to pin a specific version. Run any script with `--help` to see available flags and defaults. - Pull container images - Set up one-time configurations +Example calls in `post-create.sh`: +```bash +"$REPO_ROOT/lib/kubernetes/init.sh" # use default versions +"$REPO_ROOT/lib/argocd/init.sh" --version v3.5.0 # pin a version +"$REPO_ROOT/lib/argocd/init.sh" --read-only --version v3.5.0 # combine flags +"$REPO_ROOT/lib/kubernetes/init.sh" --kubectl-version v1.35.0 --helm-version v4.1.0 # per-tool versions +``` + **post-start.sh** runs every time the container starts: - Start services (databases, clusters, etc.) - Apply initial state diff --git a/lib/argo-rollouts/init.sh b/lib/argo-rollouts/init.sh index 147c3426..1d391844 100755 --- a/lib/argo-rollouts/init.sh +++ b/lib/argo-rollouts/init.sh @@ -1,15 +1,51 @@ #!/usr/bin/env bash set -e +help() { + echo "Usage: $0 [OPTIONS]" + echo "Options:" + echo " --help Display this help message" + echo " --version Argo Rollouts version to install (required)" +} + +# Parse flags +version="" + +while [[ $# -gt 0 ]]; do + case "$1" in + --help) + help + exit 0 + ;; + --version) + if [[ -z "${2-}" ]]; then + echo "Error: --version requires a value" >&2 + exit 1 + fi + version="$2" + shift 2 + ;; + *) + echo "Unknown option: $1" >&2 + exit 1 + ;; + esac +done + +if [[ -z "$version" ]]; then + echo "Error: --version is required" >&2 + exit 1 +fi + echo "✨ Installing Argo Rollouts" kubectl create namespace argo-rollouts -kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/download/v1.8.3/install.yaml +kubectl apply -n argo-rollouts -f "https://github.com/argoproj/argo-rollouts/releases/download/${version}/install.yaml" echo "✨ Waiting for Argo Rollouts controller to be ready" kubectl rollout status deployment/argo-rollouts -n argo-rollouts --timeout=300s echo "✨ Installing Argo Rollouts Kubectl plugin" -curl -LO https://github.com/argoproj/argo-rollouts/releases/download/v1.8.3/kubectl-argo-rollouts-linux-amd64 +curl -LO "https://github.com/argoproj/argo-rollouts/releases/download/${version}/kubectl-argo-rollouts-linux-amd64" chmod +x ./kubectl-argo-rollouts-linux-amd64 sudo mv ./kubectl-argo-rollouts-linux-amd64 /usr/local/bin/kubectl-argo-rollouts diff --git a/lib/argocd/init.sh b/lib/argocd/init.sh index 8df89f76..117c3725 100755 --- a/lib/argocd/init.sh +++ b/lib/argocd/init.sh @@ -6,35 +6,57 @@ SCRIPT_DIR="$(dirname "$(realpath "${BASH_SOURCE[0]}")")" help() { echo "Usage: $0 [OPTIONS]" echo "Options:" - echo " --help Display this help message" - echo " --read-only Disables the ArgoCD admin user and only provides read-only access" + echo " --help Display this help message" + echo " --read-only Disables the ArgoCD admin user and only provides read-only access" + echo " --version Argo CD version to install (required)" } # Parse flags read_only=false +version="" -for arg in "$@"; do - case "$arg" in +while [[ $# -gt 0 ]]; do + case "$1" in --help) help exit 0 ;; --read-only) read_only=true + shift + ;; + --version) + if [[ -z "${2-}" ]]; then + echo "Error: --version requires a value" >&2 + exit 1 + fi + version="$2" + shift 2 ;; *) - echo "Unknown option: $arg" >&2 + echo "Unknown option: $1" >&2 exit 1 ;; esac done +if [[ -z "$version" ]]; then + echo "Error: --version is required" >&2 + exit 1 +fi + echo "✨ Installing Argo CD" kubectl create namespace argocd -kubectl apply -k "$SCRIPT_DIR/manifests" + +manifests_tmp="$(mktemp -d)" +trap 'rm -rf "${manifests_tmp}"' EXIT +cp -r "$SCRIPT_DIR/manifests/." "${manifests_tmp}/" +sed -i "s|argoproj/argo-cd/[^/]*/manifests/install.yaml|argoproj/argo-cd/${version}/manifests/install.yaml|" \ + "${manifests_tmp}/kustomization.yaml" +kubectl apply -k "${manifests_tmp}" echo "✨ Installing Argo CD CLI" -curl -sSL -o argocd-linux-amd64 https://github.com/argoproj/argo-cd/releases/download/v3.2.0/argocd-linux-amd64 +curl -sSL -o argocd-linux-amd64 "https://github.com/argoproj/argo-cd/releases/download/${version}/argocd-linux-amd64" sudo install -m 555 argocd-linux-amd64 /usr/local/bin/argocd rm argocd-linux-amd64 @@ -49,7 +71,7 @@ if [ "$read_only" = true ]; then argocd login localhost:30100 --username admin --password "$admin_password" --plaintext argocd account update-password \ --account readonly \ - --current-password $admin_password \ + --current-password "$admin_password" \ --new-password a-super-secure-password echo "✨ Disabling admin user for read-only mode" diff --git a/lib/argocd/manifests/kustomization.yaml b/lib/argocd/manifests/kustomization.yaml index bcf11242..1ec91a1d 100644 --- a/lib/argocd/manifests/kustomization.yaml +++ b/lib/argocd/manifests/kustomization.yaml @@ -3,8 +3,11 @@ kind: Kustomization namespace: argocd +# ARGOCD_VERSION is a placeholder substituted by init.sh at deploy time via sed. +# Applying this kustomization directly without going through init.sh will fail +# intentionally, because kubectl cannot resolve the literal placeholder as a URL. resources: - - https://raw.githubusercontent.com/argoproj/argo-cd/v3.2.0/manifests/install.yaml + - https://raw.githubusercontent.com/argoproj/argo-cd/ARGOCD_VERSION/manifests/install.yaml patches: - path: overlays/argocd-server-service.yaml diff --git a/lib/gcp-api-mock/init.sh b/lib/gcp-api-mock/init.sh index 9c7b073a..f70f100b 100755 --- a/lib/gcp-api-mock/init.sh +++ b/lib/gcp-api-mock/init.sh @@ -1,8 +1,44 @@ #!/usr/bin/env bash set -e +help() { + echo "Usage: $0 [OPTIONS]" + echo "Options:" + echo " --help Display this help message" + echo " --version GCP API Mock version to install (required)" +} + +# Parse flags +version="" + +while [[ $# -gt 0 ]]; do + case "$1" in + --help) + help + exit 0 + ;; + --version) + if [[ -z "${2-}" ]]; then + echo "Error: --version requires a value" >&2 + exit 1 + fi + version="$2" + shift 2 + ;; + *) + echo "Unknown option: $1" >&2 + exit 1 + ;; + esac +done + +if [[ -z "$version" ]]; then + echo "Error: --version is required" >&2 + exit 1 +fi + echo "✨ Starting the GCP API Mock" -docker run -d -p 30104:8080 ghcr.io/katharinasick/gcp-api-mock:v1.1.4 +docker run -d -p 30104:8080 "ghcr.io/katharinasick/gcp-api-mock:${version}" # Set environment variable to redirect GCS backend requests to the mock echo 'export STORAGE_EMULATOR_HOST="http://localhost:30104"' >> ~/.bashrc diff --git a/lib/github-cli/init.sh b/lib/github-cli/init.sh index 0f37e9cd..cbfda1bb 100755 --- a/lib/github-cli/init.sh +++ b/lib/github-cli/init.sh @@ -4,31 +4,47 @@ set -e help() { echo "Usage: $0 [OPTIONS]" echo "Options:" - echo " --help Display this help message" - echo " --act Installs the nektos/act extension" + echo " --help Display this help message" + echo " --act Installs the nektos/act extension" + echo " --version GitHub CLI version to install (required)" } # Parse flags act=false +version="" -for arg in "$@"; do - case "$arg" in +while [[ $# -gt 0 ]]; do + case "$1" in --help) help exit 0 ;; --act) act=true + shift + ;; + --version) + if [[ -z "${2-}" ]]; then + echo "Error: --version requires a value" >&2 + exit 1 + fi + version="$2" + shift 2 ;; *) - echo "Unknown option: $arg" >&2 + echo "Unknown option: $1" >&2 exit 1 ;; esac done +if [[ -z "$version" ]]; then + echo "Error: --version is required" >&2 + exit 1 +fi + echo "✨ Installing the GitHub CLI" -curl -sS https://webi.sh/gh@v2.86.0 | sh +curl -sS "https://webi.sh/gh@${version}" | sh if [ "$act" = true ]; then echo "✨ Installin nektos/act extension" diff --git a/lib/jaeger/init.sh b/lib/jaeger/init.sh index d0e7490e..c6bb816d 100755 --- a/lib/jaeger/init.sh +++ b/lib/jaeger/init.sh @@ -3,6 +3,42 @@ set -e SCRIPT_DIR="$(dirname "$(realpath "${BASH_SOURCE[0]}")")" +help() { + echo "Usage: $0 [OPTIONS]" + echo "Options:" + echo " --help Display this help message" + echo " --version Jaeger Helm chart version to install (required)" +} + +# Parse flags +version="" + +while [[ $# -gt 0 ]]; do + case "$1" in + --help) + help + exit 0 + ;; + --version) + if [[ -z "${2-}" ]]; then + echo "Error: --version requires a value" >&2 + exit 1 + fi + version="$2" + shift 2 + ;; + *) + echo "Unknown option: $1" >&2 + exit 1 + ;; + esac +done + +if [[ -z "$version" ]]; then + echo "Error: --version is required" >&2 + exit 1 +fi + # Use a minimal Jaeger setup instead of deploying it via the operator to keep the Codespace lightweight and focused. echo "✨ Adding Jaeger Helm repo" @@ -14,7 +50,7 @@ kubectl create namespace jaeger echo "✨ Installing Jaeger via Helm" helm install jaeger jaegertracing/jaeger \ - --version 4.1.5 \ + --version "$version" \ --namespace jaeger \ --values "$SCRIPT_DIR/values.yaml" \ --wait \ diff --git a/lib/kube-state-metrics/init.sh b/lib/kube-state-metrics/init.sh index ae63beb6..c5875482 100755 --- a/lib/kube-state-metrics/init.sh +++ b/lib/kube-state-metrics/init.sh @@ -3,6 +3,42 @@ set -e SCRIPT_DIR="$(dirname "$(realpath "${BASH_SOURCE[0]}")")" +help() { + echo "Usage: $0 [OPTIONS]" + echo "Options:" + echo " --help Display this help message" + echo " --version kube-state-metrics Helm chart version to install (required)" +} + +# Parse flags +version="" + +while [[ $# -gt 0 ]]; do + case "$1" in + --help) + help + exit 0 + ;; + --version) + if [[ -z "${2-}" ]]; then + echo "Error: --version requires a value" >&2 + exit 1 + fi + version="$2" + shift 2 + ;; + *) + echo "Unknown option: $1" >&2 + exit 1 + ;; + esac +done + +if [[ -z "$version" ]]; then + echo "Error: --version is required" >&2 + exit 1 +fi + echo "✨ Adding prometheus-community Helm repo" helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update @@ -12,7 +48,7 @@ kubectl create namespace kube-state-metrics echo "✨ Installing kube-state-metrics via Helm" helm install kube-state-metrics prometheus-community/kube-state-metrics \ - --version 7.0.0 \ + --version "$version" \ --namespace kube-state-metrics \ --values "$SCRIPT_DIR/values.yaml" \ --wait \ diff --git a/lib/kubernetes/init.sh b/lib/kubernetes/init.sh index 69bd004b..102558cc 100755 --- a/lib/kubernetes/init.sh +++ b/lib/kubernetes/init.sh @@ -3,26 +3,118 @@ set -e SCRIPT_DIR="$(dirname "$(realpath "${BASH_SOURCE[0]}")")" +help() { + echo "Usage: $0 [OPTIONS]" + echo "Options:" + echo " --help Display this help message" + echo " --kind-version kind version to install (required)" + echo " --kubectl-version kubectl version to install (required)" + echo " --kubens-version kubens version to install (required)" + echo " --k9s-version k9s version to install (required)" + echo " --helm-version Helm version to install (required)" +} + +# Parse flags +kind_version="" +kubectl_version="" +kubens_version="" +k9s_version="" +helm_version="" + +while [[ $# -gt 0 ]]; do + case "$1" in + --help) + help + exit 0 + ;; + --kind-version) + if [[ -z "${2-}" ]]; then + echo "Error: --kind-version requires a value" >&2 + exit 1 + fi + kind_version="$2" + shift 2 + ;; + --kubectl-version) + if [[ -z "${2-}" ]]; then + echo "Error: --kubectl-version requires a value" >&2 + exit 1 + fi + kubectl_version="$2" + shift 2 + ;; + --kubens-version) + if [[ -z "${2-}" ]]; then + echo "Error: --kubens-version requires a value" >&2 + exit 1 + fi + kubens_version="$2" + shift 2 + ;; + --k9s-version) + if [[ -z "${2-}" ]]; then + echo "Error: --k9s-version requires a value" >&2 + exit 1 + fi + k9s_version="$2" + shift 2 + ;; + --helm-version) + if [[ -z "${2-}" ]]; then + echo "Error: --helm-version requires a value" >&2 + exit 1 + fi + helm_version="$2" + shift 2 + ;; + *) + echo "Unknown option: $1" >&2 + exit 1 + ;; + esac +done + +if [[ -z "$kind_version" ]]; then + echo "Error: --kind-version is required" >&2 + exit 1 +fi +if [[ -z "$kubectl_version" ]]; then + echo "Error: --kubectl-version is required" >&2 + exit 1 +fi +if [[ -z "$kubens_version" ]]; then + echo "Error: --kubens-version is required" >&2 + exit 1 +fi +if [[ -z "$k9s_version" ]]; then + echo "Error: --k9s-version is required" >&2 + exit 1 +fi +if [[ -z "$helm_version" ]]; then + echo "Error: --helm-version is required" >&2 + exit 1 +fi + echo "✨ Installing Kind" -curl -sS https://webi.sh/kind@v0.30.0 | sh +curl -sS "https://webi.sh/kind@${kind_version}" | sh echo "✨ Installing kubectl" -curl -LO "https://dl.k8s.io/release/v1.34.1/bin/linux/amd64/kubectl" +curl -LO "https://dl.k8s.io/release/${kubectl_version}/bin/linux/amd64/kubectl" chmod +x kubectl sudo mv kubectl /usr/local/bin/ echo "✨ Installing kubens" -curl -sS https://webi.sh/kubens@v0.9.5 | bash +curl -sS "https://webi.sh/kubens@${kubens_version}" | bash echo "✨ Installing k9s" -curl -sS https://webinstall.dev/k9s@0.50.16 | bash +curl -sS "https://webinstall.dev/k9s@${k9s_version}" | bash echo "✨ Installing Helm" -curl -LO "https://get.helm.sh/helm-v4.0.1-linux-amd64.tar.gz" -tar -zxvf helm-v4.0.1-linux-amd64.tar.gz +curl -LO "https://get.helm.sh/helm-${helm_version}-linux-amd64.tar.gz" +tar -zxvf "helm-${helm_version}-linux-amd64.tar.gz" chmod +x linux-amd64/helm sudo mv linux-amd64/helm /usr/local/bin/helm -rm -rf linux-amd64 helm-v4.0.1-linux-amd64.tar.gz +rm -rf linux-amd64 "helm-${helm_version}-linux-amd64.tar.gz" echo "✨ Starting Kind cluster" kind create cluster --config "$SCRIPT_DIR/config.yaml" --wait 300s diff --git a/lib/ollama/init.sh b/lib/ollama/init.sh index c0439521..2c6e6110 100755 --- a/lib/ollama/init.sh +++ b/lib/ollama/init.sh @@ -3,6 +3,42 @@ set -e SCRIPT_DIR="$(dirname "$(realpath "${BASH_SOURCE[0]}")")" +help() { + echo "Usage: $0 [OPTIONS]" + echo "Options:" + echo " --help Display this help message" + echo " --version Ollama Helm chart version to install (required)" +} + +# Parse flags +version="" + +while [[ $# -gt 0 ]]; do + case "$1" in + --help) + help + exit 0 + ;; + --version) + if [[ -z "${2-}" ]]; then + echo "Error: --version requires a value" >&2 + exit 1 + fi + version="$2" + shift 2 + ;; + *) + echo "Unknown option: $1" >&2 + exit 1 + ;; + esac +done + +if [[ -z "$version" ]]; then + echo "Error: --version is required" >&2 + exit 1 +fi + # Deploy Ollama to Kubernetes with TinyLlama model pre-loaded echo "✨ Adding Ollama Helm repo" @@ -11,7 +47,7 @@ helm repo update echo "✨ Installing Ollama via Helm" helm install ollama otwld/ollama \ - --version 1.40.0 \ + --version "$version" \ --namespace ollama --create-namespace \ --values "$SCRIPT_DIR/values.yaml" \ --wait \ diff --git a/lib/open-tofu/init.sh b/lib/open-tofu/init.sh index cb6da9dc..87aa0e03 100755 --- a/lib/open-tofu/init.sh +++ b/lib/open-tofu/init.sh @@ -1,13 +1,49 @@ #!/usr/bin/env bash set -e +help() { + echo "Usage: $0 [OPTIONS]" + echo "Options:" + echo " --help Display this help message" + echo " --version OpenTofu version to install (required)" +} + +# Parse flags +version="" + +while [[ $# -gt 0 ]]; do + case "$1" in + --help) + help + exit 0 + ;; + --version) + if [[ -z "${2-}" ]]; then + echo "Error: --version requires a value" >&2 + exit 1 + fi + version="$2" + shift 2 + ;; + *) + echo "Unknown option: $1" >&2 + exit 1 + ;; + esac +done + +if [[ -z "$version" ]]; then + echo "Error: --version is required" >&2 + exit 1 +fi + echo "✨ Installing Open Tofu" -curl -LO "https://github.com/opentofu/opentofu/releases/download/v1.11.2/tofu_1.11.2_linux_amd64.zip" -unzip "tofu_1.11.2_linux_amd64.zip" tofu +curl -LO "https://github.com/opentofu/opentofu/releases/download/${version}/tofu_${version#v}_linux_amd64.zip" +unzip "tofu_${version#v}_linux_amd64.zip" tofu chmod +x tofu sudo mv tofu /usr/local/bin/tofu -rm -f "tofu_1.11.2_linux_amd64.zip" +rm -f "tofu_${version#v}_linux_amd64.zip" tofu version echo "✅ Open Tofu is ready" \ No newline at end of file diff --git a/lib/otel-collector/init.sh b/lib/otel-collector/init.sh index e456a35f..b1d87ee5 100755 --- a/lib/otel-collector/init.sh +++ b/lib/otel-collector/init.sh @@ -3,11 +3,50 @@ set -e SCRIPT_DIR="$(dirname "$(realpath "${BASH_SOURCE[0]}")")" +help() { + echo "Usage: $0 [OPTIONS]" + echo "Options:" + echo " --help Display this help message" + echo " --version otel/opentelemetry-collector-contrib image tag (required)" +} + +version="" + +# Parse flags +while [[ $# -gt 0 ]]; do + case "$1" in + --help) + help + exit 0 + ;; + --version) + if [[ -z "${2-}" ]]; then + echo "Error: --version requires a value" >&2 + exit 1 + fi + version="$2" + shift 2 + ;; + *) + echo "Unknown option: $1" >&2 + exit 1 + ;; + esac +done + +if [[ -z "$version" ]]; then + echo "Error: --version is required" >&2 + exit 1 +fi + echo "✨ Creating otel namespace" kubectl create namespace otel || true -echo "✨ Deploying OTEL Collector manifests" -kubectl apply -n otel -f "$SCRIPT_DIR/manifests/" +echo "✨ Deploying OTEL Collector manifests (version ${version})" +kubectl apply -n otel -f "$SCRIPT_DIR/manifests/config.yaml" +kubectl apply -n otel -f "$SCRIPT_DIR/manifests/service.yaml" +sed "s|otel/opentelemetry-collector-contrib:.*|otel/opentelemetry-collector-contrib:${version}|" \ + "$SCRIPT_DIR/manifests/deployment.yaml" | kubectl apply -n otel -f - echo "✨ Waiting for OTEL Collector to be ready" kubectl rollout status deployment/collector -n otel --timeout=120s diff --git a/lib/otel-collector/manifests/deployment.yaml b/lib/otel-collector/manifests/deployment.yaml index d340d278..eafcb59e 100644 --- a/lib/otel-collector/manifests/deployment.yaml +++ b/lib/otel-collector/manifests/deployment.yaml @@ -20,7 +20,7 @@ spec: spec: containers: - name: collector - image: otel/opentelemetry-collector-contrib:0.142.0 + image: otel/opentelemetry-collector-contrib:0.148.0 args: - --config=/conf/collector-config.yaml ports: diff --git a/lib/prometheus/init.sh b/lib/prometheus/init.sh index 2fbfcf9b..aad739b9 100755 --- a/lib/prometheus/init.sh +++ b/lib/prometheus/init.sh @@ -6,24 +6,35 @@ SCRIPT_DIR="$(dirname "$(realpath "${BASH_SOURCE[0]}")")" help() { echo "Usage: $0 [OPTIONS]" echo "Options:" - echo " --help Display this help message" - echo " --operator Install Prometheus Operator instead of standalone Prometheus" + echo " --help Display this help message" + echo " --operator Install Prometheus Operator instead of standalone Prometheus" + echo " --version Helm chart version to install (required)" } # Parse flags use_operator=false +version="" -for arg in "$@"; do - case "$arg" in +while [[ $# -gt 0 ]]; do + case "$1" in --help) help exit 0 ;; --operator) use_operator=true + shift + ;; + --version) + if [[ -z "${2-}" ]]; then + echo "Error: --version requires a value" >&2 + exit 1 + fi + version="$2" + shift 2 ;; *) - echo "Unknown option: $arg" >&2 + echo "Unknown option: $1" >&2 exit 1 ;; esac @@ -31,6 +42,11 @@ done # Use a minimal Prometheus setup instead of kube-prometheus-stack to keep the Codespace lightweight and focused. +if [[ -z "$version" ]]; then + echo "Error: --version is required" >&2 + exit 1 +fi + echo "✨ Adding prometheus-community Helm repo" helm repo add prometheus-community https://prometheus-community.github.io/helm-charts 2>/dev/null || true helm repo update @@ -41,7 +57,7 @@ kubectl create namespace prometheus if [ "$use_operator" = true ]; then echo "✨ Installing Prometheus Operator (kube-prometheus-stack)" helm install prometheus prometheus-community/kube-prometheus-stack \ - --version 82.1.1 \ + --version "$version" \ --namespace prometheus \ --values "$SCRIPT_DIR/operator-values.yaml" \ --wait \ @@ -52,6 +68,7 @@ if [ "$use_operator" = true ]; then else echo "✨ Installing standalone Prometheus" helm install prometheus prometheus-community/prometheus \ + --version "$version" \ --namespace prometheus \ --values "$SCRIPT_DIR/standalone-values.yaml" \ --wait \ diff --git a/lib/qdrant/init.sh b/lib/qdrant/init.sh index 3574fe32..b8dc0a55 100755 --- a/lib/qdrant/init.sh +++ b/lib/qdrant/init.sh @@ -3,6 +3,42 @@ set -e SCRIPT_DIR="$(dirname "$(realpath "${BASH_SOURCE[0]}")")" +help() { + echo "Usage: $0 [OPTIONS]" + echo "Options:" + echo " --help Display this help message" + echo " --version Qdrant Helm chart version to install (required)" +} + +# Parse flags +version="" + +while [[ $# -gt 0 ]]; do + case "$1" in + --help) + help + exit 0 + ;; + --version) + if [[ -z "${2-}" ]]; then + echo "Error: --version requires a value" >&2 + exit 1 + fi + version="$2" + shift 2 + ;; + *) + echo "Unknown option: $1" >&2 + exit 1 + ;; + esac +done + +if [[ -z "$version" ]]; then + echo "Error: --version is required" >&2 + exit 1 +fi + echo "✨ Adding Qdrant Helm repo" helm repo add qdrant https://qdrant.github.io/qdrant-helm helm repo update @@ -12,7 +48,7 @@ kubectl create namespace qdrant || true echo "✨ Installing Qdrant via Helm" helm install qdrant qdrant/qdrant \ - --version 1.16.3 \ + --version "$version" \ --namespace qdrant \ --values "$SCRIPT_DIR/values.yaml" \ --wait \ diff --git a/lib/shared/init.sh b/lib/shared/init.sh index 06b4b658..03726a32 100755 --- a/lib/shared/init.sh +++ b/lib/shared/init.sh @@ -1,12 +1,48 @@ #!/usr/bin/env bash set -e +help() { + echo "Usage: $0 [OPTIONS]" + echo "Options:" + echo " --help Display this help message" + echo " --version gum version to install (required)" +} + +# Parse flags +version="" + +while [[ $# -gt 0 ]]; do + case "$1" in + --help) + help + exit 0 + ;; + --version) + if [[ -z "${2-}" ]]; then + echo "Error: --version requires a value" >&2 + exit 1 + fi + version="$2" + shift 2 + ;; + *) + echo "Unknown option: $1" >&2 + exit 1 + ;; + esac +done + +if [[ -z "$version" ]]; then + echo "Error: --version is required" >&2 + exit 1 +fi + echo "✨ Installing gum" case "$(uname -m)" in aarch64|arm64) ARCH="arm64" ;; *) ARCH="amd64" ;; esac -curl -LO "https://github.com/charmbracelet/gum/releases/download/v0.17.0/gum_0.17.0_${ARCH}.deb" -sudo apt install ./gum_0.17.0_${ARCH}.deb -rm gum_0.17.0_${ARCH}.deb +curl -LO "https://github.com/charmbracelet/gum/releases/download/${version}/gum_${version#v}_${ARCH}.deb" +sudo apt install "./gum_${version#v}_${ARCH}.deb" +rm "gum_${version#v}_${ARCH}.deb" diff --git a/scripts/new-adventure.sh b/scripts/new-adventure.sh index 3336d150..a1f78b56 100755 --- a/scripts/new-adventure.sh +++ b/scripts/new-adventure.sh @@ -347,9 +347,19 @@ source "\$REPO_ROOT/lib/scripts/tracker.sh" set_tracking_context "$selected_slug" "$level_slug" track_codespace_created -"\$REPO_ROOT/lib/shared/init.sh" - -# TODO: install & configure the tools you need by using the setup scripts located in `/lib` (e.g. "\$REPO_ROOT/lib/kubernetes/init.sh") +"\$REPO_ROOT/lib/shared/init.sh" --version v0.17.0 + +# TODO: Install and configure the tools your adventure needs using the shared setup scripts in /lib. +# Every script accepts a --version flag or per-tool version flags (e.g. kubernetes uses +# --kind-version, --kubectl-version, etc.) to pin a specific tool version — use this instead of +# editing the shared script or duplicating install logic in this file. +# +# Examples: +# "\$REPO_ROOT/lib/argocd/init.sh" --version v3.5.0 +# "\$REPO_ROOT/lib/argocd/init.sh" --read-only --version v3.5.0 +# "\$REPO_ROOT/lib/kubernetes/init.sh" --kubectl-version v1.35.0 --helm-version v4.1.0 +# +# Run any script with --help to see all available flags and their defaults. EOF cat > "$DEVCONTAINER_DIR/post-start.sh" << EOF