shopify-cli 1.13.0 → 2.0.2

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 (199) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +1 -1
  3. data/.github/CONTRIBUTING.md +7 -7
  4. data/.github/DESIGN.md +3 -3
  5. data/.github/workflows/build.yml +1 -1
  6. data/.gitignore +3 -0
  7. data/.rubocop.yml +3 -1
  8. data/.ruby-version +1 -1
  9. data/CHANGELOG.md +57 -24
  10. data/Gemfile +4 -0
  11. data/Gemfile.lock +32 -0
  12. data/LICENSE +4 -1
  13. data/README.md +94 -26
  14. data/RELEASING.md +31 -7
  15. data/Rakefile +2 -2
  16. data/SECURITY.md +1 -1
  17. data/THEMEKIT_MIGRATION.md +18 -0
  18. data/bin/load_shopify.rb +1 -1
  19. data/bin/shopify +3 -3
  20. data/dev.yml +1 -1
  21. data/docs/app/node/index.md +1 -1
  22. data/docs/app/rails/index.md +1 -1
  23. data/docs/core/index.md +1 -1
  24. data/docs/getting-started/index.md +1 -1
  25. data/docs/getting-started/install/index.md +1 -1
  26. data/docs/getting-started/migrate/index.md +1 -1
  27. data/docs/getting-started/uninstall/index.md +1 -1
  28. data/docs/getting-started/upgrade/index.md +1 -1
  29. data/docs/help/start-app/index.md +1 -1
  30. data/docs/index.md +1 -1
  31. data/ext/shopify-cli/extconf.rb +17 -5
  32. data/install.sh +1 -1
  33. data/lib/docgen/index_template.md.erb +2 -2
  34. data/lib/graphql/all_orgs_with_extensions.graphql +37 -0
  35. data/lib/graphql/api_versions.graphql +1 -1
  36. data/lib/graphql/find_organization.graphql +2 -1
  37. data/lib/project_types/extension/cli.rb +18 -15
  38. data/lib/project_types/extension/commands/build.rb +4 -5
  39. data/lib/project_types/extension/commands/connect.rb +35 -0
  40. data/lib/project_types/extension/commands/create.rb +12 -16
  41. data/lib/project_types/extension/commands/extension_command.rb +2 -2
  42. data/lib/project_types/extension/commands/info.rb +86 -0
  43. data/lib/project_types/extension/commands/push.rb +8 -7
  44. data/lib/project_types/extension/commands/register.rb +4 -5
  45. data/lib/project_types/extension/commands/serve.rb +5 -8
  46. data/lib/project_types/extension/commands/tunnel.rb +3 -1
  47. data/lib/project_types/extension/errors.rb +9 -0
  48. data/lib/project_types/extension/extension_project.rb +17 -1
  49. data/lib/project_types/extension/extension_project_keys.rb +1 -0
  50. data/lib/project_types/extension/features/argo.rb +6 -6
  51. data/lib/project_types/extension/features/argo_runtime.rb +22 -56
  52. data/lib/project_types/extension/features/argo_serve.rb +25 -18
  53. data/lib/project_types/extension/forms/connect.rb +42 -0
  54. data/lib/project_types/extension/forms/questions/ask_name.rb +14 -6
  55. data/lib/project_types/extension/forms/questions/ask_registration.rb +51 -0
  56. data/lib/project_types/extension/messages/messages.rb +80 -16
  57. data/lib/project_types/extension/models/specification.rb +1 -0
  58. data/lib/project_types/extension/models/specification_handlers/{checkout_argo_extension.rb → checkout_ui_extension.rb} +3 -1
  59. data/lib/project_types/extension/models/specification_handlers/default.rb +13 -3
  60. data/lib/project_types/extension/models/specification_handlers/theme_app_extension.rb +89 -0
  61. data/lib/project_types/extension/models/specifications.rb +1 -0
  62. data/lib/project_types/extension/tasks/configure_features.rb +6 -7
  63. data/lib/project_types/extension/tasks/configure_options.rb +20 -0
  64. data/lib/project_types/extension/tasks/get_extensions.rb +32 -0
  65. data/lib/project_types/node/cli.rb +9 -21
  66. data/lib/project_types/node/commands/connect.rb +8 -2
  67. data/lib/project_types/node/commands/create.rb +9 -5
  68. data/lib/project_types/node/commands/deploy.rb +15 -5
  69. data/lib/project_types/node/commands/deploy/heroku.rb +29 -29
  70. data/lib/project_types/node/commands/generate.rb +4 -2
  71. data/lib/project_types/node/commands/open.rb +4 -2
  72. data/lib/project_types/node/commands/serve.rb +3 -2
  73. data/lib/project_types/node/commands/tunnel.rb +4 -2
  74. data/lib/project_types/node/messages/messages.rb +47 -90
  75. data/lib/project_types/rails/cli.rb +9 -21
  76. data/lib/project_types/rails/commands/connect.rb +8 -2
  77. data/lib/project_types/rails/commands/create.rb +10 -6
  78. data/lib/project_types/rails/commands/deploy.rb +15 -5
  79. data/lib/project_types/rails/commands/deploy/heroku.rb +84 -82
  80. data/lib/project_types/rails/commands/generate.rb +15 -5
  81. data/lib/project_types/rails/commands/generate/webhook.rb +28 -26
  82. data/lib/project_types/rails/commands/open.rb +4 -2
  83. data/lib/project_types/rails/commands/serve.rb +3 -2
  84. data/lib/project_types/rails/commands/tunnel.rb +4 -2
  85. data/lib/project_types/rails/messages/messages.rb +72 -119
  86. data/lib/project_types/script/cli.rb +6 -8
  87. data/lib/project_types/script/commands/create.rb +3 -1
  88. data/lib/project_types/script/commands/push.rb +12 -5
  89. data/lib/project_types/script/graphql/app_script_update_or_create.graphql +9 -3
  90. data/lib/project_types/script/layers/application/create_script.rb +4 -3
  91. data/lib/project_types/script/layers/domain/errors.rb +6 -11
  92. data/lib/project_types/script/layers/domain/push_package.rb +4 -8
  93. data/lib/project_types/script/layers/domain/script_json.rb +32 -0
  94. data/lib/project_types/script/layers/domain/script_project.rb +1 -1
  95. data/lib/project_types/script/layers/infrastructure/errors.rb +13 -17
  96. data/lib/project_types/script/layers/infrastructure/languages/assemblyscript_project_creator.rb +29 -21
  97. data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +2 -4
  98. data/lib/project_types/script/layers/infrastructure/script_project_repository.rb +45 -34
  99. data/lib/project_types/script/layers/infrastructure/script_service.rb +37 -16
  100. data/lib/project_types/script/messages/messages.rb +66 -55
  101. data/lib/project_types/script/tasks/ensure_env.rb +22 -1
  102. data/lib/project_types/script/ui/error_handler.rb +32 -32
  103. data/lib/project_types/theme/cli.rb +16 -27
  104. data/lib/project_types/theme/commands/check.rb +33 -0
  105. data/lib/project_types/theme/commands/delete.rb +64 -0
  106. data/lib/project_types/theme/commands/init.rb +42 -0
  107. data/lib/project_types/theme/commands/language_server.rb +16 -0
  108. data/lib/project_types/theme/commands/package.rb +55 -0
  109. data/lib/project_types/theme/commands/publish.rb +43 -0
  110. data/lib/project_types/theme/commands/pull.rb +51 -0
  111. data/lib/project_types/theme/commands/push.rb +58 -32
  112. data/lib/project_types/theme/commands/serve.rb +8 -16
  113. data/lib/project_types/theme/forms/confirm_store.rb +15 -0
  114. data/lib/project_types/theme/forms/select.rb +59 -0
  115. data/lib/project_types/theme/messages/messages.rb +118 -103
  116. data/lib/project_types/theme/ui/sync_progress_bar.rb +20 -0
  117. data/lib/shopify-cli/admin_api.rb +57 -38
  118. data/lib/shopify-cli/admin_api/populate_resource_command.rb +6 -14
  119. data/lib/shopify-cli/admin_api/schema.rb +1 -10
  120. data/lib/shopify-cli/api.rb +29 -14
  121. data/lib/shopify-cli/command.rb +15 -3
  122. data/lib/shopify-cli/commands.rb +7 -2
  123. data/lib/shopify-cli/commands/help.rb +2 -29
  124. data/lib/shopify-cli/commands/login.rb +95 -0
  125. data/lib/shopify-cli/commands/logout.rb +24 -8
  126. data/lib/shopify-cli/commands/populate.rb +23 -0
  127. data/lib/{project_types/node → shopify-cli}/commands/populate/customer.rb +2 -8
  128. data/lib/{project_types/node → shopify-cli}/commands/populate/draft_order.rb +2 -2
  129. data/lib/{project_types/node → shopify-cli}/commands/populate/product.rb +2 -8
  130. data/lib/shopify-cli/commands/store.rb +15 -0
  131. data/lib/shopify-cli/commands/switch.rb +39 -0
  132. data/lib/shopify-cli/commands/system.rb +12 -0
  133. data/lib/shopify-cli/commands/whoami.rb +28 -0
  134. data/lib/shopify-cli/connect.rb +32 -0
  135. data/lib/shopify-cli/context.rb +65 -4
  136. data/lib/shopify-cli/core/entry_point.rb +3 -22
  137. data/lib/shopify-cli/core/monorail.rb +6 -2
  138. data/lib/shopify-cli/db.rb +4 -4
  139. data/lib/shopify-cli/http_request.rb +16 -0
  140. data/lib/shopify-cli/identity_auth.rb +282 -0
  141. data/lib/shopify-cli/{oauth → identity_auth}/servlet.rb +11 -12
  142. data/lib/shopify-cli/messages/messages.rb +140 -46
  143. data/lib/shopify-cli/packager.rb +5 -5
  144. data/lib/shopify-cli/partners_api.rb +21 -44
  145. data/lib/shopify-cli/partners_api/organizations.rb +8 -0
  146. data/lib/shopify-cli/project_commands.rb +16 -0
  147. data/lib/shopify-cli/project_type.rb +0 -31
  148. data/lib/shopify-cli/shopifolk.rb +8 -11
  149. data/lib/shopify-cli/sub_command.rb +1 -0
  150. data/lib/shopify-cli/tasks.rb +3 -0
  151. data/lib/shopify-cli/tasks/confirm_store.rb +18 -0
  152. data/lib/shopify-cli/tasks/create_api_client.rb +2 -2
  153. data/lib/shopify-cli/tasks/ensure_authenticated.rb +13 -0
  154. data/lib/shopify-cli/tasks/ensure_loopback_url.rb +1 -1
  155. data/lib/shopify-cli/tasks/ensure_project_type.rb +12 -0
  156. data/lib/shopify-cli/tasks/select_org_and_shop.rb +0 -3
  157. data/lib/shopify-cli/theme/dev_server.rb +98 -0
  158. data/lib/shopify-cli/theme/dev_server/certificate_manager.rb +79 -0
  159. data/lib/shopify-cli/theme/dev_server/header_hash.rb +94 -0
  160. data/lib/shopify-cli/theme/dev_server/hot-reload.js +93 -0
  161. data/lib/shopify-cli/theme/dev_server/hot_reload.rb +76 -0
  162. data/lib/shopify-cli/theme/dev_server/local_assets.rb +87 -0
  163. data/lib/shopify-cli/theme/dev_server/proxy.rb +205 -0
  164. data/lib/shopify-cli/theme/dev_server/sse.rb +75 -0
  165. data/lib/shopify-cli/theme/dev_server/watcher.rb +59 -0
  166. data/lib/shopify-cli/theme/dev_server/web_server.rb +140 -0
  167. data/lib/shopify-cli/theme/development_theme.rb +69 -0
  168. data/lib/shopify-cli/theme/file.rb +112 -0
  169. data/lib/shopify-cli/theme/ignore_filter.rb +109 -0
  170. data/lib/shopify-cli/theme/mime_type.rb +34 -0
  171. data/lib/shopify-cli/theme/syncer.rb +332 -0
  172. data/lib/shopify-cli/theme/theme.rb +204 -0
  173. data/lib/shopify-cli/tunnel.rb +1 -1
  174. data/lib/shopify-cli/version.rb +1 -1
  175. data/lib/shopify_cli.rb +18 -11
  176. data/shopify-cli.gemspec +12 -5
  177. data/shopify.fish +1 -1
  178. data/shopify.sh +1 -1
  179. metadata +91 -35
  180. data/.github/workflows/release.yml +0 -59
  181. data/lib/project_types/extension/features/argo_serve_options.rb +0 -41
  182. data/lib/project_types/node/commands/populate.rb +0 -23
  183. data/lib/project_types/rails/commands/populate.rb +0 -23
  184. data/lib/project_types/rails/commands/populate/customer.rb +0 -31
  185. data/lib/project_types/rails/commands/populate/draft_order.rb +0 -28
  186. data/lib/project_types/rails/commands/populate/product.rb +0 -30
  187. data/lib/project_types/script/layers/domain/config_ui.rb +0 -16
  188. data/lib/project_types/theme/commands/connect.rb +0 -54
  189. data/lib/project_types/theme/commands/create.rb +0 -48
  190. data/lib/project_types/theme/commands/deploy.rb +0 -38
  191. data/lib/project_types/theme/commands/generate.rb +0 -20
  192. data/lib/project_types/theme/commands/generate/env.rb +0 -79
  193. data/lib/project_types/theme/forms/connect.rb +0 -34
  194. data/lib/project_types/theme/forms/create.rb +0 -22
  195. data/lib/project_types/theme/tasks/ensure_themekit_installed.rb +0 -78
  196. data/lib/project_types/theme/themekit.rb +0 -113
  197. data/lib/shopify-cli/commands/connect.rb +0 -64
  198. data/lib/shopify-cli/commands/create.rb +0 -50
  199. data/lib/shopify-cli/oauth.rb +0 -198
