Skip to content
This repository has been archived by the owner on Jun 1, 2023. It is now read-only.

Commit

Permalink
Check if EP packages are up to date before allowing script push (#876)
Browse files Browse the repository at this point in the history
* Check if EP packages are up to date before allowing script push

* Move error class and update error handler

* Try to fix linter errors

* Another attempt at making the linter happy

* Move check to when we see if dependencies are installed

* Change error message

* Lowercase npm

* Actually check error messages
  • Loading branch information
jeffcharles authored Sep 14, 2020
1 parent 657bdfa commit 057b998
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ def install_dependencies

def dependencies_installed?
# Assuming if node_modules folder exist at root of script folder, all deps are installed
ctx.dir_exist?("node_modules")
return false unless ctx.dir_exist?("node_modules")
check_if_ep_dependencies_up_to_date!
true
end

private
Expand All @@ -58,6 +60,39 @@ def compile
def bytecode
File.read(format(BYTECODE_FILE, name: script_name))
end

def check_if_ep_dependencies_up_to_date!
return true if ENV['SHOPIFY_CLI_SCRIPTS_IGNORE_OUTDATED']

# ignore exit code since it will not be 0 unless every package is up to date which they probably won't be
out, _ = ctx.capture2e("npm", "outdated", "--json", "--depth", "0")
parsed_outdated_check = JSON.parse(out)
outdated_ep_packages = parsed_outdated_check
.select { |package_name, _| package_name.start_with?('@shopify/extension-point-as-') }
.select { |_, version_info| !package_is_up_to_date?(version_info) }
.keys
raise Errors::PackagesOutdatedError.new(outdated_ep_packages),
"NPM packages out of date: #{outdated_ep_packages.join(', ')}" unless outdated_ep_packages.empty?
end

def package_is_up_to_date?(version_info)
require 'semantic/semantic'
current_version = version_info['current']
latest_version = version_info['latest']

# making an assumption that the script developer knows what they're doing if they're not referencing a
# semver version
begin
current_version = ::Semantic::Version.new(current_version)
latest_version = ::Semantic::Version.new(latest_version)
rescue ArgumentError
return true
end

return false if current_version.major < latest_version.major
return false if latest_version.major == 0 && current_version.minor < latest_version.minor
true
end
end
end
end
Expand Down
7 changes: 7 additions & 0 deletions lib/project_types/script/layers/infrastructure/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ class ShopAuthenticationError < ScriptProjectError; end
class ShopScriptConflictError < ScriptProjectError; end
class ShopScriptUndefinedError < ScriptProjectError; end
class TaskRunnerNotFoundError < ScriptProjectError; end
class PackagesOutdatedError < ScriptProjectError
attr_reader :outdated_packages
def initialize(outdated_packages)
super("EP packages are outdated and need to be updated: #{outdated_packages.join(', ')}")
@outdated_packages = outdated_packages
end
end
end
end
end
Expand Down
3 changes: 3 additions & 0 deletions lib/project_types/script/messages/messages.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ module Messages
shop_script_conflict_help: "Disable that script or uninstall that app and try again.",

shop_script_undefined_cause: "Script is already turned off in store.",

packages_outdated_cause: "The following npm packages are out of date: %s.",
packages_outdated_help: "Run `npm update` to update them.",
},

create: {
Expand Down
8 changes: 8 additions & 0 deletions lib/project_types/script/ui/error_handler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,14 @@ def self.error_messages(e)
{
cause_of_error: ShopifyCli::Context.message('script.error.shop_script_undefined_cause'),
}
when Layers::Infrastructure::Errors::PackagesOutdatedError
{
cause_of_error: ShopifyCli::Context.message(
'script.error.packages_outdated_cause',
e.outdated_packages.join(', ')
),
help_suggestion: ShopifyCli::Context.message('script.error.packages_outdated_help'),
}
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,70 @@
describe ".dependencies_installed?" do
subject { as_task_runner.dependencies_installed? }

it "should return true if node_modules folder exists" do
before do
FileUtils.mkdir_p("node_modules")
end

it "should return true if node_modules folder exists" do
stub_npm_outdated({})
assert_equal true, subject
end

it "should return false if node_modules folder does not exists" do
Dir.stubs(:exist?).returns(false)
stub_npm_outdated({})
assert_equal false, subject
end

it "should not error if `npm outdated` returns nothing" do
stub_npm_outdated({})
subject
end

it "should not error if `npm outdated` does not return an EP package" do
stub_npm_outdated(create_package_version_info(package_name: "somepackage"))
subject
end

it "should not error if current version is linked" do
stub_npm_outdated(create_package_version_info(current: "linked"))
subject
end

it "should not error if latest version is an https URL" do
stub_npm_outdated(create_package_version_info(latest: "https://github.com/somethingsomething"))
subject
end

it "should not error if patch version is different" do
stub_npm_outdated(create_package_version_info(current: "0.9.0", latest: "0.9.1"))
subject
end

it "should not error if it's a non-zero major version and minor version is different" do
stub_npm_outdated(create_package_version_info(current: "1.0.0", latest: "1.1.0"))
subject
end

it "should error if it's a zero major version and minor version is different" do
package_name = "@shopify/extension-point-as-foo"
stub_npm_outdated(create_package_version_info(package_name: package_name, current: "0.9.0", latest: "0.10.0"))
msg = "NPM packages out of date: #{package_name}"
error = assert_raises Script::Layers::Infrastructure::Errors::PackagesOutdatedError, msg do
subject
end
assert_equal msg, error.message
end

it "should error if major version is different" do
package_name = "@shopify/extension-point-as-foo"
stub_npm_outdated(create_package_version_info(package_name: package_name, current: "0.9.0", latest: "1.0.0"))
msg = "NPM packages out of date: #{package_name}"
error = assert_raises Script::Layers::Infrastructure::Errors::PackagesOutdatedError do
subject
end
assert_equal msg, error.message
end
end

describe ".install_dependencies" do
Expand All @@ -93,4 +148,16 @@
end
end
end

private

def stub_npm_outdated(output)
ctx.stubs(:capture2e)
.with("npm", "outdated", "--json", "--depth", "0")
.returns([output.to_json, mock])
end

def create_package_version_info(package_name: "@shopify/extension-point-as-foo", current: "0.9.0", latest: "0.10.0")
{ package_name => { "current" => current, "latest" => latest } }
end
end

0 comments on commit 057b998

Please sign in to comment.