shopify-cli 1.7.1 → 1.11.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 (103) hide show
  1. checksums.yaml +4 -4
  2. data/.github/PULL_REQUEST_TEMPLATE.md +1 -0
  3. data/.github/workflows/build.yml +28 -0
  4. data/.rubocop_todo.yml +15 -2
  5. data/CHANGELOG.md +25 -0
  6. data/Gemfile.lock +15 -15
  7. data/README.md +2 -1
  8. data/dev.yml +3 -0
  9. data/lib/docgen/markdown.rb +1 -1
  10. data/lib/graphql/extension_create.graphql +17 -2
  11. data/lib/graphql/fetch_specifications.graphql +14 -0
  12. data/lib/project_types/extension/cli.rb +8 -10
  13. data/lib/project_types/extension/commands/create.rb +2 -2
  14. data/lib/project_types/extension/commands/extension_command.rb +10 -6
  15. data/lib/project_types/extension/commands/push.rb +2 -2
  16. data/lib/project_types/extension/commands/register.rb +6 -5
  17. data/lib/project_types/extension/commands/serve.rb +64 -22
  18. data/lib/project_types/extension/commands/tunnel.rb +3 -1
  19. data/lib/project_types/extension/extension_project.rb +20 -4
  20. data/lib/project_types/extension/extension_project_keys.rb +2 -1
  21. data/lib/project_types/extension/features/argo.rb +19 -44
  22. data/lib/project_types/extension/features/argo_runtime.rb +63 -0
  23. data/lib/project_types/extension/features/argo_serve.rb +79 -0
  24. data/lib/project_types/extension/features/argo_serve_options.rb +40 -0
  25. data/lib/project_types/extension/features/argo_setup.rb +1 -1
  26. data/lib/project_types/extension/forms/questions/ask_type.rb +16 -5
  27. data/lib/project_types/extension/messages/message_loading.rb +3 -1
  28. data/lib/project_types/extension/messages/messages.rb +9 -6
  29. data/lib/project_types/extension/models/npm_package.rb +14 -0
  30. data/lib/project_types/extension/models/registration.rb +1 -0
  31. data/lib/project_types/extension/models/specification.rb +7 -2
  32. data/lib/project_types/extension/models/specification_handlers/checkout_argo_extension.rb +18 -0
  33. data/lib/project_types/extension/models/specification_handlers/default.rb +35 -2
  34. data/lib/project_types/extension/models/specifications.rb +12 -1
  35. data/lib/project_types/extension/models/version.rb +1 -1
  36. data/lib/project_types/extension/tasks/choose_next_available_port.rb +36 -0
  37. data/lib/project_types/extension/tasks/configure_features.rb +5 -1
  38. data/lib/project_types/extension/tasks/converters/registration_converter.rb +2 -0
  39. data/lib/project_types/extension/tasks/fetch_specifications.rb +8 -28
  40. data/lib/project_types/extension/tasks/find_npm_packages.rb +106 -0
  41. data/lib/project_types/node/commands/generate.rb +0 -22
  42. data/lib/project_types/node/forms/create.rb +10 -1
  43. data/lib/project_types/node/messages/messages.rb +5 -4
  44. data/lib/project_types/rails/forms/create.rb +11 -1
  45. data/lib/project_types/rails/messages/messages.rb +5 -4
  46. data/lib/project_types/script/cli.rb +7 -8
  47. data/lib/project_types/script/commands/create.rb +0 -7
  48. data/lib/project_types/script/commands/push.rb +3 -3
  49. data/lib/project_types/script/config/extension_points.yml +17 -0
  50. data/lib/project_types/script/errors.rb +0 -19
  51. data/lib/project_types/script/forms/create.rb +3 -14
  52. data/lib/project_types/script/graphql/app_script_update_or_create.graphql +5 -5
  53. data/lib/project_types/script/graphql/get_app_scripts.graphql +6 -0
  54. data/lib/project_types/script/graphql/script_service_proxy.graphql +1 -2
  55. data/lib/project_types/script/layers/application/build_script.rb +1 -2
  56. data/lib/project_types/script/layers/application/create_script.rb +32 -49
  57. data/lib/project_types/script/layers/application/extension_points.rb +3 -2
  58. data/lib/project_types/script/layers/application/push_script.rb +5 -5
  59. data/lib/project_types/script/layers/domain/errors.rb +0 -2
  60. data/lib/project_types/script/layers/domain/extension_point.rb +60 -45
  61. data/lib/project_types/script/layers/domain/metadata.rb +18 -25
  62. data/lib/project_types/script/layers/domain/push_package.rb +4 -4
  63. data/lib/project_types/script/layers/domain/script_project.rb +54 -0
  64. data/lib/project_types/script/layers/infrastructure/assemblyscript_project_creator.rb +39 -14
  65. data/lib/project_types/script/layers/infrastructure/assemblyscript_task_runner.rb +14 -43
  66. data/lib/project_types/script/layers/infrastructure/command_runner.rb +19 -0
  67. data/lib/project_types/script/layers/infrastructure/errors.rb +40 -20
  68. data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +12 -13
  69. data/lib/project_types/script/layers/infrastructure/rust_project_creator.rb +9 -10
  70. data/lib/project_types/script/layers/infrastructure/rust_task_runner.rb +6 -7
  71. data/lib/project_types/script/layers/infrastructure/script_project_repository.rb +172 -0
  72. data/lib/project_types/script/layers/infrastructure/script_service.rb +25 -76
  73. data/lib/project_types/script/messages/messages.rb +20 -53
  74. data/lib/project_types/script/tasks/ensure_env.rb +85 -0
  75. data/lib/project_types/script/ui/error_handler.rb +32 -41
  76. data/lib/shopify-cli/context.rb +28 -0
  77. data/lib/shopify-cli/js_system.rb +2 -2
  78. data/lib/shopify-cli/messages/messages.rb +50 -45
  79. data/lib/shopify-cli/method_object.rb +4 -4
  80. data/lib/shopify-cli/oauth.rb +9 -3
  81. data/lib/shopify-cli/packager.rb +1 -1
  82. data/lib/shopify-cli/partners_api/organizations.rb +3 -3
  83. data/lib/shopify-cli/resolve_constant.rb +1 -1
  84. data/lib/shopify-cli/resources/env_file.rb +1 -1
  85. data/lib/shopify-cli/tasks/ensure_dev_store.rb +1 -1
  86. data/lib/shopify-cli/tasks/select_org_and_shop.rb +6 -4
  87. data/lib/shopify-cli/transform_data_structure.rb +2 -2
  88. data/lib/shopify-cli/tunnel.rb +22 -1
  89. data/lib/shopify-cli/version.rb +1 -1
  90. data/lib/shopify_cli.rb +0 -1
  91. data/vendor/deps/smart_properties/REVISION +1 -1
  92. data/vendor/deps/smart_properties/lib/smart_properties/property.rb +7 -1
  93. data/vendor/deps/smart_properties/lib/smart_properties/version.rb +1 -1
  94. metadata +17 -12
  95. data/.travis.yml +0 -14
  96. data/lib/project_types/script/commands/disable.rb +0 -25
  97. data/lib/project_types/script/commands/enable.rb +0 -80
  98. data/lib/project_types/script/graphql/shop_script_delete.graphql +0 -14
  99. data/lib/project_types/script/graphql/shop_script_update_or_create.graphql +0 -28
  100. data/lib/project_types/script/layers/application/disable_script.rb +0 -21
  101. data/lib/project_types/script/layers/application/enable_script.rb +0 -23
  102. data/lib/project_types/script/layers/infrastructure/config_ui_repository.rb +0 -46
  103. data/lib/project_types/script/script_project.rb +0 -64
