shopify-cli 1.11.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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