shopify-cli 1.0.0 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -2
  3. data/CHANGELOG.md +20 -0
  4. data/Gemfile +1 -1
  5. data/Gemfile.lock +13 -13
  6. data/docs/Gemfile.lock +23 -13
  7. data/docs/getting-started/install/index.md +37 -1
  8. data/docs/getting-started/migrate/index.md +34 -1
  9. data/lib/project_types/extension/cli.rb +1 -1
  10. data/lib/project_types/extension/commands/build.rb +1 -1
  11. data/lib/project_types/extension/models/type.rb +1 -0
  12. data/lib/project_types/extension/tasks/create_extension.rb +1 -1
  13. data/lib/project_types/extension/tasks/get_app.rb +1 -1
  14. data/lib/project_types/extension/tasks/update_draft.rb +1 -1
  15. data/lib/project_types/node/forms/create.rb +3 -54
  16. data/lib/project_types/node/messages/messages.rb +3 -14
  17. data/lib/project_types/rails/cli.rb +0 -1
  18. data/lib/project_types/rails/forms/create.rb +3 -52
  19. data/lib/project_types/rails/messages/messages.rb +2 -13
  20. data/lib/project_types/script/cli.rb +2 -3
  21. data/lib/project_types/script/commands/create.rb +5 -9
  22. data/lib/project_types/script/commands/disable.rb +4 -15
  23. data/lib/project_types/script/commands/enable.rb +37 -13
  24. data/lib/project_types/script/commands/push.rb +8 -13
  25. data/lib/project_types/script/config/extension_points.yml +9 -3
  26. data/lib/project_types/script/errors.rb +8 -0
  27. data/lib/project_types/script/forms/script_form.rb +5 -2
  28. data/lib/project_types/script/layers/application/create_script.rb +7 -6
  29. data/lib/project_types/script/layers/application/disable_script.rb +9 -7
  30. data/lib/project_types/script/layers/application/enable_script.rb +11 -9
  31. data/lib/project_types/script/layers/application/push_script.rb +6 -4
  32. data/lib/project_types/script/layers/domain/errors.rb +2 -0
  33. data/lib/project_types/script/layers/infrastructure/assemblyscript_project_creator.rb +2 -2
  34. data/lib/project_types/script/layers/infrastructure/assemblyscript_task_runner.rb +2 -2
  35. data/lib/project_types/script/layers/infrastructure/errors.rb +2 -0
  36. data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +1 -1
  37. data/lib/project_types/script/layers/infrastructure/script_repository.rb +1 -1
  38. data/lib/project_types/script/layers/infrastructure/script_service.rb +2 -0
  39. data/lib/project_types/script/messages/messages.rb +25 -31
  40. data/lib/project_types/script/script_project.rb +8 -4
  41. data/lib/project_types/script/templates/ts/as-pect.config.js +6 -0
  42. data/lib/project_types/script/ui/error_handler.rb +8 -0
  43. data/lib/project_types/script/ui/printing_spinner.rb +75 -0
  44. data/lib/shopify-cli/admin_api.rb +1 -2
  45. data/lib/shopify-cli/admin_api/populate_resource_command.rb +10 -1
  46. data/lib/shopify-cli/admin_api/schema.rb +20 -8
  47. data/lib/shopify-cli/command.rb +14 -11
  48. data/lib/shopify-cli/commands.rb +1 -0
  49. data/lib/shopify-cli/commands/config.rb +44 -0
  50. data/lib/shopify-cli/commands/connect.rb +8 -69
  51. data/lib/shopify-cli/commands/create.rb +2 -2
  52. data/lib/shopify-cli/commands/help.rb +1 -1
  53. data/lib/shopify-cli/commands/system.rb +14 -6
  54. data/lib/shopify-cli/context.rb +10 -1
  55. data/lib/shopify-cli/core.rb +0 -1
  56. data/lib/shopify-cli/core/entry_point.rb +7 -1
  57. data/lib/shopify-cli/core/executor.rb +3 -5
  58. data/lib/shopify-cli/core/finalize.rb +13 -0
  59. data/lib/shopify-cli/core/monorail.rb +1 -1
  60. data/lib/shopify-cli/db.rb +1 -1
  61. data/lib/shopify-cli/feature.rb +97 -0
  62. data/lib/shopify-cli/heroku.rb +4 -4
  63. data/lib/shopify-cli/messages/messages.rb +51 -12
  64. data/lib/shopify-cli/partners_api/organizations.rb +7 -7
  65. data/lib/shopify-cli/process_supervision.rb +8 -6
  66. data/lib/shopify-cli/project_type.rb +5 -7
  67. data/lib/shopify-cli/sub_command.rb +1 -0
  68. data/lib/shopify-cli/task.rb +2 -2
  69. data/lib/shopify-cli/tasks.rb +12 -4
  70. data/lib/shopify-cli/tasks/ensure_env.rb +72 -16
  71. data/lib/shopify-cli/tasks/select_org_and_shop.rb +77 -0
  72. data/lib/shopify-cli/tasks/update_dashboard_urls.rb +4 -3
  73. data/lib/shopify-cli/tunnel.rb +38 -14
  74. data/lib/shopify-cli/version.rb +1 -1
  75. data/lib/shopify_cli.rb +32 -9
  76. metadata +7 -4
  77. data/lib/project_types/script/forms/enable.rb +0 -24
  78. data/lib/project_types/script/forms/push.rb +0 -19
