Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
730af50
Add --scratch flag to create demos in gitignored directory
justin808 Oct 5, 2025
a716bf9
Add demo metadata JSON file generation
justin808 Oct 5, 2025
7fd66d4
shakapacker main
justin808 Oct 5, 2025
c182be0
Add --force flag to Rails generators for non-interactive demo creation
justin808 Oct 5, 2025
9a2be42
Add automatic Playwright browser installation with --skip-playwright …
justin808 Oct 5, 2025
459827e
Change demo metadata format from JSON to YAML
justin808 Oct 5, 2025
f4344c5
Add --typescript flag for unified TypeScript setup
justin808 Oct 5, 2025
27caad6
Remove --force flag from shakapacker:install command
justin808 Oct 5, 2025
c762de2
Let React on Rails handle TypeScript setup
justin808 Oct 5, 2025
f461df0
Add --skip flag to react_on_rails:install to prevent interactive prompts
justin808 Oct 5, 2025
7e05fbf
Add automated testing and improve completion message
justin808 Oct 5, 2025
eb77a55
Remove conflicting files before React on Rails installation
justin808 Oct 5, 2025
589bf46
Fix: Don't delete shakapacker.yml - let React on Rails overwrite it
justin808 Oct 5, 2025
0a4f9de
Remove automated testing - requires complex background process manage…
justin808 Oct 5, 2025
01b6bfa
Use THOR_MERGE=always to prevent interactive prompts
justin808 Oct 5, 2025
735892a
Fix: Install Playwright browsers after npm install completes
justin808 Oct 5, 2025
4070abd
Add comprehensive E2E testing with Playwright
justin808 Oct 5, 2025
7809482
Fix: Remove non-existent cypress-playwright-on-rails gem dependency
justin808 Oct 5, 2025
19e990b
Fix: Add Playwright to package.json in demo_common generator
justin808 Oct 5, 2025
0339ac5
Fix: Create .gitignore if it doesn't exist in demo_common generator
justin808 Oct 5, 2025
259c11e
Add cypress-on-rails gem integration for Playwright
justin808 Oct 5, 2025
2a901e0
Let cypress-on-rails handle Playwright installation
justin808 Oct 5, 2025
ffd18c7
Fix: Use --force flag instead of THOR_MERGE environment variable
justin808 Oct 5, 2025
879ae30
Use -f instead of --force for Rails generator
justin808 Oct 5, 2025
2df1d3b
Fix code review issues: process management, YAML generation, and clarity
justin808 Oct 5, 2025
39b3d3a
Add --typescript and --skip-playwright flags to reconstruct_command
justin808 Oct 5, 2025
a8d8fcf
Update default versions to match .new-demo-versions
justin808 Oct 5, 2025
0506503
Fix e2e.rake to use File::NULL for cross-platform compatibility
justin808 Oct 5, 2025
3cf5491
Add prerelease flags to demo metadata and test coverage
justin808 Oct 5, 2025
613d1ac
Add prerelease flags to reconstruct_command and test coverage
justin808 Oct 5, 2025
ecea074
Refactor e2e.rake and add demo_name validation
justin808 Oct 5, 2025
967b38d
Fix critical process group management in E2eTestRunner
justin808 Oct 5, 2025
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ vendor/bundle/
/demos/*/public/packs-test
/demos/*/yarn-error.log

# Scratch demos (experimental/temporary demos)
/demos-scratch/

# Testing
/demos/*/coverage/
/demos/*/test/reports/
Expand Down
6 changes: 3 additions & 3 deletions .new-demo-versions
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
RAILS_VERSION="8.0.3"

# Shakapacker version (use ~> for compatibility range, or specific version)
SHAKAPACKER_VERSION="~> 8.0"
SHAKAPACKER_VERSION="github:shakacode/shakapacker"

# React on Rails version (use ~> for compatibility range, or specific version)
REACT_ON_RAILS_VERSION="~> 16.0"
REACT_ON_RAILS_VERSION="~> 16.1"

# ═══════════════════════════════════════════════════════════════════════
# Version Management Workflows
Expand All @@ -32,4 +32,4 @@ REACT_ON_RAILS_VERSION="~> 16.0"
# Updating existing demos to new versions:
# ./scripts/update-all-demos.sh --react-on-rails-version '~> 16.1'
#
# For detailed workflows, see: docs/VERSION_MANAGEMENT.md
# For detailed workflows, see: docs/VERSION_MANAGEMENT.md
10 changes: 9 additions & 1 deletion bin/new-demo
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ options = {
react_on_rails_args: [],
dry_run: false,
shakapacker_prerelease: false,
react_on_rails_prerelease: false
react_on_rails_prerelease: false,
scratch: false
}

parser = OptionParser.new do |opts|
Expand Down Expand Up @@ -66,6 +67,10 @@ parser = OptionParser.new do |opts|
options[:react_on_rails_prerelease] = true
end

opts.on('--scratch', 'Create demo in gitignored /demos-scratch directory for experimentation') do
options[:scratch] = true
end

