railstart 0.2.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +55 -0
- data/README.md +86 -0
- data/config/presets/vite-bun.yaml +59 -0
- data/config/rails8_defaults.yaml +35 -5
- data/lib/railstart/cli.rb +13 -0
- data/lib/railstart/command_builder.rb +17 -1
- data/lib/railstart/config.rb +27 -6
- data/lib/railstart/errors.rb +3 -0
- data/lib/railstart/generator.rb +39 -7
- data/lib/railstart/template_runner.rb +77 -0
- data/lib/railstart/version.rb +1 -1
- data/lib/railstart.rb +1 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 675d33f74310aa870ad6a167cbd585cc643b3e37096d255732bcf900fa7ab65d
|
|
4
|
+
data.tar.gz: 460628c266ba316d4ad19e148b9e8044912865c98f6c091dd8a1be25653dab71
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 344c0860107725a5a56e88bf108a7e7a73891da7f0f7678850af5c47469ed63f91c8c22de71743dc68747557f7d34aac2d001814033dee29533f5b343d8b7e0d
|
|
7
|
+
data.tar.gz: 2252beeb778c40a048e1156aebd1786a904fa7cf5edec89fd89d924265b223ff742024ceee8491d5b2a5b459a8a560047be60e43a85c13d771ee96db6edd978a
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,61 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.4.0] - 2025-11-22
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- CLI `--preset` flag now accepts explicit `.yaml`/`.yml` file paths in addition to preset names.
|
|
12
|
+
- **Template post-actions**: New `type: template` post-action type for executing full Rails application templates
|
|
13
|
+
- **TemplateRunner**: New `Railstart::TemplateRunner` class wraps Rails' AppGenerator to run templates with proper context
|
|
14
|
+
- **Template variables**: Template actions support `variables` hash for injecting custom instance variables into templates
|
|
15
|
+
- **Built-in variables**: Templates automatically receive `@app_name` and `@answers` instance variables
|
|
16
|
+
- **Template DSL support**: Full access to Rails template DSL (`gem`, `route`, `initializer`, `after_bundle`, etc.)
|
|
17
|
+
- **Error handling**: New `Railstart::TemplateError` for template execution failures with proper error wrapping
|
|
18
|
+
- **Config validation**: Validation for template post-actions (requires `source`, validates `variables` as Hash)
|
|
19
|
+
- **Documentation**: README section explaining template post-actions vs command actions with security guidance
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
- **Post-action processing**: Refactored to support both command and template execution types
|
|
23
|
+
- **Directory context**: `run_post_actions` now uses block form of `Dir.chdir` for proper scoping
|
|
24
|
+
- **Config validation**: Enhanced `validate_post_action_entry` to handle multiple action types
|
|
25
|
+
|
|
26
|
+
### Technical
|
|
27
|
+
- New file: `lib/railstart/template_runner.rb` (77 lines, full YARD docs)
|
|
28
|
+
- New test file: `test/template_runner_test.rb` (comprehensive coverage with mocks)
|
|
29
|
+
- Enhanced `lib/railstart/generator.rb` with template execution flow
|
|
30
|
+
- Enhanced `lib/railstart/config.rb` with template action validation
|
|
31
|
+
- Version bump: 0.3.0 → 0.4.0
|
|
32
|
+
- All tests pass (39 runs, 111 assertions, 0 failures)
|
|
33
|
+
- RuboCop clean (20 files inspected, no offenses)
|
|
34
|
+
|
|
35
|
+
## [0.3.0] - 2025-11-22
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
- **CSS framework**: Added Sass option to CSS framework choices
|
|
39
|
+
- **CSS framework**: Added "None (skip CSS setup)" option for skipping CSS configuration
|
|
40
|
+
- **JavaScript bundler**: Added Bun as a JavaScript bundler option (Rails 8 native support)
|
|
41
|
+
- **JavaScript bundler**: Added Vite (via vite_rails gem) with automatic post-installation setup
|
|
42
|
+
- **JavaScript bundler**: Added "None (skip JavaScript)" option using `--skip-javascript` flag
|
|
43
|
+
- **Test framework**: New test framework selection question (Minitest default, RSpec option)
|
|
44
|
+
- **Post-action**: RSpec automatic setup (`bundle add rspec-rails` + `rails generate rspec:install`) when selected
|
|
45
|
+
- **Post-action**: Vite Rails automatic setup (`bundle add vite_rails` + `bundle exec vite install`) when selected
|
|
46
|
+
- **Post-action**: Bundlebun optional setup (`bundle add bundlebun` + `rake bun:install`) for Bun packaged as a gem
|
|
47
|
+
- **Preset**: New `vite-bun.yaml` preset for modern frontend with Vite + Bundlebun (use with `--preset vite-bun`)
|
|
48
|
+
- **Command builder**: Choice-level `rails_flag` support for SELECT questions
|
|
49
|
+
- **Command builder**: Different choices can now have different flags or no flag at all
|
|
50
|
+
- **Tests**: Comprehensive test coverage for choice-level rails_flag feature
|
|
51
|
+
|
|
52
|
+
### Changed
|
|
53
|
+
- **JavaScript question**: Renamed prompt from "Which JavaScript bundler?" to "Which JavaScript approach?"
|
|
54
|
+
- **Command builder**: SELECT questions now check for choice-level flags before falling back to question-level flags
|
|
55
|
+
- **Command builder**: Vite choice doesn't add any rails flag (handled via post-action instead)
|
|
56
|
+
- **Config**: JavaScript choices now use choice-level `rails_flag` instead of question-level for flexibility
|
|
57
|
+
|
|
58
|
+
### Technical
|
|
59
|
+
- Enhanced `CommandBuilder.process_select` to support per-choice flag configuration
|
|
60
|
+
- Backward compatible with existing configs using question-level flags
|
|
61
|
+
- All tests pass (33 runs, 97 assertions, 0 failures)
|
|
62
|
+
- Rubocop clean (no offenses)
|
|
8
63
|
|
|
9
64
|
## [0.2.1] - 2025-11-22
|
|
10
65
|
|
data/README.md
CHANGED
|
@@ -141,6 +141,70 @@ railstart new my_app --preset api-only
|
|
|
141
141
|
railstart new my_app --preset api-only --default
|
|
142
142
|
```
|
|
143
143
|
|
|
144
|
+
## Creating Custom Presets
|
|
145
|
+
|
|
146
|
+
Presets are powerful tools for defining opinionated Rails configurations for specific stacks or team standards. For comprehensive guidance on creating presets, see **[Creating Presets Guide](docs/railstart-preset-builder/SKILL.md)**.
|
|
147
|
+
|
|
148
|
+
### Quick Preset Creation
|
|
149
|
+
|
|
150
|
+
Create a new preset file in `config/presets/{name}.yaml`:
|
|
151
|
+
|
|
152
|
+
```yaml
|
|
153
|
+
---
|
|
154
|
+
# My Team Preset - PostgreSQL + RSpec + Vite
|
|
155
|
+
|
|
156
|
+
questions:
|
|
157
|
+
- id: database
|
|
158
|
+
choices:
|
|
159
|
+
- name: PostgreSQL
|
|
160
|
+
value: postgresql
|
|
161
|
+
default: true
|
|
162
|
+
|
|
163
|
+
- id: javascript
|
|
164
|
+
choices:
|
|
165
|
+
- name: Vite (via vite_rails gem)
|
|
166
|
+
value: vite
|
|
167
|
+
default: true
|
|
168
|
+
|
|
169
|
+
- id: test_framework
|
|
170
|
+
choices:
|
|
171
|
+
- name: RSpec
|
|
172
|
+
value: rspec
|
|
173
|
+
default: true
|
|
174
|
+
|
|
175
|
+
post_actions:
|
|
176
|
+
- id: setup_vite
|
|
177
|
+
enabled: true
|
|
178
|
+
|
|
179
|
+
- id: setup_rspec
|
|
180
|
+
enabled: true
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Then use it:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
railstart new myapp --preset my-team
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Built-in Presets
|
|
190
|
+
|
|
191
|
+
Railstart includes several ready-to-use presets:
|
|
192
|
+
|
|
193
|
+
- **`default`** - PostgreSQL + Tailwind + Importmap (sensible defaults)
|
|
194
|
+
- **`api-only`** - Minimal Rails for JSON APIs (no views, no frontend)
|
|
195
|
+
- **`vite-bun`** - Modern SPA with Vite + Bundlebun
|
|
196
|
+
|
|
197
|
+
### Learn More
|
|
198
|
+
|
|
199
|
+
For detailed documentation including:
|
|
200
|
+
- Available questions and post-actions
|
|
201
|
+
- ID-based merging system
|
|
202
|
+
- Step-by-step workflow
|
|
203
|
+
- Real-world examples
|
|
204
|
+
- Best practices and troubleshooting
|
|
205
|
+
|
|
206
|
+
See the comprehensive **[Creating Presets Guide](docs/railstart-preset-builder/SKILL.md)**.
|
|
207
|
+
|
|
144
208
|
## Configuration
|
|
145
209
|
|
|
146
210
|
### Initialize Configuration Files
|
|
@@ -245,6 +309,28 @@ post_actions:
|
|
|
245
309
|
equals: value # or includes: [array, values]
|
|
246
310
|
```
|
|
247
311
|
|
|
312
|
+
#### Template Post-Actions
|
|
313
|
+
|
|
314
|
+
Post-actions can now execute full Rails application templates (including [RailsBytes scripts](https://railsbytes.com)) instead of plain shell commands.
|
|
315
|
+
|
|
316
|
+
```yaml
|
|
317
|
+
post_actions:
|
|
318
|
+
- id: apply_tailwind_dash
|
|
319
|
+
name: "Apply Tailwind dashboard template"
|
|
320
|
+
type: template
|
|
321
|
+
enabled: false # keep disabled unless you trust the source
|
|
322
|
+
prompt: "Run the sample template?"
|
|
323
|
+
source: "https://railsbytes.com/script/zAasQK"
|
|
324
|
+
variables:
|
|
325
|
+
app_label: "internal-tools" # optional instance variables available inside template
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Key differences from `command` actions:
|
|
329
|
+
|
|
330
|
+
- Set `type: template` and provide a `source` (local path or URL). Railstart streams that template into Rails' own `apply` helper, so all standard DSL commands (`gem`, `route`, `after_bundle`, etc.) are available.
|
|
331
|
+
- `variables` is optional; when present, its keys become instance variables accessible from the template (e.g., `@app_label`). Railstart always exposes `@app_name` and `@answers` for convenience.
|
|
332
|
+
- Template actions still honor `prompt`, `default`, and `if` just like command actions. Keep remote templates disabled by default unless you explicitly trust them.
|
|
333
|
+
|
|
248
334
|
## Development
|
|
249
335
|
|
|
250
336
|
### Setup
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
# Vite + Bundlebun Preset - Modern frontend with Vite and Bun packaged as a gem
|
|
3
|
+
# This preset configures Rails with Vite for fast HMR and Bundlebun for unified JavaScript runtime
|
|
4
|
+
|
|
5
|
+
questions:
|
|
6
|
+
- id: database
|
|
7
|
+
choices:
|
|
8
|
+
- name: PostgreSQL
|
|
9
|
+
value: postgresql
|
|
10
|
+
default: true
|
|
11
|
+
|
|
12
|
+
- id: css
|
|
13
|
+
choices:
|
|
14
|
+
- name: Tailwind
|
|
15
|
+
value: tailwind
|
|
16
|
+
default: true
|
|
17
|
+
|
|
18
|
+
- id: javascript
|
|
19
|
+
choices:
|
|
20
|
+
- name: Vite (via vite_rails gem)
|
|
21
|
+
value: vite
|
|
22
|
+
default: true
|
|
23
|
+
|
|
24
|
+
- id: test_framework
|
|
25
|
+
choices:
|
|
26
|
+
- name: Minitest (default)
|
|
27
|
+
value: minitest
|
|
28
|
+
default: true
|
|
29
|
+
|
|
30
|
+
- id: skip_features
|
|
31
|
+
default: []
|
|
32
|
+
|
|
33
|
+
- id: api_only
|
|
34
|
+
default: false
|
|
35
|
+
|
|
36
|
+
- id: skip_git
|
|
37
|
+
default: true
|
|
38
|
+
|
|
39
|
+
- id: skip_docker
|
|
40
|
+
default: false
|
|
41
|
+
|
|
42
|
+
- id: skip_bundle
|
|
43
|
+
default: false
|
|
44
|
+
|
|
45
|
+
post_actions:
|
|
46
|
+
- id: setup_vite
|
|
47
|
+
name: "Setup Vite Rails"
|
|
48
|
+
enabled: true
|
|
49
|
+
command: "bundle add vite_rails && bundle install && bundle exec vite install"
|
|
50
|
+
|
|
51
|
+
- id: setup_bundlebun
|
|
52
|
+
name: "Setup Bundlebun (Bun packaged as a gem)"
|
|
53
|
+
enabled: true
|
|
54
|
+
command: "bundle add bundlebun && bundle install && bundle exec rake bun:install"
|
|
55
|
+
|
|
56
|
+
- id: init_git
|
|
57
|
+
name: "Initialize git repository"
|
|
58
|
+
enabled: true
|
|
59
|
+
command: "git init && git add . && git commit -m 'Initial commit with Vite + Bundlebun'"
|
data/config/rails8_defaults.yaml
CHANGED
|
@@ -30,24 +30,35 @@ questions:
|
|
|
30
30
|
value: bulma
|
|
31
31
|
- name: PostCSS (no framework)
|
|
32
32
|
value: postcss
|
|
33
|
-
- name:
|
|
33
|
+
- name: Sass
|
|
34
|
+
value: sass
|
|
35
|
+
- name: None (skip CSS setup)
|
|
34
36
|
value: none
|
|
35
37
|
rails_flag: "--css=%{value}"
|
|
36
38
|
|
|
37
39
|
- id: javascript
|
|
38
40
|
type: select
|
|
39
|
-
prompt: "Which JavaScript
|
|
41
|
+
prompt: "Which JavaScript approach?"
|
|
40
42
|
choices:
|
|
41
43
|
- name: Importmap (default)
|
|
42
44
|
value: importmap
|
|
43
45
|
default: true
|
|
46
|
+
rails_flag: "--javascript=importmap"
|
|
47
|
+
- name: Bun
|
|
48
|
+
value: bun
|
|
49
|
+
rails_flag: "--javascript=bun"
|
|
44
50
|
- name: esbuild
|
|
45
51
|
value: esbuild
|
|
46
|
-
|
|
47
|
-
value: webpack
|
|
52
|
+
rails_flag: "--javascript=esbuild"
|
|
48
53
|
- name: Rollup
|
|
49
54
|
value: rollup
|
|
50
|
-
|
|
55
|
+
rails_flag: "--javascript=rollup"
|
|
56
|
+
- name: Webpack
|
|
57
|
+
value: webpack
|
|
58
|
+
rails_flag: "--javascript=webpack"
|
|
59
|
+
- name: None (skip JavaScript)
|
|
60
|
+
value: none
|
|
61
|
+
rails_flag: "--skip-javascript"
|
|
51
62
|
|
|
52
63
|
- id: skip_features
|
|
53
64
|
type: multi_select
|
|
@@ -102,6 +113,17 @@ questions:
|
|
|
102
113
|
default: false
|
|
103
114
|
rails_flag: "--skip-bundle"
|
|
104
115
|
|
|
116
|
+
- id: test_framework
|
|
117
|
+
type: select
|
|
118
|
+
prompt: "Which test framework?"
|
|
119
|
+
choices:
|
|
120
|
+
- name: Minitest (default)
|
|
121
|
+
value: minitest
|
|
122
|
+
default: true
|
|
123
|
+
- name: RSpec
|
|
124
|
+
value: rspec
|
|
125
|
+
rails_flag: "--skip-test"
|
|
126
|
+
|
|
105
127
|
post_actions:
|
|
106
128
|
- id: init_git
|
|
107
129
|
name: "Initialize git repository"
|
|
@@ -122,3 +144,11 @@ post_actions:
|
|
|
122
144
|
question: skip_bundle
|
|
123
145
|
equals: true
|
|
124
146
|
command: "bundle install"
|
|
147
|
+
|
|
148
|
+
- id: setup_rspec
|
|
149
|
+
name: "Setup RSpec"
|
|
150
|
+
enabled: true
|
|
151
|
+
if:
|
|
152
|
+
question: test_framework
|
|
153
|
+
equals: rspec
|
|
154
|
+
command: "bundle add rspec-rails --group development,test && bundle exec rails generate rspec:install"
|
data/lib/railstart/cli.rb
CHANGED
|
@@ -237,6 +237,10 @@ module Railstart
|
|
|
237
237
|
end
|
|
238
238
|
|
|
239
239
|
def preset_file_for(name)
|
|
240
|
+
if (direct_path = explicit_preset_path(name))
|
|
241
|
+
return direct_path
|
|
242
|
+
end
|
|
243
|
+
|
|
240
244
|
# Check user presets first
|
|
241
245
|
user_path = File.join(PRESET_DIR, "#{name}.yaml")
|
|
242
246
|
return user_path if File.exist?(user_path)
|
|
@@ -319,5 +323,14 @@ module Railstart
|
|
|
319
323
|
enabled: true
|
|
320
324
|
YAML
|
|
321
325
|
end
|
|
326
|
+
|
|
327
|
+
def explicit_preset_path(name)
|
|
328
|
+
return unless name&.match?(/\.ya?ml\z/)
|
|
329
|
+
|
|
330
|
+
expanded = File.expand_path(name)
|
|
331
|
+
return expanded if File.exist?(expanded)
|
|
332
|
+
|
|
333
|
+
raise Railstart::ConfigLoadError, "Preset file '#{name}' not found"
|
|
334
|
+
end
|
|
322
335
|
end
|
|
323
336
|
end
|
|
@@ -42,13 +42,29 @@ module Railstart
|
|
|
42
42
|
|
|
43
43
|
def process_question_flags(flags, question, answer)
|
|
44
44
|
case question["type"]
|
|
45
|
-
when "select"
|
|
45
|
+
when "select"
|
|
46
|
+
process_select(flags, question, answer)
|
|
47
|
+
when "yes_no", "input"
|
|
46
48
|
add_flags(flags, question, answer)
|
|
47
49
|
when "multi_select"
|
|
48
50
|
process_multi_select(flags, question, answer)
|
|
49
51
|
end
|
|
50
52
|
end
|
|
51
53
|
|
|
54
|
+
def process_select(flags, question, answer)
|
|
55
|
+
# Check if the selected choice has a choice-level rails_flag
|
|
56
|
+
selected_choice = Array(question["choices"]).find { |choice| choice["value"] == answer }
|
|
57
|
+
|
|
58
|
+
if selected_choice && (selected_choice["rails_flag"] || selected_choice["rails_flags"])
|
|
59
|
+
# Use choice-level flag
|
|
60
|
+
add_flags(flags, selected_choice, answer)
|
|
61
|
+
elsif question["rails_flag"] || question["rails_flags"]
|
|
62
|
+
# Fall back to question-level flag
|
|
63
|
+
add_flags(flags, question, answer)
|
|
64
|
+
end
|
|
65
|
+
# If neither exists, no flag is added (e.g., for choices that don't need flags)
|
|
66
|
+
end
|
|
67
|
+
|
|
52
68
|
def process_multi_select(flags, question, answer)
|
|
53
69
|
Array(question["choices"]).each do |choice|
|
|
54
70
|
next unless Array(answer).include?(choice["value"])
|
data/lib/railstart/config.rb
CHANGED
|
@@ -197,12 +197,7 @@ module Railstart
|
|
|
197
197
|
|
|
198
198
|
issues.concat(validate_question_choices(entry, id || index)) if CHOICE_REQUIRED_TYPES.include?(type)
|
|
199
199
|
elsif name == "post_actions"
|
|
200
|
-
if entry.fetch("enabled", true)
|
|
201
|
-
command = entry["command"] || entry[:command]
|
|
202
|
-
if command.nil? || command.to_s.strip.empty?
|
|
203
|
-
issues << "Post-action #{id || index} is enabled but missing a command"
|
|
204
|
-
end
|
|
205
|
-
end
|
|
200
|
+
issues.concat(validate_post_action_entry(entry, id || index)) if entry.fetch("enabled", true)
|
|
206
201
|
|
|
207
202
|
if_condition = entry["if"] || entry[:if]
|
|
208
203
|
if if_condition.is_a?(Hash)
|
|
@@ -246,6 +241,32 @@ module Railstart
|
|
|
246
241
|
issues
|
|
247
242
|
end
|
|
248
243
|
|
|
244
|
+
def validate_post_action_entry(entry, identifier)
|
|
245
|
+
action_type = (entry["type"] || entry[:type] || "command").to_s
|
|
246
|
+
|
|
247
|
+
case action_type
|
|
248
|
+
when "command"
|
|
249
|
+
command = entry["command"] || entry[:command]
|
|
250
|
+
if command.nil? || command.to_s.strip.empty?
|
|
251
|
+
["Post-action #{identifier} is enabled but missing a command"]
|
|
252
|
+
else
|
|
253
|
+
[]
|
|
254
|
+
end
|
|
255
|
+
when "template"
|
|
256
|
+
issues = []
|
|
257
|
+
source = entry["source"] || entry[:source]
|
|
258
|
+
if source.nil? || source.to_s.strip.empty?
|
|
259
|
+
issues << "Post-action #{identifier} is a template but missing a source"
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
variables = entry["variables"] || entry[:variables]
|
|
263
|
+
issues << "Post-action #{identifier} template variables must be a Hash" if variables && !variables.is_a?(Hash)
|
|
264
|
+
issues
|
|
265
|
+
else
|
|
266
|
+
["Post-action #{identifier} has unsupported type '#{action_type}'"]
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
|
|
249
270
|
def deep_dup(value)
|
|
250
271
|
case value
|
|
251
272
|
when Hash
|
data/lib/railstart/errors.rb
CHANGED
data/lib/railstart/generator.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "tty-prompt"
|
|
4
4
|
require_relative "ui"
|
|
5
|
+
require_relative "template_runner"
|
|
5
6
|
|
|
6
7
|
module Railstart
|
|
7
8
|
# Orchestrates the interactive Rails app generation flow.
|
|
@@ -221,20 +222,30 @@ module Railstart
|
|
|
221
222
|
end
|
|
222
223
|
|
|
223
224
|
def run_post_actions
|
|
224
|
-
Dir.chdir(@app_name)
|
|
225
|
+
Dir.chdir(@app_name) do
|
|
226
|
+
template_runner = nil
|
|
225
227
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
228
|
+
Array(@config["post_actions"]).each do |action|
|
|
229
|
+
template_runner ||= TemplateRunner.new(app_path: Dir.pwd) if template_action?(action)
|
|
230
|
+
process_post_action(action, template_runner)
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
puts
|
|
234
|
+
UI.success("Rails app created successfully at ./#{@app_name}")
|
|
235
|
+
end
|
|
229
236
|
rescue Errno::ENOENT
|
|
230
237
|
UI.warning("Could not change to app directory. Post-actions skipped.")
|
|
231
238
|
end
|
|
232
239
|
|
|
233
|
-
def process_post_action(action)
|
|
240
|
+
def process_post_action(action, template_runner)
|
|
234
241
|
return unless should_run_action?(action)
|
|
235
242
|
return unless confirm_action?(action)
|
|
236
243
|
|
|
237
|
-
|
|
244
|
+
if template_action?(action)
|
|
245
|
+
run_template_action(action, template_runner)
|
|
246
|
+
else
|
|
247
|
+
run_command_action(action)
|
|
248
|
+
end
|
|
238
249
|
end
|
|
239
250
|
|
|
240
251
|
def confirm_action?(action)
|
|
@@ -243,12 +254,33 @@ module Railstart
|
|
|
243
254
|
@prompt.yes?(action["prompt"], default: action.fetch("default", true))
|
|
244
255
|
end
|
|
245
256
|
|
|
246
|
-
def
|
|
257
|
+
def run_command_action(action)
|
|
247
258
|
UI.info(action["name"].to_s)
|
|
248
259
|
success = system(action["command"])
|
|
249
260
|
UI.warning("Post-action '#{action["name"]}' failed. Continuing anyway.") unless success
|
|
250
261
|
end
|
|
251
262
|
|
|
263
|
+
def run_template_action(action, template_runner)
|
|
264
|
+
return unless template_runner
|
|
265
|
+
|
|
266
|
+
UI.info(action["name"].to_s)
|
|
267
|
+
source = action["source"]
|
|
268
|
+
variables = template_variables(action)
|
|
269
|
+
template_runner.apply(source, variables: variables)
|
|
270
|
+
rescue TemplateError => e
|
|
271
|
+
UI.warning("Post-action '#{action["name"]}' failed. #{e.message}")
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def template_variables(action)
|
|
275
|
+
base = { app_name: @app_name, answers: @answers }
|
|
276
|
+
extras = action["variables"].is_a?(Hash) ? action["variables"].transform_keys(&:to_sym) : {}
|
|
277
|
+
base.merge(extras)
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def template_action?(action)
|
|
281
|
+
action["type"].to_s == "template"
|
|
282
|
+
end
|
|
283
|
+
|
|
252
284
|
def should_run_action?(action)
|
|
253
285
|
return false unless action.fetch("enabled", true)
|
|
254
286
|
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "thor"
|
|
4
|
+
require_relative "errors"
|
|
5
|
+
|
|
6
|
+
module Railstart
|
|
7
|
+
# Executes Rails application templates (including RailsBytes scripts)
|
|
8
|
+
# inside a generated application directory.
|
|
9
|
+
#
|
|
10
|
+
# Wraps Rails' own AppGenerator so existing template DSL helpers such as
|
|
11
|
+
# `gem`, `initializer`, `route`, etc. are available without reimplementing
|
|
12
|
+
# them in Railstart.
|
|
13
|
+
class TemplateRunner
|
|
14
|
+
# @param app_path [String] absolute path to the Rails application
|
|
15
|
+
# @param generator_factory [#call] optional factory for injecting a
|
|
16
|
+
# generator (mainly used in tests)
|
|
17
|
+
# @param shell [Thor::Shell] Thor shell instance for output
|
|
18
|
+
def initialize(app_path:, generator_factory: nil, shell: Thor::Base.shell.new)
|
|
19
|
+
@app_path = app_path
|
|
20
|
+
@shell = shell
|
|
21
|
+
@generator_factory = generator_factory
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Apply a Rails template located at +source+.
|
|
25
|
+
#
|
|
26
|
+
# @param source [String] file path or URL
|
|
27
|
+
# @param variables [Hash] instance variables injected into the template
|
|
28
|
+
# @return [void]
|
|
29
|
+
# @raise [Railstart::TemplateError] when Rails cannot be loaded or
|
|
30
|
+
# template execution fails
|
|
31
|
+
def apply(source, variables: {})
|
|
32
|
+
raise TemplateError, "Template source must be provided" if source.to_s.strip.empty?
|
|
33
|
+
|
|
34
|
+
generator = build_generator
|
|
35
|
+
assign_variables(generator, variables)
|
|
36
|
+
generator.apply(source)
|
|
37
|
+
rescue TemplateError
|
|
38
|
+
raise
|
|
39
|
+
rescue LoadError => e
|
|
40
|
+
raise TemplateError, "Rails must be installed to run template post-actions: #{e.message}"
|
|
41
|
+
rescue StandardError => e
|
|
42
|
+
raise TemplateError, "Failed to apply template #{source}: #{e.message}"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def assign_variables(generator, variables)
|
|
48
|
+
Array(variables).each do |key, value|
|
|
49
|
+
generator.instance_variable_set(:"@#{key}", value)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def build_generator
|
|
54
|
+
generator = generator_factory.call(@app_path)
|
|
55
|
+
if generator.respond_to?(:destination_root=)
|
|
56
|
+
generator.destination_root = @app_path
|
|
57
|
+
elsif generator.respond_to?(:destination_root)
|
|
58
|
+
generator.instance_variable_set(:@destination_root, @app_path)
|
|
59
|
+
end
|
|
60
|
+
generator
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def generator_factory
|
|
64
|
+
@generator_factory ||= default_generator_factory
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def default_generator_factory
|
|
68
|
+
require "rails/generators"
|
|
69
|
+
require "rails/generators/rails/app/app_generator"
|
|
70
|
+
|
|
71
|
+
shell = @shell
|
|
72
|
+
lambda do |_app_path|
|
|
73
|
+
Rails::Generators::AppGenerator.new([], {}, shell: shell)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
data/lib/railstart/version.rb
CHANGED
data/lib/railstart.rb
CHANGED
|
@@ -5,6 +5,7 @@ require_relative "railstart/errors"
|
|
|
5
5
|
require_relative "railstart/config"
|
|
6
6
|
require_relative "railstart/command_builder"
|
|
7
7
|
require_relative "railstart/generator"
|
|
8
|
+
require_relative "railstart/template_runner"
|
|
8
9
|
require_relative "railstart/cli"
|
|
9
10
|
|
|
10
11
|
# Main namespace for the Railstart gem.
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: railstart
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- dpaluy
|
|
@@ -69,6 +69,7 @@ files:
|
|
|
69
69
|
- Rakefile
|
|
70
70
|
- config/presets/api-only.yaml
|
|
71
71
|
- config/presets/default.yaml
|
|
72
|
+
- config/presets/vite-bun.yaml
|
|
72
73
|
- config/rails8_defaults.yaml
|
|
73
74
|
- exe/railstart
|
|
74
75
|
- lib/railstart.rb
|
|
@@ -77,6 +78,7 @@ files:
|
|
|
77
78
|
- lib/railstart/config.rb
|
|
78
79
|
- lib/railstart/errors.rb
|
|
79
80
|
- lib/railstart/generator.rb
|
|
81
|
+
- lib/railstart/template_runner.rb
|
|
80
82
|
- lib/railstart/ui.rb
|
|
81
83
|
- lib/railstart/version.rb
|
|
82
84
|
homepage: https://github.com/dpaluy/railstart
|