@@ -5,13 +5,15 @@ module Script
5
5
  module Application
6
6
  class DisableScript
7
7
  def self.call(ctx:, api_key:, shop_domain:, extension_point_type:)
8
- script_service = Infrastructure::ScriptService.new(ctx: ctx)
9
- script_service.disable(
10
- api_key: api_key,
11
- shop_domain: shop_domain,
12
- extension_point_type: extension_point_type,
13
- )
14
- ctx.puts(ctx.message('script.application.disabled'))
8
+ UI::PrintingSpinner.spin(ctx, ctx.message('script.application.disabling')) do |p_ctx, spinner|
9
+ script_service = Infrastructure::ScriptService.new(ctx: p_ctx)
10
+ script_service.disable(
11
+ api_key: api_key,
12
+ shop_domain: shop_domain,
13
+ extension_point_type: extension_point_type,
14
+ )
15
+ spinner.update_title(p_ctx.message('script.application.disabled'))
16
+ end
15
17
  end
16
18
  end
17
19
  end
@@ -5,15 +5,17 @@ module Script
5
5
  module Application
6
6
  class EnableScript
7
7
  def self.call(ctx:, api_key:, shop_domain:, configuration:, extension_point_type:, title:)
8
- script_service = Infrastructure::ScriptService.new(ctx: ctx)
9
- script_service.enable(
10
- api_key: api_key,
11
- shop_domain: shop_domain,
12
- configuration: configuration,
13
- extension_point_type: extension_point_type,
14
- title: title
15
- )
16
- ctx.puts(ctx.message('script.application.enabled'))
8
+ UI::PrintingSpinner.spin(ctx, ctx.message('script.application.enabling')) do |p_ctx, spinner|
9
+ script_service = Infrastructure::ScriptService.new(ctx: p_ctx)
10
+ script_service.enable(
11
+ api_key: api_key,
12
+ shop_domain: shop_domain,
13
+ configuration: configuration,
14
+ extension_point_type: extension_point_type,
15
+ title: title
16
+ )
17
+ spinner.update_title(p_ctx.message('script.application.enabled'))
18
+ end
17
19
  end
18
20
  end
19
21
  end
@@ -20,10 +20,12 @@ module Script
20
20
  private
21
21
 
22
22
  def push_script(ctx, task_runner, script, api_key, force)
23
- Infrastructure::PushPackageRepository.new(ctx: ctx)
24
- .get_push_package(script, task_runner.compiled_type)
25
- .push(Infrastructure::ScriptService.new(ctx: ctx), api_key, force)
26
- ctx.puts(ctx.message('script.application.pushed'))
23
+ UI::PrintingSpinner.spin(ctx, ctx.message('script.application.pushing')) do |p_ctx, spinner|
24
+ Infrastructure::PushPackageRepository.new(ctx: p_ctx)
25
+ .get_push_package(script, task_runner.compiled_type)
26
+ .push(Infrastructure::ScriptService.new(ctx: p_ctx), api_key, force)
27
+ spinner.update_title(p_ctx.message('script.application.pushed'))
28
+ end
27
29
  end