@@ -144,6 +144,34 @@ module ShopifyCli
144
144
  File.write(ctx_path(fname), content)
145
145
  end
146
146
 
147
+ # will read a binary file relative to the context root unless the file path is absolute.
148
+ #
149
+ # #### Parameters
150
+ # * `fname` - filename of the file that you are reading, relative to root unless it is absolute.
151
+ #
152
+ # #### Example
153
+ #
154
+ # @ctx.read('binary.out')
155
+ #
156
+ def binread(fname)
157
+ File.binread(ctx_path(fname))
158
+ end
159
+
160
+ # will write/overwrite a binary file with the provided contents, relative to the context root
161
+ # unless the file path is absolute.
162
+ #
163
+ # #### Parameters
164
+ # * `fname` - filename of the file that you are writing, relative to root unless it is absolute.
165
+ # * `content` - the body contents of the file that you are writing
166
+ #
167
+ # #### Example
168
+ #
169
+ # @ctx.binwrite('binary.out', 'ASCII-8BIT encoded binary')
170
+ #
171
+ def binwrite(fname, content)
172
+ File.binwrite(ctx_path(fname), content)
173
+ end
174
+
147
175
  # will change directories and update the root, the filepath is relative to the command root unless absolute
148
176
  #
149
177
  # #### Parameters