@@ -14,21 +14,16 @@ module Script
14
14
  end
15
15
  end
16
16
 
17
- class InvalidConfigUiDefinitionError < ScriptProjectError
18
- attr_reader :filename
19
- def initialize(filename)
17
+ class MissingScriptJsonFieldError < ScriptProjectError
18
+ attr_reader :field
19
+ def initialize(field)
20
20
  super()
21
- @filename = filename
21
+ @field = field
22
22
  end
23
23
  end
24
24
 
25
- class MissingSpecifiedConfigUiDefinitionError < ScriptProjectError
26
- attr_reader :filename
27
- def initialize(filename)
28
- super()
29
- @filename = filename
30
- end
31
- end
25
+ class InvalidScriptJsonDefinitionError < ScriptProjectError; end
26
+ class NoScriptJsonFile < ScriptProjectError; end
32
27
 
33
28
  class ScriptNotFoundError < ScriptProjectError
34
29
  attr_reader :script_name, :extension_point_type
@@ -7,8 +7,7 @@ module Script
7
7
  attr_reader :id,
8
8
  :uuid,
9
9
  :extension_point_type,
10
- :script_name,
11
- :config_ui,
10
+ :script_json,
12
11
  :script_content,
13
12
  :compiled_type,
14
13
  :metadata
