From a522988b9691f29dbc385e5b5d1d3ecfa153f642 Mon Sep 17 00:00:00 2001 From: James Wade Date: Mon, 2 Mar 2026 16:50:54 +0000 Subject: [PATCH] Add Makefile for local setup and expand README troubleshooting - Add Makefile with setup, dev, install, fix-ipv6, clean-bundle, dev-kill targets - Update .env.local.example: PORT=3000 (avoid macOS AirPlay conflict) - Set .ruby-version to 3.3.5 - Expand README troubleshooting: port conflicts, IPv6/bundle timeout, git gem PathError, Ruby version Made-with: Cursor --- .env.local.example | 5 +- .ruby-version | 2 +- Makefile | 206 +++++++++++++++++++++++++++++++++++++++++++++ README.md | 18 ++++ 4 files changed, 228 insertions(+), 3 deletions(-) create mode 100644 Makefile diff --git a/.env.local.example b/.env.local.example index be8b6b5..c89a159 100644 --- a/.env.local.example +++ b/.env.local.example @@ -1,5 +1,6 @@ -PORT=5000 -APP_HOST=http://localhost:5000 +# 3000 avoids macOS AirPlay Receiver which uses 5000 +PORT=3000 +APP_HOST=http://localhost:3000 GITHUB_KEY= GITHUB_SECRET= GOOGLE_CLIENT_ID= diff --git a/.ruby-version b/.ruby-version index f13c6f4..fa7adc7 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -ruby-3.3.5 +3.3.5 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..cdbc728 --- /dev/null +++ b/Makefile @@ -0,0 +1,206 @@ +.PHONY: install-prereqs check install env setup dev dev-kill test lint security db-reset db-migrate clean clean-bundle reinstall-ruby validate-network fix-ipv6 debug-network help + +export PATH := $(HOME)/.rbenv/shims:$(HOME)/.rbenv/bin:$(PATH) +RBENV := export PATH="$$HOME/.rbenv/shims:$$HOME/.rbenv/bin:$$PATH" && + +# Default target - full setup to get up and running +setup: install-prereqs install env + @echo "" + @echo "== Preparing database ==" + @$(RBENV) bin/rails db:prepare + @echo "" + @echo "== Clearing old logs and temp files ==" + @$(RBENV) bin/rails log:clear tmp:clear + @echo "" + @echo "Setup complete! Run 'make dev' to start the development server." + @echo "" + @if command -v rbenv >/dev/null 2>&1 && ! grep -q 'rbenv init' ~/.zshrc 2>/dev/null; then \ + echo "Tip: Add rbenv to your shell by running:"; \ + echo " echo 'eval \"\$$(rbenv init -)\"' >> ~/.zshrc && source ~/.zshrc"; \ + echo ""; \ + fi + +help: + @echo "Quez - Quiz App" + @echo "" + @echo "Quick start:" + @echo " make Full setup (install deps, env, database)" + @echo " make dev Start development server (web + worker)" + @echo "" + @echo "Setup:" + @echo " make install-prereqs Install Ruby, rbenv, libvips (macOS)" + @echo " make check Verify prerequisites (does not install)" + @echo " make env Copy .env.local.example to .env.local if missing" + @echo " make install Install Ruby gems" + @echo " make setup Run full setup (installs everything)" + @echo "" + @echo "Development:" + @echo " make dev Start Foreman (web server + background worker)" + @echo " make dev-kill Kill process on dev port (fixes 'Address already in use')" + @echo "" + @echo "Database:" + @echo " make db-migrate Run database migrations" + @echo " make db-reset Reset and prepare database" + @echo "" + @echo "Quality:" + @echo " make test Run test suite" + @echo " make lint Run Rubocop" + @echo " make security Run Brakeman + importmap audit" + @echo "" + @echo "Maintenance:" + @echo " make clean Remove logs, temp files, caches" + @echo " make clean-bundle Clear bundler cache (fixes git gem PathError)" + @echo "" + @echo "Troubleshooting (macOS bundle install timeout):" + @echo " make validate-network Check Ruby can reach rubygems.org" + @echo " make fix-ipv6 Set IPv6 to link-local only (fixes timeout)" + @echo " make debug-network Full diagnostics" + +# Install all prerequisites (rbenv, Ruby, libvips, bundler) +install-prereqs: + @echo "== Installing prerequisites ==" + @REQUIRED_RAW=$$(cat .ruby-version 2>/dev/null || echo "3.3.5"); \ + REQUIRED=$${REQUIRED_RAW#ruby-}; \ + \ + if [ "$$(uname -s)" = "Darwin" ]; then \ + if ! command -v rbenv >/dev/null 2>&1; then \ + echo "Installing rbenv and ruby-build..."; \ + brew install rbenv ruby-build || { echo "Error: Homebrew required. Install from https://brew.sh"; exit 1; }; \ + fi; \ + if ! rbenv versions --bare 2>/dev/null | grep -q "^$$REQUIRED$$"; then \ + echo "Installing Ruby $$REQUIRED (this may take a few minutes)..."; \ + rbenv install -s $$REQUIRED || { echo "Error: Failed to install Ruby $$REQUIRED"; exit 1; }; \ + fi; \ + echo "$$REQUIRED" > .ruby-version; \ + rbenv rehash 2>/dev/null || true; \ + if ! command -v vips >/dev/null 2>&1 && ! command -v convert >/dev/null 2>&1; then \ + echo "Installing libvips for image processing..."; \ + brew install vips || true; \ + fi; \ + else \ + echo "Non-macOS detected. Please ensure Ruby $$REQUIRED, bundler, and libvips are installed."; \ + echo " rbenv: https://github.com/rbenv/rbenv"; \ + echo " asdf: https://asdf-vm.com/"; \ + CURRENT=$$(ruby -e 'puts RUBY_VERSION' 2>/dev/null || echo "none"); \ + if [ "$$CURRENT" != "$$REQUIRED" ]; then \ + echo "Error: Ruby $$REQUIRED required, found $$CURRENT"; exit 1; \ + fi; \ + fi + @echo "Verifying Ruby..." + @$(RBENV) ruby -v && \ + ($(RBENV) bundle --version >/dev/null 2>&1 || (echo "Installing bundler..." && $(RBENV) gem install bundler)) && \ + $(RBENV) bundle -v && \ + echo "Prerequisites OK" + +# Verify prerequisites (does not install) +check: + @echo "== Checking prerequisites ==" + @command -v ruby >/dev/null 2>&1 || (echo "Error: Ruby not found" && exit 1) + @REQUIRED_RAW=$$(cat .ruby-version 2>/dev/null || echo "3.3.5"); \ + REQUIRED=$${REQUIRED_RAW#ruby-}; \ + CURRENT=$$(ruby -e 'puts RUBY_VERSION' 2>/dev/null); \ + if [ "$$CURRENT" != "$$REQUIRED" ]; then \ + echo "Error: Ruby $$REQUIRED required (see .ruby-version), but found $$CURRENT"; exit 1; \ + fi + @ruby -v && bundle -v + @(command -v vips >/dev/null 2>&1 || command -v convert >/dev/null 2>&1) || (echo "Warning: libvips/imagemagick not found - image processing may fail" && exit 1) + @echo "All prerequisites OK" + +# Copy env example to .env.local if it doesn't exist +env: + @if [ ! -f .env.local ]; then \ + cp .env.local.example .env.local; \ + echo "Created .env.local from .env.local.example"; \ + echo "Edit .env.local to add GITHUB_KEY, GITHUB_SECRET, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET for OAuth"; \ + else \ + echo ".env.local already exists"; \ + fi + +# Install Ruby dependencies +install: install-prereqs + @echo "== Installing dependencies ==" + @$(RBENV) bundle config --local timeout 300 + @$(RBENV) bundle config --local retry 5 + @$(RBENV) bundle check || $(RBENV) bundle install + +# Start development server (Foreman: web + worker) +dev: + @echo "== Starting development server ==" + ./bin/dev + +# Kill process on dev port - shows what's running and prompts before killing +dev-kill: + @PORT=$$(grep -E '^PORT=' .env.local 2>/dev/null | cut -d= -f2 || echo 3000); \ + PID=$$(lsof -ti:$$PORT 2>/dev/null); \ + if [ -z "$$PID" ]; then \ + echo "No process on port $$PORT"; \ + else \ + echo "Process using port $$PORT:"; \ + lsof -i:$$PORT 2>/dev/null | head -5; \ + echo ""; \ + printf "Kill it? [y/N] "; read -r reply < /dev/tty; \ + case "$$reply" in [yY][eE][sS]|[yY]) \ + kill $$PID 2>/dev/null || kill -9 $$PID 2>/dev/null; \ + echo "Killed ($$PID)"; \ + ;; *) echo "Aborted"; ;; \ + esac; \ + fi + +# Run tests +test: + bin/rails db:test:prepare test + +# Run Rubocop linter +lint: + bin/rubocop + +# Run security checks (Brakeman + importmap audit) +security: + @echo "== Running Brakeman security scan ==" + bin/brakeman --no-pager + @echo "" + @echo "== Auditing JavaScript dependencies ==" + bin/importmap audit + +# Run database migrations +db-migrate: + bin/rails db:migrate + +# Reset database +db-reset: + bin/rails db:reset + +# Clean logs, tmp, and caches +clean: + bin/rails log:clear tmp:clear + @echo "Cleaned logs and temp files" + +# Check Ruby can reach rubygems.org (detects macOS IPv6 issue) +validate-network: + @if $(RBENV) ruby -rnet/http -ruri -e 'uri=URI("https://rubygems.org/"); Net::HTTP.start(uri.host, uri.port, use_ssl: true, open_timeout: 10, read_timeout: 10) { |h| h.get("/") }; exit 0' 2>/dev/null; then \ + echo "Validation OK: Ruby can reach rubygems.org"; \ + elif curl -sf --connect-timeout 5 -o /dev/null https://rubygems.org/ 2>/dev/null; then \ + echo "Validation FAILED: curl works but Ruby cannot reach rubygems.org"; \ + echo "This is likely the macOS IPv6 issue. Fix: make fix-ipv6"; \ + echo " (or System Preferences > Network > Advanced > TCP/IP > IPv6: Link-local only)"; \ + echo " https://rob.co.bb/posts/2018-10-22-yak-shave-gem-install-issue/"; \ + exit 1; \ + else \ + echo "Validation FAILED: Cannot reach rubygems.org (check network)"; \ + exit 1; \ + fi + +# Fix macOS IPv6 issue: set to link-local only (requires sudo) +fix-ipv6: + @SERVICE="$${SERVICE:-Wi-Fi}"; \ + if networksetup -listallnetworkservices 2>/dev/null | grep -q "$$SERVICE"; then \ + echo "Setting IPv6 to link-local for $$SERVICE (requires sudo)..."; \ + sudo networksetup -setv6LinkLocal "$$SERVICE"; \ + echo "Done. Run 'make validate-network' to verify."; \ + else \ + echo "Service '$$SERVICE' not found. Available:"; \ + networksetup -listallnetworkservices 2>/dev/null || true; \ + echo ""; \ + echo "Try: make fix-ipv6 SERVICE=\"Ethernet\""; \ + exit 1; \ + fi diff --git a/README.md b/README.md index ec1c940..58c89d7 100644 --- a/README.md +++ b/README.md @@ -42,3 +42,21 @@ Run Rubocop via: ``` ./bin/rubocop ``` + +## Troubleshooting + +**Port 5000 in use** +macOS uses port 5000 for AirPlay Receiver. The default is now 3000. If you have an existing `.env.local` with `PORT=5000`, change it to `PORT=3000` and `APP_HOST=http://localhost:3000`. +[More info](https://nono.ma/port-5000-used-by-control-center-in-macos-controlce) + +**bundle install times out (but curl works)** +On macOS, Ruby's Net::HTTP can hang when IPv6 is enabled. + +CLI fix (recommended): +```bash +make fix-ipv6 +``` +Or for Ethernet: `make fix-ipv6 SERVICE="Ethernet"` + +GUI fix: System Preferences → Network → Advanced → TCP/IP → Configure IPv6: **Link-local only** +[More info](https://rob.co.bb/posts/2018-10-22-yak-shave-gem-install-issue/)