shopify-cli 1.11.0 → 2.0.0

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 (207) 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 +48 -20
  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 +29 -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 -38
  50. data/lib/project_types/extension/features/argo_serve.rb +25 -20
  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 +21 -6
  58. data/lib/project_types/extension/models/specification_handlers/theme_app_extension.rb +86 -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 +20 -14
  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 +15 -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/language_server.rb +16 -0
  112. data/lib/project_types/theme/commands/package.rb +55 -0
  113. data/lib/project_types/theme/commands/publish.rb +43 -0
  114. data/lib/project_types/theme/commands/pull.rb +51 -0
  115. data/lib/project_types/theme/commands/push.rb +58 -32
  116. data/lib/project_types/theme/commands/serve.rb +7 -17
  117. data/lib/project_types/theme/forms/confirm_store.rb +15 -0
  118. data/lib/project_types/theme/forms/select.rb +59 -0
  119. data/lib/project_types/theme/messages/messages.rb +110 -106
  120. data/lib/project_types/theme/ui/sync_progress_bar.rb +20 -0
  121. data/lib/shopify-cli/admin_api.rb +53 -35
  122. data/lib/shopify-cli/admin_api/populate_resource_command.rb +6 -14
  123. data/lib/shopify-cli/admin_api/schema.rb +1 -10
  124. data/lib/shopify-cli/api.rb +29 -14
  125. data/lib/shopify-cli/command.rb +15 -3
  126. data/lib/shopify-cli/commands.rb +7 -2
  127. data/lib/shopify-cli/commands/help.rb +2 -29
  128. data/lib/shopify-cli/commands/login.rb +95 -0
  129. data/lib/shopify-cli/commands/logout.rb +24 -8
  130. data/lib/shopify-cli/commands/populate.rb +23 -0
  131. data/lib/{project_types/node → shopify-cli}/commands/populate/customer.rb +2 -8
  132. data/lib/{project_types/node → shopify-cli}/commands/populate/draft_order.rb +2 -2
  133. data/lib/{project_types/node → shopify-cli}/commands/populate/product.rb +2 -8
  134. data/lib/shopify-cli/commands/store.rb +15 -0
  135. data/lib/shopify-cli/commands/switch.rb +39 -0
  136. data/lib/shopify-cli/commands/system.rb +12 -0
  137. data/lib/shopify-cli/commands/whoami.rb +28 -0
  138. data/lib/shopify-cli/connect.rb +32 -0
  139. data/lib/shopify-cli/context.rb +65 -4
  140. data/lib/shopify-cli/core/entry_point.rb +3 -22
  141. data/lib/shopify-cli/db.rb +4 -4
  142. data/lib/shopify-cli/http_request.rb +10 -0
  143. data/lib/shopify-cli/identity_auth.rb +282 -0
  144. data/lib/shopify-cli/{oauth → identity_auth}/servlet.rb +11 -12
  145. data/lib/shopify-cli/messages/messages.rb +133 -39
  146. data/lib/shopify-cli/partners_api.rb +21 -41
  147. data/lib/shopify-cli/partners_api/organizations.rb +8 -0
  148. data/lib/shopify-cli/project_commands.rb +16 -0
  149. data/lib/shopify-cli/project_type.rb +0 -31
  150. data/lib/shopify-cli/resources/env_file.rb +1 -1
  151. data/lib/shopify-cli/shopifolk.rb +8 -11
  152. data/lib/shopify-cli/sub_command.rb +1 -0
  153. data/lib/shopify-cli/tasks.rb +3 -0
  154. data/lib/shopify-cli/tasks/confirm_store.rb +18 -0
  155. data/lib/shopify-cli/tasks/create_api_client.rb +2 -2
  156. data/lib/shopify-cli/tasks/ensure_authenticated.rb +13 -0
  157. data/lib/shopify-cli/tasks/ensure_loopback_url.rb +1 -1
  158. data/lib/shopify-cli/tasks/ensure_project_type.rb +12 -0
  159. data/lib/shopify-cli/tasks/select_org_and_shop.rb +0 -3
  160. data/lib/shopify-cli/theme/dev_server.rb +98 -0
  161. data/lib/shopify-cli/theme/dev_server/certificate_manager.rb +79 -0
  162. data/lib/shopify-cli/theme/dev_server/header_hash.rb +94 -0
  163. data/lib/shopify-cli/theme/dev_server/hot-reload.js +93 -0
  164. data/lib/shopify-cli/theme/dev_server/hot_reload.rb +76 -0
  165. data/lib/shopify-cli/theme/dev_server/local_assets.rb +87 -0
  166. data/lib/shopify-cli/theme/dev_server/proxy.rb +205 -0
  167. data/lib/shopify-cli/theme/dev_server/sse.rb +75 -0
  168. data/lib/shopify-cli/theme/dev_server/watcher.rb +59 -0
  169. data/lib/shopify-cli/theme/dev_server/web_server.rb +140 -0
  170. data/lib/shopify-cli/theme/development_theme.rb +69 -0
  171. data/lib/shopify-cli/theme/file.rb +112 -0
  172. data/lib/shopify-cli/theme/ignore_filter.rb +109 -0
  173. data/lib/shopify-cli/theme/mime_type.rb +34 -0
  174. data/lib/shopify-cli/theme/syncer.rb +328 -0
  175. data/lib/shopify-cli/theme/theme.rb +204 -0
  176. data/lib/shopify-cli/version.rb +1 -1
  177. data/lib/shopify_cli.rb +18 -11
  178. data/shopify-cli.gemspec +12 -5
  179. data/shopify.fish +1 -1
  180. data/shopify.sh +1 -1
  181. metadata +95 -41
  182. data/.github/workflows/release.yml +0 -61
  183. data/lib/project_types/extension/features/argo_serve_options.rb +0 -40
  184. data/lib/project_types/node/commands/populate.rb +0 -23
  185. data/lib/project_types/rails/commands/populate.rb +0 -23
  186. data/lib/project_types/rails/commands/populate/customer.rb +0 -31
  187. data/lib/project_types/rails/commands/populate/draft_order.rb +0 -28
  188. data/lib/project_types/rails/commands/populate/product.rb +0 -30
  189. data/lib/project_types/script/layers/domain/config_ui.rb +0 -16
  190. data/lib/project_types/script/layers/infrastructure/assemblyscript_project_creator.rb +0 -95
  191. data/lib/project_types/script/layers/infrastructure/assemblyscript_task_runner.rb +0 -101
  192. data/lib/project_types/script/layers/infrastructure/project_creator.rb +0 -24
  193. data/lib/project_types/script/layers/infrastructure/rust_project_creator.rb +0 -71
  194. data/lib/project_types/script/layers/infrastructure/rust_task_runner.rb +0 -58
  195. data/lib/project_types/script/layers/infrastructure/task_runner.rb +0 -19
  196. data/lib/project_types/theme/commands/connect.rb +0 -54
  197. data/lib/project_types/theme/commands/create.rb +0 -48
  198. data/lib/project_types/theme/commands/deploy.rb +0 -38
  199. data/lib/project_types/theme/commands/generate.rb +0 -20
  200. data/lib/project_types/theme/commands/generate/env.rb +0 -79
  201. data/lib/project_types/theme/forms/connect.rb +0 -34
  202. data/lib/project_types/theme/forms/create.rb +0 -22
  203. data/lib/project_types/theme/tasks/ensure_themekit_installed.rb +0 -78
  204. data/lib/project_types/theme/themekit.rb +0 -113
  205. data/lib/shopify-cli/commands/connect.rb +0 -64
  206. data/lib/shopify-cli/commands/create.rb +0 -50
  207. data/lib/shopify-cli/oauth.rb +0 -198