@@ -17,33 +16,30 @@ module Script
17
16
  id:,
18
17
  uuid:,
19
18
  extension_point_type:,
20
- script_name:,
21
19
  script_content:,
22
20
  compiled_type:,
23
21
  metadata:,
24
- config_ui:
22
+ script_json:
25
23
  )
26
24
  @id = id
27
25
  @uuid = uuid
28
26
  @extension_point_type = extension_point_type
29
- @script_name = script_name
30
27
  @script_content = script_content
31
28
  @compiled_type = compiled_type
32
29
  @metadata = metadata
33
- @config_ui = config_ui
30
+ @script_json = script_json
34
31
  end
35
32
 
36
33
  def push(script_service, api_key, force)
37
34
  script_service.push(
38
35
  uuid: @uuid,
39
36
  extension_point_type: @extension_point_type,
40
- script_name: @script_name,
41
37
  script_content: @script_content,
42
38
  compiled_type: @compiled_type,
43
39
  api_key: api_key,
44
40
  force: force,
45
41
  metadata: @metadata,
46
- config_ui: @config_ui,
42
+ script_json: @script_json,
47
43
  )
48
44
  end
49
45
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Script
4
+ module Layers
5
+ module Domain
6
+ class ScriptJson
7
+ attr_reader :content, :version, :title, :description, :configuration_ui, :configuration
8
+
9
+ REQUIRED_FIELDS = %w(version title)
10
+
11
+ def initialize(content:)
12
+ validate_content!(content)
13
+
14
+ @content = content
15
+ @version = @content["version"].to_s
16
+ @title = @content["title"]
17
+ @description = @content["description"]
18
+ @configuration_ui = @content["configurationUi"]
19
+ @configuration = @content["configuration"]
20
+ end
21
+
22
+ private
23
+
24
+ def validate_content!(content)
25
+ REQUIRED_FIELDS.each do |field|
26
+ raise Errors::MissingScriptJsonFieldError, field if content[field].nil?
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -15,7 +15,7 @@ module Script
15
15
  property! :script_name, accepts: String
