shopify-cli 1.12.0 → 2.0.1

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 (208) 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/PULL_REQUEST_TEMPLATE.md +1 -1
  6. data/.github/workflows/build.yml +1 -1
  7. data/.gitignore +3 -0
  8. data/.rubocop.yml +3 -1
  9. data/.ruby-version +1 -1
  10. data/CHANGELOG.md +52 -21
  11. data/Gemfile +4 -0
  12. data/Gemfile.lock +32 -0
  13. data/LICENSE +4 -1
  14. data/README.md +92 -26
  15. data/RELEASING.md +31 -7
  16. data/Rakefile +2 -2
  17. data/SECURITY.md +1 -1
  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/find_organization.graphql +2 -1
  36. data/lib/project_types/extension/cli.rb +18 -15
  37. data/lib/project_types/extension/commands/build.rb +4 -5
  38. data/lib/project_types/extension/commands/connect.rb +35 -0
  39. data/lib/project_types/extension/commands/create.rb +12 -16
  40. data/lib/project_types/extension/commands/extension_command.rb +2 -2
  41. data/lib/project_types/extension/commands/info.rb +86 -0
  42. data/lib/project_types/extension/commands/push.rb +8 -7
  43. data/lib/project_types/extension/commands/register.rb +4 -5
  44. data/lib/project_types/extension/commands/serve.rb +5 -8
  45. data/lib/project_types/extension/commands/tunnel.rb +3 -1
  46. data/lib/project_types/extension/errors.rb +9 -0
  47. data/lib/project_types/extension/extension_project.rb +5 -0
  48. data/lib/project_types/extension/features/argo.rb +6 -6
  49. data/lib/project_types/extension/features/argo_runtime.rb +22 -59
  50. data/lib/project_types/extension/features/argo_serve.rb +25 -21
  51. data/lib/project_types/extension/forms/connect.rb +42 -0
  52. data/lib/project_types/extension/forms/questions/ask_name.rb +14 -6
  53. data/lib/project_types/extension/forms/questions/ask_registration.rb +51 -0
  54. data/lib/project_types/extension/messages/messages.rb +75 -11
  55. data/lib/project_types/extension/models/specification.rb +1 -0
  56. data/lib/project_types/extension/models/specification_handlers/{checkout_argo_extension.rb → checkout_ui_extension.rb} +3 -1
  57. data/lib/project_types/extension/models/specification_handlers/default.rb +13 -13
  58. data/lib/project_types/extension/models/specification_handlers/theme_app_extension.rb +89 -0
  59. data/lib/project_types/extension/models/specifications.rb +1 -0
  60. data/lib/project_types/extension/tasks/configure_features.rb +6 -7
  61. data/lib/project_types/extension/tasks/configure_options.rb +20 -0
  62. data/lib/project_types/extension/tasks/get_extensions.rb +32 -0
  63. data/lib/project_types/node/cli.rb +9 -21
  64. data/lib/project_types/node/commands/connect.rb +8 -2
  65. data/lib/project_types/node/commands/create.rb +9 -5
  66. data/lib/project_types/node/commands/deploy.rb +15 -5
  67. data/lib/project_types/node/commands/deploy/heroku.rb +29 -29
  68. data/lib/project_types/node/commands/generate.rb +4 -2
  69. data/lib/project_types/node/commands/open.rb +4 -2
  70. data/lib/project_types/node/commands/serve.rb +3 -2
  71. data/lib/project_types/node/commands/tunnel.rb +4 -2
  72. data/lib/project_types/node/messages/messages.rb +46 -89
  73. data/lib/project_types/rails/cli.rb +9 -21
  74. data/lib/project_types/rails/commands/connect.rb +8 -2
  75. data/lib/project_types/rails/commands/create.rb +10 -6
  76. data/lib/project_types/rails/commands/deploy.rb +15 -5
  77. data/lib/project_types/rails/commands/deploy/heroku.rb +84 -82
  78. data/lib/project_types/rails/commands/generate.rb +15 -5
  79. data/lib/project_types/rails/commands/generate/webhook.rb +28 -26
  80. data/lib/project_types/rails/commands/open.rb +4 -2
  81. data/lib/project_types/rails/commands/serve.rb +3 -2
  82. data/lib/project_types/rails/commands/tunnel.rb +4 -2
  83. data/lib/project_types/rails/messages/messages.rb +54 -101
  84. data/lib/project_types/script/cli.rb +18 -20
  85. data/lib/project_types/script/commands/create.rb +3 -1
  86. data/lib/project_types/script/commands/push.rb +12 -5
  87. data/lib/project_types/script/config/extension_points.yml +0 -3
  88. data/lib/project_types/script/graphql/app_script_update_or_create.graphql +9 -3
  89. data/lib/project_types/script/layers/application/create_script.rb +6 -5
  90. data/lib/project_types/script/layers/application/push_script.rb +2 -1
  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 +14 -18
  96. data/lib/project_types/script/layers/infrastructure/languages/assemblyscript_project_creator.rb +105 -0
  97. data/lib/project_types/script/layers/infrastructure/languages/assemblyscript_task_runner.rb +103 -0
  98. data/lib/project_types/script/layers/infrastructure/languages/project_creator.rb +26 -0
  99. data/lib/project_types/script/layers/infrastructure/languages/rust_project_creator.rb +73 -0
  100. data/lib/project_types/script/layers/infrastructure/languages/rust_task_runner.rb +60 -0
  101. data/lib/project_types/script/layers/infrastructure/languages/task_runner.rb +21 -0
  102. data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +2 -4
  103. data/lib/project_types/script/layers/infrastructure/script_project_repository.rb +45 -34
  104. data/lib/project_types/script/layers/infrastructure/script_service.rb +37 -16
  105. data/lib/project_types/script/messages/messages.rb +66 -55
  106. data/lib/project_types/script/tasks/ensure_env.rb +22 -1
  107. data/lib/project_types/script/ui/error_handler.rb +32 -32
  108. data/lib/project_types/theme/cli.rb +16 -27
  109. data/lib/project_types/theme/commands/check.rb +33 -0
  110. data/lib/project_types/theme/commands/delete.rb +64 -0
  111. data/lib/project_types/theme/commands/init.rb +42 -0
  112. data/lib/project_types/theme/commands/language_server.rb +16 -0
  113. data/lib/project_types/theme/commands/package.rb +55 -0
  114. data/lib/project_types/theme/commands/publish.rb +43 -0
  115. data/lib/project_types/theme/commands/pull.rb +51 -0
  116. data/lib/project_types/theme/commands/push.rb +58 -32
  117. data/lib/project_types/theme/commands/serve.rb +8 -16
  118. data/lib/project_types/theme/forms/confirm_store.rb +15 -0
  119. data/lib/project_types/theme/forms/select.rb +59 -0
  120. data/lib/project_types/theme/messages/messages.rb +117 -102
  121. data/lib/project_types/theme/ui/sync_progress_bar.rb +20 -0
  122. data/lib/shopify-cli/admin_api.rb +53 -35
  123. data/lib/shopify-cli/admin_api/populate_resource_command.rb +6 -14
  124. data/lib/shopify-cli/admin_api/schema.rb +1 -10
  125. data/lib/shopify-cli/api.rb +29 -14
  126. data/lib/shopify-cli/command.rb +15 -3
  127. data/lib/shopify-cli/commands.rb +7 -2
  128. data/lib/shopify-cli/commands/help.rb +2 -29
  129. data/lib/shopify-cli/commands/login.rb +95 -0
  130. data/lib/shopify-cli/commands/logout.rb +24 -8
  131. data/lib/shopify-cli/commands/populate.rb +23 -0
  132. data/lib/{project_types/node → shopify-cli}/commands/populate/customer.rb +2 -8
  133. data/lib/{project_types/node → shopify-cli}/commands/populate/draft_order.rb +2 -2
  134. data/lib/{project_types/node → shopify-cli}/commands/populate/product.rb +2 -8
  135. data/lib/shopify-cli/commands/store.rb +15 -0
  136. data/lib/shopify-cli/commands/switch.rb +39 -0
  137. data/lib/shopify-cli/commands/system.rb +12 -0
  138. data/lib/shopify-cli/commands/whoami.rb +28 -0
  139. data/lib/shopify-cli/connect.rb +32 -0
  140. data/lib/shopify-cli/context.rb +65 -4
  141. data/lib/shopify-cli/core/entry_point.rb +3 -22
  142. data/lib/shopify-cli/db.rb +4 -4
  143. data/lib/shopify-cli/http_request.rb +16 -0
  144. data/lib/shopify-cli/identity_auth.rb +282 -0
  145. data/lib/shopify-cli/{oauth → identity_auth}/servlet.rb +11 -12
  146. data/lib/shopify-cli/messages/messages.rb +133 -39
  147. data/lib/shopify-cli/partners_api.rb +21 -41
  148. data/lib/shopify-cli/partners_api/organizations.rb +8 -0
  149. data/lib/shopify-cli/project_commands.rb +16 -0
  150. data/lib/shopify-cli/project_type.rb +0 -31
  151. data/lib/shopify-cli/resources/env_file.rb +1 -1
  152. data/lib/shopify-cli/shopifolk.rb +8 -11
  153. data/lib/shopify-cli/sub_command.rb +1 -0
  154. data/lib/shopify-cli/tasks.rb +3 -0
  155. data/lib/shopify-cli/tasks/confirm_store.rb +18 -0
  156. data/lib/shopify-cli/tasks/create_api_client.rb +2 -2
  157. data/lib/shopify-cli/tasks/ensure_authenticated.rb +13 -0
  158. data/lib/shopify-cli/tasks/ensure_loopback_url.rb +1 -1
  159. data/lib/shopify-cli/tasks/ensure_project_type.rb +12 -0
  160. data/lib/shopify-cli/tasks/select_org_and_shop.rb +0 -3
  161. data/lib/shopify-cli/theme/dev_server.rb +98 -0
  162. data/lib/shopify-cli/theme/dev_server/certificate_manager.rb +79 -0
  163. data/lib/shopify-cli/theme/dev_server/header_hash.rb +94 -0
  164. data/lib/shopify-cli/theme/dev_server/hot-reload.js +93 -0
  165. data/lib/shopify-cli/theme/dev_server/hot_reload.rb +76 -0
  166. data/lib/shopify-cli/theme/dev_server/local_assets.rb +87 -0
  167. data/lib/shopify-cli/theme/dev_server/proxy.rb +205 -0
  168. data/lib/shopify-cli/theme/dev_server/sse.rb +75 -0
  169. data/lib/shopify-cli/theme/dev_server/watcher.rb +59 -0
  170. data/lib/shopify-cli/theme/dev_server/web_server.rb +140 -0
  171. data/lib/shopify-cli/theme/development_theme.rb +69 -0
  172. data/lib/shopify-cli/theme/file.rb +112 -0
  173. data/lib/shopify-cli/theme/ignore_filter.rb +109 -0
  174. data/lib/shopify-cli/theme/mime_type.rb +34 -0
  175. data/lib/shopify-cli/theme/syncer.rb +328 -0
  176. data/lib/shopify-cli/theme/theme.rb +204 -0
  177. data/lib/shopify-cli/version.rb +1 -1
  178. data/lib/shopify_cli.rb +18 -11
  179. data/shopify-cli.gemspec +12 -5
  180. data/shopify.fish +1 -1
  181. data/shopify.sh +1 -1
  182. metadata +96 -41
  183. data/.github/workflows/release.yml +0 -61
  184. data/lib/project_types/extension/features/argo_serve_options.rb +0 -41
  185. data/lib/project_types/node/commands/populate.rb +0 -23
  186. data/lib/project_types/rails/commands/populate.rb +0 -23
  187. data/lib/project_types/rails/commands/populate/customer.rb +0 -31
  188. data/lib/project_types/rails/commands/populate/draft_order.rb +0 -28
  189. data/lib/project_types/rails/commands/populate/product.rb +0 -30
  190. data/lib/project_types/script/layers/domain/config_ui.rb +0 -16
  191. data/lib/project_types/script/layers/infrastructure/assemblyscript_project_creator.rb +0 -95
  192. data/lib/project_types/script/layers/infrastructure/assemblyscript_task_runner.rb +0 -101
  193. data/lib/project_types/script/layers/infrastructure/project_creator.rb +0 -24
  194. data/lib/project_types/script/layers/infrastructure/rust_project_creator.rb +0 -71
  195. data/lib/project_types/script/layers/infrastructure/rust_task_runner.rb +0 -58
  196. data/lib/project_types/script/layers/infrastructure/task_runner.rb +0 -19
  197. data/lib/project_types/theme/commands/connect.rb +0 -54
  198. data/lib/project_types/theme/commands/create.rb +0 -48
  199. data/lib/project_types/theme/commands/deploy.rb +0 -38
  200. data/lib/project_types/theme/commands/generate.rb +0 -20
  201. data/lib/project_types/theme/commands/generate/env.rb +0 -79
  202. data/lib/project_types/theme/forms/connect.rb +0 -34
  203. data/lib/project_types/theme/forms/create.rb +0 -22
  204. data/lib/project_types/theme/tasks/ensure_themekit_installed.rb +0 -78
  205. data/lib/project_types/theme/themekit.rb +0 -113
  206. data/lib/shopify-cli/commands/connect.rb +0 -64
  207. data/lib/shopify-cli/commands/create.rb +0 -50
  208. data/lib/shopify-cli/oauth.rb +0 -198
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+ module Script
3
+ module Layers
4
+ module Infrastructure
5
+ module Languages
6
+ class RustTaskRunner
7
+ attr_reader :ctx
8
+
9
+ BUILD_TARGET = "wasm32-unknown-unknown"
10
+ METADATA_FILE = "build/metadata.json"
11
+ CARGO_BUILD_CMD = "cargo build --target=#{BUILD_TARGET} --release"
12
+
13
+ def initialize(ctx, _)
14
+ @ctx = ctx
15
+ end
16
+
17
+ def dependencies_installed?
18
+ true
19
+ end
20
+
21
+ def install_dependencies
22
+ end
23
+
24
+ def build
25
+ compile
26
+ bytecode
27
+ end
28
+
29
+ def compiled_type
30
+ "wasm"
31
+ end
32
+
33
+ def metadata
34
+ unless @ctx.file_exist?(METADATA_FILE)
35
+ msg = @ctx.message("script.error.metadata_not_found_cause", METADATA_FILE)
36
+ raise Domain::Errors::MetadataNotFoundError, msg
37
+ end
38
+
39
+ raw_contents = File.read(METADATA_FILE)
40
+ Domain::Metadata.create_from_json(@ctx, raw_contents)
41
+ end
42
+
43
+ private
44
+
45
+ def compile
46
+ CommandRunner.new(ctx: ctx).call(CARGO_BUILD_CMD)
47
+ end
48
+
49
+ def bytecode
50
+ binary_name = "script.wasm"
51
+ binary_path = "target/#{BUILD_TARGET}/release/#{binary_name}"
52
+ raise Errors::WebAssemblyBinaryNotFoundError unless ctx.file_exist?(binary_path)
53
+
54
+ ctx.binread(binary_path)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Script
4
+ module Layers
5
+ module Infrastructure
6
+ module Languages
7
+ class TaskRunner
8
+ TASK_RUNNERS = {
9
+ "assemblyscript" => AssemblyScriptTaskRunner,
10
+ "rust" => RustTaskRunner,
11
+ }
12
+
13
+ def self.for(ctx, language, script_name)
14
+ raise Errors::TaskRunnerNotFoundError unless TASK_RUNNERS[language]
15
+ TASK_RUNNERS[language].new(ctx, script_name)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ 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)
@@ -4,22 +4,28 @@ module Script
4
4
  module Messages