@@ -11,7 +11,7 @@ module Script
11
11
  script_project_repo = Layers::Infrastructure::ScriptProjectRepository.new(ctx: ctx)
12
12
  script_project = script_project_repo.get
13
13
 
14
- return if script_project.api_key && script_project.api_secret && script_project.uuid_defined?
14
+ return false if script_project.api_key && script_project.api_secret && script_project.uuid_defined?
15
15
 
16
16
  org = ask_org
17
17
  app = ask_app(org["apps"])
@@ -22,11 +22,15 @@ module Script
22
22
  secret: app["apiSecretKeys"].first["secret"],
23
23
  uuid: uuid
24
24
  )
25
+
26
+ true
25
27
  end
26
28
 
27
29
  private
28
30
 
29
31
  def ask_org
32
+ return stubbed_org if partner_proxy_bypass
33
+
30
34
  if ShopifyCli::Shopifolk.check && wants_to_run_against_shopify_org?
31
35
  ShopifyCli::Shopifolk.act_as_shopify_organization
32
36
  end
@@ -47,6 +51,23 @@ module Script
47
51
  end
48
52
  end
49
53
 
54
+ def stubbed_org
55
+ {
56
+ "apps" => [
57
+ {
58
+ "appType" => "custom",
59
+ "apiKey" => "stubbed-api-key",
60
+ "apiSecretKeys" => [{ "secret" => "stubbed-api-secret" }],
61
+ "title" => "Fake App (Not connected to Partners)",
62
+ },
63
+ ],
64
+ }
65
+ end
66
+
67
+ def partner_proxy_bypass
68
+ !ENV["BYPASS_PARTNERS_PROXY"].nil?
69
+ end
70
+
50
71
  def ask_app(apps)
