bulldozer 1.6.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.
Files changed (108) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +12 -0
  5. data/CONTRIBUTING.md +59 -0
  6. data/Gemfile +3 -0
  7. data/LICENSE +21 -0
  8. data/NEWS.md +638 -0
  9. data/README.md +225 -0
  10. data/RELEASING.md +18 -0
  11. data/Rakefile +8 -0
  12. data/USAGE +13 -0
  13. data/bin/bulldozer +23 -0
  14. data/bin/rake +16 -0
  15. data/bin/rspec +16 -0
  16. data/bin/setup +13 -0
  17. data/bulldozer.gemspec +35 -0
  18. data/docker-compose.yml +8 -0
  19. data/dockerfile +11 -0
  20. data/lib/bulldozer.rb +24 -0
  21. data/lib/bulldozer/actions.rb +85 -0
  22. data/lib/bulldozer/adapters/heroku.rb +123 -0
  23. data/lib/bulldozer/app_builder.rb +321 -0
  24. data/lib/bulldozer/generators/analytics_generator.rb +24 -0
  25. data/lib/bulldozer/generators/app_generator.rb +231 -0
  26. data/lib/bulldozer/generators/base.rb +20 -0
  27. data/lib/bulldozer/generators/ci_generator.rb +22 -0
  28. data/lib/bulldozer/generators/db_optimizations_generator.rb +30 -0
  29. data/lib/bulldozer/generators/factories_generator.rb +22 -0
  30. data/lib/bulldozer/generators/forms_generator.rb +18 -0
  31. data/lib/bulldozer/generators/jobs_generator.rb +38 -0
  32. data/lib/bulldozer/generators/js_driver_generator.rb +15 -0
  33. data/lib/bulldozer/generators/json_generator.rb +10 -0
  34. data/lib/bulldozer/generators/lint_generator.rb +9 -0
  35. data/lib/bulldozer/generators/production/deployment_generator.rb +27 -0
  36. data/lib/bulldozer/generators/production/email_generator.rb +37 -0
  37. data/lib/bulldozer/generators/production/force_tls_generator.rb +11 -0
  38. data/lib/bulldozer/generators/production/manifest_generator.rb +24 -0
  39. data/lib/bulldozer/generators/production/timeout_generator.rb +21 -0
  40. data/lib/bulldozer/generators/staging/pull_requests_generator.rb +33 -0
  41. data/lib/bulldozer/generators/static_generator.rb +10 -0
  42. data/lib/bulldozer/generators/stylesheet_base_generator.rb +31 -0
  43. data/lib/bulldozer/generators/testing_generator.rb +55 -0
  44. data/lib/bulldozer/generators/views_generator.rb +30 -0
  45. data/lib/bulldozer/version.rb +8 -0
  46. data/spec/adapters/heroku_spec.rb +72 -0
  47. data/spec/fakes/bin/heroku +5 -0
  48. data/spec/fakes/bin/hub +5 -0
  49. data/spec/features/api_spec.rb +18 -0
  50. data/spec/features/cli_help_spec.rb +36 -0
  51. data/spec/features/github_spec.rb +16 -0
  52. data/spec/features/heroku_spec.rb +71 -0
  53. data/spec/features/json_spec.rb +15 -0
  54. data/spec/features/new_project_spec.rb +341 -0
  55. data/spec/features/production/deployment_spec.rb +22 -0
  56. data/spec/features/production/email_spec.rb +47 -0
  57. data/spec/features/production/manifest_spec.rb +35 -0
  58. data/spec/features/staging/pull_requests_spec.rb +22 -0
  59. data/spec/spec_helper.rb +21 -0
  60. data/spec/support/be_executable_matcher.rb +7 -0
  61. data/spec/support/bulldozer.rb +182 -0
  62. data/spec/support/contain_json_matcher.rb +24 -0
  63. data/spec/support/exist_as_a_file_matcher.rb +7 -0
  64. data/spec/support/fake_github.rb +21 -0
  65. data/spec/support/fake_heroku.rb +53 -0
  66. data/spec/support/generators.rb +5 -0
  67. data/spec/support/match_contents_matcher.rb +6 -0
  68. data/spec/support/project_files.rb +13 -0
  69. data/templates/Gemfile.erb +51 -0
  70. data/templates/Procfile +2 -0
  71. data/templates/README.md.erb +28 -0
  72. data/templates/_analytics.html.erb +8 -0
  73. data/templates/_css_overrides.html.erb +7 -0
  74. data/templates/_flashes.html.erb +7 -0
  75. data/templates/_javascript.html.erb +3 -0
  76. data/templates/action_mailer.rb +5 -0
  77. data/templates/active_job.rb +13 -0
  78. data/templates/application.scss +8 -0
  79. data/templates/bin_deploy +12 -0
  80. data/templates/bin_setup +28 -0
  81. data/templates/bin_setup_review_app.erb +22 -0
  82. data/templates/browserslist +3 -0
  83. data/templates/bulldozer_gitignore +18 -0
  84. data/templates/bulldozer_layout.html.erb.erb +21 -0
  85. data/templates/bundler_audit.rake +4 -0
  86. data/templates/chromedriver.rb +17 -0
  87. data/templates/circle.yml.erb +6 -0
  88. data/templates/config_locales_en.yml.erb +19 -0
  89. data/templates/dev.rake +12 -0
  90. data/templates/dotfiles/.ctags +2 -0
  91. data/templates/dotfiles/.env +13 -0
  92. data/templates/email.rb +3 -0
  93. data/templates/errors.rb +34 -0
  94. data/templates/factories.rb +2 -0
  95. data/templates/factory_bot_rspec.rb +5 -0
  96. data/templates/flashes_helper.rb +5 -0
  97. data/templates/hound.yml +14 -0
  98. data/templates/i18n.rb +3 -0
  99. data/templates/json_encoding.rb +1 -0
  100. data/templates/postgresql_database.yml.erb +19 -0
  101. data/templates/puma.rb +28 -0
  102. data/templates/rack_mini_profiler.rb +5 -0
  103. data/templates/rails_helper.rb +22 -0
  104. data/templates/secrets.yml +8 -0
  105. data/templates/shoulda_matchers_config_rspec.rb +6 -0
  106. data/templates/smtp.rb +9 -0
  107. data/templates/spec_helper.rb +28 -0
  108. metadata +197 -0
