shopify-cli 1.3.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (206) 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 +10 -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/.travis.yml +1 -0
  11. data/CHANGELOG.md +30 -0
  12. data/Gemfile +3 -2
  13. data/Gemfile.lock +39 -37
  14. data/README.md +39 -7
  15. data/RELEASING.md +19 -29
  16. data/Rakefile +2 -0
  17. data/dev.yml +2 -2
  18. data/docs/_config.yml +1 -18
  19. data/docs/app/node/commands/index.md +2 -80
  20. data/docs/app/node/index.md +2 -33
  21. data/docs/app/rails/commands/index.md +2 -78
  22. data/docs/app/rails/index.md +2 -34
  23. data/docs/core/index.md +2 -84
  24. data/docs/getting-started/index.md +2 -25
  25. data/docs/getting-started/install/index.md +1 -118
  26. data/docs/getting-started/migrate/index.md +2 -94
  27. data/docs/getting-started/uninstall/index.md +2 -35
  28. data/docs/getting-started/upgrade/index.md +2 -39
  29. data/docs/help/start-app/index.md +2 -4
  30. data/docs/index.md +2 -24
  31. data/install.sh +1 -1
  32. data/lib/project_types/extension/cli.rb +21 -11
  33. data/lib/project_types/extension/commands/extension_command.rb +2 -2
  34. data/lib/project_types/extension/features/argo.rb +117 -0
  35. data/lib/project_types/extension/forms/create.rb +2 -2
  36. data/lib/project_types/extension/models/specification.rb +35 -0
  37. data/lib/project_types/extension/models/specification_handlers/checkout_post_purchase.rb +19 -0
  38. data/lib/project_types/extension/models/specification_handlers/default.rb +67 -0
  39. data/lib/project_types/extension/models/specifications.rb +77 -0
  40. data/lib/project_types/extension/tasks/configure_features.rb +52 -0
  41. data/lib/project_types/extension/tasks/fetch_specifications.rb +38 -0
  42. data/lib/project_types/node/cli.rb +4 -1
  43. data/lib/project_types/node/commands/connect.rb +15 -0
  44. data/lib/project_types/node/commands/create.rb +10 -4
  45. data/lib/project_types/node/commands/generate.rb +2 -11
  46. data/lib/project_types/node/messages/messages.rb +16 -50
  47. data/lib/project_types/rails/cli.rb +4 -1
  48. data/lib/project_types/rails/commands/connect.rb +15 -0
  49. data/lib/project_types/rails/commands/create.rb +15 -12
  50. data/lib/project_types/rails/forms/create.rb +1 -1
  51. data/lib/project_types/rails/gem.rb +1 -1
  52. data/lib/project_types/rails/messages/messages.rb +8 -5
  53. data/lib/project_types/script/cli.rb +9 -5
  54. data/lib/project_types/script/commands/create.rb +6 -4
  55. data/lib/project_types/script/commands/enable.rb +12 -4
  56. data/lib/project_types/script/commands/push.rb +5 -13
  57. data/lib/project_types/script/config/extension_points.yml +17 -12
  58. data/lib/project_types/script/errors.rb +21 -0
  59. data/lib/project_types/script/forms/create.rb +26 -2
  60. data/lib/project_types/script/graphql/app_script_update_or_create.graphql +10 -1
  61. data/lib/project_types/script/layers/application/build_script.rb +18 -17
  62. data/lib/project_types/script/layers/application/create_script.rb +12 -10
  63. data/lib/project_types/script/layers/application/extension_points.rb +24 -0
  64. data/lib/project_types/script/layers/application/push_script.rb +18 -16
  65. data/lib/project_types/script/layers/domain/errors.rb +7 -0
  66. data/lib/project_types/script/layers/domain/extension_point.rb +62 -7
  67. data/lib/project_types/script/layers/domain/metadata.rb +55 -0
  68. data/lib/project_types/script/layers/domain/push_package.rb +25 -6
  69. data/lib/project_types/script/layers/infrastructure/assemblyscript_project_creator.rb +17 -52
  70. data/lib/project_types/script/layers/infrastructure/assemblyscript_task_runner.rb +42 -11
  71. data/lib/project_types/script/layers/infrastructure/errors.rb +16 -0
  72. data/lib/project_types/script/layers/infrastructure/extension_point_repository.rb +10 -4
  73. data/lib/project_types/script/layers/infrastructure/project_creator.rb +2 -1
  74. data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +25 -13
  75. data/lib/project_types/script/layers/infrastructure/rust_project_creator.rb +72 -0
  76. data/lib/project_types/script/layers/infrastructure/rust_task_runner.rb +59 -0
  77. data/lib/project_types/script/layers/infrastructure/script_service.rb +9 -1
  78. data/lib/project_types/script/layers/infrastructure/task_runner.rb +4 -3
  79. data/lib/project_types/script/messages/messages.rb +55 -4
  80. data/lib/project_types/script/script_project.rb +25 -16
  81. data/lib/project_types/script/ui/error_handler.rb +59 -1
  82. data/lib/project_types/theme/cli.rb +40 -0
  83. data/lib/project_types/theme/commands/connect.rb +54 -0
  84. data/lib/project_types/theme/commands/create.rb +48 -0
  85. data/lib/project_types/theme/commands/deploy.rb +38 -0
  86. data/lib/project_types/theme/commands/generate.rb +20 -0
  87. data/lib/project_types/theme/commands/generate/env.rb +79 -0
  88. data/lib/project_types/theme/commands/push.rb +55 -0
  89. data/lib/project_types/theme/commands/serve.rb +31 -0
  90. data/lib/project_types/theme/forms/connect.rb +34 -0
  91. data/lib/project_types/theme/forms/create.rb +22 -0
  92. data/lib/project_types/theme/messages/messages.rb +147 -0
  93. data/lib/project_types/theme/tasks/ensure_themekit_installed.rb +78 -0
  94. data/lib/project_types/theme/themekit.rb +113 -0
  95. data/lib/shopify-cli/admin_api.rb +42 -2
  96. data/lib/shopify-cli/api.rb +34 -33
  97. data/lib/shopify-cli/commands/config.rb +24 -0
  98. data/lib/shopify-cli/commands/connect.rb +32 -15
  99. data/lib/shopify-cli/commands/system.rb +10 -1
  100. data/lib/shopify-cli/context.rb +23 -2
  101. data/lib/shopify-cli/core/entry_point.rb +1 -1
  102. data/lib/shopify-cli/core/monorail.rb +6 -4
  103. data/lib/shopify-cli/feature.rb +0 -2
  104. data/lib/shopify-cli/http_request.rb +27 -0
  105. data/lib/shopify-cli/js_deps.rb +1 -1
  106. data/lib/shopify-cli/messages/messages.rb +31 -7
  107. data/lib/shopify-cli/method_object.rb +104 -0
  108. data/lib/shopify-cli/partners_api.rb +25 -3
  109. data/lib/shopify-cli/process_supervision.rb +1 -1
  110. data/lib/shopify-cli/project.rb +12 -8
  111. data/lib/shopify-cli/project_type.rb +18 -2
  112. data/lib/shopify-cli/resolve_constant.rb +25 -0
  113. data/lib/shopify-cli/result.rb +432 -0
  114. data/lib/shopify-cli/shopifolk.rb +87 -0
  115. data/lib/shopify-cli/task.rb +8 -0
  116. data/lib/shopify-cli/tasks/create_api_client.rb +13 -2
  117. data/lib/shopify-cli/tasks/ensure_env.rb +3 -0
  118. data/lib/shopify-cli/tasks/select_org_and_shop.rb +10 -5
  119. data/lib/shopify-cli/tunnel.rb +8 -2
  120. data/lib/shopify-cli/version.rb +1 -1
  121. data/lib/shopify_cli.rb +5 -1
  122. data/shopify.fish +1 -1
  123. data/shopify.sh +1 -1
  124. data/vendor/deps/cli-kit/REVISION +1 -1
  125. data/vendor/deps/cli-kit/lib/cli/kit/logger.rb +2 -2
  126. data/vendor/deps/cli-kit/lib/cli/kit/system.rb +3 -3
  127. data/vendor/deps/cli-ui/REVISION +1 -1
  128. data/vendor/deps/cli-ui/lib/cli/ui.rb +26 -22
  129. data/vendor/deps/cli-ui/lib/cli/ui/ansi.rb +4 -6
  130. data/vendor/deps/cli-ui/lib/cli/ui/frame.rb +3 -3
  131. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_stack.rb +8 -9
  132. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style.rb +1 -1
  133. data/vendor/deps/cli-ui/lib/cli/ui/glyph.rb +1 -0
  134. data/vendor/deps/cli-ui/lib/cli/ui/printer.rb +15 -3
  135. data/vendor/deps/cli-ui/lib/cli/ui/prompt/interactive_options.rb +4 -11
  136. data/vendor/deps/cli-ui/lib/cli/ui/spinner.rb +3 -5
  137. data/vendor/deps/cli-ui/lib/cli/ui/terminal.rb +10 -10
  138. data/vendor/deps/cli-ui/lib/cli/ui/version.rb +1 -1
  139. data/vendor/deps/cli-ui/lib/cli/ui/wrap.rb +56 -0
  140. data/vendor/deps/webrick/.gitignore +9 -0
  141. data/vendor/deps/webrick/Gemfile +3 -0
  142. data/vendor/deps/webrick/LICENSE.txt +22 -0
  143. data/vendor/deps/webrick/README.md +61 -0
  144. data/vendor/deps/webrick/Rakefile +10 -0
  145. data/vendor/deps/webrick/lib/webrick.rb +232 -0
  146. data/vendor/deps/webrick/lib/webrick/accesslog.rb +157 -0
  147. data/vendor/deps/webrick/lib/webrick/cgi.rb +313 -0
  148. data/vendor/deps/webrick/lib/webrick/compat.rb +36 -0
  149. data/vendor/deps/webrick/lib/webrick/config.rb +158 -0
  150. data/vendor/deps/webrick/lib/webrick/cookie.rb +172 -0
  151. data/vendor/deps/webrick/lib/webrick/htmlutils.rb +30 -0
  152. data/vendor/deps/webrick/lib/webrick/httpauth.rb +96 -0
  153. data/vendor/deps/webrick/lib/webrick/httpauth/authenticator.rb +117 -0
  154. data/vendor/deps/webrick/lib/webrick/httpauth/basicauth.rb +116 -0
  155. data/vendor/deps/webrick/lib/webrick/httpauth/digestauth.rb +395 -0
  156. data/vendor/deps/webrick/lib/webrick/httpauth/htdigest.rb +132 -0
  157. data/vendor/deps/webrick/lib/webrick/httpauth/htgroup.rb +97 -0
  158. data/vendor/deps/webrick/lib/webrick/httpauth/htpasswd.rb +158 -0
  159. data/vendor/deps/webrick/lib/webrick/httpauth/userdb.rb +53 -0
  160. data/vendor/deps/webrick/lib/webrick/httpproxy.rb +354 -0
  161. data/vendor/deps/webrick/lib/webrick/httprequest.rb +636 -0
  162. data/vendor/deps/webrick/lib/webrick/httpresponse.rb +564 -0
  163. data/vendor/deps/webrick/lib/webrick/https.rb +152 -0
  164. data/vendor/deps/webrick/lib/webrick/httpserver.rb +294 -0
  165. data/vendor/deps/webrick/lib/webrick/httpservlet.rb +23 -0
  166. data/vendor/deps/webrick/lib/webrick/httpservlet/abstract.rb +152 -0
  167. data/vendor/deps/webrick/lib/webrick/httpservlet/cgi_runner.rb +47 -0
  168. data/vendor/deps/webrick/lib/webrick/httpservlet/cgihandler.rb +126 -0
  169. data/vendor/deps/webrick/lib/webrick/httpservlet/erbhandler.rb +88 -0
  170. data/vendor/deps/webrick/lib/webrick/httpservlet/filehandler.rb +552 -0
  171. data/vendor/deps/webrick/lib/webrick/httpservlet/prochandler.rb +47 -0
  172. data/vendor/deps/webrick/lib/webrick/httpstatus.rb +194 -0
  173. data/vendor/deps/webrick/lib/webrick/httputils.rb +512 -0
  174. data/vendor/deps/webrick/lib/webrick/httpversion.rb +76 -0
  175. data/vendor/deps/webrick/lib/webrick/log.rb +156 -0
  176. data/vendor/deps/webrick/lib/webrick/server.rb +381 -0
  177. data/vendor/deps/webrick/lib/webrick/ssl.rb +215 -0
  178. data/vendor/deps/webrick/lib/webrick/utils.rb +265 -0
  179. data/vendor/deps/webrick/lib/webrick/version.rb +18 -0
  180. data/vendor/deps/webrick/webrick.gemspec +74 -0
  181. metadata +77 -27
  182. data/docs/Gemfile +0 -5
  183. data/docs/Gemfile.lock +0 -258
  184. data/docs/_data/nav.yml +0 -35
  185. data/docs/_includes/footer.html +0 -15
  186. data/docs/_includes/head.html +0 -19
  187. data/docs/_includes/sidebar_nav.html +0 -22
  188. data/docs/_includes/toc.html +0 -112
  189. data/docs/_layouts/default.html +0 -79
  190. data/docs/css/docs.css +0 -157
  191. data/docs/images/header.png +0 -0
  192. data/docs/installing-ruby.md +0 -28
  193. data/lib/project_types/extension/features/argo/admin.rb +0 -20
  194. data/lib/project_types/extension/features/argo/base.rb +0 -129
  195. data/lib/project_types/extension/features/argo/checkout.rb +0 -20
  196. data/lib/project_types/extension/models/type.rb +0 -81
  197. data/lib/project_types/extension/models/types/checkout_post_purchase.rb +0 -23
  198. data/lib/project_types/extension/models/types/product_subscription.rb +0 -24
  199. data/lib/project_types/node/commands/generate/billing.rb +0 -39
  200. data/lib/project_types/node/commands/generate/page.rb +0 -59
  201. data/lib/project_types/node/commands/generate/webhook.rb +0 -37
  202. data/lib/project_types/script/layers/domain/script.rb +0 -18
  203. data/lib/project_types/script/layers/infrastructure/assemblyscript_tsconfig.rb +0 -38
  204. data/lib/project_types/script/layers/infrastructure/script_repository.rb +0 -59
  205. data/lib/project_types/script/templates/ts/as-pect.config.js +0 -27
  206. data/lib/project_types/script/templates/ts/as-pect.d.ts +0 -1
