shopify-cli 2.25.0 → 2.26.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 (70) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/Gemfile.lock +1 -1
  4. data/dev.yml +0 -3
  5. data/lib/project_types/script/cli.rb +0 -79
  6. data/lib/project_types/script/commands/connect.rb +3 -8
  7. data/lib/project_types/script/commands/create.rb +4 -29
  8. data/lib/project_types/script/commands/javy.rb +3 -8
  9. data/lib/project_types/script/commands/push.rb +4 -41
  10. data/lib/project_types/script/messages/messages.rb +1 -258
  11. data/lib/project_types/theme/commands/common/shop_helper.rb +13 -0
  12. data/lib/project_types/theme/commands/delete.rb +4 -1
  13. data/lib/project_types/theme/commands/list.rb +3 -4
  14. data/lib/project_types/theme/commands/open.rb +4 -1
  15. data/lib/project_types/theme/commands/publish.rb +4 -1
  16. data/lib/project_types/theme/commands/pull.rb +3 -1
  17. data/lib/project_types/theme/commands/push.rb +3 -1
  18. data/lib/project_types/theme/messages/messages.rb +5 -5
  19. data/lib/shopify_cli/messages/messages.rb +1 -1
  20. data/lib/shopify_cli/packager.rb +12 -3
  21. data/lib/shopify_cli/release.rb +4 -2
  22. data/lib/shopify_cli/version.rb +1 -1
  23. data/vendor/deps/cli-ui/lib/cli/ui/prompt/interactive_options.rb +1 -1
  24. metadata +3 -48
  25. data/lib/project_types/script/config/extension_points.yml +0 -45
  26. data/lib/project_types/script/errors.rb +0 -10
  27. data/lib/project_types/script/forms/ask_app.rb +0 -27
  28. data/lib/project_types/script/forms/ask_org.rb +0 -30
  29. data/lib/project_types/script/forms/ask_script_uuid.rb +0 -22
  30. data/lib/project_types/script/forms/create.rb +0 -33
  31. data/lib/project_types/script/forms/run_against_shopify_org.rb +0 -14
  32. data/lib/project_types/script/graphql/app_script_set.graphql +0 -46
  33. data/lib/project_types/script/graphql/get_app_scripts.graphql +0 -6
  34. data/lib/project_types/script/graphql/module_upload_url_generate.graphql +0 -13
  35. data/lib/project_types/script/graphql/script_service_proxy.graphql +0 -7
  36. data/lib/project_types/script/layers/application/build_script.rb +0 -25
  37. data/lib/project_types/script/layers/application/connect_app.rb +0 -86
  38. data/lib/project_types/script/layers/application/create_script.rb +0 -90
  39. data/lib/project_types/script/layers/application/extension_points.rb +0 -66
  40. data/lib/project_types/script/layers/application/project_dependencies.rb +0 -26
  41. data/lib/project_types/script/layers/application/push_script.rb +0 -74
  42. data/lib/project_types/script/layers/domain/app_bridge.rb +0 -16
  43. data/lib/project_types/script/layers/domain/errors.rb +0 -47
  44. data/lib/project_types/script/layers/domain/extension_point.rb +0 -81
  45. data/lib/project_types/script/layers/domain/metadata.rb +0 -46
  46. data/lib/project_types/script/layers/domain/push_package.rb +0 -41
  47. data/lib/project_types/script/layers/domain/script_config.rb +0 -32
  48. data/lib/project_types/script/layers/domain/script_project.rb +0 -61
  49. data/lib/project_types/script/layers/infrastructure/api_clients/partners_proxy_api_client.rb +0 -53
  50. data/lib/project_types/script/layers/infrastructure/api_clients/script_service_api_client.rb +0 -35
  51. data/lib/project_types/script/layers/infrastructure/command_runner.rb +0 -19
  52. data/lib/project_types/script/layers/infrastructure/errors.rb +0 -211
  53. data/lib/project_types/script/layers/infrastructure/extension_point_repository.rb +0 -37
  54. data/lib/project_types/script/layers/infrastructure/languages/project_creator.rb +0 -62
  55. data/lib/project_types/script/layers/infrastructure/languages/task_runner.rb +0 -47
  56. data/lib/project_types/script/layers/infrastructure/languages/tool_version_checker.rb +0 -26
  57. data/lib/project_types/script/layers/infrastructure/languages/typescript_project_creator.rb +0 -45
  58. data/lib/project_types/script/layers/infrastructure/languages/typescript_task_runner.rb +0 -103
  59. data/lib/project_types/script/layers/infrastructure/languages/wasm_project_creator.rb +0 -12
  60. data/lib/project_types/script/layers/infrastructure/languages/wasm_task_runner.rb +0 -32
  61. data/lib/project_types/script/layers/infrastructure/metadata_repository.rb +0 -18
  62. data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +0 -36
  63. data/lib/project_types/script/layers/infrastructure/script_project_repository.rb +0 -273
  64. data/lib/project_types/script/layers/infrastructure/script_service.rb +0 -135
  65. data/lib/project_types/script/layers/infrastructure/script_uploader.rb +0 -40
  66. data/lib/project_types/script/layers/infrastructure/service_locator.rb +0 -20
  67. data/lib/project_types/script/layers/infrastructure/sparse_checkout_details.rb +0 -35
  68. data/lib/project_types/script/ui/error_handler.rb +0 -331
  69. data/lib/project_types/script/ui/printing_spinner.rb +0 -75
  70. data/lib/project_types/script/ui/strict_spinner.rb +0 -20
