shopify-cli 2.5.0 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +11 -0
  4. data/Dockerfile +0 -2
  5. data/Gemfile.lock +22 -16
  6. data/Rakefile +7 -16
  7. data/bin/console +11 -0
  8. data/bin/shopify +15 -3
  9. data/dev.yml +3 -0
  10. data/ext/shopify-cli/extconf.rb +2 -0
  11. data/lib/project_types/extension/cli.rb +2 -0
  12. data/lib/project_types/extension/commands/build.rb +2 -1
  13. data/lib/project_types/extension/features/argo.rb +1 -1
  14. data/lib/project_types/extension/features/argo_serve.rb +1 -0
  15. data/lib/project_types/extension/models/development_server.rb +4 -0
  16. data/lib/project_types/extension/models/development_server_requirements.rb +1 -2
  17. data/lib/project_types/extension/models/specification_handlers/default.rb +4 -0
  18. data/lib/project_types/extension/tasks/converters/server_config_converter.rb +31 -0
  19. data/lib/project_types/extension/tasks/find_npm_packages.rb +2 -2
  20. data/lib/project_types/extension/tasks/load_server_config.rb +23 -0
  21. data/lib/project_types/extension/tasks/run_extension_command.rb +26 -10
  22. data/lib/project_types/node/commands/serve.rb +9 -1
  23. data/lib/project_types/node/messages/messages.rb +3 -0
  24. data/lib/project_types/script/cli.rb +4 -3
  25. data/lib/project_types/script/commands/create.rb +2 -0
  26. data/lib/project_types/script/config/extension_points.yml +30 -29
  27. data/lib/project_types/script/layers/application/create_script.rb +32 -12
  28. data/lib/project_types/script/layers/application/extension_points.rb +3 -3
  29. data/lib/project_types/script/layers/domain/extension_point.rb +13 -45
  30. data/lib/project_types/script/layers/infrastructure/api_clients/partners_proxy_api_client.rb +4 -2
  31. data/lib/project_types/script/layers/infrastructure/api_clients/script_service_api_client.rb +1 -1
  32. data/lib/project_types/script/layers/infrastructure/errors.rb +5 -0
  33. data/lib/project_types/script/layers/infrastructure/languages/assemblyscript_project_creator.rb +10 -90
  34. data/lib/project_types/script/layers/infrastructure/languages/project_creator.rb +76 -11
  35. data/lib/project_types/script/layers/infrastructure/languages/task_runner.rb +1 -1
  36. data/lib/project_types/script/layers/infrastructure/languages/typescript_project_creator.rb +33 -0
  37. data/lib/project_types/script/layers/infrastructure/languages/typescript_task_runner.rb +105 -0
  38. data/lib/project_types/script/layers/infrastructure/script_project_repository.rb +1 -1
  39. data/lib/project_types/script/messages/messages.rb +4 -0
  40. data/lib/project_types/script/ui/error_handler.rb +8 -0
  41. data/lib/shopify_cli/command/app_sub_command.rb +16 -0
  42. data/lib/shopify_cli/constants.rb +33 -5
  43. data/lib/shopify_cli/core/executor.rb +5 -1
  44. data/lib/shopify_cli/environment.rb +35 -4
  45. data/lib/shopify_cli/exception_reporter/permission_controller.rb +54 -0
  46. data/lib/shopify_cli/exception_reporter.rb +55 -0
  47. data/lib/shopify_cli/git.rb +30 -0
  48. data/lib/shopify_cli/messages/messages.rb +27 -1
  49. data/lib/shopify_cli/method_object.rb +11 -4
  50. data/lib/shopify_cli/migrator/migration.rb +27 -0
  51. data/lib/shopify_cli/migrator/migrations/1631709766_noop.rb +13 -0
  52. data/lib/shopify_cli/migrator.rb +48 -0
  53. data/lib/shopify_cli/version.rb +1 -1
  54. data/lib/shopify_cli.rb +11 -3
  55. data/shopify-cli.gemspec +9 -1
  56. data/utilities/docker.rb +47 -0
  57. data/utilities/utilities.rb +5 -0
  58. metadata +31 -6
  59. data/lib/project_types/script/layers/infrastructure/languages/rust_project_creator.rb +0 -73
  60. data/lib/project_types/script/layers/infrastructure/languages/rust_task_runner.rb +0 -60
