Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 53 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@ During this transition:

Git hooks are installed automatically when you run the standard setup commands. They will run automatic linting on **all changed files (staged + unstaged + untracked)** - making commits fast while preventing CI failures.

- After cloning the repo, run `bin/setup` from the root directory to install all dependencies.

- After updating code via Git, to prepare all examples:

```sh
cd react_on_rails/
bundle && pnpm install && rake shakapacker_examples:gen_all && rake node_package && rake
```

See [Dev Initial Setup](#dev-initial-setup) below for, well... initial setup,
See [Dev Initial Setup](#dev-initial-setup) below for initial setup details,
and [Running tests](#running-tests) for more details on running tests.

# IDE/IDE SETUP
Expand Down Expand Up @@ -199,9 +200,57 @@ or the equivalent command for your package manager.

## Dev Initial Setup

### Prereqs
### Quick Setup (Recommended)

After checking out the repo and ensuring you have Ruby and Node version managers set up (such as rvm and nvm, or rbenv and nodenv, etc.) with the correct versions active, run:

```sh
# First, verify your versions match the project requirements
ruby -v # Should show 3.4.x or version in .ruby-version
node -v # Should show 22.x or version in .node-version

# Then run the setup script
bin/setup

# Or skip Pro setup (for contributors without Pro access)
bin/setup --skip-pro
```

This single command installs all dependencies across the monorepo:

- Root pnpm and bundle dependencies
- Builds the node package
- Sets up `react_on_rails/spec/dummy`
- Sets up `react_on_rails_pro` (if present)
- Sets up `react_on_rails_pro/spec/dummy` (if present)
- Sets up `react_on_rails_pro/spec/execjs-compatible-dummy` (if present)

### Manual Setup (Alternative)

If you prefer to set up manually or need more control:

1. Install root dependencies:

```sh
bundle install
pnpm install
```

2. Build the node package:

```sh
rake node_package
```

3. Set up the dummy app:

```sh
cd react_on_rails/spec/dummy
bundle install
pnpm install
```

After checking out the repo, making sure you have Ruby and Node version managers set up (such as rvm and nvm, or rbenv and nodenv, etc.), cd to `react_on_rails/spec/dummy` and run `bin/setup` to install ruby dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
You can also run `bin/console` for an interactive prompt that will allow you to experiment.

### Local Node Package

Expand Down
284 changes: 284 additions & 0 deletions bin/setup
Original file line number Diff line number Diff line change
@@ -0,0 +1,284 @@
#!/usr/bin/env bash
#
# bin/setup - Unified development environment setup for React on Rails
#
# This script installs all dependencies across all directories in the monorepo,
# making it easy for new contributors to get started quickly.
#
# Usage:
# bin/setup # Full setup of all packages
# bin/setup --skip-pro # Skip Pro package setup
# bin/setup --help # Show this help message
#

set -euo pipefail

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Script directory (for running from anywhere)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"

# Track start time for elapsed time display
START_TIME=$(date +%s)

# Flags
SKIP_PRO=false

show_help() {
echo "Usage: bin/setup [OPTIONS]"
echo ""
echo "Sets up the React on Rails development environment by installing"
echo "all dependencies across the monorepo."
echo ""
echo "Options:"
echo " --skip-pro Skip react_on_rails_pro setup (for contributors without Pro access)"
echo " --help Show this help message"
echo ""
echo "This script will:"
echo " 1. Install root pnpm and bundle dependencies"
echo " 2. Build the node package"
echo " 3. Set up react_on_rails/spec/dummy"
echo " 4. Set up react_on_rails_pro (if present and not skipped)"
echo " 5. Set up react_on_rails_pro/spec/dummy (if present and not skipped)"
echo " 6. Set up react_on_rails_pro/spec/execjs-compatible-dummy (if present and not skipped)"
}

print_step() {
echo -e "\n${BLUE}==>${NC} ${GREEN}$1${NC}"
}

print_warning() {
echo -e "${YELLOW}Warning:${NC} $1"
}

print_error() {
echo -e "${RED}Error:${NC} $1"
}

print_success() {
echo -e "${GREEN}✓${NC} $1"
}

check_prerequisites() {
local missing=()

if ! command -v pnpm &> /dev/null; then
missing+=("pnpm")
fi

if ! command -v bundle &> /dev/null; then
missing+=("bundler")
fi

if ! command -v node &> /dev/null; then
missing+=("node")
fi

if ! command -v ruby &> /dev/null; then
missing+=("ruby")
fi

if [ ${#missing[@]} -ne 0 ]; then
print_error "Missing required tools: ${missing[*]}"
echo ""
echo "Please install the following before running this script:"
for tool in "${missing[@]}"; do
case $tool in
pnpm)
echo " - pnpm: https://pnpm.io/installation"
;;
bundler)
echo " - bundler: gem install bundler"
;;
node)
echo " - node: https://nodejs.org/ (or use nvm/nodenv)"
;;
ruby)
echo " - ruby: https://www.ruby-lang.org/ (or use rvm/rbenv)"
;;
esac
done
exit 1
fi

# Display versions found
echo " Ruby: $(ruby -v | head -1)"
echo " Node: $(node -v)"
echo " pnpm: $(pnpm -v)"
echo " Bundler: $(bundle -v)"
}

verify_root_directory() {
if [ ! -f "$ROOT_DIR/Rakefile" ]; then
print_error "Rakefile not found. Are you in the correct directory?"
print_error "Expected location: $ROOT_DIR/Rakefile"
exit 1
fi

if [ ! -f "$ROOT_DIR/package.json" ]; then
print_error "package.json not found. Are you in the correct directory?"
print_error "Expected location: $ROOT_DIR/package.json"
exit 1
fi
}

install_dependencies() {
local dir="$1"
local name="$2"

if [ ! -d "$dir" ]; then
print_warning "Directory not found: $dir (skipping)"
return 0
fi

print_step "Setting up $name..."
cd "$dir"

# Install Ruby dependencies if Gemfile exists
if [ -f "Gemfile" ]; then
echo " Installing Ruby dependencies..."
if bundle check &> /dev/null; then
print_success "Ruby dependencies already satisfied"
else
if ! bundle install; then
print_error "Failed to install Ruby dependencies in $name"
exit 1
fi
print_success "Ruby dependencies installed"
fi
fi

# Install JS dependencies if package.json exists
# Use --frozen-lockfile to match CI behavior and ensure lockfile integrity
if [ -f "package.json" ]; then
echo " Installing JavaScript dependencies..."
if ! pnpm install --frozen-lockfile; then
print_error "Failed to install JavaScript dependencies in $name"
exit 1
fi
print_success "JavaScript dependencies installed"
fi

cd "$ROOT_DIR"
}

build_node_package() {
# Builds TypeScript packages and runs pnpm yalc:publish for local development.
# This compiles node_package/src/ to lib/ and makes packages available locally.
print_step "Building node package..."
if ! rake node_package; then
print_error "Failed to build node package"
exit 1
fi
print_success "Node package built"
}

verify_build_artifacts() {
print_step "Verifying build artifacts..."

local artifact="packages/react-on-rails/lib/ReactOnRails.full.js"
if [ ! -f "$ROOT_DIR/$artifact" ]; then
print_error "Build failed: $artifact not found"
print_error "Expected location: $ROOT_DIR/$artifact"
exit 1
fi
print_success "Build artifacts verified"
}

show_elapsed_time() {
local END_TIME=$(date +%s)
local ELAPSED=$((END_TIME - START_TIME))
local MINUTES=$((ELAPSED / 60))
local SECONDS=$((ELAPSED % 60))

if [ $MINUTES -gt 0 ]; then
echo -e "Total time: ${BLUE}${MINUTES}m ${SECONDS}s${NC}"
else
echo -e "Total time: ${BLUE}${SECONDS}s${NC}"
fi
}

main() {
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
--help|-h)
show_help
exit 0
;;
--skip-pro)
SKIP_PRO=true
shift
;;
*)
print_error "Unknown option: $1"
echo "Run 'bin/setup --help' for usage information."
exit 1
;;
esac
done

