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
9 changes: 5 additions & 4 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,16 @@ AllCops:
- 'demos/**/tmp/**/*'
- 'demos/**/vendor/**/*'
- 'packages/shakacode_demo_common/node_modules/**/*'
- 'bin/**/*'
- 'scripts/**/*'

# Allow longer blocks in specs and Rakefiles
# Allow longer blocks in specs, Rakefiles, and bin scripts
Metrics/BlockLength:
Exclude:
- 'spec/**/*_spec.rb'
- '**/*Rakefile'
- 'Rakefile'
- '**/Rakefile'
- 'packages/shakacode_demo_common/lib/tasks/**/*.rake'
- 'bin/*'

# Allow longer methods in demo creation (complex setup)
Metrics/MethodLength:
Expand All @@ -32,9 +31,11 @@ Metrics/MethodLength:
- 'lib/demo_scripts/demo_creator.rb'
- 'lib/demo_scripts/demo_scaffolder.rb'

# Allow longer classes for demo creators (lots of setup code)
# Allow longer classes for demo creators and bin scripts (lots of setup code)
Metrics/ClassLength:
Max: 300
Exclude:
- 'bin/*'

# Allow more complex methods for demo scaffolding
Metrics/AbcSize:
Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ git clone https://github.com/shakacode/react_on_rails-demos.git
cd react_on_rails-demos

# Bootstrap all demos
./scripts/bootstrap-all.sh
bin/bootstrap-all
```

## Working with Demos
Expand Down Expand Up @@ -67,7 +67,7 @@ See the [README](./README.md#create-a-new-demo) for detailed usage examples.
Run tests for all demos:

```bash
./scripts/test-all.sh
bin/test-all
```

Run tests for a specific demo:
Expand Down
21 changes: 17 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,13 @@ See [Development Setup](./docs/CONTRIBUTING_SETUP.md) for details.
### Bootstrap All Demos

```bash
./scripts/bootstrap-all.sh
bin/bootstrap-all
```

### Run Tests Across All Demos

```bash
./scripts/test-all.sh
bin/test-all
```

### Create a New Demo
Expand Down Expand Up @@ -151,7 +151,20 @@ bin/update-all-demos --demos "demo-v16-*" --react-on-rails-version '~> 16.1'
bin/update-all-demos --help
```

**Note:** Ruby scripts (in `bin/`) are fully tested and recommended. Bash scripts (in `scripts/`) are kept for compatibility.
#### 4. `bin/apply-shared` - Apply Shared Configurations

Creates symlinks to shared configuration files and adds the shakacode_demo_common gem to all demos.

```bash
# Apply shared configs to all demos
bin/apply-shared

# Dry run mode to see what would be done
bin/apply-shared --dry-run

# Show help
bin/apply-shared --help
```

Default versions are configured in `.new-demo-versions`. Override with command-line flags.

Expand All @@ -168,7 +181,7 @@ REACT_ON_RAILS_VERSION="~> 16.0"

- Use `--shakapacker-version` and `--react-on-rails-version` flags
- Supports version constraints (`~> 8.0`) or exact versions (`8.0.0`)
- Example: `./scripts/new-demo.sh my-demo --react-on-rails-version '16.1.0'`
- Example: `bin/new-demo my-demo --react-on-rails-version '16.1.0'`

## Shared Configuration

Expand Down
121 changes: 121 additions & 0 deletions bin/apply-shared
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

require 'bundler/setup'
require_relative '../lib/demo_scripts'
require 'pathname'
require 'optparse'

module DemoScripts
# Applies shared configurations to all demos
class SharedConfigApplier < DemoManager
CONFIG_FILES = {
'.rubocop.yml' => 'config/rubocop.yml',
'eslint.config.js' => 'configs/eslint.config.js',
'prettier.config.js' => 'configs/prettier.config.js'
}.freeze

def apply!
validate_directories!

puts '🔧 Applying shared configurations to all demos...'

each_demo do |demo_path|
apply_to_demo(demo_path)
end

puts '✅ Shared configurations applied successfully!'
end

private

def validate_directories!
raise Error, 'packages/shakacode_demo_common directory not found' unless shakacode_demo_common_exists?
end

def apply_to_demo(demo_path)
puts "📦 Updating #{demo_name(demo_path)}..."
create_config_symlinks(demo_path)
update_gemfile(demo_path)
end

