shopify-cli 0.9.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +3 -0
  3. data/CHANGELOG.md +24 -2
  4. data/RELEASING.md +4 -4
  5. data/docs/_config.yml +3 -0
  6. data/docs/_data/nav.yml +9 -0
  7. data/docs/getting-started/index.md +5 -40
  8. data/docs/getting-started/install/index.md +75 -0
  9. data/docs/getting-started/migrate/index.md +96 -0
  10. data/docs/getting-started/uninstall/index.md +37 -0
  11. data/docs/getting-started/upgrade/index.md +37 -0
  12. data/docs/index.md +5 -6
  13. data/lib/project_types/extension/cli.rb +2 -1
  14. data/lib/project_types/extension/commands/tunnel.rb +1 -1
  15. data/lib/project_types/extension/forms/register.rb +2 -3
  16. data/lib/project_types/extension/graphql/get_app_by_api_key.graphql +9 -0
  17. data/lib/project_types/extension/tasks/converters/app_converter.rb +27 -0
  18. data/lib/project_types/extension/tasks/get_app.rb +22 -0
  19. data/lib/project_types/extension/tasks/get_apps.rb +1 -6
  20. data/lib/project_types/node/forms/create.rb +3 -54
  21. data/lib/project_types/node/messages/messages.rb +3 -14
  22. data/lib/project_types/rails/forms/create.rb +3 -52
  23. data/lib/project_types/rails/messages/messages.rb +2 -13
  24. data/lib/project_types/script/cli.rb +5 -5
  25. data/lib/project_types/script/commands/create.rb +5 -4
  26. data/lib/project_types/script/commands/push.rb +1 -0
  27. data/lib/project_types/script/config/extension_points.yml +3 -3
  28. data/lib/project_types/script/errors.rb +1 -0
  29. data/lib/project_types/script/forms/create.rb +8 -4
  30. data/lib/project_types/script/layers/application/build_script.rb +7 -10
  31. data/lib/project_types/script/layers/application/create_script.rb +16 -14
  32. data/lib/project_types/script/layers/application/project_dependencies.rb +3 -9
  33. data/lib/project_types/script/layers/application/push_script.rb +13 -11
  34. data/lib/project_types/script/layers/infrastructure/assemblyscript_project_creator.rb +106 -0
  35. data/lib/project_types/script/layers/infrastructure/assemblyscript_task_runner.rb +64 -0
  36. data/lib/project_types/script/layers/infrastructure/errors.rb +2 -2
  37. data/lib/project_types/script/layers/infrastructure/project_creator.rb +23 -0
  38. data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +6 -3
  39. data/lib/project_types/script/layers/infrastructure/script_repository.rb +8 -38
  40. data/lib/project_types/script/layers/infrastructure/task_runner.rb +18 -0
  41. data/lib/project_types/script/messages/messages.rb +5 -6
  42. data/lib/project_types/script/script_project.rb +22 -9
  43. data/lib/project_types/script/templates/ts/as-pect.d.ts +1 -0
  44. data/lib/project_types/script/ui/error_handler.rb +5 -0
  45. data/lib/shopify-cli/admin_api.rb +1 -2
  46. data/lib/shopify-cli/admin_api/populate_resource_command.rb +10 -1
  47. data/lib/shopify-cli/admin_api/schema.rb +11 -1
  48. data/lib/shopify-cli/api.rb +2 -0
  49. data/lib/shopify-cli/context.rb +60 -0
  50. data/lib/shopify-cli/core/entry_point.rb +6 -0
  51. data/lib/shopify-cli/core/finalize.rb +13 -0
  52. data/lib/shopify-cli/git.rb +14 -10
  53. data/lib/shopify-cli/messages/messages.rb +22 -2
  54. data/lib/shopify-cli/tasks.rb +1 -0
  55. data/lib/shopify-cli/tasks/select_org_and_shop.rb +77 -0
  56. data/lib/shopify-cli/tunnel.rb +33 -1
  57. data/lib/shopify-cli/version.rb +1 -1
  58. data/vendor/deps/cli-ui/REVISION +1 -1
  59. data/vendor/deps/cli-ui/lib/cli/ui.rb +52 -11
  60. data/vendor/deps/cli-ui/lib/cli/ui/color.rb +11 -7
  61. data/vendor/deps/cli-ui/lib/cli/ui/formatter.rb +34 -21
  62. data/vendor/deps/cli-ui/lib/cli/ui/frame.rb +107 -149
  63. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_stack.rb +99 -0
  64. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style.rb +119 -0
  65. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/box.rb +158 -0
  66. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/bracket.rb +112 -0
  67. data/vendor/deps/cli-ui/lib/cli/ui/glyph.rb +9 -15
  68. data/vendor/deps/cli-ui/lib/cli/ui/printer.rb +47 -0
  69. data/vendor/deps/cli-ui/lib/cli/ui/progress.rb +9 -7
  70. data/vendor/deps/cli-ui/lib/cli/ui/prompt.rb +39 -14
  71. data/vendor/deps/cli-ui/lib/cli/ui/prompt/interactive_options.rb +62 -44
  72. data/vendor/deps/cli-ui/lib/cli/ui/prompt/options_handler.rb +7 -2
  73. data/vendor/deps/cli-ui/lib/cli/ui/spinner.rb +23 -3
  74. data/vendor/deps/cli-ui/lib/cli/ui/spinner/spin_group.rb +34 -10
  75. data/vendor/deps/cli-ui/lib/cli/ui/stdout_router.rb +12 -7
  76. data/vendor/deps/cli-ui/lib/cli/ui/terminal.rb +26 -16
  77. data/vendor/deps/cli-ui/lib/cli/ui/truncater.rb +3 -3
  78. data/vendor/deps/cli-ui/lib/cli/ui/widgets.rb +75 -0
  79. data/vendor/deps/cli-ui/lib/cli/ui/widgets/base.rb +27 -0
  80. data/vendor/deps/cli-ui/lib/cli/ui/widgets/status.rb +61 -0
  81. metadata +24 -9
  82. data/lib/project_types/extension/features/tunnel_url.rb +0 -20
  83. data/lib/project_types/script/layers/infrastructure/assemblyscript_dependency_manager.rb +0 -73
  84. data/lib/project_types/script/layers/infrastructure/assemblyscript_wasm_builder.rb +0 -39
  85. data/lib/project_types/script/layers/infrastructure/dependency_manager.rb +0 -36
  86. data/lib/project_types/script/layers/infrastructure/script_builder.rb +0 -34
  87. data/lib/project_types/script/layers/infrastructure/test_suite_repository.rb +0 -59
  88. data/vendor/deps/cli-ui/lib/cli/ui/box.rb +0 -15
