test-installer-files.sh 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. #!/usr/bin/env bash
  2. ###############################################################################
  3. # Installer Test Script
  4. # Simulates the installer and shows which files would fail to download
  5. # Usage: ./scripts/tests/test-installer-files.sh [--profile=<profile>] [--verbose]
  6. ###############################################################################
  7. set -e
  8. # Colors
  9. RED='\033[0;31m'
  10. GREEN='\033[0;32m'
  11. YELLOW='\033[1;33m'
  12. BLUE='\033[0;34m'
  13. CYAN='\033[0;36m'
  14. BOLD='\033[1m'
  15. NC='\033[0m'
  16. # Configuration
  17. BRANCH="main"
  18. RAW_URL="https://raw.githubusercontent.com/darrenhinde/OpenAgentsControl/${BRANCH}"
  19. TEMP_DIR="/tmp/opencode-installer-test-$$"
  20. # Allow local testing (useful for CI/CD or when testing changes before pushing)
  21. USE_LOCAL=false
  22. LOCAL_REGISTRY="./registry.json"
  23. # Global variables
  24. VERBOSE=false
  25. TEST_PROFILE=""
  26. FAILED_FILES=()
  27. SKIPPED_FILES=()
  28. SUCCESS_COUNT=0
  29. FAIL_COUNT=0
  30. # Cleanup function
  31. # shellcheck disable=SC2329
  32. cleanup() {
  33. rm -rf "$TEMP_DIR" 2>/dev/null || true
  34. }
  35. trap cleanup EXIT INT TERM
  36. # Print functions
  37. print_header() {
  38. echo -e "${CYAN}${BOLD}"
  39. echo "╔════════════════════════════════════════════════════════════════╗"
  40. echo "║ ║"
  41. echo "║ Installer File Test - v1.0.0 ║"
  42. echo "║ ║"
  43. echo "╚════════════════════════════════════════════════════════════════╝"
  44. echo -e "${NC}"
  45. }
  46. print_success() {
  47. echo -e "${GREEN}✓${NC} $1"
  48. }
  49. print_error() {
  50. echo -e "${RED}✗${NC} $1"
  51. }
  52. print_warning() {
  53. echo -e "${YELLOW}⚠${NC} $1"
  54. }
  55. print_info() {
  56. echo -e "${BLUE}ℹ${NC} $1"
  57. }
  58. print_step() {
  59. echo -e "\n${BOLD}$1${NC}"
  60. }
  61. # Check if URL is accessible
  62. check_url() {
  63. local url="$1"
  64. local component="$2"
  65. if curl -fsSL --max-time 10 -I "$url" > /dev/null 2>&1; then
  66. return 0
  67. else
  68. return 1
  69. fi
  70. }
  71. # Test a single file
  72. test_file() {
  73. local path="$1"
  74. local component="$2"
  75. local url="${RAW_URL}/${path}"
  76. if check_url "$url" "$component"; then
  77. SUCCESS_COUNT=$((SUCCESS_COUNT + 1))
  78. if [ "$VERBOSE" = true ]; then
  79. print_success "Accessible: ${path}"
  80. fi
  81. return 0
  82. else
  83. FAIL_COUNT=$((FAIL_COUNT + 1))
  84. FAILED_FILES+=("${component}|${path}")
  85. print_error "NOT FOUND: ${path}"
  86. return 1
  87. fi
  88. }
  89. # Test components from a category
  90. test_category() {
  91. local category="$1"
  92. local registry_file="$2"
  93. print_step "Testing ${category}..."
  94. local components
  95. components=$(jq -r ".components.${category}[]? | \"\(.id)|\(.path)\"" "$registry_file" 2>/dev/null || echo "")
  96. if [ -z "$components" ]; then
  97. print_warning "No components in category: ${category}"
  98. return
  99. fi
  100. while IFS='|' read -r id path; do
  101. [ -z "$id" ] && continue
  102. test_file "$path" "${category}:${id}"
  103. done <<< "$components"
  104. }
  105. # Test profile components
  106. test_profile() {
  107. local profile="$1"
  108. local registry_file="$2"
  109. print_step "Testing Profile: ${profile}"
  110. # Get components from profile
  111. local components
  112. components=$(jq -r ".profiles.${profile}.components[]?" "$registry_file" 2>/dev/null || echo "")
  113. if [ -z "$components" ]; then
  114. print_error "Profile not found or empty: ${profile}"
  115. return 1
  116. fi
  117. print_info "Profile components:"
  118. while IFS= read -r component; do
  119. [ -z "$component" ] && continue
  120. local type="${component%%:*}"
  121. local id="${component##*:}"
  122. # Handle wildcards
  123. if [[ "$id" == *"*"* ]]; then
  124. print_info " Wildcard: ${component} (expanding...)"
  125. if [ "$type" = "context" ]; then
  126. local prefix="${id%%\**}"
  127. prefix="${prefix%/}"
  128. # Find matching contexts
  129. local matches
  130. matches=$(jq -r ".components.contexts[]? | select(.path | startswith(\".opencode/context/${prefix}\")) | \"\(.id)|\(.path)\"" "$registry_file")
  131. while IFS='|' read -r match_id match_path; do
  132. [ -z "$match_id" ] && continue
  133. test_file "$match_path" "context:${match_id}"
  134. done <<< "$matches"
  135. fi
  136. continue
  137. fi
  138. # Get path for component
  139. local path
  140. path=$(jq -r ".components.${type}s[]? | select(.id == \"${id}\") | .path" "$registry_file")
  141. if [ -n "$path" ] && [ "$path" != "null" ]; then
  142. test_file "$path" "${component}"
  143. else
  144. print_warning " Component not found in registry: ${component}"
  145. SKIPPED_FILES+=("${component}|not_in_registry")
  146. fi
  147. done <<< "$components"
  148. }
  149. # Test all categories
  150. test_all() {
  151. local registry_file="$1"
  152. print_step "Testing All Component Categories"
  153. local categories=("agents" "subagents" "commands" "tools" "plugins" "skills" "contexts" "config")
  154. for category in "${categories[@]}"; do
  155. test_category "$category" "$registry_file"
  156. done
  157. }
  158. # Print summary
  159. print_summary() {
  160. echo ""
  161. echo -e "${BOLD}═══════════════════════════════════════════════════════════════${NC}"
  162. echo -e "${BOLD}Test Summary${NC}"
  163. echo -e "${BOLD}═══════════════════════════════════════════════════════════════${NC}"
  164. echo ""
  165. echo -e "Total files tested: ${CYAN}$((SUCCESS_COUNT + FAIL_COUNT))${NC}"
  166. echo -e "Files accessible: ${GREEN}${SUCCESS_COUNT}${NC}"
  167. echo -e "Files NOT FOUND: ${RED}${FAIL_COUNT}${NC}"
  168. if [ ${#SKIPPED_FILES[@]} -gt 0 ]; then
  169. echo -e "Skipped: ${YELLOW}${#SKIPPED_FILES[@]}${NC}"
  170. fi
  171. echo ""
  172. if [ $FAIL_COUNT -gt 0 ]; then
  173. print_error "Found ${FAIL_COUNT} file(s) that would FAIL during installation:"
  174. echo ""
  175. echo "Failed files:"
  176. for entry in "${FAILED_FILES[@]}"; do
  177. local component="${entry%%|*}"
  178. local path="${entry##*|}"
  179. echo " - ${component}"
  180. echo " URL: ${RAW_URL}/${path}"
  181. done
  182. echo ""
  183. echo -e "${YELLOW}These files need to be:${NC}"
  184. echo " 1. Added to the repository, OR"
  185. echo " 2. Removed from registry.json"
  186. echo ""
  187. return 1
  188. else
  189. print_success "All files are accessible and would install successfully!"
  190. return 0
  191. fi
  192. }
  193. # Usage
  194. usage() {
  195. echo "Usage: $0 [OPTIONS]"
  196. echo ""
  197. echo "Options:"
  198. echo " --profile=<name> Test a specific profile (essential, developer, business, full, advanced)"
  199. echo " --all Test all components (default)"
  200. echo " --verbose Show successful file checks"
  201. echo " --local Use local registry.json instead of downloading from GitHub"
  202. echo " --help Show this help message"
  203. echo ""
  204. echo "Examples:"
  205. echo " $0 # Test all components (remote registry)"
  206. echo " $0 --profile=essential # Test essential profile"
  207. echo " $0 --profile=developer --verbose # Test developer profile with details"
  208. echo " $0 --local # Test using local registry.json"
  209. echo ""
  210. exit 0
  211. }
  212. # Main
  213. main() {
  214. print_header
  215. # Parse arguments
  216. TEST_MODE="all"
  217. while [ $# -gt 0 ]; do
  218. case "$1" in
  219. --profile=*)
  220. TEST_PROFILE="${1#*=}"
  221. TEST_MODE="profile"
  222. ;;
  223. --profile)
  224. if [ -n "$2" ]; then
  225. TEST_PROFILE="$2"
  226. TEST_MODE="profile"
  227. shift
  228. else
  229. echo "Error: --profile requires a profile name"
  230. exit 1
  231. fi
  232. ;;
  233. --all)
  234. TEST_MODE="all"
  235. ;;
  236. --verbose)
  237. VERBOSE=true
  238. ;;
  239. --local)
  240. USE_LOCAL=true
  241. ;;
  242. --help|-h)
  243. usage
  244. ;;
  245. *)
  246. echo "Unknown option: $1"
  247. echo "Run '$0 --help' for usage information"
  248. exit 1
  249. ;;
  250. esac
  251. shift
  252. done
  253. # Check dependencies
  254. if ! command -v curl &> /dev/null; then
  255. print_error "curl is required but not installed"
  256. exit 1
  257. fi
  258. if ! command -v jq &> /dev/null; then
  259. print_error "jq is required but not installed"
  260. exit 1
  261. fi
  262. # Create temp directory
  263. mkdir -p "$TEMP_DIR"
  264. # Get registry (local or remote)
  265. if [ "$USE_LOCAL" = true ]; then
  266. print_step "Using local registry..."
  267. if [ ! -f "$LOCAL_REGISTRY" ]; then
  268. print_error "Local registry not found: $LOCAL_REGISTRY"
  269. exit 1
  270. fi
  271. cp "$LOCAL_REGISTRY" "${TEMP_DIR}/registry.json"
  272. print_success "Local registry loaded"
  273. else
  274. print_step "Downloading registry from GitHub..."
  275. if ! curl -fsSL "${RAW_URL}/registry.json" -o "${TEMP_DIR}/registry.json"; then
  276. print_error "Failed to download registry from ${RAW_URL}/registry.json"
  277. exit 1
  278. fi
  279. print_success "Registry downloaded successfully"
  280. fi
  281. # Validate registry JSON
  282. if ! jq empty "${TEMP_DIR}/registry.json" 2>/dev/null; then
  283. print_error "Registry is not valid JSON"
  284. exit 1
  285. fi
  286. # Run tests
  287. echo ""
  288. print_info "Testing file accessibility from: ${RAW_URL}"
  289. echo ""
  290. case "$TEST_MODE" in
  291. profile)
  292. if [ -z "$TEST_PROFILE" ]; then
  293. print_error "No profile specified. Use --profile=<name>"
  294. exit 1
  295. fi
  296. test_profile "$TEST_PROFILE" "${TEMP_DIR}/registry.json"
  297. ;;
  298. all)
  299. test_all "${TEMP_DIR}/registry.json"
  300. ;;
  301. esac
  302. # Print summary
  303. print_summary
  304. exit $?
  305. }
  306. main "$@"
  307. # Shellcheck validation passed