51
72
  unless ShopifyCli::Shopifolk.acting_as_shopify_organization?
52
73
  apps = apps.select { |app| app["appType"] == "custom" }
@@ -34,7 +34,7 @@ module Script
34
34
  cause_of_error: ShopifyCli::Context.message("script.error.enospc_cause"),
35
35
  help_suggestion: ShopifyCli::Context.message("script.error.enospc_help"),
36
36
  }
37
- when ShopifyCli::OAuth::Error
37
+ when ShopifyCli::IdentityAuth::Error
38
38
  {
39
39
  cause_of_error: ShopifyCli::Context.message("script.error.oauth_cause"),
40
40
  help_suggestion: ShopifyCli::Context.message("script.error.oauth_help"),
@@ -120,17 +120,20 @@ module Script
120
120
  cause_of_error: ShopifyCli::Context.message("script.error.metadata_not_found_cause"),
121
121
  help_suggestion: ShopifyCli::Context.message("script.error.metadata_not_found_help"),
122
122
  }
123
- when Layers::Domain::Errors::InvalidConfigUiDefinitionError
123
+ when Layers::Domain::Errors::MissingScriptJsonFieldError
124
124
  {
125
- cause_of_error: ShopifyCli::Context
126
- .message("script.error.invalid_config_ui_definition_cause", e.filename),
127
- help_suggestion: ShopifyCli::Context.message("script.error.invalid_config_ui_definition_help"),
125
+ cause_of_error: ShopifyCli::Context.message("script.error.missing_script_json_field_cause", e.field),
126
+ help_suggestion: ShopifyCli::Context.message("script.error.missing_script_json_field_help"),
128
127
  }
129
- when Layers::Domain::Errors::MissingSpecifiedConfigUiDefinitionError
128
+ when Layers::Domain::Errors::InvalidScriptJsonDefinitionError
130
129
  {
131
- cause_of_error: ShopifyCli::Context
132
- .message("script.error.missing_config_ui_definition_cause", e.filename),
133
- help_suggestion: ShopifyCli::Context.message("script.error.missing_config_ui_definition_help"),
130
+ cause_of_error: ShopifyCli::Context.message("script.error.invalid_script_json_definition_cause"),
131
+ help_suggestion: ShopifyCli::Context.message("script.error.invalid_script_json_definition_help"),
132
+ }
133
+ when Layers::Domain::Errors::NoScriptJsonFile
134
+ {
135
+ cause_of_error: ShopifyCli::Context.message("script.error.no_script_json_file_cause"),
136
+ help_suggestion: ShopifyCli::Context.message("script.error.no_script_json_file_help"),
134
137
  }
135
138
  when Layers::Infrastructure::Errors::AppNotInstalledError