@@ -18,8 +18,12 @@ module Script
18
18
  invalid_context_cause: "Your .shopify-cli.yml file is not correct.",
19
19
  invalid_context_help: "See https://help.shopify.com",
20
20
 
21
+ invalid_script_name_cause: "Invalid script name.",
22
+ invalid_script_name_help: "Replace or remove unsupported characters. Valid characters "\
23
+ "are numbers, letters, hyphens, or underscores.",
24
+
21
25
  no_existing_apps_cause: "You don't have any apps.",
22
- no_existing_apps_help: "Please create an app with {{command:shopify create}} or"\
26
+ no_existing_apps_help: "Please create an app with {{command:shopify create}} or "\
23
27
  "visit https://partners.shopify.com/.",
24
28
 
25
29
  no_existing_orgs_cause: "You don't have any partner organizations.",
@@ -169,11 +173,6 @@ module Script
169
173
  create: {
170
174
  select_extension_point: "Which extension point do you want to use?",
171
175
  script_name: "Script Name",
172
-
173
- error: {
174
- invalid_name: "Invalid script name: replace or remove unsupported characters. Valid "\
175
- "characters are numbers, letters, spaces, hyphens, or underscores.",
176
- },
177
176
  },
178
177
  script_form: {
179
178
  ask_app_api_key_default: "Which app do you want this script to belong to?",
@@ -3,14 +3,28 @@
3
3
  module Script
4
4
  class ScriptProject < ShopifyCli::Project
5
5
  SUPPORTED_LANGUAGES = %w(ts)
6
+ SOURCE_DIR = "src"
6
7
 
7
8
  attr_reader :extension_point_type, :script_name, :language
8
9
 
9
- def initialize(dir)
10
- super(dir)
10
+ def initialize(*args)
11
+ super
11
12
  @extension_point_type = lookup_config('extension_point_type')
12
13
  @script_name = lookup_config('script_name')
13
14
  @language = 'ts'
15
+ ShopifyCli::Core::Monorail.metadata = {
16
+ "script_name" => @script_name,
17
+ "extension_point_type" => @extension_point_type,
18
+ "language" => @language,
19
+ }
20
+ end
21
+
22
+ def source_file
23
+ "#{SOURCE_DIR}/#{file_name}"
24
+ end
25
+
26
+ def file_name
27
+ "script.#{language}"
14
28
  end
15
29
 
16
30
  private
@@ -21,16 +35,15 @@ module Script
21
35
  end
22
36
 
23
37
  class << self
24
- def create(dir)
25
- raise Errors::ScriptProjectAlreadyExistsError, dir if Dir.exist?(dir)
26
-
27
- FileUtils.mkdir_p(dir)
28
- Dir.chdir(dir)
38
+ def create(ctx, dir)
39
+ raise Errors::ScriptProjectAlreadyExistsError, dir if ctx.dir_exist?(dir)
40
+ ctx.mkdir_p(dir)
41
+ ctx.chdir(dir)
29
42
  end
30
43
 
31
44
  def cleanup(ctx:, script_name:, root_dir:)
32
- Dir.chdir(root_dir)
33
- ctx.rm_r("#{root_dir}/#{script_name}") if Dir.exist?("#{root_dir}/#{script_name}")
45
+ ctx.chdir(root_dir)
46
+ ctx.rm_r("#{root_dir}/#{script_name}") if ctx.dir_exist?("#{root_dir}/#{script_name}")
34
47
  end
35
48
  end
36
49
  end
@@ -0,0 +1 @@
1
+ /// <reference types="@as-pect/assembly/types/as-pect" />
@@ -44,6 +44,11 @@ module Script
44
44
  cause_of_error: ShopifyCli::Context.message('script.error.invalid_context_cause'),
45
45
  help_suggestion: ShopifyCli::Context.message('script.error.invalid_context_help'),
46
46
  }