28
30
  end
29
31
  end
@@ -8,12 +8,14 @@ module Script
8
8
  class InvalidExtensionPointError < ScriptProjectError
9
9
  attr_reader :type
10
10
  def initialize(type)
11
+ super()
11
12
  @type = type
12
13
  end
13
14
  end
14
15
  class ScriptNotFoundError < ScriptProjectError
15
16
  attr_reader :script_name, :extension_point_type
16
17
  def initialize(extension_point_type, script_name)
18
+ super()
17
19
  @script_name = script_name
18
20
  @extension_point_type = extension_point_type
19
21
  end
@@ -86,14 +86,14 @@ module Script
86
86
  "@shopify/scripts-toolchain-as": "#{extension_point.sdks[:ts].toolchain_version}",
87
87
  "#{extension_point.sdks[:ts].package}": "#{extension_point.sdks[:ts].version}",
88
88
  "@as-pect/cli": "4.0.0",
89
- "as-wasi": "^0.0.1",
89
+ "as-wasi": "^0.2.0",
90
90
  "assemblyscript": "^0.12.0"
91
91
  },
92
92
  "scripts": {
93
93
  "test": "asp --config test/as-pect.config.js --summary --verbose"
94
94
  },
95
95
  "engines": {
96
- "node": ">=12.16"
96
+ "node": ">=14.5"
97
97
  }
98
98
  }
99
99
  HERE
@@ -6,7 +6,7 @@ module Script
6
6
  class AssemblyScriptTaskRunner
7
7
  BYTECODE_FILE = "%{name}.wasm"
8
8
  SCRIPT_SDK_BUILD = "npx --no-install shopify-scripts-build --src=../%{source} --binary=#{BYTECODE_FILE} "\
9
- "-- --lib=../node_modules --validate --optimize"
9
+ "-- --lib=../node_modules --optimize --use Date="
10
10
 
11
11
  attr_reader :ctx, :script_name, :script_source_file
12
12
 
@@ -34,7 +34,7 @@ module Script
34
34
 
35
35
  def dependencies_installed?
36
36
  # Assuming if node_modules folder exist at root of script folder, all deps are installed
37
- ctx.exist?("node_modules")
37
+ ctx.dir_exist?("node_modules")
38
38
  end
39
39
 
40
40
  private
@@ -5,6 +5,7 @@ module Script
5
5
  module Infrastructure
6
6
  module Errors
7
7
  class AppNotInstalledError < ScriptProjectError; end
8
+ class AppScriptNotPushedError < ScriptProjectError; end
8
9
  class AppScriptUndefinedError < ScriptProjectError; end
9
10
  class BuildError < ScriptProjectError; end
10
11
  class DependencyInstallError < ScriptProjectError; end
@@ -20,6 +21,7 @@ module Script
20
21
  class ScriptRepushError < ScriptProjectError
21
22
  attr_reader :api_key
22
23
  def initialize(api_key)
24
+ super()
23
25
  @api_key = api_key
24
26
  end
25
27
  end
@@ -22,7 +22,7 @@ module Script
22
22
  def get_push_package(script, compiled_type)
23
23
  build_file_path = file_path(script.name, compiled_type)
24
24
 
25
- raise Domain::PushPackageNotFoundError unless File.exist?(build_file_path)
25
+ raise Domain::PushPackageNotFoundError unless ctx.file_exist?(build_file_path)
26
26
 
27
27
  script_content = File.read(build_file_path)
28
28
 
@@ -9,7 +9,7 @@ module Script
9
9
 
10
10
  def get_script(language, extension_point_type, script_name)
11
11
  source_file_path = src_code_file(language)
12
- unless File.exist?(source_file_path)
12
+ unless ctx.file_exist?(source_file_path)
13
13
  raise Domain::Errors::ScriptNotFoundError.new(extension_point_type, source_file_path)
14
14
  end