16
16
  property! :language, accepts: String
17
17
 
18
- property :config_ui, accepts: ConfigUi
18
+ property :script_json, accepts: ScriptJson
19
19
 
20
20
  def initialize(*)
21
21
  super
@@ -6,40 +6,36 @@ module Script
6
6
  module Errors
7
7
  class AppNotInstalledError < ScriptProjectError; end
8
8
  class BuildError < ScriptProjectError; end
9
- class ConfigUiSyntaxError < ScriptProjectError; end
9
+ class ScriptJsonSyntaxError < ScriptProjectError; end
10
10
 
11
- class ConfigUiMissingKeysError < ScriptProjectError
12
- attr_reader :filename, :missing_keys
13
- def initialize(filename, missing_keys)
11
+ class ScriptJsonMissingKeysError < ScriptProjectError
12
+ attr_reader :missing_keys
13
+ def initialize(missing_keys)
14
14
  super()
15
- @filename = filename
16
15
  @missing_keys = missing_keys
17
16
  end
18
17
  end
19
18
 
20
- class ConfigUiInvalidInputModeError < ScriptProjectError
21
- attr_reader :filename, :valid_input_modes
22
- def initialize(filename, valid_input_modes)
19
+ class ScriptJsonInvalidValueError < ScriptProjectError
20
+ attr_reader :valid_input_modes
21
+ def initialize(valid_input_modes)
23
22
  super()