@@ -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
@@ -83,7 +84,7 @@ module ShopifyCli
83
84
  end
84
85
 
85
86
  def display_ngrok
86
- ngrok_location = File.join(ShopifyCli.cache_dir, @ctx.windows? ? 'ngrok.exe' : 'ngrok')
87
+ ngrok_location = File.join(ShopifyCli.cache_dir, "ngrok#{@ctx.executable_file_extension}")
87
88
  if File.exist?(ngrok_location)
88
89
  @ctx.puts(" " + @ctx.message('core.system.ngrok_available', ngrok_location))
89
90
  else
@@ -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
@@ -329,14 +329,18 @@ module ShopifyCli
329
329
  # - `**kwargs`: additional keyword arguments to pass to Process.spawn
330
330
  #
331
331
  # #### Returns
332
- # - `status`: boolean success status of the command execution
332
+ # - `status`: The `Process::Status` result of the command execution.
333
333
  #
334
334
  # #### Usage
335
335
  #
336
336
  # stat = @ctx.system('ls', 'a_folder')
337
337
  #
338
338
  def system(*args, **kwargs)
339
- CLI::Kit::System.system(*args, env: @env, **kwargs)
339
+ process_status = CLI::Kit::System.system(*args, env: @env, **kwargs)
340
+ unless process_status.success?
341
+ abort("System call failed: #{args.join(' ')}")
342
+ end
343
+ process_status
340
344
  end
