shopify-cli 2.7.2 → 2.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +2 -2
  3. data/.github/workflows/shopify.yml +1 -1
  4. data/.gitignore +1 -0
  5. data/.ruby-version +1 -1
  6. data/CHANGELOG.md +52 -0
  7. data/Codespace.dockerfile +2 -2
  8. data/Gemfile.lock +4 -4
  9. data/RELEASING.md +4 -3
  10. data/Tests.dockerfile +2 -2
  11. data/dev.yml +3 -3
  12. data/ext/javy/hashes/javy-arm-macos-v0.1.0.gz.sha256 +1 -0
  13. data/ext/javy/hashes/javy-x86_64-linux-v0.1.0.gz.sha256 +1 -0
  14. data/ext/javy/hashes/javy-x86_64-macos-v0.1.0.gz.sha256 +1 -0
  15. data/ext/javy/hashes/javy-x86_64-windows-v0.1.0.gz.sha256 +1 -0
  16. data/ext/javy/javy.rb +31 -13
  17. data/lib/graphql/get_extension_registrations.graphql +27 -0
  18. data/lib/project_types/extension/cli.rb +27 -2
  19. data/lib/project_types/extension/commands/build.rb +10 -10
  20. data/lib/project_types/extension/commands/create.rb +2 -3
  21. data/lib/project_types/extension/commands/push.rb +36 -8
  22. data/lib/project_types/extension/extension_project.rb +1 -1
  23. data/lib/project_types/extension/features/argo_serve.rb +6 -5
  24. data/lib/project_types/extension/forms/questions/ask_registration.rb +6 -2
  25. data/lib/project_types/extension/loaders/project.rb +29 -0
  26. data/lib/project_types/extension/loaders/specification_handler.rb +22 -0
  27. data/lib/project_types/extension/messages/messages.rb +4 -0
  28. data/lib/project_types/extension/models/app.rb +1 -1
  29. data/lib/project_types/extension/models/development_server.rb +2 -4
  30. data/lib/project_types/extension/models/specification_handlers/default.rb +4 -0
  31. data/lib/project_types/extension/tasks/convert_server_config.rb +3 -1
  32. data/lib/project_types/extension/tasks/execute_commands/base.rb +13 -0
  33. data/lib/project_types/extension/tasks/execute_commands/build.rb +29 -0
  34. data/lib/project_types/extension/tasks/execute_commands/create.rb +33 -0
  35. data/lib/project_types/extension/tasks/execute_commands/serve.rb +35 -0
  36. data/lib/project_types/extension/tasks/merge_server_config.rb +33 -22
  37. data/lib/project_types/rails/commands/create.rb +1 -1
  38. data/lib/project_types/rails/gem.rb +1 -2
  39. data/lib/project_types/script/cli.rb +8 -1
  40. data/lib/project_types/script/commands/connect.rb +19 -0
  41. data/lib/project_types/script/commands/create.rb +8 -2
  42. data/lib/project_types/script/commands/push.rb +35 -12
  43. data/lib/project_types/script/config/extension_points.yml +10 -2
  44. data/lib/project_types/script/graphql/app_script_set.graphql +2 -2
  45. data/lib/project_types/script/layers/application/connect_app.rb +15 -3
  46. data/lib/project_types/script/layers/application/create_script.rb +17 -17
  47. data/lib/project_types/script/layers/application/extension_points.rb +50 -26
  48. data/lib/project_types/script/layers/application/push_script.rb +6 -3
  49. data/lib/project_types/script/layers/domain/errors.rb +1 -4
  50. data/lib/project_types/script/layers/domain/extension_point.rb +14 -0
  51. data/lib/project_types/script/layers/domain/push_package.rb +3 -3
  52. data/lib/project_types/script/layers/domain/{script_json.rb → script_config.rb} +2 -2
  53. data/lib/project_types/script/layers/domain/script_project.rb +1 -1
  54. data/lib/project_types/script/layers/infrastructure/errors.rb +30 -5
  55. data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +2 -2
  56. data/lib/project_types/script/layers/infrastructure/script_project_repository.rb +125 -27
  57. data/lib/project_types/script/layers/infrastructure/script_service.rb +11 -11
  58. data/lib/project_types/script/loaders/project.rb +44 -0
  59. data/lib/project_types/script/loaders/specification_handler.rb +22 -0
  60. data/lib/project_types/script/messages/messages.rb +34 -3
  61. data/lib/project_types/script/ui/error_handler.rb +35 -15
  62. data/lib/project_types/theme/commands/pull.rb +39 -16
  63. data/lib/project_types/theme/commands/push.rb +60 -29
  64. data/lib/project_types/theme/commands/serve.rb +5 -0
  65. data/lib/project_types/theme/messages/messages.rb +30 -18
  66. data/lib/shopify_cli/command.rb +6 -0
  67. data/lib/shopify_cli/commands/login.rb +11 -5
  68. data/lib/shopify_cli/commands/switch.rb +1 -1
  69. data/lib/shopify_cli/constants.rb +5 -0
  70. data/lib/shopify_cli/context.rb +66 -11
  71. data/lib/shopify_cli/environment.rb +15 -4
  72. data/lib/shopify_cli/form.rb +2 -0
  73. data/lib/shopify_cli/git.rb +2 -0
  74. data/lib/shopify_cli/identity_auth.rb +1 -0
  75. data/lib/shopify_cli/messages/messages.rb +10 -2
  76. data/lib/shopify_cli/partners_api/app_extensions/job.rb +36 -0
  77. data/lib/shopify_cli/partners_api/app_extensions.rb +46 -0
  78. data/lib/shopify_cli/partners_api/organizations.rb +2 -5
  79. data/lib/shopify_cli/partners_api.rb +1 -0
  80. data/lib/shopify_cli/project.rb +8 -7
  81. data/lib/shopify_cli/resources/env_file.rb +18 -6
  82. data/lib/shopify_cli/services/app/create/rails_service.rb +1 -1
  83. data/lib/shopify_cli/theme/dev_server/cdn_fonts.rb +73 -0
  84. data/lib/shopify_cli/theme/dev_server/hot-reload.js +57 -10
  85. data/lib/shopify_cli/theme/dev_server/hot_reload.rb +18 -2
  86. data/lib/shopify_cli/theme/dev_server/proxy/template_param_builder.rb +84 -0
  87. data/lib/shopify_cli/theme/dev_server/proxy.rb +10 -15
  88. data/lib/shopify_cli/theme/dev_server/reload_mode.rb +34 -0
  89. data/lib/shopify_cli/theme/dev_server.rb +8 -21
  90. data/lib/shopify_cli/theme/theme.rb +26 -4
  91. data/lib/shopify_cli/thread_pool/job.rb +27 -0
  92. data/lib/shopify_cli/thread_pool.rb +37 -0
  93. data/lib/shopify_cli/tunnel.rb +1 -0
  94. data/lib/shopify_cli/version.rb +1 -1
  95. data/lib/shopify_cli.rb +4 -0
  96. data/shopify-cli.gemspec +1 -1
  97. data/vendor/deps/cli-kit/lib/cli/kit/error_handler.rb +3 -1
  98. metadata +26 -7
  99. data/lib/graphql/all_orgs_with_extensions.graphql +0 -37
  100. data/lib/project_types/extension/tasks/run_extension_command.rb +0 -82