@@ -37,8 +37,8 @@ module ShopifyCli
37
37
  #
38
38
  # ShopifyCli::JsSystem.call(ctx, yarn: ['install', '--silent'], npm: ['install', '--no-audit'])
39
39
  #
40
- def call(ctx, yarn:, npm:)
41
- JsSystem.new(ctx: ctx).call(yarn: yarn, npm: npm)
40
+ def call(ctx, yarn:, npm:, capture_response: false)
41
+ JsSystem.new(ctx: ctx).call(yarn: yarn, npm: npm, capture_response: capture_response)
42
42
  end
43
43
  end
44
44
 
@@ -16,8 +16,8 @@ module ShopifyCli
16
16
  core: {
17
17
  connect: {
18
18
  help: <<~HELP,
19
- Connect (or re-connect) an existing project to a Shopify partner organization and/or a store. Creates or updates the {{green:.env}} file, and creates the {{green:.shopify-cli.yml}} file.
20
- Usage: {{command:%s connect}}
19
+ Connect (or re-connect) an existing project to a Shopify partner organization and/or a store. Creates or updates the {{green:.env}} file, and creates the {{green:.shopify-cli.yml}} file.
20
+ Usage: {{command:%s connect}}
21
21
  HELP
22
22
 
23
23
  already_connected_warning: "{{yellow:! This app appears to be already connected}}",
@@ -27,15 +27,15 @@ module ShopifyCli
27
27
 
28
28
  context: {
29
29
  open_url: <<~OPEN,
30
- Please open this URL in your browser:
31
- {{green:%s}}
30
+ Please open this URL in your browser:
31
+ {{green:%s}}
32
32
  OPEN
33
33
  },
34
34
 
35
35
  create: {
36
36
  help: <<~HELP,
37
- Create a new project.
38
- Usage: {{command:%s create [ %s ]}}
37
+ Create a new project.
38
+ Usage: {{command:%s create [ %s ]}}
39
39
  HELP
40
40
 
41
41
  error: {
@@ -53,13 +53,13 @@ module ShopifyCli
53
53
 
54
54
  config: {
55
55
  help: <<~HELP,
56
- Change configuration of how the CLI operates
57
- Usage: {{command:%s config [ feature | analytics ] }}
56
+ Change configuration of how the CLI operates
57
+ Usage: {{command:%s config [ feature | analytics ] }}
58
58
  HELP
59
59
  feature: {
60
60
  help: <<~HELP,
61
- Change configuration of various features
62
- Usage: {{command:%s config [ feature ] [ feature_name ] }}
61
+ Change configuration of various features
62
+ Usage: {{command:%s config [ feature ] [ feature_name ] }}
63
63
  HELP
64
64
  enabled: "{{v}} feature {{green:%s}} has been enabled",
65
65
  disabled: "{{v}} feature {{green:%s}} has been disabled",
@@ -68,8 +68,8 @@ module ShopifyCli
68
68
  },
69
69
  analytics: {
70
70
  help: <<~HELP,
71
- Opt in/out of anonymous usage reporting
72
- Usage: {{command:%s config [ analytics ] }}
71
+ Opt in/out of anonymous usage reporting
72
+ Usage: {{command:%s config [ analytics ] }}
73
73
  HELP
74
74
  enabled: "{{v}} analytics have been enabled",
75
75
  disabled: "{{v}} analytics have been disabled",
@@ -82,7 +82,8 @@ module ShopifyCli
82
82
  error: {
83
83
  directory_exists: "Project directory already exists. Please create a project with a new name.",
84
84
  no_branches_found: "Could not find any git branches",
85
- repo_not_initiated: "Git repo is not initiated. Please run `git init` and make at least one commit.",
85
+ repo_not_initiated:
86
+ "Git repo is not initiated. Please run {{command:git init}} and make at least one commit.",
86
87
  no_commits_made: "No git commits have been made. Please make at least one commit.",
87
88
  },
88
89
 
@@ -96,9 +97,9 @@ module ShopifyCli
96
97
  },
97
98
 
98
99
  preamble: <<~MESSAGE,
99
- Use {{command:%s help <command>}} to display detailed information about a specific command.
100
+ Use {{command:%s help <command>}} to display detailed information about a specific command.
100
101
 
101
- {{bold:Available core commands:}}
102
+ {{bold:Available core commands:}}
102
103
 
103
104
  MESSAGE
104
105
  },
@@ -110,7 +111,7 @@ module ShopifyCli
110
111
  deploy: "Could not deploy to Heroku",
111
112
  download: "Heroku CLI could not be downloaded",
112
113
  install: "Could not install Heroku CLI",
113
- could_not_select_app: "Heroku app `%s` could not be selected",
114
+ could_not_select_app: "Heroku app {{green:%s}} could not be selected",
114
115
  },
115
116
  },
116
117
 
@@ -130,8 +131,8 @@ module ShopifyCli
130
131
 
131
132
  logout: {
132
133
  help: <<~HELP,
133
- Log out of a currently authenticated partner organization and store, or clear invalid credentials
134
- Usage: {{command:%s logout}}
134
+ Log out of a currently authenticated partner organization and store, or clear invalid credentials
135
+ Usage: {{command:%s logout}}
135
136
  HELP
136
137
 
137
138
  success: "Logged out of partner organization and store",
@@ -153,6 +154,7 @@ module ShopifyCli
153
154
  location: {
154
155
  admin: "development store",
155
156
  partner: "Shopify Partners account",
157
+ shopifolk: "{{green:Shopify Employee account}}",
156
158
  },
157
159
  authentication_required:
158
160
  "{{i}} Authentication required. Login to the URL below with your %s credentials to continue.",
@@ -174,8 +176,8 @@ module ShopifyCli
174
176
  org_name_and_id: "%s (%s)",
175
177
  error: {
176
178
  account_not_found: <<~MESSAGE,
177
- {{x}} error: Your account was not found. Please sign up at https://partners.shopify.com/signup
178
- For authentication issues, run {{command:%s logout}} to clear invalid credentials
179
+ {{x}} error: Your account was not found. Please sign up at https://partners.shopify.com/signup
180
+ For authentication issues, run {{command:%s logout}} to clear invalid credentials
179
181
  MESSAGE
180
182
  },
181
183
  },
@@ -195,16 +197,16 @@ module ShopifyCli
195
197
  },
196
198
  populating: "Populating %d %ss...",
197
199
  completion_message: <<~COMPLETION_MESSAGE,
198
- Successfully added %d %s to {{green:%s}}
199
- {{*}} View all %ss at {{underline:%s%ss}}
200
+ Successfully added %d %s to {{green:%s}}
201
+ {{*}} View all %ss at {{underline:%s%ss}}
200
202
  COMPLETION_MESSAGE
201
203
  },
