shopify-cli 2.3.0 → 2.6.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 (266) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +1 -0
  3. data/.github/workflows/shopify.yml +104 -0
  4. data/.gitignore +3 -0
  5. data/.rubocop.yml +14 -14
  6. data/.rubocop_todo.yml +3 -3
  7. data/CHANGELOG.md +26 -0
  8. data/CONTRIBUTING.md +23 -0
  9. data/Dockerfile +17 -0
  10. data/Gemfile +1 -0
  11. data/Gemfile.lock +67 -24
  12. data/README.md +1 -1
  13. data/RELEASING.md +1 -1
  14. data/Rakefile +75 -18
  15. data/bin/console +11 -0
  16. data/bin/shopify +17 -4
  17. data/dev.yml +14 -1
  18. data/ext/shopify-cli/extconf.rb +2 -0
  19. data/ext/shopify-extensions/extconf.rb +21 -0
  20. data/ext/shopify-extensions/shopify_extensions.rb +152 -0
  21. data/ext/shopify-extensions/version +1 -0
  22. data/lib/project_types/extension/cli.rb +19 -3
  23. data/lib/project_types/extension/commands/build.rb +32 -3
  24. data/lib/project_types/extension/commands/check.rb +2 -2
  25. data/lib/project_types/extension/commands/connect.rb +1 -1
  26. data/lib/project_types/extension/commands/create.rb +59 -16
  27. data/lib/project_types/extension/commands/extension_command.rb +1 -1
  28. data/lib/project_types/extension/commands/info.rb +1 -1
  29. data/lib/project_types/extension/commands/push.rb +1 -1
  30. data/lib/project_types/extension/commands/register.rb +2 -2
  31. data/lib/project_types/extension/commands/serve.rb +5 -5
  32. data/lib/project_types/extension/commands/tunnel.rb +6 -6
  33. data/lib/project_types/extension/extension_project.rb +4 -4
  34. data/lib/project_types/extension/features/argo.rb +3 -3
  35. data/lib/project_types/extension/features/argo_config.rb +5 -5
  36. data/lib/project_types/extension/features/argo_serve.rb +21 -6
  37. data/lib/project_types/extension/features/argo_setup.rb +1 -1
  38. data/lib/project_types/extension/features/argo_setup_step.rb +1 -1
  39. data/lib/project_types/extension/features/argo_setup_steps.rb +2 -2
  40. data/lib/project_types/extension/forms/connect.rb +2 -2
  41. data/lib/project_types/extension/forms/create.rb +6 -3
  42. data/lib/project_types/extension/forms/questions/ask_app.rb +2 -2
  43. data/lib/project_types/extension/forms/questions/ask_name.rb +1 -1
  44. data/lib/project_types/extension/forms/questions/ask_registration.rb +2 -2
  45. data/lib/project_types/extension/forms/questions/ask_template.rb +44 -0
  46. data/lib/project_types/extension/forms/questions/ask_type.rb +2 -2
  47. data/lib/project_types/extension/messages/message_loading.rb +2 -2
  48. data/lib/project_types/extension/messages/messages.rb +3 -0
  49. data/lib/project_types/extension/models/development_server.rb +78 -0
  50. data/lib/project_types/extension/models/development_server_requirements.rb +35 -0
  51. data/lib/project_types/extension/models/lazy_specification_handler.rb +1 -1
  52. data/lib/project_types/extension/models/server_config/base.rb +31 -0
  53. data/lib/project_types/extension/models/server_config/development.rb +23 -0
  54. data/lib/project_types/extension/models/server_config/development_entries.rb +38 -0
  55. data/lib/project_types/extension/models/server_config/development_renderer.rb +30 -0
  56. data/lib/project_types/extension/models/server_config/extension.rb +35 -0
  57. data/lib/project_types/extension/models/server_config/root.rb +18 -0
  58. data/lib/project_types/extension/models/server_config/user.rb +10 -0
  59. data/lib/project_types/extension/models/specification.rb +1 -1
  60. data/lib/project_types/extension/models/specification_handlers/default.rb +14 -2
  61. data/lib/project_types/extension/models/specification_handlers/theme_app_extension.rb +1 -1
  62. data/lib/project_types/extension/models/specifications.rb +4 -4
  63. data/lib/project_types/extension/tasks/choose_next_available_port.rb +2 -2
  64. data/lib/project_types/extension/tasks/configure_features.rb +1 -1
  65. data/lib/project_types/extension/tasks/configure_options.rb +1 -1
  66. data/lib/project_types/extension/tasks/converters/product_converter.rb +1 -1
  67. data/lib/project_types/extension/tasks/converters/server_config_converter.rb +31 -0
  68. data/lib/project_types/extension/tasks/create_extension.rb +2 -2
  69. data/lib/project_types/extension/tasks/fetch_specifications.rb +2 -2
  70. data/lib/project_types/extension/tasks/find_npm_packages.rb +5 -5
  71. data/lib/project_types/extension/tasks/get_app.rb +2 -2
  72. data/lib/project_types/extension/tasks/get_apps.rb +2 -2
  73. data/lib/project_types/extension/tasks/get_extensions.rb +2 -2
  74. data/lib/project_types/extension/tasks/get_product.rb +2 -2
  75. data/lib/project_types/extension/tasks/load_server_config.rb +23 -0
  76. data/lib/project_types/extension/tasks/run_extension_command.rb +81 -0
  77. data/lib/project_types/extension/tasks/update_draft.rb +2 -2
  78. data/lib/project_types/node/cli.rb +3 -3
  79. data/lib/project_types/node/commands/connect.rb +4 -4
  80. data/lib/project_types/node/commands/create.rb +10 -14
  81. data/lib/project_types/node/commands/deploy/heroku.rb +4 -4
  82. data/lib/project_types/node/commands/deploy.rb +3 -3
  83. data/lib/project_types/node/commands/generate.rb +2 -2
  84. data/lib/project_types/node/commands/open.rb +3 -3
  85. data/lib/project_types/node/commands/serve.rb +15 -7
  86. data/lib/project_types/node/commands/tunnel.rb +6 -6
  87. data/lib/project_types/node/forms/create.rb +3 -3
  88. data/lib/project_types/node/messages/messages.rb +3 -0
  89. data/lib/project_types/php/cli.rb +27 -0
  90. data/lib/project_types/php/commands/connect.rb +19 -0
  91. data/lib/project_types/php/commands/create.rb +143 -0
  92. data/lib/project_types/php/commands/deploy/heroku.rb +129 -0
  93. data/lib/project_types/php/commands/deploy.rb +32 -0
  94. data/lib/project_types/php/commands/open.rb +16 -0
  95. data/lib/project_types/php/commands/serve.rb +51 -0
  96. data/lib/project_types/php/commands/tunnel.rb +37 -0
  97. data/lib/project_types/php/forms/create.rb +45 -0
  98. data/lib/project_types/php/messages/messages.rb +191 -0
  99. data/lib/project_types/rails/cli.rb +3 -3
  100. data/lib/project_types/rails/commands/connect.rb +4 -4
  101. data/lib/project_types/rails/commands/create.rb +12 -16
  102. data/lib/project_types/rails/commands/deploy/heroku.rb +4 -4
  103. data/lib/project_types/rails/commands/deploy.rb +3 -3
  104. data/lib/project_types/rails/commands/generate/webhook.rb +3 -3
  105. data/lib/project_types/rails/commands/generate.rb +3 -3
  106. data/lib/project_types/rails/commands/open.rb +3 -3
  107. data/lib/project_types/rails/commands/serve.rb +8 -8
  108. data/lib/project_types/rails/commands/tunnel.rb +6 -6
  109. data/lib/project_types/rails/forms/create.rb +3 -3
  110. data/lib/project_types/rails/gem.rb +1 -1
  111. data/lib/project_types/rails/ruby.rb +1 -1
  112. data/lib/project_types/script/cli.rb +16 -6
  113. data/lib/project_types/script/commands/create.rb +4 -2
  114. data/lib/project_types/script/commands/push.rb +2 -2
  115. data/lib/project_types/script/config/extension_points.yml +30 -29
  116. data/lib/project_types/script/forms/create.rb +1 -1
  117. data/lib/project_types/script/layers/application/create_script.rb +32 -12
  118. data/lib/project_types/script/layers/application/extension_points.rb +4 -4
  119. data/lib/project_types/script/layers/application/push_script.rb +13 -1
  120. data/lib/project_types/script/layers/domain/extension_point.rb +13 -45
  121. data/lib/project_types/script/layers/domain/push_package.rb +0 -12
  122. data/lib/project_types/script/layers/domain/script_project.rb +2 -2
  123. data/lib/project_types/script/layers/infrastructure/api_clients/partners_proxy_api_client.rb +57 -0
  124. data/lib/project_types/script/layers/infrastructure/api_clients/script_service_api_client.rb +35 -0
  125. data/lib/project_types/script/layers/infrastructure/command_runner.rb +1 -1
  126. data/lib/project_types/script/layers/infrastructure/errors.rb +5 -0
  127. data/lib/project_types/script/layers/infrastructure/languages/assemblyscript_project_creator.rb +10 -90
  128. data/lib/project_types/script/layers/infrastructure/languages/project_creator.rb +76 -11
  129. data/lib/project_types/script/layers/infrastructure/languages/task_runner.rb +1 -1
  130. data/lib/project_types/script/layers/infrastructure/languages/typescript_project_creator.rb +33 -0
  131. data/lib/project_types/script/layers/infrastructure/languages/typescript_task_runner.rb +105 -0
  132. data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +1 -1
  133. data/lib/project_types/script/layers/infrastructure/script_project_repository.rb +6 -6
  134. data/lib/project_types/script/layers/infrastructure/script_service.rb +25 -144
  135. data/lib/project_types/script/layers/infrastructure/script_uploader.rb +27 -0
  136. data/lib/project_types/script/layers/infrastructure/service_locator.rb +20 -0
  137. data/lib/project_types/script/messages/messages.rb +4 -0
  138. data/lib/project_types/script/tasks/ensure_env.rb +7 -7
  139. data/lib/project_types/script/ui/error_handler.rb +84 -76
  140. data/lib/project_types/script/ui/printing_spinner.rb +1 -1
  141. data/lib/project_types/theme/cli.rb +3 -3
  142. data/lib/project_types/theme/commands/check.rb +3 -3
  143. data/lib/project_types/theme/commands/delete.rb +7 -7
  144. data/lib/project_types/theme/commands/init.rb +3 -3
  145. data/lib/project_types/theme/commands/language_server.rb +2 -2
  146. data/lib/project_types/theme/commands/package.rb +2 -2
  147. data/lib/project_types/theme/commands/publish.rb +5 -5
  148. data/lib/project_types/theme/commands/pull.rb +9 -9
  149. data/lib/project_types/theme/commands/push.rb +12 -12
  150. data/lib/project_types/theme/commands/serve.rb +4 -4
  151. data/lib/project_types/theme/forms/confirm_store.rb +1 -1
  152. data/lib/project_types/theme/forms/select.rb +2 -2
  153. data/lib/{shopify-cli → shopify_cli}/admin_api/populate_resource_command.rb +3 -3
  154. data/lib/{shopify-cli → shopify_cli}/admin_api/schema.rb +4 -4
  155. data/lib/{shopify-cli → shopify_cli}/admin_api.rb +27 -27
  156. data/lib/{shopify-cli → shopify_cli}/api.rb +12 -8
  157. data/lib/shopify_cli/command/app_sub_command.rb +16 -0
  158. data/lib/{shopify-cli → shopify_cli}/command.rb +3 -3
  159. data/lib/{shopify-cli → shopify_cli}/commands/config.rb +14 -14
  160. data/lib/{shopify-cli → shopify_cli}/commands/help.rb +4 -4
  161. data/lib/{shopify-cli → shopify_cli}/commands/login.rb +7 -7
  162. data/lib/shopify_cli/commands/logout.rb +39 -0
  163. data/lib/{shopify-cli → shopify_cli}/commands/populate/customer.rb +4 -4
  164. data/lib/{shopify-cli → shopify_cli}/commands/populate/draft_order.rb +4 -4
  165. data/lib/{shopify-cli → shopify_cli}/commands/populate/product.rb +4 -4
  166. data/lib/shopify_cli/commands/populate.rb +23 -0
  167. data/lib/shopify_cli/commands/store.rb +15 -0
  168. data/lib/{shopify-cli → shopify_cli}/commands/switch.rb +5 -5
  169. data/lib/{shopify-cli → shopify_cli}/commands/system.rb +10 -10
  170. data/lib/shopify_cli/commands/version.rb +15 -0
  171. data/lib/{shopify-cli → shopify_cli}/commands/whoami.rb +7 -7
  172. data/lib/shopify_cli/commands.rb +34 -0
  173. data/lib/{shopify-cli → shopify_cli}/connect.rb +3 -3
  174. data/lib/shopify_cli/constants.rb +54 -0
  175. data/lib/{shopify-cli → shopify_cli}/context.rb +6 -6
  176. data/lib/{shopify-cli → shopify_cli}/core/entry_point.rb +7 -7
  177. data/lib/{shopify-cli → shopify_cli}/core/executor.rb +8 -4
  178. data/lib/{shopify-cli → shopify_cli}/core/finalize.rb +1 -1
  179. data/lib/{shopify-cli → shopify_cli}/core/help_resolver.rb +2 -2
  180. data/lib/{shopify-cli → shopify_cli}/core/monorail.rb +8 -8
  181. data/lib/shopify_cli/core.rb +8 -0
  182. data/lib/{shopify-cli → shopify_cli}/db.rb +8 -8
  183. data/lib/shopify_cli/environment.rb +91 -0
  184. data/lib/shopify_cli/exception_reporter/permission_controller.rb +54 -0
  185. data/lib/shopify_cli/exception_reporter.rb +55 -0
  186. data/lib/{shopify-cli → shopify_cli}/feature.rb +8 -8
  187. data/lib/{shopify-cli → shopify_cli}/form.rb +2 -2
  188. data/lib/{shopify-cli → shopify_cli}/git.rb +38 -8
  189. data/lib/{shopify-cli → shopify_cli}/helpers/haikunator.rb +1 -1
  190. data/lib/shopify_cli/helpers.rb +5 -0
  191. data/lib/{shopify-cli → shopify_cli}/heroku.rb +38 -13
  192. data/lib/{shopify-cli → shopify_cli}/http_request.rb +1 -1
  193. data/lib/{shopify-cli → shopify_cli}/identity_auth/servlet.rb +1 -1
  194. data/lib/{shopify-cli → shopify_cli}/identity_auth.rb +24 -31
  195. data/lib/{shopify-cli → shopify_cli}/js_deps.rb +7 -7
  196. data/lib/{shopify-cli → shopify_cli}/js_system.rb +10 -10
  197. data/lib/{shopify-cli → shopify_cli}/lazy_delegator.rb +2 -2
  198. data/lib/{shopify-cli → shopify_cli}/messages/messages.rb +44 -2
  199. data/lib/{shopify-cli → shopify_cli}/method_object.rb +15 -8
  200. data/lib/shopify_cli/migrator/migration.rb +27 -0
  201. data/lib/shopify_cli/migrator/migrations/1631709766_noop.rb +13 -0
  202. data/lib/shopify_cli/migrator.rb +48 -0
  203. data/lib/{shopify-cli → shopify_cli}/options.rb +1 -1
  204. data/lib/{shopify-cli → shopify_cli}/packager.rb +8 -8
  205. data/lib/{shopify-cli → shopify_cli}/partners_api/organizations.rb +1 -1
  206. data/lib/{shopify-cli → shopify_cli}/partners_api.rb +16 -40
  207. data/lib/shopify_cli/php_deps.rb +102 -0
  208. data/lib/{shopify-cli → shopify_cli}/process_supervision.rb +10 -8
  209. data/lib/{shopify-cli → shopify_cli}/project.rb +15 -15
  210. data/lib/{shopify-cli → shopify_cli}/project_commands.rb +3 -3
  211. data/lib/{shopify-cli → shopify_cli}/project_type.rb +5 -5
  212. data/lib/{shopify-cli → shopify_cli}/resolve_constant.rb +5 -5
  213. data/lib/{shopify-cli → shopify_cli}/resources/env_file.rb +1 -1
  214. data/lib/shopify_cli/resources.rb +5 -0
  215. data/lib/{shopify-cli → shopify_cli}/result.rb +11 -11
  216. data/lib/{shopify-cli → shopify_cli}/shopifolk.rb +6 -6
  217. data/lib/{shopify-cli → shopify_cli}/sub_command.rb +1 -1
  218. data/lib/{shopify-cli → shopify_cli}/task.rb +1 -1
  219. data/lib/{shopify-cli → shopify_cli}/tasks/confirm_store.rb +3 -3
  220. data/lib/{shopify-cli → shopify_cli}/tasks/create_api_client.rb +4 -4
  221. data/lib/shopify_cli/tasks/ensure_authenticated.rb +13 -0
  222. data/lib/{shopify-cli → shopify_cli}/tasks/ensure_dev_store.rb +5 -5
  223. data/lib/{shopify-cli → shopify_cli}/tasks/ensure_env.rb +3 -3
  224. data/lib/{shopify-cli → shopify_cli}/tasks/ensure_loopback_url.rb +4 -4
  225. data/lib/{shopify-cli → shopify_cli}/tasks/ensure_project_type.rb +3 -3
  226. data/lib/{shopify-cli → shopify_cli}/tasks/select_org_and_shop.rb +8 -8
  227. data/lib/{shopify-cli → shopify_cli}/tasks/update_dashboard_urls.rb +6 -6
  228. data/lib/{shopify-cli → shopify_cli}/tasks.rb +10 -10
  229. data/lib/{shopify-cli → shopify_cli}/theme/dev_server/certificate_manager.rb +5 -5
  230. data/lib/{shopify-cli → shopify_cli}/theme/dev_server/header_hash.rb +1 -1
  231. data/lib/{shopify-cli → shopify_cli}/theme/dev_server/hot-reload.js +0 -0
  232. data/lib/{shopify-cli → shopify_cli}/theme/dev_server/hot_reload.rb +5 -6
  233. data/lib/{shopify-cli → shopify_cli}/theme/dev_server/local_assets.rb +1 -1
  234. data/lib/{shopify-cli → shopify_cli}/theme/dev_server/proxy.rb +2 -2
  235. data/lib/{shopify-cli → shopify_cli}/theme/dev_server/sse.rb +1 -1
  236. data/lib/{shopify-cli → shopify_cli}/theme/dev_server/watcher.rb +1 -1
  237. data/lib/{shopify-cli → shopify_cli}/theme/dev_server/web_server.rb +1 -1
  238. data/lib/{shopify-cli → shopify_cli}/theme/dev_server.rb +3 -3
  239. data/lib/shopify_cli/theme/development_theme.rb +83 -0
  240. data/lib/{shopify-cli → shopify_cli}/theme/file.rb +1 -1
  241. data/lib/{shopify-cli → shopify_cli}/theme/ignore_filter.rb +1 -1
  242. data/lib/{shopify-cli → shopify_cli}/theme/mime_type.rb +1 -1
  243. data/lib/{shopify-cli → shopify_cli}/theme/syncer.rb +6 -6
  244. data/lib/{shopify-cli → shopify_cli}/theme/theme.rb +4 -4
  245. data/lib/{shopify-cli → shopify_cli}/transform_data_structure.rb +4 -4
  246. data/lib/{shopify-cli → shopify_cli}/tunnel.rb +14 -14
  247. data/lib/shopify_cli/version.rb +3 -0
  248. data/lib/shopify_cli.rb +61 -50
  249. data/shopify-cli.gemspec +13 -5
  250. data/utilities/docker.rb +47 -0
  251. data/utilities/utilities.rb +5 -0
  252. metadata +155 -97
  253. data/.github/workflows/build.yml +0 -28
  254. data/lib/project_types/script/layers/infrastructure/languages/rust_project_creator.rb +0 -73
  255. data/lib/project_types/script/layers/infrastructure/languages/rust_task_runner.rb +0 -60
  256. data/lib/shopify-cli/commands/logout.rb +0 -39
  257. data/lib/shopify-cli/commands/populate.rb +0 -23
  258. data/lib/shopify-cli/commands/store.rb +0 -15
  259. data/lib/shopify-cli/commands/version.rb +0 -15
  260. data/lib/shopify-cli/commands.rb +0 -34
  261. data/lib/shopify-cli/core.rb +0 -8
  262. data/lib/shopify-cli/helpers.rb +0 -5
  263. data/lib/shopify-cli/resources.rb +0 -5
  264. data/lib/shopify-cli/tasks/ensure_authenticated.rb +0 -13
  265. data/lib/shopify-cli/theme/development_theme.rb +0 -69
  266. data/lib/shopify-cli/version.rb +0 -3
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  module Node
3
3
  class Command