24
- @filename = filename
25
23
  @valid_input_modes = valid_input_modes
26
24
  end
27
25
  end
28
26
 
29
- class ConfigUiFieldsMissingKeysError < ScriptProjectError
30
- attr_reader :filename, :missing_keys
31
- def initialize(filename, missing_keys)
27
+ class ScriptJsonFieldsMissingKeysError < ScriptProjectError
28
+ attr_reader :missing_keys
29
+ def initialize(missing_keys)
32
30
  super()
33
- @filename = filename
34
31
  @missing_keys = missing_keys
35
32
  end
36
33
  end
37
34
 
38
- class ConfigUiFieldsInvalidTypeError < ScriptProjectError
39
- attr_reader :filename, :valid_types
40
- def initialize(filename, valid_types)
35
+ class ScriptJsonFieldsInvalidValueError < ScriptProjectError
36
+ attr_reader :valid_types
37
+ def initialize(valid_types)
41
38
  super()
42
- @filename = filename
43
39
  @valid_types = valid_types
44
40
  end
45
41
  end
@@ -45,27 +45,20 @@ module Script
45
45
  end
46
46
 
47
47
  def write_package_json
48
- package_json = <<~HERE
49
- {
50
- "name": "#{script_name}",
51
- "version": "1.0.0",
52
- "devDependencies": {
53
- "@shopify/scripts-sdk-as": "#{extension_point.sdks.assemblyscript.sdk_version}",
54
- "@shopify/scripts-toolchain-as": "#{extension_point.sdks.assemblyscript.toolchain_version}",
55
- "#{extension_point.sdks.assemblyscript.package}": "#{extension_point_version}",
56
- "@as-pect/cli": "^6.0.0",
57
- "assemblyscript": "^0.18.13"
58
- },
59
- "scripts": {
60
- "test": "asp --summary --verbose",
61
- "build": "#{build_command}"
62
- },
63
- "engines": {
64
- "node": ">=#{MIN_NODE_VERSION}"
65
- }
66
- }
67
- HERE
68
- ctx.write("package.json", package_json)
48
+ package_json = {
49
+ name: script_name,
50
+ version: "1.0.0",
51
+ devDependencies: dev_dependencies,
52
+ scripts: {
53
+ test: "asp --summary --verbose",
54
+ build: build_command,
55
+ },
56
+ engines: {
57
+ node: ">=#{MIN_NODE_VERSION}",
58
+ },
59
+ }
60
+
61
+ ctx.write("package.json", JSON.pretty_generate(package_json))
69
62
  end
70
63
 
71
64
  def bootstap_command
@@ -90,6 +83,21 @@ module Script
90
83
  "#{BUILD} --domain #{domain} --ep #{type} #{ASC_ARGS}"
91
84
  end
92
85
  end
86
+
87
+ def dev_dependencies
88
+ dependencies = {
89
+ "@as-pect/cli": "^6.0.0",
90
+ "assemblyscript": "^0.18.13",
91
+ "@shopify/scripts-toolchain-as": extension_point.sdks.assemblyscript.toolchain_version,
92
+ "#{extension_point.sdks.assemblyscript.package}": extension_point_version,
93
+ }
94
+
95
+ if extension_point.sdks.assemblyscript.sdk_version
96
+ dependencies["@shopify/scripts-sdk-as"] = extension_point.sdks.assemblyscript.sdk_version
97
+ end
98
+
99
+ dependencies
100
+ end
93
101
  end