15
15
 
@@ -60,6 +60,8 @@ module Script
60
60
  raise Errors::AppScriptUndefinedError, api_key
61
61
  elsif user_errors.any? { |e| e['tag'] == 'shop_script_conflict' }
62
62
  raise Errors::ShopScriptConflictError
63
+ elsif user_errors.any? { |e| e['tag'] == 'app_script_not_pushed' }
64
+ raise Errors::AppScriptNotPushedError
63
65
  else
64
66
  raise Errors::ScriptServiceUserError.new(query_name, user_errors.to_s)
65
67
  end
@@ -38,10 +38,15 @@ module Script
38
38
  invalid_extension_cause: "Invalid extension point %s",
39
39
  invalid_extension_help: "Allowed values: %s.",
40
40
 
41
+ invalid_config: "Can't change the configuration values because %1$s is missing or "\
42
+ "it is not formatted properly.",
43
+
41
44
  script_not_found_cause: "Couldn't find script %s for extension point %s",
42
45
 
43
46
  app_not_installed_cause: "App not installed on development store.",
44
47
 
48
+ app_script_not_pushed_help: "Push the script and then try this command again.",
49
+
45
50
  app_script_undefined_help: "Push script to app.",
46
51
 
47
52
  build_error_cause: "Something went wrong while building the script.",
@@ -72,32 +77,26 @@ module Script
72
77
  help: <<~HELP,
73
78
  {{command:%1$s create script}}: Creates a script project.
74
79
  Usage: {{command:%1$s create script}}
75
- HELP
76
- extended_help: <<~HELP,
77
- \s\sOptions:
78
- \s\s{{command:--name=NAME}} Script project name. Use any string.
79
- \s\s{{command:--extension_point=TYPE}} Extension point name. Allowed values: %2$s.
80
+ Options:
81
+ {{command:--name=NAME}} Script project name. Use any string.
82
+ {{command:--extension_point=TYPE}} Extension point name. Allowed values: %2$s.
80
83
  HELP
81
84
 
82
85
  error: {
83
86
  operation_failed: "Script not created.",
84
87
  },
85
88
 
86
- script_path: "{{v}} Project directory: {{green:%{folder}}}",
87
- script_created: "{{v}} Script created: {{green:%{script_id}}}",
89
+ change_directory_notice: "{{*}} Change directories to {{green:%s}} to run script commands",
88
90
  creating: "Creating script",
89
- created: "Created script",
91
+ created: "Created script: {{green:%s}}",
90
92
  },
91
93
 
