shopify-cli 1.2.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +2 -2
  3. data/.github/CONTRIBUTING.md +9 -1
  4. data/.github/PULL_REQUEST_TEMPLATE.md +9 -1
  5. data/.github/workflows/release.yml +61 -0
  6. data/.github/workflows/triage.yml +22 -0
  7. data/.gitignore +0 -1
  8. data/.rubocop.yml +61 -8
  9. data/.rubocop_todo.yml +11 -0
  10. data/CHANGELOG.md +25 -0
  11. data/Gemfile +3 -2
  12. data/Gemfile.lock +39 -37
  13. data/RELEASING.md +19 -29
  14. data/docs/core/index.md +16 -0
  15. data/lib/project_types/extension/cli.rb +7 -2
  16. data/lib/project_types/extension/commands/register.rb +1 -1
  17. data/lib/project_types/extension/features/argo/admin.rb +20 -0
  18. data/lib/project_types/extension/features/argo/base.rb +129 -0
  19. data/lib/project_types/extension/features/argo/checkout.rb +20 -0
  20. data/lib/project_types/extension/messages/messages.rb +8 -2
  21. data/lib/project_types/extension/models/type.rb +4 -0
  22. data/lib/project_types/extension/models/types/checkout_post_purchase.rb +2 -2
  23. data/lib/project_types/extension/models/types/product_subscription.rb +24 -0
  24. data/lib/project_types/node/cli.rb +4 -1
  25. data/lib/project_types/node/commands/connect.rb +15 -0
  26. data/lib/project_types/node/commands/create.rb +8 -4
  27. data/lib/project_types/node/messages/messages.rb +7 -6
  28. data/lib/project_types/rails/cli.rb +4 -1
  29. data/lib/project_types/rails/commands/connect.rb +15 -0
  30. data/lib/project_types/rails/commands/create.rb +8 -4
  31. data/lib/project_types/rails/messages/messages.rb +7 -4
  32. data/lib/project_types/script/cli.rb +2 -1
  33. data/lib/project_types/script/commands/enable.rb +12 -4
  34. data/lib/project_types/script/config/extension_points.yml +13 -12
  35. data/lib/project_types/script/errors.rb +4 -0
  36. data/lib/project_types/script/layers/application/build_script.rb +12 -16
  37. data/lib/project_types/script/layers/domain/errors.rb +3 -0
  38. data/lib/project_types/script/layers/domain/extension_point.rb +0 -1
  39. data/lib/project_types/script/layers/infrastructure/assemblyscript_project_creator.rb +15 -50
  40. data/lib/project_types/script/layers/infrastructure/assemblyscript_task_runner.rb +28 -7
  41. data/lib/project_types/script/layers/infrastructure/errors.rb +16 -0
  42. data/lib/project_types/script/layers/infrastructure/script_repository.rb +0 -12
  43. data/lib/project_types/script/layers/infrastructure/script_service.rb +2 -0
  44. data/lib/project_types/script/messages/messages.rb +23 -5
  45. data/lib/project_types/script/ui/error_handler.rb +31 -6
  46. data/lib/shopify-cli/api.rb +8 -10
  47. data/lib/shopify-cli/commands/config.rb +57 -1
  48. data/lib/shopify-cli/commands/connect.rb +32 -15
  49. data/lib/shopify-cli/commands/system.rb +9 -0
  50. data/lib/shopify-cli/core/entry_point.rb +1 -1
  51. data/lib/shopify-cli/core/monorail.rb +6 -4
  52. data/lib/shopify-cli/http_request.rb +15 -0
  53. data/lib/shopify-cli/js_deps.rb +1 -1
  54. data/lib/shopify-cli/js_system.rb +22 -5
  55. data/lib/shopify-cli/messages/messages.rb +44 -9
  56. data/lib/shopify-cli/partners_api.rb +17 -1
  57. data/lib/shopify-cli/process_supervision.rb +1 -1
  58. data/lib/shopify-cli/project.rb +12 -8
  59. data/lib/shopify-cli/project_type.rb +17 -1
  60. data/lib/shopify-cli/shopifolk.rb +86 -0
  61. data/lib/shopify-cli/task.rb +8 -0
  62. data/lib/shopify-cli/tasks/create_api_client.rb +13 -2
  63. data/lib/shopify-cli/tasks/ensure_env.rb +3 -0
  64. data/lib/shopify-cli/tasks/select_org_and_shop.rb +4 -0
  65. data/lib/shopify-cli/tunnel.rb +1 -1
  66. data/lib/shopify-cli/version.rb +1 -1
  67. data/lib/shopify_cli.rb +1 -0
  68. metadata +13 -5
  69. data/lib/project_types/extension/features/argo.rb +0 -48
  70. data/lib/project_types/extension/models/types/subscription_management.rb +0 -20
  71. data/lib/project_types/script/layers/infrastructure/assemblyscript_tsconfig.rb +0 -38