94
102
  end
95
103
  end
@@ -15,11 +15,10 @@ module Script
15
15
  id: build_file_path,
16
16
  uuid: script_project.uuid,
17
17
  extension_point_type: script_project.extension_point_type,
18
- script_name: script_project.script_name,
19
18
  script_content: script_content,
20
19
  compiled_type: compiled_type,
21
20
  metadata: metadata,
22
- config_ui: script_project.config_ui,
21
+ script_json: script_project.script_json,
23
22
  )
24
23
  end
25
24
 
@@ -32,11 +31,10 @@ module Script
32
31
  id: build_file_path,
33
32
  uuid: script_project.uuid,
34
33
  extension_point_type: script_project.extension_point_type,
35
- script_name: script_project.script_name,
36
34
  script_content: script_content,
37
35
  compiled_type: compiled_type,
38
36
  metadata: metadata,
39
- config_ui: script_project.config_ui,
37
+ script_json: script_project.script_json,
40
38
  )
41
39
  end
42
40
 
@@ -7,24 +7,19 @@ module Script
7
7
  include SmartProperties
8
8
  property! :ctx, accepts: ShopifyCli::Context
9
9
 
10
- DEFAULT_CONFIG_UI_FILENAME = "config-ui.yml"
10
+ SCRIPT_JSON_FILENAME = "script.json"
11
11
  MUTABLE_ENV_VALUES = %i(uuid)
12
12
 
13
- def create(script_name:, extension_point_type:, language:, no_config_ui:)
13
+ def create(script_name:, extension_point_type:, language:)
14
14
  validate_metadata!(extension_point_type, language)
15
15
 
16
- config_ui_file = nil
17
- optional_identifiers = {}
18
- optional_identifiers.merge!(config_ui_file: DEFAULT_CONFIG_UI_FILENAME) unless no_config_ui
19
-
20
16
  ShopifyCli::Project.write(
21
17
  ctx,
22
18
  project_type: :script,
23
19
  organization_id: nil,
24
20
  extension_point_type: extension_point_type,
25
21
  script_name: script_name,
26
- language: language,
27
- **optional_identifiers
22
+ language: language
28
23
  )
29
24
 
30
25
  Domain::ScriptProject.new(
@@ -32,23 +27,20 @@ module Script
32
27
  env: project.env,
33
28
  script_name: script_name,
34
29
  extension_point_type: extension_point_type,
35
- language: language,
36
- config_ui: config_ui_file
30
+ language: language
37
31
  )
38
32
  end
39
33
 
40
34
  def get
41
35
  validate_metadata!(extension_point_type, language)
42
36
 
43
- config_ui = ConfigUiRepository.new(ctx: ctx).get(config_ui_file)
44
-
45
37
  Domain::ScriptProject.new(
46
38
  id: project.directory,
47
39
  env: project.env,
48
40
  script_name: script_name,
49
41
  extension_point_type: extension_point_type,
50
42
  language: language,
51
- config_ui: config_ui
43
+ script_json: ScriptJsonRepository.new(ctx: ctx).get
52
44
  )
53
45
  end
54
46
 
@@ -66,7 +58,7 @@ module Script
66
58
  script_name: script_name,
67
59
  extension_point_type: extension_point_type,
68
60
  language: language,
69
- config_ui: ConfigUiRepository.new(ctx: ctx).get(config_ui_file),
61
+ script_json: ScriptJsonRepository.new(ctx: ctx).get,
70
62
  )
71
63
  end
72
64
 
@@ -85,7 +77,22 @@ module Script
85
77
  script_name: script_name,
86
78
  extension_point_type: extension_point_type,
87
79
  language: language,
88
- config_ui: ConfigUiRepository.new(ctx: ctx).get(config_ui_file),
80
+ script_json: ScriptJsonRepository.new(ctx: ctx).get,
81
+ )
82
+ end
83
+
84
+ def update_or_create_script_json(title:, configuration_ui: false)
85
+ script_json = ScriptJsonRepository
86
+ .new(ctx: ctx)
87
+ .update_or_create(title: title, configuration_ui: configuration_ui)
88
+
89
+ Domain::ScriptProject.new(
90
+ id: ctx.root,
91
+ env: project.env,
92
+ script_name: script_name,
93
+ extension_point_type: extension_point_type,
94
+ language: language,
95
+ script_json: script_json,
89
96
  )