341
345
 
342
346
  # Execute a command in the user's environment
@@ -470,6 +474,23 @@ module ShopifyCli
470
474
  end
471
475
  end
472
476
 
477
+ # Returns file extension depending on OS
478
+ # since windows has multiple extensions, the default is .exe unless otherwise specified
479
+ #
480
+ # #### Parameters
481
+ # - ext: optional extension for windows file
482
+ #
483
+ # #### Returns
484
+ # - ext: string for file extension on windows
485
+ # : empty string otherwise
486
+ def executable_file_extension(ext = '.exe')
487
+ if windows?
488
+ ext
489
+ else
490
+ ''
491
+ end
492
+ end
493
+
473
494
  private
474
495
 
475
496
  def ctx_path(fname)
@@ -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
@@ -87,8 +87,6 @@ module ShopifyCli
87
87
  ShopifyCli::Config.get_bool(SECTION, feature.to_s)
88
88
  end
89
89
 
90
- private
91
-
92
90
  def set(feature, value)
93
91
  ShopifyCli::Config.set(SECTION, feature.to_s, value)
94
92
  end
@@ -0,0 +1,27 @@
1
+ require 'net/http'
2
+
3
+ module ShopifyCli
4
+ class HttpRequest
5
+ class << self
6
+ def post(uri, body, headers)
7
+ req = ::Net::HTTP::Post.new(uri.request_uri)
8
+ request(uri, body, headers, req)
9
+ end
10
+
11
+ def get(uri, body, headers)
12
+ req = ::Net::HTTP::Get.new(uri.request_uri)
13
+ request(uri, body, headers, req)
14
+ end
15
+
16
+ def request(uri, body, headers, req)
17
+ http = ::Net::HTTP.new(uri.host, uri.port)
18
+ http.use_ssl = true
19
+
20
+ req.body = body unless body.nil?
21
+ req['Content-Type'] = 'application/json'
22
+ headers.each { |header, value| req[header] = value }
23
+ http.request(req)
24
+ end
25
+ end
26
+ end
27
+ 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)
@@ -3,6 +3,16 @@
3
3
  module ShopifyCli