@@ -18,6 +18,10 @@ module Script
18
18
  invalid_context_cause: "Your .shopify-cli.yml file is not correct.",
19
19
  invalid_context_help: "See https://help.shopify.com",
20
20
 
21
+ invalid_config_props_cause: "{{command:--config_props}} is formatted incorrectly.",
22
+ invalid_config_props_help: "Try again using this format: "\
23
+ "{{cyan:--config_props='name1:value1, name2:value2'}}",
24
+
21
25
  invalid_script_name_cause: "Invalid script name.",
22
26
  invalid_script_name_help: "Replace or remove unsupported characters. Valid characters "\
23
27
  "are numbers, letters, hyphens, or underscores.",
@@ -45,9 +49,7 @@ module Script
45
49
 
46
50
  app_not_installed_cause: "App not installed on store.",
47
51
 
48
- app_script_not_pushed_help: "Push the script and then try this command again.",
49
-
50
- app_script_undefined_help: "Push script to app.",
52
+ app_script_not_pushed_help: "Script isn't on the app. Run {{command:shopify push}}, and then try again.",
51
53
 
52
54
  build_error_cause: "Something went wrong while building the script.",
53
55
  build_error_help: "Correct the errors and try again.",
@@ -55,6 +57,9 @@ module Script
55
57
  dependency_install_cause: "Something went wrong while installing the dependencies that are needed.",
56
58
  dependency_install_help: "Correct the errors and try again.",
57
59
 
60
+ failed_api_request_cause: "Something went wrong while communicating with Shopify.",
61
+ failed_api_request_help: "Try again.",
62
+
58
63
  forbidden_error_cause: "You do not have permission to do this action.",
59
64
 
60
65
  graphql_error_cause: "An error was returned: %s.",
@@ -72,8 +77,21 @@ module Script
72
77
 
73
78
  shop_script_undefined_cause: "Script is already turned off in store.",
74
79
 
75
- packages_outdated_cause: "The following npm packages are out of date: %s.",
76
- packages_outdated_help: "Run `npm update` to update them.",
80
+ packages_outdated_cause: "These npm packages are out of date: %s.",
81
+ packages_outdated_help: "To update them, run {{cyan:npm install --save-dev %s}}.",
82
+
83
+ invalid_build_script: "Invalid build script.",
84
+ build_script_not_found: "Build script not found.",
85
+ # rubocop:disable Layout/LineLength
86
+ build_script_suggestion: "Root package.json needs a script named build, which" \
87
+ "uses @shopify/scripts-toolchain-as to compile to WebAssembly.\n" \
88
+ "Example:\n" \
89
+ "build: npx shopify-scripts-toolchain-as build --src src/script.ts --binary <script_name>.wasm -- --lib node_modules --optimize --use Date=",
90
+
91
+ web_assembly_binary_not_found: "WebAssembly binary not found.",
92
+ web_assembly_binary_not_found_suggestion: "No WebAssembly binary found." \
93
+ "Check that your build npm script outputs the generated binary to the root of the directory." \
94
+ "Generated binary should match the script name: <script_name>.wasm",
77
95
  },
