shopify-cli 1.6.0 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
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