shopify-cli 2.6.4 → 2.7.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 (181) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer.json +5 -0
  3. data/.github/DESIGN.md +1 -1
  4. data/.github/ISSUE_TEMPLATE.md +7 -0
  5. data/.gitignore +1 -0
  6. data/.vscode/extensions.json +5 -0
  7. data/.vscode/settings.json +9 -0
  8. data/CHANGELOG.md +35 -3
  9. data/CONTRIBUTING.md +1 -21
  10. data/{Dockerfile → Codespace.dockerfile} +11 -3
  11. data/Gemfile +1 -0
  12. data/Gemfile.lock +6 -4
  13. data/README.md +20 -99
  14. data/Rakefile +27 -0
  15. data/Tests.dockerfile +35 -0
  16. data/assets/logo.png +0 -0
  17. data/dev.yml +0 -3
  18. data/docs/README.md +13 -0
  19. data/docs/contributors/testing.md +27 -0
  20. data/docs/users/installation.md +46 -0
  21. data/{THEMEKIT_MIGRATION.md → docs/users/migrate-from-themekit.md} +1 -1
  22. data/ext/javy/javy.rb +186 -0
  23. data/ext/javy/version +1 -0
  24. data/lib/project_types/extension/cli.rb +7 -3
  25. data/lib/project_types/extension/commands/build.rb +1 -0
  26. data/lib/project_types/extension/commands/create.rb +6 -6
  27. data/lib/project_types/extension/commands/extension_command.rb +1 -1
  28. data/lib/project_types/extension/features/argo.rb +1 -8
  29. data/lib/project_types/extension/features/argo_serve.rb +9 -23
  30. data/lib/project_types/extension/forms/create.rb +1 -1
  31. data/lib/project_types/extension/forms/questions/ask_template.rb +3 -6
  32. data/lib/project_types/extension/messages/messages.rb +1 -0
  33. data/lib/project_types/extension/models/development_server_requirements.rb +2 -3
  34. data/lib/project_types/extension/models/server_config/app.rb +13 -0
  35. data/lib/project_types/extension/models/server_config/development.rb +5 -4
  36. data/lib/project_types/extension/models/server_config/development_renderer.rb +1 -1
  37. data/lib/project_types/extension/models/server_config/development_resource.rb +13 -0
  38. data/lib/project_types/extension/models/server_config/extension.rb +4 -0
  39. data/lib/project_types/extension/models/server_config/root.rb +4 -1
  40. data/lib/project_types/extension/tasks/convert_server_config.rb +65 -0
  41. data/lib/project_types/extension/tasks/ensure_resource_url.rb +39 -0
  42. data/lib/project_types/extension/tasks/find_package_from_json.rb +37 -0
  43. data/lib/project_types/extension/tasks/merge_server_config.rb +32 -0
  44. data/lib/project_types/extension/tasks/run_extension_command.rb +11 -10
  45. data/lib/project_types/node/cli.rb +0 -16
  46. data/lib/project_types/node/forms/create.rb +5 -5
  47. data/lib/project_types/node/messages/messages.rb +2 -144
  48. data/lib/project_types/php/cli.rb +0 -11
  49. data/lib/project_types/php/forms/create.rb +5 -6
  50. data/lib/project_types/php/messages/messages.rb +2 -161
  51. data/lib/project_types/rails/cli.rb +0 -16
  52. data/lib/project_types/rails/commands/create.rb +46 -17
  53. data/lib/project_types/rails/forms/create.rb +5 -7
  54. data/lib/project_types/rails/messages/messages.rb +6 -151
  55. data/lib/project_types/script/cli.rb +2 -1
  56. data/lib/project_types/script/commands/create.rb +2 -5
  57. data/lib/project_types/script/commands/javy.rb +31 -0
  58. data/lib/project_types/script/commands/push.rb +1 -1
  59. data/lib/project_types/script/config/extension_points.yml +3 -0
  60. data/lib/project_types/script/errors.rb +0 -18
  61. data/lib/project_types/script/layers/application/create_script.rb +2 -2
  62. data/lib/project_types/script/layers/domain/script_json.rb +1 -1
  63. data/lib/project_types/script/layers/infrastructure/api_clients/partners_proxy_api_client.rb +0 -4
  64. data/lib/project_types/script/layers/infrastructure/errors.rb +8 -3
  65. data/lib/project_types/script/layers/infrastructure/languages/assemblyscript_task_runner.rb +22 -3
  66. data/lib/project_types/script/layers/infrastructure/languages/typescript_task_runner.rb +25 -0
  67. data/lib/project_types/script/layers/infrastructure/script_project_repository.rb +3 -4
  68. data/lib/project_types/script/layers/infrastructure/script_service.rb +1 -1
  69. data/lib/project_types/script/messages/messages.rb +16 -22
  70. data/lib/project_types/script/ui/error_handler.rb +1 -27
  71. data/lib/project_types/theme/cli.rb +1 -1
  72. data/lib/project_types/theme/commands/check.rb +1 -1
  73. data/lib/project_types/theme/commands/delete.rb +1 -1
  74. data/lib/project_types/theme/commands/init.rb +1 -1
  75. data/lib/project_types/theme/commands/language_server.rb +1 -1
  76. data/lib/project_types/theme/commands/package.rb +1 -1
  77. data/lib/project_types/theme/commands/publish.rb +1 -1
  78. data/lib/project_types/theme/commands/pull.rb +1 -1
  79. data/lib/project_types/theme/commands/push.rb +1 -1
  80. data/lib/project_types/theme/commands/serve.rb +9 -2
  81. data/lib/project_types/theme/messages/messages.rb +30 -1
  82. data/lib/shopify_cli/admin_api/populate_resource_command.rb +1 -1
  83. data/lib/shopify_cli/api.rb +7 -2
  84. data/lib/shopify_cli/app_type_detector.rb +24 -20
  85. data/lib/shopify_cli/command/app_sub_command.rb +10 -0
  86. data/lib/shopify_cli/command/project_command.rb +18 -0
  87. data/lib/shopify_cli/command/sub_command.rb +19 -0
  88. data/lib/shopify_cli/command.rb +7 -2
  89. data/lib/shopify_cli/commands/app/connect.rb +22 -0
  90. data/lib/shopify_cli/commands/app/create/node.rb +38 -0
  91. data/lib/shopify_cli/commands/app/create/php.rb +36 -0
  92. data/lib/shopify_cli/commands/app/create/rails.rb +40 -0
  93. data/lib/shopify_cli/commands/app/create.rb +28 -0
  94. data/lib/shopify_cli/commands/app/deploy.rb +49 -0
  95. data/lib/shopify_cli/commands/app/open.rb +19 -0
  96. data/lib/shopify_cli/commands/app/serve.rb +49 -0
  97. data/lib/shopify_cli/commands/app/tunnel.rb +43 -0
  98. data/lib/shopify_cli/commands/app.rb +29 -0
  99. data/lib/shopify_cli/commands/config.rb +2 -2
  100. data/lib/shopify_cli/commands.rb +1 -0
  101. data/lib/shopify_cli/constants.rb +4 -0
  102. data/lib/shopify_cli/exception_reporter.rb +8 -6
  103. data/lib/shopify_cli/git.rb +12 -1
  104. data/lib/shopify_cli/github/issue_url_generator.rb +19 -0
  105. data/lib/shopify_cli/github.rb +5 -0
  106. data/lib/shopify_cli/messages/messages.rb +253 -9
  107. data/lib/shopify_cli/migrator.rb +9 -11
  108. data/lib/shopify_cli/project.rb +5 -1
  109. data/lib/shopify_cli/project_commands.rb +1 -1
  110. data/lib/shopify_cli/services/app/connect_service.rb +25 -0
  111. data/lib/shopify_cli/services/app/create/node_service.rb +155 -0
  112. data/lib/shopify_cli/services/app/create/php_service.rb +152 -0
  113. data/lib/shopify_cli/services/app/create/rails_service.rb +215 -0
  114. data/lib/shopify_cli/services/app/deploy/heroku/node_service.rb +101 -0
  115. data/lib/shopify_cli/services/app/deploy/heroku/php_service.rb +135 -0
  116. data/lib/shopify_cli/services/app/deploy/heroku/rails_service.rb +120 -0
  117. data/lib/shopify_cli/services/app/open_service.rb +19 -0
  118. data/lib/shopify_cli/services/app/serve/node_service.rb +42 -0
  119. data/lib/shopify_cli/services/app/serve/php_service.rb +46 -0
  120. data/lib/shopify_cli/services/app/serve/rails_service.rb +48 -0
  121. data/lib/shopify_cli/services/app/tunnel/auth_service.rb +21 -0
  122. data/lib/shopify_cli/services/app/tunnel/start_service.rb +20 -0
  123. data/lib/shopify_cli/services/app/tunnel/stop_service.rb +20 -0
  124. data/lib/shopify_cli/services.rb +31 -0
  125. data/lib/shopify_cli/theme/dev_server/local_assets.rb +1 -1
  126. data/lib/shopify_cli/theme/dev_server.rb +35 -17
  127. data/lib/shopify_cli/tunnel.rb +25 -20
  128. data/lib/shopify_cli/version.rb +1 -1
  129. data/lib/shopify_cli.rb +1 -2
  130. data/shopify-cli.gemspec +2 -6
  131. data/shopify-dev +18 -0
  132. data/utilities/constants.rb +7 -0
  133. data/utilities/docker/container.rb +30 -2
  134. data/utilities/docker.rb +3 -2
  135. data/utilities/utilities.rb +1 -0
  136. data/vendor/deps/cli-kit/lib/cli/kit/system.rb +1 -1
  137. metadata +56 -53
  138. data/docs/_config.yml +0 -2
  139. data/docs/app/node/commands/index.md +0 -4
  140. data/docs/app/node/index.md +0 -4
  141. data/docs/app/rails/commands/index.md +0 -4
  142. data/docs/app/rails/index.md +0 -4
  143. data/docs/core/index.md +0 -4
  144. data/docs/getting-started/index.md +0 -4
  145. data/docs/getting-started/install/index.md +0 -4
  146. data/docs/getting-started/migrate/index.md +0 -4
  147. data/docs/getting-started/uninstall/index.md +0 -4
  148. data/docs/getting-started/upgrade/index.md +0 -4
  149. data/docs/help/start-app/index.md +0 -4
  150. data/docs/index.md +0 -4
  151. data/ext/shopify-cli/extconf.rb +0 -60
  152. data/install.sh +0 -7
  153. data/lib/project_types/extension/tasks/converters/server_config_converter.rb +0 -31
  154. data/lib/project_types/extension/tasks/load_server_config.rb +0 -23
  155. data/lib/project_types/node/commands/connect.rb +0 -21
  156. data/lib/project_types/node/commands/create.rb +0 -125
  157. data/lib/project_types/node/commands/deploy/heroku.rb +0 -96
  158. data/lib/project_types/node/commands/deploy.rb +0 -32
  159. data/lib/project_types/node/commands/generate.rb +0 -22
  160. data/lib/project_types/node/commands/open.rb +0 -18
  161. data/lib/project_types/node/commands/serve.rb +0 -45
  162. data/lib/project_types/node/commands/tunnel.rb +0 -41
  163. data/lib/project_types/php/commands/connect.rb +0 -19
  164. data/lib/project_types/php/commands/create.rb +0 -143
  165. data/lib/project_types/php/commands/deploy/heroku.rb +0 -129
  166. data/lib/project_types/php/commands/deploy.rb +0 -32
  167. data/lib/project_types/php/commands/open.rb +0 -16
  168. data/lib/project_types/php/commands/serve.rb +0 -48
  169. data/lib/project_types/php/commands/tunnel.rb +0 -37
  170. data/lib/project_types/rails/commands/connect.rb +0 -21
  171. data/lib/project_types/rails/commands/deploy/heroku.rb +0 -115
  172. data/lib/project_types/rails/commands/deploy.rb +0 -32
  173. data/lib/project_types/rails/commands/generate/webhook.rb +0 -42
  174. data/lib/project_types/rails/commands/generate.rb +0 -60
  175. data/lib/project_types/rails/commands/open.rb +0 -18
  176. data/lib/project_types/rails/commands/serve.rb +0 -51
  177. data/lib/project_types/rails/commands/tunnel.rb +0 -41
  178. data/lib/project_types/script/graphql/app_script_update_or_create.graphql +0 -0
  179. data/lib/shopify_cli/sub_command.rb +0 -17
  180. data/shopify.fish +0 -12
  181. data/shopify.sh +0 -11