78
96
 
79
97
  create: {
@@ -44,6 +44,11 @@ module Script
44
44
  cause_of_error: ShopifyCli::Context.message('script.error.invalid_context_cause'),
45
45
  help_suggestion: ShopifyCli::Context.message('script.error.invalid_context_help'),
46
46
  }
47
+ when Errors::InvalidConfigProps
48
+ {
49
+ cause_of_error: ShopifyCli::Context.message('script.error.invalid_config_props_cause'),
50
+ help_suggestion: ShopifyCli::Context.message('script.error.invalid_config_props_help'),
51
+ }
47
52
  when Errors::InvalidConfigYAMLError
48
53
  {
49
54
  cause_of_error: ShopifyCli::Context.message('script.error.invalid_config', e.config_file),
@@ -96,14 +101,11 @@ module Script
96
101
  {
97
102
  cause_of_error: ShopifyCli::Context.message('script.error.app_not_installed_cause'),
98
103
  }
99
- when Layers::Infrastructure::Errors::AppScriptNotPushedError
104
+ when Layers::Infrastructure::Errors::AppScriptNotPushedError,
105
+ Layers::Infrastructure::Errors::AppScriptUndefinedError
100
106
  {
101
107
  cause_of_error: ShopifyCli::Context.message('script.error.app_script_not_pushed_help'),
102
108
  }
103
- when Layers::Infrastructure::Errors::AppScriptUndefinedError
104
- {
105
- help_suggestion: ShopifyCli::Context.message('script.error.app_script_undefined_help'),
106
- }
107
109
  when Layers::Infrastructure::Errors::BuildError
108
110
  {
109
111
  cause_of_error: ShopifyCli::Context.message('script.error.build_error_cause'),
@@ -114,6 +116,11 @@ module Script
114
116
  cause_of_error: ShopifyCli::Context.message('script.error.dependency_install_cause'),
115
117
  help_suggestion: ShopifyCli::Context.message('script.error.dependency_install_help'),
116
118
  }
119
+ when Layers::Infrastructure::Errors::EmptyResponseError
120
+ {
121
+ cause_of_error: ShopifyCli::Context.message('script.error.failed_api_request_cause'),
122
+ help_suggestion: ShopifyCli::Context.message('script.error.failed_api_request_help'),
123
+ }
117
124
  when Layers::Infrastructure::Errors::ForbiddenError
118
125
  {
119
126
  cause_of_error: ShopifyCli::Context.message('script.error.forbidden_error_cause'),
@@ -148,7 +155,25 @@ module Script
148
155
  'script.error.packages_outdated_cause',
149
156
  e.outdated_packages.join(', ')
150
157
  ),
151
- help_suggestion: ShopifyCli::Context.message('script.error.packages_outdated_help'),
158
+ help_suggestion: ShopifyCli::Context.message(
159
+ 'script.error.packages_outdated_help',
160
+ e.outdated_packages.collect { |package| "#{package}@latest" }.join(' ')
161
+ ),
162
+ }
163
+ when Layers::Infrastructure::Errors::BuildScriptNotFoundError
164
+ {
165
+ cause_of_error: ShopifyCli::Context.message('script.error.build_script_not_found'),
166
+ help_suggestion: ShopifyCli::Context.message('script.error.build_script_suggestion'),
167
+ }
168
+ when Layers::Infrastructure::Errors::InvalidBuildScriptError
169
+ {
170
+ cause_of_error: ShopifyCli::Context.message('script.error.invalid_build_script'),
171
+ help_suggestion: ShopifyCli::Context.message('script.error.build_script_suggestion'),
172
+ }
173
+ when Layers::Infrastructure::Errors::WebAssemblyBinaryNotFoundError
174
+ {
175
+ cause_of_error: ShopifyCli::Context.message('script.error.web_assembly_binary_not_found'),
176
+ help_suggestion: ShopifyCli::Context.message('script.error.web_assembly_binary_not_found_suggestion'),
152
177
  }
