Skip to content

Commit c338a85

Browse files
Introduce suspenders:setup generator
Replaces the [default setup script][] provided by Rails. The trade-off being that the implementation is simple, but the cost is we risk drifting from Rails. After attempting to use [gsub_file][] and [insert_into_file][], it felt simpler to just override the file completely. Uses [Homebrew Bundle][] in combination with [asdf][] to install system and tool dependencies locally. Re-introduces [dev:prime][] to seed development data on top of [seed][] data necessary for production. Allow caller to wipe the database clean by setting `WIPE_DATABASE=true` before running `bin/setup`. Additionally, we [setup the test environment][] to avoid issues with asset compilation. [default setup script]: https://github.com/rails/rails/blob/main/railties/lib/rails/generators/rails/app/templates/bin/setup.tt [gsub_file]: https://rubydoc.info/gems/thor/Thor/Actions#gsub_file-instance_method [insert_into_file]: https://rubydoc.info/gems/thor/Thor/Actions#insert_into_file-instance_method [Homebrew Bundle]: https://github.com/Homebrew/homebrew-bundle [asdf]: https://asdf-vm.com [dev:prime]: https://thoughtbot.com/blog/priming-the-pump [seed]: https://guides.rubyonrails.org/active_record_migrations.html#migrations-and-seed-data [setup the test environment]: https://github.com/rails/rails/pull/47719/files
1 parent 51dcd4b commit c338a85

File tree

7 files changed

+215
-0
lines changed

7 files changed

+215
-0
lines changed

NEWS.md

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Unreleased
1010
* Introduce `suspenders:lint` generator
1111
* Introduce `suspenders:rake` generator
1212
* Introduce `suspenders:views` generator
13+
* Introduce `suspenders:setup` generator
1314

1415
20230113.0 (January, 13, 2023)
1516

README.md

+14
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,20 @@ document [lang][].
134134
[title]: https://github.com/calebhearth/title
135135
[lang]: https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang
136136

137+
### Setup
138+
139+
A holistic setup script.
140+
141+
```sh
142+
bin/setup
143+
```
144+
145+
or
146+
147+
```sh
148+
WIPE_DATABASE=true bin/setup
149+
```
150+
137151
## Contributing
138152

