shopify-cli 1.6.0 → 1.7.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 (179) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/Gemfile +12 -12
  4. data/Rakefile +32 -30
  5. data/bin/load_shopify.rb +6 -6
  6. data/bin/shopify +2 -2
  7. data/ext/shopify-cli/extconf.rb +7 -7
  8. data/lib/docgen/markdown.rb +11 -11
  9. data/lib/{project_types/extension/graphql → graphql}/get_app_by_api_key.graphql +0 -0
  10. data/lib/project_types/extension/cli.rb +52 -45
  11. data/lib/project_types/extension/commands/build.rb +3 -3
  12. data/lib/project_types/extension/commands/create.rb +16 -9
  13. data/lib/project_types/extension/commands/extension_command.rb +8 -5
  14. data/lib/project_types/extension/commands/push.rb +8 -8
  15. data/lib/project_types/extension/commands/register.rb +19 -30
  16. data/lib/project_types/extension/commands/serve.rb +2 -2
  17. data/lib/project_types/extension/commands/tunnel.rb +12 -12
  18. data/lib/project_types/extension/extension_project.rb +4 -4
  19. data/lib/project_types/extension/extension_project_keys.rb +4 -4
  20. data/lib/project_types/extension/features/argo.rb +13 -13
  21. data/lib/project_types/extension/features/argo_config.rb +5 -5
  22. data/lib/project_types/extension/features/argo_dependencies.rb +5 -5
  23. data/lib/project_types/extension/features/argo_setup.rb +2 -2
  24. data/lib/project_types/extension/features/argo_setup_steps.rb +4 -4
  25. data/lib/project_types/extension/forms/create.rb +28 -34
  26. data/lib/project_types/extension/forms/questions/ask_app.rb +53 -0
  27. data/lib/project_types/extension/forms/questions/ask_name.rb +40 -0
  28. data/lib/project_types/extension/forms/questions/ask_type.rb +36 -0
  29. data/lib/project_types/extension/messages/messages.rb +53 -52
  30. data/lib/project_types/extension/models/lazy_specification_handler.rb +12 -0
  31. data/lib/project_types/extension/models/specification_handlers/checkout_post_purchase.rb +1 -1
  32. data/lib/project_types/extension/models/specification_handlers/default.rb +2 -2
  33. data/lib/project_types/extension/models/specifications.rb +3 -3
  34. data/lib/project_types/extension/tasks/configure_features.rb +4 -4
  35. data/lib/project_types/extension/tasks/converters/app_converter.rb +6 -6
  36. data/lib/project_types/extension/tasks/converters/registration_converter.rb +6 -6
  37. data/lib/project_types/extension/tasks/converters/validation_error_converter.rb +4 -4
  38. data/lib/project_types/extension/tasks/converters/version_converter.rb +7 -7
  39. data/lib/project_types/extension/tasks/create_extension.rb +4 -4
  40. data/lib/project_types/extension/tasks/fetch_specifications.rb +4 -4
  41. data/lib/project_types/extension/tasks/get_app.rb +4 -4
  42. data/lib/project_types/extension/tasks/get_apps.rb +3 -3
  43. data/lib/project_types/extension/tasks/update_draft.rb +4 -4
  44. data/lib/project_types/extension/tasks/user_errors.rb +4 -4
  45. data/lib/project_types/node/cli.rb +19 -19
  46. data/lib/project_types/node/commands/connect.rb +3 -3
  47. data/lib/project_types/node/commands/create.rb +40 -38
  48. data/lib/project_types/node/commands/deploy.rb +4 -4
  49. data/lib/project_types/node/commands/deploy/heroku.rb +24 -24
  50. data/lib/project_types/node/commands/generate.rb +8 -8
  51. data/lib/project_types/node/commands/open.rb +2 -2
  52. data/lib/project_types/node/commands/populate.rb +6 -6
  53. data/lib/project_types/node/commands/populate/customer.rb +5 -5
  54. data/lib/project_types/node/commands/populate/draft_order.rb +5 -5
  55. data/lib/project_types/node/commands/populate/product.rb +5 -5
  56. data/lib/project_types/node/commands/serve.rb +9 -9
  57. data/lib/project_types/node/commands/tunnel.rb +7 -7
  58. data/lib/project_types/node/forms/create.rb +7 -7
  59. data/lib/project_types/node/messages/messages.rb +3 -3
  60. data/lib/project_types/rails/cli.rb +21 -21
  61. data/lib/project_types/rails/commands/connect.rb +3 -3
  62. data/lib/project_types/rails/commands/create.rb +51 -48
  63. data/lib/project_types/rails/commands/deploy.rb +4 -4
  64. data/lib/project_types/rails/commands/deploy/heroku.rb +30 -30
  65. data/lib/project_types/rails/commands/generate.rb +7 -7
  66. data/lib/project_types/rails/commands/generate/webhook.rb +6 -6
  67. data/lib/project_types/rails/commands/open.rb +2 -2
  68. data/lib/project_types/rails/commands/populate.rb +6 -6
  69. data/lib/project_types/rails/commands/populate/customer.rb +5 -5
  70. data/lib/project_types/rails/commands/populate/draft_order.rb +5 -5
  71. data/lib/project_types/rails/commands/populate/product.rb +5 -5
  72. data/lib/project_types/rails/commands/serve.rb +11 -11
  73. data/lib/project_types/rails/commands/tunnel.rb +7 -7
  74. data/lib/project_types/rails/forms/create.rb +23 -23
  75. data/lib/project_types/rails/gem.rb +23 -23
  76. data/lib/project_types/rails/messages/messages.rb +4 -4
  77. data/lib/project_types/rails/ruby.rb +2 -2
  78. data/lib/project_types/script/cli.rb +40 -40
  79. data/lib/project_types/script/commands/create.rb +9 -8
  80. data/lib/project_types/script/commands/disable.rb +3 -3
  81. data/lib/project_types/script/commands/enable.rb +9 -7
  82. data/lib/project_types/script/commands/push.rb +5 -4
  83. data/lib/project_types/script/errors.rb +17 -0
  84. data/lib/project_types/script/forms/create.rb +5 -5
  85. data/lib/project_types/script/graphql/app_script_update_or_create.graphql +2 -0
  86. data/lib/project_types/script/layers/application/build_script.rb +6 -8
  87. data/lib/project_types/script/layers/application/create_script.rb +2 -2
  88. data/lib/project_types/script/layers/application/disable_script.rb +2 -2
  89. data/lib/project_types/script/layers/application/enable_script.rb +2 -2
  90. data/lib/project_types/script/layers/application/project_dependencies.rb +4 -4
  91. data/lib/project_types/script/layers/application/push_script.rb +4 -12
  92. data/lib/project_types/script/layers/domain/push_package.rb +5 -1
  93. data/lib/project_types/script/layers/infrastructure/assemblyscript_project_creator.rb +3 -3
  94. data/lib/project_types/script/layers/infrastructure/assemblyscript_task_runner.rb +10 -10
  95. data/lib/project_types/script/layers/infrastructure/errors.rb +1 -1
  96. data/lib/project_types/script/layers/infrastructure/extension_point_repository.rb +2 -2
  97. data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +12 -17
  98. data/lib/project_types/script/layers/infrastructure/rust_project_creator.rb +4 -4
  99. data/lib/project_types/script/layers/infrastructure/rust_task_runner.rb +1 -1
  100. data/lib/project_types/script/layers/infrastructure/script_service.rb +18 -16
  101. data/lib/project_types/script/messages/messages.rb +14 -8
  102. data/lib/project_types/script/script_project.rb +27 -5
  103. data/lib/project_types/script/ui/error_handler.rb +80 -68
  104. data/lib/project_types/script/ui/printing_spinner.rb +1 -1
  105. data/lib/project_types/script/ui/strict_spinner.rb +1 -1
  106. data/lib/project_types/theme/cli.rb +19 -19
  107. data/lib/project_types/theme/commands/connect.rb +12 -12
  108. data/lib/project_types/theme/commands/create.rb +11 -11
  109. data/lib/project_types/theme/commands/deploy.rb +8 -8
  110. data/lib/project_types/theme/commands/generate.rb +3 -3
  111. data/lib/project_types/theme/commands/generate/env.rb +15 -15
  112. data/lib/project_types/theme/commands/push.rb +15 -15
  113. data/lib/project_types/theme/commands/serve.rb +5 -5
  114. data/lib/project_types/theme/forms/connect.rb +4 -4
  115. data/lib/project_types/theme/forms/create.rb +5 -5
  116. data/lib/project_types/theme/tasks/ensure_themekit_installed.rb +22 -22
  117. data/lib/project_types/theme/themekit.rb +15 -15
  118. data/lib/rubygems_plugin.rb +3 -3
  119. data/lib/shopify-cli/admin_api.rb +11 -11
  120. data/lib/shopify-cli/admin_api/populate_resource_command.rb +17 -17
  121. data/lib/shopify-cli/admin_api/schema.rb +3 -3
  122. data/lib/shopify-cli/api.rb +10 -10
  123. data/lib/shopify-cli/command.rb +1 -1
  124. data/lib/shopify-cli/commands.rb +9 -9
  125. data/lib/shopify-cli/commands/config.rb +28 -52
  126. data/lib/shopify-cli/commands/connect.rb +10 -10
  127. data/lib/shopify-cli/commands/create.rb +5 -5
  128. data/lib/shopify-cli/commands/help.rb +6 -6
  129. data/lib/shopify-cli/commands/logout.rb +3 -3
  130. data/lib/shopify-cli/commands/system.rb +32 -32
  131. data/lib/shopify-cli/commands/version.rb +2 -2
  132. data/lib/shopify-cli/context.rb +23 -23
  133. data/lib/shopify-cli/core.rb +4 -4
  134. data/lib/shopify-cli/core/entry_point.rb +5 -5
  135. data/lib/shopify-cli/core/executor.rb +1 -1
  136. data/lib/shopify-cli/core/help_resolver.rb +2 -2
  137. data/lib/shopify-cli/core/monorail.rb +16 -16
  138. data/lib/shopify-cli/db.rb +2 -2
  139. data/lib/shopify-cli/feature.rb +1 -1
  140. data/lib/shopify-cli/form.rb +1 -1
  141. data/lib/shopify-cli/git.rb +17 -17
  142. data/lib/shopify-cli/helpers.rb +1 -1
  143. data/lib/shopify-cli/helpers/haikunator.rb +1 -1
  144. data/lib/shopify-cli/heroku.rb +28 -28
  145. data/lib/shopify-cli/http_request.rb +2 -2
  146. data/lib/shopify-cli/js_deps.rb +12 -12
  147. data/lib/shopify-cli/js_system.rb +5 -5
  148. data/lib/shopify-cli/lazy_delegator.rb +55 -0
  149. data/lib/shopify-cli/messages/messages.rb +4 -14
  150. data/lib/shopify-cli/oauth.rb +25 -25
  151. data/lib/shopify-cli/oauth/servlet.rb +9 -9
  152. data/lib/shopify-cli/options.rb +3 -3
  153. data/lib/shopify-cli/packager.rb +24 -24
  154. data/lib/shopify-cli/partners_api.rb +16 -16
  155. data/lib/shopify-cli/partners_api/organizations.rb +10 -10
  156. data/lib/shopify-cli/process_supervision.rb +7 -7
  157. data/lib/shopify-cli/project.rb +16 -16
  158. data/lib/shopify-cli/project_type.rb +3 -3
  159. data/lib/shopify-cli/resources.rb +1 -1
  160. data/lib/shopify-cli/resources/env_file.rb +9 -9
  161. data/lib/shopify-cli/result.rb +8 -8
  162. data/lib/shopify-cli/shopifolk.rb +6 -9
  163. data/lib/shopify-cli/sub_command.rb +1 -1
  164. data/lib/shopify-cli/task.rb +3 -3
  165. data/lib/shopify-cli/tasks.rb +7 -7
  166. data/lib/shopify-cli/tasks/create_api_client.rb +5 -5
  167. data/lib/shopify-cli/tasks/ensure_dev_store.rb +11 -11
  168. data/lib/shopify-cli/tasks/ensure_env.rb +15 -15
  169. data/lib/shopify-cli/tasks/ensure_loopback_url.rb +4 -4
  170. data/lib/shopify-cli/tasks/select_org_and_shop.rb +19 -19
  171. data/lib/shopify-cli/tasks/update_dashboard_urls.rb +10 -10
  172. data/lib/shopify-cli/transform_data_structure.rb +86 -0
  173. data/lib/shopify-cli/tunnel.rb +30 -30
  174. data/lib/shopify-cli/version.rb +1 -1
  175. data/lib/shopify_cli.rb +56 -54
  176. data/shopify-cli.gemspec +6 -6
  177. data/vendor/gen/template/bin/update-deps +9 -9
  178. metadata +9 -4
  179. data/lib/project_types/extension/forms/register.rb +0 -47
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require 'shopify_cli'
2
+ require "shopify_cli"
3
3
 