136
139
  {
@@ -141,49 +144,46 @@ module Script
141
144
  cause_of_error: ShopifyCli::Context.message("script.error.build_error_cause"),
142
145
  help_suggestion: ShopifyCli::Context.message("script.error.build_error_help"),
143
146
  }
144
- when Layers::Infrastructure::Errors::ConfigUiSyntaxError
147
+ when Layers::Infrastructure::Errors::ScriptJsonSyntaxError
145
148
  {
146
- cause_of_error: ShopifyCli::Context.message(
147
- "script.error.config_ui_syntax_error_cause",
148
- filename: e.message
149
- ),
150
- help_suggestion: ShopifyCli::Context.message("script.error.config_ui_syntax_error_help"),
149
+ cause_of_error: ShopifyCli::Context.message("script.error.configuration_syntax_error_cause"),
150
+ help_suggestion: ShopifyCli::Context.message("script.error.configuration_syntax_error_help"),
151
151
  }
152
- when Layers::Infrastructure::Errors::ConfigUiMissingKeysError
152
+ when Layers::Infrastructure::Errors::ScriptJsonMissingKeysError
153
153
  {
154
154
  cause_of_error: ShopifyCli::Context.message(
155
- "script.error.config_ui_missing_keys_error_cause",
156
- filename: e.filename,
155
+ "script.error.configuration_missing_keys_error_cause",
157
156
  missing_keys: e.missing_keys
158
157
  ),
159
- help_suggestion: ShopifyCli::Context.message("script.error.config_ui_missing_keys_error_help"),
158
+ help_suggestion: ShopifyCli::Context.message("script.error.configuration_missing_keys_error_help"),
160
159
  }
161
- when Layers::Infrastructure::Errors::ConfigUiInvalidInputModeError
160
+ when Layers::Infrastructure::Errors::ScriptJsonInvalidValueError
162
161
  {
163
162
  cause_of_error: ShopifyCli::Context.message(
164
- "script.error.config_ui_invalid_input_mode_error_cause",
165
- filename: e.filename,
163
+ "script.error.configuration_invalid_value_error_cause",
166
164
  valid_input_modes: e.valid_input_modes
167
165
  ),
168
- help_suggestion: ShopifyCli::Context.message("script.error.config_ui_invalid_input_mode_error_help"),
166
+ help_suggestion: ShopifyCli::Context.message("script.error.configuration_invalid_value_error_help"),
169
167
  }
170
- when Layers::Infrastructure::Errors::ConfigUiFieldsMissingKeysError
168
+ when Layers::Infrastructure::Errors::ScriptJsonFieldsMissingKeysError
171
169
  {
172
170
  cause_of_error: ShopifyCli::Context.message(
173
- "script.error.config_ui_fields_missing_keys_error_cause",
174
- filename: e.filename,
171
+ "script.error.configuration_schema_field_missing_keys_error_cause",
175
172
  missing_keys: e.missing_keys
176
173
  ),
177
- help_suggestion: ShopifyCli::Context.message("script.error.config_ui_fields_missing_keys_error_help"),
174
+ help_suggestion: ShopifyCli::Context.message(
175
+ "script.error.configuration_definition_schema_field_missing_keys_error_help"
176
+ ),
178
177
  }
179
- when Layers::Infrastructure::Errors::ConfigUiFieldsInvalidTypeError
178
+ when Layers::Infrastructure::Errors::ScriptJsonFieldsInvalidValueError
180
179
  {
181
180
  cause_of_error: ShopifyCli::Context.message(
182
- "script.error.config_ui_fields_invalid_type_error_cause",
183
- filename: e.filename,
181
+ "script.error.configuration_schema_field_invalid_value_error_cause",
184
182
  valid_types: e.valid_types
185
183
  ),
186
- help_suggestion: ShopifyCli::Context.message("script.error.config_ui_fields_invalid_type_error_help"),
184
+ help_suggestion: ShopifyCli::Context.message(
185
+ "script.error.configuration_schema_field_invalid_value_error_help"
186
+ ),
187
187
  }
188
188
  when Layers::Infrastructure::Errors::DependencyInstallError
189
189
  {
@@ -214,7 +214,7 @@ module Script
214
214
  }