47
+ when Errors::InvalidScriptNameError
48
+ {
49
+ cause_of_error: ShopifyCli::Context.message('script.error.invalid_script_name_cause'),
50
+ help_suggestion: ShopifyCli::Context.message('script.error.invalid_script_name_help'),
51
+ }
47
52
  when Errors::NoExistingAppsError
48
53
  {
49
54
  cause_of_error: ShopifyCli::Context.message('script.error.no_existing_apps_cause'),
@@ -37,8 +37,7 @@ module ShopifyCli
37
37
  #
38
38
  # ShopifyCli::AdminAPI.query(@ctx, 'all_organizations')
39
39
  #
40
- def query(ctx, query_name, api_version: nil, shop: nil, **variables)
41
- shop ||= Project.current.env.shop
40
+ def query(ctx, query_name, shop:, api_version: nil, **variables)
42
41
  authenticated_req(ctx, shop) do
43
42
  api_client(ctx, api_version, shop).query(query_name, variables: variables)
44
43
  end
@@ -41,6 +41,8 @@ module ShopifyCli
41
41
  return @ctx.puts(output)
42
42
  end
43
43
 
44
+ @shop ||= Project.current.env.shop || get_shop(@ctx)
45
+
44
46
  if @silent
45
47
  spin_group = CLI::UI::SpinGroup.new
46
48
  spin_group.add(@ctx.message('core.populate.populating', @count, camel_case_resource_type)) do |spinner|
@@ -114,7 +116,7 @@ module ShopifyCli
114
116
 
115
117
  def run_mutation(data)
116
118
  kwargs = { input: data }
117
- kwargs[:shop] = @shop if @shop
119
+ kwargs[:shop] = @shop
118
120
  resp = AdminAPI.query(
119
121
  @ctx, "create_#{snake_case_resource_type}", kwargs
120
122
  )
@@ -145,6 +147,13 @@ module ShopifyCli
145
147
 
146
148
  private
147
149
 
150
+ def get_shop(ctx)
151
+ res = ShopifyCli::Tasks::SelectOrgAndShop.call(ctx)
152
+ domain = res[:shop_domain]
153
+ Project.current.env.update(ctx, :shop, domain)
154
+ domain
155
+ end
156
+
148
157
  def camel_case_resource_type
149
158
  @camel_case_resource_type ||= self.class.to_s.split('::').last
150
159
  end
@@ -5,7 +5,8 @@ module ShopifyCli
5
5
  class Schema < Hash
6
6
  def self.get(ctx)
7
7
  unless ShopifyCli::DB.exists?(:shopify_admin_schema)
8
- schema = AdminAPI.query(ctx, 'admin_introspection')
8
+ shop = Project.current.env.shop || get_shop(@ctx)
9
+ schema = AdminAPI.query(ctx, 'admin_introspection', shop: shop)
9
10
  ShopifyCli::DB.set(shopify_admin_schema: JSON.dump(schema))
10
11
  end
11
12
  # This is ruby magic for making a new hash with another hash.
@@ -27,6 +28,15 @@ module ShopifyCli
27
28
  object["name"]
28
29
  end
29
30
  end
31
+
32
+ private
33
+
34
+ def get_shop(ctx)
35
+ res = ShopifyCli::Tasks::SelectOrgAndShop.call(ctx)
36
+ domain = res[:shop_domain]
37
+ Project.current.env.update(ctx, :shop, domain)
38
+ domain
39
+ end
30
40
  end
31
41
  end
32
42
  end
@@ -32,6 +32,8 @@ module ShopifyCli
32
32
  )