@@ -0,0 +1,135 @@
1
+ module ShopifyCLI
2
+ module Services
3
+ module App
4
+ module Deploy
5
+ module Heroku
6
+ class PHPService < BaseService
7
+ attr_reader :context
8
+
9
+ def initialize(context:)
10
+ @context = context
11
+ super()
12
+ end
13
+
14
+ def call
15
+ spin_group = CLI::UI::SpinGroup.new
16
+ heroku_service = ShopifyCLI::Heroku.new(context)
17
+
18
+ spin_group.add(context.message("core.app.deploy.heroku.downloading")) do |spinner|
19
+ heroku_service.download
20
+ spinner.update_title(context.message("core.app.deploy.heroku.downloaded"))
21
+ end
22
+ spin_group.wait
23
+
24
+ install_message = context.message(
25
+ context.windows? ? "core.app.deploy.heroku.installing_windows" : "core.app.deploy.heroku.installing"
26
+ )
27
+ spin_group.add(install_message) do |spinner|
28
+ heroku_service.install
29
+ spinner.update_title(context.message("core.app.deploy.heroku.installed"))
30
+ end
31
+ spin_group.wait
32
+
33
+ spin_group.add(context.message("core.app.deploy.heroku.git.checking")) do |spinner|
34
+ ShopifyCLI::Git.init(context)
35
+ spinner.update_title(context.message("core.app.deploy.heroku.git.initialized"))
36
+ end
37
+ spin_group.wait
38
+
39
+ if (account = heroku_service.whoami)
40
+ context.puts(context.message("core.app.deploy.heroku.authenticated_with_account", account))
41
+ else
42
+ CLI::UI::Frame.open(
43
+ context.message("core.app.deploy.heroku.authenticating"),
44
+ success_text: context.message("core.app.deploy.heroku.authenticated")
45
+ ) do
46
+ heroku_service.authenticate
47
+ end
48
+ end
49
+
50
+ if (app_name = heroku_service.app)
51
+ context.puts(context.message("core.app.deploy.heroku.app.selected", app_name))
52
+ else
53
+ app_type = CLI::UI::Prompt.ask(context.message("core.app.deploy.heroku.app.no_apps_found")) do |handler|
54
+ handler.option(context.message("core.app.deploy.heroku.app.create")) { :new }
55
+ handler.option(context.message("core.app.deploy.heroku.app.select")) { :existing }
56
+ end
57
+
58
+ if app_type == :existing
59
+ app_name = CLI::UI::Prompt.ask(context.message("core.app.deploy.heroku.app.name"))
60
+ CLI::UI::Frame.open(
61
+ context.message("core.app.deploy.heroku.app.selecting", app_name),
62
+ success_text: context.message("core.app.deploy.heroku.app.selected", app_name)
63
+ ) do
64
+ heroku_service.select_existing_app(app_name)
65
+ end
66
+ elsif app_type == :new
67
+ CLI::UI::Frame.open(
68
+ context.message("core.app.deploy.heroku.app.creating"),
69
+ success_text: context.message("core.app.deploy.heroku.app.created")
70
+ ) do
71
+ heroku_service.create_new_app
72
+ app_name = heroku_service.app
73
+ end
74
+ end
75
+ end
76
+
77
+ branches = ShopifyCLI::Git.branches(context)
78
+ if branches.length == 1
79
+ branch_to_deploy = branches[0]
80
+ context.puts(context.message("core.app.deploy.heroku.git.branch_selected", branch_to_deploy))
81
+ else
82
+ prompt_question = context.message("core.app.deploy.heroku.git.what_branch")
83
+ branch_to_deploy = CLI::UI::Prompt.ask(prompt_question) do |handler|
84
+ branches.each do |branch|
85
+ handler.option(branch) { branch }
86
+ end
87
+ end
88
+ end
89
+
90
+ app_url = "https://#{app_name}.herokuapp.com"
91
+
92
+ CLI::UI::Frame.open(
93
+ context.message("core.app.deploy.heroku.app.setting_configs"),
94
+ success_text: context.message("core.app.deploy.heroku.app.configs_set")
95
+ ) do
96
+ allowed_configs = [/SHOPIFY_API_KEY/, /SHOPIFY_API_SECRET/, /SCOPES/, /HOST/]
97
+
98
+ ShopifyCLI::Project.current.env.to_h.each do |config, value|
99
+ next unless allowed_configs.any? { |pattern| pattern.match?(config) }
100
+
101
+ value = app_url if config == "HOST"
102
+
103
+ current = heroku_service.get_config(config)
104
+ heroku_service.set_config(config, value) if current.nil? || current != value
105
+ end
106
+
107
+ current_key = heroku_service.get_config("APP_KEY")
108
+ if current_key.nil? || current_key.empty?
109
+ output, status = context.capture2e("php", "artisan", "key:generate", "--show")
110
+
111
+ abort_message = context.message("core.app.deploy.heroku.php.error.generate_app_key")
112
+ context.abort(abort_message) unless status.success?
113
+
114
+ heroku_service.set_config("APP_KEY", output.strip) if status.success?
115
+ end
116
+
117
+ heroku_service.add_buildpacks(["heroku/php", "heroku/nodejs"])
118
+ end
119
+
120
+ CLI::UI::Frame.open(
121
+ context.message("core.app.deploy.heroku.deploying"),
122
+ success_text: context.message("core.app.deploy.heroku.deployed")
123
+ ) do
124
+ heroku_service.deploy(branch_to_deploy)
125
+ end
126
+
127
+ heroku_command = heroku_service.heroku_command
128
+ context.puts(context.message("core.app.deploy.heroku.php.post_deploy", app_url, heroku_command))
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,120 @@
1
+ module ShopifyCLI
2
+ module Services
3
+ module App
4
+ module Deploy
5
+ module Heroku
6
+ class RailsService < BaseService
7
+ DB_CHECK_CMD = 'bundle exec rails runner "puts ActiveRecord::Base.connection.adapter_name.downcase"'
8
+
9
+ attr_reader :context
10
+
11
+ def initialize(context:)
12
+ @context = context
13
+ super()
14
+ end
15
+
16
+ def call
17
+ CLI::UI::Frame.open(context.message("core.app.deploy.heroku.rails.db_check.validating")) do
18
+ CLI::UI::Spinner.spin(context.message("core.app.deploy.heroku.rails.db_check.checking")) do |spinner|
19
+ db_type, err = check_db(context)
20
+ context.abort(context.message(err)) unless err.nil?
21
+ spinner.update_title(context.message("core.app.deploy.heroku.rails.db_check.validated", db_type))
22
+ end
23
+ true
24
+ end
25
+
26
+ spin_group = CLI::UI::SpinGroup.new
27
+ heroku_service = ShopifyCLI::Heroku.new(context)
28
+
29
+ spin_group.add(context.message("core.app.deploy.heroku.downloading")) do |spinner|
30
+ heroku_service.download
31
+ spinner.update_title(context.message("core.app.deploy.heroku.downloaded"))
32
+ end
33
+ spin_group.wait
34
+
35
+ spin_group.add(context.message("core.app.deploy.heroku.installing")) do |spinner|
36
+ heroku_service.install
37
+ spinner.update_title(context.message("core.app.deploy.heroku.installed"))
38
+ end
39
+ spin_group.add(context.message("core.app.deploy.heroku.git.checking")) do |spinner|
40
+ ShopifyCLI::Git.init(context)
41
+ spinner.update_title(context.message("core.app.deploy.heroku.git.initialized"))
42
+ end
43
+ spin_group.wait
44
+
45
+ if (account = heroku_service.whoami)
46
+ context.puts(context.message("core.app.deploy.heroku.authenticated_with_account", account))
47
+ else
48
+ CLI::UI::Frame.open(
49
+ context.message("core.app.deploy.heroku.authenticating"),
50
+ success_text: context.message("core.app.deploy.heroku.authenticated")
51
+ ) do
52
+ heroku_service.authenticate
53
+ end
54
+ end
55
+
56
+ if (app_name = heroku_service.app)
57
+ context.puts(context.message("core.app.deploy.heroku.app.selected", app_name))
58
+ else
59
+ app_type = CLI::UI::Prompt.ask(context.message("core.app.deploy.heroku.app.no_apps_found")) do |handler|
60
+ handler.option(context.message("core.app.deploy.heroku.app.create")) { :new }
61
+ handler.option(context.message("core.app.deploy.heroku.app.select")) { :existing }
62
+ end
63
+
64
+ if app_type == :existing
65
+ app_name = CLI::UI::Prompt.ask(context.message("core.app.deploy.heroku.app.name"))
66
+ CLI::UI::Frame.open(
67
+ context.message("core.app.deploy.heroku.app.selecting", app_name),
68
+ success_text: context.message("core.app.deploy.heroku.app.selected", app_name)
69
+ ) do
70
+ heroku_service.select_existing_app(app_name)
71
+ end
72
+ elsif app_type == :new
73
+ CLI::UI::Frame.open(
74
+ context.message("core.app.deploy.heroku.app.creating"),
75
+ success_text: context.message("core.app.deploy.heroku.app.created")
76
+ ) do
77
+ heroku_service.create_new_app
78
+ end
79
+ end
80
+ end
81
+
82
+ branches = ShopifyCLI::Git.branches(context)
83
+ if branches.length == 1
84
+ branch_to_deploy = branches[0]
85
+ context.puts(context.message("core.app.deploy.heroku.git.branch_selected", branch_to_deploy))
86
+ else
87
+ prompt_question = context.message("core.app.deploy.heroku.git.what_branch")
88
+ branch_to_deploy = CLI::UI::Prompt.ask(prompt_question) do |handler|
89
+ branches.each do |branch|
90
+ handler.option(branch) { branch }
91
+ end
92
+ end
93
+ end
94
+
95
+ CLI::UI::Frame.open(
96
+ context.message("core.app.deploy.heroku.deploying"),
97
+ success_text: context.message("core.app.deploy.heroku.deployed")
98
+ ) do
99
+ heroku_service.deploy(branch_to_deploy)
100
+ end
101
+ end
102
+
103
+ private
104
+
105
+ def check_db(context)
106
+ out, stat = context.capture2e(DB_CHECK_CMD)
107
+ if stat.success? && out.strip == "sqlite"
108
+ ["sqlite", "core.app.deploy.heroku.rails.db_check.sqlite"]
109
+ elsif !stat.success?
110
+ [nil, "core.app.deploy.heroku.rails.db_check.problem"]
111
+ else
112
+ [out.strip, nil]
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,19 @@
1
+ module ShopifyCLI
2
+ module Services
3
+ module App
4
+ class OpenService < BaseService
5
+ attr_reader :project, :context
6
+
7
+ def initialize(project:, context:)
8
+ @project = project
9
+ @context = context
10
+ super()
11
+ end
12
+
13
+ def call
14
+ context.open_url!("#{project.env.host}/login?shop=#{project.env.shop}")
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,42 @@
1
+ module ShopifyCLI
2
+ module Services
3
+ module App
4
+ module Serve
5
+ class NodeService < BaseService
6
+ attr_accessor :host, :port, :context
7
+
8
+ def initialize(host:, port:, context:)
9
+ @host = host
10
+ @port = port
11
+ @context = context
12
+ super()
13
+ end
14
+
15
+ def call
16
+ project = ShopifyCLI::Project.current
17
+ url = host || ShopifyCLI::Tunnel.start(context)
18
+ raise ShopifyCLI::Abort,
19
+ context.message("core.app.serve.error.host_must_be_https") if url.match(/^https/i).nil?
20
+ project.env.update(context, :host, url)
21
+ ShopifyCLI::Tasks::UpdateDashboardURLS.call(
22
+ context,
23
+ url: url,
24
+ callback_url: "/auth/callback",
25
+ )
26
+
27
+ if project.env.shop
28
+ project_url = "#{project.env.host}/auth?shop=#{project.env.shop}"
29
+ context.puts("\n" + context.message("core.app.serve.open_info", project_url) + "\n")
30
+ end
31
+
32
+ CLI::UI::Frame.open(context.message("core.app.serve.running_server")) do
33
+ env = project.env.to_h
34
+ env["PORT"] = port.to_s
35
+ context.system("npm run dev", env: env)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,46 @@
1
+ module ShopifyCLI
2
+ module Services
3
+ module App
4
+ module Serve
5
+ class PHPService < BaseService
6
+ attr_accessor :host, :port, :context
7
+
8
+ def initialize(host:, port:, context:)
9
+ @host = host
10
+ @port = port
11
+ @context = context
12
+ super()
13
+ end
14
+
15
+ def call
16
+ project = ShopifyCLI::Project.current
17
+ url = host || ShopifyCLI::Tunnel.start(context, port: port)
18
+ raise ShopifyCLI::Abort,
19
+ context.message("core.app.serve.error.host_must_be_https") if url.match(/^https/i).nil?
20
+ project.env.update(context, :host, url)
21
+ ShopifyCLI::Tasks::UpdateDashboardURLS.call(
22
+ context,
23
+ url: url,
24
+ callback_url: "/auth/callback",
25
+ )
26
+
27
+ if project.env.shop
28
+ project_url = "#{project.env.host}/login?shop=#{project.env.shop}"
29
+ context.puts("\n" + context.message("core.app.serve.open_info", project_url) + "\n")
30
+ end
31
+
32
+ CLI::UI::Frame.open(context.message("core.app.serve.running_server")) do
33
+ if ShopifyCLI::ProcessSupervision.running?(:npm_watch)
34
+ ShopifyCLI::ProcessSupervision.stop(:npm_watch)
35
+ end
36
+ ShopifyCLI::ProcessSupervision.start(:npm_watch, "npm run watch", force_spawn: true)
37
+
38
+ env = project.env.to_h
39
+ context.system("php", "artisan", "serve", "--port", port.to_s, env: env)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,48 @@
1
+ module ShopifyCLI
2
+ module Services
3
+ module App
4
+ module Serve
5
+ class RailsService < BaseService
6
+ attr_accessor :host, :port, :context
7
+
8
+ def initialize(host:, port:, context:)
9
+ @host = host
10
+ @port = port
11
+ @context = context
12
+ super()
13
+ end
14
+
15
+ def call
16
+ project = ShopifyCLI::Project.current
17
+ url = host || ShopifyCLI::Tunnel.start(context)
18
+ raise ShopifyCLI::Abort,
19
+ context.message("core.app.serve.error.host_must_be_https") if url.match(/^https/i).nil?
20
+ project.env.update(context, :host, url)
21
+ ShopifyCLI::Tasks::UpdateDashboardURLS.call(
22
+ context,
23
+ url: url,
24
+ callback_url: "/auth/shopify/callback",
25
+ )
26
+
27
+ if project.env.shop
28
+ project_url = "#{project.env.host}/login?shop=#{project.env.shop}"
29
+ context.puts("\n" + context.message("core.app.serve.open_info", project_url) + "\n")
30
+ end
31
+
32
+ CLI::UI::Frame.open(context.message("core.app.serve.running_server")) do
33
+ env = ShopifyCLI::Project.current.env.to_h
34
+ env.delete("HOST")
35
+ env["PORT"] = port.to_s
36
+ env["GEM_PATH"] = Rails::Gem.gem_path(context)
37
+ if context.windows?
38
+ context.system("ruby bin\\rails server", env: env)
39
+ else
40
+ context.system("bin/rails server", env: env)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,21 @@
1
+ module ShopifyCLI
2
+ module Services
3
+ module App
4
+ module Tunnel
5
+ class AuthService < BaseService
6
+ attr_accessor :context, :token
7
+
8
+ def initialize(token:, context:)
9
+ @context = context
10
+ @token = token
11
+ super()
12
+ end
13
+
14
+ def call
15
+ ShopifyCLI::Tunnel.auth(context, token)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,20 @@
1
+ module ShopifyCLI
2
+ module Services
3
+ module App
4
+ module Tunnel
5
+ class StartService < BaseService
6
+ attr_accessor :context
7
+
8
+ def initialize(context:)
9
+ @context = context
10
+ super()
11
+ end
12
+
13
+ def call
14
+ ShopifyCLI::Tunnel.start(context)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ module ShopifyCLI
2
+ module Services
3
+ module App
4
+ module Tunnel
5
+ class StopService < BaseService
6
+ attr_accessor :context
7
+
8
+ def initialize(context:)
9
+ @context = context
10
+ super()
11
+ end
12
+
13
+ def call
14
+ ShopifyCLI::Tunnel.stop(context)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -2,5 +2,36 @@ module ShopifyCLI
2
2
  module Services
