cloudflare/vinext
Publicmirrored fromhttps://github.com/cloudflare/vinextAvailable
scripts/test-repos.sh
225lines · modecode
| 1 | #!/usr/bin/env bash |
| 2 | set -euo pipefail |
| 3 | |
| 4 | # Test vinext against ecosystem repos from .github/repos.json |
| 5 | # Usage: ./scripts/test-repos.sh |
| 6 | # |
| 7 | # Clones each repo, installs vinext, runs build + dev server smoke test |
| 8 | # (hits the index page). All repos run in parallel. Results summarized at the end. |
| 9 | |
| 10 | SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" |
| 11 | ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" |
| 12 | VINEXT_PKG="$ROOT_DIR/packages/vinext" |
| 13 | WORK_DIR="$ROOT_DIR/.ecosystem-test" |
| 14 | REPOS_JSON="$ROOT_DIR/.github/repos.json" |
| 15 | RESULTS_DIR="$WORK_DIR/results" |
| 16 | MAX_PARALLEL=4 |
| 17 | DEV_SERVER_TIMEOUT=30 # seconds to wait for dev server to respond |
| 18 | |
| 19 | # Colors |
| 20 | RED='\033[0;31m' |
| 21 | GREEN='\033[0;32m' |
| 22 | YELLOW='\033[0;33m' |
| 23 | BOLD='\033[1m' |
| 24 | NC='\033[0m' |
| 25 | |
| 26 | log() { echo -e "${BOLD}[$1]${NC} $2"; } |
| 27 | pass() { echo -e "${GREEN}PASS${NC} $1"; } |
| 28 | fail() { echo -e "${RED}FAIL${NC} $1"; } |
| 29 | warn() { echo -e "${YELLOW}WARN${NC} $1"; } |
| 30 | |
| 31 | cleanup() { |
| 32 | # Kill any leftover dev servers |
| 33 | if [[ -f "$WORK_DIR/pids" ]]; then |
| 34 | while read -r pid; do |
| 35 | kill "$pid" 2>/dev/null || true |
| 36 | done < "$WORK_DIR/pids" |
| 37 | rm -f "$WORK_DIR/pids" |
| 38 | fi |
| 39 | } |
| 40 | trap cleanup EXIT |
| 41 | |
| 42 | # Parse repos.json |
| 43 | repos=$(jq -c '.[]' "$REPOS_JSON") |
| 44 | repo_count=$(echo "$repos" | wc -l | tr -d ' ') |
| 45 | |
| 46 | echo "" |
| 47 | echo -e "${BOLD}vinext ecosystem test${NC}" |
| 48 | echo -e "Testing $repo_count repos from .github/repos.json" |
| 49 | echo "" |
| 50 | |
| 51 | # Clean previous run |
| 52 | rm -rf "$WORK_DIR" |
| 53 | mkdir -p "$WORK_DIR" "$RESULTS_DIR" |
| 54 | touch "$WORK_DIR/pids" |
| 55 | |
| 56 | test_repo() { |
| 57 | local name="$1" |
| 58 | local url="$2" |
| 59 | local repo_dir="$WORK_DIR/$name" |
| 60 | local log_file="$RESULTS_DIR/$name.log" |
| 61 | local result_file="$RESULTS_DIR/$name.result" |
| 62 | |
| 63 | { |
| 64 | echo "clone=fail" |
| 65 | echo "install=skip" |
| 66 | echo "vinext_install=skip" |
| 67 | echo "build=skip" |
| 68 | echo "dev=skip" |
| 69 | } > "$result_file" |
| 70 | |
| 71 | exec > "$log_file" 2>&1 |
| 72 | |
| 73 | echo "=== Testing $name ===" |
| 74 | echo "URL: $url" |
| 75 | echo "" |
| 76 | |
| 77 | # Clone |
| 78 | echo "--- clone ---" |
| 79 | if ! git clone --depth 1 "$url" "$repo_dir"; then |
| 80 | echo "FAILED: git clone" |
| 81 | return 1 |
| 82 | fi |
| 83 | sed -i '' 's/^clone=.*/clone=pass/' "$result_file" |
| 84 | |
| 85 | cd "$repo_dir" |
| 86 | |
| 87 | # Install deps |
| 88 | echo "" |
| 89 | echo "--- install ---" |
| 90 | sed -i '' 's/^install=.*/install=fail/' "$result_file" |
| 91 | if ! npm install --legacy-peer-deps 2>&1; then |
| 92 | echo "FAILED: npm install" |
| 93 | return 1 |
| 94 | fi |
| 95 | sed -i '' 's/^install=.*/install=pass/' "$result_file" |
| 96 | |
| 97 | # Install vinext from local build |
| 98 | echo "" |
| 99 | echo "--- install vinext ---" |
| 100 | sed -i '' 's/^vinext_install=.*/vinext_install=fail/' "$result_file" |
| 101 | if ! npm install --legacy-peer-deps "$VINEXT_PKG" 2>&1; then |
| 102 | echo "FAILED: npm install vinext" |
| 103 | return 1 |
| 104 | fi |
| 105 | sed -i '' 's/^vinext_install=.*/vinext_install=pass/' "$result_file" |
| 106 | |
| 107 | # Build |
| 108 | echo "" |
| 109 | echo "--- build ---" |
| 110 | sed -i '' 's/^build=.*/build=fail/' "$result_file" |
| 111 | if npm run build 2>&1; then |
| 112 | sed -i '' 's/^build=.*/build=pass/' "$result_file" |
| 113 | else |
| 114 | echo "FAILED: npm run build" |
| 115 | # Don't return — still try dev server |
| 116 | fi |
| 117 | |
| 118 | # Dev server smoke test |
| 119 | echo "" |
| 120 | echo "--- dev server ---" |
| 121 | sed -i '' 's/^dev=.*/dev=fail/' "$result_file" |
| 122 | |
| 123 | # Find an available port |
| 124 | local port=$((3100 + RANDOM % 900)) |
| 125 | |
| 126 | # Start dev server in background |
| 127 | PORT=$port npx vinext dev --port "$port" & |
| 128 | local dev_pid=$! |
| 129 | echo "$dev_pid" >> "$WORK_DIR/pids" |
| 130 | |
| 131 | # Wait for the server to respond |
| 132 | local started=false |
| 133 | for i in $(seq 1 "$DEV_SERVER_TIMEOUT"); do |
| 134 | if curl -sf -o /dev/null "http://localhost:$port" 2>/dev/null; then |
| 135 | started=true |
| 136 | break |
| 137 | fi |
| 138 | sleep 1 |
| 139 | done |
| 140 | |
| 141 | if $started; then |
| 142 | # Fetch the page and check we got HTML |
| 143 | local status |
| 144 | status=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:$port" 2>/dev/null || echo "000") |
| 145 | echo "Dev server responded with HTTP $status" |
| 146 | if [[ "$status" =~ ^[23] ]]; then |
| 147 | sed -i '' 's/^dev=.*/dev=pass/' "$result_file" |
| 148 | fi |
| 149 | else |
| 150 | echo "Dev server did not respond within ${DEV_SERVER_TIMEOUT}s" |
| 151 | fi |
| 152 | |
| 153 | # Kill dev server |
| 154 | kill "$dev_pid" 2>/dev/null || true |
| 155 | wait "$dev_pid" 2>/dev/null || true |
| 156 | } |
| 157 | |
| 158 | # Run repos in parallel with limited concurrency |
| 159 | pids=() |
| 160 | names=() |
| 161 | idx=0 |
| 162 | |
| 163 | while IFS= read -r repo; do |
| 164 | name=$(echo "$repo" | jq -r '.name') |
| 165 | url=$(echo "$repo" | jq -r '.url') |
| 166 | |
| 167 | log "$name" "starting..." |
| 168 | test_repo "$name" "$url" & |
| 169 | pids+=($!) |
| 170 | names+=("$name") |
| 171 | idx=$((idx + 1)) |
| 172 | |
| 173 | # Throttle parallelism |
| 174 | if (( ${#pids[@]} >= MAX_PARALLEL )); then |
| 175 | wait "${pids[0]}" 2>/dev/null || true |
| 176 | pids=("${pids[@]:1}") |
| 177 | fi |
| 178 | done <<< "$repos" |
| 179 | |
| 180 | # Wait for remaining |
| 181 | for pid in "${pids[@]}"; do |
| 182 | wait "$pid" 2>/dev/null || true |
| 183 | done |
| 184 | |
| 185 | # Print results |
| 186 | echo "" |
| 187 | echo -e "${BOLD}============================================${NC}" |
| 188 | echo -e "${BOLD} Results${NC}" |
| 189 | echo -e "${BOLD}============================================${NC}" |
| 190 | echo "" |
| 191 | |
| 192 | printf "%-30s %-8s %-8s %-10s %-8s %-8s\n" "REPO" "CLONE" "INSTALL" "VINEXT" "BUILD" "DEV" |
| 193 | printf "%-30s %-8s %-8s %-10s %-8s %-8s\n" "----" "-----" "-------" "------" "-----" "---" |
| 194 | |
| 195 | pass_count=0 |
| 196 | fail_count=0 |
| 197 | |
| 198 | for result_file in "$RESULTS_DIR"/*.result; do |
| 199 | name=$(basename "$result_file" .result) |
| 200 | clone=$(grep '^clone=' "$result_file" | cut -d= -f2) |
| 201 | install=$(grep '^install=' "$result_file" | cut -d= -f2) |
| 202 | vinext_install=$(grep '^vinext_install=' "$result_file" | cut -d= -f2) |
| 203 | build=$(grep '^build=' "$result_file" | cut -d= -f2) |
| 204 | dev=$(grep '^dev=' "$result_file" | cut -d= -f2) |
| 205 | |
| 206 | # Colorize |
| 207 | c_clone=$([[ "$clone" == "pass" ]] && echo -e "${GREEN}pass${NC}" || echo -e "${RED}$clone${NC}") |
| 208 | c_install=$([[ "$install" == "pass" ]] && echo -e "${GREEN}pass${NC}" || echo -e "${RED}$install${NC}") |
| 209 | c_vinext=$([[ "$vinext_install" == "pass" ]] && echo -e "${GREEN}pass${NC}" || echo -e "${RED}$vinext_install${NC}") |
| 210 | c_build=$([[ "$build" == "pass" ]] && echo -e "${GREEN}pass${NC}" || echo -e "${YELLOW}$build${NC}") |
| 211 | c_dev=$([[ "$dev" == "pass" ]] && echo -e "${GREEN}pass${NC}" || echo -e "${RED}$dev${NC}") |
| 212 | |
| 213 | printf "%-30s %-17s %-17s %-19s %-17s %-17s\n" "$name" "$c_clone" "$c_install" "$c_vinext" "$c_build" "$c_dev" |
| 214 | |
| 215 | if [[ "$dev" == "pass" ]]; then |
| 216 | pass_count=$((pass_count + 1)) |
| 217 | else |
| 218 | fail_count=$((fail_count + 1)) |
| 219 | fi |
| 220 | done |
| 221 | |
| 222 | echo "" |
| 223 | echo -e "${GREEN}$pass_count passed${NC}, ${RED}$fail_count failed${NC} out of $repo_count repos" |
| 224 | echo "" |
| 225 | echo "Logs: $RESULTS_DIR/*.log" |