shopify-cli 2.6.3 → 2.6.4

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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/.github/PULL_REQUEST_TEMPLATE.md +15 -4
  3. data/.github/workflows/shopify.yml +3 -6
  4. data/CHANGELOG.md +71 -102
  5. data/Dockerfile +12 -2
  6. data/Gemfile +1 -0
  7. data/Gemfile.lock +5 -3
  8. data/RELEASING.md +17 -30
  9. data/Rakefile +0 -5
  10. data/lib/project_types/extension/features/argo.rb +8 -2
  11. data/lib/project_types/extension/models/specification_handlers/checkout_post_purchase.rb +1 -1
  12. data/lib/project_types/extension/models/specification_handlers/checkout_ui_extension.rb +1 -1
  13. data/lib/project_types/node/commands/serve.rb +7 -16
  14. data/lib/project_types/node/messages/messages.rb +0 -5
  15. data/lib/project_types/php/commands/serve.rb +6 -9
  16. data/lib/project_types/php/messages/messages.rb +1 -4
  17. data/lib/project_types/rails/commands/serve.rb +7 -8
  18. data/lib/project_types/rails/messages/messages.rb +1 -4
  19. data/lib/project_types/script/commands/create.rb +3 -1
  20. data/lib/project_types/script/config/extension_points.yml +7 -0
  21. data/lib/project_types/script/graphql/app_script_set.graphql +2 -0
  22. data/lib/project_types/script/layers/application/build_script.rb +2 -1
  23. data/lib/project_types/script/layers/application/push_script.rb +15 -1
  24. data/lib/project_types/script/layers/domain/push_package.rb +5 -2
  25. data/lib/project_types/script/layers/infrastructure/errors.rb +17 -0
  26. data/lib/project_types/script/layers/infrastructure/languages/assemblyscript_task_runner.rb +10 -13
  27. data/lib/project_types/script/layers/infrastructure/languages/typescript_task_runner.rb +4 -13
  28. data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +4 -2
  29. data/lib/project_types/script/layers/infrastructure/script_service.rb +6 -1
  30. data/lib/project_types/script/messages/messages.rb +6 -0
  31. data/lib/project_types/script/ui/error_handler.rb +16 -0
  32. data/lib/project_types/theme/commands/serve.rb +1 -0
  33. data/lib/project_types/theme/messages/messages.rb +5 -0
  34. data/lib/shopify_cli/app_type_detector.rb +32 -0
  35. data/lib/shopify_cli/command.rb +6 -1
  36. data/lib/shopify_cli/command_options/command_serve_options.rb +43 -0
  37. data/lib/shopify_cli/command_options.rb +7 -0
  38. data/lib/shopify_cli/commands/login.rb +3 -3
  39. data/lib/shopify_cli/commands/reporting.rb +38 -0
  40. data/lib/shopify_cli/commands/switch.rb +1 -1
  41. data/lib/shopify_cli/commands.rb +1 -0
  42. data/lib/shopify_cli/constants.rb +7 -3
  43. data/lib/shopify_cli/core/monorail.rb +9 -20
  44. data/lib/shopify_cli/environment.rb +15 -1
  45. data/lib/shopify_cli/exception_reporter.rb +24 -13
  46. data/lib/shopify_cli/messages/messages.rb +48 -19
  47. data/lib/shopify_cli/migrator/migration.rb +1 -1
  48. data/lib/shopify_cli/migrator/migrations/1631709766_noop.rb +1 -1
  49. data/lib/shopify_cli/migrator/migrations/1633691650_merge_reporting_configuration.rb +41 -0
  50. data/lib/shopify_cli/reporting_configuration_controller.rb +64 -0
  51. data/lib/shopify_cli/services/base_service.rb +13 -0
  52. data/lib/shopify_cli/services/reporting_service.rb +16 -0
  53. data/lib/shopify_cli/services.rb +6 -0
  54. data/lib/shopify_cli/theme/dev_server/watcher.rb +2 -2
  55. data/lib/shopify_cli/theme/dev_server.rb +2 -2
  56. data/lib/shopify_cli/version.rb +1 -1
  57. data/lib/shopify_cli.rb +4 -0
  58. data/shopify-cli.gemspec +1 -8
  59. data/utilities/docker/container.rb +76 -0
  60. data/utilities/docker.rb +44 -3
  61. metadata +14 -5
  62. data/lib/shopify_cli/exception_reporter/permission_controller.rb +0 -54