@@ -1,26 +1,54 @@
1
1
  module ShopifyCLI
2
2
  module Constants
3
+ module Paths
4
+ ROOT = File.expand_path("../..", __dir__)
5
+ end
6
+
7
+ module StoreKeys
8
+ LAST_MIGRATION_DATE = :last_migration_date
9
+ ANALYTICS_ENABLED = :analytics_enabled
10
+ end
11
+
12
+ module Bugsnag
13
+ API_KEY = "773b0c801eb40c20d8928be5b7c739bd"
14
+ end
15
+
16
+ module Config
17
+ module Sections
18
+ module ErrorTracking
19
+ NAME = "error-tracking"
20
+ module Fields
21
+ AUTOMATIC_REPORTING = "automatic-reporting"
22
+ end
23
+ end
24
+ end
25
+ end
26
+
3
27
  module EnvironmentVariables
28
+ STACKTRACE = "SHOPIFY_CLI_STACKTRACE"
29
+
4
30
  # When true the CLI points to a local instance of
5
31
  # the partners dashboard and identity.
6
32
  LOCAL_PARTNERS = "SHOPIFY_APP_CLI_LOCAL_PARTNERS"
7
33
 
8
34
  # When true the CLI points to a spin instance of spin
9
35
  SPIN_PARTNERS = "SHOPIFY_APP_CLI_SPIN_PARTNERS"
10
-
11
36
  SPIN_WORKSPACE = "SPIN_WORKSPACE"
12
-
13
37
  SPIN_NAMESPACE = "SPIN_NAMESPACE"
14
-
15
38
  SPIN_HOST = "SPIN_HOST"
16
39
 
17
- # Set to true when running tests.
18
- RUNNING_TESTS = "RUNNING_SHOPIFY_CLI_TESTS"
40
+ # Environments
41
+ TEST = "SHOPIFY_CLI_TEST"
42
+ DEVELOPMENT = "SHOPIFY_CLI_DEVELOPMENT"
19
43
  end
20
44
 
21
45
  module Identity
22
46
  CLIENT_ID_DEV = "e5380e02-312a-7408-5718-e07017e9cf52"
23
47
  CLIENT_ID = "fbdb2649-e327-4907-8f67-908d24cfd7e3"
24
48
  end
49
+
50
+ module Links
51
+ NEW_ISSUE = "https://github.com/Shopify/shopify-cli/issues/new"
52
+ end
25
53
  end
26
54
  end
@@ -12,7 +12,11 @@ module ShopifyCLI
12
12
  def call(command, command_name, args)
13
13
  command.task_registry = @task_registry
14
14
  command.ctx = @ctx
15
- super
15
+ with_traps do
16
+ with_logging do |_id|
17
+ command.call(args, command_name)
18
+ end
19
+ end
16
20
  end
17
21
  end
18
22
  end
@@ -3,6 +3,18 @@ module ShopifyCLI
3
3
  # the environment in which the CLI runs
4
4
  module Environment
5
5
  TRUTHY_ENV_VARIABLE_VALUES = ["1", "true", "TRUE", "yes", "YES"]
6
+
7
+ def self.development?(env_variables: ENV)
8
+ env_variable_truthy?(
9
+ Constants::EnvironmentVariables::DEVELOPMENT,
10
+ env_variables: env_variables
11
+ )
12
+ end
13
+
14
+ def self.interactive?
15
+ ShopifyCLI::Context.new.tty?
16
+ end
17
+
6
18
  def self.use_local_partners_instance?(env_variables: ENV)
7
19
  env_variable_truthy?(
8
20
  Constants::EnvironmentVariables::LOCAL_PARTNERS,
@@ -10,16 +22,30 @@ module ShopifyCLI
10
22
  )