202
204
 
203
205
  project: {
204
206
  error: {
205
207
  not_in_project: <<~MESSAGE,
206
- {{x}} You are not in a Shopify app project
207
- {{yellow:{{*}}}}{{reset: Run}}{{cyan: shopify create}}{{reset: to create your app}}
208
+ {{x}} You are not in a Shopify app project
209
+ {{yellow:{{*}}}}{{reset: Run}}{{cyan: shopify create}}{{reset: to create your app}}
208
210
  MESSAGE
209
211
  },
210
212
  },
@@ -225,10 +227,10 @@ module ShopifyCli
225
227
 
226
228
  system: {
227
229
  help: <<~HELP,
228
- Print details about the development system.
229
- Usage: {{command:%s system [all]}}
230
+ Print details about the development system.
231
+ Usage: {{command:%s system [all]}}
230
232
 
231
- {{cyan:all}}: displays more details about development system and environment
233
+ {{cyan:all}}: displays more details about development system and environment
232
234
 
233
235
  HELP
234
236
 
@@ -239,8 +241,8 @@ module ShopifyCli
239
241
  header: "{{bold:Shopify App CLI}}",
240
242
  const: "%17s = %s",
241
243
  ruby_header: <<~RUBY_MESSAGE,
242
- {{bold:Ruby (via RbConfig)}}
243
- %s
244
+ {{bold:Ruby (via RbConfig)}}
245
+ %s
244
246
  RUBY_MESSAGE
245
247
  rb_config: "%-25s - RbConfig[\"%s\"]",
246
248
  command_header: "{{bold:Commands}}",
@@ -267,8 +269,8 @@ module ShopifyCli
267
269
  ensure_env: {
268
270
  organization_select: "To which partner organization does this project belong?",
269
271
  no_development_stores: <<~MESSAGE,
270
- No development stores available.
271
- Visit {{underline:https://partners.shopify.com/%d/stores}} to create one
272
+ No development stores available.
273
+ Visit {{underline:https://partners.shopify.com/%d/stores}} to create one
272
274
  MESSAGE
273
275
  development_store_select: "Which development store would you like to use?",
274
276
  app_select: "To which app does this project belong?",
@@ -305,7 +307,10 @@ module ShopifyCli
305
307
  no_development_stores: "{{x}} No Development Stores available.",
306
308
  no_organizations: "No partner organizations available.",
307
309
  organization_not_found: "Cannot find a partner organization with that ID",
308
- partners_notice: "Please visit https://partners.shopify.com/ to create a partners account",
310
+ shopifolk_notice: <<~MESSAGE,
311
+ {{i}} As a {{green:Shopify}} employee, the authentication should take you to the Shopify Okta login,
312
+ NOT the Partner account login. Please run {{command:%s logout}} and try again.
313
+ MESSAGE
309
314
  },
310
315
  first_party: "Are you working on a 1P (1st Party) app?",
311
316
  identified_as_shopify: "We've identified you as a {{green:Shopify}} employee.",
@@ -326,9 +331,9 @@ module ShopifyCli
326
331
 
327
332
  not_running: "{{green:x}} ngrok tunnel not running",
328
333
  signup_suggestion: <<~MESSAGE,
329
- {{*}} To avoid tunnels that timeout, it is recommended to signup for a free ngrok
330
- account at {{underline:https://ngrok.com/signup}}. After you signup, install your
331
- personalized authorization token using {{command:%s tunnel auth <token>}}.
334
+ {{*}} To avoid tunnels that timeout, it is recommended to signup for a free ngrok
335
+ account at {{underline:https://ngrok.com/signup}}. After you signup, install your
336
+ personalized authorization token using {{command:%s tunnel auth <token>}}.
332
337
  MESSAGE
333
338
  start: "{{v}} ngrok tunnel running at {{underline:%s}}",
334
339
  start_with_account: "{{v}} ngrok tunnel running at {{underline:%s}}, with account %s",
@@ -340,31 +345,31 @@ module ShopifyCli
340
345
 
341
346
  version: {
342
347
  help: <<~HELP,
343
- Prints version number.
344
- Usage: {{command:%s version}}
348
+ Prints version number.
349
+ Usage: {{command:%s version}}
345
350
  HELP
346
351
  },
347
352
 
348
353
  warning: {
349
354
  development_version: <<~DEVELOPMENT,
350
- {{*}} {{yellow:You are running a development version of the CLI at:}}
351
- {{yellow:%s}}
355
+ {{*}} {{yellow:You are running a development version of the CLI at:}}
356
+ {{yellow:%s}}
352
357
 
353
358
  DEVELOPMENT
354
359
 
355
360
  shell_shim: <<~MESSAGE,
356
- {{x}} This version of Shopify App CLI is no longer supported. You’ll need to migrate to the new CLI version to continue.
361
+ {{x}} This version of Shopify App CLI is no longer supported. You’ll need to migrate to the new CLI version to continue.
357
362
 
358
- Please visit this page for complete instructions:
359
- {{underline:https://shopify.dev/tools/cli/troubleshooting#migrate-from-a-legacy-version}}
363
+ Please visit this page for complete instructions:
364
+ {{underline:https://shopify.dev/tools/cli/troubleshooting#migrate-from-a-legacy-version}}
360
365
 
361
366
  MESSAGE
362
367
 
363
368
  new_version: <<~MESSAGE,
364
- {{*}} {{yellow:A new version of Shopify App CLI is available! You have version %s and the latest version is %s.
369
+ {{*}} {{yellow:A new version of Shopify App CLI is available! You have version %s and the latest version is %s.
365
370
 
366
- To upgrade, follow the instructions for the package manager you’re using:
367
- {{underline:https://shopify.dev/tools/cli/troubleshooting#upgrade-shopify-app-cli}}}}
371
+ To upgrade, follow the instructions for the package manager you’re using:
372
+ {{underline:https://shopify.dev/tools/cli/troubleshooting#upgrade-shopify-app-cli}}}}
368
373
 
369
374
  MESSAGE
370
375
  },
@@ -52,8 +52,8 @@ module ShopifyCli
52
52
  # invokes the original `call` implementation and wraps its return value
53
53
  # into a result object.
54
54
  #
55
- def call(*args, **kwargs)
56
- Result.wrap { super(*args, **kwargs) }.call
55
+ def call(*args, **kwargs, &block)
56
+ Result.wrap { kwargs.any? ? super(*args, **kwargs, &block) : super(*args, &block) }.call
57
57
  end
58
58
  end
59
59
 
@@ -64,10 +64,10 @@ module ShopifyCli
64
64
  # initializer or to `call`. If the keyword argument matches the name of
65
65
  # property, it is forwarded to the initializer, otherwise to call.
66
66
  #
67
- def call(*args, **kwargs)
67
+ def call(*args, **kwargs, &block)
68
68
  properties.keys.yield_self do |properties|
69
69
  new(**kwargs.slice(*properties))
70
- .call(*args, **kwargs.slice(*(kwargs.keys - properties)))
70
+ .call(*args, **kwargs.slice(*(kwargs.keys - properties)), &block)
71
71
  end
72
72
  end
73
73
 
@@ -24,10 +24,10 @@ module ShopifyCli
24
24
  property! :service, accepts: String
25
25
  property! :client_id, accepts: String
26
26
  property! :scopes
27
- property :store, default: ShopifyCli::DB.new
27
+ property :store, default: -> { ShopifyCli::DB.new }
28
28
  property :secret, accepts: String
29
29
  property :request_exchange, accepts: String
30
- property :options, default: {}, accepts: Hash
30
+ property :options, default: -> { {} }, accepts: Hash
31
31
  property :auth_path, default: "/authorize", accepts: ->(path) { path.is_a?(String) && path.start_with?("/") }
32
32
  property :token_path, default: "/token", accepts: ->(path) { path.is_a?(String) && path.start_with?("/") }
33
33
  property :state_token, accepts: String, default: SecureRandom.hex(30)
@@ -80,7 +80,13 @@ module ShopifyCli
80
80
  end
81
81
 
82
82
  def output_authentication_info(uri)
83
- login_location = ctx.message(service == "admin" ? "core.oauth.location.admin" : "core.oauth.location.partner")
83
+ login_location = if service == "admin"
84
+ ctx.message("core.oauth.location.admin")
85
+ elsif Shopifolk.acting_as_shopify_organization?
86
+ ctx.message("core.oauth.location.shopifolk")
87
+ else
88
+ ctx.message("core.oauth.location.partner")
89
+ end
84
90
  ctx.puts(ctx.message("core.oauth.authentication_required", login_location))
85
91
  ctx.open_url!(uri)
86
92
  end
@@ -99,7 +99,7 @@ module ShopifyCli
99
99
  raise <<~MESSAGE
100
100
 
101
101
  Could not find program #{program} which is required to build the package.
102
- You can install it by running `#{installation_cmd}`.
102
+ You can install it by running #{installation_cmd}.
103
103
 
104
104
  MESSAGE
105
105
  end
@@ -4,7 +4,7 @@ module ShopifyCli
4
4
  class << self
5
5
  def fetch_all(ctx)
6
6
  resp = PartnersAPI.query(ctx, "all_organizations")
7
- (resp.dig("data", "organizations", "nodes") || []).map do |org|
7
+ (resp&.dig("data", "organizations", "nodes") || []).map do |org|
8
8
  org["stores"] = (org.dig("stores", "nodes") || [])
9
9
  org
10
10
  end
@@ -12,7 +12,7 @@ module ShopifyCli
12
12
 
13
13
  def fetch(ctx, id:)
14
14
  resp = PartnersAPI.query(ctx, "find_organization", id: id)
15
- org = resp.dig("data", "organizations", "nodes").first
15
+ org = resp&.dig("data", "organizations", "nodes")&.first
16
16
  return nil if org.nil?
17
17
  org["stores"] = (org.dig("stores", "nodes") || [])
18
18
  org
@@ -20,7 +20,7 @@ module ShopifyCli
20
20
 
21
21
  def fetch_with_app(ctx)
22
22
  resp = PartnersAPI.query(ctx, "all_orgs_with_apps")
23
- (resp.dig("data", "organizations", "nodes") || []).map do |org|
23
+ (resp&.dig("data", "organizations", "nodes") || []).map do |org|
24
24
  org["stores"] = (org.dig("stores", "nodes") || [])
25
25
  org["apps"] = (org.dig("apps", "nodes") || [])
26
26
  org
@@ -11,7 +11,7 @@
11
11
  module ShopifyCli
12
12
  class ResolveConstant
13
13
  include ShopifyCli::MethodObject
14
- property! :namespace, accepts: ->(ns) { ns.respond_to?(:const_get) }, default: Kernel
14
+ property! :namespace, accepts: ->(ns) { ns.respond_to?(:const_get) }, default: -> { Kernel }
15
15
 
16
16
  def call(name)
17
17
  name
@@ -57,7 +57,7 @@ module ShopifyCli
57
57
  property :shop
58
58
  property :scopes
59
59
  property :host
60
- property :extra, default: {}
60
+ property :extra, default: -> { {} }
61
61
 
62
62
  def to_h
63
63
  out = {}
@@ -5,7 +5,7 @@ module ShopifyCli
5
5
  class EnsureDevStore < ShopifyCli::Task
6
6
  def call(ctx)
7
7
  @ctx = ctx
8
- return ctx.puts(ctx.message(
8
+ return ctx.abort(ctx.message(
9
9
  "core.tasks.ensure_dev_store.could_not_verify_store", project.env.shop
10
10
  )) if shop.nil?
11
11
  return if shop["transferDisabled"] == true
@@ -35,14 +35,16 @@ module ShopifyCli
35
35
  @organization ||= if !organization_id.nil?
36
36
  org = ShopifyCli::PartnersAPI::Organizations.fetch(ctx, id: organization_id)
37
37
  if org.nil?
38
- ctx.puts(ctx.message("core.tasks.select_org_and_shop.error.authentication_issue", ShopifyCli::TOOL_NAME))
38
+ ctx.puts(ctx.message("core.tasks.select_org_and_shop.authentication_issue", ShopifyCli::TOOL_NAME))
39
39
  ctx.abort(ctx.message("core.tasks.select_org_and_shop.error.organization_not_found"))
40
40
  end
41
41
  org
42
42
  elsif organizations.count == 0
43
- ctx.puts(ctx.message("core.tasks.select_org_and_shop.error.partners_notice"))
44
- ctx.puts(ctx.message("core.tasks.select_org_and_shop.authentication_issue", ShopifyCli::TOOL_NAME))
45
- ctx.abort(ctx.message("core.tasks.select_org_and_shop.error.no_organizations"))
43
+ if Shopifolk.acting_as_shopify_organization?
44
+ ctx.abort(ctx.message("core.tasks.select_org_and_shop.error.shopifolk_notice", ShopifyCli::TOOL_NAME))
45
+ else
46
+ ctx.abort(ctx.message("core.tasks.select_org_and_shop.error.no_organizations"))
47
+ end
46
48
  elsif organizations.count == 1
47
49
  org = organizations.first
48
50
  ctx.puts(ctx.message("core.tasks.select_org_and_shop.organization", org["businessName"], org["id"]))
@@ -42,7 +42,7 @@ module ShopifyCli
42
42
  property! :symbolize_keys, accepts: [true, false], default: false, reader: :symbolize_keys?
43
43
  property! :associative_array_container,
44
44
  accepts: ->(c) { c.respond_to?(:new) && c.method_defined?(:[]=) },
45
- default: Hash
45
+ default: -> { Hash }
46
46
 
47
47
  def call(object)
48
48
  case object
@@ -68,7 +68,7 @@ module ShopifyCli
68
68
  def underscore_key(key)
69
69
  return key unless underscore_keys? && key.respond_to?(:to_str)
70
70
 
71
- key.to_str.dup.yield_self do |k|
71
+ key.to_str.dup.tap do |k|
72
72
  k.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
73
73
  k.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
74
74
  k.tr!("-", "_")
@@ -2,6 +2,7 @@ require "json"
2
2
  require "fileutils"
3
3
  require "shopify_cli"
4
4
  require "forwardable"
5
+ require "uri"
5
6
 
6
7
  module ShopifyCli
7
8
  ##
@@ -11,7 +12,7 @@ module ShopifyCli
11
12
  class Tunnel
12
13
  extend SingleForwardable
13
14
 
14
- def_delegators :new, :start, :stop, :auth, :stats, :urls
15
+ def_delegators :new, :start, :stop, :auth, :stats, :urls, :running_on?
15
16
 
16
17
  class FetchUrlError < RuntimeError; end
17
18
  class NgrokError < RuntimeError; end
@@ -26,6 +27,7 @@ module ShopifyCli
26
27
 
27
28
  NGROK_TUNNELS_URI = URI.parse("http://localhost:4040/api/tunnels")
28
29
  TUNNELS_FIELD = "tunnels"
30
+ TUNNEL_ADDRESS_KEY_PATH = ["config", "addr"]
29
31
  PUBLIC_URL_FIELD = "public_url"
30
32
 
31
33
  ##
@@ -120,6 +122,25 @@ module ShopifyCli
120
122
  []
121
123
  end
122
124
 
125
+ ##
126
+ # Returns Boolean if a tunnel is running on a given port
127
+ #
128
+ # #### Parameters
129
+ #
130
+ # * `port` - port to check
131
+ #
132
+ # #### Returns
133
+ #
134
+ # * true / false
135
+ #
136
+ def running_on?(port)
137
+ extract_port = ->(tunnel) { URI(tunnel.dig(*TUNNEL_ADDRESS_KEY_PATH)).port }
138
+ matches_port = ->(occupied_port) { occupied_port == port }
139
+ stats.fetch(TUNNELS_FIELD, []).map(&extract_port).any?(&matches_port)
140
+ rescue
141
+ false
142
+ end
143
+
123
144
  private
124
145
 
125
146
  def install(ctx)