4
4
  module ShopifyCli
5
5
  class SubCommand < Command
@@ -1,4 +1,4 @@
1
- require 'shopify_cli'
1
+ require "shopify_cli"
2
2
 
3
3
  module ShopifyCli
4
4
  class Task
@@ -10,8 +10,8 @@ module ShopifyCli
10
10
  private
11
11
 
12
12
  def wants_to_run_against_shopify_org?
13
- @ctx.puts(@ctx.message('core.tasks.select_org_and_shop.identified_as_shopify'))
14
- message = @ctx.message('core.tasks.select_org_and_shop.first_party')
13
+ @ctx.puts(@ctx.message("core.tasks.select_org_and_shop.identified_as_shopify"))
14
+ message = @ctx.message("core.tasks.select_org_and_shop.first_party")
15
15
  CLI::UI::Prompt.confirm(message, default: false)
16
16
  end
17
17
  end
@@ -1,4 +1,4 @@
1
- require 'shopify_cli'
1
+ require "shopify_cli"
2
2
 
3
3
  module ShopifyCli
4
4
  module Tasks
@@ -30,11 +30,11 @@ module ShopifyCli
30
30
  Registry.add(-> () { const_get(task) }, name)
31
31
  end
32
32
 
33
- register :CreateApiClient, :create_api_client, 'shopify-cli/tasks/create_api_client'
34
- register :EnsureEnv, :ensure_env, 'shopify-cli/tasks/ensure_env'
35
- register :EnsureLoopbackURL, :ensure_loopback_url, 'shopify-cli/tasks/ensure_loopback_url'
36
- register :EnsureDevStore, :ensure_dev_store, 'shopify-cli/tasks/ensure_dev_store'
37
- register :SelectOrgAndShop, :select_org_and_shop, 'shopify-cli/tasks/select_org_and_shop'
38
- register :UpdateDashboardURLS, :update_dashboard_urls, 'shopify-cli/tasks/update_dashboard_urls'
33
+ register :CreateApiClient, :create_api_client, "shopify-cli/tasks/create_api_client"
34
+ register :EnsureEnv, :ensure_env, "shopify-cli/tasks/ensure_env"
35
+ register :EnsureLoopbackURL, :ensure_loopback_url, "shopify-cli/tasks/ensure_loopback_url"
36
+ register :EnsureDevStore, :ensure_dev_store, "shopify-cli/tasks/ensure_dev_store"
37
+ register :SelectOrgAndShop, :select_org_and_shop, "shopify-cli/tasks/select_org_and_shop"
38
+ register :UpdateDashboardURLS, :update_dashboard_urls, "shopify-cli/tasks/update_dashboard_urls"
39
39
  end
