gnarails 3.0.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/gnarly.rb CHANGED
@@ -2,7 +2,7 @@
2
2
  # to look up files
3
3
  def source_paths
4
4
  Array(super) +
5
- [File.expand_path(File.dirname(__FILE__))]
5
+ [__dir__]
6
6
  end
7
7
 
8
8
  def create_gnarly_rails_app
@@ -16,14 +16,17 @@ def create_gnarly_rails_app
16
16
 
17
17
  add_gems
18
18
 
19
- run "bundle install"
19
+ run_bundle
20
20
 
21
21
  after_bundle do
22
22
  setup_testing
23
+ setup_binstubs
23
24
  setup_database
24
- setup_scss
25
+ setup_assets
25
26
  setup_gitignore
26
- setup_analysis
27
+ setup_linting
28
+ setup_pronto
29
+ setup_simplecov
27
30
  setup_environments
28
31
  setup_readme
29
32
  remove_dir "test"
@@ -35,28 +38,24 @@ end
35
38
 
36
39
  def add_gems
37
40
  gem_group :development, :test do
38
- gem 'axe-matchers'
39
- gem 'bullet'
40
- gem 'bundler-audit'
41
- gem 'capybara'
42
- gem 'dotenv-rails'
43
- gem 'factory_bot_rails'
44
- gem 'gnar-style', require: false
45
- gem 'launchy'
46
- gem 'lol_dba'
47
- gem 'okcomputer'
48
- gem 'pronto'
49
- gem 'pronto-brakeman', require: false
50
- gem 'pronto-rubocop', require: false
51
- gem 'pronto-scss', require: false
52
- gem 'pry-byebug'
53
- gem 'pry-rails'
54
- gem 'rspec-its'
55
- gem 'rspec-rails', '~> 3.7'
56
- gem 'scss_lint', require: false
57
- gem 'selenium-webdriver'
58
- gem 'shoulda-matchers'
59
- gem 'simplecov', require: false
41
+ gem "axe-core-capybara"
42
+ gem "axe-core-rspec"
43
+ gem "bullet"
44
+ gem "dotenv-rails"
45
+ gem "factory_bot_rails"
46
+ gem "gnar-style", require: false
47
+ gem "launchy"
48
+ gem "lol_dba"
49
+ gem "okcomputer"
50
+ gem "pronto"
51
+ gem "pronto-rubocop", require: false
52
+ gem "pry-byebug"
53
+ gem "pry-rails"
54
+ gem "rspec-its"
55
+ gem "rspec-rails", "~> 4"
56
+ gem "rubocop-rspec", require: false
57
+ gem "shoulda-matchers"
58
+ gem "simplecov", require: false
60
59
  end
61
60
  end
62
61
 
@@ -64,17 +63,26 @@ def setup_database
64
63
  remove_file "config/database.yml"
65
64
  copy_file "templates/database.yml", "config/database.yml"
66
65
  gsub_file "config/database.yml", "__application_name__", app_name
67
-
68
66
  gsub_file "Gemfile", /.*sqlite.*\n/, ""
69
67
  end
70
68
 
71
- def setup_scss
72
- run "mv app/assets/stylesheets/application.css app/assets/stylesheets/application.scss"
69
+ def setup_assets
70
+ run "yarn add esbuild-rails"
71
+ remove_file "esbuild.config.js"
72
+ copy_file "templates/esbuild.config.js", "esbuild.config.js"
73
+ run "npm set-script build 'node esbuild.config.js'"
73
74
  end
74
75
 
75
76
  def setup_gitignore
76
- remove_file ".gitignore"
77
- copy_file "templates/.gitignore", ".gitignore"
77
+ append_to_file ".gitignore" do
78
+ <<~GITIGNORE
79
+ # Ignore Byebug command history file.
80
+ .byebug_history
81
+
82
+ # Ignore output of simplecov
83
+ coverage
84
+ GITIGNORE
85
+ end
78
86
  end
79
87
 
80
88
  def setup_testing
@@ -115,7 +123,8 @@ end
115
123
  def system_tests_rails_helper_text
116
124
  <<~SYSTEM_TESTS
117
125
  require "capybara/rails"
118
- require "axe/rspec"
126
+ require "axe-rspec"
127
+ require "axe-capybara"
119
128
  require "selenium/webdriver"
120
129
  SYSTEM_TESTS
121
130
  end
@@ -188,27 +197,29 @@ def limit_test_logging
188
197
  end