echo -e "${GREEN}Setting up React on Rails development environment...${NC}"
echo ""

cd "$ROOT_DIR"

# Verify we're in the correct directory
print_step "Verifying project directory..."
verify_root_directory
print_success "Project directory verified"

# Check prerequisites
print_step "Checking prerequisites..."
check_prerequisites
print_success "All prerequisites found"

# Root dependencies
install_dependencies "$ROOT_DIR" "root directory"

# Build node package
build_node_package

# Verify build artifacts
verify_build_artifacts

# react_on_rails/spec/dummy
install_dependencies "$ROOT_DIR/react_on_rails/spec/dummy" "react_on_rails/spec/dummy"

# react_on_rails_pro (if present and not skipped)
if [ "$SKIP_PRO" = true ]; then
print_warning "Skipping react_on_rails_pro setup (--skip-pro flag)"
elif [ -d "$ROOT_DIR/react_on_rails_pro" ]; then
install_dependencies "$ROOT_DIR/react_on_rails_pro" "react_on_rails_pro"

# react_on_rails_pro/spec/dummy
install_dependencies "$ROOT_DIR/react_on_rails_pro/spec/dummy" "react_on_rails_pro/spec/dummy"

# react_on_rails_pro/spec/execjs-compatible-dummy
install_dependencies "$ROOT_DIR/react_on_rails_pro/spec/execjs-compatible-dummy" "react_on_rails_pro/spec/execjs-compatible-dummy"
fi

echo ""
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN}Setup complete!${NC}"
echo -e "${GREEN}========================================${NC}"
show_elapsed_time
echo ""
echo "Git hooks have been automatically installed during setup."
echo "They will run linting on changed files before each commit."
echo ""
echo "You can now run:"
echo " rake # Run all tests"
echo " rake lint # Run linters"
echo " rake all_but_examples # Run tests (excluding generator examples)"
echo ""
echo "For more information, see CONTRIBUTING.md"
}

main "$@"
Loading