11
23
  end
12
24
 
13
- def self.use_spin_partners_instance?(env_variables: ENV)
25
+ def self.print_stacktrace?(env_variables: ENV)
14
26
  env_variable_truthy?(
15
- Constants::EnvironmentVariables::SPIN_PARTNERS,
27
+ Constants::EnvironmentVariables::STACKTRACE,
28
+ env_variables: env_variables
29
+ )
30
+ end
31
+
32
+ def self.test?(env_variables: ENV)
33
+ env_variable_truthy?(
34
+ Constants::EnvironmentVariables::TEST,
35
+ env_variables: env_variables
36
+ )
37
+ end
38
+
39
+ def self.print_backtrace?(env_variables: ENV)
40
+ env_variable_truthy?(
41
+ Constants::EnvironmentVariables::BACKTRACE,
16
42
  env_variables: env_variables
17
43
  )
18
44
  end
19
45
 
20
- def self.running_tests?(env_variables: ENV)
46
+ def self.use_spin_partners_instance?(env_variables: ENV)
21
47
  env_variable_truthy?(
22
- Constants::EnvironmentVariables::RUNNING_TESTS,
48
+ Constants::EnvironmentVariables::SPIN_PARTNERS,
23
49
  env_variables: env_variables
24
50
  )
25
51
  end
@@ -34,6 +60,11 @@ module ShopifyCLI
34
60
  end
35
61
  end
36
62
 
63
+ def self.use_spin?(env_variables: ENV)
64
+ !env_variables[Constants::EnvironmentVariables::SPIN_WORKSPACE].nil? &&
65
+ !env_variables[Constants::EnvironmentVariables::SPIN_NAMESPACE].nil?
66
+ end
67
+
37
68
  def self.spin_url(env_variables: ENV)
38
69
  spin_workspace = spin_workspace(env_variables: env_variables)
39
70
  spin_namespace = spin_namespace(env_variables: env_variables)