153
178
  end
154
179
  end
@@ -1,5 +1,4 @@
1
1
  require 'shopify_cli'
2
- require 'net/http'
3
2
 
4
3
  module ShopifyCli
5
4
  class API
@@ -32,8 +31,9 @@ module ShopifyCli
32
31
  )
33
32
  ctx.debug(resp)
34
33
  resp
35
- rescue API::APIRequestServerError, API::APIRequestUnexpectedError
34
+ rescue API::APIRequestServerError, API::APIRequestUnexpectedError => e
36
35
  ctx.puts(ctx.message('core.api.error.internal_server_error'))
36
+ ctx.debug(ctx.message('core.api.error.internal_server_error_debug', e.message))
37
37
  end
38
38
 
39
39
  protected
@@ -58,14 +58,10 @@ module ShopifyCli
58
58
  unless uri.is_a?(URI::HTTP)
59
59
  ctx.abort("Invalid URL: #{graphql_url}")
60
60
  end
61
- http = ::Net::HTTP.new(uri.host, uri.port)
62
- http.use_ssl = true
63
61
 
64
- req = ::Net::HTTP::Post.new(uri.request_uri)
65
- req.body = JSON.dump(query: body.tr("\n", ""), variables: variables)
66
- req['Content-Type'] = 'application/json'
67
- headers.each { |header, value| req[header] = value }
68
- response = http.request(req)
62
+ # we delay this require so as to avoid a performance hit on starting the CLI
63
+ require 'shopify-cli/http_request'
64
+ response = HttpRequest.call(uri, body, variables, headers)
69
65
 
70
66
  case response.code.to_i
71
67
  when 200..399
@@ -95,7 +91,9 @@ module ShopifyCli
95
91
  def default_headers
96
92
  {
97
93
  'User-Agent' => "Shopify App CLI #{ShopifyCli::VERSION} #{current_sha} | #{ctx.uname}",
98
- }.merge(auth_headers(token))
94
+ }.tap do |headers|
95
+ headers['X-Shopify-Cli-Employee'] = '1' if Shopifolk.acting_as_shopify_organization?
96
+ end.merge(auth_headers(token))
99
97
  end
100
98
 
101
99
  def auth_headers(token)
@@ -6,6 +6,8 @@ module ShopifyCli
6
6
  hidden_feature(feature_set: :debug)
7
7
 
8
8
  subcommand :Feature, 'feature'
9
+ subcommand :Analytics, 'analytics'
10
+ subcommand :ShopifolkBeta, 'shopifolk-beta'
9
11
 
10
12
  def call(*)
11
13
  @ctx.puts(self.class.help)
@@ -16,6 +18,10 @@ module ShopifyCli
16
18
  end
17
19
 
18
20
  class Feature < ShopifyCli::SubCommand
21
+ def self.help
22
+ ShopifyCli::Context.message('core.config.feature.help', ShopifyCli::TOOL_NAME)
23
+ end
24
+
19
25
  options do |parser, flags|
20
26
  parser.on('--enable') { flags[:action] = 'enable' }
21
27
  parser.on('--disable') { flags[:action] = 'disable' }
@@ -28,7 +34,7 @@ module ShopifyCli
28
34
  is_enabled = ShopifyCli::Feature.enabled?(feature_name)
29
35
  if options.flags[:action] == 'disable' && is_enabled
30
36
  ShopifyCli::Feature.disable(feature_name)
31
- @ctx.puts(@ctx.message('core.config.feature.disabled', is_enabled))
37
+ @ctx.puts(@ctx.message('core.config.feature.disabled', feature_name))
32
38
  elsif options.flags[:action] == 'enable' && !is_enabled
33
39
  ShopifyCli::Feature.enable(feature_name)
34
40
  @ctx.puts(@ctx.message('core.config.feature.enabled', feature_name))
@@ -39,6 +45,56 @@ module ShopifyCli
39
45
  end