33
33
  ctx.debug(resp)
34
34
  resp
35
+ rescue API::APIRequestServerError, API::APIRequestUnexpectedError
36
+ ctx.puts(ctx.message('core.api.error.internal_server_error'))
35
37
  end
36
38
 
37
39
  protected
@@ -131,6 +131,56 @@ module ShopifyCli
131
131
  File.write(ctx_path(fname), content)
132
132
  end
133
133
 
134
+ # will change directories and update the root, the filepath is relative to the command root unless absolute
135
+ #
136
+ # #### Parameters
137
+ # * `path` - the file path to a directory, relative to the context root to remove from the FS
138
+ #
139
+ def chdir(path)
140
+ Dir.chdir(ctx_path(path))
141
+ self.root = ctx_path(path)
142
+ end
143
+
144
+ # checks if a directory exists, the filepath is relative to the command root unless absolute
145
+ #
146
+ # #### Parameters
147
+ # * `path` - the file path to a directory, relative to the context root to remove from the FS
148
+ #
149
+ def dir_exist?(path)
150
+ Dir.exist?(ctx_path(path))
151
+ end
152
+
153
+ # checks if a file exists, the filepath is relative to the command root unless absolute
154
+ #
155
+ # #### Parameters
156
+ # * `path` - the file path to a file, relative to the context root to remove from the FS
157
+ #
158
+ def file_exist?(path)
159
+ File.exist?(ctx_path(path))
160
+ end
161
+
162
+ # will recursively copy a directory from the FS, the filepath is relative to the command
163
+ # root unless absolute
164
+ #
165
+ # #### Parameters
166
+ # * `from` - the path of the original file
167
+ # * `to` - the destination path
168
+ #
169
+ def cp_r(from, to)
170
+ FileUtils.cp_r(ctx_path(from), ctx_path(to))
171
+ end
172
+
173
+ # will copy a directory from the FS, the filepath is relative to the command
174
+ # root unless absolute
175
+ #
176
+ # #### Parameters
177
+ # * `from` - the path of the original file
178
+ # * `to` - the destination path
179
+ #
180
+ def cp(from, to)
181
+ FileUtils.cp(ctx_path(from), ctx_path(to))
182
+ end
183
+
134
184
  # will rename a file from one place to another, relative to the command root
135
185
  # unless the path is absolute.
136
186
  #
@@ -162,6 +212,16 @@ module ShopifyCli
162
212
  FileUtils.rm_r(ctx_path(fname))
163
213
  end
164
214
 
215
+ # will force remove a directory from the FS, the filepath is relative to the command
216
+ # root unless absolute
217
+ #
218
+ # #### Parameters
219
+ # * `fname` - the file path to a directory, relative to the context root to remove from the FS
220
+ #
221
+ def rm_rf(fname)
222
+ FileUtils.rm_rf(ctx_path(fname))
223
+ end
224
+
165
225
  # will create a directory, recursively if it does not exist. So if you create
166
226
  # a directory `foo/bar/dun`, this will also create the directories `foo` and
167
227
  # `foo/bar` if they do not exist. The path will be made relative to the command
@@ -11,6 +11,12 @@ module ShopifyCli
11
11
  IO.open(9) { is_shell_shim = true }
12
12
  rescue Errno::EBADF
13
13
  # This is expected if the descriptor doesn't exist
14
+ rescue ArgumentError => e
15
+ # This can happen on RVM, because it can use fd 9 itself and block access to it. That only happens if the fd
16
+ # did not exist beforehand, so that means there was no fd 9 before Ruby started.
17
+ unless e.message == 'The given fd is not accessible because RubyVM reserves it'
18
+ raise e
19
+ end
14
20
  end