opts.on('-h', '--help', 'Show this help message') do
puts opts
puts ''
Expand All @@ -87,6 +92,9 @@ parser = OptionParser.new do |opts|
puts ' bin/new-demo my-demo --react-on-rails-args="--redux,--node"'
puts ' bin/new-demo my-demo --rails-args="--skip-test" --react-on-rails-args="--redux"'
puts ''
puts ' # Create experimental demo in gitignored directory'
puts ' bin/new-demo my-demo --scratch'
puts ''
puts 'After creation, run E2E tests with:'
puts ' cd demos/my-demo && npx playwright test'
exit
Expand Down
65 changes: 60 additions & 5 deletions lib/demo_scripts/demo_creator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@ def initialize(
dry_run: false,
skip_pre_flight: false,
shakapacker_prerelease: false,
react_on_rails_prerelease: false
react_on_rails_prerelease: false,
scratch: false
)
@demo_name = demo_name
@demo_dir = File.join('demos', demo_name)
@scratch = scratch
demos_base_dir = scratch ? 'demos-scratch' : 'demos'
@demo_dir = File.join(demos_base_dir, demo_name)
@config = Config.new(
shakapacker_version: shakapacker_version,
react_on_rails_version: react_on_rails_version,
Expand All @@ -47,6 +50,8 @@ def create!
end
puts ''

@creation_start_time = Time.now

create_rails_app
setup_database
add_gems
Expand All @@ -58,6 +63,7 @@ def create!
build_github_npm_packages if using_github_sources?
create_readme
cleanup_unnecessary_files
create_metadata_file

print_completion_message
end
Expand Down Expand Up @@ -303,13 +309,13 @@ def copy_built_package(temp_dir, gem_name)
def install_shakapacker
puts ''
puts '📦 Installing Shakapacker...'
@runner.run!('bin/rails shakapacker:install', dir: @demo_dir)
@runner.run!('bin/rails shakapacker:install --force', dir: @demo_dir)
end

def install_react_on_rails
puts ''
puts '📦 Installing React on Rails (skipping git check)...'
base_args = ['--ignore-warnings']
base_args = ['--ignore-warnings', '--force']
all_args = (base_args + @react_on_rails_args).join(' ')
@runner.run!(
"bin/rails generate react_on_rails:install #{all_args}",
Expand All @@ -320,7 +326,7 @@ def install_react_on_rails
def install_demo_common_generator
puts ''
puts '📦 Installing demo common tools (Playwright, linting, git hooks)...'
@runner.run!('bin/rails generate shakacode_demo_common:install', dir: @demo_dir)
@runner.run!('bin/rails generate shakacode_demo_common:install --force', dir: @demo_dir)
end

def create_readme
Expand Down Expand Up @@ -399,6 +405,55 @@ def generate_readme_content
README
end

def create_metadata_file
puts ''
puts '📝 Creating demo metadata file...'

return if @dry_run

shakapacker_github = @config.shakapacker_version&.start_with?('github:')
react_on_rails_github = @config.react_on_rails_version&.start_with?('github:')

metadata = {
demo_name: @demo_name,
demo_directory: @demo_dir,
scratch_mode: @scratch,
created_at: @creation_start_time.iso8601,
versions: {
rails: @config.rails_version,
shakapacker: @config.shakapacker_version,
react_on_rails: @config.react_on_rails_version
},
options: {
rails_args: @rails_args,
react_on_rails_args: @react_on_rails_args,
shakapacker_prerelease: shakapacker_github ? false : nil,
react_on_rails_prerelease: react_on_rails_github ? false : nil
}.compact,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Metadata drops prerelease intent.

shakapacker_prerelease / react_on_rails_prerelease are never recorded as true; the hash inserts false for GitHub specs and drops everything else via .compact. If a demo was generated with --shakapacker-prerelease or --react-on-rails-prerelease, the emitted metadata now misrepresents those options, so readers can’t reconstruct the original command accurately. Please persist the actual flag values (e.g., store the incoming booleans or expose them from Config) instead of the current hard-coded false/nil logic.

🤖 Prompt for AI Agents
In lib/demo_scripts/demo_creator.rb around lines 437 to 441, the code forces
shakapacker_prerelease/react_on_rails_prerelease to false for GitHub specs and
then .compact removes nils, losing any true flags; change it to persist the
actual boolean inputs (use the incoming flag variables or read from Config) so
the hash stores true/false explicitly and do not allow .compact to drop false
values for these keys (or build the hash to always include these keys with their
real boolean values) so emitted metadata accurately reflects the original CLI
flags.

command: reconstruct_command,
ruby_version: RUBY_VERSION,
bundler_version: Gem::Version.new(Bundler::VERSION).to_s
}

metadata_path = File.join(@demo_dir, '.demo-metadata.json')
File.write(metadata_path, JSON.pretty_generate(metadata))
puts " Created #{metadata_path}"
end

def reconstruct_command
cmd_parts = ["bin/new-demo #{@demo_name}"]
cmd_parts << '--scratch' if @scratch
if @config.shakapacker_version != Config::DEFAULT_SHAKAPACKER_VERSION
cmd_parts << "--shakapacker-version=\"#{@config.shakapacker_version}\""
end
if @config.react_on_rails_version != Config::DEFAULT_REACT_ON_RAILS_VERSION
cmd_parts << "--react-on-rails-version=\"#{@config.react_on_rails_version}\""
end
cmd_parts << "--rails-args=\"#{@rails_args.join(',')}\"" if @rails_args.any?
cmd_parts << "--react-on-rails-args=\"#{@react_on_rails_args.join(',')}\"" if @react_on_rails_args.any?
cmd_parts.join(' ')
end

def print_completion_message
puts ''
if @dry_run
Expand Down
136 changes: 136 additions & 0 deletions spec/demo_scripts/demo_creator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,27 @@

expect(creator).to be_a(described_class)
end

it 'uses demos directory by default' do
creator = described_class.new(
demo_name: demo_name,
dry_run: true,
skip_pre_flight: true
)

expect(creator.instance_variable_get(:@demo_dir)).to eq("demos/#{demo_name}")
end

it 'uses demos-scratch directory when scratch flag is true' do
creator = described_class.new(
demo_name: demo_name,
scratch: true,
dry_run: true,
skip_pre_flight: true
)

expect(creator.instance_variable_get(:@demo_dir)).to eq("demos-scratch/#{demo_name}")
end
end

describe '#create!' do
Expand Down Expand Up @@ -521,4 +542,119 @@
dry_run_creator.send(:cleanup_unnecessary_files)
end
end

describe '#create_metadata_file' do
subject(:creator) do
described_class.new(
demo_name: demo_name,
shakapacker_version: 'github:shakacode/shakapacker@main',
react_on_rails_version: '~> 16.0',
rails_args: ['--skip-test'],
react_on_rails_args: ['--redux', '--typescript'],
scratch: true,
dry_run: false,
skip_pre_flight: true
)
end

it 'creates metadata JSON file with correct structure' do
creator.instance_variable_set(:@creation_start_time, Time.now)
scratch_demo_dir = 'demos-scratch/test-demo'
metadata_path = File.join(scratch_demo_dir, '.demo-metadata.json')

expect(File).to receive(:write).with(metadata_path, anything)

creator.send(:create_metadata_file)
end

it 'includes all required metadata fields' do
creator.instance_variable_set(:@creation_start_time, Time.new(2025, 1, 1, 12, 0, 0, '+00:00'))
scratch_demo_dir = 'demos-scratch/test-demo'
metadata_path = File.join(scratch_demo_dir, '.demo-metadata.json')

allow(File).to receive(:write) do |path, content|
expect(path).to eq(metadata_path)
metadata = JSON.parse(content)

expect(metadata['demo_name']).to eq('test-demo')
expect(metadata['demo_directory']).to eq('demos-scratch/test-demo')
expect(metadata['scratch_mode']).to be true
expect(metadata['created_at']).to match(/2025-01-01T12:00:00/)
expect(metadata['versions']['shakapacker']).to eq('github:shakacode/shakapacker@main')
expect(metadata['versions']['react_on_rails']).to eq('~> 16.0')
expect(metadata['options']['rails_args']).to eq(['--skip-test'])
expect(metadata['options']['react_on_rails_args']).to eq(['--redux', '--typescript'])
expect(metadata['command']).to include('--scratch')
expect(metadata['ruby_version']).to eq(RUBY_VERSION)
end

creator.send(:create_metadata_file)
end

it 'does not create file in dry-run mode' do
dry_run_creator = described_class.new(
demo_name: demo_name,
dry_run: true,
skip_pre_flight: true
)
dry_run_creator.instance_variable_set(:@creation_start_time, Time.now)

expect(File).not_to receive(:write)

dry_run_creator.send(:create_metadata_file)
end
end

describe '#reconstruct_command' do
it 'reconstructs basic command' do
creator = described_class.new(
demo_name: demo_name,
dry_run: true,
skip_pre_flight: true
)

command = creator.send(:reconstruct_command)
expect(command).to eq('bin/new-demo test-demo')
end

it 'includes scratch flag when enabled' do
creator = described_class.new(
demo_name: demo_name,
scratch: true,
dry_run: true,
skip_pre_flight: true
)

command = creator.send(:reconstruct_command)
expect(command).to include('--scratch')
end

it 'includes custom version arguments' do
creator = described_class.new(
demo_name: demo_name,
shakapacker_version: 'github:shakacode/shakapacker@main',
react_on_rails_version: '~> 16.1',
dry_run: true,
skip_pre_flight: true
)

command = creator.send(:reconstruct_command)
expect(command).to include('--shakapacker-version="github:shakacode/shakapacker@main"')
expect(command).to include('--react-on-rails-version="~> 16.1"')
end

it 'includes rails and react-on-rails args' do
creator = described_class.new(
demo_name: demo_name,
rails_args: ['--skip-test', '--api'],
react_on_rails_args: ['--redux', '--typescript'],
dry_run: true,
skip_pre_flight: true
)

command = creator.send(:reconstruct_command)
expect(command).to include('--rails-args="--skip-test,--api"')
expect(command).to include('--react-on-rails-args="--redux,--typescript"')
end
end
end