@@ -2,20 +2,17 @@
2
2
  module PHP
3
3
  class Command
4
4
  class Serve < ShopifyCLI::SubCommand
5
- PORT = 3000
5
+ include ShopifyCLI::CommandOptions::CommandServeOptions
6
6
 
7
7
  prerequisite_task :ensure_env, :ensure_dev_store
8
8
 
9
- options do |parser, flags|
10
- parser.on("--host=HOST") do |h|
11
- flags[:host] = h.gsub('"', "")
12
- end
13
- end
9
+ parse_host_option
10
+ parse_port_option
14
11
 
15
12
  def call(*)
16
13
  project = ShopifyCLI::Project.current
17
- url = options.flags[:host] || ShopifyCLI::Tunnel.start(@ctx, port: PORT)
18
- @ctx.abort(@ctx.message("php.serve.error.host_must_be_https")) if url.match(/^https/i).nil?
14
+ tunnel_port = port.to_s
15
+ url = host || ShopifyCLI::Tunnel.start(@ctx, port: tunnel_port)
19
16
  project.env.update(@ctx, :host, url)
20
17
  ShopifyCLI::Tasks::UpdateDashboardURLS.call(
21
18
  @ctx,
@@ -35,7 +32,7 @@ module PHP
35
32
  ShopifyCLI::ProcessSupervision.start(:npm_watch, "npm run watch", force_spawn: true)
36
33
 
37
34
  env = project.env.to_h
38
- @ctx.system("php", "artisan", "serve", "--port", PORT.to_s, env: env)
35
+ @ctx.system("php", "artisan", "serve", "--port", tunnel_port, env: env)
39
36
  end
40
37
  end
41
38
 
@@ -133,12 +133,9 @@ module PHP
133
133
  extended_help: <<~HELP,
134
134
  {{bold:Options:}}
135
135
  {{cyan:--host=HOST}}: Bypass running tunnel and use custom host. HOST must be HTTPS url.
136
+ {{cyan:--port=PORT}}: Use custom port.
136
137
  HELP
137
138
 
138
- error: {
139
- host_must_be_https: "HOST must be a HTTPS url.",
140
- },
141
-
142
139
  open_info: <<~MESSAGE,
143
140
  {{*}} To install and start using your app, open this URL in your browser:
144
141
  {{green:%s}}
@@ -2,19 +2,18 @@
2
2
  module Rails
3
3
  class Command
4
4
  class Serve < ShopifyCLI::SubCommand
5
+ include ShopifyCLI::CommandOptions::CommandServeOptions
6
+
5
7
  prerequisite_task ensure_project_type: :rails
6
8
  prerequisite_task :ensure_env, :ensure_dev_store
7
9
 
8
- options do |parser, flags|
9
- parser.on("--host=HOST") do |h|
10
- flags[:host] = h.gsub('"', "")
11
- end
12
- end
10
+ parse_host_option
11
+ parse_port_option
13
12
 
14
13
  def call(*)
15
14
  project = ShopifyCLI::Project.current
16
- url = options.flags[:host] || ShopifyCLI::Tunnel.start(@ctx)
17
- @ctx.abort(@ctx.message("rails.serve.error.host_must_be_https")) if url.match(/^https/i).nil?
15
+ tunnel_port = port.to_s
16
+ url = host || ShopifyCLI::Tunnel.start(@ctx, port: tunnel_port)
18
17
  project.env.update(@ctx, :host, url)
19
18
  ShopifyCLI::Tasks::UpdateDashboardURLS.call(
20
19
  @ctx,
@@ -30,7 +29,7 @@ module Rails
30
29
  CLI::UI::Frame.open(@ctx.message("rails.serve.running_server")) do
31
30
  env = ShopifyCLI::Project.current.env.to_h
32
31
  env.delete("HOST")
33
- env["PORT"] = ShopifyCLI::Tunnel::PORT.to_s
32
+ env["PORT"] = tunnel_port
34
33
  env["GEM_PATH"] = Gem.gem_path(@ctx)
35
34
  if @ctx.windows?
36
35
  @ctx.system("ruby bin\\rails server", env: env)
@@ -170,12 +170,9 @@ module Rails
170
170
  extended_help: <<~HELP,
171
171
  {{bold:Options:}}
172
172
  {{cyan:--host=HOST}}: Bypass running tunnel and use custom host. HOST must be HTTPS url.
173
+ {{cyan:--port=PORT}}: Use custom port.
173
174
  HELP
174
175
 
175
- error: {
176
- host_must_be_https: "{{red:HOST must be a HTTPS url.}}",
177
- },
178
-
179
176
  open_info: <<~MESSAGE,
180
177
  {{*}} To install and start using your app, open this URL in your browser:
181
178
  {{green:%s}}
@@ -3,7 +3,9 @@
3
3
  module Script
4
4
  class Command
5
5
  class Create < ShopifyCLI::SubCommand
6
- prerequisite_task :ensure_authenticated
6
+ unless ShopifyCLI::Environment.acceptance_test?
7
+ prerequisite_task :ensure_authenticated
8
+ end
7
9
 
8
10
  options do |parser, flags|
9
11
  parser.on("--name=NAME") { |name| flags[:name] = name }
@@ -42,3 +42,10 @@ shipping_methods:
42
42
  typescript:
43
43
  beta: true
44
44
  repo: "https://github.com/Shopify/scripts-apis-examples"
45
+ discount_types:
46
+ beta: true
47
+ domain: 'discounts'
48
+ libraries:
49
+ typescript:
50
+ beta: true
51
+ repo: "https://github.com/Shopify/scripts-apis-examples"
@@ -10,6 +10,7 @@ mutation AppScriptSet(
10
10
  $configurationUi: Boolean!,
11
11
  $configurationDefinition: String!,
12
12
  $moduleUploadUrl: String!,
13
+ $library: LibraryInput,
13
14
  ) {
14
15
  appScriptSet(
15
16
  uuid: $uuid
@@ -23,6 +24,7 @@ mutation AppScriptSet(
23
24
  configurationUi: $configurationUi,
24
25
  configurationDefinition: $configurationDefinition,
25
26
  moduleUploadUrl: $moduleUploadUrl,
27
+ library: $library,
26
28
  ) {
27
29
  userErrors {
28
30
  field
@@ -5,7 +5,7 @@ module Script
5
5
  module Application
6
6
  class BuildScript
7
7
  class << self
8
- def call(ctx:, task_runner:, script_project:)
8
+ def call(ctx:, task_runner:, script_project:, library:)
9
9
  CLI::UI::Frame.open(ctx.message("script.application.building")) do
10
10
  begin
11
11
  UI::StrictSpinner.spin(ctx.message("script.application.building_script")) do |spinner|
@@ -14,6 +14,7 @@ module Script
14
14
  script_content: task_runner.build,
15
15
  compiled_type: task_runner.compiled_type,
16
16
  metadata: task_runner.metadata,
17
+ library: library,
17
18
  )
18
19
  spinner.update_title(ctx.message("script.application.built"))
19
20
  end
@@ -11,14 +11,27 @@ module Script
11
11
  task_runner = Infrastructure::Languages::TaskRunner
12
12
  .for(ctx, script_project.language, script_project.script_name)
13
13
 
14
+ extension_point = ExtensionPoints.get(type: script_project.extension_point_type)
15
+ library_name = extension_point.libraries.for(script_project.language)&.package
16
+ raise Infrastructure::Errors::LanguageLibraryForAPINotFoundError.new(
17
+ language: script_project.language,
18
+ api: script_project.extension_point_type
19
+ ) unless library_name
20
+
21
+ library = {
22
+ language: script_project.language,
23
+ version: task_runner.library_version(library_name),
24
+ }
25
+
14
26
  ProjectDependencies.install(ctx: ctx, task_runner: task_runner)
15
- BuildScript.call(ctx: ctx, task_runner: task_runner, script_project: script_project)
27
+ BuildScript.call(ctx: ctx, task_runner: task_runner, script_project: script_project, library: library)
16
28
 
17
29
  UI::PrintingSpinner.spin(ctx, ctx.message("script.application.pushing")) do |p_ctx, spinner|
18
30
  package = Infrastructure::PushPackageRepository.new(ctx: p_ctx).get_push_package(
19
31
  script_project: script_project,
20
32
  compiled_type: task_runner.compiled_type,
21
33
  metadata: task_runner.metadata,
34
+ library: library,
22
35
  )
23
36
  script_service = Infrastructure::ServiceLocator.script_service(
24
37
  ctx: p_ctx,
@@ -32,6 +45,7 @@ module Script
32
45
  metadata: package.metadata,
33
46
  script_json: package.script_json,
34
47
  module_upload_url: module_upload_url,
48
+ library: package.library,
35
49
  )
36
50
  script_project_repo.update_env(uuid: uuid)
37
51
  spinner.update_title(p_ctx.message("script.application.pushed"))
@@ -10,7 +10,8 @@ module Script
10
10
  :script_json,
11
11
  :script_content,
12
12
  :compiled_type,
13
- :metadata
13
+ :metadata,
14
+ :library
14
15
 
15
16
  def initialize(
16
17
  id:,
@@ -19,7 +20,8 @@ module Script
19
20
  script_content:,
20
21
  compiled_type: nil,
21
22
  metadata:,
22
- script_json:
23
+ script_json:,
24
+ library:
23
25
  )
24
26
  @id = id
25
27
  @uuid = uuid
@@ -28,6 +30,7 @@ module Script
28
30
  @compiled_type = compiled_type
29
31
  @metadata = metadata
30
32
  @script_json = script_json
33
+ @library = library
31
34
  end
32
35
  end
33
36
  end
@@ -40,6 +40,23 @@ module Script
40
40
  end
41
41
  end
42
42
 
43
+ class APILibraryNotFoundError < ScriptProjectError
44
+ attr_reader :library_name
45
+ def initialize(library_name)
46
+ super()
47
+ @library_name = library_name
48
+ end
49
+ end
50
+
51
+ class LanguageLibraryForAPINotFoundError < ScriptProjectError
52
+ attr_reader :language, :api
53
+ def initialize(language:, api:)
54
+ super()
55
+ @language = language
56
+ @api = api
57
+ end
58
+ end
59
+
43
60
  class DependencyInstallError < ScriptProjectError; end
44
61
  class DeprecatedEPError < ScriptProjectError; end
45
62
  class EmptyResponseError < ScriptProjectError; end
@@ -5,7 +5,7 @@ module Script
5
5
  module Infrastructure
6
6
  module Languages
7
7
  class AssemblyScriptTaskRunner
8
- BYTECODE_FILE = "build/%{name}.wasm"
8
+ BYTECODE_FILE = "build/script.wasm"
9
9
  METADATA_FILE = "build/metadata.json"
10
10
  SCRIPT_SDK_BUILD = "npm run build"
11
11
 
@@ -47,6 +47,12 @@ module Script
47
47
  Domain::Metadata.create_from_json(@ctx, raw_contents)
48
48
  end
49
49
 
50
+ def library_version(library_name)
51
+ output = JSON.parse(CommandRunner.new(ctx: ctx).call("npm list --json"))
52
+ raise Errors::APILibraryNotFoundError.new(library_name), output unless output["dependencies"][library_name]
53
+ output["dependencies"][library_name]["version"]
54
+ end
55
+
50
56
  private
51
57
 
52
58
  def check_node_version!
@@ -80,19 +86,10 @@ module Script
80
86
  end
81
87
 
82
88
  def bytecode
83
- legacy_filename = format(BYTECODE_FILE, name: script_name)
84
- filename = format(BYTECODE_FILE, name: "script")
85
-
86
- bytecode_file = if ctx.file_exist?(filename)
87
- filename
88
- elsif ctx.file_exist?(legacy_filename)
89
- legacy_filename
90
- else
91
- raise Errors::WebAssemblyBinaryNotFoundError
92
- end
89
+ raise Errors::WebAssemblyBinaryNotFoundError unless ctx.file_exist?(BYTECODE_FILE)
93
90
 
94
- contents = ctx.binread(bytecode_file)
95
- ctx.rm(bytecode_file)
91
+ contents = ctx.binread(BYTECODE_FILE)
92
+ ctx.rm(BYTECODE_FILE)
96
93
 
97
94
  contents
98
95
  end
@@ -5,7 +5,7 @@ module Script
5
5
  module Infrastructure
6
6
  module Languages
7
7
  class TypeScriptTaskRunner
8
- BYTECODE_FILE = "build/%{name}.wasm"
8
+ BYTECODE_FILE = "build/index.wasm"
9
9
  METADATA_FILE = "build/metadata.json"
10
10
  SCRIPT_SDK_BUILD = "npm run build"
11
11
  GEN_METADATA = "npm run gen-metadata"
@@ -82,19 +82,10 @@ module Script
82
82
  end
83
83
 
84
84
  def bytecode
85
- legacy_filename = format(BYTECODE_FILE, name: script_name)
86
- filename = format(BYTECODE_FILE, name: "index")
87
-
88
- bytecode_file = if ctx.file_exist?(filename)
89
- filename
90
- elsif ctx.file_exist?(legacy_filename)
91
- legacy_filename
92
- else
93
- raise Errors::WebAssemblyBinaryNotFoundError
94
- end
85
+ raise Errors::WebAssemblyBinaryNotFoundError unless ctx.file_exist?(BYTECODE_FILE)
95
86
 
96
- contents = ctx.binread(bytecode_file)
97
- ctx.rm(bytecode_file)
87
+ contents = ctx.binread(BYTECODE_FILE)
88
+ ctx.rm(BYTECODE_FILE)
98
89
 
99
90
  contents
100
91
  end
@@ -7,7 +7,7 @@ module Script
7
7
  include SmartProperties
8
8
  property! :ctx, accepts: ShopifyCLI::Context
9
9
 
10
- def create_push_package(script_project:, script_content:, compiled_type:, metadata:)
10
+ def create_push_package(script_project:, script_content:, compiled_type:, metadata:, library:)
11
11
  build_file_path = file_path(script_project.id, compiled_type)
12
12
  write_to_path(build_file_path, script_content)
13
13
 
@@ -19,10 +19,11 @@ module Script
19
19
  compiled_type: compiled_type,
20
20
  metadata: metadata,
21
21
  script_json: script_project.script_json,
22
+ library: library
22
23
  )
23
24
  end
24
25
 
25
- def get_push_package(script_project:, compiled_type:, metadata:)
26
+ def get_push_package(script_project:, compiled_type:, metadata:, library:)
26
27
  build_file_path = file_path(script_project.id, compiled_type)
27
28
  raise Domain::PushPackageNotFoundError unless ctx.file_exist?(build_file_path)
28
29
 
@@ -34,6 +35,7 @@ module Script
34
35
  script_content: script_content,
35
36
  metadata: metadata,
36
37
  script_json: script_project.script_json,
38
+ library: library
37
39
  )
38
40
  end
39
41
 
@@ -18,7 +18,8 @@ module Script
18
18
  force: false,
19
19
  metadata:,
20
20
  script_json:,
21
- module_upload_url:
21
+ module_upload_url:,
22
+ library:
22
23
  )
23
24
  query_name = "app_script_set"
24
25
  variables = {
@@ -33,6 +34,10 @@ module Script
33
34
  configurationUi: script_json.configuration_ui,
34
35
  configurationDefinition: script_json.configuration&.to_json,
35
36
  moduleUploadUrl: module_upload_url,
37
+ library: {
38
+ language: library[:language],
39
+ version: library[:version],
40
+ },
36
41
  }
37
42
  resp_hash = make_request(query_name: query_name, variables: variables)
38
43
  user_errors = resp_hash["data"]["appScriptSet"]["userErrors"]
@@ -148,6 +148,12 @@ module Script
148
148
 
149
149
  script_upload_cause: "Fail to upload script.",
150
150
  script_upload_help: "Try again.",
151
+
152
+ api_library_not_found_cause: "Script can't be created because API library %{library_name} is missing from the dependencies",
153
+ api_library_not_found_help: "This error can occur because the API library was removed from your system or there is a problem with dependencies in the repository.",
154
+
155
+ language_library_for_api_not_found_cause: "Script can’t be pushed because the %{language} library for API %{api} is missing.",
156
+ language_library_for_api_not_found_help: "Make sure extension_point.yml contains the correct API library.",
151
157
  },
152
158
 
153
159
  create: {
@@ -250,6 +250,22 @@ module Script
250
250
  cause_of_error: ShopifyCLI::Context.message("script.error.script_upload_cause"),
251
251
  help_suggestion: ShopifyCLI::Context.message("script.error.script_upload_help"),
252
252
  }
253
+ when Layers::Infrastructure::Errors::APILibraryNotFoundError
254
+ {
255
+ cause_of_error: ShopifyCLI::Context
256
+ .message("script.error.api_library_not_found_cause", library_name: e.library_name),
257
+ help_suggestion: ShopifyCLI::Context.message("script.error.api_library_not_found_help"),
258
+ }
259
+ when Layers::Infrastructure::Errors::LanguageLibraryForAPINotFoundError
260
+ {
261
+ cause_of_error: ShopifyCLI::Context
262
+ .message(
263
+ "script.error.language_library_for_api_not_found_cause",
264
+ language: e.language,
265
+ api: e.api
266
+ ),
267
+ help_suggestion: ShopifyCLI::Context.message("script.error.language_library_for_api_not_found_help"),
268
+ }
253
269
  end
254
270
  end
255
271
  end
@@ -6,6 +6,7 @@ module Theme
6
6
  class Serve < ShopifyCLI::SubCommand
7
7
  options do |parser, flags|
8
8
  parser.on("--port=PORT") { |port| flags[:port] = port.to_i }
9
+ parser.on("--poll") { flags[:poll] = true }
9
10
  end
10
11
 
11
12
  def call(*)
@@ -88,7 +88,12 @@ module Theme
88
88
  serve: {
89
89
  help: <<~HELP,
90
90
  Uploads the current theme as a development theme to the connected store, then prints theme editor and preview URLs to your terminal. While running, changes will push to the store in real time.
91
+
91
92
  Usage: {{command:%s theme serve}}
93
+
94
+ Options:
95
+ {{command:--port=PORT}} Local port to serve theme preview from
96
+ {{command:--poll}} Force polling to detect file changes
92
97
  HELP
93
98
  serve: "Viewing theme…",
94
99
  open_fail: "Couldn't open the theme",
@@ -0,0 +1,32 @@
1
+ require "json"
2
+
3
+ module ShopifyCLI
4
+ class AppTypeDetector
5
+ Error = Class.new(StandardError)
6
+ TypeNotFoundError = Class.new(Error)
7
+
8
+ def self.detect(project_directory:)
9
+ return :node if node?(project_directory: project_directory)
10
+ return :rails if rails?(project_directory: project_directory)
11
+ return :php if php?(project_directory: project_directory)
12
+ raise TypeNotFoundError, "Couldn't detect the project type in directory: #{project_directory}"
13
+ end
14
+
15
+ def self.node?(project_directory:)
16
+ package_json_path = File.join(project_directory, "package.json")
17
+ return false unless File.exist?(package_json_path)
18
+ package_json = JSON.parse(File.read(package_json_path))
19
+ !package_json.dig("scripts", "dev").nil?
20
+ end
21
+
22
+ def self.rails?(project_directory:)
23
+ rails_binstub_path = File.join(project_directory, "bin/rails")
24
+ File.exist?(rails_binstub_path)
25
+ end
26
+
27
+ def self.php?(project_directory:)
28
+ bootstrap_app_path = File.join(project_directory, "bootstrap/app.php")
29
+ File.exist?(bootstrap_app_path)
30
+ end
31
+ end
32
+ end
@@ -27,7 +27,12 @@ module ShopifyCLI
27
27
  end
28
28
 
29
29
  def options(&block)
30
- @_options = block
30
+ existing_options = @_options
31
+ # We prevent new options calls to override existing blocks by nesting them.
32
+ @_options = ->(parser, flags) {
33
+ existing_options&.call(parser, flags)
34
+ block.call(parser, flags)
35
+ }
31
36
  end
32
37
 
33
38
  def subcommand(const, cmd, path = nil)
@@ -0,0 +1,43 @@
1
+ require "shopify_cli"
2
+
3
+ module ShopifyCLI
4
+ module CommandOptions
5
+ module CommandServeOptions
6
+ def self.included(base)
7
+ base.extend(ClassMethods)
8
+ base.class_eval do
9
+ def port
10
+ return ShopifyCLI::Tunnel::PORT.to_s unless options.flags.key?(:port)
11
+ port = options.flags[:port].to_i
12
+ @ctx.abort(@ctx.message("core.app.serve.error.invalid_port", options.flags[:port])) unless port > 0
13
+ port
14
+ end
15
+
16
+ def host
17
+ host = options.flags[:host]
18
+ unless host.nil?
19
+ @ctx.abort(@ctx.message("core.app.serve.error.host_must_be_https")) if host.match(/^https/i).nil?
20
+ end
21
+ host
22
+ end
23
+ end
24
+ end
25
+
26
+ module ClassMethods
27
+ def parse_host_option
28
+ options do |parser, flags|
29
+ parser.on("--host=HOST") do |h|
30
+ flags[:host] = h.gsub('"', "")
31
+ end
32
+ end
33
+ end
34
+
35
+ def parse_port_option
36
+ options do |parser, flags|
37
+ parser.on("--port=PORT") { |port| flags[:port] = port }
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,7 @@
1
+ require "shopify_cli"
2
+
3
+ module ShopifyCLI
4
+ module CommandOptions
5
+ autoload :CommandServeOptions, "shopify_cli/command_options/command_serve_options"
6
+ end
7
+ end
@@ -15,7 +15,7 @@ module ShopifyCLI
15
15
 
16
16
  def call(*)
17
17
  shop = (options.flags[:shop] || @ctx.getenv("SHOPIFY_SHOP" || nil))
18
- ShopifyCLI::DB.set(shop: self.class.validate_shop(shop)) unless shop.nil?
18
+ ShopifyCLI::DB.set(shop: self.class.validate_shop(shop, context: @ctx)) unless shop.nil?
19
19
 
20
20
  if shop.nil? && Shopifolk.check
21
21
  Shopifolk.reset
@@ -41,9 +41,9 @@ module ShopifyCLI
41
41
  ShopifyCLI::Context.message("core.login.help", ShopifyCLI::TOOL_NAME)
42
42
  end
43
43
 
44
- def self.validate_shop(shop)
44
+ def self.validate_shop(shop, context:)
45
45
  permanent_domain = shop_to_permanent_domain(shop)
46
- @ctx.abort(@ctx.message("core.login.invalid_shop", shop)) unless permanent_domain
46
+ context.abort(context.message("core.login.invalid_shop", shop)) unless permanent_domain
47
47
  permanent_domain
48
48
  end
49
49
 
@@ -0,0 +1,38 @@
1
+ require "shopify_cli"
2
+
3
+ module ShopifyCLI
4
+ module Commands
5
+ class Reporting < ShopifyCLI::Command
6
+ def call(args, _name)
7
+ enable_reporting = reporting_enabled?(args)
8
+ Services::ReportingService.call(enable: enable_reporting)
9
+
10
+ message = if enable_reporting
11
+ @ctx.message("core.reporting.turned_on_message")
12
+ else
13
+ @ctx.message("core.reporting.turned_off_message", ShopifyCLI::TOOL_NAME)
14
+ end
15
+ @ctx.puts(message)
16
+ end
17
+
18
+ def reporting_enabled?(args)
19
+ case args.first
20
+ when nil
21
+ @ctx.abort(@ctx.message("core.reporting.missing_argument", ShopifyCLI::TOOL_NAME))
22
+ when "on"
23
+ true
24
+ when "off"
25
+ false
26
+ else
27
+ @ctx.abort(
28
+ @ctx.message("core.reporting.invalid_argument", ShopifyCLI::TOOL_NAME, args.first)
29
+ )
30
+ end
31
+ end
32
+
33
+ def self.help
34
+ ShopifyCLI::Context.message("core.reporting.help", ShopifyCLI::TOOL_NAME)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -16,7 +16,7 @@ module ShopifyCLI
16
16
  end
17
17
 
18
18
  shop = if options.flags[:shop]
19
- Login.validate_shop(options.flags[:shop])
19
+ Login.validate_shop(options.flags[:shop], context: @ctx)
20
20
  elsif (org_id = DB.get(:organization_id))
21
21
  res = ShopifyCLI::Tasks::SelectOrgAndShop.call(@ctx, organization_id: org_id)
22
22
  res[:shop_domain]
@@ -23,6 +23,7 @@ module ShopifyCLI
23
23
  register :Login, "login", "shopify_cli/commands/login", true
24
24
  register :Logout, "logout", "shopify_cli/commands/logout", true
25
25
  register :Populate, "populate", "shopify_cli/commands/populate", true
26
+ register :Reporting, "reporting", "shopify_cli/commands/reporting", true
26
27
  register :Store, "store", "shopify_cli/commands/store", true
27
28
  register :Switch, "switch", "shopify_cli/commands/switch", true
28
29
  register :System, "system", "shopify_cli/commands/system", true
@@ -15,10 +15,10 @@ module ShopifyCLI
15
15
 
16
16
  module Config
17
17
  module Sections
18
- module ErrorTracking
19
- NAME = "error-tracking"
18
+ module Analytics
19
+ NAME = "analytics"
20
20
  module Fields
21
- AUTOMATIC_REPORTING = "automatic-reporting"
21
+ ENABLED = "enabled"
22
22
  end
23
23
  end
24
24
  end
@@ -39,7 +39,11 @@ module ShopifyCLI
39
39
 
40
40
  # Environments
41
41
  TEST = "SHOPIFY_CLI_TEST"
42
+ ACCEPTANCE_TEST = "SHOPIFY_CLI_ACCEPTANCE_TEST"
42
43
  DEVELOPMENT = "SHOPIFY_CLI_DEVELOPMENT"
44
+
45
+ # Monorail
46
+ MONORAIL_REAL_EVENTS = "MONORAIL_REAL_EVENTS"
43
47
  end
44
48
 
45
49
  module Identity