4
- class Serve < ShopifyCli::SubCommand
4
+ class Serve < ShopifyCLI::SubCommand
5
5
  prerequisite_task ensure_project_type: :node
6
6
  prerequisite_task :ensure_env, :ensure_dev_store
7
7
 
@@ -9,14 +9,15 @@ module Node
9
9
  parser.on("--host=HOST") do |h|
10
10
  flags[:host] = h.gsub('"', "")
11
11
  end
12
+ parser.on("--port=PORT") { |port| flags[:port] = port }
12
13
  end
13
14
 
14
15
  def call(*)
15
- project = ShopifyCli::Project.current
16
- url = options.flags[:host] || ShopifyCli::Tunnel.start(@ctx)
16
+ project = ShopifyCLI::Project.current
17
+ url = options.flags[:host] || ShopifyCLI::Tunnel.start(@ctx)
17
18
  @ctx.abort(@ctx.message("node.serve.error.host_must_be_https")) if url.match(/^https/i).nil?
18
19
  project.env.update(@ctx, :host, url)
19
- ShopifyCli::Tasks::UpdateDashboardURLS.call(
20
+ ShopifyCLI::Tasks::UpdateDashboardURLS.call(
20
21
  @ctx,
21
22
  url: url,
22
23
  callback_url: "/auth/callback",
@@ -29,17 +30,24 @@ module Node
29
30
 
30
31
  CLI::UI::Frame.open(@ctx.message("node.serve.running_server")) do
31
32
  env = project.env.to_h
32
- env["PORT"] = ShopifyCli::Tunnel::PORT.to_s
33
+ env["PORT"] = port.to_s
33
34
  @ctx.system("npm run dev", env: env)
34
35
  end
35
36
  end
36
37
 
38
+ def port
39
+ return ShopifyCLI::Tunnel::PORT.to_s unless options.flags.key?(:port)
40
+ port = options.flags[:port].to_i
41
+ @ctx.abort(@ctx.message("node.serve.error.invalid_port", options.flags[:port])) unless port > 0
42
+ port
43
+ end
44
+
37
45
  def self.help
38
- ShopifyCli::Context.message("node.serve.help", ShopifyCli::TOOL_NAME)
46
+ ShopifyCLI::Context.message("node.serve.help", ShopifyCLI::TOOL_NAME)
39
47
  end
40
48
 
41
49
  def self.extended_help
42
- ShopifyCli::Context.message("node.serve.extended_help")
50
+ ShopifyCLI::Context.message("node.serve.extended_help")
43
51
  end
44
52
  end
45
53
  end
@@ -4,7 +4,7 @@ require "shopify_cli"
4
4
 
5
5
  module Node
6
6
  class Command
7
- class Tunnel < ShopifyCli::SubCommand
7
+ class Tunnel < ShopifyCLI::SubCommand
8
8
  # subcommands :auth, :start, :stop
9
9
 
10
10
  prerequisite_task ensure_project_type: :node
@@ -18,23 +18,23 @@ module Node
18
18
  @ctx.puts(@ctx.message("node.tunnel.error.token_argument_missing"))
19
19
  @ctx.puts("#{self.class.help}\n#{self.class.extended_help}")
20
20
  else
21
- ShopifyCli::Tunnel.auth(@ctx, token)
21
+ ShopifyCLI::Tunnel.auth(@ctx, token)
22
22
  end
23
23
  when "start"
24
- ShopifyCli::Tunnel.start(@ctx)
24
+ ShopifyCLI::Tunnel.start(@ctx)
25
25
  when "stop"
26
- ShopifyCli::Tunnel.stop(@ctx)
26
+ ShopifyCLI::Tunnel.stop(@ctx)
27
27
  else
28
28
  @ctx.puts(self.class.help)
29
29
  end
30
30
  end
31
31
 
32
32
  def self.help
33
- ShopifyCli::Context.message("node.tunnel.help", ShopifyCli::TOOL_NAME)
33
+ ShopifyCLI::Context.message("node.tunnel.help", ShopifyCLI::TOOL_NAME)
34
34
  end
35
35
 
36
36
  def self.extended_help
37
- ShopifyCli::Context.message("node.tunnel.extended_help", ShopifyCli::TOOL_NAME)
37
+ ShopifyCLI::Context.message("node.tunnel.extended_help", ShopifyCLI::TOOL_NAME)
38
38
  end
39
39
  end
40
40
  end
@@ -2,7 +2,7 @@ require "uri"
2
2
 
3
3
  module Node
4
4
  module Forms
5
- class Create < ShopifyCli::Form
5
+ class Create < ShopifyCLI::Form
6
6
  attr_accessor :name
7
7
  flag_arguments :title, :organization_id, :shop_domain, :type
8
8
 
@@ -10,7 +10,7 @@ module Node
10
10
  self.title ||= CLI::UI::Prompt.ask(ctx.message("node.forms.create.app_name"))
11
11
  self.name = format_name
12
12
  self.type = ask_type
13
- res = ShopifyCli::Tasks::SelectOrgAndShop.call(ctx, organization_id: organization_id, shop_domain: shop_domain)
13
+ res = ShopifyCLI::Tasks::SelectOrgAndShop.call(ctx, organization_id: organization_id, shop_domain: shop_domain)
14
14
  self.organization_id = res[:organization_id]
15
15
  self.shop_domain = res[:shop_domain]
16
16
  end
@@ -34,7 +34,7 @@ module Node
34
34
  end
35
35
  end
36
36
 
37
- unless ShopifyCli::Tasks::CreateApiClient::VALID_APP_TYPES.include?(type)
37
+ unless ShopifyCLI::Tasks::CreateApiClient::VALID_APP_TYPES.include?(type)
38
38
  ctx.abort(ctx.message("node.forms.create.error.invalid_app_type", type))
39
39
  end
40
40
  ctx.puts(ctx.message("node.forms.create.app_type.selected", type))
@@ -119,10 +119,12 @@ module Node
119
119
  extended_help: <<~HELP,
120
120
  {{bold:Options:}}
121
121
  {{cyan:--host=HOST}}: Bypass running tunnel and use custom host. HOST must be HTTPS url.
122
+ {{cyan:--port=PORT}}: Use custom port.
122
123
  HELP
123
124
 
124
125
  error: {
125
126
  host_must_be_https: "HOST must be a HTTPS url.",
127
+ invalid_port: "%s is not a valid port.",
126
128
  },
127
129
 
128
130
  open_info: <<~MESSAGE,
@@ -154,6 +156,7 @@ module Node
154
156
  error: {
155
157
  token_argument_missing: "{{x}} {{red:auth requires a token argument}}\n\n",
156
158
  },
159
+
157
160
  },
158
161
 
159
162
  forms: {
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+ module PHP
3
+ class Project < ShopifyCLI::ProjectType
4
+ require Project.project_filepath("messages/messages")
5
+ register_messages(PHP::Messages::MESSAGES)
6
+ end
7
+
8
+ # define/autoload project specific Commands
9
+ class Command < ShopifyCLI::ProjectCommands
10
+ subcommand :Connect, "connect", Project.project_filepath("commands/connect")
11
+ subcommand :Create, "create", Project.project_filepath("commands/create")
12
+ subcommand :Deploy, "deploy", Project.project_filepath("commands/deploy")
13
+ subcommand :Open, "open", Project.project_filepath("commands/open")
14
+ subcommand :Serve, "serve", Project.project_filepath("commands/serve")
15
+ subcommand :Tunnel, "tunnel", Project.project_filepath("commands/tunnel")
16
+ end
17
+ ShopifyCLI::Commands.register("PHP::Command", "php")
18
+
19
+ # define/autoload project specific Tasks
20
+ module Tasks
21
+ end
22
+
23
+ # define/autoload project specific Forms
24
+ module Forms
25
+ autoload :Create, Project.project_filepath("forms/create")
26
+ end
27
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+ module PHP
3
+ class Command
4
+ class Connect < ShopifyCLI::SubCommand
5
+ def call(*)
6
+ if ShopifyCLI::Project.has_current? && ShopifyCLI::Project.current.env
7
+ @ctx.puts(@ctx.message("php.connect.production_warning"))
8
+ end
9
+
10
+ app = ShopifyCLI::Connect.new(@ctx).default_connect("php")
11
+ @ctx.done(@ctx.message("php.connect.connected", app))
12
+ end
13
+
14
+ def self.help
15
+ ShopifyCLI::Context.message("php.connect.help", ShopifyCLI::TOOL_NAME, ShopifyCLI::TOOL_NAME)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+ require "semantic/semantic"
3
+
4
+ module PHP
5
+ class Command
6
+ class Create < ShopifyCLI::SubCommand
7
+ options do |parser, flags|
8
+ parser.on("--name=NAME") { |name| flags[:title] = name }
9
+ parser.on("--organization-id=ID") { |organization_id| flags[:organization_id] = organization_id }
10
+ parser.on("--store=MYSHOPIFYDOMAIN") { |url| flags[:shop_domain] = url }
11
+ parser.on("--type=APPTYPE") { |type| flags[:type] = type }
12
+ parser.on("--verbose") { flags[:verbose] = true }
13
+ end
14
+
15
+ def call(args, _name)
16
+ form = Forms::Create.ask(@ctx, args, options.flags)
17
+ return @ctx.puts(self.class.help) if form.nil?
18
+
19
+ check_php
20
+ check_composer
21
+ check_npm
22
+ app_id = build(form)
23
+
24
+ ShopifyCLI::Project.write(
25
+ @ctx,
26
+ project_type: "php",
27
+ organization_id: form.organization_id,
28
+ )
29
+
30
+ partners_url = ShopifyCLI::PartnersAPI.partners_url_for(form.organization_id, app_id)
31
+
32
+ @ctx.puts(@ctx.message("apps.create.info.created", form.title, partners_url))
33
+ @ctx.puts(@ctx.message("apps.create.info.serve", form.name, ShopifyCLI::TOOL_NAME, "php"))
34
+ unless ShopifyCLI::Shopifolk.acting_as_shopify_organization?
35
+ @ctx.puts(@ctx.message("apps.create.info.install", partners_url, form.title))
36
+ end
37
+ end
38
+
39
+ def self.help
40
+ ShopifyCLI::Context.message("php.create.help", ShopifyCLI::TOOL_NAME, ShopifyCLI::TOOL_NAME)
41
+ end
42
+
43
+ private
44
+
45
+ def check_php
46
+ cmd_path = @ctx.which("php")
47
+ @ctx.abort(@ctx.message("php.create.error.php_required")) if cmd_path.nil?
48
+
49
+ version, stat = @ctx.capture2e("php", "-r", "echo phpversion();")
50
+ @ctx.abort(@ctx.message("php.create.error.php_version_failure")) unless stat.success?
51
+
52
+ if ::Semantic::Version.new(version) < ::Semantic::Version.new("7.3.0")
53
+ @ctx.abort(@ctx.message("php.create.error.php_version_too_low", "7.3"))
54
+ end
55
+
56
+ @ctx.done(@ctx.message("php.create.php_version", version))
57
+ end
58
+
59
+ def check_composer
60
+ cmd_path = @ctx.which("composer")
61
+ @ctx.abort(@ctx.message("php.create.error.composer_required")) if cmd_path.nil?
62
+ end
63
+
64
+ def check_npm
65
+ cmd_path = @ctx.which("npm")
66
+ @ctx.abort(@ctx.message("php.create.error.npm_required")) if cmd_path.nil?
67
+
68
+ version, stat = @ctx.capture2e("npm", "-v")
69
+ @ctx.abort(@ctx.message("php.create.error.npm_version_failure")) unless stat.success?
70
+
71
+ @ctx.done(@ctx.message("php.create.npm_version", version))
72
+ end
73
+
74
+ def build(form)
75
+ ShopifyCLI::Git.clone("https://github.com/Shopify/shopify-app-php.git", form.name)
76
+
77
+ @ctx.root = File.join(@ctx.root, form.name)
78
+ @ctx.chdir(@ctx.root)
79
+
80
+ api_client = ShopifyCLI::Tasks::CreateApiClient.call(
81
+ @ctx,
82
+ org_id: form.organization_id,
83
+ title: form.title,
84
+ type: form.type,
85
+ )
86
+
87
+ # Override the example settings with our own
88
+ @ctx.cp(".env.example", ".env")
89
+
90
+ env_file = ShopifyCLI::Resources::EnvFile.read
91
+ env_file.api_key = api_client["apiKey"]
92
+ env_file.secret = api_client["apiSecretKeys"].first["secret"]
93
+ env_file.shop = form.shop_domain
94
+ env_file.host = "localhost"
95
+ env_file.scopes = "write_products,write_draft_orders,write_customers"
96
+ env_file.extra["DB_DATABASE"] = File.join(@ctx.root, env_file.extra["DB_DATABASE"])
97
+ env_file.write(@ctx)
98
+
99
+ ShopifyCLI::PHPDeps.install(@ctx, !options.flags[:verbose].nil?)
100
+
101
+ set_npm_config
102
+ ShopifyCLI::JsDeps.install(@ctx, !options.flags[:verbose].nil?)
103
+
104
+ title = @ctx.message("php.create.app_setting_up")
105
+ success = @ctx.message("php.create.app_set_up")
106
+ failure = @ctx.message("php.create.error.app_setup")
107
+ CLI::UI::Frame.open(title, success_text: success, failure_text: failure) do
108
+ FileUtils.touch(env_file.extra["DB_DATABASE"])
109
+ @ctx.system("php", "artisan", "key:generate")
110
+ @ctx.system("php", "artisan", "migrate")
111
+ end
112
+
113
+ begin
114
+ @ctx.rm_r(".git")
115
+ @ctx.rm_r(".github")
116
+ rescue Errno::ENOENT => e
117
+ @ctx.debug(e)
118
+ end
119
+
120
+ api_client["id"]
121
+ end
122
+
123
+ def set_npm_config
124
+ # check available npmrc (either user or system) for production registry
125
+ registry, _ = @ctx.capture2("npm config get @shopify:registry")
126
+ return if registry.include?("https://registry.yarnpkg.com")
127
+
128
+ # available npmrc doesn't have production registry =>
129
+ # set a project-based .npmrc
130
+ @ctx.system(
131
+ "npm",
132
+ "--userconfig",
133
+ "./.npmrc",
134
+ "config",
135
+ "set",
136
+ "@shopify:registry",
137
+ "https://registry.yarnpkg.com",
138
+ chdir: @ctx.root
139
+ )
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+ require "shopify_cli"
3
+
4
+ module PHP
5
+ class Command
6
+ class Deploy
7
+ class Heroku
8
+ def self.help
9
+ ShopifyCLI::Context.message("php.deploy.heroku.help", ShopifyCLI::TOOL_NAME)
10
+ end
11
+
12
+ def self.start(ctx)
13
+ spin_group = CLI::UI::SpinGroup.new
14
+ heroku_service = ShopifyCLI::Heroku.new(ctx)
15
+
16
+ spin_group.add(ctx.message("php.deploy.heroku.downloading")) do |spinner|
17
+ heroku_service.download
18
+ spinner.update_title(ctx.message("php.deploy.heroku.downloaded"))
19
+ end
20
+ spin_group.wait
21
+
22
+ install_message = ctx.message(
23
+ ctx.windows? ? "php.deploy.heroku.installing_windows" : "php.deploy.heroku.installing"
24
+ )
25
+ spin_group.add(install_message) do |spinner|
26
+ heroku_service.install
27
+ spinner.update_title(ctx.message("php.deploy.heroku.installed"))
28
+ end
29
+ spin_group.wait
30
+
31
+ spin_group.add(ctx.message("php.deploy.heroku.git.checking")) do |spinner|
32
+ ShopifyCLI::Git.init(ctx)
33
+ spinner.update_title(ctx.message("php.deploy.heroku.git.initialized"))
34
+ end
35
+ spin_group.wait
36
+
37
+ if (account = heroku_service.whoami)
38
+ ctx.puts(ctx.message("php.deploy.heroku.authenticated_with_account", account))
39
+ else
40
+ CLI::UI::Frame.open(
41
+ ctx.message("php.deploy.heroku.authenticating"),
42
+ success_text: ctx.message("php.deploy.heroku.authenticated")
43
+ ) do
44
+ heroku_service.authenticate
45
+ end
46
+ end
47
+
48
+ if (app_name = heroku_service.app)
49
+ ctx.puts(ctx.message("php.deploy.heroku.app.selected", app_name))
50
+ else
51
+ app_type = CLI::UI::Prompt.ask(ctx.message("php.deploy.heroku.app.no_apps_found")) do |handler|
52
+ handler.option(ctx.message("php.deploy.heroku.app.create")) { :new }
53
+ handler.option(ctx.message("php.deploy.heroku.app.select")) { :existing }
54
+ end
55
+
56
+ if app_type == :existing
57
+ app_name = CLI::UI::Prompt.ask(ctx.message("php.deploy.heroku.app.name"))
58
+ CLI::UI::Frame.open(
59
+ ctx.message("php.deploy.heroku.app.selecting", app_name),
60
+ success_text: ctx.message("php.deploy.heroku.app.selected", app_name)
61
+ ) do
62
+ heroku_service.select_existing_app(app_name)
63
+ end
64
+ elsif app_type == :new
65
+ CLI::UI::Frame.open(
66
+ ctx.message("php.deploy.heroku.app.creating"),
67
+ success_text: ctx.message("php.deploy.heroku.app.created")
68
+ ) do
69
+ heroku_service.create_new_app
70
+ app_name = heroku_service.app
71
+ end
72
+ end
73
+ end
74
+
75
+ branches = ShopifyCLI::Git.branches(ctx)
76
+ if branches.length == 1
77
+ branch_to_deploy = branches[0]
78
+ ctx.puts(ctx.message("php.deploy.heroku.git.branch_selected", branch_to_deploy))
79
+ else
80
+ branch_to_deploy = CLI::UI::Prompt.ask(ctx.message("php.deploy.heroku.git.what_branch")) do |handler|
81
+ branches.each do |branch|
82
+ handler.option(branch) { branch }
83
+ end
84
+ end
85
+ end
86
+
87
+ app_url = "https://#{app_name}.herokuapp.com"
88
+
89
+ CLI::UI::Frame.open(
90
+ ctx.message("php.deploy.heroku.app.setting_configs"),
91
+ success_text: ctx.message("php.deploy.heroku.app.configs_set")
92
+ ) do
93
+ allowed_configs = [/SHOPIFY_API_KEY/, /SHOPIFY_API_SECRET/, /SCOPES/, /HOST/]
94
+
95
+ ShopifyCLI::Project.current.env.to_h.each do |config, value|
96
+ next unless allowed_configs.any? { |pattern| pattern.match?(config) }
97
+
98
+ value = app_url if config == "HOST"
99
+
100
+ current = heroku_service.get_config(config)
101
+ heroku_service.set_config(config, value) if current.nil? || current != value
102
+ end
103
+
104
+ current_key = heroku_service.get_config("APP_KEY")
105
+ if current_key.nil? || current_key.empty?
106
+ output, status = ctx.capture2e("php", "artisan", "key:generate", "--show")
107
+
108
+ ctx.abort(ctx.message("php.deploy.heroku.error.generate_app_key")) unless status.success?
109
+
110
+ heroku_service.set_config("APP_KEY", output.strip) if status.success?
111
+ end
112
+
113
+ heroku_service.add_buildpacks(["heroku/php", "heroku/nodejs"])
114
+ end
115
+
116
+ CLI::UI::Frame.open(
117
+ ctx.message("php.deploy.heroku.deploying"),
118
+ success_text: ctx.message("php.deploy.heroku.deployed")
119
+ ) do
120
+ heroku_service.deploy(branch_to_deploy)
121
+ end
122
+
123
+ heroku_command = heroku_service.heroku_command
124
+ ctx.puts(ctx.message("php.deploy.heroku.post_deploy", app_url, heroku_command))
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ require "shopify_cli"
3
+
4
+ module PHP
5
+ class Command
6
+ class Deploy < ShopifyCLI::SubCommand
7
+ prerequisite_task ensure_project_type: :php
8
+
9
+ autoload :Heroku, Project.project_filepath("commands/deploy/heroku")
10
+
11
+ HEROKU = "heroku"
12
+
13
+ def call(args, _name)
14
+ subcommand = args.shift
15
+ case subcommand
16
+ when HEROKU
17
+ PHP::Command::Deploy::Heroku.start(@ctx)
18
+ else
19
+ @ctx.puts(self.class.help)
20
+ end
21
+ end
22
+
23
+ def self.help
24
+ ShopifyCLI::Context.message("php.deploy.help", ShopifyCLI::TOOL_NAME)
25
+ end
26
+
27
+ def self.extended_help
28
+ ShopifyCLI::Context.message("php.deploy.extended_help", ShopifyCLI::TOOL_NAME)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PHP
4
+ class Command
5
+ class Open < ShopifyCLI::SubCommand
6
+ def call(*)
7
+ project = ShopifyCLI::Project.current
8
+ @ctx.open_url!("#{project.env.host}/login?shop=#{project.env.shop}")
9
+ end
10
+
11
+ def self.help
12
+ ShopifyCLI::Context.message("php.open.help", ShopifyCLI::TOOL_NAME)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+ module PHP
3
+ class Command
4
+ class Serve < ShopifyCLI::SubCommand
5
+ PORT = 3000
6
+
7
+ prerequisite_task :ensure_env, :ensure_dev_store
8
+
9
+ options do |parser, flags|
10
+ parser.on("--host=HOST") do |h|
11
+ flags[:host] = h.gsub('"', "")
12
+ end
13
+ end
14
+
15
+ def call(*)
16
+ project = ShopifyCLI::Project.current
17
+ url = options.flags[:host] || ShopifyCLI::Tunnel.start(@ctx, port: PORT)
18
+ @ctx.abort(@ctx.message("php.serve.error.host_must_be_https")) if url.match(/^https/i).nil?
19
+ project.env.update(@ctx, :host, url)
20
+ ShopifyCLI::Tasks::UpdateDashboardURLS.call(
21
+ @ctx,
22
+ url: url,
23
+ callback_url: "/auth/callback",
24
+ )
25
+
26
+ if project.env.shop
27
+ project_url = "#{project.env.host}/login?shop=#{project.env.shop}"
28
+ @ctx.puts("\n" + @ctx.message("php.serve.open_info", project_url) + "\n")
29
+ end
30
+
31
+ CLI::UI::Frame.open(@ctx.message("php.serve.running_server")) do
32
+ if ShopifyCLI::ProcessSupervision.running?(:npm_watch)
33
+ ShopifyCLI::ProcessSupervision.stop(:npm_watch)
34
+ end
35
+ ShopifyCLI::ProcessSupervision.start(:npm_watch, "npm run watch", force_spawn: true)
36
+
37
+ env = project.env.to_h
38
+ @ctx.system("php", "artisan", "serve", "--port", PORT.to_s, env: env)
39
+ end
40
+ end
41
+
42
+ def self.help
43
+ ShopifyCLI::Context.message("php.serve.help", ShopifyCLI::TOOL_NAME)
44
+ end
45
+
46
+ def self.extended_help
47
+ ShopifyCLI::Context.message("php.serve.extended_help")
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "shopify_cli"
4
+
5
+ module PHP
6
+ class Command
7
+ class Tunnel < ShopifyCLI::SubCommand
8
+ def call(args, _name)
9
+ subcommand = args.shift
10
+ case subcommand
11
+ when "auth"
12
+ token = args.shift
13
+ if token.nil?
14
+ @ctx.puts(@ctx.message("php.tunnel.error.token_argument_missing"))
15
+ @ctx.puts("#{self.class.help}\n#{self.class.extended_help}")
16
+ else
17
+ ShopifyCLI::Tunnel.auth(@ctx, token)
18
+ end
19
+ when "start"
20
+ ShopifyCLI::Tunnel.start(@ctx)
21
+ when "stop"
22
+ ShopifyCLI::Tunnel.stop(@ctx)
23
+ else
24
+ @ctx.puts(self.class.help)
25
+ end
26
+ end
27
+
28
+ def self.help
29
+ ShopifyCLI::Context.message("php.tunnel.help", ShopifyCLI::TOOL_NAME)
30
+ end
31
+
32
+ def self.extended_help
33
+ ShopifyCLI::Context.message("php.tunnel.extended_help", ShopifyCLI::TOOL_NAME)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,45 @@
1
+ require "uri"
2
+
3
+ module PHP
4
+ module Forms
5
+ class Create < ShopifyCLI::Form
6
+ attr_accessor :name
7
+ flag_arguments :title, :organization_id, :shop_domain, :type
8
+
9
+ def ask
10
+ self.title ||= CLI::UI::Prompt.ask(ctx.message("php.forms.create.app_name"))
11
+ self.name = format_name
12
+ self.type = ask_type
13
+ res = ShopifyCLI::Tasks::SelectOrgAndShop.call(ctx, organization_id: organization_id, shop_domain: shop_domain)
14
+ self.organization_id = res[:organization_id]
15
+ self.shop_domain = res[:shop_domain]
16
+ end
17
+
18
+ private
19
+
20
+ def format_name
21
+ name = title.downcase.split(" ").join("_")
22
+
23
+ if name.include?("shopify")
24
+ ctx.abort(ctx.message("php.forms.create.error.invalid_app_name"))
25
+ end
26
+ name
27
+ end
28
+
29
+ def ask_type
30
+ if type.nil?
31
+ return CLI::UI::Prompt.ask(ctx.message("php.forms.create.app_type.select")) do |handler|
32
+ handler.option(ctx.message("php.forms.create.app_type.select_public")) { "public" }
33
+ handler.option(ctx.message("php.forms.create.app_type.select_custom")) { "custom" }
34
+ end
35
+ end
36
+
37
+ unless ShopifyCLI::Tasks::CreateApiClient::VALID_APP_TYPES.include?(type)
38
+ ctx.abort(ctx.message("php.forms.create.error.invalid_app_type", type))
39
+ end
40
+ ctx.puts(ctx.message("php.forms.create.app_type.selected", type))
41
+ type
42
+ end
43
+ end
44
+ end
45
+ end