@@ -0,0 +1,54 @@
1
+ module ShopifyCLI
2
+ module ExceptionReporter
3
+ module PermissionController
4
+ def self.report_error?(context: ShopifyCLI::Context.new)
5
+ CLI::UI::Prompt.ask(context.message("core.error_reporting.report_error.question")) do |handler|
6
+ handler.option(context.message("core.error_reporting.report_error.yes")) { |_| true }
7
+ handler.option(context.message("core.error_reporting.report_error.no")) { |_| false }
8
+ end
9
+ end
10
+
11
+ def self.automatic_reporting_prompted?
12
+ ShopifyCLI::Config.get_section(Constants::Config::Sections::ErrorTracking::NAME).key?(
13
+ Constants::Config::Sections::ErrorTracking::Fields::AUTOMATIC_REPORTING
14
+ )
15
+ end
16
+
17
+ def self.can_report_automatically?(context: ShopifyCLI::Context.new)
18
+ # If the terminal is not interactive we can't prompt the user.
19
+ return false unless ShopifyCLI::Environment.interactive?
20
+
21
+ if automatic_reporting_prompted?
22
+ automatic_reporting_enabled?
23
+ else
24
+ prompt_user(context: context)
25
+ end
26
+ end
27
+
28
+ def self.prompt_user(context:)
29
+ enable_automatic_tracking = CLI::UI::Prompt.ask(
30
+ context.message("core.error_reporting.enable_automatic_reporting_prompt.question")
31
+ ) do |handler|
32
+ handler.option(context.message("core.error_reporting.enable_automatic_reporting_prompt.yes")) { |_| true }
33
+ handler.option(context.message("core.error_reporting.enable_automatic_reporting_prompt.no")) { |_| false }
34
+ end
35
+
36
+ ShopifyCLI::Config.set(
37
+ Constants::Config::Sections::ErrorTracking::NAME,
38
+ Constants::Config::Sections::ErrorTracking::Fields::AUTOMATIC_REPORTING,
39
+ enable_automatic_tracking
40
+ )
41
+
42
+ enable_automatic_tracking
43
+ end
44
+
45
+ def self.automatic_reporting_enabled?
46
+ ShopifyCLI::Config.get_bool(
47
+ Constants::Config::Sections::ErrorTracking::NAME,
48
+ Constants::Config::Sections::ErrorTracking::Fields::AUTOMATIC_REPORTING,
49
+ default: false
50
+ )
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,55 @@
1
+ module ShopifyCLI
2
+ module ExceptionReporter
3
+ autoload :PermissionController, "shopify_cli/exception_reporter/permission_controller"
4
+
5
+ def self.report(error, _logs = nil, _api_key = nil, custom_metadata = {})
6
+ context = ShopifyCLI::Context.new
7
+ context.puts("\n")
8
+ context.puts(context.message("core.error_reporting.unhandled_error.message"))
9
+ context.puts(context.message("core.error_reporting.unhandled_error.issue_message"))
10
+ unless ShopifyCLI::Environment.print_stacktrace?
11
+ context.puts(context.message("core.error_reporting.unhandled_error.stacktrace_message",
12
+ "#{ShopifyCLI::Constants::EnvironmentVariables::STACKTRACE}=1"))
13
+ end
14
+ context.puts("\n")
15
+
16
+ return unless reportable_error?(error)
17
+ return unless report?
18
+
19
+ ENV["BUGSNAG_DISABLE_AUTOCONFIGURE"] = "1"
20
+ require "bugsnag"
21
+
22
+ Bugsnag.configure do |config|
23
+ config.logger.level = ::Logger::ERROR
24
+ config.api_key = ShopifyCLI::Constants::Bugsnag::API_KEY
25
+ config.app_type = "shopify"
26
+ config.project_root = File.expand_path("../../..", __FILE__)
27
+ config.app_version = ShopifyCLI::VERSION
28
+ config.auto_capture_sessions = false
29
+ end
30
+
31
+ metadata = {}
32
+ metadata.merge!(custom_metadata)
33
+ # Bugsnag.notify(error, metadata)
34
+ end
35
+
36
+ def self.report?
37
+ # return false if ShopifyCLI::Environment.development?
38
+ return true if ExceptionReporter::PermissionController.automatic_reporting_prompted? &&
39
+ ExceptionReporter::PermissionController.can_report_automatically?
40
+
41
+ report_error = ExceptionReporter::PermissionController.report_error?
42
+
43
+ unless ExceptionReporter::PermissionController.automatic_reporting_prompted?
44
+ ExceptionReporter::PermissionController.can_report_automatically?
45
+ end
46
+
47
+ report_error
48
+ end
49
+
50
+ def self.reportable_error?(error)
51
+ is_abort = error.is_a?(ShopifyCLI::Abort) || error.is_a?(ShopifyCLI::AbortSilent)
52
+ !is_abort
53
+ end
54
+ end
55
+ end
@@ -105,6 +105,36 @@ module ShopifyCLI
105
105
  end
106
106
  end
107
107
 
108
+ def sparse_checkout(repo, set, branch, ctx)
109
+ _, status = ctx.capture2e("git init")
110
+ unless status.success?
111
+ ctx.abort(ctx.message("core.git.error.repo_not_initiated"))
112
+ end
113
+
114
+ _, status = ctx.capture2e("git remote add -f origin #{repo}")
115
+ unless status.success?
116
+ ctx.abort(ctx.message("core.git.error.remote_not_added"))
117
+ end
118
+
119
+ _, status = ctx.capture2e("git config core.sparsecheckout true")
120
+ unless status.success?
121
+ ctx.abort(ctx.message("core.git.error.sparse_checkout_not_enabled"))
122
+ end
123
+
124
+ _, status = ctx.capture2e("git sparse-checkout set #{set}")
125
+ unless status.success?
126
+ ctx.abort(ctx.message("core.git.error.sparse_checkout_not_set"))
127
+ end
128
+
129
+ resp, status = ctx.capture2e("git pull origin #{branch}")
130
+ unless status.success?
131
+ if resp.include?("fatal: couldn't find remote ref")
132
+ ctx.abort(ctx.message("core.git.error.pull_failed_bad_branch", branch))
133
+ end
134
+ ctx.abort(ctx.message("core.git.error.pull_failed"))
135
+ end
136
+ end
137
+
108
138
  private