15
21
 
16
22
  if !ctx.testing? && is_shell_shim
@@ -0,0 +1,13 @@
1
+ module ShopifyCli
2
+ module Core
3
+ # This class is just a dummy to make sure that we don't trigger warnings on the first time the updated code runs.
4
+ # The old code would try to call the Finalizer after it is done updating, which would then trigger an autoload of
5
+ # this class and fail.
6
+ module Finalize
7
+ class << self
8
+ def deliver!
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -46,10 +46,10 @@ module ShopifyCli
46
46
  if Dir.exist?(dest)
47
47
  ctx.abort(ctx.message('core.git.error.directory_exists'))
48
48
  else
49
- CLI::UI::Frame.open(ctx.message('core.git.cloning', dest)) do
49
+ success_message = ctx.message('core.git.cloned', dest)
50
+ CLI::UI::Frame.open(ctx.message('core.git.cloning', repository, dest), success_text: success_message) do
50
51
  clone_progress('clone', '--single-branch', repository, dest, ctx: ctx)
51
52
  end
52
- ctx.done(ctx.message('core.git.cloned', dest))
53
53
  end
54
54
  end
55
55
 
@@ -121,19 +121,23 @@ module ShopifyCli
121
121
  def clone_progress(*git_command, ctx:)
122
122
  CLI::UI::Progress.progress do |bar|
123
123
  msg = []
124
- success = ctx.system('git', *git_command, '--progress') do |_out, err|
125
- if err.strip.start_with?('Receiving objects:')
126
- percent = (err.match(/Receiving objects:\s+(\d+)/)[1].to_f / 100).round(2)
124
+ require 'open3'
125
+
126
+ success = Open3.popen3('git', *git_command, '--progress') do |_stdin, _stdout, stderr, thread|
127
+ while (line = stderr.gets)
128
+ next unless line.strip.start_with?('Receiving objects:')
129
+ percent = (line.match(/Receiving objects:\s+(\d+)/)[1].to_f / 100).round(2)
127
130
  bar.tick(set_percent: percent)
128
131
  next
129
132
  end
130
- msg << err
133
+
134
+ msg << stderr
135
+ thread.value
131
136
  end.success?
132
- unless success
133
- ctx.abort(msg.join("\n"))
134
- end
137
+
138
+ ctx.abort(msg.join("\n")) unless success
135
139
  bar.tick(set_percent: 1.0)
136
- true
140
+ success
137
141
  end
138
142
  end
139
143
  end
@@ -60,8 +60,8 @@ module ShopifyCli
60
60
  no_commits_made: "No git commits have been made. Please make at least one commit.",
61
61
  },
62
62
 
63
- cloning: "Cloning into %s...",
64
- cloned: "Cloned into %s",
63
+ cloning: "Cloning %s into %s...",
64
+ cloned: "{{v}} Cloned into %s",
65
65
  },
66
66
 
67
67
  help: {
@@ -154,6 +154,12 @@ module ShopifyCli
154
154
  },
155
155
  },
156
156
 
157
+ api: {
158
+ error: {
159
+ internal_server_error: '{{red:{{x}} An unexpected error occurred on Shopify.}}',
160
+ },
161
+ },
162
+
157
163
  populate: {
158
164
  options: {
159
165
  header: "{{bold:{{cyan:%s}} options:}}",
@@ -245,6 +251,20 @@ module ShopifyCli
245
251
  "{{x}} error: For authentication issues, run {{command:%s logout}} to clear invalid credentials",
246
252
  update_prompt: "Do you want to update your application url?",
247
253
  },
254
+ select_org_and_shop: {
255
+ authentication_issue: "For authentication issues, run {{command:%s logout}} to clear invalid credentials",
256
+ create_store: "Visit {{underline:https://partners.shopify.com/%s/stores}} to create one",
257
+ development_store: "Using development store {{green:%s}}",
258
+ development_store_select: "Select a development store",
259
+ error: {
260
+ no_development_stores: "{{x}} No Development Stores available.",
261
+ no_organizations: "No partner organizations available.",
262
+ organization_not_found: "Cannot find a partner organization with that ID",
263
+ partners_notice: "Please visit https://partners.shopify.com/ to create a partners account",
264
+ },
265
+ organization: "Partner organization {{green:%s (%s)}}",
266
+ organization_select: "Select partner organization",
267
+ },
248
268
  },