40
46
  end
41
47
  end
48
+
49
+ class Analytics < ShopifyCli::SubCommand
50
+ def self.help
51
+ ShopifyCli::Context.message('core.config.analytics.help', ShopifyCli::TOOL_NAME)
52
+ end
53
+
54
+ options do |parser, flags|
55
+ parser.on('--enable') { flags[:action] = 'enable' }
56
+ parser.on('--disable') { flags[:action] = 'disable' }
57
+ parser.on('--status') { flags[:action] = 'status' }
58
+ end
59
+
60
+ def call(_args, _name)
61
+ is_enabled = ShopifyCli::Config.get_bool('analytics', 'enabled')
62
+ if options.flags[:action] == 'disable' && is_enabled
63
+ ShopifyCli::Config.set('analytics', 'enabled', false)
64
+ @ctx.puts(@ctx.message('core.config.analytics.disabled'))
65
+ elsif options.flags[:action] == 'enable' && !is_enabled
66
+ ShopifyCli::Config.set('analytics', 'enabled', true)
67
+ @ctx.puts(@ctx.message('core.config.analytics.enabled'))
68
+ elsif is_enabled
69
+ @ctx.puts(@ctx.message('core.config.analytics.is_enabled'))
70
+ else
71
+ @ctx.puts(@ctx.message('core.config.analytics.is_disabled'))
72
+ end
73
+ end
74
+ end
75
+
76
+ class ShopifolkBeta < ShopifyCli::SubCommand
77
+ options do |parser, flags|
78
+ parser.on('--enable') { flags[:action] = 'enable' }
79
+ parser.on('--disable') { flags[:action] = 'disable' }
80
+ parser.on('--status') { flags[:action] = 'status' }
81
+ end
82
+
83
+ def call(_args, _name)
84
+ is_enabled = ShopifyCli::Config.get_bool('shopifolk-beta', 'enabled')
85
+ if options.flags[:action] == 'disable' && is_enabled
86
+ ShopifyCli::Config.set('shopifolk-beta', 'enabled', false)
87
+ @ctx.puts(@ctx.message('core.config.shopifolk_beta.disabled'))
88
+ elsif options.flags[:action] == 'enable' && !is_enabled
89
+ ShopifyCli::Config.set('shopifolk-beta', 'enabled', true)
90
+ @ctx.puts(@ctx.message('core.config.shopifolk_beta.enabled'))
91
+ elsif is_enabled
92
+ @ctx.puts(@ctx.message('core.config.shopifolk_beta.is_enabled'))
93
+ else
94
+ @ctx.puts(@ctx.message('core.config.shopifolk_beta.is_disabled'))
95
+ end
96
+ end
97
+ end
42
98
  end
43
99
  end
44
100
  end
@@ -3,23 +3,33 @@ require 'shopify_cli'
3
3
  module ShopifyCli
4
4
  module Commands
5
5
  class Connect < ShopifyCli::Command
6
- def call(*)
7
- project_type = ask_project_type unless Project.has_current?
8
-
9
- if Project.has_current? && Project.current && Project.current.env
10
- @ctx.puts @ctx.message('core.connect.already_connected_warning')
11
- prod_warning = @ctx.message('core.connect.production_warning')
12
- @ctx.puts prod_warning if [:rails, :node].include?(Project.current_project_type)
6
+ class << self
7
+ def call(args, command_name)
8
+ ProjectType.load_type(args[0]) unless args.empty?
9
+ super
13
10
  end
14
11
 
15
- org = ShopifyCli::Tasks::EnsureEnv.call(@ctx, regenerate: true)
16
- write_cli_yml(project_type, org['id']) unless Project.has_current?
17
- api_key = Project.current(force_reload: true).env['api_key']
18
- @ctx.puts(@ctx.message('core.connect.connected', get_app(org['apps'], api_key).first["title"]))
12
+ def help
13
+ ShopifyCli::Context.message('core.connect.help', ShopifyCli::TOOL_NAME)
14
+ end
19
15
  end