92
94
  push: {
93
95
  help: <<~HELP,
94
96
  Build the script and put it into production. If you've already pushed a script with the same extension point, use --force to replace the current script with the newest one.
95
97
  Usage: {{command:%s push}}
96
- HELP
97
- extended_help: <<~HELP,
98
- \s\sOptions:
99
- \s\s{{command:--API_key=<API_key>}} API key. Must be a valid API key, otherwise store access fails.
100
- \s\s{{command:[--force]}} Forces the script to be overwritten if an instance of it already exists.
98
+ Options:
99
+ {{command:[--force]}} Forces the script to be overwritten if an instance of it already exists.
101
100
  HELP
102
101
 
103
102
  error: {
@@ -112,14 +111,10 @@ module Script
112
111
  Turn off script in development store.
113
112
  Usage: {{command:%s disable}}
114
113
  HELP
115
- extended_help: <<~HELP,
116
- \s\sOptions:
117
- \s\s{{command:--API_key=<API_key>}} API key. Must be a valid API key, otherwise store access fails.
118
- \s\s{{command:--shop_domain=<my_store.myshopify.com>}} Test store URL. Must be an existing test store.
119
- HELP
120
114
 
121
115
  error: {
122
116
  operation_failed: "Can't disable script.",
117
+ not_pushed_to_app: "Can't disable the script because it hasn't been pushed to the app.",
123
118
  },
124
119
 
125
120
  script_disabled: "{{v}} Script disabled. Script is turned off in development store.",
@@ -129,11 +124,9 @@ module Script
129
124
  help: <<~HELP,
130
125
  Turn on script in development store.
131
126
  Usage: {{command:%s enable}}
132
- HELP
133
- extended_help: <<~HELP,
134
- \s\sOptions:
135
- \s\s{{command:--API_key=<API_key>}} API key. Must be a valid API key, otherwise store access fails.
136
- \s\s{{command:--shop_domain=<my_store.myshopify.com>}} Test store URL. Must be an existing test store.
127
+ Options:
128
+ {{command:--config_props='name1:value1, name2:value2'}} Optional. Define the configuration of your script by passing individual name and value pairs. If used with --config_file, then matching values in --config_props will override those set in the file.
129
+ {{command:--config_file=<path/to/YAMLFilename>}} Optional. Define the configuration of your script using a YAML formatted file. --config_props values override properties in this file.
137
130
  HELP
138
131
 
139
132
  info: "{{*}} A script always remains enabled until you disable it - even after pushing "\
@@ -142,6 +135,7 @@ module Script
142
135
 
143
136
  error: {
144
137
  operation_failed: "Can't enable script.",
138
+ not_pushed_to_app: "Can't enable the script because it hasn't been pushed to the app.",
145
139
  },
146
140
 
147
141
  script_enabled: "{{v}} Script enabled. %{type} script %{title} in app (API key: %{api_key}) "\
@@ -177,25 +171,25 @@ module Script
177
171
  script_form: {
178
172
  ask_app_api_key_default: "Which app do you want this script to belong to?",
179
173
  ask_shop_domain_default: "Select a development store",
180
- fetching_organizations: "{{i}} Fetching partner organizations",
174
+ fetching_organizations: "Fetching partner organizations",
175
+ fetched_organizations: "Fetched partner organizations",
181
176
  select_organization: "Select partner organization.",
182
177
  using_app: "Using app {{green:%{title} (%{api_key})}}.",
183
178
  using_development_store: "Using development store {{green:%{domain}}}",
184
179
  using_organization: "Partner organization {{green:%s}}.",
185
180
  },
186
- enable: {
187
- ask_app_api_key: "Which app is the script pushed to?",
188
- ask_shop_domain: "Which development store is the app installed on?",
189
- },
190
181
  },
191
182
 
192
183
  application: {
193
184
  building: "Building",
194
185
  building_script: "Building script",
195
186
  built: "Built",
196
- pushed: "{{v}} Pushed",
197
- disabled: "{{v}} Disabled",
198
- enabled: "{{v}} Enabled",
187
+ pushing: "Pushing",
188
+ pushed: "Pushed",
189
+ disabling: "Disabling",
190
+ disabled: "Disabled",
191
+ enabling: "Enabling",
192
+ enabled: "Enabled",
199
193
  },
200
194
  },
201
195
  }.freeze
@@ -19,12 +19,16 @@ module Script
19
19
  }
20
20
  end
21
21
 
22
+ def file_name
23
+ "script.#{language}"
24
+ end
25
+
22
26
  def source_file
23
27
  "#{SOURCE_DIR}/#{file_name}"
24
28
  end
25
29
 
26
- def file_name
27
- "script.#{language}"
30
+ def source_path
31
+ "#{script_name}/#{source_file}"
28
32
  end
29
33
 
30
34
  private
@@ -36,14 +40,14 @@ module Script
36
40
 
37
41
  class << self
38
42
  def create(ctx, dir)
39
- raise Errors::ScriptProjectAlreadyExistsError, dir if ctx.exist?(dir)
43
+ raise Errors::ScriptProjectAlreadyExistsError, dir if ctx.dir_exist?(dir)
40
44
  ctx.mkdir_p(dir)
41
45
  ctx.chdir(dir)
42
46
  end
43
47
 
44
48
  def cleanup(ctx:, script_name:, root_dir:)
45
49
  ctx.chdir(root_dir)
46
- ctx.rm_r("#{root_dir}/#{script_name}") if ctx.exist?("#{root_dir}/#{script_name}")
50
+ ctx.rm_r("#{root_dir}/#{script_name}") if ctx.dir_exist?("#{root_dir}/#{script_name}")
47
51
  end
48
52
  end
49
53
  end