109
139
 
110
140
  def exec(*args, dir: Dir.pwd, default: nil, ctx: Context.new)
@@ -14,6 +14,25 @@ module ShopifyCLI
14
14
  },
15
15
  },
16
16
  core: {
17
+ error_reporting: {
18
+ unhandled_error: {
19
+ message: "{{x}} {{red:An unexpected error occured.}}",
20
+ issue_message: "{{red:\tTo \e]8;;#{ShopifyCLI::Constants::Links::NEW_ISSUE}\e\\submit an issue\e]8;;\e\\"\
21
+ " include the stack trace.}}",
22
+ stacktrace_message: "{{red:\tTo print the stack trace, add the environment variable %s.}}",
23
+ },
24
+ enable_automatic_reporting_prompt: {
25
+ question: "Automatically send error reports moving forward?",
26
+ yes: "Automatically send error reports to the Shopify team",
27
+ no: "Don't send error reports",
28
+ enabled: "Anonymized error reports will be sent to Shopify.",
29
+ },
30
+ report_error: {
31
+ question: "Send an error report to Shopify?",
32
+ yes: "Send report",
33
+ no: "Don't send",
34
+ },
35
+ },
17
36
  connect: {
18
37
  already_connected_warning: "{{yellow:! This app appears to be already connected}}",
19
38
  project_type_select: "What type of project would you like to connect?",
@@ -67,10 +86,18 @@ module ShopifyCLI
67
86
  repo_not_initiated:
68
87
  "Git repo is not initiated. Please run {{command:git init}} and make at least one commit.",
69
88
  no_commits_made: "No git commits have been made. Please make at least one commit.",
89
+ remote_not_added: "Remote could not be added.",
90
+ sparse_checkout_not_enabled: "Sparse checkout could not be enabled.",
91
+ sparse_checkout_not_set: "Sparse checkout set command failed.",
92
+ pull_failed: "Pull failed.",
93
+ pull_failed_bad_branch: "Pull failed. Branch %s cannot be found. Check the branch name and try again.",
70
94
  },
71
95
 
72
96
  cloning: "Cloning %s into %s…",
73
97
  cloned: "{{v}} Cloned into %s",
98
+ pulling_from_to: "Pulling %s into %s…",
99
+ pulling: "Pulling…",
100
+ pulled: "Pulled into %s",
74
101
  },
75
102
 
76
103
  help: {
@@ -429,7 +456,6 @@ module ShopifyCLI
429
456
  ngrok: "Something went wrong with ngrok installation,"\
430
457
  "please make sure %s exists within %s before trying again",
431
458
  },
432
-
433
459
  installing: "Installing ngrok…",
434
460
  not_running: "{{green:x}} ngrok tunnel not running",
435
461
  prereq_command_location: "%s @ %s",
@@ -48,12 +48,14 @@ module ShopifyCLI
48
48
  #
49
49
  module MethodObject
50
50
  module AutoCreateResultObject
51
+ def self.ruby2_keywords(*); end unless respond_to?(:ruby2_keywords, true)
52
+
51
53
  ##
52
54
  # invokes the original `call` implementation and wraps its return value
53
55
  # into a result object.
54
56
  #
55
- def call(*args, **kwargs, &block)
56
- Result.wrap { kwargs.any? ? super(*args, **kwargs, &block) : super(*args, &block) }.call
57
+ ruby2_keywords def call(*args, &block)
58
+ Result.wrap { super(*args, &block) }.call
57
59
  end
58
60
  end
59
61
 
@@ -66,8 +68,13 @@ module ShopifyCLI
66
68
  #
67
69
  def call(*args, **kwargs, &block)
68
70
  properties.keys.yield_self do |properties|