@@ -5,9 +5,10 @@ module Script
5
5
  module Application
6
6
  class PushScript
7
7
  class << self
8
- def call(ctx:, force:)
8
+ def call(ctx:, force:, project:)
9
9
  script_project_repo = Infrastructure::ScriptProjectRepository.new(ctx: ctx)
10
10
  script_project = script_project_repo.get
11
+ script_project.env = project.env
11
12
  task_runner = Infrastructure::Languages::TaskRunner
12
13
  .for(ctx, script_project.language, script_project.script_name)
13
14
 
@@ -43,11 +44,13 @@ module Script
43
44
  extension_point_type: package.extension_point_type,
44
45
  force: force,
45
46
  metadata: package.metadata,
46
- script_json: package.script_json,
47
+ script_config: package.script_config,
47
48
  module_upload_url: module_upload_url,
48
49
  library: package.library,
49
50
  )
50
- script_project_repo.update_env(uuid: uuid)
51
+ if ShopifyCLI::Environment.interactive?
52
+ script_project_repo.update_env(uuid: uuid)
53
+ end
51
54
  spinner.update_title(p_ctx.message("script.application.pushed"))
52
55
  end
53
56
  end
@@ -14,7 +14,7 @@ module Script
14
14
  end
15
15
  end
16
16
 