20
16
 
21
- def get_app(apps, api_key)
22
- apps.select { |app| app["apiKey"] == api_key }
17
+ def call(args, command_name)
18
+ if Project.current&.env
19
+ @ctx.puts(@ctx.message('core.connect.already_connected_warning'))
20
+ end
21
+
22
+ project_type = ask_project_type
23
+
24
+ klass = ProjectType.load_type(project_type)&.connect_command
25
+
26
+ if klass
27
+ klass.ctx = @ctx
28
+ klass.call(args, command_name, 'connect')
29
+ else
30
+ app = default_connect(project_type)
31
+ @ctx.done(@ctx.message('core.connect.connected', app))
32
+ end
23
33
  end
24
34
 
25
35
  def ask_project_type
@@ -30,6 +40,13 @@ module ShopifyCli
30
40
  end
31
41
  end
32
42
 
43
+ def default_connect(project_type)
44
+ org = ShopifyCli::Tasks::EnsureEnv.call(@ctx, regenerate: true)
45
+ write_cli_yml(project_type, org['id']) unless Project.has_current?
46
+ api_key = Project.current(force_reload: true).env['api_key']
47
+ get_app(org['apps'], api_key).first['title']
48
+ end
49
+
33
50
  def write_cli_yml(project_type, org_id)
34
51
  ShopifyCli::Project.write(
35
52
  @ctx,
@@ -39,8 +56,8 @@ module ShopifyCli
39
56
  @ctx.done(@ctx.message('core.connect.cli_yml_saved'))
40
57
  end
41
58
 
42
- def self.help
43
- ShopifyCli::Context.message('core.connect.help', ShopifyCli::TOOL_NAME)
59
+ def get_app(apps, api_key)
60
+ apps.select { |app| app["apiKey"] == api_key }
44
61
  end
45
62
  end
46
63
  end
@@ -23,6 +23,7 @@ module ShopifyCli
23
23
  display_cli_ruby(show_all_details)
24
24
  display_utility_commands(show_all_details)
25
25
  display_project_commands(show_all_details)
26
+ display_shopify_staff_identity if show_all_details
26
27
  end
27
28
 
28
29
  def self.help
@@ -139,6 +140,14 @@ module ShopifyCli
139
140
  end
140
141
  @ctx.puts("")
141
142
  end
143
+
144
+ def display_shopify_staff_identity
145
+ is_shopifolk = ShopifyCli::Shopifolk.check
146
+ if is_shopifolk
147
+ @ctx.puts("\n" + @ctx.message('core.system.identity_header'))
148
+ @ctx.puts(" " + @ctx.message('core.system.identity_is_shopifolk'))
149
+ end
150
+ end
142
151
  end
143
152
  end
144
153
  end
@@ -28,7 +28,7 @@ module ShopifyCli
28
28
  ctx.puts(
29
29
  ctx.message('core.warning.development_version', File.join(ShopifyCli::ROOT, 'bin', ShopifyCli::TOOL_NAME))
30
30
  )
31
- else
31
+ elsif !ctx.testing?
32
32
  new_version = ctx.new_version
33
33
  ctx.puts(ctx.message('core.warning.new_version', ShopifyCli::VERSION, new_version)) unless new_version.nil?
34
34
  end
@@ -7,7 +7,7 @@ module ShopifyCli
7
7
  module Core
8
8
  module Monorail
9
9
  ENDPOINT_URI = URI.parse('https://monorail-edge.shopifycloud.com/v1/produce')
10
- INVOCATIONS_SCHEMA = 'app_cli_command/4.0'
10
+ INVOCATIONS_SCHEMA = 'app_cli_command/5.0'
11
11
 
12
12
  # Extra hash of data that will be sent in the payload
13
13
  @metadata = {}
@@ -101,14 +101,16 @@ module ShopifyCli
101
101
  uname: RbConfig::CONFIG["host"],
102
102
  cli_version: ShopifyCli::VERSION,
103
103
  ruby_version: RUBY_VERSION,
104
+ is_employee: ShopifyCli::Shopifolk.acting_as_shopify_organization?,
104
105
  }.tap do |payload|