def create_config_symlinks(demo_path)
CONFIG_FILES.each do |target_name, source_path|
source_file = File.join(@shakacode_demo_common_path, source_path)
next unless File.exist?(source_file)

create_symlink(source_file, File.join(demo_path, target_name), target_name)
end
end

def create_symlink(source, target, name)
relative_source = calculate_relative_path(target, source)
puts " Linking #{name}..."

if @dry_run
puts " [DRY-RUN] ln -sf #{relative_source} #{target}"
else
# Use force: true for atomic symlink creation to avoid race conditions
FileUtils.ln_s(relative_source, target, force: true)
end
end

def update_gemfile(demo_path)
gemfile_path = File.join(demo_path, 'Gemfile')
return unless File.exist?(gemfile_path)

if File.read(gemfile_path).include?('shakacode_demo_common')
puts ' shakacode_demo_common already in Gemfile'
return
end

add_gem_to_gemfile(gemfile_path)
end

def add_gem_to_gemfile(gemfile_path)
puts ' Adding shakacode_demo_common to Gemfile...'
addition = <<~GEM

# Shared demo configuration and utilities
gem "shakacode_demo_common", path: "../../packages/shakacode_demo_common"
GEM

if @dry_run
puts " [DRY-RUN] Would append to #{gemfile_path}"
else
File.open(gemfile_path, 'a') { |f| f.puts addition }
end
end

def calculate_relative_path(from, to)
Pathname.new(to).relative_path_from(Pathname.new(File.dirname(from))).to_s
end
end
end

# Main execution
options = { dry_run: false }

parser = OptionParser.new do |opts|
opts.banner = 'Usage: bin/apply-shared [options]'
opts.separator ''
opts.separator 'Apply shared configurations to all demos'
opts.separator ''

opts.on('--dry-run', 'Show what would be done') { options[:dry_run] = true }
opts.on('-h', '--help', 'Show this help') do
puts opts
exit
end
end

begin
parser.parse!
DemoScripts::SharedConfigApplier.new(**options).apply!
rescue DemoScripts::Error => e
warn "Error: #{e.message}"
exit 1
rescue StandardError => e
warn "Unexpected error: #{e.message}"
exit 1
end
94 changes: 94 additions & 0 deletions bin/bootstrap-all
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

require 'bundler/setup'
require_relative '../lib/demo_scripts'
require 'optparse'

module DemoScripts
# Bootstraps all demo applications
class Bootstrapper < DemoManager
def bootstrap!
puts '🚀 Bootstrapping all React on Rails demos...'

bootstrap_shakacode_demo_common
bootstrap_demos

puts "\n✅ Bootstrap complete!"
end

private

def bootstrap_shakacode_demo_common
return unless shakacode_demo_common_exists?

puts '📦 Installing shakacode_demo_common dependencies...'
Dir.chdir(@shakacode_demo_common_path) do
install_dependencies
end
end

def bootstrap_demos
each_demo do |demo_path|
bootstrap_demo(demo_path)
end
end

def bootstrap_demo(demo_path)
puts "\n📦 Bootstrapping #{demo_name(demo_path)}..."
Dir.chdir(demo_path) do
install_dependencies
setup_database if rails?
end
end

def install_dependencies
install_ruby_dependencies if gemfile?
install_javascript_dependencies if package_json?
end

def install_ruby_dependencies
puts ' Installing Ruby dependencies...'
run_command('bundle install')
end

def install_javascript_dependencies
puts ' Installing JavaScript dependencies...'
cmd = command_exists?('pnpm') ? 'pnpm install' : 'npm install'
run_command(cmd)
end

def setup_database
puts ' Setting up database...'
run_command('bin/rails db:prepare', allow_failure: true)
end
end
end

# Main execution
options = { dry_run: false, verbose: false }

parser = OptionParser.new do |opts|
opts.banner = 'Usage: bin/bootstrap-all [options]'
opts.separator ''
opts.separator 'Bootstrap all demo applications'
opts.separator ''

opts.on('--dry-run', 'Show what would be done') { options[:dry_run] = true }
opts.on('-v', '--verbose', 'Show detailed output') { options[:verbose] = true }
opts.on('-h', '--help', 'Show this help') do
puts opts
exit
end
end

begin
parser.parse!
DemoScripts::Bootstrapper.new(**options).bootstrap!
rescue DemoScripts::Error => e
warn "Error: #{e.message}"
exit 1
rescue StandardError => e
warn "Unexpected error: #{e.message}"
exit 1
end
Loading