17
- class MissingScriptJsonFieldError < ScriptProjectError
17
+ class MissingScriptConfigFieldError < ScriptProjectError
18
18
  attr_reader :field
19
19
  def initialize(field)
20
20
  super()
@@ -22,9 +22,6 @@ module Script
22
22
  end
23
23
  end
24
24
 
25
- class InvalidScriptJsonDefinitionError < ScriptProjectError; end
26
- class NoScriptJsonFile < ScriptProjectError; end
27
-
28
25
  class ScriptNotFoundError < ScriptProjectError
29
26
  attr_reader :script_name, :extension_point_type
30
27
  def initialize(extension_point_type, script_name)
@@ -18,6 +18,10 @@ module Script
18
18
  @beta
19
19
  end
20
20
 
21
+ def stable?
22
+ !beta?
23
+ end
24
+
21
25
  def deprecated?
22
26
  @deprecated
23
27
  end
@@ -26,6 +30,12 @@ module Script
26
30
  @type.gsub("_", "-")
27
31
  end
28
32
 
33
+ def library_languages(include_betas: false)
34
+ @libraries.all.map do |library|
35
+ include_betas || library.stable? ? library.language : nil
36
+ end.compact
37
+ end
38
+
29
39
  class ExtensionPointLibraries
30
40
  def initialize(config)
31
41
  @config = config
@@ -57,6 +67,10 @@ module Script
57
67
  @beta
58
68
  end
59
69
 
70
+ def stable?
71
+ !beta?
72
+ end
73
+
60
74
  def versioned?
61
75
  @version
62
76
  end
@@ -7,7 +7,7 @@ module Script
7
7
  attr_reader :id,
8
8
  :uuid,
9
9
  :extension_point_type,
10
- :script_json,
10
+ :script_config,
11
11
  :script_content,
12
12
  :compiled_type,
13
13
  :metadata,
@@ -20,7 +20,7 @@ module Script
20
20
  script_content:,
21
21
  compiled_type: nil,
22
22
  metadata:,
23
- script_json:,
23
+ script_config:,
24
24
  library:
25
25
  )
26
26
  @id = id
@@ -29,7 +29,7 @@ module Script
29
29
  @script_content = script_content
30
30
  @compiled_type = compiled_type
31
31
  @metadata = metadata
32
- @script_json = script_json
32
+ @script_config = script_config
33
33
  @library = library
34
34
  end
35
35
  end
@@ -3,7 +3,7 @@
3
3
  module Script
4
4
  module Layers
5
5
  module Domain
6
- class ScriptJson
6
+ class ScriptConfig
7
7
  attr_reader :content, :version, :title, :description, :configuration_ui, :configuration
8
8
 
9
9
  REQUIRED_FIELDS = %w(version title)
@@ -23,7 +23,7 @@ module Script
23
23
 
24
24
  def validate_content!(content)
25
25
  REQUIRED_FIELDS.each do |field|
26
- raise Errors::MissingScriptJsonFieldError, field if content[field].nil?
26
+ raise Errors::MissingScriptConfigFieldError, field if content[field].nil?
27
27
  end
28
28
  end
29
29
  end
@@ -15,7 +15,7 @@ module Script
15
15
  property! :script_name, accepts: String
16
16
  property! :language, accepts: String
17
17
 
18
- property :script_json, accepts: ScriptJson
18
+ property :script_config, accepts: ScriptConfig
19
19
 
20
20
  def initialize(*)
21
21
  super
@@ -5,9 +5,9 @@ module Script
5
5
  module Infrastructure
6
6
  module Errors
7
7
  class BuildError < ScriptProjectError; end
8
- class ScriptJsonSyntaxError < ScriptProjectError; end
8
+ class ScriptConfigSyntaxError < ScriptProjectError; end
9
9
 
10
- class ScriptJsonMissingKeysError < ScriptProjectError
10
+ class ScriptConfigMissingKeysError < ScriptProjectError
11
11
  attr_reader :missing_keys
12
12
  def initialize(missing_keys)