3
3
  autoload :BaseService, "shopify_cli/services/base_service"
4
4
  autoload :ReportingService, "shopify_cli/services/reporting_service"
5
+
6
+ module App
7
+ module Serve
8
+ autoload :NodeService, "shopify_cli/services/app/serve/node_service"
9
+ autoload :RailsService, "shopify_cli/services/app/serve/rails_service"
10
+ autoload :PHPService, "shopify_cli/services/app/serve/php_service"
11
+ end
12
+
13
+ module Create
14
+ autoload :NodeService, "shopify_cli/services/app/create/node_service"
15
+ autoload :RailsService, "shopify_cli/services/app/create/rails_service"
16
+ autoload :PHPService, "shopify_cli/services/app/create/php_service"
17
+ end
18
+
19
+ module Deploy
20
+ module Heroku
21
+ autoload :NodeService, "shopify_cli/services/app/deploy/heroku/node_service"
22
+ autoload :RailsService, "shopify_cli/services/app/deploy/heroku/rails_service"
23
+ autoload :PHPService, "shopify_cli/services/app/deploy/heroku/php_service"
24
+ end
25
+ end
26
+
27
+ module Tunnel
28
+ autoload :StartService, "shopify_cli/services/app/tunnel/start_service"
29
+ autoload :StopService, "shopify_cli/services/app/tunnel/stop_service"
30
+ autoload :AuthService, "shopify_cli/services/app/tunnel/auth_service"
31
+ end
32
+
33
+ autoload :ConnectService, "shopify_cli/services/app/connect_service"
34
+ autoload :OpenService, "shopify_cli/services/app/open_service"
35
+ end
5
36
  end