189
198
  end
190
199
 
191
- def setup_analysis
192
- setup_linting
193
- setup_pronto
194
- setup_brakeman
195
- setup_simplecov
200
+ def setup_binstubs
201
+ remove_file "bin/setup"
202
+ copy_file "templates/bin/setup", "bin/setup"
203
+ run "chmod +x bin/setup"
204
+
205
+ copy_file "templates/bin/rspec", "bin/rspec"
206
+ run "chmod +x bin/rspec"
207
+
208
+ copy_file "templates/bin/rubocop", "bin/rubocop"
209
+ run "chmod +x bin/rubocop"
196
210
  end
197
211
 
198
212
  def setup_linting
199
213
  copy_file "templates/.rubocop.yml", ".rubocop.yml"
200
- copy_file "templates/.scss-lint.yml", ".scss-lint.yml"
201
214
  end
202
215
 
203
216
  def setup_pronto
204
217
  copy_file "templates/.pronto.yml", ".pronto.yml"
205
- copy_file "templates/bin/ci_pronto", "bin/ci_pronto"
206
- run "chmod +x bin/ci_pronto"
207
- end
208
218
 
209
- def setup_brakeman
210
- copy_file "templates/bin/brakeman", "bin/brakeman"
211
- run "chmod +x bin/brakeman"
219
+ copy_file "templates/bin/pronto", "bin/pronto"
220
+ run "chmod +x bin/pronto"
221
+
222
+ copy_file ".github/workflows/pronto.yml", ".github/workflows/pronto.yml"
212
223
  end
213
224
 
214
225
  def setup_simplecov
@@ -230,7 +241,7 @@ end
230
241
 
231
242
  def setup_environments
232
243
  setup_dotenv
233
- setup_ci
244
+ setup_github_workflows
234
245
  setup_docker
235
246
  setup_procfile
236
247
  configure_i18n
@@ -243,10 +254,12 @@ def setup_dotenv
243
254
  gsub_file ".env.test", "__application_name__", app_name
244
255
  end
245
256
 
246
- def setup_ci
247
- copy_file "templates/.circleci/config.yml", ".circleci/config.yml"
248
- gsub_file ".circleci/config.yml", "__ruby_version__", RUBY_VERSION
249
- gsub_file ".circleci/config.yml", "__application_name__", app_name
257
+ def setup_github_workflows
258
+ copy_file "templates/.github/workflows/run-tests.yml", ".github/workflows/run-tests.yml"
259
+ copy_file "templates/.github/workflows/brakeman.yml", ".github/workflows/brakeman.yml"
260
+
261
+ copy_file ".github/actions/test-rails/action.yml", ".github/actions/test-rails/action.yml"
262
+ copy_file ".github/workflows/bundler-audit.yml", ".github/workflows/bundler-audit.yml"
250
263
  end
251
264
 
252
265
  def setup_docker
@@ -305,16 +318,21 @@ def post_install_instructions
305
318
  puts "* Install ChromeDriver for default headless acceptance tests: brew cask install chromedriver"
306
319
  puts "* Follow the post-install instructions to set up circle to allow gnarbot to comment on PRs."
307
320
  puts " * https://github.com/TheGnarCo/gnarails#post-install"
321
+ puts "=========="
322
+ puts "* Make sure your package.json has the following scripts:"
323
+ puts "* \`\"build\": \"node esbuild.config.js\"\`"
324
+ puts "* \`\"build:css\": \"sass ./app/assets/stylesheets/application.sass.scss ./app/assets/builds/application.css --no-source-map --load-path=node_modules\"\`"
308
325
  end
309
326
 
310
327
  def format_ruby
311
- run "bundle exec rubocop --auto-correct"
328
+ run "bin/rubocop -A"
312
329
  end
313
330
 
314
331
  def completion_notification
315
332
  puts ""
316
333
  ascii_art
317
334
  post_install_instructions
335
+ puts ""
318
336
  end
319
337
 
320
338
  create_gnarly_rails_app
@@ -7,180 +7,52 @@ module Gnarails
7
7
 
8
8
  add_runtime_options!
9
9
 