4
4
  module Messages
5
5
  MESSAGES = {
6
+ apps: {
7
+ create: {
8
+ info: {
9
+ created: "{{v}} {{green:%s}} was created in the organization's Partner Dashboard {{underline:%s}}",
10
+ serve: "{{*}} Change directories to your new project folder {{green:%s}} and run {{command:%s serve}} " \
11
+ "to start a local server",
12
+ install: "{{*}} Then, visit {{underline:%s/test}} to install {{green:%s}} on your Dev Store",
13
+ },
14
+ },
15
+ },
6
16
  core: {
7
17
  connect: {
8
18
  help: <<~HELP,
@@ -10,11 +20,7 @@ module ShopifyCli
10
20
  Usage: {{command:%s connect}}
11
21
  HELP
12
22
 
13
- production_warning: <<~MESSAGE,
14
- {{yellow:! Warning: if you have connected to an {{bold:app in production}}, running {{command:serve}} may update the app URL and cause an outage.
15
- MESSAGE
16
23
  already_connected_warning: "{{yellow:! This app appears to be already connected}}",
17
- connected: "{{v}} Project now connected to {{green:%s}}",
18
24
  project_type_select: "What type of project would you like to connect?",
19
25
  cli_yml_saved: ".shopify-cli.yml saved to project root",
20
26
  },
@@ -70,6 +76,16 @@ module ShopifyCli
70
76
  is_enabled: "{{v}} analytics are currently enabled",
71
77
  is_disabled: "{{v}} analytics are currently disabled",
72
78
  },
79
+ shopifolk_beta: {
80
+ help: <<~HELP,
81
+ Opt in/out of shopifolk beta
82
+ Usage: {{command:%s config [ analytics ] }}
83
+ HELP
84
+ enabled: "{{v}} shopifolk-beta has been enabled",
85
+ disabled: "{{v}} shopifolk-beta has been disabled",
86
+ is_enabled: "{{v}} shopifolk-beta is currently enabled",
87
+ is_disabled: "{{v}} shopifolk-beta is currently disabled",
88
+ },
73
89
  },
74
90
 
75
91
  git: {
@@ -177,6 +193,8 @@ module ShopifyCli
177
193
  api: {
178
194
  error: {
179
195
  internal_server_error: '{{red:{{x}} An unexpected error occurred on Shopify.}}',
196
+ internal_server_error_debug: "\n{{red:Response details:}}\n%s\n\n",
197
+ invalid_url: 'Invalid URL: %s',
180
198
  },
181
199
  },
182
200
 
@@ -251,6 +269,8 @@ module ShopifyCli
251
269
  },
252
270
  environment_header: "{{bold:Environment}}",
253
271
  env: "%-17s = %s",
272
+ identity_header: "{{bold:Identity}}",
273
+ identity_is_shopifolk: "{{v}} Checked user settings: you’re Shopify staff!",
254
274
  },
255
275
 
256
276
  tasks: {
@@ -297,6 +317,8 @@ module ShopifyCli
297
317
  organization_not_found: "Cannot find a partner organization with that ID",
298
318
  partners_notice: "Please visit https://partners.shopify.com/ to create a partners account",
299
319
  },
320
+ first_party: "Are you working on a 1P (1st Party) app?",
321
+ identified_as_shopify: "We've identified you as a {{green:Shopify}} employee.",
300
322
  organization: "Partner organization {{green:%s (%s)}}",
301
323
  organization_select: "Select partner organization",
302
324
  },