5
5
  MESSAGES = {
6
6
  script: {
7
+ help: <<~HELP,
8
+ Suite of commands for developing script applications. See {{command:%1$s script <command> --help}} for usage of each command.
9
+ Usage: {{command:%1$s script [ %2$s ]}}
10
+ HELP
11
+
7
12
  error: {
8
- deprecated_ep: "This project uses an extension point %s which has been deprecated. "\
9
- "This Script will no longer function in production.",
10
- deprecated_ep_cause: "Try using a different extension point.",
13
+ deprecated_ep: "This project uses a Script API (%s) that has been deprecated. "\
14
+ "This Script won't work in production.",
15
+ deprecated_ep_cause: "Try using a different Script API.",
11
16
  generic: "{{red:{{x}} Error}}",
12
17
  eacces_cause: "You don't have permission to write to this directory.",
13
- eacces_help: "Change your directory permissions and try again.",
18
+ eacces_help: "Try again and choose a different directory.",
14
19
 
15
- enospc_cause: "You don't have enough disk space to perform this action.",
20
+ enospc_cause: "You don't have enough disk space to do this action.",
16
21
  enospc_help: "Free up some space and try again.",
17
22
 
18
23
  oauth_cause: "Something went wrong while authenticating your account with the Partner Dashboard.",
19
24
  oauth_help: "Try again.",
20
25
 
21
- invalid_context_cause: "Your .shopify-cli.yml file is not correct.",
22
- invalid_context_help: "See https://help.shopify.com",
26
+ invalid_context_cause: "Your .shopify-cli.yml file is not correct. Values are missing for "\
27
+ "extension_point_type or script_name.",
28
+ invalid_context_help: "Add these values and try again.",
23
29
 
24
30
  invalid_config_props_cause: "{{command:--config-props}} is formatted incorrectly.",
25
31
  invalid_config_props_help: "Try again using this format: "\
@@ -29,68 +35,72 @@ module Script
29
35
  invalid_script_name_help: "Replace or remove unsupported characters. Valid characters "\
30
36
  "are numbers, letters, hyphens, or underscores.",
31
37
 
32
- no_existing_apps_cause: "You don't have any apps.",
33
- no_existing_apps_help: "Create an app with {{command:shopify create}} or "\
34
- "visit https://partners.shopify.com/.",
38
+ no_existing_apps_cause: "You don't have any apps in your Partner Dashboard.",
39
+ no_existing_apps_help: "Create an app with {{command:shopify [node|rails] create}}" \
40
+ " or visit https://partners.shopify.com/.",
35
41
 
36
42
  no_existing_orgs_cause: "You don't have any partner organizations.",
37
43
  no_existing_orgs_help: "Visit https://partners.shopify.com/ to create a partners account.",
38
44
 
39
- no_existing_stores_cause: "You don't have any stores.",
45
+ no_existing_stores_cause: "You don't have any stores in your Partner Dashboard.",
40
46
  no_existing_stores_help: "Visit https://partners.shopify.com/%{organization_id}/stores/ to create one.",
41
47
 
42
- project_exists_cause: "Directory with the same name as the script already exists.",
43
- project_exists_help: "Use different script name and try again.",
48
+ project_exists_cause: "A directory with this same name already exists.",
49
+ project_exists_help: "Try again and enter a different name for the script.",
44
50
 
45
- invalid_extension_cause: "Invalid extension point %s.",
51
+ invalid_extension_cause: "Invalid Script API %s.",
46
52
  invalid_extension_help: "Allowed values: %s.",
47
53
 
48
54
  invalid_language_cause: "Invalid language %s.",
49
55
  invalid_language_help: "Allowed values: %s.",
50
56
 
51
57
  invalid_config: "Can't change the configuration values because %1$s is missing or "\
52
- "it is not formatted properly.",
58
+ "it isn't formatted properly.",
59
+
60
+ missing_script_json_field_cause: "The script.json file is missing the required %s field.",
61
+ missing_script_json_field_help: "Add the field and try again.",
53
62
 
54
- invalid_config_ui_definition_cause: "The UI configuration file %s contains invalid YAML.",
55
- invalid_config_ui_definition_help: "Fix the errors and try again.",
63
+ invalid_script_json_definition_cause: "The script.json file contains invalid JSON.",
64
+ invalid_script_json_definition_help: "Fix the errors and try again.",
56
65
 
57
- missing_config_ui_definition_cause: "You are missing the UI configuration file %s.",
58
- missing_config_ui_definition_help: "Create this file and try again.",
66
+ no_script_json_file_cause: "The script.json file is missing.",
67
+ no_script_json_file_help: "Create this file and try again.",
59
68
 
60
- config_ui_syntax_error_cause: "The UI configuration file %{filename} is not formatted properly.",
61
- config_ui_syntax_error_help: "Fix the errors and try again.",
69
+ configuration_syntax_error_cause: "The script.json is not formatted properly.",
70
+ configuration_syntax_error_help: "Fix the errors and try again.",
62
71
 
63
- config_ui_missing_keys_error_cause: "The UI configuration file %{filename} is missing required keys: "\
72
+ configuration_missing_keys_error_cause: "The script.json file is missing required keys: "\
64
73
  "%{missing_keys}.",
65
- config_ui_missing_keys_error_help: "Add the keys and try again.",
74
+ configuration_missing_keys_error_help: "Add the keys and try again.",
66
75
 
67
- config_ui_invalid_input_mode_error_cause: "The UI configuration file %{filename} only accept "\
68
- "one of the following input mode(s): %{valid_input_modes}.",
69
- config_ui_invalid_input_mode_error_help: "Change the input modes and try again.",
76
+ configuration_invalid_value_error_cause: "The script.json configuration only accepts "\
77
+ "one of the following types(s): %{valid_input_modes}.",
78
+ configuration_invalid_value_error_help: "Change the type and try again.",
70
79
 
71
- config_ui_fields_missing_keys_error_cause: "A field entry in the UI configuration file %{filename} is "\
72
- "missing required keys: %{missing_keys}.",
73
- config_ui_fields_missing_keys_error_help: "Add the keys and try again.",
80
+ configuration_schema_field_missing_keys_error_cause: "A configuration entry in the script.json file "\
81
+ "is missing required keys: %{missing_keys}.",
82
+ configuration_definition_schema_field_missing_keys_error_help: "Add the keys and try again.",
74
83
 
75
- config_ui_fields_invalid_type_error_cause: "The UI configuration file %{filename} fields only accept "\
76
- "one of the following type(s): %{valid_types}.",
77
- config_ui_fields_invalid_type_error_help: "Change the types and try again.",
84
+ configuration_schema_field_invalid_value_error_cause: "The configuration entries in the "\
85
+ "script.json file only accept one of the following "\
86
+ "type(s): %{valid_types}.",
87
+ configuration_schema_field_invalid_value_error_help: "Change the types and try again.",
78
88
 
79
- script_not_found_cause: "Couldn't find script %s for extension point %s",
89
+ script_not_found_cause: "Couldn't find a script %s for the Script API %s",
80
90
 
81
91
  system_call_failure_cause: "An error was returned while running {{command:%{cmd}}}.",
82
92
  system_call_failure_help: "Review the following error and try again.\n{{red:%{out}}}",
83
93
 
84
- metadata_validation_cause: "Invalid script extension metadata.",
94
+ metadata_validation_cause: "Invalid Script API metadata.",
85
95
  metadata_validation_help: "Ensure the 'shopify/scripts-toolchain-as' package is up to date.",
86
96
 
87
- metadata_schema_versions_missing: "Invalid script metadata:" \
97
+ metadata_schema_versions_missing: "Invalid Script metadata:" \
88
98
  " 'schemaVersions' field is missing",
89
- metadata_schema_versions_single_key: "Invalid script extension metadata:" \
90
- " 'schemaVersions' can have only one extension point name.",
91
- metadata_schema_versions_missing_major: "Invalid script extension metadata:" \
99
+ metadata_schema_versions_single_key: "Invalid Script API metadata:" \
100
+ " 'schemaVersions' can have only one Script API name.",
101
+ metadata_schema_versions_missing_major: "Invalid Script API metadata:" \
92
102
  " 'schemaVersions' is missing the 'major' field",
93
- metadata_schema_versions_missing_minor: "Invalid script extension metadata:" \
103
+ metadata_schema_versions_missing_minor: "Invalid Script API metadata:" \
94
104
  " 'schemaVersions' is missing the 'minor' field",
95
105
 
96
106
  metadata_not_found_cause: "Script version file (%s) cannot be found.",
@@ -102,7 +112,7 @@ module Script
102
112
  build_error_cause: "Something went wrong while building the script.",
103
113
  build_error_help: "Correct the errors and try again.",
104
114
 
105
- dependency_install_cause: "Something went wrong while installing the dependencies that are needed.",
115
+ dependency_install_cause: "Something went wrong while installing the needed dependencies.",
106
116
  dependency_install_help: "Correct the errors and try again.",
107
117
 
108
118
  failed_api_request_cause: "Something went wrong while communicating with Shopify.",
@@ -113,7 +123,7 @@ module Script
113
123
  graphql_error_cause: "An error was returned: %s.",
114
124
  graphql_error_help: "\nReview the error and try again.",
115
125
 
116
- script_repush_cause: "A script with this UUID already exists (UUID: %s).",
126
+ script_repush_cause: "A version of this script already exists on the app.",
117
127
  script_repush_help: "Use {{cyan:--force}} to replace the existing script.",
118
128
 
119
129
  shop_auth_cause: "Unable to authenticate with the store.",
@@ -135,12 +145,12 @@ module Script
135
145
 
136
146
  create: {
137
147
  help: <<~HELP,
138
- {{command:%1$s create script}}: Creates a script project.
139
- Usage: {{command:%1$s create script}}
140
- Options:
141
- {{command:--name=NAME}} Script project name. Use any string.
142
- {{command:--extension-point=TYPE}} Extension point name. Allowed values: %2$s.
143
- {{command:--no-config-ui}} Specify this option if you don’t want Scripts to render an interface in the Shopify admin.
148
+ {{command:%1$s script create}}: Creates a script project.
149
+ Usage: {{command:%1$s script create}}
150
+ Options:
151
+ {{command:--name=NAME}} Script project name. Use any string.
152
+ {{command:--extension-point=TYPE}} Script API name. Allowed values: %2$s.
153
+ {{command:--no-config-ui}} Specify this option when you don’t want your script to render an interface in Shopify admin.
144
154
  HELP
145
155
 
146
156
  error: {
@@ -154,14 +164,15 @@ module Script
154
164
 
155
165
  push: {
156
166
  help: <<~HELP,
157
- Build the script and put it into production. If you've already pushed a script with the same extension point, use --force to replace the current script with the newest one.
158
- Usage: {{command:%s push}}
159
- Options:
160
- {{command:[--force]}} Forces the script to be overwritten if an instance of it already exists.
167
+ Build the script, upload it to Shopify, and register it to an app. If you've already pushed the script to this app, then use --force to replace the existing version on the app.
168
+ Usage: {{command:%s script push}}
169
+ Options:
170
+ {{command:[--force]}} Replaces the existing script on the app with this version.
161
171
  HELP
162
172
 
163
173
  error: {
164
- operation_failed: "Couldn't push script to app (API key: %{api_key}).",
174
+ operation_failed_with_api_key: "Couldn't push script to app (API key: %{api_key}).",
175
+ operation_failed_no_api_key: "Couldn't push script to app.",
165
176
  },
166
177
 
167
178
  script_pushed: "{{v}} Script pushed to app (API key: %{api_key}).",
@@ -176,9 +187,9 @@ module Script
176
187
 
177
188
  forms: {
178
189
  create: {
179
- select_extension_point: "Which extension point do you want to use?",
190
+ select_extension_point: "Which Script API do you want to use?",
180
191
  select_language: "Which language do you want to use?",
181
- script_name: "Script Name",
192
+ script_name: "Script name",
182
193
  },
183
194
  },
184
195
 
@@ -198,7 +209,7 @@ module Script
198
209
  app: "Script will be pushed to app {{green:%s}}.",
199
210
  app_select: "Which app do you want to push this script to?",
200
211
  ask_connect_to_existing_script: "The selected app has some scripts. Do you want to replace any of the "\
201
- "existing scripts with the current script?",
212
+ "existing scripts on the app with this script?",
202
213
  ask_which_script_to_connect_to: "Which script do you want to replace?",
203
214
  },
204
215
  },