90
97
  end
91
98
 
@@ -103,10 +110,6 @@ module Script
103
110
  project_config_value!("script_name")
104
111
  end
105
112
 
106
- def config_ui_file
107
- project_config_value("config_ui_file")
108
- end
109
-
110
113
  def language
111
114
  project_config_value("language")&.downcase || default_language
112
115
  end
@@ -137,32 +140,40 @@ module Script
137
140
  end
138
141
  end
139
142
 
140
- class ConfigUiRepository
143
+ class ScriptJsonRepository
141
144
  include SmartProperties
142
145
  property! :ctx, accepts: ShopifyCli::Context
143
146
 
144
- def get(filename)
145
- return nil unless filename
147
+ def get
148
+ current_script_json || raise(Domain::Errors::NoScriptJsonFile)
149
+ end
146
150
 
147
- path = File.join(ctx.root, filename)
148
- raise Domain::Errors::MissingSpecifiedConfigUiDefinitionError, filename unless File.exist?(path)
151
+ def update_or_create(title:, configuration_ui:)
152
+ json = current_script_json&.content || {}
153
+ json["version"] ||= "1"
154
+ json["title"] = title
155
+ json["configurationUi"] = !!configuration_ui
149
156
 
150
- content = File.read(path)
151
- raise Domain::Errors::InvalidConfigUiDefinitionError, filename unless valid_config_ui?(content)
157
+ ctx.write(SCRIPT_JSON_FILENAME, JSON.pretty_generate(json))
152
158
 
153
- Domain::ConfigUi.new(
154
- filename: filename,
155
- content: content,
156
- )
159
+ Domain::ScriptJson.new(content: json)
157
160
  end
158
161
 
159
162
  private
160
163
 
161
- def valid_config_ui?(raw_yaml)
162
- require "yaml" # takes 20ms, so deferred as late as possible.
163
- YAML.safe_load(raw_yaml)
164
+ def current_script_json
165
+ return nil unless ctx.file_exist?(SCRIPT_JSON_FILENAME)
166
+
167
+ content = ctx.read(SCRIPT_JSON_FILENAME)
168
+ raise Domain::Errors::InvalidScriptJsonDefinitionError unless valid_script_json?(content)
169
+
170
+ Domain::ScriptJson.new(content: JSON.parse(content))
171
+ end
172
+
173
+ def valid_script_json?(content)
174
+ JSON.parse(content)
164
175
  true
165
- rescue Psych::SyntaxError
176
+ rescue JSON::ParserError
166
177
  false
167
178
  end
168
179
  end
@@ -13,26 +13,28 @@ module Script
13
13
  def push(
14
14
  uuid:,
15
15
  extension_point_type:,
16
- script_name:,
17
16
  script_content:,
18
17
  compiled_type:,
19
18
  api_key: nil,
20
19
  force: false,
21
20
  metadata:,
22
- config_ui:
21
+ script_json:
23
22
  )
24
23
  query_name = "app_script_update_or_create"
25
24
  variables = {
26
25
  uuid: uuid,
27
26
  extensionPointName: extension_point_type.upcase,
28
- title: script_name,
29
- configUi: config_ui&.content,
27
+ title: script_json.title,
28
+ description: script_json.description,
30
29
  sourceCode: Base64.encode64(script_content),
31
30
  language: compiled_type,
32
31
  force: force,
33
32
  schemaMajorVersion: metadata.schema_major_version.to_s, # API expects string value
34
33
  schemaMinorVersion: metadata.schema_minor_version.to_s, # API expects string value
35
34
  useMsgpack: metadata.use_msgpack,
35
+ scriptJsonVersion: script_json.version,
36
+ configurationUi: script_json.configuration_ui,
37
+ configurationDefinition: script_json.configuration&.to_json,
36
38
  }
37
39
  resp_hash = script_service_request(query_name: query_name, api_key: api_key, variables: variables)
38
40
  user_errors = resp_hash["data"]["appScriptUpdateOrCreate"]["userErrors"]
@@ -41,16 +43,20 @@ module Script
41
43
 
42
44
  if user_errors.any? { |e| e["tag"] == "already_exists_error" }
43
45
  raise Errors::ScriptRepushError, uuid