10
- WEBPACKS = %w[react vue angular elm stimulus].freeze
11
-
12
- method_option :ruby,
13
- type: :string,
14
- aliases: "-r",
15
- default: Thor::Util.ruby_command,
16
- desc: "Path to the Ruby binary of your choice", banner: "PATH"
17
-
18
- method_option :skip_namespace,
19
- type: :boolean,
20
- default: false,
21
- desc: "Skip namespace (affects only isolated applications)"
22
-
23
- method_option :skip_yarn,
24
- type: :boolean,
25
- default: false,
26
- desc: "Don't use Yarn for managing JavaScript dependencies"
27
-
28
- method_option :skip_gemfile,
29
- type: :boolean,
30
- default: false,
31
- desc: "Don't create a Gemfile"
32
-
33
- method_option :skip_git,
34
- type: :boolean,
35
- aliases: "-G",
36
- default: false,
37
- desc: "Skip .gitignore file"
38
-
39
- method_option :skip_keeps,
40
- type: :boolean,
41
- default: false,
42
- desc: "Skip source control .keep files"
43
-
44
- method_option :skip_action_mailer,
45
- type: :boolean,
46
- aliases: "-M",
47
- default: false,
48
- desc: "Skip Action Mailer files"
49
-
50
- method_option :skip_active_record,
51
- type: :boolean,
52
- aliases: "-O",
53
- default: false,
54
- desc: "Skip Active Record files"
55
-
56
- method_option :skip_active_storage,
57
- type: :boolean,
58
- default: false,
59
- desc: "Skip Active Storage files"
60
-
61
- method_option :skip_puma,
62
- type: :boolean,
63
- aliases: "-P",
64
- default: false,
65
- desc: "Skip Puma related files"
66
-
67
- method_option :skip_action_cable,
68
- type: :boolean,
69
- aliases: "-C",
70
- default: false,
71
- desc: "Skip Action Cable files"
72
-
73
- method_option :skip_sprockets,
74
- type: :boolean,
75
- aliases: "-S",
76
- default: false,
77
- desc: "Skip Sprockets files"
78
-
79
- method_option :skip_spring,
80
- type: :boolean,
81
- default: false,
82
- desc: "Don't install Spring application preloader"
83
-
84
- method_option :skip_listen,
85
- type: :boolean,
86
- default: false,
87
- desc: "Don't generate configuration that depends on the listen gem"
88
-
89
- method_option :skip_coffee,
90
- type: :boolean,
91
- default: false,
92
- desc: "Don't use CoffeeScript"
93
-
94
- method_option :skip_javascript,
95
- type: :boolean,
96
- aliases: "-J",
97
- default: false,
98
- desc: "Skip JavaScript files"
99
-
100
- method_option :skip_turbolinks,
101
- type: :boolean,
102
- default: false,
103
- desc: "Skip turbolinks gem"
104
-
105
- method_option :skip_test,
106
- type: :boolean,
107
- aliases: "-T",
108
- default: false,
109
- desc: "Skip test files"
110
-
111
- method_option :skip_system_test,
112
- type: :boolean,
113
- default: false,
114
- desc: "Skip system test files"
115
-
116
- method_option :skip_bootsnap,
117
- type: :boolean,
118
- default: false,
119
- desc: "Skip bootsnap gem"
120
-
121
- method_option :dev,
122
- type: :boolean,
123
- default: false,
124
- desc: "Setup the application with Gemfile pointing to your Rails checkout"
125
-
126
- method_option :edge,
127
- type: :boolean,
128
- default: false,
129
- desc: "Setup the application with Gemfile pointing to Rails repository"
130
-
131
- method_option :rc,
132
- type: :string,
133
- default: nil,
134
- desc: "Path to file containing extra configuration options for rails command"
135
-
136
- method_option :no_rc,
137
- type: :boolean,
138
- default: false,
139
- desc: "Skip loading of extra configuration options from .railsrc file"
140
-
141
- method_option :api,
142
- type: :boolean,
143
- desc: "Preconfigure smaller stack for API only apps"
144
-
145
- method_option :skip_bundle,
146
- type: :boolean,
147
- aliases: "-B",
148
- default: false,
149
- desc: "Don't run bundle install"
150
-
151
- method_option :webpack,
152
- type: :string,
153
- default: nil,
154
- desc: "Preconfigure for app-like JavaScript with Webpack (options: #{WEBPACKS.join('/')})"
155
-
156
10
  desc "new APP_PATH [options]", "generate a gnarly rails app"
157
11
  long_desc <<-LONGDESC
158
12
  `gnarails new NAME` will create a new rails application called NAME,
159
13
  pre-built with the same helpful default configuration you can expect from
160
14
  any rails project built by The Gnar Company.
