shopify-cli 2.5.0 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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