From db14f14dc2511e26b3a7e6f7311eeaf338e36914 Mon Sep 17 00:00:00 2001 From: Steve Polito Date: Fri, 3 May 2024 14:33:51 -0400 Subject: [PATCH] Prerequisites: Use system version of Node We were incorrectly assuming consumers had the version of Node installed that is declared in `Suspenders::NODE_LTS_VERSION`. Because of this, we were generating a `.node-version` file with a version that was not installed on the user's system. This was a problem because when subsequent generators depending on Node where invoked, they would raise the following: ``` No preset version installed for command node Please install a version by running one of the following: asdf install nodejs 20.11.1 ``` To account for this, we [borrow][] from Rails, but modify slightly. First, we look to see if `ENV["NODE_VERSION"]` is set. If not, we then look to see if Node is installed, and set the version via `node --version`. If neither of those values are present, we raise. This is because we can't use a fallback value, since the consumer does not have Node installed on their system. Removes `Suspenders::NODE_LTS_VERSION` since it's no longer used as a fallback. Introduced [climate_control][] as a development dependency in order to test this feature. [borrow]: https://github.com/rails/rails/blob/d65fec4fd2a047533408cbbd4824b248adc0e3fd/railties/lib/rails/generators/app_base.rb#L521-L529 [climate_control]: https://github.com/thoughtbot/climate_control --- Gemfile.lock | 2 ++ .../suspenders/install/web_generator.rb | 1 + .../suspenders/prerequisites_generator.rb | 5 +++- .../templates/prerequisites/node-version.tt | 2 +- lib/suspenders/cleanup/generate_readme.rb | 4 ++- lib/suspenders/generators.rb | 27 +++++++++++++++++++ lib/suspenders/version.rb | 1 - suspenders.gemspec | 1 + .../suspenders/install/web_generator_test.rb | 10 +++++++ .../prerequisites_generator_test.rb | 27 +++++++++++++++++-- .../cleanup/generate_readme_test.rb | 4 ++- test/suspenders_test.rb | 4 --- 12 files changed, 77 insertions(+), 11 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 7287ff99c..81d31eafb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -84,6 +84,7 @@ GEM base64 (0.1.1) bigdecimal (3.1.4) builder (3.2.4) + climate_control (1.2.0) concurrent-ruby (1.2.2) connection_pool (2.4.1) crass (1.0.6) @@ -234,6 +235,7 @@ PLATFORMS x86_64-linux DEPENDENCIES + climate_control mocha puma sqlite3 diff --git a/lib/generators/suspenders/install/web_generator.rb b/lib/generators/suspenders/install/web_generator.rb index 0b5172272..c6e08f23e 100644 --- a/lib/generators/suspenders/install/web_generator.rb +++ b/lib/generators/suspenders/install/web_generator.rb @@ -4,6 +4,7 @@ module Install class WebGenerator < Rails::Generators::Base include Suspenders::Generators::APIAppUnsupported include Suspenders::Generators::DatabaseUnsupported + include Suspenders::Generators::NodeNotInstalled source_root File.expand_path("../../../templates/install/web", __FILE__) desc <<~MARKDOWN diff --git a/lib/generators/suspenders/prerequisites_generator.rb b/lib/generators/suspenders/prerequisites_generator.rb index e96fb1d21..91f1ca6e0 100644 --- a/lib/generators/suspenders/prerequisites_generator.rb +++ b/lib/generators/suspenders/prerequisites_generator.rb @@ -1,13 +1,16 @@ module Suspenders module Generators class PrerequisitesGenerator < Rails::Generators::Base + include Suspenders::Generators::Helpers + include Suspenders::Generators::NodeNotInstalled + source_root File.expand_path("../../templates/prerequisites", __FILE__) desc <<~MARKDOWN Creates `.node-version` file set to the current LTS version. MARKDOWN - def node_version + def set_node_version template "node-version", ".node-version" end end diff --git a/lib/generators/templates/prerequisites/node-version.tt b/lib/generators/templates/prerequisites/node-version.tt index 934c88064..e31b5f423 100644 --- a/lib/generators/templates/prerequisites/node-version.tt +++ b/lib/generators/templates/prerequisites/node-version.tt @@ -1 +1 @@ -<%= Suspenders::NODE_LTS_VERSION %> +<%= node_version %> diff --git a/lib/suspenders/cleanup/generate_readme.rb b/lib/suspenders/cleanup/generate_readme.rb index d6de5fee7..13ae6e04e 100644 --- a/lib/suspenders/cleanup/generate_readme.rb +++ b/lib/suspenders/cleanup/generate_readme.rb @@ -16,6 +16,8 @@ module Suspenders module Cleanup class GenerateReadme + include Suspenders::Generators::Helpers + def self.perform(readme, app_name) new(readme, app_name).perform end @@ -153,7 +155,7 @@ def prerequisites @file.write <<~MARKDOWN Ruby: `#{Suspenders::MINIMUM_RUBY_VERSION}` - Node: `#{Suspenders::NODE_LTS_VERSION}` + Node: `#{node_version}` MARKDOWN new_line diff --git a/lib/suspenders/generators.rb b/lib/suspenders/generators.rb index 6343f75ff..1588d42e8 100644 --- a/lib/suspenders/generators.rb +++ b/lib/suspenders/generators.rb @@ -18,6 +18,10 @@ def default_test_helper_present? def rspec_test_helper_present? File.exist? Rails.root.join("spec/rails_helper.rb") end + + def node_version + ENV["NODE_VERSION"] || `node --version`[/\d+\.\d+\.\d+/] + end end module APIAppUnsupported @@ -46,6 +50,8 @@ def api_only_app? end module DatabaseUnsupported + include Helpers + class Error < StandardError def message "This generator requires PostgreSQL" @@ -72,5 +78,26 @@ def database_unsupported? end end end + + module NodeNotInstalled + class Error < StandardError + end + + extend ActiveSupport::Concern + + included do + def raise_if_node_not_installed + if node_not_installed? + raise Suspenders::Generators::NodeNotInstalled::Error + end + end + end + + private + + def node_not_installed? + !node_version.present? + end + end end end diff --git a/lib/suspenders/version.rb b/lib/suspenders/version.rb index bad1e5174..8f46d901c 100644 --- a/lib/suspenders/version.rb +++ b/lib/suspenders/version.rb @@ -2,5 +2,4 @@ module Suspenders VERSION = "3.0.0".freeze RAILS_VERSION = "~> 7.0".freeze MINIMUM_RUBY_VERSION = ">= 3.1".freeze - NODE_LTS_VERSION = "20.11.1".freeze end diff --git a/suspenders.gemspec b/suspenders.gemspec index c0588195f..c6fc589fa 100644 --- a/suspenders.gemspec +++ b/suspenders.gemspec @@ -27,6 +27,7 @@ Gem::Specification.new do |spec| spec.add_dependency "rails", Suspenders::RAILS_VERSION + spec.add_development_dependency "climate_control" spec.add_development_dependency "mocha" spec.add_development_dependency "standard" end diff --git a/test/generators/suspenders/install/web_generator_test.rb b/test/generators/suspenders/install/web_generator_test.rb index 5c7ff4be1..b5c777448 100644 --- a/test/generators/suspenders/install/web_generator_test.rb +++ b/test/generators/suspenders/install/web_generator_test.rb @@ -28,6 +28,16 @@ class WebGeneratorTest < Rails::Generators::TestCase end end + test "raises if Node is not installed" do + Object.any_instance.stubs(:`).returns("") + + with_database "postgresql" do + assert_raises Suspenders::Generators::NodeNotInstalled::Error do + run_generator + end + end + end + private def prepare_destination diff --git a/test/generators/suspenders/prerequisites_generator_test.rb b/test/generators/suspenders/prerequisites_generator_test.rb index 70d065dd5..99910867b 100644 --- a/test/generators/suspenders/prerequisites_generator_test.rb +++ b/test/generators/suspenders/prerequisites_generator_test.rb @@ -1,4 +1,5 @@ require "test_helper" +require "climate_control" require "generators/suspenders/prerequisites_generator" module Suspenders @@ -10,14 +11,36 @@ class PrerequisitesGeneratorTest < Rails::Generators::TestCase destination Rails.root teardown :restore_destination - test "generates .node-version file" do + test "generates .node-version file (from ENV)" do + ClimateControl.modify NODE_VERSION: "1.2.3" do + run_generator + + assert_file app_root(".node-version") do |file| + assert_match(/1\.2\.3/, file) + end + end + end + + test "generates .node-version file (from system)" do + Object.any_instance.stubs(:`).returns("v1.2.3\n") + run_generator assert_file app_root(".node-version") do |file| - assert_match(/20\.11\.1/, file) + assert_match(/1\.2\.3/, file) end end + test "raises if Node is not installed" do + Object.any_instance.stubs(:`).returns("") + + assert_raises Suspenders::Generators::NodeNotInstalled::Error do + run_generator + end + + assert_no_file app_root(".node-version") + end + private def restore_destination diff --git a/test/suspenders/cleanup/generate_readme_test.rb b/test/suspenders/cleanup/generate_readme_test.rb index 1c54efeb6..1dc8899a8 100644 --- a/test/suspenders/cleanup/generate_readme_test.rb +++ b/test/suspenders/cleanup/generate_readme_test.rb @@ -6,6 +6,8 @@ module Suspenders module Cleanup class GenerateReadmeTest < ActiveSupport::TestCase test "generates README using generator descriptions" do + Object.any_instance.stubs(:`).returns("v1.2.3\n") + Tempfile.create "README.md" do |readme| path = readme.path @@ -18,7 +20,7 @@ class GenerateReadmeTest < ActiveSupport::TestCase assert_match "## Prerequisites", readme assert_match Suspenders::MINIMUM_RUBY_VERSION, readme - assert_match Suspenders::NODE_LTS_VERSION, readme + assert_match "Node: `1.2.3`", readme assert_match "## Configuration", readme assert_match "### Test", readme diff --git a/test/suspenders_test.rb b/test/suspenders_test.rb index cf14b1478..948ef5022 100644 --- a/test/suspenders_test.rb +++ b/test/suspenders_test.rb @@ -12,8 +12,4 @@ class SuspendersTest < ActiveSupport::TestCase test "it has a Minimum Ruby version number" do assert Suspenders::MINIMUM_RUBY_VERSION end - - test "it has a Node LTS version number" do - assert Suspenders::NODE_LTS_VERSION - end end