Skip to content

Commit

Permalink
Prerequisites: Raise if Node version unsupported (#1202)
Browse files Browse the repository at this point in the history
Follow-up to #1201

It's not enough to ensure Node is installed. We also need to ensure the
consumer has the supported minimum version installed. Otherwise,
subsequent generators will raise errors like so:

```
error [email protected]: The engine "node" is incompatible with this module. Expected version ">=18.12.0". Got "18.0.0"
error Found incompatible module.
```

We select `v20.0.0` as our minimum supported version because it is
slated for Active LTS, but is not bleeding edge at [this time][]

We also raise when calling the template to avoid unnecessarily
generating a new Rails application.

[this time]: https://nodejs.org/en/about/previous-releases
  • Loading branch information
stevepolitodesign committed May 10, 2024
1 parent 6f68a52 commit 688622e
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 11 deletions.
1 change: 1 addition & 0 deletions lib/generators/suspenders/install/web_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class WebGenerator < Rails::Generators::Base
include Suspenders::Generators::APIAppUnsupported
include Suspenders::Generators::DatabaseUnsupported
include Suspenders::Generators::NodeNotInstalled
include Suspenders::Generators::NodeVersionUnsupported

source_root File.expand_path("../../../templates/install/web", __FILE__)
desc <<~MARKDOWN
Expand Down
1 change: 1 addition & 0 deletions lib/generators/suspenders/prerequisites_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module Generators
class PrerequisitesGenerator < Rails::Generators::Base
include Suspenders::Generators::Helpers
include Suspenders::Generators::NodeNotInstalled
include Suspenders::Generators::NodeVersionUnsupported

source_root File.expand_path("../../templates/prerequisites", __FILE__)

Expand Down
23 changes: 23 additions & 0 deletions lib/install/web.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,27 @@
def node_version
ENV["NODE_VERSION"] || `node --version`[/\d+\.\d+\.\d+/]
end

def node_not_installed?
!node_version.present?
end

def node_version_unsupported?
node_version < "20.0.0"
end

def apply_template!
if node_not_installed? || node_version_unsupported?
message = <<~ERROR
=== Node version unsupported ===
Suspenders requires Node >= 20.0.0
ERROR

fail Rails::Generators::Error, message
end
if options[:database] == "postgresql" && options[:skip_test]
after_bundle do
gem_group :development, :test do
Expand Down
29 changes: 26 additions & 3 deletions lib/suspenders/generators.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ def rspec_test_helper_present?
def node_version
ENV["NODE_VERSION"] || `node --version`[/\d+\.\d+\.\d+/]
end

def node_not_installed?
!node_version.present?
end

def node_version_unsupported?
node_version < Suspenders::MINIMUM_NODE_VERSION
end
end

module APIAppUnsupported
Expand Down Expand Up @@ -81,6 +89,9 @@ def database_unsupported?

module NodeNotInstalled
class Error < StandardError
def message
"This generator requires Node"
end
end

extend ActiveSupport::Concern
Expand All @@ -92,11 +103,23 @@ def raise_if_node_not_installed
end
end
end
end

private
module NodeVersionUnsupported
class Error < StandardError
def message
"This generator requires Node >= #{Suspenders::MINIMUM_NODE_VERSION}"
end
end

def node_not_installed?
!node_version.present?
extend ActiveSupport::Concern

included do
def raise_if_node_version_unsupported
if node_version_unsupported?
raise Suspenders::Generators::NodeVersionUnsupported::Error
end
end
end
end
end
Expand Down
1 change: 1 addition & 0 deletions lib/suspenders/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ module Suspenders
VERSION = "3.0.0".freeze
RAILS_VERSION = "~> 7.0".freeze
MINIMUM_RUBY_VERSION = ">= 3.1".freeze
MINIMUM_NODE_VERSION = "20.0.0".freeze
end
10 changes: 10 additions & 0 deletions test/generators/suspenders/install/web_generator_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ class WebGeneratorTest < Rails::Generators::TestCase
end
end

test "raises if Node is unsupported" do
Object.any_instance.stubs(:`).returns("v19.9.9\n")

with_database "postgresql" do
assert_raises Suspenders::Generators::NodeVersionUnsupported::Error do
run_generator
end
end
end

private

def prepare_destination
Expand Down
18 changes: 14 additions & 4 deletions test/generators/suspenders/prerequisites_generator_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,22 @@ class PrerequisitesGeneratorTest < Rails::Generators::TestCase
teardown :restore_destination

test "generates .node-version file (from ENV)" do
ClimateControl.modify NODE_VERSION: "1.2.3" do
ClimateControl.modify NODE_VERSION: "20.0.0" do
run_generator

assert_file app_root(".node-version") do |file|
assert_match(/1\.2\.3/, file)
assert_match(/20\.0\.0/, file)
end
end
end

test "generates .node-version file (from system)" do
Object.any_instance.stubs(:`).returns("v1.2.3\n")
Object.any_instance.stubs(:`).returns("v20.0.0\n")

run_generator

assert_file app_root(".node-version") do |file|
assert_match(/1\.2\.3/, file)
assert_match(/20\.0\.0/, file)
end
end

Expand All @@ -41,6 +41,16 @@ class PrerequisitesGeneratorTest < Rails::Generators::TestCase
assert_no_file app_root(".node-version")
end

test "raises if Node is unsupported" do
Object.any_instance.stubs(:`).returns("v19.9.9\n")

assert_raises Suspenders::Generators::NodeVersionUnsupported::Error do
run_generator
end

assert_no_file app_root(".node-version")
end

private

def restore_destination
Expand Down
4 changes: 2 additions & 2 deletions test/suspenders/cleanup/generate_readme_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module Suspenders
module Cleanup
class GenerateReadmeTest < ActiveSupport::TestCase
test "generates README using generator descriptions" do
Object.any_instance.stubs(:`).returns("v1.2.3\n")
Object.any_instance.stubs(:`).returns("v20.0.0\n")

Tempfile.create "README.md" do |readme|
path = readme.path
Expand All @@ -20,7 +20,7 @@ class GenerateReadmeTest < ActiveSupport::TestCase

assert_match "## Prerequisites", readme
assert_match Suspenders::MINIMUM_RUBY_VERSION, readme
assert_match "Node: `1.2.3`", readme
assert_match "Node: `20.0.0`", readme

assert_match "## Configuration", readme
assert_match "### Test", readme
Expand Down
20 changes: 18 additions & 2 deletions test/suspenders/generators_test.rb
Original file line number Diff line number Diff line change
@@ -1,19 +1,35 @@
require "test_helper"

class Suspenders::GeneratorsTest < ActiveSupport::TestCase
class APIAppUnsupportedTest < Suspenders::GeneratorsTest
class APIAppUnsupportedTest < ActiveSupport::TestCase
test "message returns a custom message" do
expected = "This generator cannot be used on API only applications."

assert_equal expected, Suspenders::Generators::APIAppUnsupported::Error.new.message
end
end

class DatabaseUnsupportedTest < Suspenders::GeneratorsTest
class DatabaseUnsupportedTest < ActiveSupport::TestCase
test "message returns a custom message" do
expected = "This generator requires PostgreSQL"

assert_equal expected, Suspenders::Generators::DatabaseUnsupported::Error.new.message
end
end

class NodeNotInstalledTest < ActiveSupport::TestCase
test "message returns a custom message" do
expected = "This generator requires Node"

assert_equal expected, Suspenders::Generators::NodeNotInstalled::Error.new.message
end
end

class NodeVersionUnsupportedTest < ActiveSupport::TestCase
test "message returns a custom message" do
expected = "This generator requires Node >= #{Suspenders::MINIMUM_NODE_VERSION}"

assert_equal expected, Suspenders::Generators::NodeVersionUnsupported::Error.new.message
end
end
end
4 changes: 4 additions & 0 deletions test/suspenders_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,8 @@ class SuspendersTest < ActiveSupport::TestCase
test "it has a Minimum Ruby version number" do
assert Suspenders::MINIMUM_RUBY_VERSION
end

test "it has a Minimum Node version number" do
assert Suspenders::MINIMUM_NODE_VERSION
end
end

0 comments on commit 688622e

Please sign in to comment.