139153
See the [CONTRIBUTING] document.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
module Suspenders
2+
module Generators
3+
class SetupGenerator < Rails::Generators::Base
4+
source_root File.expand_path("../../templates/setup", __FILE__)
5+
desc <<~TEXT
6+
A holistic setup script.
7+
8+
```sh
9+
bin/setup
10+
```
11+
12+
or
13+
14+
```sh
15+
WIPE_DATABASE=true bin/setup
16+
```
17+
TEXT
18+
19+
def create_brewfile
20+
copy_file "brewfile", "Brewfile"
21+
end
22+
23+
def create_dev_prime
24+
copy_file "dev_prime.rb", "lib/tasks/dev.rake"
25+
end
26+
27+
def replace_bin_setup
28+
copy_file "bin_setup.rb", "bin/setup", force: true
29+
end
30+
end
31+
end
32+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#!/usr/bin/env ruby
2+
require "fileutils"
3+
require "open3"
4+
5+
# path to your application root.
6+
APP_ROOT = File.expand_path("..", __dir__)
7+
8+
def system!(*args)
9+
system(*args, exception: true)
10+
end
11+
12+
def using_node?
13+
File.exist? "package.json"
14+
end
15+
16+
FileUtils.chdir APP_ROOT do
17+
if ENV["CI"].nil?
18+
puts "\n== Installing Homebrew Bundle from Brewfile =="
19+
system! "brew bundle"
20+
21+
puts "\n== Starting postgresql@15 =="
22+
system! "brew services restart postgresql@15"
23+
24+
puts "\n== Starting redis =="
25+
system! "brew services restart redis"
26+
27+
_, _, status = Open3.capture3("which asdf")
28+
if status.success?
29+
puts "\n== Installing tool dependecies via asdf =="
30+
system! "asdf plugin-add ruby https://github.com/asdf-vm/asdf-ruby"
31+
system! "asdf plugin-add nodejs https://github.com/asdf-vm/asdf-nodejs" if using_node?
32+
system! "asdf plugin-add yarn https://github.com/twuni/asdf-yarn" if using_node?
33+
system! "asdf plugin-update --all"
34+
system! "asdf install"
35+
end
36+
end
37+
38+
puts "\n== Installing dependencies =="
39+
system! "gem install bundler --conservative"
40+
system("bundle check") || system!("bundle install")
41+
system("yarn install --check-files") if using_node?
42+
43+
puts "\n== Preparing database and adding development seed data =="
44+
if ENV["WIPE_DATABASE"] == true
45+
system! "bin/rails db:reset dev:prime"
46+
else
47+
system! "bin/rails dev:prime"
48+
end
49+
50+
# https://github.com/rails/rails/pull/47719/files
51+
puts "\n== Setup test environment =="
52+
system! "bin/rails test:prepare"
53+
54+
puts "\n== Removing old logs and tempfiles =="
55+
system! "bin/rails log:clear tmp:clear"
56+
57+
puts "\n== Restarting application server =="
58+
system! "bin/rails restart"
59+
end
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# https://formulae.brew.sh/formula/vips
2+
brew "vips"
3+
4+
# https://formulae.brew.sh/formula/redis
5+
brew "redis"
6+
7+
# https://formulae.brew.sh/formula/postgresql@15
8+
# Change version to match production
9+
brew "postgresql@15"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
if Rails.env.development? || Rails.env.test?
2+
require "factory_bot" if Bundler.rubygems.find_name("factory_bot_rails").any?
3+
4+
namespace :dev do
5+
desc "Sample data for local development environment"
6+
task prime: "db:setup" do
7+
include FactoryBot::Syntax::Methods if Bundler.rubygems.find_name("factory_bot_rails").any?
8+
9+
# create(:user, email: "[email protected]", password: "password")
10+
end
11+
end
12+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
require "test_helper"
2+
require "generators/suspenders/setup_generator"
3+
4+
module Suspenders
5+
module Generators
6+
class SetupGeneratorTest < Rails::Generators::TestCase
7+
include Suspenders::TestHelpers
8+
9+
tests Suspenders::Generators::SetupGenerator
10+
destination Rails.root
11+
setup :prepare_destination
12+
teardown :restore_destination
13+
14+
test "creates Brewfile" do
15+
expected = <<~TEXT
16+
# https://formulae.brew.sh/formula/vips
17+
brew "vips"
18+
19+
# https://formulae.brew.sh/formula/redis
20+
brew "redis"
21+
22+
# https://formulae.brew.sh/formula/postgresql@15
23+
# Change version to match production
24+
brew "postgresql@15"
25+
TEXT
26+
27+
run_generator
28+
29+
assert_file app_root("Brewfile") do |file|
30+
assert_equal expected, file
31+
end
32+
end
33+
34+
test "modifies bin/setup" do
35+
expected = bin_setup
36+
37+
run_generator
38+
39+
assert_file app_root("bin/setup") do |file|
40+
assert_equal expected, file
41+
end
42+
end
43+
44+
test "creates dev:prime task" do
45+
expected = <<~RUBY
46+
if Rails.env.development? || Rails.env.test?
47+
require "factory_bot" if Bundler.rubygems.find_name("factory_bot_rails").any?
48+
49+
namespace :dev do
50+
desc "Sample data for local development environment"
51+
task prime: "db:setup" do
52+
include FactoryBot::Syntax::Methods if Bundler.rubygems.find_name("factory_bot_rails").any?
53+
54+
# create(:user, email: "[email protected]", password: "password")
55+
end
56+
end
57+
end
58+
RUBY
59+
60+
run_generator
61+
62+
assert_file app_root("lib/tasks/dev.rake") do |file|
63+
assert_equal expected, file
64+
end
65+
end
66+
67+
test "has a custom description" do
68+
assert_no_match(/Description:/, generator_class.desc)
69+
end
70+
71+
private
72+
73+
def prepare_destination
74+
backup_file "bin/setup"
75+
end
76+
77+
def restore_destination
78+
remove_file_if_exists "Brewfile"
79+
restore_file "bin/setup"
80+
remove_dir_if_exists "lib/tasks"
81+
end
82+
83+
def bin_setup
84+
File.read("./lib/generators/templates/setup/bin_setup.rb")
85+
end
86+
end
87+
end
88+
end

0 commit comments

Comments
 (0)