215
215
  when Layers::Infrastructure::Errors::ScriptRepushError
216
216
  {
217
- cause_of_error: ShopifyCli::Context.message("script.error.script_repush_cause", e.uuid),
217
+ cause_of_error: ShopifyCli::Context.message("script.error.script_repush_cause"),
218
218
  help_suggestion: ShopifyCli::Context.message("script.error.script_repush_help"),
219
219
  }
220
220
  when Layers::Infrastructure::Errors::ShopAuthenticationError
@@ -1,40 +1,28 @@
1
1
  # frozen_string_literal: true
2
2
  module Theme
3
3
  class Project < ShopifyCli::ProjectType
4
- hidden_feature
5
-
6
- title("Theme")
7
- creator("Theme::Commands::Create")
8
- connector("Theme::Commands::Connect")
9
-
10
- register_command("Theme::Commands::Deploy", "deploy")
11
- register_command("Theme::Commands::Generate", "generate")
12
- register_command("Theme::Commands::Push", "push")
13
- register_command("Theme::Commands::Serve", "serve")
14
-
15
- register_task("Theme::Tasks::EnsureThemekitInstalled", :ensure_themekit_installed)
16
-
17
4
  require Project.project_filepath("messages/messages")
18
5
  register_messages(Theme::Messages::MESSAGES)
19
6
  end
20
7
 
21
- module Commands
22
- autoload :Connect, Project.project_filepath("commands/connect")
23
- autoload :Create, Project.project_filepath("commands/create")
24
- autoload :Deploy, Project.project_filepath("commands/deploy")
25
- autoload :Generate, Project.project_filepath("commands/generate")
26
- autoload :Push, Project.project_filepath("commands/push")
27
- autoload :Serve, Project.project_filepath("commands/serve")
28
- end
29
-
30
- module Tasks
31
- autoload :EnsureThemekitInstalled, Project.project_filepath("tasks/ensure_themekit_installed")
8
+ class Command < ShopifyCli::ProjectCommands
9
+ subcommand :Serve, "serve", Project.project_filepath("commands/serve")
10
+ subcommand :Pull, "pull", Project.project_filepath("commands/pull")
11
+ subcommand :Push, "push", Project.project_filepath("commands/push")
12
+ subcommand :Delete, "delete", Project.project_filepath("commands/delete")
13
+ subcommand :Check, "check", Project.project_filepath("commands/check")
14
+ subcommand :Publish, "publish", Project.project_filepath("commands/publish")
15
+ subcommand :Package, "package", Project.project_filepath("commands/package")
16
+ subcommand :LanguageServer, "language-server", Project.project_filepath("commands/language_server")
32
17
  end
18
+ ShopifyCli::Commands.register("Theme::Command", "theme")
33
19
 
34
20
  module Forms
35
- autoload :Create, Project.project_filepath("forms/create")
36
- autoload :Connect, Project.project_filepath("forms/connect")
21
+ autoload :ConfirmStore, Project.project_filepath("forms/confirm_store")
22
+ autoload :Select, Project.project_filepath("forms/select")
37
23
  end
38
24
 
39
- autoload :Themekit, Project.project_filepath("themekit")
25
+ module UI
26
+ autoload :SyncProgressBar, Project.project_filepath("ui/sync_progress_bar")
27
+ end
40
28
  end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+ require "theme_check"