6
37
  end
@@ -4,7 +4,7 @@ module ShopifyCLI
4
4
  module Theme
5
5
  module DevServer
6
6
  class LocalAssets
7
- ASSET_REGEX = %r{//cdn.shopify.com/s/.*?/(assets/.+\.(?:css|js))}
7
+ ASSET_REGEX = %r{//cdn\.shopify\.com/s/.+?/(assets/.+?\.(?:css|js))}
8
8
 
9
9
  class FileBody
10
10
  def initialize(path)
@@ -17,10 +17,14 @@ require "pathname"
17
17
  module ShopifyCLI
18
18
  module Theme
19
19
  module DevServer
20
+ # Errors
21
+ Error = Class.new(StandardError)
22
+ AddressBindingError = Class.new(Error)
23
+
20
24
  class << self
21
25
  attr_accessor :ctx
22
26
 
23
- def start(ctx, root, port: 9292, poll: false)
27
+ def start(ctx, root, http_bind: "127.0.0.1", port: 9292, poll: false)
24
28
  @ctx = ctx
25
29
  theme = DevelopmentTheme.new(ctx, root: root)
26
30
  ignore_filter = IgnoreFilter.from_path(root)
@@ -32,6 +36,7 @@ module ShopifyCLI
32
36
  @app = LocalAssets.new(ctx, @app, theme: theme)
33
37
  @app = HotReload.new(ctx, @app, theme: theme, watcher: watcher, ignore_filter: ignore_filter)
34
38
  stopped = false
39
+ address = "http://#{http_bind}:#{port}"
35
40
 
36
41
  theme.ensure_exists!
37
42
 
@@ -40,8 +45,8 @@ module ShopifyCLI
40
45
  stop
41
46
  end
42
47
 
43
- CLI::UI::Frame.open(@ctx.message("theme.serve.serve")) do
44
- ctx.print_task("Syncing theme ##{theme.id} on #{theme.shop}")
48
+ CLI::UI::Frame.open(@ctx.message("theme.serve.viewing_theme")) do
49
+ ctx.print_task(ctx.message("theme.serve.syncing_theme", theme.id, theme.shop))
45
50
  @syncer.start_threads
46
51
  if block_given?
47
52
  yield @syncer
@@ -51,18 +56,9 @@ module ShopifyCLI
51
56
 
52
57
  return if stopped
53
58
 
54
- ctx.puts("")
55
- ctx.puts("Serving #{theme.root}")
56
- ctx.puts("")
57
- ctx.open_url!("http://127.0.0.1:#{port}")
58
- ctx.puts("")
59
- ctx.puts("Customize this theme in the Online Store Editor:")
60
- ctx.puts("{{green:#{theme.editor_url}}}")
61
- ctx.puts("")
62
- ctx.puts("Share this theme preview:")
63
- ctx.puts("{{green:#{theme.preview_url}}}")
64
- ctx.puts("")
65
- ctx.puts("(Use Ctrl-C to stop)")
59
+ ctx.puts(ctx.message("theme.serve.serving", theme.root))
60
+ ctx.open_url!(address)
61
+ ctx.puts(ctx.message("theme.serve.customize_or_preview", theme.editor_url, theme.preview_url))
66
62
  end
67
63
 
68
64
  logger = if ctx.debug?
@@ -74,6 +70,7 @@ module ShopifyCLI
74
70
  watcher.start
75
71
  WebServer.run(
76
72
  @app,
73
+ BindAddress: http_bind,
77
74
  Port: port,
78
75
  Logger: logger,
79
76
  AccessLog: [],
@@ -82,8 +79,11 @@ module ShopifyCLI
82
79
 
83
80
  rescue ShopifyCLI::API::APIRequestForbiddenError,
84
81
  ShopifyCLI::API::APIRequestUnauthorizedError
85
- @ctx.abort("You are not authorized to edit themes on #{theme.shop}.\n" \
86
- "Make sure you are a user of that store, and allowed to edit themes.")
82
+ raise ShopifyCLI::Abort, @ctx.message("theme.serve.ensure_user", theme.shop)
83
+ rescue Errno::EADDRINUSE
84
+ abort_address_already_in_use(address)
85
+ rescue Errno::EADDRNOTAVAIL
86
+ raise AddressBindingError, "Error binding to the address #{http_bind}."
87
87
  end
88
88
 
89
89
  def stop
@@ -92,6 +92,24 @@ module ShopifyCLI
92
92
  @syncer.shutdown
93
93
  WebServer.shutdown
94
94
  end
95
+
96
+ private
97
+
98
+ def abort_address_already_in_use(address)
99
+ open_frame(@ctx.message("theme.serve.already_in_use_error"), color: :red) do
100
+ @ctx.puts(@ctx.message("theme.serve.address_already_in_use", address))
101
+ end
102
+
103
+ open_frame(@ctx.message("theme.serve.try_this"), color: :green) do
104
+ @ctx.puts(@ctx.message("theme.serve.try_port_option"))
105
+ end
106
+
107
+ raise ShopifyCLI::AbortSilent
108
+ end
109
+
110
+ def open_frame(title, color:, &block)
111
+ CLI::UI::Frame.open(title, color: CLI::UI.resolve_color(color), timing: false, &block)
112
+ end
95
113
  end
96
114
  end
97
115
  end