@@ -1,273 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Script
4
- module Layers
5
- module Infrastructure
6
- class ScriptProjectRepository
7
- include SmartProperties
8
- property! :ctx, accepts: ShopifyCLI::Context
9
- property :directory, accepts: String
10
- property :initial_directory, accepts: String
11
-
12
- MUTABLE_ENV_VALUES = %i(uuid)
13
- INPUT_QUERY_PATH = "input.graphql"
14
-
15
- def create_project_directory
16
- raise Infrastructure::Errors::ScriptProjectAlreadyExistsError, directory if ctx.dir_exist?(directory)
17
- ctx.mkdir_p(directory)
18
- change_directory(directory: directory)
19
- end
20
-
21
- def delete_project_directory
22
- change_to_initial_directory
23
- ctx.rm_r(directory)
24
- end
25
-
26
- def change_to_initial_directory
27
- change_directory(directory: initial_directory)
28
- end
29
-
30
- def create(title:, extension_point_type:, language:)
31
- validate_metadata!(extension_point_type, language)
32
-
33
- ShopifyCLI::Project.write(
34
- ctx,
35
- project_type: :script,
36
- organization_id: nil,
37
- extension_point_type: extension_point_type,
38
- title: title,
39
- description: nil,
40
- language: language,
41
- app_bridge_create_path: "/",
42
- app_bridge_details_path: "/",
43
- )
44
-
45
- build_script_project(script_config: nil)
46
- end
47
-
48
- def get
49
- validate_metadata!(extension_point_type, language)
50
-
51
- Domain::ScriptProject.new(
52
- id: project.directory,
53
- env: project.env,
54
- title: title,
55
- description: description,
56
- extension_point_type: extension_point_type,
57
- language: language,
58
- script_config: script_config_repository.get!,
59
- app_bridge: app_bridge,
60
- input_query: read_input_query,
61
- )
62
- end
63
-
64
- def update_env(**args)
65
- capture_io do
66
- args.slice(*MUTABLE_ENV_VALUES).each do |key, value|
67
- project.env.extra[key.to_s.upcase] = value
68
- project.env.update(ctx, :extra, project.env.extra)
69
- end
70
- end
71
-
72
- build_script_project
73
- end
74
-
75
- def create_env(api_key:, secret:, uuid:)
76
- ShopifyCLI::Resources::EnvFile.new(
77
- api_key: api_key,
78
- secret: secret,
79
- extra: {
80
- Domain::ScriptProject::UUID_ENV_KEY => uuid,
81
- }
82
- ).write(ctx)
83
-
84
- build_script_project
85
- end
86
-
87
- private
88
-
89
- def build_script_project(
90
- script_config: script_config_repository.get!
91
- )
92
- Domain::ScriptProject.new(
93
- id: ctx.root,
94
- env: project.env,
95
- title: title,
96
- description: description,
97
- extension_point_type: extension_point_type,
98
- language: language,
99
- script_config: script_config,
100
- app_bridge: app_bridge,
101
- )
102
- end
103
-
104
- def change_directory(directory:)
105
- ctx.chdir(directory)
106
- end
107
-
108
- def capture_io(&block)
109
- CLI::UI::StdoutRouter::Capture.new(&block).run
110
- end
111
-
112
- def extension_point_type
113
- project_config_value!("extension_point_type")
114
- end
115
-
116
- def title
117
- project_config_value!("title")
118
- end
119
-
120
- def description
121
- project_config_value("description")
122
- end
123
-
124
- def language
125
- project_config_value("language")&.downcase || default_language
126
- end
127
-
128
- def app_bridge
129
- create_path = project_config_value!("app_bridge_create_path")
130
- details_path = project_config_value!("app_bridge_details_path")
131
-
132
- Domain::AppBridge.new(
133
- create_path: create_path,
134
- details_path: details_path,
135
- )
136
- end
137
-
138
- def project_config_value(key)
139
- return nil unless project.config.key?(key)
140
- project.config[key]
141
- end
142
-
143
- def project_config_value!(key)
144
- raise Errors::InvalidContextError, key unless project.config.key?(key)
145
- project.config[key]
146
- end
147
-
148
- def project
149
- @project ||= ShopifyCLI::Project.current(force_reload: true)
150
- end
151
-
152
- def default_language
153
- "wasm"
154
- end
155
-
156
- def validate_metadata!(extension_point_type, language)
157
- if Application::ExtensionPoints.deprecated_types.include?(extension_point_type)
158
- raise Errors::DeprecatedEPError, extension_point_type
159
- elsif !Application::ExtensionPoints.supported_language?(type: extension_point_type, language: language)
160
- raise Errors::InvalidLanguageError.new(language, extension_point_type)
161
- end
162
- end
163
-
164
- def script_config_repository
165
- @script_config_repository ||= begin
166
- script_config_yml_repo = ScriptConfigYmlRepository.new(ctx: ctx)
167
- supported_repos = [
168
- script_config_yml_repo,
169
- ScriptJsonRepository.new(ctx: ctx),
170
- ]
171
- repo = supported_repos.find(&:active?)
172
- if repo.nil?
173
- raise Infrastructure::Errors::NoScriptConfigFileError, script_config_yml_repo.filename
174
- end
175
- repo
176
- end
177
- end
178
-
179
- def read_input_query
180
- ctx.read(INPUT_QUERY_PATH) if ctx.file_exist?(INPUT_QUERY_PATH)
181
- end
182
-
183
- class ScriptConfigRepository
184
- include SmartProperties
185
- property! :ctx, accepts: ShopifyCLI::Context
186
-
187
- def active?
188
- ctx.file_exist?(filename)
189
- end
190
-
191
- def get!
192
- raise Infrastructure::Errors::NoScriptConfigFileError, filename unless active?
193
-
194
- content = ctx.read(filename)
195
- hash = file_content_to_hash(content)
196
-
197
- from_h(hash)
198
- end
199
-
200
- def filename
201
- raise NotImplementedError
202
- end
203
-
204
- private
205
-
206
- def from_h(hash)
207
- Domain::ScriptConfig.new(content: hash, filename: filename)
208
- end
209
-
210
- def file_content_to_hash(file_content)
211
- raise NotImplementedError
212
- end
213
-
214
- def hash_to_file_content(hash)
215
- raise NotImplementedError
216
- end
217
- end
218
-
219
- class ScriptConfigYmlRepository < ScriptConfigRepository
220
- def filename
221
- "script.config.yml"
222
- end
223
-
224
- private
225
-
226
- def file_content_to_hash(file_content)
227
- begin
228
- hash = YAML.load(file_content)
229
- rescue Psych::SyntaxError
230
- raise parse_error
231
- end
232
- raise parse_error unless hash.is_a?(Hash)
233
- hash
234
- end
235
-
236
- def hash_to_file_content(hash)
237
- YAML.dump(hash)
238
- end
239
-
240
- def parse_error
241
- Errors::ScriptConfigParseError.new(filename: filename, serialization_format: "YAML")
242
- end
243
- end
244
-
245
- class ScriptJsonRepository < ScriptConfigRepository
246
- def filename
247
- "script.json"
248
- end
249
-
250
- private
251
-
252
- def file_content_to_hash(file_content)
253
- begin
254
- hash = JSON.parse(file_content)
255
- rescue JSON::ParserError
256
- raise parse_error
257
- end
258
- raise parse_error unless hash.is_a?(Hash)
259
- hash
260
- end
261
-
262
- def hash_to_file_content(hash)
263
- JSON.pretty_generate(hash)
264
- end
265
-
266
- def parse_error
267
- Errors::ScriptConfigParseError.new(filename: filename, serialization_format: "JSON")
268
- end
269
- end
270
- end
271
- end
272
- end
273
- end
@@ -1,135 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "base64"
4
- require "json"
5
-
6
- module Script
7
- module Layers
8
- module Infrastructure
9
- class ScriptService
10
- def initialize(client:, api_key:)
11
- @client = client
12
- @api_key = api_key
13
- end
14
-
15
- def set_app_script(
16
- uuid:,
17
- extension_point_type:,
18
- title:,
19
- description:,
20
- force: false,
21
- metadata:,
22
- script_config:,
23
- app_bridge:,
24
- module_upload_url:,
25
- library:,
26
- input_query: nil
27
- )
28
- query_name = "app_script_set"
29
- variables = {
30
- uuid: uuid,
31
- extensionPointName: extension_point_type.upcase,
32
- title: title,
33
- description: description,
34
- force: force,
35
- schemaMajorVersion: metadata.schema_major_version.to_s, # API expects string value
36
- schemaMinorVersion: metadata.schema_minor_version.to_s, # API expects string value
37
- scriptConfigVersion: script_config.version,
38
- configurationUi: script_config.configuration_ui,
39
- configurationDefinition: script_config.configuration&.to_json,
40
- appBridge: {
41
- createPath: app_bridge.create_path,
42
- detailsPath: app_bridge.details_path,
43
- },
44
- moduleUploadUrl: module_upload_url,
45
- inputQuery: input_query,
46
- }
47
-
48
- variables[:library] = {
49
- language: library[:language],
50
- version: library[:version],
51
- } if library
52
-
53
- resp_hash = make_request(query_name: query_name, variables: variables)
54
- user_errors = resp_hash["data"]["appScriptSet"]["userErrors"]
55
-
56
- return resp_hash["data"]["appScriptSet"]["appScript"]["uuid"] if user_errors.empty?
57
-
58
- if user_errors.any? { |e| e["tag"] == "already_exists_error" }
59
- raise Errors::ScriptRepushError, uuid
60
- elsif (errors = user_errors.select { |err| err["tag"] == "configuration_definition_error" }).any?
61
- raise Errors::ScriptConfigurationDefinitionError.new(
62
- messages: errors.map { |e| e["message"] },
63
- filename: script_config.filename,
64
- )
65
- elsif (e = user_errors.any? { |err| err["tag"] == "configuration_definition_syntax_error" })
66
- raise Errors::ScriptConfigSyntaxError, script_config.filename
67
- elsif (e = user_errors.find { |err| err["tag"] == "configuration_definition_missing_keys_error" })
68
- raise Errors::ScriptConfigMissingKeysError.new(
69
- missing_keys: e["message"],
70
- filename: script_config.filename,
71
- )
72
- elsif (e = user_errors.find { |err| err["tag"] == "configuration_definition_invalid_value_error" })
73
- raise Errors::ScriptConfigInvalidValueError.new(
74
- valid_input_modes: e["message"],
75
- filename: script_config.filename,
76
- )
77
- elsif (e = user_errors.find do |err|
78
- err["tag"] == "configuration_definition_schema_field_missing_keys_error"
79
- end)
80
- raise Errors::ScriptConfigFieldsMissingKeysError.new(
81
- missing_keys: e["message"],
82
- filename: script_config.filename,
83
- )
84
- elsif (e = user_errors.find do |err|
85
- err["tag"] == "configuration_definition_schema_field_invalid_value_error"
86
- end)
87
- raise Errors::ScriptConfigFieldsInvalidValueError.new(
88
- valid_types: e["message"],
89
- filename: script_config.filename,
90
- )
91
- elsif (errors = user_errors.filter { |err| err["tag"] == "input_query_validation_error" }).any?
92
- raise Errors::InvalidInputQueryErrors, errors.map { |err| err["message"] }
93
- elsif user_errors.find { |err| %w(schema_version_argument_error).include?(err["tag"]) }
94
- raise Domain::Errors::MetadataValidationError
95
- elsif user_errors.find { |err| err["tag"] == "invalid_app_bridge_create_path" }
96
- raise Errors::InvalidAppBridgePathError, "create"
97
- elsif user_errors.find { |err| err["tag"] == "invalid_app_bridge_details_path" }
98
- raise Errors::InvalidAppBridgePathError, "details"
99
- else
100
- raise Errors::GraphqlError, user_errors
101
- end
102
- end
103
-
104
- def get_app_scripts(extension_point_type:)
105
- query_name = "get_app_scripts"
106
- variables = { appKey: @api_key, extensionPointName: extension_point_type.upcase }
107
- response = make_request(query_name: query_name, variables: variables)
108
- response["data"]["appScripts"]
109
- end
110
-
111
- def generate_module_upload_details
112
- query_name = "module_upload_url_generate"
113
- variables = {}
114
- response = make_request(query_name: query_name, variables: variables)
115
- user_errors = response["data"]["moduleUploadUrlGenerate"]["userErrors"]
116
-
117
- raise Errors::GraphqlError, user_errors if user_errors.any?
118
-
119
- data = response["data"]["moduleUploadUrlGenerate"]["details"]
120
- { url: data["url"], headers: data["headers"], max_size: data["humanizedMaxSize"] }
121
- end
122
-
123
- private
124
-
125
- def make_request(query_name:, variables: {})
126
- response = @client.query(query_name, variables: variables)
127
- raise Errors::EmptyResponseError if response.nil?
128
- raise Errors::GraphqlError, response["errors"] if response.key?("errors")
129
-
130
- response
131
- end
132
- end
133
- end
134
- end
135
- end
@@ -1,40 +0,0 @@
1
- module Script
2
- module Layers
3
- module Infrastructure
4
- class ScriptUploader
5
- def initialize(script_service)
6
- @script_service = script_service
7
- end
8
-
9
- def upload(script_content)
10
- upload_details = @script_service.generate_module_upload_details
11
- url = URI(upload_details[:url])
12
-
13
- https = Net::HTTP.new(url.host, url.port)
14
- https.use_ssl = true
15
-
16
- request = Net::HTTP::Put.new(url)
17
- request["Content-Type"] = "application/wasm"
18
-
19
- upload_details[:headers].each do |header, value|
20
- request[header] = value
21
- end
22
-
23
- request.body = script_content
24
-
25
- response = https.request(request)
26
- raise Errors::ScriptTooLargeError, upload_details[:max_size] if script_too_large?(response)
27
- raise Errors::ScriptUploadError unless response.code == "200"
28
-
29
- upload_details[:url]
30
- end
31
-
32
- private
33
-
34
- def script_too_large?(response)
35
- response.code == "400" && response.body.include?("EntityTooLarge")
36
- end
37
- end
38
- end
39
- end
40
- end
@@ -1,20 +0,0 @@
1
- module Script
2
- module Layers
3
- module Infrastructure
4
- class ServiceLocator
5
- def self.api_client(ctx:, api_key:)
6
- if ENV["BYPASS_PARTNERS_PROXY"]
7
- ApiClients::ScriptServiceApiClient.new(ctx, api_key)
8
- else
9
- ApiClients::PartnersProxyApiClient.new(ctx, api_key)
10
- end
11
- end
12
-
13
- def self.script_service(ctx:, api_key:)
14
- client = api_client(ctx: ctx, api_key: api_key)
15
- ScriptService.new(client: client, api_key: api_key)
16
- end
17
- end
18
- end
19
- end
20
- end
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Script
4
- module Layers
5
- module Infrastructure
6
- class SparseCheckoutDetails
7
- include SmartProperties
8
- property! :repo, accepts: String
9
- property! :branch, accepts: String
10
- property! :path, accepts: String
11
- property! :input_queries_enabled, accepts: [true, false]
12
-
13
- def ==(other)
14
- self.class == other.class &&
15
- self.class.properties.all? { |name, _| self[name] == other[name] }
16
- end
17
-
18
- def setup(ctx)
19
- ShopifyCLI::Git.sparse_checkout(repo, patterns_to_checkout, branch, ctx)
20
- end
21
-
22
- private
23
-
24
- def patterns_to_checkout
25
- paths = [path]
26
- unless input_queries_enabled
27
- paths << "!#{path}/#{ScriptProjectRepository::INPUT_QUERY_PATH}"
28
- paths << "!#{path}/schema.graphql"
29
- end
30
- paths.join(" ")
31
- end
32
- end
33
- end
34
- end
35
- end