3
+
4
+ module Theme
5
+ class Command
6
+ class Check < ShopifyCli::SubCommand
7
+ class Options < ShopifyCli::Options
8
+ def initialize(theme_check)
9
+ super()
10
+ @theme_check = theme_check
11
+ end
12
+
13
+ def parse(_options_block, args)
14
+ @theme_check.parse(args)
15
+ end
16
+ end
17
+
18
+ def initialize(*)
19
+ super
20
+ @theme_check = ThemeCheck::Cli.new
21
+ self.options = Options.new(@theme_check)
22
+ end
23
+
24
+ def call(*)
25
+ @theme_check.run
26
+ end
27
+
28
+ def self.help
29
+ ShopifyCli::Context.message("theme.check.help", ShopifyCli::TOOL_NAME)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+ require "shopify-cli/theme/theme"
3
+ require "shopify-cli/theme/development_theme"
4
+
5
+ module Theme
6
+ class Command
7
+ class Delete < ShopifyCli::SubCommand
8
+ options do |parser, flags|
9
+ parser.on("-d", "--development") { flags[:development] = true }
10
+ parser.on("-a", "--show-all") { flags[:show_all] = true }
11
+ parser.on("-f", "--force") { flags[:force] = true }
12
+ end
13
+
14
+ def call(args, _name)
15
+ themes = if options.flags[:development]
16
+ [ShopifyCli::Theme::DevelopmentTheme.new(@ctx)]
17
+ elsif args.any?
18
+ args.map { |id| ShopifyCli::Theme::Theme.new(@ctx, id: id) }
19
+ else
20
+ form = Forms::Select.ask(
21
+ @ctx,
22
+ [],
23
+ title: @ctx.message("theme.delete.select"),
24
+ exclude_roles: ["live"],
25
+ include_foreign_developments: options.flags[:show_all],
26
+ )
27
+ return unless form
28
+ [form.theme]
29
+ end
30
+
31
+ deleted = 0
32
+ themes.each do |theme|
33
+ if theme.live?
34
+ @ctx.puts(@ctx.message("theme.delete.live", theme.id))
35
+ next
36
+ elsif !confirm?(theme)
37
+ next
38
+ end
39
+ theme.delete
40
+ deleted += 1
41
+ rescue ShopifyCli::API::APIRequestNotFoundError
42
+ @ctx.puts(@ctx.message("theme.delete.not_found", theme.id))
43
+ end
44
+
45
+ @ctx.done(@ctx.message("theme.delete.done", deleted))
46
+ end
47
+
48
+ def self.help
49
+ ShopifyCli::Context.message("theme.delete.help", ShopifyCli::TOOL_NAME, ShopifyCli::TOOL_NAME)
50
+ end
51
+
52
+ private
53
+
54
+ def confirm?(theme)
55
+ Forms::ConfirmStore.ask(
56
+ @ctx,
57
+ [],
58
+ title: @ctx.message("theme.delete.confirm", theme.name, theme.shop),
59
+ force: options.flags[:force],
60
+ ).confirmed?
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+ require "theme_check"
3
+
4
+ module Theme
5
+ class Command
6
+ class LanguageServer < ShopifyCli::SubCommand
7
+ def call(*)
8
+ ThemeCheck::LanguageServer.start
9
+ end
10
+
11
+ def self.help
12
+ ShopifyCli::Context.message("theme.language_server.help", ShopifyCli::TOOL_NAME)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+ require "pathname"
3
+ require "json"
4
+
5
+ module Theme
6
+ class Command
7
+ class Package < ShopifyCli::SubCommand
8
+ THEME_DIRECTORIES = %w[
9
+ assets
10
+ config
11
+ layout
12
+ locales
13
+ sections
14
+ snippets
15
+ templates
16
+ ]
17
+
18
+ def call(args, _name)
19
+ path = args.first || "."
20
+
21
+ check_prereq_command("zip")
22
+ zip_name = theme_name(path) + ".zip"
23
+ zip(zip_name, path, THEME_DIRECTORIES)
24
+ @ctx.done(@ctx.message("theme.package.done", zip_name))
25
+ end
26
+
27
+ def self.help
28
+ ShopifyCli::Context.message("theme.package.help", ShopifyCli::TOOL_NAME, ShopifyCli::TOOL_NAME)
29
+ end
30
+
31
+ private
32
+
33
+ def check_prereq_command(command)
34
+ cmd_path = @ctx.which(command)
35
+ @ctx.abort(@ctx.message("theme.package.error.prereq_command_required", command)) if cmd_path.nil?
36
+ end
37
+
38
+ def zip(zip_name, path, files)
39
+ @ctx.system("zip", "-r", zip_name, *files, chdir: path)
40
+ end
41
+
42
+ def theme_name(path)
43
+ settings_schema = Pathname.new(path).join("config/settings_schema.json")
44
+ @ctx.abort(@ctx.message("theme.package.error.missing_config")) unless settings_schema.file?
45
+
46
+ content = settings_schema.read
47
+ theme_info = JSON.parse(content).find { |section| section["name"] == "theme_info" }
48
+ theme_name = theme_info&.dig("theme_name")
49
+ @ctx.abort(@ctx.message("theme.package.error.missing_theme_name")) unless theme_name
50
+
51
+ [theme_name, theme_info["theme_version"]].compact.join("-")
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+ require "shopify-cli/theme/theme"
3
+
4
+ module Theme
5
+ class Command
6
+ class Publish < ShopifyCli::SubCommand
7
+ options do |parser, flags|
8
+ parser.on("-f", "--force") { flags[:force] = true }
9
+ end
10
+
11
+ def call(args, *)
12
+ theme = if (theme_id = args.first)
13
+ ShopifyCli::Theme::Theme.new(@ctx, id: theme_id)
14
+ else
15
+ form = Forms::Select.ask(
16
+ @ctx,
17
+ [],
18
+ title: @ctx.message("theme.publish.select"),
19
+ exclude_roles: ["live", "development", "demo"],
20
+ )
21
+ return unless form
22
+ form.theme
23
+ end
24
+
25
+ return unless Forms::ConfirmStore.ask(
26
+ @ctx,
27
+ [],
28
+ title: @ctx.message("theme.publish.confirm", theme.name, theme.shop),
29
+ force: options.flags[:force],
30
+ ).confirmed?
31
+
32
+ theme.publish
33
+ @ctx.done(@ctx.message("theme.publish.done", theme.preview_url))
34
+ rescue ShopifyCli::API::APIRequestNotFoundError
35
+ @ctx.puts(@ctx.message("theme.publish.not_found", theme.id))
36
+ end
37
+
38
+ def self.help
39
+ ShopifyCli::Context.message("theme.publish.help", ShopifyCli::TOOL_NAME, ShopifyCli::TOOL_NAME)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+ require "shopify-cli/theme/theme"
3
+ require "shopify-cli/theme/ignore_filter"
4
+ require "shopify-cli/theme/syncer"
5
+
6
+ module Theme
7
+ class Command
8
+ class Pull < ShopifyCli::SubCommand
9
+ options do |parser, flags|
10
+ parser.on("-n", "--nodelete") { flags[:nodelete] = true }
11
+ parser.on("-i", "--themeid=ID") { |theme_id| flags[:theme_id] = theme_id }
12
+ end
13
+
14
+ def call(args, _name)
15
+ root = args.first || "."
16
+ delete = !options.flags[:nodelete]
17
+
18
+ theme = if (theme_id = options.flags[:theme_id])
19
+ ShopifyCli::Theme::Theme.new(@ctx, root: root, id: theme_id)
20
+ else
21
+ form = Forms::Select.ask(
22
+ @ctx,
23
+ [],
24
+ title: @ctx.message("theme.pull.select"),
25
+ root: root,
26
+ )
27
+ return unless form
28
+ form.theme
29
+ end
30
+
31
+ ignore_filter = ShopifyCli::Theme::IgnoreFilter.from_path(root)
32
+ syncer = ShopifyCli::Theme::Syncer.new(@ctx, theme: theme, ignore_filter: ignore_filter)
33
+ begin
34
+ syncer.start_threads
35
+ CLI::UI::Frame.open(@ctx.message("theme.pull.pulling", theme.name, theme.id, theme.shop)) do
36
+ UI::SyncProgressBar.new(syncer).progress(:download_theme!, delete: delete)
37
+ end
38
+ @ctx.done(@ctx.message("theme.pull.done"))
39
+ rescue ShopifyCli::API::APIRequestNotFoundError
40
+ @ctx.abort(@ctx.message("theme.pull.theme_not_found", theme.id))
41
+ ensure
42
+ syncer.shutdown
43
+ end
44
+ end
45
+
46
+ def self.help
47
+ ShopifyCli::Context.message("theme.pull.help", ShopifyCli::TOOL_NAME, ShopifyCli::TOOL_NAME)
48
+ end
49
+ end
50
+ end
51
+ end