69
- new(**kwargs.slice(*properties))
70
- .call(*args, **kwargs.slice(*(kwargs.keys - properties)), &block)
71
+ instance = new(**kwargs.slice(*properties))
72
+ kwargs = kwargs.slice(*(kwargs.keys - properties))
73
+ if kwargs.any?
74
+ instance.call(*args, **kwargs, &block)
75
+ else
76
+ instance.call(*args, &block)
77
+ end
71
78
  end
72
79
  end
73
80
 
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+ require "date"
3
+
4
+ module ShopifyCLI
5
+ module Migrator
6
+ class Migration
7
+ attr_reader :name, :path, :date
8
+
9
+ def initialize(name:, path:, date:)
10
+ @name = name
11
+ @path = path
12
+ @date = date
13
+ end
14
+
15
+ def run
16
+ require(path)
17
+ ShopifyCli::Migrator::Migrations.const_get(class_name).run
18
+ rescue StandardError
19
+ # Continue
20
+ end
21
+
22
+ def class_name
23
+ name.split("_").collect(&:capitalize).join
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShopifyCLI
4
+ module Migrator
5
+ module Migrations
6
+ class Base
7
+ def self.run
8
+ # This is a noop migration to be used as a reference
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+ require "date"
3
+
4
+ module ShopifyCLI
5
+ module Migrator
6
+ autoload :Migration, "shopify_cli/migrator/migration"
7
+
8
+ def self.migrate(
9
+ migrations_directory: File.expand_path("migrator/migrations", __dir__)
10
+ )
11
+ baseline_date = last_migration_date
12
+ unless baseline_date.nil?
13
+ migrations = migrations(migrations_directory: migrations_directory)
14
+ .select { |m|
15
+ m.date > baseline_date.to_i
16
+ }
17
+ .each { |m| m.run }
18
+ end
19
+
20
+ store_last_migration_date
21
+ end
22
+
23
+ private
24
+
25
+ def self.store_last_migration_date
26
+ ShopifyCLI::DB.set(ShopifyCLI::Constants::StoreKeys::LAST_MIGRATION_DATE => Time.now.to_i)
27
+ end
28
+
29
+ def self.last_migration_date
30
+ ShopifyCLI::DB.get(ShopifyCLI::Constants::StoreKeys::LAST_MIGRATION_DATE)
31
+ end
32
+
33
+ def self.migrations(migrations_directory:)
34
+ Dir.glob(File.join(migrations_directory, "*.rb")).map do |file_path|
35
+ file_name = File.basename(file_path).gsub(".rb", "")
36
+ file_name_components = file_name.split("_")
37
+ date_timestamp = file_name_components[0].to_i
38
+ migration_name = file_name_components[1...].join("_")
39
+
40
+ Migrator::Migration.new(
41
+ name: migration_name,
42
+ date: Time.at(date_timestamp).to_i,
43
+ path: file_path
44
+ )
45
+ end
46
+ end
47
+ end
48
+ end
@@ -1,3 +1,3 @@
1
1
  module ShopifyCLI
2
- VERSION = "2.5.0"
2
+ VERSION = "2.6.0"
3
3
  end
data/lib/shopify_cli.rb CHANGED
@@ -25,6 +25,8 @@ require "cli/ui"
25
25
  require "cli/kit"
26
26
  require "smart_properties"
27
27
  require_relative "shopify_cli/version"
28
+ require_relative "shopify_cli/migrator"
29
+ require_relative "shopify_cli/exception_reporter"
28
30
 
29
31
  # Enable stdout routing. At this point all calls to STDOUT (and STDERR) will go through this class.
30
32
  # See https://github.com/Shopify/cli-ui/blob/main/lib/cli/ui/stdout_router.rb for more info
@@ -90,7 +92,7 @@ module ShopifyCLI
90
92
  autocall(:ErrorHandler) do
91
93
  CLI::Kit::ErrorHandler.new(
92
94
  log_file: ShopifyCLI.log_file,
93
- exception_reporter: nil,
95
+ exception_reporter: ->() { ShopifyCLI::ExceptionReporter },
94
96
  )
95
97
  end
96
98
 