13
13
  super()
@@ -15,7 +15,7 @@ module Script
15
15
  end
16
16
  end
17
17
 
18
- class ScriptJsonInvalidValueError < ScriptProjectError
18
+ class ScriptConfigInvalidValueError < ScriptProjectError
19
19
  attr_reader :valid_input_modes
20
20
  def initialize(valid_input_modes)
21
21
  super()
@@ -23,7 +23,7 @@ module Script
23
23
  end
24
24
  end
25
25
 
26
- class ScriptJsonFieldsMissingKeysError < ScriptProjectError
26
+ class ScriptConfigFieldsMissingKeysError < ScriptProjectError
27
27
  attr_reader :missing_keys
28
28
  def initialize(missing_keys)
29
29
  super()
@@ -31,7 +31,7 @@ module Script
31
31
  end
32
32
  end
33
33
 
34
- class ScriptJsonFieldsInvalidValueError < ScriptProjectError
34
+ class ScriptConfigFieldsInvalidValueError < ScriptProjectError
35
35
  attr_reader :valid_types
36
36
  def initialize(valid_types)
37
37
  super()
@@ -39,6 +39,31 @@ module Script
39
39
  end
40
40
  end
41
41
 
42
+ class ScriptEnvAppNotConnectedError < ScriptProjectError; end
43
+
44
+ class InvalidScriptConfigYmlDefinitionError < ScriptProjectError; end
45
+
46
+ class InvalidScriptJsonDefinitionError < ScriptProjectError; end
47
+
48
+ class MissingScriptConfigYmlFieldError < ScriptProjectError
49
+ attr_reader :field
50
+ def initialize(field)
51
+ super()
52
+ @field = field
53
+ end
54
+ end
55
+
56
+ class MissingScriptJsonFieldError < ScriptProjectError
57
+ attr_reader :field
58
+ def initialize(field)
59
+ super()
60
+ @field = field
61
+ end
62
+ end
63
+
64
+ class NoScriptConfigYmlFileError < ScriptProjectError; end
65
+ class NoScriptConfigFileError < ScriptProjectError; end
66
+
42
67
  class APILibraryNotFoundError < ScriptProjectError
43
68
  attr_reader :library_name
44
69
  def initialize(library_name)
@@ -18,7 +18,7 @@ module Script
18
18
  script_content: script_content,
19
19
  compiled_type: compiled_type,
20
20
  metadata: metadata,
21
- script_json: script_project.script_json,
21
+ script_config: script_project.script_config,
22
22
  library: library
23
23
  )
24
24
  end
@@ -34,7 +34,7 @@ module Script
34
34
  extension_point_type: script_project.extension_point_type,
35
35
  script_content: script_content,
36
36
  metadata: metadata,
37
- script_json: script_project.script_json,
37
+ script_config: script_project.script_config,
38
38
  library: library
39
39
  )
40
40
  end
@@ -6,10 +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
- SCRIPT_JSON_FILENAME = "script.json"
11
12
  MUTABLE_ENV_VALUES = %i(uuid)
12
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
+
13
29
  def create(script_name:, extension_point_type:, language:)
14
30
  validate_metadata!(extension_point_type, language)
15
31
 
@@ -40,7 +56,7 @@ module Script
40
56
  script_name: script_name,
41
57
  extension_point_type: extension_point_type,
42
58
  language: language,
43
- script_json: ScriptJsonRepository.new(ctx: ctx).get
59
+ script_config: script_config_repository.get!
44
60
  )
45
61
  end
46
62
 
@@ -58,7 +74,7 @@ module Script
58
74
  script_name: script_name,
59
75
  extension_point_type: extension_point_type,
60
76
  language: language,
61
- script_json: ScriptJsonRepository.new(ctx: ctx).get,
77
+ script_config: script_config_repository.get!,
62
78
  )
63
79
  end
64
80
 
@@ -77,14 +93,12 @@ module Script
77
93
  script_name: script_name,
78
94
  extension_point_type: extension_point_type,
79
95
  language: language,
80
- script_json: ScriptJsonRepository.new(ctx: ctx).get,
96
+ script_config: script_config_repository.get!,
81
97
  )
82
98
  end
83
99
 