44
- elsif (e = user_errors.any? { |err| err["tag"] == "config_ui_syntax_error" })
45
- raise Errors::ConfigUiSyntaxError, config_ui&.filename
46
- elsif (e = user_errors.find { |err| err["tag"] == "config_ui_missing_keys_error" })
47
- raise Errors::ConfigUiMissingKeysError.new(config_ui&.filename, e["message"])
48
- elsif (e = user_errors.find { |err| err["tag"] == "config_ui_invalid_input_mode_error" })
49
- raise Errors::ConfigUiInvalidInputModeError.new(config_ui&.filename, e["message"])
50
- elsif (e = user_errors.find { |err| err["tag"] == "config_ui_fields_missing_keys_error" })
51
- raise Errors::ConfigUiFieldsMissingKeysError.new(config_ui&.filename, e["message"])
52
- elsif (e = user_errors.find { |err| err["tag"] == "config_ui_fields_invalid_type_error" })
53
- raise Errors::ConfigUiFieldsInvalidTypeError.new(config_ui&.filename, e["message"])
46
+ elsif (e = user_errors.any? { |err| err["tag"] == "configuration_syntax_error" })
47
+ raise Errors::ScriptJsonSyntaxError
48
+ elsif (e = user_errors.find { |err| err["tag"] == "configuration_definition_missing_keys_error" })
49
+ raise Errors::ScriptJsonMissingKeysError, e["message"]
50
+ elsif (e = user_errors.find { |err| err["tag"] == "configuration_definition_invalid_value_error" })
51
+ raise Errors::ScriptJsonInvalidValueError, e["message"]
52
+ elsif (e = user_errors.find do |err|
53
+ err["tag"] == "configuration_definition_schema_field_missing_keys_error"
54
+ end)
55
+ raise Errors::ScriptJsonFieldsMissingKeysError, e["message"]
56
+ elsif (e = user_errors.find do |err|
57
+ err["tag"] == "configuration_definition_schema_field_invalid_value_error"
58
+ end)
59
+ raise Errors::ScriptJsonFieldsInvalidValueError, e["message"]
54
60
  elsif user_errors.find { |err| %w(not_use_msgpack_error schema_version_argument_error).include?(err["tag"]) }
55
61
  raise Domain::Errors::MetadataValidationError
56
62
  else
@@ -69,19 +75,30 @@ module Script
69
75
  class ScriptServiceAPI < ShopifyCli::API
70
76
  property(:api_key, accepts: String)
71
77
 
78
+ LOCAL_INSTANCE_URL = "https://script-service.myshopify.io"
79
+
72
80
  def self.query(ctx, query_name, api_key: nil, variables: {})
73
81
  api_client(ctx, api_key).query(query_name, variables: variables)
74
82
  end
75
83
 
76
84
  def self.api_client(ctx, api_key)
85
+ instance_url = spin_instance_url || LOCAL_INSTANCE_URL
77
86
  new(
78
87
  ctx: ctx,
79
- url: "https://script-service.myshopify.io/graphql",
88
+ url: "#{instance_url}/graphql",
80
89
  token: "",
81
90
  api_key: api_key
82
91
  )
83
92
  end
84
93
 
94
+ def self.spin_instance_url
95
+ workspace = ENV["SPIN_WORKSPACE"]
96
+ namespace = ENV["SPIN_NAMESPACE"]
97
+ return if workspace.nil? || namespace.nil?
98
+
99
+ "https://script-service.#{workspace}.#{namespace}.us.spin.dev"
100
+ end
101
+
85
102
  def auth_headers(*)
86
103
  tokens = { "APP_KEY" => api_key }.compact.to_json
87
104
  { "X-Shopify-Authenticated-Tokens" => tokens }
@@ -98,7 +115,7 @@ module Script
98
115
  private_constant(:PartnersProxyAPI)
99
116
 
100
117
  def script_service_request(query_name:, variables: nil, **options)
101
- resp = if ENV["BYPASS_PARTNERS_PROXY"]
118
+ resp = if bypass_partners_proxy
102
119
  ScriptServiceAPI.query(ctx, query_name, variables: variables, **options)
103
120
  else
104
121
  proxy_through_partners(query_name: query_name, variables: variables, **options)
@@ -107,6 +124,10 @@ module Script
107
124
  resp
108
125
  end
109
126
 
127
+ def bypass_partners_proxy
128
+ !ENV["BYPASS_PARTNERS_PROXY"].nil?
129
+ end
130
+
110
131
  def proxy_through_partners(query_name:, variables: nil, **options)
111
132
  options[:variables] = variables.to_json if variables
112
133
  resp = PartnersProxyAPI.query(ctx, query_name, **options)