@@ -308,6 +330,8 @@ module ShopifyCli
308
330
  url_fetch_failure: "Unable to fetch external url",
309
331
  prereq_command_required: "%1$s is required for installing ngrok. Please install %1$s using the appropriate"\
310
332
  " package manager for your system.",
333
+ ngrok: "Something went wrong with ngrok installation,"\
334
+ "please make sure %s exists within %s before trying again",
311
335
  },
312
336
 
313
337
  not_running: "{{green:x}} ngrok tunnel not running",
@@ -342,15 +366,15 @@ module ShopifyCli
342
366
  {{x}} This version of Shopify App CLI is no longer supported. You’ll need to migrate to the new CLI version to continue.
343
367
 
344
368
  Please visit this page for complete instructions:
345
- {{underline:https://shopify.github.io/shopify-app-cli/migrate/}}
369
+ {{underline:https://shopify.dev/tools/cli/troubleshooting#migrate-from-a-legacy-version}}
346
370
 
347
371
  MESSAGE
348
372
 
349
373
  new_version: <<~MESSAGE,
350
- {{*}} {{yellow:A new version of the Shopify App CLI is available! You have version %s and the latest version is %s.
374
+ {{*}} {{yellow:A new version of Shopify App CLI is available! You have version %s and the latest version is %s.
351
375
 
352
376
  To upgrade, follow the instructions for the package manager you’re using:
353
- {{underline:https://shopify.github.io/shopify-app-cli/getting-started/upgrade/}}}}
377
+ {{underline:https://shopify.dev/tools/cli/troubleshooting#upgrade-shopify-app-cli}}}}
354
378
 
355
379
  MESSAGE
356
380
  },
@@ -0,0 +1,104 @@
1
+ module ShopifyCli
2
+ ##
3
+ # The `MethodObject` mixin can be included in any class that implements `call`
4
+ # to ensure that
5
+ #
6
+ # * `call` will always return a `ShopifyCli::Result` by prepending a module
7
+ # that takes care of the result wrapping and
8
+ # * a `to_proc` method that allows instances of this class to be passed as a
9
+ # block.
10
+ #
11
+ # For convenience, this mixin also adds the corresponding class methods:
12
+ # `call` and `to_proc`. Method and result objects pair nicely as they greatly
13
+ # simplify the creation of complex processing chains:
14
+ #
15
+ # class Serialize
16
+ # include MethodObject
17
+ #
18
+ # def call(attrs)
19
+ # attrs.to_json
20
+ # end
21
+ # end
22
+ #
23
+ # class Deserialize
24
+ # include MethodObject
25
+ #
26
+ # def call(json)
27
+ # JSON.parse(json)
28
+ # end
29
+ # end
30
+ #
31
+ # Serialize
32
+ # .call(firstname: "John", lastname: "Doe")
33
+ # .then(&Deserialize)
34
+ # .map { |attrs| OpenStruct.new(attrs) }
35
+ # .unwrap(nil)
36
+ #
37
+ # While this example is contrived, it still illustrates some key advantages of
38
+ # this programming paradigm:
39
+ #
40
+ # * chaining operations is as simple as repeatedly calling `then` or `map`,
41
+ # * method objects don't have to be manually instantiated but can be
42
+ # constructed using the `&` operator,
43
+ # * error handling is deferred until the result is unwrapped.
44
+ #
45
+ # Please see the section for `ShopifyCli::Result`,
46
+ # `ShopifyCli::Result::Success`, and `ShopifyCli::Result::Failure` for more
47
+ # information on the API of result objects.
48
+ #
49
+ module MethodObject
50
+ module AutoCreateResultObject
51
+ ##
52
+ # invokes the original `call` implementation and wraps its return value
53
+ # into a result object.
54
+ #
55
+ def call(*args, **kwargs)
56
+ Result.wrap { super(*args, **kwargs) }.call
57
+ end
58
+ end
59
+
60
+ module ClassMethods
61
+ ##
62
+ # creates a new instance and invokes `call`. Any positional argument
63
+ # is forward to `call`. Keyword arguments are either forwarded to the
64
+ # inializer or to `call`. If the keyword argument matches the name of
65
+ # property, it is forwarded to the initializer, otherwise to call.
66
+ #
67
+ def call(*args, **kwargs)
68
+ properties.keys.yield_self do |properties|
69
+ new(**kwargs.slice(*properties))
70
+ .call(*args, **kwargs.slice(*(kwargs.keys - properties)))
71
+ end
72
+ end
73
+
74
+ ##
75
+ # returns a proc that invokes `call` with all arguments it receives when
76
+ # called itself.
77
+ #
78
+ def to_proc
79
+ method(:call).to_proc
80
+ end
81
+ end
82
+
83
+ ##
84
+ # is invoked when this mixin is included into a class. This results in
85
+ #
86
+ # * including `SmartProperties`,
87
+ # * prepending the result wrapping mechanism, and
88
+ # * adding the class methods `.call` and `.to_proc`.
89
+ #
90
+ def self.included(method_object_implementation)
91
+ method_object_implementation.prepend(AutoCreateResultObject)
92
+ method_object_implementation.include(SmartProperties)
93
+ method_object_implementation.extend(ClassMethods)
94
+ end
95
+
96
+ ##
97
+ # returns a proc that invokes `call` with all arguments it receives when
98
+ # called itself.
99
+ #
100
+ def to_proc
101
+ method(:call).to_proc
102
+ end
103
+ end
104
+ end
@@ -10,7 +10,7 @@ module ShopifyCli
10
10
 
11
11
  # Defines the environment variable that this API looks for to operate on local
12
12
  # services. If you set this environment variable in your shell then the partners
13
- # api will operation on your local instance
13
+ # API will operate on your local instance
14
14
  #
15
15
  # #### Example
16
16
  #
@@ -27,7 +27,7 @@ module ShopifyCli
27
27
  # #### Parameters
28
28
  # - `ctx`: running context from your command
29
29
  # - `query_name`: name of the query you want to use, loaded from the `lib/graphql` directory.
30
- # - `**variable`: a hash of variables to be supplied to the query ro mutation
30
+ # - `**variables`: a hash of variables to be supplied to the query or mutation
31
31
  #
32
32
  # #### Raises
33
33
  #
@@ -50,6 +50,13 @@ module ShopifyCli
50
50
  end
51
51
  end
52
52
 
53
+ def partners_url_for(organization_id, api_client_id, local_debug)
54
+ if ShopifyCli::Shopifolk.acting_as_shopify_organization?
55
+ organization_id = 'internal'
56
+ end
57
+ "#{partners_endpoint(local_debug)}/#{organization_id}/apps/#{api_client_id}"
58
+ end
59
+
53
60
  private
54
61
 
55
62
  def authenticated_req(ctx)
@@ -81,7 +88,7 @@ module ShopifyCli
81
88
  ctx: ctx,
82
89
  service: 'identity',
83
90
  client_id: cli_id,
84
- scopes: 'openid https://api.shopify.com/auth/partners.app.cli.access',
91
+ scopes: scopes.join(" "),
85
92
  request_exchange: partners_id,
86
93
  ).authenticate("#{auth_endpoint}/oauth")
87
94
  end
@@ -105,6 +112,21 @@ module ShopifyCli
105
112
  return 'https://partners.shopify.com' if ENV[LOCAL_DEBUG].nil?
106
113
  'https://partners.myshopify.io/'
107
114
  end
115
+
116
+ def partners_endpoint(local_debug)
117
+ domain = if local_debug
118
+ 'partners.myshopify.io'
119
+ else
120
+ 'partners.shopify.com'
121
+ end
122
+ "https://#{domain}"
123
+ end
124
+
125
+ def scopes
126
+ %w[openid https://api.shopify.com/auth/partners.app.cli.access].tap do |result|
127
+ result << "employee" if ShopifyCli::Shopifolk.acting_as_shopify_organization?
128
+ end
129
+ end
108
130
  end
109
131
 
110
132
  def auth_headers(token)
@@ -206,7 +206,7 @@ module ShopifyCli
206
206
  unless ctx.windows?
207
207
  Process.kill('TERM', id)
208
208
  50.times do
209
- sleep 0.1
209
+ sleep(0.1)
210
210
  break unless stat(id)
211
211
  end
212
212
  end
@@ -34,7 +34,8 @@ module ShopifyCli
34
34
  # project = ShopifyCli::Project.current
35
35
  #
36
36
  def current(force_reload: false)
37
- at(Dir.pwd, force_reload: force_reload)
37
+ clear if force_reload
38
+ at(Dir.pwd)
38
39
  end
39
40
 
40
41
  ##
@@ -87,27 +88,30 @@ module ShopifyCli
87
88
  content = Hash[{ project_type: project_type, organization_id: organization_id.to_i }
88
89
  .merge(identifiers)
89
90
  .collect { |k, v| [k.to_s, v] }]
91
+ content['shopify_organization'] = true if Shopifolk.acting_as_shopify_organization?
90
92
 
91
93
  ctx.write('.shopify-cli.yml', YAML.dump(content))
94
+ clear
92
95
  end
93
96
 
94
97
  def project_name
95
98
  File.basename(current.directory)
96
99
  end
97
100
 
98
- private
101
+ def clear
102
+ @at = nil
103
+ @dir = nil
104
+ end
99
105
 
100
- def directory(dir, force_reload: false)
101
- @dir = nil if force_reload
106
+ private
102
107
 
108
+ def directory(dir)
103
109
  @dir ||= Hash.new { |h, k| h[k] = __directory(k) }
104
110
  @dir[dir]
105
111
  end
106
112
 
107
- def at(dir, force_reload: false)
108
- @at = nil if force_reload
109
-
110
- proj_dir = directory(dir, force_reload: force_reload)
113
+ def at(dir)
114
+ proj_dir = directory(dir)
111
115
  unless proj_dir
112
116
  raise(ShopifyCli::Abort, Context.message('core.project.error.not_in_project'))
113
117
  end