|
| 1 | +#!/bin/bash |
| 2 | +# run-pr.sh — Build & run a tilt PR in a throwaway container, with the |
| 3 | +# tilt-example-html/0-base project loaded. |
| 4 | +# |
| 5 | +# Usage: scripts/run-pr.sh <pr-number> |
| 6 | +set -euo pipefail |
| 7 | + |
| 8 | +PR_NUMBER="${1:?Usage: $0 <pr-number>}" |
| 9 | + |
| 10 | +# ---------- resolve PR via gh ----------------------------------------------- |
| 11 | +echo "==> Looking up PR #${PR_NUMBER}..." |
| 12 | +PR_JSON=$(gh pr view "$PR_NUMBER" --repo tilt-dev/tilt --json title,headRefName,headRepository,headRepositoryOwner) |
| 13 | +PR_TITLE=$(echo "$PR_JSON" | jq -r .title) |
| 14 | +PR_BRANCH=$(echo "$PR_JSON" | jq -r .headRefName) |
| 15 | +PR_OWNER=$(echo "$PR_JSON" | jq -r .headRepositoryOwner.login) |
| 16 | +PR_REPO=$(echo "$PR_JSON" | jq -r .headRepository.name) |
| 17 | +CLONE_URL="https://github.com/${PR_OWNER}/${PR_REPO}.git" |
| 18 | + |
| 19 | +echo " Title: ${PR_TITLE}" |
| 20 | +echo " Branch: ${PR_OWNER}:${PR_BRANCH}" |
| 21 | +echo " Repo: ${CLONE_URL}" |
| 22 | + |
| 23 | +IMAGE_NAME="tilt-pr-${PR_NUMBER}" |
| 24 | +CONTAINER_NAME="tilt-pr-${PR_NUMBER}-test" |
| 25 | +PORT=10350 |
| 26 | + |
| 27 | +cleanup() { |
| 28 | + echo "" |
| 29 | + echo "==> Cleaning up..." |
| 30 | + docker rm -f "$CONTAINER_NAME" 2>/dev/null || true |
| 31 | +} |
| 32 | +trap cleanup EXIT |
| 33 | + |
| 34 | +# ---------- check kubeconfig ----------------------------------------------- |
| 35 | +KUBE_CONTEXT=$(kubectl config current-context) |
| 36 | +if [[ "$KUBE_CONTEXT" != *"docker-desktop"* ]]; then |
| 37 | + echo "Error: kubeconfig context is ${KUBE_CONTEXT}" >&2 |
| 38 | + echo " This script only supports local clusters running in Docker Desktop." >&2 |
| 39 | + exit 1 |
| 40 | +fi |
| 41 | + |
| 42 | +K8S_SERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}') |
| 43 | +if [ -z "$K8S_SERVER" ]; then |
| 44 | + echo "Error: could not determine k8s server from kubeconfig." >&2 |
| 45 | + exit 1 |
| 46 | +fi |
| 47 | + |
| 48 | +K8S_HOST=$(echo "$K8S_SERVER" | sed -E 's|https?://([^:]+):.*|\1|') |
| 49 | +K8S_PORT=$(echo "$K8S_SERVER" | sed -E 's|https?://[^:]+:([0-9]+).*|\1|') |
| 50 | + |
| 51 | +if [[ "$K8S_HOST" != "127.0.0.1" && "$K8S_HOST" != "localhost" ]]; then |
| 52 | + echo "Error: kubeconfig cluster server points to ${K8S_SERVER}" >&2 |
| 53 | + echo " Expected a cluster at localhost. This script only supports local clusters." >&2 |
| 54 | + exit 1 |
| 55 | +fi |
| 56 | + |
| 57 | +echo "==> Detected k8s API at ${K8S_HOST}:${K8S_PORT}" |
| 58 | + |
| 59 | +# ---------- build ----------------------------------------------------------- |
| 60 | +docker rm -f "$CONTAINER_NAME" 2>/dev/null || true |
| 61 | + |
| 62 | +echo "==> Building tilt from PR #${PR_NUMBER} (this may take a few minutes)..." |
| 63 | + |
| 64 | +docker build -t "$IMAGE_NAME" - <<DOCKERFILE |
| 65 | +# --- Stage 1: build web assets with Node --- |
| 66 | +FROM node:20 AS web |
| 67 | +RUN git clone ${CLONE_URL} /tilt |
| 68 | +WORKDIR /tilt |
| 69 | +RUN git checkout ${PR_BRANCH} |
| 70 | +WORKDIR /tilt/web |
| 71 | +RUN corepack enable && yarn install --immutable && yarn build |
| 72 | +
|
| 73 | +# --- Stage 2: build tilt binary with Go --- |
| 74 | +FROM golang:1.25 |
| 75 | +RUN apt-get update && apt-get install -y socat && rm -rf /var/lib/apt/lists/* |
| 76 | +RUN git clone ${CLONE_URL} /tilt |
| 77 | +WORKDIR /tilt |
| 78 | +RUN git checkout ${PR_BRANCH} |
| 79 | +# Overlay the freshly-built web assets into the embed directory |
| 80 | +COPY --from=web /tilt/web/build/ pkg/assets/build/ |
| 81 | +RUN go install -mod vendor ./cmd/tilt/... |
| 82 | +
|
| 83 | +# Clone the example project that tilt will run against |
| 84 | +RUN git clone https://github.com/tilt-dev/tilt-example-html.git /tilt-example-html |
| 85 | +
|
| 86 | +WORKDIR /tilt-example-html/0-base |
| 87 | +DOCKERFILE |
| 88 | + |
| 89 | +# ---------- run -------------------------------------------------------------- |
| 90 | +echo "==> Starting tilt (web UI at http://localhost:${PORT})..." |
| 91 | + |
| 92 | +# Open the browser after tilt has a moment to start |
| 93 | +(sleep 5 && open "http://localhost:${PORT}") & |
| 94 | + |
| 95 | +# Inside the container: |
| 96 | +# - socat forwards 127.0.0.1:<k8s-port> → host.docker.internal:<k8s-port> |
| 97 | +# so the kubeconfig's localhost reference reaches the host's k8s API. |
| 98 | +# - tilt runs against the example project in the foreground. |
| 99 | +docker run -it --rm \ |
| 100 | + --name "$CONTAINER_NAME" \ |
| 101 | + -p "${PORT}:${PORT}" \ |
| 102 | + -v /var/run/docker.sock:/var/run/docker.sock \ |
| 103 | + -v "${HOME}/.kube:/root/.kube:ro" \ |
| 104 | + "$IMAGE_NAME" \ |
| 105 | + bash -c "socat TCP-LISTEN:${K8S_PORT},fork,reuseaddr,bind=127.0.0.1 TCP:host.docker.internal:${K8S_PORT} & exec tilt up --host 0.0.0.0 --web-mode=prod" |
0 commit comments