84
- def update_or_create_script_json(title:)
85
- script_json = ScriptJsonRepository
86
- .new(ctx: ctx)
87
- .update_or_create(title: title)
100
+ def update_script_config(title:)
101
+ script_config = script_config_repository.update!(title: title)
88
102
 
89
103
  Domain::ScriptProject.new(
90
104
  id: ctx.root,
@@ -92,12 +106,16 @@ module Script
92
106
  script_name: script_name,
93
107
  extension_point_type: extension_point_type,
94
108
  language: language,
95
- script_json: script_json,
109
+ script_config: script_config,
96
110
  )
97
111
  end
98
112
 
99
113
  private
100
114
 
115
+ def change_directory(directory:)
116
+ ctx.chdir(directory)
117
+ end
118
+
101
119
  def capture_io(&block)
102
120
  CLI::UI::StdoutRouter::Capture.new(&block).run
103
121
  end
@@ -140,40 +158,120 @@ module Script
140
158
  end
141
159
  end
142
160
 
143
- class ScriptJsonRepository
161
+ def script_config_repository
162
+ @script_config_repository ||= begin
163
+ supported_repos = [
164
+ ScriptConfigYmlRepository.new(ctx: ctx),
165
+ ScriptJsonRepository.new(ctx: ctx),
166
+ ]
167
+ repo = supported_repos.find(&:active?)
168
+ raise Infrastructure::Errors::NoScriptConfigYmlFileError if repo.nil?
169
+ repo
170
+ end
171
+ end
172
+
173
+ class ScriptConfigRepository
144
174
  include SmartProperties
145
175
  property! :ctx, accepts: ShopifyCLI::Context
146
176
 
147
- def get
148
- current_script_json || raise(Domain::Errors::NoScriptJsonFile)
177
+ def active?
178
+ ctx.file_exist?(filename)
179
+ end
180
+
181
+ def get!
182
+ raise Infrastructure::Errors::NoScriptConfigFileError unless active?
183
+
184
+ content = ctx.read(filename)
185
+ hash = file_content_to_hash(content)
186
+
187
+ from_h(hash)
188
+ end
189
+
190
+ def update!(title:)
191
+ hash = get!.content
192
+ update_hash(hash: hash, title: title)
193
+
194
+ ctx.write(filename, hash_to_file_content(hash))
195
+
196
+ from_h(hash)
197
+ end
198
+
199
+ private
200
+
201
+ def update_hash(hash:, title:)
202
+ hash["version"] ||= "2"
203
+ hash["title"] = title
204
+ end
205
+
206
+ def from_h(hash)
207
+ Domain::ScriptConfig.new(content: hash)
208
+ rescue Domain::Errors::MissingScriptConfigFieldError => e
209
+ raise missing_field_error, e.field
149
210
  end
150
211
 
151
- def update_or_create(title:)
152
- json = current_script_json&.content || {}
153
- json["version"] ||= "1"
154
- json["title"] = title
212
+ # to be implemented by subclasses
213
+ def filename
214
+ raise NotImplementedError
215
+ end
155
216
 
156
- ctx.write(SCRIPT_JSON_FILENAME, JSON.pretty_generate(json))
217
+ def file_content_to_hash(file_content)
218
+ raise NotImplementedError
219
+ end
157
220
 
158
- Domain::ScriptJson.new(content: json)
221
+ def hash_to_file_content(hash)
222
+ raise NotImplementedError
159
223
  end
160
224
 
225
+ def missing_field_error
226
+ raise NotImplementedError
227
+ end
228
+ end
229
+
230
+ class ScriptConfigYmlRepository < ScriptConfigRepository
161
231
  private
162
232
 
163
- def current_script_json
164
- return nil unless ctx.file_exist?(SCRIPT_JSON_FILENAME)
233
+ def filename
234
+ "script.config.yml"
235
+ end
236
+
237
+ def file_content_to_hash(file_content)
238
+ begin
239
+ hash = YAML.load(file_content)
240
+ rescue Psych::SyntaxError
241
+ raise Errors::InvalidScriptConfigYmlDefinitionError
242
+ end
243
+ raise Errors::InvalidScriptConfigYmlDefinitionError unless hash.is_a?(Hash)
244
+ hash
245
+ end
246
+
247
+ def hash_to_file_content(hash)
248
+ YAML.dump(hash)
249
+ end
165
250
 
