From cb2d6e6b598df2dbd1cdebcf7f0b955ed16cd355 Mon Sep 17 00:00:00 2001 From: Greggory Rothmeier Date: Mon, 5 Aug 2019 15:03:53 -0700 Subject: [PATCH 1/6] Run generators within application bundle The test is creating a mock application, but isn't including the "stitches" gem in the Gemfile in as the directions indicate, so even though the generator is adding "apitome" to the application's Gemfile, it's still necessary to have "apitome" as a runtime dependency of the gem. The gem inserts "apitome" and "rspec-rails" (now adds, rather than assuming it already there) and within the gem context of the application executes the generators and updates the files. --- README.md | 2 - lib/stitches.rb | 2 - lib/stitches/api_generator.rb | 62 ++++++++++++----------- spec/integration/add_to_rails_app_spec.rb | 16 +++--- stitches.gemspec | 4 +- 5 files changed, 42 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index aad611c..2f976f7 100644 --- a/README.md +++ b/README.md @@ -29,8 +29,6 @@ bundle install Then, set it up: ``` -> bin/rails generate rspec:install -> bin/rails generate apitome:install > bin/rails generate stitches:api > bundle exec rake db:migrate ``` diff --git a/lib/stitches.rb b/lib/stitches.rb index 3f9f3ff..e946ae9 100644 --- a/lib/stitches.rb +++ b/lib/stitches.rb @@ -1,4 +1,2 @@ require 'stitches_norailtie' require 'stitches/railtie' -# Add new stitches ruby files to the stitches_norailtie file instead of here -require 'apitome' diff --git a/lib/stitches/api_generator.rb b/lib/stitches/api_generator.rb index c30288f..0d966ae 100644 --- a/lib/stitches/api_generator.rb +++ b/lib/stitches/api_generator.rb @@ -4,7 +4,7 @@ module Stitches class ApiGenerator < Rails::Generators::Base include Rails::Generators::Migration - source_root(File.expand_path(File.join(File.dirname(__FILE__),"generator_files"))) + source_root(File.expand_path(File.join(File.dirname(__FILE__), "generator_files"))) def self.next_migration_number(path) Time.now.utc.strftime("%Y%m%d%H%M%S") @@ -12,14 +12,22 @@ def self.next_migration_number(path) desc "Bootstraps your API service with a basic ping controller and spec to ensure everything is setup properly" def bootstrap_api - inject_into_file "Gemfile", after: /^gem ['"]rails['"].*$/ do<<-GEM - -gem "apitome" -gem "responders" -gem "rspec_api_documentation", group: [ :development, :test ] -gem "capybara", group: [ :development, :test ] - GEM + gem "stitches" + gem "apitome" + gem "responders" + gem_group :development, :test do + gem "rspec" + gem "rspec-rails" + gem "rspec_api_documentation" end + + run "bundle install" + generate "apitome:install" + generate "rspec:install" + + gsub_file 'config/initializers/apitome.rb', /config.mount_at = .*$/, "config.mount_at = nil" + gsub_file 'config/initializers/apitome.rb', /config.title = .*$/, "config.title = 'Service Documentation'" + inject_into_file "config/routes.rb", before: /^end/ do<<-ROUTES namespace :api do scope module: :v1, constraints: Stitches::ApiVersionConstraint.new(1) do @@ -32,15 +40,14 @@ def bootstrap_api # as well as for your client to be able to validate this as well. end end -api_docs = Rack::Auth::Basic.new(Apitome::Engine ) do |_,password| + +api_docs = Rack::Auth::Basic.new(Apitome::Engine) do |_, password| password == ENV['HTTP_AUTH_PASSWORD'] end mount api_docs, at: "docs" ROUTES end - run 'bundle install' - copy_file "app/controllers/api.rb" copy_file "app/controllers/api/api_controller.rb" copy_file "app/controllers/api/v1.rb" @@ -53,8 +60,6 @@ def bootstrap_api template "spec/features/api_spec.rb.erb", "spec/features/api_spec.rb" copy_file "spec/acceptance/ping_v1_spec.rb", "spec/acceptance/ping_v1_spec.rb" - run 'bundle install' - migration_template "db/migrate/enable_uuid_ossp_extension.rb", "db/migrate/enable_uuid_ossp_extension.rb" sleep 1 # allow clock to tick so we get different numbers migration_template "db/migrate/create_api_clients.rb", "db/migrate/create_api_clients.rb" @@ -70,26 +75,23 @@ def bootstrap_api append_to_file 'spec/rails_helper.rb' do<<-RSPEC_API require 'rspec_api_documentation' + RspecApiDocumentation.configure do |config| -config.format = :json -config.request_headers_to_include = %w( - Accept - Content-Type - Authorization - If-Modified-Since -) -config.response_headers_to_include = %w( - Last-Modified - ETag -) -config.api_name = "YOUR SERVICE NAME HERE" + config.format = :json + config.request_headers_to_include = %w( + Accept + Content-Type + Authorization + If-Modified-Since + ) + config.response_headers_to_include = %w( + Last-Modified + ETag + ) + config.api_name = "YOUR SERVICE NAME HERE" end - RSPEC_API +RSPEC_API end - run "rails g apitome:install" - gsub_file 'config/initializers/apitome.rb', /config.mount_at = .*$/, "config.mount_at = nil" - gsub_file 'config/initializers/apitome.rb', /config.title = .*$/, "config.title = 'Service Documentation'" - end end end diff --git a/spec/integration/add_to_rails_app_spec.rb b/spec/integration/add_to_rails_app_spec.rb index c0c0609..51fddf5 100644 --- a/spec/integration/add_to_rails_app_spec.rb +++ b/spec/integration/add_to_rails_app_spec.rb @@ -7,7 +7,7 @@ let(:rails_app_name) { "swamp-thing" } def run(command) - stdout, stderr, stat = Open3.capture3(command) + stdout, stderr, stat = Bundler.with_original_env { Open3.capture3(command) } success = stat.success? && stdout !~ /Could not find generator/im if ENV["DEBUG"] == 'true' || !success @@ -37,17 +37,23 @@ def run(command) "--no-rc", "--skip-bundle", ].join(" ") + + # Use this local version of stitches rather than the one on Rubygems + gem_path = File.expand_path("../..", File.dirname(__FILE__)) + use_local_stitches = %{echo "gem 'stitches', path: '#{gem_path}'" >> Gemfile} + FileUtils.chdir work_dir do run rails_new + FileUtils.chdir rails_app_name do + run use_local_stitches + run "bundle install" example.run end end end it "works as described in the README" do - run "bin/rails generate rspec:install" - run "bin/rails generate apitome:install" run "bin/rails generate stitches:api" rails_root = Pathname(work_dir) / rails_app_name @@ -81,8 +87,6 @@ def run(command) end it "inserts the deprecation module into ApiController" do - run "bin/rails generate rspec:install" - run "bin/rails generate apitome:install" run "bin/rails generate stitches:api" rails_root = Pathname(work_dir) / rails_app_name @@ -106,8 +110,6 @@ def run(command) end it "inserts can update old configuration" do - run "bin/rails generate rspec:install" - run "bin/rails generate apitome:install" run "bin/rails generate stitches:api" rails_root = Pathname(work_dir) / rails_app_name diff --git a/stitches.gemspec b/stitches.gemspec index 2cfb2e5..76afc76 100644 --- a/stitches.gemspec +++ b/stitches.gemspec @@ -20,10 +20,8 @@ Gem::Specification.new do |s| s.add_runtime_dependency("rails") s.add_runtime_dependency("pg") - s.add_runtime_dependency("rspec", ">= 3") - s.add_runtime_dependency("rspec-rails", "~> 3") - s.add_runtime_dependency("apitome") + s.add_development_dependency("rspec", ">= 3") s.add_development_dependency("rake") s.add_development_dependency("rspec_junit_formatter") end From 397198e8567dde09c27451cc4ca1bc92f4402c33 Mon Sep 17 00:00:00 2001 From: Greggory Rothmeier Date: Mon, 5 Aug 2019 17:19:33 -0700 Subject: [PATCH 2/6] Specify the gemfile explicitly BUNDLE_GEMFILE is being set in CI to switch which version of Rails the gem builds against, but that also has the consequence of changin the Gemfile the sample application is looking for. --- .gitignore | 1 + spec/integration/add_to_rails_app_spec.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 29b3d2f..d93dd81 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ config/database.yml .jhw-cache **.orig Gemfile.lock +Gemfile.*.lock .projections.json diff --git a/spec/integration/add_to_rails_app_spec.rb b/spec/integration/add_to_rails_app_spec.rb index 51fddf5..7a965f0 100644 --- a/spec/integration/add_to_rails_app_spec.rb +++ b/spec/integration/add_to_rails_app_spec.rb @@ -7,7 +7,7 @@ let(:rails_app_name) { "swamp-thing" } def run(command) - stdout, stderr, stat = Bundler.with_original_env { Open3.capture3(command) } + stdout, stderr, stat = Bundler.with_original_env { Open3.capture3({ 'BUNDLE_GEMFILE' => 'Gemfile' }, command) } success = stat.success? && stdout !~ /Could not find generator/im if ENV["DEBUG"] == 'true' || !success From 1de3bc8f8bf4e4a2caee6d007a8d39b0e2638132 Mon Sep 17 00:00:00 2001 From: Greggory Rothmeier Date: Tue, 6 Aug 2019 16:50:43 -0700 Subject: [PATCH 3/6] Install gems before bundling Otherwise bundler seems to not be able to pull the gems down from rubygems. I don't have this problem locally or when I test the gem, so I believe this something to do with the testing. --- spec/integration/add_to_rails_app_spec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/integration/add_to_rails_app_spec.rb b/spec/integration/add_to_rails_app_spec.rb index 7a965f0..4879090 100644 --- a/spec/integration/add_to_rails_app_spec.rb +++ b/spec/integration/add_to_rails_app_spec.rb @@ -7,7 +7,7 @@ let(:rails_app_name) { "swamp-thing" } def run(command) - stdout, stderr, stat = Bundler.with_original_env { Open3.capture3({ 'BUNDLE_GEMFILE' => 'Gemfile' }, command) } + stdout, stderr, stat = Bundler.with_clean_env { Open3.capture3({ 'BUNDLE_GEMFILE' => 'Gemfile' }, command) } success = stat.success? && stdout !~ /Could not find generator/im if ENV["DEBUG"] == 'true' || !success @@ -48,6 +48,7 @@ def run(command) FileUtils.chdir rails_app_name do run use_local_stitches run "bundle install" + run "gem install apitome responders rspec-rails rspec_api_documentation" example.run end end From 16456f48e86fd17e0f141a9911fc09cba259f8be Mon Sep 17 00:00:00 2001 From: Greggory Rothmeier Date: Tue, 6 Aug 2019 18:34:29 -0700 Subject: [PATCH 4/6] Try a single clean env block --- spec/integration/add_to_rails_app_spec.rb | 24 +++++++++++------------ 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/spec/integration/add_to_rails_app_spec.rb b/spec/integration/add_to_rails_app_spec.rb index 4879090..82d8158 100644 --- a/spec/integration/add_to_rails_app_spec.rb +++ b/spec/integration/add_to_rails_app_spec.rb @@ -5,9 +5,10 @@ RSpec.describe "Adding Stitches to a New Rails App", :integration do let(:work_dir) { Dir.mktmpdir } let(:rails_app_name) { "swamp-thing" } + let(:rails_root) { Pathname(work_dir) / rails_app_name } def run(command) - stdout, stderr, stat = Bundler.with_clean_env { Open3.capture3({ 'BUNDLE_GEMFILE' => 'Gemfile' }, command) } + stdout, stderr, stat = Open3.capture3({ 'BUNDLE_GEMFILE' => rails_root.join('Gemfile').to_path }, command) success = stat.success? && stdout !~ /Could not find generator/im if ENV["DEBUG"] == 'true' || !success @@ -42,14 +43,16 @@ def run(command) gem_path = File.expand_path("../..", File.dirname(__FILE__)) use_local_stitches = %{echo "gem 'stitches', path: '#{gem_path}'" >> Gemfile} - FileUtils.chdir work_dir do - run rails_new + Bundler.with_clean_env do + FileUtils.chdir work_dir do + run rails_new - FileUtils.chdir rails_app_name do - run use_local_stitches - run "bundle install" - run "gem install apitome responders rspec-rails rspec_api_documentation" - example.run + FileUtils.chdir rails_app_name do + run use_local_stitches + run "gem install apitome responders rspec-rails rspec_api_documentation" + run "bundle install" + example.run + end end end end @@ -57,8 +60,6 @@ def run(command) it "works as described in the README" do run "bin/rails generate stitches:api" - rails_root = Pathname(work_dir) / rails_app_name - # Yuck! So much duplication! BUT: Rails app templates have a notoriously silent failure mode, so mostly # what this is doing is ensuring that the generator inserted stuff when asked and that the very basics of what happens # during generation are there. It's gross, and I'm sorry. @@ -89,8 +90,6 @@ def run(command) it "inserts the deprecation module into ApiController" do run "bin/rails generate stitches:api" - - rails_root = Pathname(work_dir) / rails_app_name api_controller = rails_root / "app" / "controllers" / "api" / "api_controller.rb" api_controller_contents = File.read(api_controller).split(/\n/) @@ -113,7 +112,6 @@ def run(command) it "inserts can update old configuration" do run "bin/rails generate stitches:api" - rails_root = Pathname(work_dir) / rails_app_name initializer = rails_root / "config" / "initializers" / "stitches.rb" initializer_contents = File.read(initializer).split(/\n/) From d23b451af2905e571bac6fe399f78f00e6d7e233 Mon Sep 17 00:00:00 2001 From: Greggory Rothmeier Date: Wed, 7 Aug 2019 12:43:25 -0700 Subject: [PATCH 5/6] Remove responders dependency As of https://github.com/stitchfix/stitches/pull/72 this gem is no longer necessary. --- lib/stitches/api_generator.rb | 1 - spec/integration/add_to_rails_app_spec.rb | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/stitches/api_generator.rb b/lib/stitches/api_generator.rb index 0d966ae..b9427cd 100644 --- a/lib/stitches/api_generator.rb +++ b/lib/stitches/api_generator.rb @@ -14,7 +14,6 @@ def self.next_migration_number(path) def bootstrap_api gem "stitches" gem "apitome" - gem "responders" gem_group :development, :test do gem "rspec" gem "rspec-rails" diff --git a/spec/integration/add_to_rails_app_spec.rb b/spec/integration/add_to_rails_app_spec.rb index 82d8158..c91e5a4 100644 --- a/spec/integration/add_to_rails_app_spec.rb +++ b/spec/integration/add_to_rails_app_spec.rb @@ -49,7 +49,7 @@ def run(command) FileUtils.chdir rails_app_name do run use_local_stitches - run "gem install apitome responders rspec-rails rspec_api_documentation" + run "gem install apitome rspec-rails rspec_api_documentation" run "bundle install" example.run end @@ -68,9 +68,7 @@ def run(command) aggregate_failures do expect(File.exist?(rails_root / "app" / "controllers" / "api" / "api_controller.rb")).to eq(true) expect(rails_root / "Gemfile").to contain_gem("apitome") - expect(rails_root / "Gemfile").to contain_gem("responders") expect(rails_root / "Gemfile").to contain_gem("rspec_api_documentation") - expect(rails_root / "Gemfile").to contain_gem("capybara") expect(rails_root / "config" / "routes.rb").to have_route(namespace: :api, module_scope: :v1, resource: 'ping') expect(rails_root / "config" / "routes.rb").to have_route(namespace: :api, module_scope: :v2, resource: 'ping') expect(rails_root / "config" / "routes.rb").to have_mounted_engine("Apitome::Engine") From 8c9282c963bcf7bd3e5f9706668098fb5904a2b7 Mon Sep 17 00:00:00 2001 From: Greggory Rothmeier Date: Wed, 7 Aug 2019 13:07:31 -0700 Subject: [PATCH 6/6] Comment on odd spec step --- spec/integration/add_to_rails_app_spec.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/integration/add_to_rails_app_spec.rb b/spec/integration/add_to_rails_app_spec.rb index c91e5a4..5755b07 100644 --- a/spec/integration/add_to_rails_app_spec.rb +++ b/spec/integration/add_to_rails_app_spec.rb @@ -49,6 +49,8 @@ def run(command) FileUtils.chdir rails_app_name do run use_local_stitches + # It's unclear why, but on CI the gems are not found when installed + # through bundler however installing them explicitly first fixes it. run "gem install apitome rspec-rails rspec_api_documentation" run "bundle install" example.run