249
269
 
250
270
  tunnel: {
@@ -27,6 +27,7 @@ module ShopifyCli
27
27
  register :EnsureEnv, :ensure_env, 'shopify-cli/tasks/ensure_env'
28
28
  register :EnsureLoopbackURL, :ensure_loopback_url, 'shopify-cli/tasks/ensure_loopback_url'
29
29
  register :EnsureDevStore, :ensure_dev_store, 'shopify-cli/tasks/ensure_dev_store'
30
+ register :SelectOrgAndShop, :select_org_and_shop, 'shopify-cli/tasks/select_org_and_shop'
30
31
  register :UpdateDashboardURLS, :update_dashboard_urls, 'shopify-cli/tasks/update_dashboard_urls'
31
32
  end
32
33
  end
@@ -0,0 +1,77 @@
1
+ require 'shopify_cli'
2
+
3
+ module ShopifyCli
4
+ module Tasks
5
+ class SelectOrgAndShop < ShopifyCli::Task
6
+ attr_reader :ctx
7
+
8
+ def call(ctx, organization_id: nil, shop_domain: nil)
9
+ @ctx = ctx
10
+ return response(organization_id.to_i, shop_domain) unless organization_id.nil? || shop_domain.nil?
11
+ org = get_organization(organization_id)
12
+ shop_domain ||= get_shop_domain(org)
13
+ response(org["id"].to_i, shop_domain)
14
+ end
15
+
16
+ private
17
+
18
+ def response(organization_id, shop_domain)
19
+ {
20
+ organization_id: organization_id,
21
+ shop_domain: shop_domain,
22
+ }
23
+ end
24
+
25
+ def organizations
26
+ @organizations ||= ShopifyCli::PartnersAPI::Organizations.fetch_all(ctx)
27
+ end
28
+
29
+ def get_organization(organization_id)
30
+ @organization ||= if !organization_id.nil?
31
+ org = ShopifyCli::PartnersAPI::Organizations.fetch(ctx, id: organization_id)
32
+ if org.nil?
33
+ ctx.puts(ctx.message('core.tasks.select_org_and_shop.error.authentication_issue', ShopifyCli::TOOL_NAME))
34
+ ctx.abort(ctx.message('core.tasks.select_org_and_shop.error.organization_not_found'))
35
+ end
36
+ org
37
+ elsif organizations.count == 0
38
+ ctx.puts(ctx.message('core.tasks.select_org_and_shop.error.partners_notice'))
39
+ ctx.puts(ctx.message('core.tasks.select_org_and_shop.authentication_issue', ShopifyCli::TOOL_NAME))
40
+ ctx.abort(ctx.message('core.tasks.select_org_and_shop.error.no_organizations'))
41
+ elsif organizations.count == 1
42
+ org = organizations.first
43
+ ctx.puts(ctx.message('core.tasks.select_org_and_shop.organization', org['businessName'], org['id']))
44
+ org
45
+ else
46
+ org_id = CLI::UI::Prompt.ask(ctx.message('core.tasks.select_org_and_shop.organization_select')) do |handler|
47
+ organizations.each do |o|
48
+ handler.option(ctx.message('core.partners_api.org_name_and_id', o['businessName'], o['id'])) { o['id'] }
49
+ end
50
+ end
51
+ organizations.find { |o| o['id'] == org_id }
52
+ end
53
+ end
54
+
55
+ def get_shop_domain(organization)
56
+ valid_stores = organization['stores'].select do |store|
57
+ store['transferDisabled'] == true || store['convertableToPartnerTest'] == true
58
+ end
59
+
60
+ if valid_stores.count == 0
61
+ ctx.puts(ctx.message('core.tasks.select_org_and_shop.error.no_development_stores'))
62
+ ctx.puts(ctx.message('core.tasks.select_org_and_shop.create_store', organization['id']))
63
+ ctx.puts(ctx.message('core.tasks.select_org_and_shop.authentication_issue', ShopifyCli::TOOL_NAME))
64
+ elsif valid_stores.count == 1
65
+ domain = valid_stores.first['shopDomain']
66
+ ctx.puts(ctx.message('core.tasks.select_org_and_shop.development_store', domain))
67
+ domain
68
+ else
69
+ CLI::UI::Prompt.ask(
70
+ ctx.message('core.tasks.select_org_and_shop.development_store_select'),
71
+ options: valid_stores.map { |s| s['shopDomain'] }
72
+ )
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end