166
- content = ctx.read(SCRIPT_JSON_FILENAME)
167
- raise Domain::Errors::InvalidScriptJsonDefinitionError unless valid_script_json?(content)
251
+ def missing_field_error
252
+ Errors::MissingScriptConfigYmlFieldError
253
+ end
254
+ end
168
255
 
169
- Domain::ScriptJson.new(content: JSON.parse(content))
256
+ class ScriptJsonRepository < ScriptConfigRepository
257
+ private
258
+
259
+ def filename
260
+ "script.json"
170
261
  end
171
262
 
172
- def valid_script_json?(content)
173
- JSON.parse(content)
174
- true
263
+ def file_content_to_hash(file_content)
264
+ JSON.parse(file_content)
175
265
  rescue JSON::ParserError
176
- false
266
+ raise Errors::InvalidScriptJsonDefinitionError
267
+ end
268
+
269
+ def hash_to_file_content(hash)
270
+ JSON.pretty_generate(hash)
271
+ end
272
+
273
+ def missing_field_error
274
+ Errors::MissingScriptJsonFieldError
177
275
  end
178
276
  end
179
277
  end
@@ -17,7 +17,7 @@ module Script
17
17
  extension_point_type:,
18
18
  force: false,
19
19
  metadata:,
20
- script_json:,
20
+ script_config:,
21
21
  module_upload_url:,
22
22
  library:
23
23
  )