@@ -0,0 +1,37 @@
1
+ require_relative "../base"
2
+
3
+ module Bulldozer
4
+ module Production
5
+ class EmailGenerator < Generators::Base
6
+ def smtp_configuration
7
+ copy_file "smtp.rb", "config/smtp.rb"
8
+
9
+ prepend_file "config/environments/production.rb",
10
+ %{require Rails.root.join("config/smtp")\n}
11
+ end
12
+
13
+ def use_smtp
14
+ config = <<-RUBY
15
+
16
+ config.action_mailer.delivery_method = :smtp
17
+ config.action_mailer.smtp_settings = SMTP_SETTINGS
18
+ RUBY
19
+
20
+ inject_into_file "config/environments/production.rb", config,
21
+ after: "config.action_mailer.perform_caching = false"
22
+ end
23
+
24
+ def env_vars
25
+ expand_json(
26
+ "app.json",
27
+ env: {
28
+ SMTP_ADDRESS: { required: true },
29
+ SMTP_DOMAIN: { required: true },
30
+ SMTP_PASSWORD: { required: true },
31
+ SMTP_USERNAME: { required: true },
32
+ },
33
+ )
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,11 @@
1
+ require_relative "../base"
2
+
3
+ module Bulldozer
4
+ module Production
5
+ class ForceTlsGenerator < Generators::Base
6
+ def config_enforce_ssl
7
+ configure_environment "production", "config.force_ssl = true"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,24 @@
1
+ require_relative "../base"
2
+
3
+ module Bulldozer
4
+ module Production
5
+ class ManifestGenerator < Generators::Base
6
+ def render_manifest
7
+ expand_json(
8
+ "app.json",
9
+ name: app_name.dasherize,
10
+ scripts: {},
11
+ env: {
12
+ APPLICATION_HOST: { required: true },
13
+ EMAIL_RECIPIENTS: { required: true },
14
+ HEROKU_APP_NAME: { required: true },
15
+ HEROKU_PARENT_APP_NAME: { required: true },
16
+ RACK_ENV: { required: true },
17
+ SECRET_KEY_BASE: { generator: "secret" },
18
+ },
19
+ addons: ["heroku-postgresql"],
20
+ )
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,21 @@
1
+ require_relative "../base"
2
+
3
+ module Bulldozer
4
+ module Production
5
+ class TimeoutGenerator < Generators::Base
6
+ def add_gem
7
+ gem "rack-timeout", group: :production
8
+ end
9
+
10
+ def configure_rack_timeout
11
+ append_file ".env", rack_timeout_config
12
+ end
13
+
14
+ private
15
+
16
+ def rack_timeout_config
17
+ %{RACK_TIMEOUT_SERVICE_TIMEOUT=10}
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,33 @@
1
+ require_relative "../base"
2
+
3
+ module Bulldozer
4
+ module Staging
5
+ class PullRequestsGenerator < Generators::Base
6
+ def configure_heroku_staging_pr_pipeline_host
7
+ config = <<-RUBY
8
+
9
+ if ENV.fetch("HEROKU_APP_NAME", "").include?("staging-pr-")
10
+ ENV["APPLICATION_HOST"] = ENV["HEROKU_APP_NAME"] + ".herokuapp.com"
11
+ ENV["ASSET_HOST"] = ENV["HEROKU_APP_NAME"] + ".herokuapp.com"
12
+ end
13
+ RUBY
14
+
15
+ inject_into_file(
16
+ "config/environments/production.rb",
17
+ config,
18
+ after: "Rails.application.configure do\n",
19
+ )
20
+ end
21
+
22
+ def create_review_apps_setup_script
23
+ template(
24
+ "bin_setup_review_app.erb",
25
+ "bin/setup_review_app",
26
+ force: true,
27
+ )
28
+
29
+ run "chmod a+x bin/setup_review_app"
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,10 @@
1
+ require_relative "base"
2
+
3
+ module Bulldozer
4
+ class StaticGenerator < Generators::Base
5
+ def add_high_voltage
6
+ gem "high_voltage"
7
+ Bundler.with_clean_env { run "bundle install" }
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,31 @@
1
+ require_relative "base"
2
+
3
+ module Bulldozer
4
+ class StylesheetBaseGenerator < Generators::Base
5
+ def add_stylesheet_gems
6
+ gem "bourbon", ">= 5.0.1"
7
+ gem "neat", ">= 3.0.1"
8
+ Bundler.with_clean_env { run "bundle install" }
9
+ end
10
+
11
+ def add_css_config
12
+ copy_file(
13
+ "application.scss",
14
+ "app/assets/stylesheets/application.scss",
15
+ force: true,
16
+ )
17
+ end
18
+
19
+ def remove_prior_config
20
+ remove_file "app/assets/stylesheets/application.css"
21
+ end
22
+
23
+ def install_bitters
24
+ run "bitters install --path app/assets/stylesheets"
25
+ end
26
+
27
+ def install_normalize_css
28
+ run "bin/yarn add normalize.css"
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,55 @@
1
+ require_relative "base"
2
+
3
+ module Bulldozer
4
+ class TestingGenerator < Generators::Base
5
+ def add_testing_gems
6
+ gem "spring-commands-rspec", group: :development
7
+ gem "rspec-rails", "~> 3.6", group: %i(development test)
8
+ gem "shoulda-matchers", group: :test
9
+
10
+ Bundler.with_clean_env { run "bundle install" }
11
+ end
12
+
13
+ def generate_rspec
14
+ generate "rspec:install"
15
+ end
16
+
17
+ def configure_rspec
18
+ remove_file "spec/rails_helper.rb"
19
+ remove_file "spec/spec_helper.rb"
20
+ copy_file "rails_helper.rb", "spec/rails_helper.rb"
21
+ copy_file "spec_helper.rb", "spec/spec_helper.rb"
22
+ end
23
+
24
+ def provide_shoulda_matchers_config
25
+ copy_file(
26
+ "shoulda_matchers_config_rspec.rb",
27
+ "spec/support/shoulda_matchers.rb",
28
+ )
29
+ end
30
+
31
+ def configure_spec_support_features
32
+ empty_directory_with_keep_file "spec/features"
33
+ empty_directory_with_keep_file "spec/support/features"
34
+ end
35
+
36
+ def configure_i18n_for_test_environment
37
+ copy_file "i18n.rb", "spec/support/i18n.rb"
38
+ end
39
+
40
+ def configure_action_mailer_in_specs
41
+ copy_file "action_mailer.rb", "spec/support/action_mailer.rb"
42
+ end
43
+
44
+ private
45
+
46
+ def empty_directory_with_keep_file(destination)
47
+ empty_directory(destination, {})
48
+ keep_file(destination)
49
+ end
50
+
51
+ def keep_file(destination)
52
+ create_file(File.join(destination, ".keep"))
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,30 @@
1
+ require_relative "base"
2
+
3
+ module Bulldozer
4
+ class ViewsGenerator < Generators::Base
5
+ def create_partials_directory
6
+ empty_directory "app/views/application"
7
+ end
8
+
9
+ def create_shared_flashes
10
+ copy_file "_flashes.html.erb", "app/views/application/_flashes.html.erb"
11
+ copy_file "flashes_helper.rb", "app/helpers/flashes_helper.rb"
12
+ end
13
+
14
+ def create_shared_javascripts
15
+ copy_file "_javascript.html.erb",
16
+ "app/views/application/_javascript.html.erb"
17
+ end
18
+
19
+ def create_shared_css_overrides
20
+ copy_file "_css_overrides.html.erb",
21
+ "app/views/application/_css_overrides.html.erb"
22
+ end
23
+
24
+ def create_application_layout
25
+ template "bulldozer_layout.html.erb.erb",
26
+ "app/views/layouts/application.html.erb",
27
+ force: true
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,8 @@
1
+ module Bulldozer
2
+ RAILS_VERSION = "~> 5.2.0".freeze
3
+ RUBY_VERSION = IO.
4
+ read("#{File.dirname(__FILE__)}/../../.ruby-version").
5
+ strip.
6
+ freeze
7
+ VERSION = "1.6.0".freeze
8
+ end
@@ -0,0 +1,72 @@
1
+ require "spec_helper"
2
+
3
+ module Bulldozer
4
+ module Adapters
5
+ RSpec.describe Heroku do
6
+ it "sets the heroku remotes" do
7
+ setup_file = "bin/setup"
8
+ app_builder = double(app_name: app_name)
9
+ allow(app_builder).to receive(:append_file)
10
+
11
+ Heroku.new(app_builder).set_heroku_remotes
12
+
13
+ expect(app_builder).to have_received(:append_file).
14
+ with(setup_file, /heroku join --app #{app_name.dasherize}-production/)
15
+ expect(app_builder).to have_received(:append_file).
16
+ with(setup_file, /heroku join --app #{app_name.dasherize}-staging/)
17
+ end
18
+
19
+ it "sets the heroku rails secrets" do
20
+ app_builder = double(app_name: app_name)
21
+ allow(app_builder).to receive(:run)
22
+
23
+ Heroku.new(app_builder).set_heroku_rails_secrets
24
+
25
+ expect(app_builder).to(
26
+ have_configured_var("staging", "SECRET_KEY_BASE"),
27
+ )
28
+ expect(app_builder).to(
29
+ have_configured_var("production", "SECRET_KEY_BASE"),
30
+ )
31
+ end
32
+
33
+ it "sets the heroku backup schedule" do
34
+ app_builder = double(app_name: app_name)
35
+ allow(app_builder).to receive(:run)
36
+
37
+ Heroku.new(app_builder).set_heroku_backup_schedule
38
+
39
+ expect(app_builder).to have_backup_schedule("staging")
40
+ expect(app_builder).to have_backup_schedule("production")
41
+ end
42
+
43
+ it "sets the application host" do
44
+ app_builder = double(app_name: app_name)
45
+ allow(app_builder).to receive(:run)
46
+
47
+ Heroku.new(app_builder).set_heroku_application_host
48
+
49
+ expect(app_builder).to(
50
+ have_configured_var("staging", "APPLICATION_HOST"),
51
+ )
52
+
53
+ expect(app_builder).to(
54
+ have_configured_var("production", "APPLICATION_HOST"),
55
+ )
56
+ end
57
+
58
+ def app_name
59
+ BulldozerTestHelpers::APP_NAME
60
+ end
61
+
62
+ def have_backup_schedule(remote_name)
63
+ have_received(:run).
64
+ with(/pg:backups:schedule DATABASE_URL --at '10:00 UTC' --remote #{remote_name}/)
65
+ end
66
+
67
+ def have_configured_var(remote_name, var)
68
+ have_received(:run).with(/config:add #{var}=.+ --remote #{remote_name}/)
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path(File.join('..', '..', 'support', 'fake_heroku'), File.dirname(__FILE__))
4
+
5
+ FakeHeroku.new(ARGV).run!
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path(File.join('..', '..', 'support', 'fake_github'), File.dirname(__FILE__))
4
+
5
+ FakeGithub.new(ARGV).run!
@@ -0,0 +1,18 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "Suspend a new project with --api flag" do
4
+ before(:all) do
5
+ drop_dummy_database
6
+ remove_project_directory
7
+ end
8
+
9
+ it "ensures project specs pass" do
10
+ run_bulldozer("--api")
11
+
12
+ Dir.chdir(project_path) do
13
+ Bundler.with_clean_env do
14
+ expect(`rake`).to include("0 failures")
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,36 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "Command line help output" do
4
+ let(:help_text) { bulldozer_help_command }
5
+
6
+ it "does not contain the default rails usage statement" do
7
+ expect(help_text).not_to include("rails new APP_PATH [options]")
8
+ end
9
+
10
+ it "provides the correct usage statement for bulldozer" do
11
+ expect(help_text).to include <<~EOH
12
+ Usage:
13
+ bulldozer APP_PATH [options]
14
+ EOH
15
+ end
16
+
17
+ it "does not contain the default rails group" do
18
+ expect(help_text).not_to include("Rails options:")
19
+ end
20
+
21
+ it "provides help and version usage within the bulldozer group" do
22
+ expect(help_text).to include <<~EOH
23
+ Bulldozer options:
24
+ -h, [--help], [--no-help] # Show this help message and quit
25
+ -v, [--version], [--no-version] # Show Bulldozer version number and quit
26
+ EOH
27
+ end
28
+
29
+ it "does not show the default extended rails help section" do
30
+ expect(help_text).not_to include("Create bulldozer files for app generator.")
31
+ end
32
+
33
+ it "contains the usage statement from the bulldozer gem" do
34
+ expect(help_text).to include IO.read(usage_file)
35
+ end
36
+ end
@@ -0,0 +1,16 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "GitHub" do
4
+ before do
5
+ drop_dummy_database
6
+ remove_project_directory
7
+ end
8
+
9
+ it "suspends a project with --github option" do
10
+ repo_name = "test"
11
+ run_bulldozer("--github=#{repo_name}")
12
+ setup_app_dependencies
13
+
14
+ expect(FakeGithub).to have_created_repo(repo_name)
15
+ end
16
+ end
@@ -0,0 +1,71 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "Heroku" do
4
+ context "--heroku" do
5
+ before(:all) do
6
+ clean_up
7
+ run_bulldozer("--heroku=true")
8
+ setup_app_dependencies
9
+ end
10
+
11
+ it "suspends a project for Heroku" do
12
+ app_name = BulldozerTestHelpers::APP_NAME.dasherize
13
+
14
+ expect(FakeHeroku).to have_created_app_for("staging")
15
+ expect(FakeHeroku).to have_created_app_for("production")
16
+ expect(FakeHeroku).to have_configured_vars("staging", "SECRET_KEY_BASE")
17
+ expect(FakeHeroku).to have_configured_vars(
18
+ "production",
19
+ "SECRET_KEY_BASE",
20
+ )
21
+ %w(staging production).each do |env|
22
+ expect(FakeHeroku).to have_configured_vars(env, "APPLICATION_HOST")
23
+ expect(FakeHeroku).to have_configured_vars(env, "HONEYBADGER_ENV")
24
+ end
25
+ expect(FakeHeroku).to have_setup_pipeline_for(app_name)
26
+
27
+ bin_setup_path = "#{project_path}/bin/setup"
28
+ bin_setup = IO.read(bin_setup_path)
29
+
30
+ expect(bin_setup).to match(/^if heroku join --app #{app_name}-production/)
31
+ expect(bin_setup).to match(/^if heroku join --app #{app_name}-staging/)
32
+ expect(bin_setup).to match(/^git config heroku.remote staging/)
33
+ expect("bin/setup").to be_executable
34
+
35
+ readme = IO.read("#{project_path}/README.md")
36
+
37
+ expect(readme).to include("./bin/deploy staging")
38
+ expect(readme).to include("./bin/deploy production")
39
+
40
+ circle_yml_path = "#{project_path}/circle.yml"
41
+ circle_yml = IO.read(circle_yml_path)
42
+
43
+ expect(circle_yml).to include <<-YML.strip_heredoc
44
+ deployment:
45
+ staging:
46
+ branch: master
47
+ commands:
48
+ - bin/deploy staging
49
+ YML
50
+ end
51
+ end
52
+
53
+ context "--heroku with region flag" do
54
+ before(:all) do
55
+ clean_up
56
+ run_bulldozer(%{--heroku=true --heroku-flags="--region eu"})
57
+ setup_app_dependencies
58
+ end
59
+
60
+ it "suspends a project with extra Heroku flags" do
61
+ expect(FakeHeroku).to have_created_app_for("staging", "--region eu")
62
+ expect(FakeHeroku).to have_created_app_for("production", "--region eu")
63
+ end
64
+ end
65
+
66
+ def clean_up
67
+ drop_dummy_database
68
+ remove_project_directory
69
+ FakeHeroku.clear!
70
+ end
71
+ end