@@ -17,5 +17,11 @@ module.exports = {
17
17
  reportMax: false,
18
18
  reportMin: false,
19
19
  },
20
+ wasi: {
21
+ args: [],
22
+ env: process.env,
23
+ preopens: {},
24
+ returnOnExit: false,
25
+ },
20
26
  outputBinary: false,
21
27
  };
@@ -44,6 +44,10 @@ 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::InvalidConfigYAMLError
48
+ {
49
+ cause_of_error: ShopifyCli::Context.message('script.error.invalid_config', e.config_file),
50
+ }
47
51
  when Errors::InvalidScriptNameError
48
52
  {
49
53
  cause_of_error: ShopifyCli::Context.message('script.error.invalid_script_name_cause'),
@@ -92,6 +96,10 @@ module Script
92
96
  {
93
97
  cause_of_error: ShopifyCli::Context.message('script.error.app_not_installed_cause'),
94
98
  }
99
+ when Layers::Infrastructure::Errors::AppScriptNotPushedError
100
+ {
101
+ cause_of_error: ShopifyCli::Context.message('script.error.app_script_not_pushed_help'),
102
+ }
95
103
  when Layers::Infrastructure::Errors::AppScriptUndefinedError
96
104
  {
97
105
  help_suggestion: ShopifyCli::Context.message('script.error.app_script_undefined_help'),
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+ require 'shopify_cli'
3
+
4
+ module Script
5
+ module UI
6
+ module PrintingSpinner
7
+ ##
8
+ # Creates a single spinner that runs the provided block.
9
+ # The block can take in a ctx argument that formats printed output to support
10
+ # printing from within the spin block.
11
+ #
12
+ # ==== Attributes
13
+ #
14
+ # * +ctx+ - The current context.
15
+ # * +title+ - Title of the spinner to use
16
+ #
17
+ # ==== Options
18
+ #
19
+ # * +:auto_debrief+ - Automatically debrief exceptions? Default to true
20
+ #
21
+ # ==== Block
22
+ #
23
+ # * +ctx+ - Instance of the PrintingSpinnerContext built from the ctx attribute.
24
+ # - +ctx.puts(...)+ formats output to enable support for printing within spinners
25
+ # * +spinner+ - Instance of the spinner. Can call +update_title+ to update the user of changes
26
+ #
27
+ def self.spin(ctx, title, auto_debrief: false)
28
+ StrictSpinner.spin(title, auto_debrief: auto_debrief) do |spinner, *args|
29
+ Thread.current[:cliui_output_hook] = nil
30
+ yield(PrintingSpinnerContext.from(ctx, spinner), spinner, *args)
31
+ end
32
+ end
33
+
34
+ ##
35
+ # Printing within spinners requires the manipulation of ANSI escape
36
+ # sequences in order to make sure the CLI::UI::Spinner does not overwrite
37
+ # previously printed content.
38
+ class PrintingSpinnerContext < ShopifyCli::Context
39
+ include SmartProperties
40
+ property :spinner, required: true
41
+
42
+ def self.from(ctx, spinner)
43
+ new_ctx = new(spinner: spinner)
44
+ ctx.instance_variables.each do |var|
45
+ new_ctx.instance_variable_set(var, ctx.instance_variable_get(var))
46
+ end
47
+ new_ctx
48
+ end
49
+
50
+ def puts(*input)
51
+ super(encoded_lines(*input) + "\n" + spinner_text)
52
+ end
53
+
54
+ private
55
+
56
+ def encoded_lines(*lines)
57
+ lines
58
+ .join("\n")
59
+ .split("\n")
60
+ .map { |line| encode_ansi(line) unless line.nil? }
61
+ .join(CLI::UI::ANSI.next_line + "\n")
62
+ end
63
+
64
+ def encode_ansi(line)
65
+ CLI::UI::ANSI.previous_line + line + CLI::UI::ANSI.clear_to_end_of_line
66
+ end
67
+
68
+ def spinner_text
69
+ spinner.render(0, true)
70
+ end
71
+ end
72
+ private_constant(:PrintingSpinnerContext)
73
+ end
74
+ end
75
+ end
@@ -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