@@ -25,14 +25,14 @@ module Script
25
25
  variables = {
26
26
  uuid: uuid,
27
27
  extensionPointName: extension_point_type.upcase,
28
- title: script_json.title,
29
- description: script_json.description,
28
+ title: script_config.title,
29
+ description: script_config.description,
30
30
  force: force,
31
31
  schemaMajorVersion: metadata.schema_major_version.to_s, # API expects string value
32
32
  schemaMinorVersion: metadata.schema_minor_version.to_s, # API expects string value
33
- scriptJsonVersion: script_json.version,
34
- configurationUi: script_json.configuration_ui,
35
- configurationDefinition: script_json.configuration&.to_json,
33
+ scriptConfigVersion: script_config.version,
34
+ configurationUi: script_config.configuration_ui,
35
+ configurationDefinition: script_config.configuration&.to_json,
36
36
  moduleUploadUrl: module_upload_url,
37
37
  library: {
38
38
  language: library[:language],
@@ -47,19 +47,19 @@ module Script
47
47
  if user_errors.any? { |e| e["tag"] == "already_exists_error" }
48
48
  raise Errors::ScriptRepushError, uuid
49
49
  elsif (e = user_errors.any? { |err| err["tag"] == "configuration_definition_syntax_error" })
50
- raise Errors::ScriptJsonSyntaxError
50
+ raise Errors::ScriptConfigSyntaxError
51
51
  elsif (e = user_errors.find { |err| err["tag"] == "configuration_definition_missing_keys_error" })
52
- raise Errors::ScriptJsonMissingKeysError, e["message"]
52
+ raise Errors::ScriptConfigMissingKeysError, e["message"]
53
53
  elsif (e = user_errors.find { |err| err["tag"] == "configuration_definition_invalid_value_error" })
54
- raise Errors::ScriptJsonInvalidValueError, e["message"]
54
+ raise Errors::ScriptConfigInvalidValueError, e["message"]
55
55
  elsif (e = user_errors.find do |err|
56
56
  err["tag"] == "configuration_definition_schema_field_missing_keys_error"
57
57
  end)
58
- raise Errors::ScriptJsonFieldsMissingKeysError, e["message"]
58
+ raise Errors::ScriptConfigFieldsMissingKeysError, e["message"]
59
59
  elsif (e = user_errors.find do |err|
60
60
  err["tag"] == "configuration_definition_schema_field_invalid_value_error"
61
61
  end)
62
- raise Errors::ScriptJsonFieldsInvalidValueError, e["message"]
62
+ raise Errors::ScriptConfigFieldsInvalidValueError, e["message"]
63
63
  elsif user_errors.find { |err| %w(not_use_msgpack_error schema_version_argument_error).include?(err["tag"]) }
64
64
  raise Domain::Errors::MetadataValidationError
65
65
  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,14 +47,23 @@ module Script
47
47
  invalid_language_cause: "Invalid language %s.",
48
48
  invalid_language_help: "Allowed values: %s.",
49
49
 
50
+ missing_script_config_yml_field_cause: "The script.config.yml file is missing the required %s field.",
51
+ missing_script_config_yml_field_help: "Add the field and try again.",
52
+
50
53
  missing_script_json_field_cause: "The script.json file is missing the required %s field.",
51
54
  missing_script_json_field_help: "Add the field and try again.",
52
55
 
53
56
  invalid_script_json_definition_cause: "The script.json file contains invalid JSON.",
54
57
  invalid_script_json_definition_help: "Fix the errors and try again.",
55
58
 
56
- no_script_json_file_cause: "The script.json file is missing.",
57
- no_script_json_file_help: "Create this file and try again.",
59
+ invalid_script_config_yml_definition_cause: "The script.config.yml file contains invalid YAML.",
60
+ invalid_script_config_yml_definition_help: "Fix the errors and try again.",
61
+
62
+ no_script_config_yml_file_cause: "The script.config.yml file is missing.",
63
+ no_script_config_yml_file_help: "Create this file and try again.",
64
+
65
+ app_not_connected_cause: "Script is not connected to an app.",
66
+ app_not_connected_help: "Run shopify connect or enter fields for api-key and api-secret.",
58
67
 
59
68
  configuration_syntax_error_cause: "The script.json is not formatted properly.",
60
69
  configuration_syntax_error_help: "Fix the errors and try again.",
@@ -138,6 +147,12 @@ module Script
138
147
 
139
148
  language_library_for_api_not_found_cause: "Script can’t be pushed because the %{language} library for API %{api} is missing.",
140
149
  language_library_for_api_not_found_help: "Make sure extension_point.yml contains the correct API library.",
150
+ no_scripts_found_in_app: "The selected apps have no scripts. Please, create them first on the partners' dashboard.",
151
+ missing_env_file_variables: "The following variables are missing in the .env file: %s."\
152
+ " It might happen when the script hasn't been previously connected to an app."\
153
+ " To connect the script to an app, run {{command:%s script connect}}",
154
+ missing_push_options: "The following options are required: %s."\
155
+ " You can obtain them from the .env file generated after connecting the script to an app.",
141
156
  },
142
157
 
143
158
  create: {
@@ -147,6 +162,7 @@ module Script
147
162
  Options:
148
163
  {{command:--name=NAME}} Script project name. Use any string.
149
164
  {{command:--api=TYPE}} Script API name. Allowed values: %2$s.
165
+ {{command:--language=LANGUAGE}} Programming language. Allowed values: %3$s.
150
166
  HELP
151
167
 
152
168
  error: {
@@ -164,16 +180,31 @@ module Script
164
180
  Usage: {{command:%s script push}}
165
181
  Options:
166
182
  {{command:[--force]}} Replaces the existing script on the app with this version.
183
+ {{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.
184
+ {{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.
185
+ {{command:[--uuid=UUID]}} The uuid of the script. Overrides the value in the .env file, if present.
167
186
  HELP
168
187
 
169
188
  error: {
189
+ operation_failed_no_uuid: "UUID is required to push in a CI environment.",
170
190
  operation_failed_with_api_key: "Couldn't push script to app (API key: %{api_key}).",
171
191
  operation_failed_no_api_key: "Couldn't push script to app.",
172
192
  },
173
193
 
174
194
  script_pushed: "{{v}} Script pushed to app (API key: %{api_key}).",
175
195
  },
176
-
196
+ connect: {
197
+ connected: "Connected! Your project is now connected to {{green:%s}}",
198
+ help: <<~HELP,
199
+ {{command:%s script connect}}: Connects an existing script to an app.
200
+ Usage: {{command:%s script connect}}
201
+ HELP
202
+ error: {
203
+ operation_failed: "Couldn't connect script to app.",
204
+ missing_env_file_variables: "The following variables are missing in the .env file: %s."\
205
+ " 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}}",
206
+ },
207
+ },
177
208
  javy: {
178
209
  help: <<~HELP,
179
210
  Compile the JavaScript code into WebAssembly.