161
15
 
162
- By default, we pass arguments to `rails new` that skip test unit
163
- generation and use postgres instead of sqlite as the default database.
16
+ By default, we pass arguments to `rails new` that:
17
+ - skip test unit (We'll install rspec later)
18
+ - use postgres over SQLlite,
19
+ - use Propshaft,
20
+ - Bundle CSS with cssbundling (using sass)
21
+ - bundle JS with esbuild
164
22
 
165
23
  You should also be able to pass any other arguments you would expect to
166
- be able to when generating a new rails app.
24
+ be able to when generating a new rails app. Use `rails -h` for more
25
+ information.
167
26
  LONGDESC
168
27
  def new(name)
169
- Kernel.system "rails new #{name} #{cli_options(options)}"
28
+ Kernel.system command(name, options)
170
29
  end
171
30
 
31
+ DEFAULT_OPTIONS = [
32
+ "--asset-pipeline=propshaft",
33
+ "--skip-test-unit",
34
+ "--css=sass",
35
+ "--javascript=esbuild",
36
+ "--database=postgresql",
37
+ ].freeze
38
+
172
39
  no_tasks do
40
+ def command(name, options)
41
+ "rails new #{name} #{cli_options(options)}"
42
+ end
43
+
173
44
  def cli_options(options)
174
- options_string = "-m #{Gnarails.template_file} --skip-test-unit --database=postgresql"
45
+ options_string = "-m #{Gnarails.template_file} " + DEFAULT_OPTIONS.join(" ")
175
46
  options.each_with_object(options_string) do |(k, v), str|
176
47
  str << cli_option(k, v)
177
48
  end
178
49
  end
179
50
 
180
51
  def cli_option(key, value)
181
- if value == false
52
+ case value
53
+ when false
182
54
  ""
183
- elsif value == true
55
+ when true
184
56
  " --#{key}"
185
57
  else
186
58
  " --#{key}=#{value}"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Gnarails
2
- VERSION = "3.0.0"
4
+ VERSION = "3.0.1"
3
5
  end
@@ -0,0 +1,22 @@
1
+ name: Brakeman
2
+
3
+ on: [push]
4
+
5
+ jobs:
6
+ build:
7
+ runs-on: ubuntu-latest
8
+ steps:
9
+ - uses: actions/checkout@v3
10
+
11
+ - name: Setup Ruby
12
+ uses: ruby/setup-ruby@v1
13
+ with:
14
+ bundler-cache: true
15
+
16
+ - name: Brakeman
17
+ run: |
18
+ gem install brakeman --no-document
19
+ brakeman --exit-on-warn --separate-models -o tmp/brakeman.html -o tmp/brakeman.text .
20
+ brakeman_exit_code=$?
21
+ cat tmp/brakeman.text
22
+ exit $brakeman_exit_code
@@ -0,0 +1,26 @@
1
+ name: Run Tests
2
+ on: [push]
3
+
4
+ jobs:
5
+ run-tests:
6
+ runs-on: ubuntu-latest
7
+ env:
8
+ RAILS_ENV: test
9
+ DATABASE_PASSWORD: password
10
+ services:
11
+ postgres:
12
+ image: postgres:14
13
+ env:
14
+ POSTGRES_PASSWORD: password
15
+ ports: ["5432:5432"]
16
+ options:
17
+ --health-cmd pg_isready
18
+ --health-interval 10s
19
+ --health-timeout 5s
20
+ --health-retries 5
21
+ steps:
22
+ - name: Checkout code
23
+ uses: actions/checkout@v3
24
+
25
+ - name: Test
26
+ uses: ./.github/actions/test-rails
data/templates/README.md CHANGED
@@ -4,10 +4,9 @@
4
4
 
5
5
  ```sh
6
6
  $ bundle install
7
- $ bundle exec rake db:create
8
- $ bundle exec rake db:migrate
9
- $ bundle exec rake db:seed
10
- $ bundle exec rails s
7
+ $ yarn install
8
+ $ bin/setup
9
+ $ bin/dev
11
10
  $ open http://localhost:3000
12
11
  ```
13
12
 
@@ -64,7 +63,7 @@ $ docker-compose up
64
63
 
65
64
  To run rspec:
66
65
  ```sh
67
- $ docker-compose run web bundle exec rspec
66
+ $ docker-compose run web ./bin/rspec
68
67
  ```
69
68
 
70
69
  ### Using pry with Docker
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'pronto' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("bundle", __dir__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if /This file was generated by Bundler/.match?(File.read(bundle_binstub, 300))
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("pronto", "pronto")
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rspec' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("bundle", __dir__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if /This file was generated by Bundler/.match?(File.read(bundle_binstub, 300))
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("rspec-core", "rspec")
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rubocop' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("bundle", __dir__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if /This file was generated by Bundler/.match?(File.read(bundle_binstub, 300))
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("rubocop", "rubocop")
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+ require "fileutils"
3
+
4
+ # path to your application root.
5
+ APP_ROOT = File.expand_path("..", __dir__)
6
+
7
+ def system!(*args)
8
+ system(*args) || abort("\n== Command #{args} failed ==")
9
+ end
10
+
11
+ FileUtils.chdir APP_ROOT do
12
+ # This script is a way to set up or update your development environment automatically.
13
+ # This script is idempotent, so that you can run it at any time and get an expectable outcome.
14
+ # Add necessary setup steps to this file.
15
+
16
+ puts "== Installing dependencies =="
17
+ system! "gem install bundler --conservative"
18
+ system("bundle check") || system!("bundle install")
19
+
20
+ system! "yarn install --pure-lockfile"
21
+
22
+ puts "\n== Preparing database =="
23
+ system! "bin/rails db:prepare"
24
+
25
+ puts "\n== Removing old logs and tempfiles =="
26
+ system! "bin/rails log:clear tmp:clear"
27
+
28
+ puts "\n== Restarting application server =="
29
+ system! "bin/rails restart"
30
+ end
@@ -4,7 +4,7 @@ services:
4
4
  image: postgres
5
5
  web:
6
6
  build: .
7
- command: bash -c 'rm -f tmp/pids/server.pid && bundle exec rails s --port 3000 --binding 0.0.0.0'
7
+ command: bash -c 'rm -f tmp/pids/server.pid && bin/dev --binding 0.0.0.0'
8
8
  volumes:
9
9
  - .:/app
10
10
  ports:
@@ -0,0 +1,11 @@
1
+ const path = require('path')
2
+ const rails = require('esbuild-rails')
3
+
4
+ require('esbuild').build({
5
+ entryPoints: ['application.js'],
6
+ bundle: true,
7
+ outdir: path.join(process.cwd(), 'app/assets/builds'),
8
+ absWorkingDir: path.join(process.cwd(), 'app/javascript'),
9
+ watch: process.argv.includes('--watch'),
10
+ plugins: [rails()],
11
+ }).catch(() => process.exit(1))
@@ -4,8 +4,8 @@
4
4
  <title>RailsTestApp</title>
5
5
  <%= csrf_meta_tags %>
6
6
 
7
- <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
8
- <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
7
+ <%= stylesheet_link_tag "application" %>
8
+ <%= javascript_include_tag "application", defer: true %>
9
9
  </head>
10
10
 
11
11
  <body>
@@ -5,17 +5,17 @@ RSpec.feature "Viewing all job postings", type: :system do
5
5
  create_list :job_posting, 1
6
6
  visit job_postings_path
7
7
 
8
- expect(page).to be_accessible
8
+ expect(page).to be_axe_clean
9
9
  end
10
10
 
11
11
  scenario "N+1 query proteection" do
12
12
  job_posting = create :job_posting
13
- job_posting.comments.create(body: "first comment")
14
- job_posting.comments.create(body: "second comment")
13
+ job_posting.comments.create!(body: "first comment")
14
+ job_posting.comments.create!(body: "second comment")
15
15
 
16
16
  another_posting = create :job_posting
17
- another_posting.comments.create(body: "third comment")
18
- another_posting.comments.create(body: "fourth comment")
17
+ another_posting.comments.create!(body: "third comment")
18
+ another_posting.comments.create!(body: "fourth comment")
19
19
 
20
20
  expect { visit job_postings_path }
21
21
  .to raise_error Bullet::Notification::UnoptimizedQueryError
@@ -25,10 +25,6 @@ RSpec.feature "Viewing all job postings", type: :system do
25
25
  posting = create :job_posting
26
26
  visit job_postings_path
27
27
 
28
- expect(has_job_posting?(posting)).to be true
29
- end
30
-
31
- def has_job_posting?(posting)
32
28
  within(".job-posting-#{posting.id}") do
33
29
  expect(page).to have_css("td.posting-title", text: posting.title)
34
30
  end