shopify-cli 2.25.0 → 2.26.0

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