40
40
  end
@@ -1,15 +1,15 @@
1
- require 'shopify_cli'
1
+ require "shopify_cli"
2
2
 
3
3
  module ShopifyCli
4
4
  module Tasks
5
5
  class CreateApiClient < ShopifyCli::Task
6
6
  VALID_APP_TYPES = %w(public custom)
7
- DEFAULT_APP_URL = 'https://shopify.github.io/shopify-app-cli/help/start-app/'
7
+ DEFAULT_APP_URL = "https://shopify.github.io/shopify-app-cli/help/start-app/"
8
8
 
9
9
  def call(ctx, org_id:, title:, type:)
10
10
  resp = ShopifyCli::PartnersAPI.query(
11
11
  ctx,
12
- 'create_app',
12
+ "create_app",
13
13
  org: org_id.to_i,
14
14
  title: title,
15
15
  type: type,
@@ -23,12 +23,12 @@ module ShopifyCli
23
23
 
24
24
  errors = resp.dig("errors")
25
25
  if !errors.nil? && errors.any?
26
- ctx.abort(errors.map { |err| "#{err['field']} #{err['message']}" }.join(", "))
26
+ ctx.abort(errors.map { |err| "#{err["field"]} #{err["message"]}" }.join(", "))
27
27
  end
28
28
 
29
29
  user_errors = resp.dig("data", "appCreate", "userErrors")
30
30
  if !user_errors.nil? && user_errors.any?
31
- ctx.abort(user_errors.map { |err| "#{err['field']} #{err['message']}" }.join(", "))
31
+ ctx.abort(user_errors.map { |err| "#{err["field"]} #{err["message"]}" }.join(", "))
32
32
  end
33
33
 
34
34
  ShopifyCli::Core::Monorail.metadata[:api_key] = resp.dig("data", "appCreate", "app", "apiKey")
@@ -1,4 +1,4 @@
1
- require 'shopify_cli'
1
+ require "shopify_cli"
2
2
 
3
3
  module ShopifyCli
4
4
  module Tasks
@@ -6,17 +6,17 @@ module ShopifyCli
6
6
  def call(ctx)
7
7
  @ctx = ctx
8
8
  return ctx.puts(ctx.message(
9
- 'core.tasks.ensure_dev_store.could_not_verify_store', project.env.shop
9
+ "core.tasks.ensure_dev_store.could_not_verify_store", project.env.shop
10
10
  )) if shop.nil?
11
- return if shop['transferDisabled'] == true
11
+ return if shop["transferDisabled"] == true
12
12
  return unless CLI::UI::Prompt.confirm(
13
- ctx.message('core.tasks.ensure_dev_store.convert_to_dev_store', project.env.shop)
13
+ ctx.message("core.tasks.ensure_dev_store.convert_to_dev_store", project.env.shop)
14
14
  )
15
- ShopifyCli::PartnersAPI.query(ctx, 'convert_dev_to_test_store', input: {
16
- organizationID: shop['orgID'].to_i,
17
- shopId: shop['shopId'],
15
+ ShopifyCli::PartnersAPI.query(ctx, "convert_dev_to_test_store", input: {
16
+ organizationID: shop["orgID"].to_i,
17
+ shopId: shop["shopId"],
18
18
  })
19
- ctx.puts(ctx.message('core.tasks.ensure_dev_store.transfer_disabled', project.env.shop))
19
+ ctx.puts(ctx.message("core.tasks.ensure_dev_store.transfer_disabled", project.env.shop))
20
20
  end
21
21
 
22
22
  private
@@ -29,9 +29,9 @@ module ShopifyCli
29
29
  @shop ||= begin
30
30
  current_domain = project.env.shop
31
31
  ShopifyCli::PartnersAPI::Organizations.fetch_all(@ctx).map do |org|
32
- org['stores'].find do |store|
33
- store['orgID'] = org['id']
34
- store['shopDomain'] == current_domain
32
+ org["stores"].find do |store|
33
+ store["orgID"] = org["id"]
34
+ store["shopDomain"] == current_domain
35
35
  end
36
36
  end.compact.first
37
37
  end
@@ -1,4 +1,4 @@
1
- require 'shopify_cli'
1
+ require "shopify_cli"
2
2
 
3
3
  module ShopifyCli
4
4
  module Tasks
@@ -29,10 +29,10 @@ module ShopifyCli
29
29
  org_id = if orgs.count == 1
30
30
  orgs.first["id"]
31
31
  else
32
- CLI::UI::Prompt.ask(@ctx.message('core.tasks.ensure_env.organization_select')) do |handler|
32
+ CLI::UI::Prompt.ask(@ctx.message("core.tasks.ensure_env.organization_select")) do |handler|
33
33
  orgs.each do |org|
34
34
  handler.option(
35
- @ctx.message('core.partners_api.org_name_and_id', org['businessName'], org['id'])
35
+ @ctx.message("core.partners_api.org_name_and_id", org["businessName"], org["id"])
36
36
  ) { org["id"] }
37
37
  end
38
38
  end
@@ -44,15 +44,15 @@ module ShopifyCli
44
44
  if apps.count == 1
45
45
  apps.first
46
46
  elsif apps.count == 0
47
- @ctx.puts(@ctx.message('core.tasks.ensure_env.no_apps'))
48
- title = CLI::UI::Prompt.ask(@ctx.message('core.tasks.ensure_env.app_name'))
49
- type = CLI::UI::Prompt.ask(@ctx.message('core.tasks.ensure_env.app_type.select')) do |handler|
50
- handler.option(@ctx.message('core.tasks.ensure_env.app_type.select_public')) { 'public' }
51
- handler.option(@ctx.message('core.tasks.ensure_env.app_type.select_custom')) { 'custom' }
47
+ @ctx.puts(@ctx.message("core.tasks.ensure_env.no_apps"))
48
+ title = CLI::UI::Prompt.ask(@ctx.message("core.tasks.ensure_env.app_name"))
49
+ type = CLI::UI::Prompt.ask(@ctx.message("core.tasks.ensure_env.app_type.select")) do |handler|
50
+ handler.option(@ctx.message("core.tasks.ensure_env.app_type.select_public")) { "public" }
51
+ handler.option(@ctx.message("core.tasks.ensure_env.app_type.select_custom")) { "custom" }
52
52
  end
53
53
  ShopifyCli::Tasks::CreateApiClient.call(@ctx, org_id: org_id, title: title, type: type)
54
54
  else
55
- CLI::UI::Prompt.ask(@ctx.message('core.tasks.ensure_env.app_select')) do |handler|
55
+ CLI::UI::Prompt.ask(@ctx.message("core.tasks.ensure_env.app_select")) do |handler|
56
56
  apps.each { |app| handler.option(app["title"]) { app } }
57
57
  end
58
58
  end
@@ -62,9 +62,9 @@ module ShopifyCli
62
62
  if shops.count == 1
63
63
  shop = shops.first["shopDomain"]
64
64
  elsif shops.count == 0
65
- @ctx.puts(@ctx.message('core.tasks.ensure_env.no_development_stores', id))
65
+ @ctx.puts(@ctx.message("core.tasks.ensure_env.no_development_stores", id))
66
66
  else
67
- shop = CLI::UI::Prompt.ask(@ctx.message('core.tasks.ensure_env.development_store_select')) do |handler|
67
+ shop = CLI::UI::Prompt.ask(@ctx.message("core.tasks.ensure_env.development_store_select")) do |handler|
68
68
  shops.each { |s| handler.option(s["shopName"]) { s["shopDomain"] } }
69
69
  end
70
70
  end
@@ -72,13 +72,13 @@ module ShopifyCli
72
72
  end
73
73
 
74
74
  def write_env(env_data, org)
75
- id = org['id']
76
- app = get_app(id, org['apps'])
75
+ id = org["id"]
76
+ app = get_app(id, org["apps"])
77
77
 
78
- env_data[:shop] = get_shop(org['stores'], id)
78
+ env_data[:shop] = get_shop(org["stores"], id)
79
79
  env_data[:api_key] = app["apiKey"]
80
80
  env_data[:secret] = app["apiSecretKeys"].first["secret"]
81
- env_data[:scopes] = 'write_products,write_customers,write_draft_orders' if env_data[:scopes].nil?
81
+ env_data[:scopes] = "write_products,write_customers,write_draft_orders" if env_data[:scopes].nil?
82
82
  env_data[:extra] = {} if env_data[:extra].nil?
83
83
 
84
84
  Resources::EnvFile.new(
@@ -4,13 +4,13 @@ module ShopifyCli
4
4
  def call(ctx)
5
5
  @ctx = ctx
6
6
  api_key = Project.current.env.api_key
7
- result = ShopifyCli::PartnersAPI.query(ctx, 'get_app_urls', apiKey: api_key)
7
+ result = ShopifyCli::PartnersAPI.query(ctx, "get_app_urls", apiKey: api_key)
8
8
  loopback = OAuth::REDIRECT_HOST
9
- app = result['data']['app']
10
- urls = app['redirectUrlWhitelist']
9
+ app = result["data"]["app"]
10
+ urls = app["redirectUrlWhitelist"]
11
11
  if urls.grep(/#{loopback}/).empty?
12
12
  with_loopback = urls.push(loopback)
13
- ShopifyCli::PartnersAPI.query(@ctx, 'update_dashboard_urls', input: {
13
+ ShopifyCli::PartnersAPI.query(@ctx, "update_dashboard_urls", input: {
14
14
  redirectUrlWhitelist: with_loopback, apiKey: api_key
15
15
  })
16
16
  end
@@ -1,4 +1,4 @@
1
- require 'shopify_cli'
1
+ require "shopify_cli"
2
2
 
3
3
  module ShopifyCli
4
4
  module Tasks
@@ -35,45 +35,45 @@ 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))
39
- ctx.abort(ctx.message('core.tasks.select_org_and_shop.error.organization_not_found'))
38
+ ctx.puts(ctx.message("core.tasks.select_org_and_shop.error.authentication_issue", ShopifyCli::TOOL_NAME))
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
+ 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"))
46
46
  elsif organizations.count == 1
47
47
  org = organizations.first
48
- ctx.puts(ctx.message('core.tasks.select_org_and_shop.organization', org['businessName'], org['id']))
48
+ ctx.puts(ctx.message("core.tasks.select_org_and_shop.organization", org["businessName"], org["id"]))
49
49
  org
50
50
  else
51
- org_id = CLI::UI::Prompt.ask(ctx.message('core.tasks.select_org_and_shop.organization_select')) do |handler|
51
+ org_id = CLI::UI::Prompt.ask(ctx.message("core.tasks.select_org_and_shop.organization_select")) do |handler|
52
52
  organizations.each do |o|
53
- handler.option(ctx.message('core.partners_api.org_name_and_id', o['businessName'], o['id'])) { o['id'] }
53
+ handler.option(ctx.message("core.partners_api.org_name_and_id", o["businessName"], o["id"])) { o["id"] }
54
54
  end
55
55
  end
56
- organizations.find { |o| o['id'] == org_id }
56
+ organizations.find { |o| o["id"] == org_id }
57
57
  end
58
58
  end
59
59
 
60
60
  def get_shop_domain(organization)
61
- valid_stores = organization['stores'].select do |store|
62
- store['transferDisabled'] == true || store['convertableToPartnerTest'] == true
61
+ valid_stores = organization["stores"].select do |store|
62
+ store["transferDisabled"] == true || store["convertableToPartnerTest"] == true
63
63
  end
64
64
 
65
65
  if valid_stores.count == 0
66
- ctx.puts(ctx.message('core.tasks.select_org_and_shop.error.no_development_stores'))
67
- ctx.puts(ctx.message('core.tasks.select_org_and_shop.create_store', organization['id']))
68
- ctx.puts(ctx.message('core.tasks.select_org_and_shop.authentication_issue', ShopifyCli::TOOL_NAME))
66
+ ctx.puts(ctx.message("core.tasks.select_org_and_shop.error.no_development_stores"))
67
+ ctx.puts(ctx.message("core.tasks.select_org_and_shop.create_store", organization["id"]))
68
+ ctx.puts(ctx.message("core.tasks.select_org_and_shop.authentication_issue", ShopifyCli::TOOL_NAME))
69
69
  elsif valid_stores.count == 1
70
- domain = valid_stores.first['shopDomain']
71
- ctx.puts(ctx.message('core.tasks.select_org_and_shop.development_store', domain))
70
+ domain = valid_stores.first["shopDomain"]
71
+ ctx.puts(ctx.message("core.tasks.select_org_and_shop.development_store", domain))
72
72
  domain
73
73
  else
74
74
  CLI::UI::Prompt.ask(
75
- ctx.message('core.tasks.select_org_and_shop.development_store_select'),
76
- options: valid_stores.map { |s| s['shopDomain'] }
75
+ ctx.message("core.tasks.select_org_and_shop.development_store_select"),
76
+ options: valid_stores.map { |s| s["shopDomain"] }
77
77
  )
78
78
  end
79
79
  end
@@ -7,24 +7,24 @@ module ShopifyCli
7
7
  @ctx = ctx
8
8
  project = ShopifyCli::Project.current
9
9
  api_key = project.env.api_key
10
- result = ShopifyCli::PartnersAPI.query(ctx, 'get_app_urls', apiKey: api_key)
11
- app = result['data']['app']
12
- consent = check_application_url(app['applicationUrl'], url)
13
- constructed_urls = construct_redirect_urls(app['redirectUrlWhitelist'], url, callback_url)
14
- return if url == app['applicationUrl']
15
- ShopifyCli::PartnersAPI.query(@ctx, 'update_dashboard_urls', input: {
16
- applicationUrl: consent ? url : app['applicationUrl'],
10
+ result = ShopifyCli::PartnersAPI.query(ctx, "get_app_urls", apiKey: api_key)
11
+ app = result["data"]["app"]
12
+ consent = check_application_url(app["applicationUrl"], url)
13
+ constructed_urls = construct_redirect_urls(app["redirectUrlWhitelist"], url, callback_url)
14
+ return if url == app["applicationUrl"]
15
+ ShopifyCli::PartnersAPI.query(@ctx, "update_dashboard_urls", input: {
16
+ applicationUrl: consent ? url : app["applicationUrl"],
17
17
  redirectUrlWhitelist: constructed_urls, apiKey: api_key
18
18
  })
19
- @ctx.puts(@ctx.message('core.tasks.update_dashboard_urls.updated'))
19
+ @ctx.puts(@ctx.message("core.tasks.update_dashboard_urls.updated"))
20
20
  rescue
21
- @ctx.puts(@ctx.message('core.tasks.update_dashboard_urls.update_error', ShopifyCli::TOOL_NAME))
21
+ @ctx.puts(@ctx.message("core.tasks.update_dashboard_urls.update_error", ShopifyCli::TOOL_NAME))
22
22
  raise
23
23
  end
24
24
 
25
25
  def check_application_url(application_url, new_url)
26
26
  return false if application_url.match(new_url)
27
- CLI::UI::Prompt.confirm(@ctx.message('core.tasks.update_dashboard_urls.update_prompt'))
27
+ CLI::UI::Prompt.confirm(@ctx.message("core.tasks.update_dashboard_urls.update_prompt"))
28
28
  end
29
29
 
30
30
  def construct_redirect_urls(urls, new_url, callback_url)
@@ -0,0 +1,86 @@
1
+
2
+ module ShopifyCli
3
+ ##
4
+ # `TransformDataStructure` helps to standardize data structure access. It
5
+ # traverses nested data structures and can convert
6
+ #
7
+ # * all strings used as keys to symbols,
8
+ # * all strings used as keys from `CamelCase` to `snake_case` and
9
+ # * associative array containers, e.g. from Hash to OpenStruct.
10
+ #
11
+ # Standardizing how a data structure is accessed greatly reduces the risk
12
+ # of subtle bugs especially when dealing with API responses.
13
+ #
14
+ # TransformDataStructure.new(
15
+ # symbolize_keys: true,
16
+ # underscore_keys: true,
17
+ # associative_array_container: OpenStruct
18
+ # ).call([{"SomeKey" => "value"}]).tap do |result|
19
+ # result.value # => [#<OpenStruct: some_key: "value">]
20
+ # end
21
+ #
22
+ # Since `TransformDataStructure` is a method object, it can easily be chained:
23
+ #
24
+ # require 'open-uri'
25
+ # ShopifyCli::Result
26
+ # .call { open("https://jsonplaceholder.typicode.com/todos/1") }
27
+ # .map(&TransformDataStructure.new(symbolize_keys: true, underscore_keys: true))
28
+ # .value # => { id: 1, user_id: 1, ... }
29
+ #
30
+ class TransformDataStructure
31
+ include ShopifyCli::MethodObject
32
+
33
+ class << self
34
+ private
35
+
36
+ def valid_associative_array_container(klass)
37
+ klass.respond_to?(:new) && klass.method_defined?(:[]=)
38
+ end
39
+ end
40
+
41
+ property! :underscore_keys, accepts: [true, false], default: false, reader: :underscore_keys?
42
+ property! :symbolize_keys, accepts: [true, false], default: false, reader: :symbolize_keys?
43
+ property! :associative_array_container,
44
+ accepts: ->(c) { c.respond_to?(:new) && c.method_defined?(:[]=) },
45
+ default: Hash
46
+
47
+ def call(object)
48
+ case object
49
+ when Array
50
+ object.map(&self).map(&:value)
51
+ when Hash
52
+ object.each.with_object(associative_array_container.new) do |(key, value), result|
53
+ result[transform_key(key)] = call(value).value
54
+ end
55
+ else
56
+ ShopifyCli::Result.success(object)
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def transform_key(key)
63
+ key
64
+ .yield_self(&method(:underscore_key))
65
+ .yield_self(&method(:symbolize_key))
66
+ end
67
+
68
+ def underscore_key(key)
69
+ return key unless underscore_keys? && key.respond_to?(:to_str)
70
+
71
+ key.to_str.dup.yield_self do |k|
72
+ k.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
73
+ k.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
74
+ k.tr!("-", "_")
75
+ k.gsub!(/\s/, "_")
76
+ k.gsub!(/__+/, "_")
77
+ k.downcase!
78
+ end
79
+ end
80
+
81
+ def symbolize_key(key)
82
+ return key unless symbolize_keys? && key.respond_to?(:to_sym)
83
+ key.to_sym
84
+ end
85
+ end
86
+ end
@@ -1,7 +1,7 @@
1
- require 'json'
2
- require 'fileutils'
3
- require 'shopify_cli'
4
- require 'forwardable'
1
+ require "json"
2
+ require "fileutils"
3
+ require "shopify_cli"
4
+ require "forwardable"
5
5
 
6
6
  module ShopifyCli
7
7
  ##
@@ -19,14 +19,14 @@ module ShopifyCli
19
19
  PORT = 8081 # port that ngrok will bind to
20
20
  # mapping for supported operating systems for where to download ngrok from.
21
21
  DOWNLOAD_URLS = {
22
- mac: 'https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-darwin-amd64.zip',
23
- linux: 'https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip',
24
- windows: 'https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-windows-amd64.zip',
22
+ mac: "https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-darwin-amd64.zip",
23
+ linux: "https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip",
24
+ windows: "https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-windows-amd64.zip",
25
25
  }
26
26
 
27
- NGROK_TUNNELS_URI = URI.parse('http://localhost:4040/api/tunnels')
28
- TUNNELS_FIELD = 'tunnels'
29
- PUBLIC_URL_FIELD = 'public_url'
27
+ NGROK_TUNNELS_URI = URI.parse("http://localhost:4040/api/tunnels")
28
+ TUNNELS_FIELD = "tunnels"
29
+ PUBLIC_URL_FIELD = "public_url"
30
30
 
31
31
  ##
32
32
  # will find and stop a running tunnel process. It will also output if the
@@ -39,12 +39,12 @@ module ShopifyCli
39
39
  def stop(ctx)
40
40
  if ShopifyCli::ProcessSupervision.running?(:ngrok)
41
41
  if ShopifyCli::ProcessSupervision.stop(:ngrok)
42
- ctx.puts(ctx.message('core.tunnel.stopped'))
42
+ ctx.puts(ctx.message("core.tunnel.stopped"))
43
43
  else
44
- ctx.abort(ctx.message('core.tunnel.error.stop'))
44
+ ctx.abort(ctx.message("core.tunnel.error.stop"))
45
45
  end
46
46
  else
47
- ctx.puts(ctx.message('core.tunnel.not_running'))
47
+ ctx.puts(ctx.message("core.tunnel.not_running"))
48
48
  end
49
49
  end
50
50
 
@@ -65,15 +65,15 @@ module ShopifyCli
65
65
  install(ctx)
66
66
  url, account, seconds_remaining = start_ngrok(ctx, port)
67
67
  if account
68
- ctx.puts(ctx.message('core.tunnel.start_with_account', url, account))
68
+ ctx.puts(ctx.message("core.tunnel.start_with_account", url, account))
69
69
  else
70
70
  if seconds_remaining <= 0
71
- ctx.puts(ctx.message('core.tunnel.timed_out'))
71
+ ctx.puts(ctx.message("core.tunnel.timed_out"))
72
72
  url, _account, seconds_remaining = restart_ngrok(ctx, port)
73
73
  end
74
- ctx.puts(ctx.message('core.tunnel.start', url))
75
- ctx.puts(ctx.message('core.tunnel.will_timeout', seconds_to_hm(seconds_remaining)))
76
- ctx.puts(ctx.message('core.tunnel.signup_suggestion', ShopifyCli::TOOL_NAME))
74
+ ctx.puts(ctx.message("core.tunnel.start", url))
75
+ ctx.puts(ctx.message("core.tunnel.will_timeout", seconds_to_hm(seconds_remaining)))
76
+ ctx.puts(ctx.message("core.tunnel.signup_suggestion", ShopifyCli::TOOL_NAME))
77
77
  end
78
78
  url
79
79
  end
@@ -89,7 +89,7 @@ module ShopifyCli
89
89
  #
90
90
  def auth(ctx, token)
91
91
  install(ctx)
92
- ctx.system(File.join(ShopifyCli.cache_dir, 'ngrok'), 'authtoken', token)
92
+ ctx.system(File.join(ShopifyCli.cache_dir, "ngrok"), "authtoken", token)
93
93
  end
94
94
 
95
95
  ##
@@ -125,13 +125,13 @@ module ShopifyCli
125
125
  def install(ctx)
126
126
  ngrok = "ngrok#{ctx.executable_file_extension}"
127
127
  return if File.exist?(File.join(ShopifyCli.cache_dir, ngrok))
128
- check_prereq_command(ctx, 'curl')
129
- check_prereq_command(ctx, ctx.linux? ? 'unzip' : 'tar')
128
+ check_prereq_command(ctx, "curl")
129
+ check_prereq_command(ctx, ctx.linux? ? "unzip" : "tar")
130
130
  spinner = CLI::UI::SpinGroup.new
131
- spinner.add('Installing ngrok...') do
132
- zip_dest = File.join(ShopifyCli.cache_dir, 'ngrok.zip')
131
+ spinner.add("Installing ngrok...") do
132
+ zip_dest = File.join(ShopifyCli.cache_dir, "ngrok.zip")
133
133
  unless File.exist?(zip_dest)
134
- ctx.system('curl', '-o', zip_dest, DOWNLOAD_URLS[ctx.os], chdir: ShopifyCli.cache_dir)
134
+ ctx.system("curl", "-o", zip_dest, DOWNLOAD_URLS[ctx.os], chdir: ShopifyCli.cache_dir)
135
135
  end
136
136
  args = if ctx.linux?
137
137
  %W(unzip -u #{zip_dest})
@@ -145,7 +145,7 @@ module ShopifyCli
145
145
 
146
146
  # final check to see if ngrok is accessible
147
147
  unless File.exist?(File.join(ShopifyCli.cache_dir, ngrok))
148
- ctx.abort(ctx.message('core.tunnel.error.ngrok', ngrok, ShopifyCli.cache_dir))
148
+ ctx.abort(ctx.message("core.tunnel.error.ngrok", ngrok, ShopifyCli.cache_dir))
149
149
  end
150
150
  end
151
151
 
@@ -157,7 +157,7 @@ module ShopifyCli
157
157
  end
158
158
 
159
159
  def ngrok_command(port)
160
- "\"#{File.join(ShopifyCli.cache_dir, 'ngrok')}\" http -inspect=false -log=stdout -log-level=debug #{port}"
160
+ "\"#{File.join(ShopifyCli.cache_dir, "ngrok")}\" http -inspect=false -log=stdout -log-level=debug #{port}"
161
161
  end
162
162
 
163
163
  def seconds_to_hm(seconds)
@@ -173,15 +173,15 @@ module ShopifyCli
173
173
 
174
174
  def restart_ngrok(ctx, port)
175
175
  unless ShopifyCli::ProcessSupervision.stop(:ngrok)
176
- ctx.abort(ctx.message('core.tunnel.error.stop'))
176
+ ctx.abort(ctx.message("core.tunnel.error.stop"))
177
177
  end
178
178
  start_ngrok(ctx, port)
179
179
  end
180
180
 
181
181
  def check_prereq_command(ctx, command)
182
182
  cmd_path = ctx.which(command)
183
- ctx.abort(ctx.message('core.tunnel.error.prereq_command_required', command)) if cmd_path.nil?
184
- ctx.done(ctx.message('core.tunnel.prereq_command_location', command, cmd_path))
183
+ ctx.abort(ctx.message("core.tunnel.error.prereq_command_required", command)) if cmd_path.nil?
184
+ ctx.done(ctx.message("core.tunnel.prereq_command_location", command, cmd_path))
185
185
  end
186
186
 
187
187
  class LogParser # :nodoc:
@@ -199,7 +199,7 @@ module ShopifyCli
199
199
  sleep(1)
200
200
  end
201
201
 
202
- raise FetchUrlError, Context.message('core.tunnel.error.url_fetch_failure') unless url
202
+ raise FetchUrlError, Context.message("core.tunnel.error.url_fetch_failure") unless url
203
203
  end
204
204
 
205
205
  def parse