@@ -135,7 +137,7 @@ module ShopifyCLI
135
137
  Context.load_messages(ShopifyCLI::Messages::MESSAGES)
136
138
 
137
139
  def self.cache_dir
138
- cache_dir = if Environment.running_tests?
140
+ cache_dir = if Environment.test?
139
141
  TEMP_DIR
140
142
  elsif ENV["LOCALAPPDATA"].nil?
141
143
  File.join(File.expand_path(ENV.fetch("XDG_CACHE_HOME", "~/.cache")), TOOL_NAME)
@@ -150,7 +152,7 @@ module ShopifyCLI
150
152
  end
151
153
 
152
154
  def self.tool_config_path
153
- if Environment.running_tests?
155
+ if Environment.test?
154
156
  TEMP_DIR
155
157
  elsif ENV["APPDATA"].nil?
156
158
  File.join(File.expand_path(ENV.fetch("XDG_CONFIG_HOME", "~/.config")), TOOL_NAME)
@@ -171,4 +173,10 @@ module ShopifyCLI
171
173
  return @sha if defined?(@sha)
172
174
  @sha = Git.sha(dir: ShopifyCLI::ROOT)
173
175
  end
176
+
177
+ # Migrate runs migrations that migrate the state of the environment
178
+ # in which the CLI runs.
179
+ unless ShopifyCLI::Environment.test? || ShopifyCLI::Environment.development?
180
+ ShopifyCLI::Migrator.migrate
181
+ end
174
182
  end
data/shopify-cli.gemspec CHANGED
@@ -43,6 +43,14 @@ Gem::Specification.new do |spec|
43
43
  spec.add_development_dependency("rake", "~> 12.3", ">= 12.3.3")
44
44
  spec.add_development_dependency("minitest", "~> 5.0")
45
45
 
46
+ spec.add_dependency("bugsnag", "~> 6.22")
46
47
  spec.add_dependency("listen", "~> 3.7.0")
47
- spec.add_dependency("theme-check", "~> 1.4.0")
48
+
49
+ # Note: theme-check is _intentionally_ not specifying the third
50
+ # digit. We _want_ new features to make their way into new installs
51
+ # of the Shopify CLI. Otherwise updates need to be released twice.
52
+ #
53
+ # That is, DO USE ~> 1.X, DO NOT USE ~> 1.X.Y, this would unnecessarily
54
+ # fix the feature version.
55
+ spec.add_dependency("theme-check", "~> 1.7")
48
56
  end
@@ -0,0 +1,47 @@
1
+ require "open3"
2
+
3
+ module Utilities
4
+ module Docker
5
+ Error = Class.new(StandardError)
6
+
7
+ class << self
8
+ def run_and_rm_container(*args)
9
+ build_image_if_needed
10
+ system(
11
+ "docker", "run",
12
+ "-t", "--rm",
13
+ "--volume", "#{Shellwords.escape(root_dir)}:/usr/src/app",
14
+ image_tag,
15
+ *args
16
+ ) || abort
17
+ end
18
+
19
+ private
20
+
21
+ def root_dir
22
+ File.expand_path("..", __dir__)
23
+ end
24
+
25
+ def build_image_if_needed
26
+ unless image_exists?(image_tag)
27
+ system("docker", "build", root_dir, "-t", image_tag) || abort
28
+ end
29
+ end
30
+
31
+ def image_tag
32
+ gemfile_lock_path = File.expand_path("./Gemfile.lock", root_dir)
33
+ image_sha = Digest::SHA256.hexdigest(File.read(gemfile_lock_path))
34
+ "shopify-cli-#{image_sha}"
35
+ end
36
+
37
+ def image_exists?(tag)
38
+ _, stat = Open3.capture2(
39
+ "docker", "inspect",
40
+ "--type=image",
41
+ tag
42
+ )
43
+ stat.success?
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,5 @@
1
+ $LOAD_PATH.unshift(__dir__) unless $LOAD_PATH.include?(__dir__)
2
+
3
+ module Utilities
4
+ autoload :Docker, "docker"
5
+ end