shopify-cli 2.7.3 → 2.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +44 -0
- data/Gemfile.lock +1 -1
- data/RELEASING.md +4 -3
- data/dev.yml +2 -2
- data/ext/javy/javy.rb +8 -9
- data/lib/graphql/get_extension_registrations.graphql +27 -0
- data/lib/project_types/extension/cli.rb +27 -2
- data/lib/project_types/extension/commands/build.rb +10 -10
- data/lib/project_types/extension/commands/create.rb +2 -3
- data/lib/project_types/extension/commands/push.rb +36 -8
- data/lib/project_types/extension/extension_project.rb +1 -1
- data/lib/project_types/extension/features/argo_serve.rb +6 -5
- data/lib/project_types/extension/forms/questions/ask_registration.rb +6 -2
- data/lib/project_types/extension/loaders/project.rb +29 -0
- data/lib/project_types/extension/loaders/specification_handler.rb +22 -0
- data/lib/project_types/extension/messages/messages.rb +4 -0
- data/lib/project_types/extension/models/app.rb +1 -1
- data/lib/project_types/extension/models/development_server.rb +2 -4
- data/lib/project_types/extension/models/specification_handlers/default.rb +4 -0
- data/lib/project_types/extension/tasks/convert_server_config.rb +3 -1
- data/lib/project_types/extension/tasks/execute_commands/base.rb +13 -0
- data/lib/project_types/extension/tasks/execute_commands/build.rb +29 -0
- data/lib/project_types/extension/tasks/execute_commands/create.rb +33 -0
- data/lib/project_types/extension/tasks/execute_commands/serve.rb +35 -0
- data/lib/project_types/extension/tasks/merge_server_config.rb +33 -22
- data/lib/project_types/rails/gem.rb +1 -2
- data/lib/project_types/script/cli.rb +7 -0
- data/lib/project_types/script/commands/connect.rb +19 -0
- data/lib/project_types/script/commands/create.rb +8 -2
- data/lib/project_types/script/commands/push.rb +35 -12
- data/lib/project_types/script/layers/application/connect_app.rb +15 -3
- data/lib/project_types/script/layers/application/create_script.rb +16 -16
- data/lib/project_types/script/layers/application/extension_points.rb +50 -26
- data/lib/project_types/script/layers/application/push_script.rb +5 -2
- data/lib/project_types/script/layers/domain/errors.rb +3 -2
- data/lib/project_types/script/layers/domain/extension_point.rb +14 -0
- data/lib/project_types/script/layers/domain/script_config.rb +6 -4
- data/lib/project_types/script/layers/infrastructure/errors.rb +38 -23
- data/lib/project_types/script/layers/infrastructure/script_project_repository.rb +49 -28
- data/lib/project_types/script/layers/infrastructure/script_service.rb +22 -5
- data/lib/project_types/script/loaders/project.rb +44 -0
- data/lib/project_types/script/loaders/specification_handler.rb +22 -0
- data/lib/project_types/script/messages/messages.rb +39 -16
- data/lib/project_types/script/ui/error_handler.rb +46 -29
- data/lib/project_types/theme/commands/pull.rb +45 -17
- data/lib/project_types/theme/commands/push.rb +65 -28
- data/lib/project_types/theme/commands/serve.rb +5 -0
- data/lib/project_types/theme/messages/messages.rb +34 -18
- data/lib/shopify_cli/command.rb +6 -0
- data/lib/shopify_cli/commands/login.rb +1 -1
- data/lib/shopify_cli/commands/switch.rb +1 -1
- data/lib/shopify_cli/constants.rb +11 -2
- data/lib/shopify_cli/context.rb +66 -12
- data/lib/shopify_cli/core/executor.rb +4 -4
- data/lib/shopify_cli/environment.rb +50 -20
- data/lib/shopify_cli/form.rb +2 -0
- data/lib/shopify_cli/identity_auth.rb +4 -3
- data/lib/shopify_cli/messages/messages.rb +9 -1
- data/lib/shopify_cli/method_object.rb +21 -9
- data/lib/shopify_cli/partners_api/app_extensions/job.rb +36 -0
- data/lib/shopify_cli/partners_api/app_extensions.rb +46 -0
- data/lib/shopify_cli/partners_api/organizations.rb +2 -5
- data/lib/shopify_cli/partners_api.rb +1 -0
- data/lib/shopify_cli/project.rb +8 -7
- data/lib/shopify_cli/resources/env_file.rb +18 -6
- data/lib/shopify_cli/result.rb +61 -59
- data/lib/shopify_cli/task.rb +5 -3
- data/lib/shopify_cli/theme/dev_server/cdn/cdn_helper.rb +49 -0
- data/lib/shopify_cli/theme/dev_server/cdn_assets.rb +69 -0
- data/lib/shopify_cli/theme/dev_server/cdn_fonts.rb +8 -28
- data/lib/shopify_cli/theme/dev_server/hot-reload.js +34 -3
- data/lib/shopify_cli/theme/dev_server/hot_reload.rb +18 -2
- data/lib/shopify_cli/theme/dev_server/local_assets.rb +4 -0
- data/lib/shopify_cli/theme/dev_server/proxy/template_param_builder.rb +84 -0
- data/lib/shopify_cli/theme/dev_server/proxy.rb +10 -15
- data/lib/shopify_cli/theme/dev_server/reload_mode.rb +34 -0
- data/lib/shopify_cli/theme/dev_server.rb +8 -21
- data/lib/shopify_cli/theme/file.rb +2 -2
- data/lib/shopify_cli/theme/filter/path_matcher.rb +38 -0
- data/lib/shopify_cli/theme/ignore_filter.rb +14 -18
- data/lib/shopify_cli/theme/include_filter.rb +43 -0
- data/lib/shopify_cli/theme/syncer.rb +17 -2
- data/lib/shopify_cli/theme/theme.rb +26 -4
- data/lib/shopify_cli/thread_pool/job.rb +27 -0
- data/lib/shopify_cli/thread_pool.rb +37 -0
- data/lib/shopify_cli/version.rb +1 -1
- data/lib/shopify_cli.rb +6 -1
- data/vendor/deps/cli-kit/lib/cli/kit/error_handler.rb +3 -1
- data/vendor/deps/ruby2_keywords/LICENSE +22 -0
- data/vendor/deps/ruby2_keywords/README.md +67 -0
- data/vendor/deps/ruby2_keywords/Rakefile +54 -0
- data/vendor/deps/ruby2_keywords/lib/ruby2_keywords.rb +57 -0
- data/vendor/deps/ruby2_keywords/ruby2_keywords.gemspec +18 -0
- data/vendor/deps/ruby2_keywords/test/test_keyword.rb +41 -0
- metadata +28 -4
- data/lib/graphql/all_orgs_with_extensions.graphql +0 -37
- data/lib/project_types/extension/tasks/run_extension_command.rb +0 -82
@@ -6,9 +6,26 @@ module Script
|
|
6
6
|
class ScriptProjectRepository
|
7
7
|
include SmartProperties
|
8
8
|
property! :ctx, accepts: ShopifyCLI::Context
|
9
|
+
property :directory, accepts: String
|
10
|
+
property :initial_directory, accepts: String
|
9
11
|
|
10
12
|
MUTABLE_ENV_VALUES = %i(uuid)
|
11
13
|
|
14
|
+
def create_project_directory
|
15
|
+
raise Infrastructure::Errors::ScriptProjectAlreadyExistsError, directory if ctx.dir_exist?(directory)
|
16
|
+
ctx.mkdir_p(directory)
|
17
|
+
change_directory(directory: directory)
|
18
|
+
end
|
19
|
+
|
20
|
+
def delete_project_directory
|
21
|
+
change_to_initial_directory
|
22
|
+
ctx.rm_r(directory)
|
23
|
+
end
|
24
|
+
|
25
|
+
def change_to_initial_directory
|
26
|
+
change_directory(directory: initial_directory)
|
27
|
+
end
|
28
|
+
|
12
29
|
def create(script_name:, extension_point_type:, language:)
|
13
30
|
validate_metadata!(extension_point_type, language)
|
14
31
|
|
@@ -95,6 +112,10 @@ module Script
|
|
95
112
|
|
96
113
|
private
|
97
114
|
|
115
|
+
def change_directory(directory:)
|
116
|
+
ctx.chdir(directory)
|
117
|
+
end
|
118
|
+
|
98
119
|
def capture_io(&block)
|
99
120
|
CLI::UI::StdoutRouter::Capture.new(&block).run
|
100
121
|
end
|
@@ -139,12 +160,15 @@ module Script
|
|
139
160
|
|
140
161
|
def script_config_repository
|
141
162
|
@script_config_repository ||= begin
|
163
|
+
script_config_yml_repo = ScriptConfigYmlRepository.new(ctx: ctx)
|
142
164
|
supported_repos = [
|
143
|
-
|
165
|
+
script_config_yml_repo,
|
144
166
|
ScriptJsonRepository.new(ctx: ctx),
|
145
167
|
]
|
146
168
|
repo = supported_repos.find(&:active?)
|
147
|
-
|
169
|
+
if repo.nil?
|
170
|
+
raise Infrastructure::Errors::NoScriptConfigFileError, script_config_yml_repo.filename
|
171
|
+
end
|
148
172
|
repo
|
149
173
|
end
|
150
174
|
end
|
@@ -158,7 +182,7 @@ module Script
|
|
158
182
|
end
|
159
183
|
|
160
184
|
def get!
|
161
|
-
raise Infrastructure::Errors::NoScriptConfigFileError unless active?
|
185
|
+
raise Infrastructure::Errors::NoScriptConfigFileError, filename unless active?
|
162
186
|
|
163
187
|
content = ctx.read(filename)
|
164
188
|
hash = file_content_to_hash(content)
|
@@ -175,6 +199,10 @@ module Script
|
|
175
199
|
from_h(hash)
|
176
200
|
end
|
177
201
|
|
202
|
+
def filename
|
203
|
+
raise NotImplementedError
|
204
|
+
end
|
205
|
+
|
178
206
|
private
|
179
207
|
|
180
208
|
def update_hash(hash:, title:)
|
@@ -183,14 +211,7 @@ module Script
|
|
183
211
|
end
|
184
212
|
|
185
213
|
def from_h(hash)
|
186
|
-
Domain::ScriptConfig.new(content: hash)
|
187
|
-
rescue Domain::Errors::MissingScriptConfigFieldError => e
|
188
|
-
raise missing_field_error, e.field
|
189
|
-
end
|
190
|
-
|
191
|
-
# to be implemented by subclasses
|
192
|
-
def filename
|
193
|
-
raise NotImplementedError
|
214
|
+
Domain::ScriptConfig.new(content: hash, filename: filename)
|
194
215
|
end
|
195
216
|
|
196
217
|
def file_content_to_hash(file_content)
|
@@ -200,26 +221,22 @@ module Script
|
|
200
221
|
def hash_to_file_content(hash)
|
201
222
|
raise NotImplementedError
|
202
223
|
end
|
203
|
-
|
204
|
-
def missing_field_error
|
205
|
-
raise NotImplementedError
|
206
|
-
end
|
207
224
|
end
|
208
225
|
|
209
226
|
class ScriptConfigYmlRepository < ScriptConfigRepository
|
210
|
-
private
|
211
|
-
|
212
227
|
def filename
|
213
228
|
"script.config.yml"
|
214
229
|
end
|
215
230
|
|
231
|
+
private
|
232
|
+
|
216
233
|
def file_content_to_hash(file_content)
|
217
234
|
begin
|
218
235
|
hash = YAML.load(file_content)
|
219
236
|
rescue Psych::SyntaxError
|
220
|
-
raise
|
237
|
+
raise parse_error
|
221
238
|
end
|
222
|
-
raise
|
239
|
+
raise parse_error unless hash.is_a?(Hash)
|
223
240
|
hash
|
224
241
|
end
|
225
242
|
|
@@ -227,30 +244,34 @@ module Script
|
|
227
244
|
YAML.dump(hash)
|
228
245
|
end
|
229
246
|
|
230
|
-
def
|
231
|
-
Errors::
|
247
|
+
def parse_error
|
248
|
+
Errors::ScriptConfigParseError.new(filename: filename, serialization_format: "YAML")
|
232
249
|
end
|
233
250
|
end
|
234
251
|
|
235
252
|
class ScriptJsonRepository < ScriptConfigRepository
|
236
|
-
private
|
237
|
-
|
238
253
|
def filename
|
239
254
|
"script.json"
|
240
255
|
end
|
241
256
|
|
257
|
+
private
|
258
|
+
|
242
259
|
def file_content_to_hash(file_content)
|
243
|
-
|
244
|
-
|
245
|
-
|
260
|
+
begin
|
261
|
+
hash = JSON.parse(file_content)
|
262
|
+
rescue JSON::ParserError
|
263
|
+
raise parse_error
|
264
|
+
end
|
265
|
+
raise parse_error unless hash.is_a?(Hash)
|
266
|
+
hash
|
246
267
|
end
|
247
268
|
|
248
269
|
def hash_to_file_content(hash)
|
249
270
|
JSON.pretty_generate(hash)
|
250
271
|
end
|
251
272
|
|
252
|
-
def
|
253
|
-
Errors::
|
273
|
+
def parse_error
|
274
|
+
Errors::ScriptConfigParseError.new(filename: filename, serialization_format: "JSON")
|
254
275
|
end
|
255
276
|
end
|
256
277
|
end
|
@@ -46,20 +46,37 @@ module Script
|
|
46
46
|
|
47
47
|
if user_errors.any? { |e| e["tag"] == "already_exists_error" }
|
48
48
|
raise Errors::ScriptRepushError, uuid
|
49
|
+
elsif (e = user_errors.find { |err| err["tag"] == "configuration_definition_error" })
|
50
|
+
raise Errors::ScriptConfigurationDefinitionError.new(
|
51
|
+
message: e["message"],
|
52
|
+
filename: script_config.filename,
|
53
|
+
)
|
49
54
|
elsif (e = user_errors.any? { |err| err["tag"] == "configuration_definition_syntax_error" })
|
50
|
-
raise Errors::ScriptConfigSyntaxError
|
55
|
+
raise Errors::ScriptConfigSyntaxError, script_config.filename
|
51
56
|
elsif (e = user_errors.find { |err| err["tag"] == "configuration_definition_missing_keys_error" })
|
52
|
-
raise Errors::ScriptConfigMissingKeysError
|
57
|
+
raise Errors::ScriptConfigMissingKeysError.new(
|
58
|
+
missing_keys: e["message"],
|
59
|
+
filename: script_config.filename,
|
60
|
+
)
|
53
61
|
elsif (e = user_errors.find { |err| err["tag"] == "configuration_definition_invalid_value_error" })
|
54
|
-
raise Errors::ScriptConfigInvalidValueError
|
62
|
+
raise Errors::ScriptConfigInvalidValueError.new(
|
63
|
+
valid_input_modes: e["message"],
|
64
|
+
filename: script_config.filename,
|
65
|
+
)
|
55
66
|
elsif (e = user_errors.find do |err|
|
56
67
|
err["tag"] == "configuration_definition_schema_field_missing_keys_error"
|
57
68
|
end)
|
58
|
-
raise Errors::ScriptConfigFieldsMissingKeysError
|
69
|
+
raise Errors::ScriptConfigFieldsMissingKeysError.new(
|
70
|
+
missing_keys: e["message"],
|
71
|
+
filename: script_config.filename,
|
72
|
+
)
|
59
73
|
elsif (e = user_errors.find do |err|
|
60
74
|
err["tag"] == "configuration_definition_schema_field_invalid_value_error"
|
61
75
|
end)
|
62
|
-
raise Errors::ScriptConfigFieldsInvalidValueError
|
76
|
+
raise Errors::ScriptConfigFieldsInvalidValueError.new(
|
77
|
+
valid_types: e["message"],
|
78
|
+
filename: script_config.filename,
|
79
|
+
)
|
63
80
|
elsif user_errors.find { |err| %w(not_use_msgpack_error schema_version_argument_error).include?(err["tag"]) }
|
64
81
|
raise Domain::Errors::MetadataValidationError
|
65
82
|
else
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Script
|
4
|
+
module Loaders
|
5
|
+
module Project
|
6
|
+
def self.load(directory:, api_key:, uuid:, api_secret:, context: ShopifyCLI::Context.new)
|
7
|
+
env_overrides = {
|
8
|
+
"SHOPIFY_API_KEY" => api_key,
|
9
|
+
"SHOPIFY_API_SECRET" => api_secret,
|
10
|
+
"UUID" => uuid,
|
11
|
+
}.compact
|
12
|
+
env_file_present = env_file_exists?(directory)
|
13
|
+
env = if env_file_present
|
14
|
+
ShopifyCLI::Resources::EnvFile.read(directory, overrides: env_overrides)
|
15
|
+
else
|
16
|
+
ShopifyCLI::Resources::EnvFile.from_hash(env_overrides)
|
17
|
+
end
|
18
|
+
|
19
|
+
project = ShopifyCLI::Project.at(directory)
|
20
|
+
project.env = env
|
21
|
+
project
|
22
|
+
rescue SmartProperties::InitializationError, SmartProperties::InvalidValueError => error
|
23
|
+
handle_error(error, context: context, env_file_present: env_file_present)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.handle_error(error, context:, env_file_present:)
|
27
|
+
if env_file_present
|
28
|
+
properties_hash = { api_key: "SHOPIFY_API_KEY", secret: "SHOPIFY_API_SECRET" }
|
29
|
+
missing_env_variables = error.properties.map { |p| properties_hash[p.name] }.compact.join(", ")
|
30
|
+
raise ShopifyCLI::Abort,
|
31
|
+
context.message("script.error.missing_env_file_variables", missing_env_variables, ShopifyCLI::TOOL_NAME)
|
32
|
+
else
|
33
|
+
properties_hash = { api_key: "--api-key", secret: "--api-secret" }
|
34
|
+
missing_options = error.properties.map { |p| properties_hash[p.name] }.compact.join(", ")
|
35
|
+
raise ShopifyCLI::Abort, context.message("script.error.missing_push_options", missing_options)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.env_file_exists?(directory)
|
40
|
+
File.exist?(ShopifyCLI::Resources::EnvFile.path(directory))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Script
|
4
|
+
module Loaders
|
5
|
+
module SpecificationHandler
|
6
|
+
def self.load(project:, context:)
|
7
|
+
identifier = project.specification_identifier
|
8
|
+
Models::LazySpecificationHandler.new(identifier) do
|
9
|
+
specifications = Models::Specifications.new(
|
10
|
+
fetch_specifications: Tasks::FetchSpecifications.new(api_key: project.app.api_key, context: context)
|
11
|
+
)
|
12
|
+
|
13
|
+
unless specifications.valid?(identifier)
|
14
|
+
context.abort(context.message("errors.unknown_type", project.specification_identifier))
|
15
|
+
end
|
16
|
+
|
17
|
+
specifications[identifier]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -47,38 +47,39 @@ module Script
|
|
47
47
|
invalid_language_cause: "Invalid language %s.",
|
48
48
|
invalid_language_help: "Allowed values: %s.",
|
49
49
|
|
50
|
-
|
51
|
-
|
50
|
+
missing_script_config_field_cause: "The %{filename} file is missing the required %{field} field.",
|
51
|
+
missing_script_config_field_help: "Add the field and try again.",
|
52
52
|
|
53
|
-
|
54
|
-
|
53
|
+
script_config_parse_error_cause: "The %{filename} file contains invalid %{serialization_format}.",
|
54
|
+
script_config_parse_error_help: "Fix the errors and try again.",
|
55
55
|
|
56
|
-
|
57
|
-
|
56
|
+
no_script_config_file_cause: "The %{filename} file is missing.",
|
57
|
+
no_script_config_file_help: "Create this file and try again.",
|
58
58
|
|
59
|
-
|
60
|
-
|
59
|
+
app_not_connected_cause: "Script is not connected to an app.",
|
60
|
+
app_not_connected_help: "Run shopify connect or enter fields for api-key and api-secret.",
|
61
61
|
|
62
|
-
|
63
|
-
|
62
|
+
configuration_definition_error_cause: "In the %{filename} file, there was a problem with the "\
|
63
|
+
"configuration. %{message}",
|
64
|
+
configuration_definition_error_help: "Fix the error and try again.",
|
64
65
|
|
65
|
-
configuration_syntax_error_cause: "The
|
66
|
+
configuration_syntax_error_cause: "The %{filename} is not formatted properly.",
|
66
67
|
configuration_syntax_error_help: "Fix the errors and try again.",
|
67
68
|
|
68
|
-
configuration_missing_keys_error_cause: "The
|
69
|
+
configuration_missing_keys_error_cause: "The %{filename} file is missing required keys: "\
|
69
70
|
"%{missing_keys}.",
|
70
71
|
configuration_missing_keys_error_help: "Add the keys and try again.",
|
71
72
|
|
72
|
-
configuration_invalid_value_error_cause: "The
|
73
|
+
configuration_invalid_value_error_cause: "The %{filename} configuration only accepts "\
|
73
74
|
"one of the following types(s): %{valid_input_modes}.",
|
74
75
|
configuration_invalid_value_error_help: "Change the type and try again.",
|
75
76
|
|
76
|
-
configuration_schema_field_missing_keys_error_cause: "A configuration entry in the
|
77
|
+
configuration_schema_field_missing_keys_error_cause: "A configuration entry in the %{filename} file "\
|
77
78
|
"is missing required keys: %{missing_keys}.",
|
78
79
|
configuration_definition_schema_field_missing_keys_error_help: "Add the keys and try again.",
|
79
80
|
|
80
81
|
configuration_schema_field_invalid_value_error_cause: "The configuration entries in the "\
|
81
|
-
"
|
82
|
+
"%{filename} file only accept one of the following "\
|
82
83
|
"type(s): %{valid_types}.",
|
83
84
|
configuration_schema_field_invalid_value_error_help: "Change the types and try again.",
|
84
85
|
|
@@ -144,6 +145,12 @@ module Script
|
|
144
145
|
|
145
146
|
language_library_for_api_not_found_cause: "Script can’t be pushed because the %{language} library for API %{api} is missing.",
|
146
147
|
language_library_for_api_not_found_help: "Make sure extension_point.yml contains the correct API library.",
|
148
|
+
no_scripts_found_in_app: "The selected apps have no scripts. Please, create them first on the partners' dashboard.",
|
149
|
+
missing_env_file_variables: "The following variables are missing in the .env file: %s."\
|
150
|
+
" It might happen when the script hasn't been previously connected to an app."\
|
151
|
+
" To connect the script to an app, run {{command:%s script connect}}",
|
152
|
+
missing_push_options: "The following options are required: %s."\
|
153
|
+
" You can obtain them from the .env file generated after connecting the script to an app.",
|
147
154
|
},
|
148
155
|
|
149
156
|
create: {
|
@@ -153,6 +160,7 @@ module Script
|
|
153
160
|
Options:
|
154
161
|
{{command:--name=NAME}} Script project name. Use any string.
|
155
162
|
{{command:--api=TYPE}} Script API name. Allowed values: %2$s.
|
163
|
+
{{command:--language=LANGUAGE}} Programming language. Allowed values: %3$s.
|
156
164
|
HELP
|
157
165
|
|
158
166
|
error: {
|
@@ -170,16 +178,31 @@ module Script
|
|
170
178
|
Usage: {{command:%s script push}}
|
171
179
|
Options:
|
172
180
|
{{command:[--force]}} Replaces the existing script on the app with this version.
|
181
|
+
{{command:[--api-key=API_KEY]}} The API key used to register an app with the script. This can be found on the app page on Partners Dashboard. Overrides the value in the .env file, if present.
|
182
|
+
{{command:[--api-secret=API_SECRET]}} The API secret of the app the script is registered with. Overrides the value in the .env file, if present.
|
183
|
+
{{command:[--uuid=UUID]}} The uuid of the script. Overrides the value in the .env file, if present.
|
173
184
|
HELP
|
174
185
|
|
175
186
|
error: {
|
187
|
+
operation_failed_no_uuid: "UUID is required to push in a CI environment.",
|
176
188
|
operation_failed_with_api_key: "Couldn't push script to app (API key: %{api_key}).",
|
177
189
|
operation_failed_no_api_key: "Couldn't push script to app.",
|
178
190
|
},
|
179
191
|
|
180
192
|
script_pushed: "{{v}} Script pushed to app (API key: %{api_key}).",
|
181
193
|
},
|
182
|
-
|
194
|
+
connect: {
|
195
|
+
connected: "Connected! Your project is now connected to {{green:%s}}",
|
196
|
+
help: <<~HELP,
|
197
|
+
{{command:%s script connect}}: Connects an existing script to an app.
|
198
|
+
Usage: {{command:%s script connect}}
|
199
|
+
HELP
|
200
|
+
error: {
|
201
|
+
operation_failed: "Couldn't connect script to app.",
|
202
|
+
missing_env_file_variables: "The following variables are missing in the .env file: %s."\
|
203
|
+
" To connect the script to an app, either enter the value into the .env file or delete the .env file, then run {{command:%s script connect}}",
|
204
|
+
},
|
205
|
+
},
|
183
206
|
javy: {
|
184
207
|
help: <<~HELP,
|
185
208
|
Compile the JavaScript code into WebAssembly.
|
@@ -103,51 +103,65 @@ module Script
|
|
103
103
|
cause_of_error: ShopifyCLI::Context.message("script.error.metadata_not_found_cause"),
|
104
104
|
help_suggestion: ShopifyCLI::Context.message("script.error.metadata_not_found_help"),
|
105
105
|
}
|
106
|
+
when Layers::Domain::Errors::MissingScriptConfigFieldError
|
107
|
+
{
|
108
|
+
cause_of_error: ShopifyCLI::Context.message(
|
109
|
+
"script.error.missing_script_config_field_cause",
|
110
|
+
field: e.field,
|
111
|
+
filename: e.filename,
|
112
|
+
),
|
113
|
+
help_suggestion: ShopifyCLI::Context.message("script.error.missing_script_config_field_help"),
|
114
|
+
}
|
106
115
|
when Layers::Infrastructure::Errors::BuildError
|
107
116
|
{
|
108
117
|
cause_of_error: ShopifyCLI::Context.message("script.error.build_error_cause"),
|
109
118
|
help_suggestion: ShopifyCLI::Context.message("script.error.build_error_help"),
|
110
119
|
}
|
111
|
-
when Layers::Infrastructure::Errors::
|
112
|
-
{
|
113
|
-
cause_of_error: ShopifyCLI::Context.message("script.error.invalid_script_config_yml_definition_cause"),
|
114
|
-
help_suggestion: ShopifyCLI::Context.message("script.error.invalid_script_config_yml_definition_help"),
|
115
|
-
}
|
116
|
-
when Layers::Infrastructure::Errors::InvalidScriptJsonDefinitionError
|
117
|
-
{
|
118
|
-
cause_of_error: ShopifyCLI::Context.message("script.error.invalid_script_json_definition_cause"),
|
119
|
-
help_suggestion: ShopifyCLI::Context.message("script.error.invalid_script_json_definition_help"),
|
120
|
-
}
|
121
|
-
when Layers::Infrastructure::Errors::MissingScriptConfigYmlFieldError
|
122
|
-
{
|
123
|
-
cause_of_error: ShopifyCLI::Context.message("script.error.missing_script_config_yml_field_cause", e.field),
|
124
|
-
help_suggestion: ShopifyCLI::Context.message("script.error.missing_script_config_yml_field_help"),
|
125
|
-
}
|
126
|
-
when Layers::Infrastructure::Errors::MissingScriptConfigYmlFieldError
|
120
|
+
when Layers::Infrastructure::Errors::ScriptConfigParseError
|
127
121
|
{
|
128
|
-
cause_of_error: ShopifyCLI::Context.message(
|
129
|
-
|
122
|
+
cause_of_error: ShopifyCLI::Context.message(
|
123
|
+
"script.error.script_config_parse_error_cause",
|
124
|
+
filename: e.filename,
|
125
|
+
serialization_format: e.serialization_format,
|
126
|
+
),
|
127
|
+
help_suggestion: ShopifyCLI::Context.message("script.error.script_config_parse_error_help"),
|
130
128
|
}
|
131
|
-
when Layers::Infrastructure::Errors::
|
129
|
+
when Layers::Infrastructure::Errors::NoScriptConfigFileError
|
132
130
|
{
|
133
|
-
cause_of_error: ShopifyCLI::Context.message(
|
134
|
-
|
131
|
+
cause_of_error: ShopifyCLI::Context.message(
|
132
|
+
"script.error.no_script_config_file_cause",
|
133
|
+
filename: e.filename,
|
134
|
+
),
|
135
|
+
help_suggestion: ShopifyCLI::Context.message("script.error.no_script_config_file_help"),
|
135
136
|
}
|
136
|
-
when Layers::Infrastructure::Errors::
|
137
|
+
when Layers::Infrastructure::Errors::ScriptConfigurationDefinitionError
|
137
138
|
{
|
138
|
-
cause_of_error: ShopifyCLI::Context.message(
|
139
|
-
|
139
|
+
cause_of_error: ShopifyCLI::Context.message(
|
140
|
+
"script.error.configuration_definition_error_cause",
|
141
|
+
message: e.message,
|
142
|
+
filename: e.filename,
|
143
|
+
),
|
144
|
+
help_suggestion: ShopifyCLI::Context.message("script.error.configuration_definition_error_help"),
|
140
145
|
}
|
141
146
|
when Layers::Infrastructure::Errors::ScriptConfigSyntaxError
|
142
147
|
{
|
143
|
-
cause_of_error: ShopifyCLI::Context.message(
|
148
|
+
cause_of_error: ShopifyCLI::Context.message(
|
149
|
+
"script.error.configuration_syntax_error_cause",
|
150
|
+
filename: e.filename,
|
151
|
+
),
|
144
152
|
help_suggestion: ShopifyCLI::Context.message("script.error.configuration_syntax_error_help"),
|
145
153
|
}
|
154
|
+
when Layers::Infrastructure::Errors::ScriptEnvAppNotConnectedError
|
155
|
+
{
|
156
|
+
cause_of_error: ShopifyCLI::Context.message("script.error.app_not_connected_cause"),
|
157
|
+
help_suggestion: ShopifyCLI::Context.message("script.error.app_not_connected_help"),
|
158
|
+
}
|
146
159
|
when Layers::Infrastructure::Errors::ScriptConfigMissingKeysError
|
147
160
|
{
|
148
161
|
cause_of_error: ShopifyCLI::Context.message(
|
149
162
|
"script.error.configuration_missing_keys_error_cause",
|
150
|
-
missing_keys: e.missing_keys
|
163
|
+
missing_keys: e.missing_keys,
|
164
|
+
filename: e.filename,
|
151
165
|
),
|
152
166
|
help_suggestion: ShopifyCLI::Context.message("script.error.configuration_missing_keys_error_help"),
|
153
167
|
}
|
@@ -155,7 +169,8 @@ module Script
|
|
155
169
|
{
|
156
170
|
cause_of_error: ShopifyCLI::Context.message(
|
157
171
|
"script.error.configuration_invalid_value_error_cause",
|
158
|
-
valid_input_modes: e.valid_input_modes
|
172
|
+
valid_input_modes: e.valid_input_modes,
|
173
|
+
filename: e.filename,
|
159
174
|
),
|
160
175
|
help_suggestion: ShopifyCLI::Context.message("script.error.configuration_invalid_value_error_help"),
|
161
176
|
}
|
@@ -163,7 +178,8 @@ module Script
|
|
163
178
|
{
|
164
179
|
cause_of_error: ShopifyCLI::Context.message(
|
165
180
|
"script.error.configuration_schema_field_missing_keys_error_cause",
|
166
|
-
missing_keys: e.missing_keys
|
181
|
+
missing_keys: e.missing_keys,
|
182
|
+
filename: e.filename,
|
167
183
|
),
|
168
184
|
help_suggestion: ShopifyCLI::Context.message(
|
169
185
|
"script.error.configuration_definition_schema_field_missing_keys_error_help"
|
@@ -173,7 +189,8 @@ module Script
|
|
173
189
|
{
|
174
190
|
cause_of_error: ShopifyCLI::Context.message(
|
175
191
|
"script.error.configuration_schema_field_invalid_value_error_cause",
|
176
|
-
valid_types: e.valid_types
|
192
|
+
valid_types: e.valid_types,
|
193
|
+
filename: e.filename,
|
177
194
|
),
|
178
195
|
help_suggestion: ShopifyCLI::Context.message(
|
179
196
|
"script.error.configuration_schema_field_invalid_value_error_help"
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require "shopify_cli/theme/theme"
|
3
3
|
require "shopify_cli/theme/ignore_filter"
|
4
|
+
require "shopify_cli/theme/include_filter"
|
4
5
|
require "shopify_cli/theme/syncer"
|
5
6
|
|
6
7
|
module Theme
|
@@ -9,7 +10,10 @@ module Theme
|
|
9
10
|
options do |parser, flags|
|
10
11
|
parser.on("-n", "--nodelete") { flags[:nodelete] = true }
|
11
12
|
parser.on("-i", "--themeid=ID") { |theme_id| flags[:theme_id] = theme_id }
|
13
|
+
parser.on("-t", "--theme=NAME_OR_ID") { |theme| flags[:theme] = theme }
|
12
14
|
parser.on("-l", "--live") { flags[:live] = true }
|
15
|
+
parser.on("-d", "--development") { flags[:development] = true }
|
16
|
+
parser.on("-o", "--only=PATTERN") { |pattern| flags[:includes] = pattern }
|
13
17
|
parser.on("-x", "--ignore=PATTERN") do |pattern|
|
14
18
|
flags[:ignores] ||= []
|
15
19
|
flags[:ignores] << pattern
|
@@ -19,26 +23,16 @@ module Theme
|
|
19
23
|
def call(args, _name)
|
20
24
|
root = args.first || "."
|
21
25
|
delete = !options.flags[:nodelete]
|
26
|
+
theme = find_theme(root, **options.flags)
|
27
|
+
return if theme.nil?
|
22
28
|
|
23
|
-
|
24
|
-
ShopifyCLI::Theme::Theme.new(@ctx, root: root, id: theme_id)
|
25
|
-
elsif options.flags[:live]
|
26
|
-
ShopifyCLI::Theme::Theme.live(@ctx, root: root)
|
27
|
-
else
|
28
|
-
form = Forms::Select.ask(
|
29
|
-
@ctx,
|
30
|
-
[],
|
31
|
-
title: @ctx.message("theme.pull.select"),
|
32
|
-
root: root,
|
33
|
-
)
|
34
|
-
return unless form
|
35
|
-
form.theme
|
36
|
-
end
|
37
|
-
|
29
|
+
include_filter = ShopifyCLI::Theme::IncludeFilter.new(options.flags[:includes])
|
38
30
|
ignore_filter = ShopifyCLI::Theme::IgnoreFilter.from_path(root)
|
39
31
|
ignore_filter.add_patterns(options.flags[:ignores]) if options.flags[:ignores]
|
40
32
|
|
41
|
-
syncer = ShopifyCLI::Theme::Syncer.new(@ctx, theme: theme,
|
33
|
+
syncer = ShopifyCLI::Theme::Syncer.new(@ctx, theme: theme,
|
34
|
+
include_filter: include_filter,
|
35
|
+
ignore_filter: ignore_filter)
|
42
36
|
begin
|
43
37
|
syncer.start_threads
|
44
38
|
CLI::UI::Frame.open(@ctx.message("theme.pull.pulling", theme.name, theme.id, theme.shop)) do
|
@@ -46,7 +40,7 @@ module Theme
|
|
46
40
|
end
|
47
41
|
@ctx.done(@ctx.message("theme.pull.done"))
|
48
42
|
rescue ShopifyCLI::API::APIRequestNotFoundError
|
49
|
-
@ctx.abort(@ctx.message("theme.pull.theme_not_found", theme.id))
|
43
|
+
@ctx.abort(@ctx.message("theme.pull.theme_not_found", "##{theme.id}"))
|
50
44
|
ensure
|
51
45
|
syncer.shutdown
|
52
46
|
end
|
@@ -55,6 +49,40 @@ module Theme
|
|
55
49
|
def self.help
|
56
50
|
ShopifyCLI::Context.message("theme.pull.help", ShopifyCLI::TOOL_NAME, ShopifyCLI::TOOL_NAME)
|
57
51
|
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def find_theme(root, theme_id: nil, theme: nil, live: nil, development: nil, **_args)
|
56
|
+
if theme_id
|
57
|
+
@ctx.warn(@ctx.message("theme.pull.deprecated_themeid"))
|
58
|
+
return ShopifyCLI::Theme::Theme.new(@ctx, root: root, id: theme_id)
|
59
|
+
end
|
60
|
+
|
61
|
+
if theme
|
62
|
+
selected_theme = ShopifyCLI::Theme::Theme.find_by_identifier(@ctx, root: root, identifier: theme)
|
63
|
+
return selected_theme || @ctx.abort(@ctx.message("theme.pull.theme_not_found", theme))
|
64
|
+
end
|
65
|
+
|
66
|
+
if live
|
67
|
+
return ShopifyCLI::Theme::Theme.live(@ctx, root: root)
|
68
|
+
end
|
69
|
+
|
70
|
+
if development
|
71
|
+
return ShopifyCLI::Theme::Theme.development(@ctx, root: root)
|
72
|
+
end
|
73
|
+
|
74
|
+
select_theme(root)
|
75
|
+
end
|
76
|
+
|
77
|
+
def select_theme(root)
|
78
|
+
form = Forms::Select.ask(
|
79
|
+
@ctx,
|
80
|
+
[],
|
81
|
+
title: @ctx.message("theme.pull.select"),
|
82
|
+
root: root,
|
83
|
+
)
|
84
|
+
form&.theme
|
85
|
+
end
|
58
86
|
end
|
59
87
|
end
|
60
88
|
end
|