105
- payload[:metadata] = JSON.dump(metadata) unless metadata.empty?
106
-
106
+ payload[:api_key] = metadata.delete(:api_key)
107
+ payload[:partner_id] = metadata.delete(:organization_id)
107
108
  if Project.has_current?
108
- project = Project.current
109
+ project = Project.current(force_reload: true)
109
110
  payload[:api_key] = project.env&.api_key
110
111
  payload[:partner_id] = project.config['organization_id']
111
112
  end
113
+ payload[:metadata] = JSON.dump(metadata) unless metadata.empty?
112
114
  end,
113
115
  }
114
116
  end
@@ -0,0 +1,15 @@
1
+ require 'net/http'
2
+
3
+ module ShopifyCli
4
+ class HttpRequest
5
+ def self.call(uri, body, variables, headers)
6
+ http = ::Net::HTTP.new(uri.host, uri.port)
7
+ http.use_ssl = true
8
+ req = ::Net::HTTP::Post.new(uri.request_uri)
9
+ req.body = JSON.dump(query: body.tr("\n", ""), variables: variables)
10
+ req['Content-Type'] = 'application/json'
11
+ headers.each { |header, value| req[header] = value }
12
+ http.request(req)
13
+ end
14
+ end
15
+ end
@@ -59,7 +59,7 @@ module ShopifyCli
59
59
  end
60
60
 
61
61
  def npm(verbose = false)
62
- cmd = %w(npm install --no-audit --no-optional)
62
+ cmd = %w(npm install --no-audit)
63
63
  cmd << '--quiet' unless verbose
64
64
 
65
65
  run_install_command(cmd)
@@ -76,23 +76,40 @@ module ShopifyCli
76
76
  # - `ctx`: running context from your command
77
77
  # - `yarn`: The proc, array, or string command to run if yarn is available
78
78
  # - `npm`: The proc, array, or string command to run if npm is available
79
+ # - `capture_response`: The boolean flag to capture the output of the running command if it is set to true
79
80
  #
80
81
  # #### Example
81
82
  #
82
- # ShopifyCli::JsSystem.new(ctx: ctx).call(yarn: ['install', '--silent'], npm: ['install', '--no-audit'])
83
+ # ShopifyCli::JsSystem.new(ctx: ctx).call(
84
+ # yarn: ['install', '--silent'],
85
+ # npm: ['install', '--no-audit'],
86
+ # capture_response: false
87
+ # )
83
88
  #
84
- def call(yarn:, npm:)
85
- yarn? ? call_command(yarn, YARN_CORE_COMMAND) : call_command(npm, NPM_CORE_COMMAND)
89
+ def call(yarn:, npm:, capture_response: false)
90
+ if yarn?
91
+ call_command(yarn, YARN_CORE_COMMAND, capture_response)
92
+ else
93
+ call_command(npm, NPM_CORE_COMMAND, capture_response)
94
+ end
86
95
  end
87
96
 
88
97
  private
89
98
 
90
- def call_command(command, core_command)
99
+ def call_command(command, core_command, capture_response)
91
100
  if command.is_a?(String) || command.is_a?(Array)
92
- CLI::Kit::System.system(core_command, *command, chdir: ctx.root).success?
101
+ capture_response ? call_with_capture(command, core_command) : call_without_capture(command, core_command)
93
102
  else
94
103
  command.call
95
104
  end
96
105
  end
106
+
107
+ def call_with_capture(command, core_command)
108
+ CLI::Kit::System.capture3(core_command, *command, chdir: ctx.root)
109
+ end
110
+
111
+ def call_without_capture(command, core_command)
112
+ CLI::Kit::System.system(core_command, *command, chdir: ctx.root).success?
113
+ end
97
114
  end
98
115
  end