shopify-cli 2.10.1 → 2.11.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.yaml +117 -0
  3. data/.github/ISSUE_TEMPLATE/enhancement.yaml +38 -0
  4. data/.github/ISSUE_TEMPLATE/feature.yaml +47 -0
  5. data/.github/ISSUE_TEMPLATE.md +18 -0
  6. data/CHANGELOG.md +38 -3
  7. data/Gemfile.lock +1 -1
  8. data/bin/shopify +9 -0
  9. data/dev.yml +3 -0
  10. data/lib/project_types/extension/commands/check.rb +2 -0
  11. data/lib/project_types/extension/commands/create.rb +2 -0
  12. data/lib/project_types/extension/commands/push.rb +15 -0
  13. data/lib/project_types/extension/commands/serve.rb +2 -0
  14. data/lib/project_types/extension/loaders/project.rb +28 -8
  15. data/lib/project_types/extension/messages/messages.rb +10 -2
  16. data/lib/project_types/extension/models/specification_handlers/default.rb +1 -1
  17. data/lib/project_types/extension/models/specification_handlers/theme_app_extension.rb +7 -1
  18. data/lib/project_types/extension/tasks/convert_server_config.rb +3 -1
  19. data/lib/project_types/script/cli.rb +5 -0
  20. data/lib/project_types/script/commands/connect.rb +3 -1
  21. data/lib/project_types/script/commands/create.rb +2 -0
  22. data/lib/project_types/script/commands/push.rb +6 -0
  23. data/lib/project_types/script/config/extension_points.yml +12 -0
  24. data/lib/project_types/script/graphql/module_upload_url_generate.graphql +5 -1
  25. data/lib/project_types/script/layers/application/build_script.rb +6 -2
  26. data/lib/project_types/script/layers/application/create_script.rb +1 -1
  27. data/lib/project_types/script/layers/application/project_dependencies.rb +1 -1
  28. data/lib/project_types/script/layers/application/push_script.rb +39 -31
  29. data/lib/project_types/script/layers/domain/errors.rb +7 -1
  30. data/lib/project_types/script/layers/domain/extension_point.rb +2 -2
  31. data/lib/project_types/script/layers/infrastructure/errors.rb +13 -3
  32. data/lib/project_types/script/layers/infrastructure/languages/assemblyscript_task_runner.rb +3 -16
  33. data/lib/project_types/script/layers/infrastructure/languages/project_creator.rb +1 -0
  34. data/lib/project_types/script/layers/infrastructure/languages/task_runner.rb +35 -8
  35. data/lib/project_types/script/layers/infrastructure/languages/typescript_task_runner.rb +3 -16
  36. data/lib/project_types/script/layers/infrastructure/languages/wasm_project_creator.rb +15 -0
  37. data/lib/project_types/script/layers/infrastructure/languages/wasm_task_runner.rb +32 -0
  38. data/lib/project_types/script/layers/infrastructure/metadata_repository.rb +18 -0
  39. data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +1 -1
  40. data/lib/project_types/script/layers/infrastructure/script_service.rb +12 -8
  41. data/lib/project_types/script/layers/infrastructure/script_uploader.rb +22 -9
  42. data/lib/project_types/script/loaders/project.rb +2 -1
  43. data/lib/project_types/script/messages/messages.rb +92 -84
  44. data/lib/project_types/script/ui/error_handler.rb +39 -14
  45. data/lib/project_types/theme/commands/check.rb +2 -0
  46. data/lib/project_types/theme/commands/delete.rb +2 -0
  47. data/lib/project_types/theme/commands/init.rb +2 -0
  48. data/lib/project_types/theme/commands/language_server.rb +2 -0
  49. data/lib/project_types/theme/commands/package.rb +2 -0
  50. data/lib/project_types/theme/commands/publish.rb +2 -0
  51. data/lib/project_types/theme/commands/pull.rb +9 -2
  52. data/lib/project_types/theme/commands/push.rb +7 -4
  53. data/lib/project_types/theme/commands/serve.rb +2 -0
  54. data/lib/shopify_cli/command/sub_command.rb +2 -0
  55. data/lib/shopify_cli/command.rb +74 -0
  56. data/lib/shopify_cli/commands/app/create/node.rb +3 -0
  57. data/lib/shopify_cli/commands/app/create/rails.rb +3 -0
  58. data/lib/shopify_cli/commands/app/deploy.rb +2 -0
  59. data/lib/shopify_cli/commands/app/serve.rb +2 -0
  60. data/lib/shopify_cli/constants.rb +13 -1
  61. data/lib/shopify_cli/environment.rb +55 -35
  62. data/lib/shopify_cli/exception_reporter.rb +9 -0
  63. data/lib/shopify_cli/github/issue_url_generator.rb +19 -8
  64. data/lib/shopify_cli/identity_auth/env_auth_token.rb +34 -0
  65. data/lib/shopify_cli/identity_auth.rb +33 -15
  66. data/lib/shopify_cli/messages/messages.rb +3 -2
  67. data/lib/shopify_cli/partners_api.rb +7 -2
  68. data/lib/shopify_cli/services/app/create/rails_service.rb +37 -13
  69. data/lib/shopify_cli/theme/dev_server/hot_reload/remote_file_reloader.rb +63 -0
  70. data/lib/shopify_cli/theme/dev_server/hot_reload.rb +22 -6
  71. data/lib/shopify_cli/theme/dev_server/proxy.rb +4 -5
  72. data/lib/shopify_cli/theme/dev_server.rb +1 -3
  73. data/lib/shopify_cli/theme/development_theme.rb +11 -0
  74. data/lib/shopify_cli/theme/file.rb +4 -0
  75. data/lib/shopify_cli/theme/include_filter.rb +39 -17
  76. data/lib/shopify_cli/theme/theme.rb +0 -4
  77. data/lib/shopify_cli/utilities.rb +7 -0
  78. data/lib/shopify_cli/version.rb +1 -1
  79. data/lib/shopify_cli.rb +1 -0
  80. data/vendor/deps/cli-kit/lib/cli/kit/system.rb +11 -6
  81. data/vendor/deps/cli-kit/lib/cli/kit/util.rb +5 -1
  82. data/vendor/deps/cli-ui/lib/cli/ui/os.rb +6 -4
  83. data/vendor/lib/semantic/version.rb +0 -1
  84. metadata +11 -3
  85. data/lib/project_types/rails/commands/create.rb +0 -210
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "hot_reload/remote_file_reloader"
4
+
3
5
  module ShopifyCLI
4
6
  module Theme
5
7
  module DevServer
@@ -10,6 +12,7 @@ module ShopifyCLI
10
12
  @theme = theme
11
13
  @mode = mode
12
14
  @streams = SSE::Streams.new
15
+ @remote_file_reloader = RemoteFileReloader.new(ctx, theme: @theme, streams: @streams)
13
16
  @watcher = watcher
14
17
  @watcher.add_observer(self, :notify_streams_of_file_change)
15
18
  @ignore_filter = ignore_filter
@@ -32,17 +35,30 @@ module ShopifyCLI
32
35
  end
33
36
 
34
37
  def notify_streams_of_file_change(modified, added, _removed)
35
- files = (modified + added).reject { |file| @ignore_filter&.ignore?(file) }
36
- .map { |file| @theme[file].relative_path }
38
+ files = (modified + added)
39
+ .reject { |file| @ignore_filter&.ignore?(file) }
40
+ .map { |file| @theme[file] }
37
41
 
38
- unless files.empty?
39
- @streams.broadcast(JSON.generate(modified: files))
40
- @ctx.debug("[HotReload] Modified #{files.join(", ")}")
41
- end
42
+ files -= liquid_css_files = files.select(&:liquid_css?)
43
+
44
+ hot_reload(files) unless files.empty?
45
+ remote_reload(liquid_css_files)
42
46
  end
43
47
 
44
48
  private
45
49
 
50
+ def hot_reload(files)
51
+ paths = files.map(&:relative_path)
52
+ @streams.broadcast(JSON.generate(modified: paths))
53
+ @ctx.debug("[HotReload] Modified #{paths.join(", ")}")
54
+ end
55
+
56
+ def remote_reload(files)
57
+ files.each do |file|
58
+ @remote_file_reloader.reload(file)
59
+ end
60
+ end
61
+
46
62
  def request_is_html?(headers)
47
63
  headers["content-type"]&.start_with?("text/html")
48
64
  end
@@ -43,9 +43,8 @@ module ShopifyCLI
43
43
  headers["Accept-Encoding"] = "none"
44
44
  headers["User-Agent"] = "Shopify CLI"
45
45
 
46
- query = URI.decode_www_form(env["QUERY_STRING"]).to_h
46
+ query = URI.decode_www_form(env["QUERY_STRING"])
47
47
  replace_templates = build_replace_templates_param(env)
48
-
49
48
  response = if replace_templates.any?
50
49
  # Pass to SFR the recently modified templates in `replace_templates` body param
51
50
  headers["Authorization"] = "Bearer #{bearer_token}"
@@ -158,7 +157,7 @@ module ShopifyCLI
158
157
  def secure_session_id
159
158
  if secure_session_id_expired?
160
159
  @ctx.debug("Refreshing preview _secure_session_id cookie")
161
- response = request("HEAD", "/", query: { preview_theme_id: @theme.id })
160
+ response = request("HEAD", "/", query: [[:preview_theme_id, @theme.id]])
162
161
  @secure_session_id = extract_secure_session_id_from_response_headers(response)
163
162
  @last_session_cookie_refresh = Time.now
164
163
  end
@@ -189,9 +188,9 @@ module ShopifyCLI
189
188
  response_headers
190
189
  end
191
190
 
192
- def request(method, path, headers: nil, query: {}, form_data: nil, body_stream: nil)
191
+ def request(method, path, headers: nil, query: [], form_data: nil, body_stream: nil)
193
192
  uri = URI.join("https://#{@theme.shop}", path)
194
- uri.query = URI.encode_www_form(query.merge(_fd: 0, pb: 0))
193
+ uri.query = URI.encode_www_form(query + [[:_fd, 0], [:pb, 0]])
195
194
 
196
195
  @ctx.debug("Proxying #{method} #{uri}")
197
196
 
@@ -28,7 +28,7 @@ module ShopifyCLI
28
28
 
29
29
  def start(ctx, root, host: "127.0.0.1", port: 9292, poll: false, mode: ReloadMode.default)
30
30
  @ctx = ctx
31
- theme = DevelopmentTheme.new(ctx, root: root)
31
+ theme = DevelopmentTheme.find_or_create!(ctx, root: root)
32
32
  ignore_filter = IgnoreFilter.from_path(root)
33
33
  @syncer = Syncer.new(ctx, theme: theme, ignore_filter: ignore_filter)
34
34
  watcher = Watcher.new(ctx, theme: theme, syncer: @syncer, ignore_filter: ignore_filter, poll: poll)
@@ -41,8 +41,6 @@ module ShopifyCLI
41
41
  stopped = false
42
42
  address = "http://#{host}:#{port}"
43
43
 
44
- theme.ensure_exists!
45
-
46
44
  trap("INT") do
47
45
  stopped = true
48
46
  stop
@@ -38,6 +38,8 @@ module ShopifyCLI
38
38
  @ctx.debug("Created temporary development theme: #{@id}")
39
39
  ShopifyCLI::DB.set(development_theme_id: @id)
40
40
  end
41
+
42
+ self
41
43
  end
42
44
 
43
45
  def exists?
@@ -63,6 +65,15 @@ module ShopifyCLI
63
65
  new(ctx).delete
64
66
  end
65
67
 
68
+ def self.find(ctx, root: nil)
69
+ dev_theme = new(ctx, root: root)
70
+ dev_theme.exists? ? dev_theme : nil
71
+ end
72
+
73
+ def self.find_or_create!(ctx, root: nil)
74
+ new(ctx, root: root).ensure_exists!
75
+ end
76
+
66
77
  private
67
78
 
68
79
  def generate_theme_name
@@ -53,6 +53,10 @@ module ShopifyCLI
53
53
  path.extname == ".liquid"
54
54
  end
55
55
 
56
+ def liquid_css?
57
+ relative_path.to_s.end_with?(".css.liquid")
58
+ end
59
+
56
60
  def json?
57
61
  path.extname == ".json"
58
62
  end
@@ -7,36 +7,58 @@ module ShopifyCLI
7
7
  class IncludeFilter
8
8
  include Filter::PathMatcher
9
9
 
10
- def initialize(pattern = nil)
11
- @pattern = pattern
10
+ attr_reader :globs, :regexes
11
+
12
+ def initialize(patterns = [])
13
+ @patterns = patterns.nil? ? [] : patterns.compact.reject(&:empty?)
14
+
15
+ regexes, globs = patterns_to_regexes_and_globs(@patterns)
16
+
17
+ @regexes = regexes
18
+ @globs = globs
12
19
  end
13
20
 
14
21
  def match?(path)
15
- return true unless present?(@pattern)
22
+ return true unless present?(@patterns)
23
+
24
+ path = path.to_s
25
+
26
+ return true if path.empty?
16
27
 
17
- if regex_pattern?
18
- regex_match?(regex_pattern, path)
19
- else
20
- glob_match?(glob_pattern, path)
28
+ regexes.each do |regex|
29
+ return true if regex_match?(regex, path)
21
30
  end
31
+
32
+ globs.each do |glob|
33
+ return true if glob_match?(glob, path)
34
+ end
35
+
36
+ false
22
37
  end
23
38
 
24
39
  private
25
40
 
26
- def present?(pattern)
27
- !pattern.nil? && !pattern.empty?
41
+ def present?(patterns)
42
+ !patterns.nil? && !patterns.empty?
28
43
  end
29
44
 
30
- def regex_pattern?
31
- @is_regex_pattern ||= regex?(@pattern)
32
- end
45
+ # Take in string patterns and convert them to either
46
+ # regex patterns or glob patterns so that they are handled in an expected manner.
47
+ def patterns_to_regexes_and_globs(patterns)
48
+ new_regexes = []
49
+ new_globs = []
33
50
 
34
- def regex_pattern
35
- @regex_pattern ||= as_regex(@pattern)
36
- end
51
+ patterns
52
+ .map(&:strip)
53
+ .each do |pattern|
54
+ if regex?(pattern)
55
+ new_regexes << as_regex(pattern)
56
+ else
57
+ new_globs << as_glob(pattern)
58
+ end
59
+ end
37
60
 
38
- def glob_pattern
39
- @glob_pattern ||= as_glob(@pattern)
61
+ [new_regexes, new_globs]
40
62
  end
41
63
  end
42
64
  end
@@ -176,10 +176,6 @@ module ShopifyCLI
176
176
  find(ctx, root) { |attrs| attrs["role"] == "main" }
177
177
  end
178
178
 
179
- def development(ctx, root: nil)
180
- find(ctx, root) { |attrs| attrs["role"] == "development" }
181
- end
182
-
183
179
  # Finds a Theme by its identifier
184
180
  #
185
181
  # #### Parameters
@@ -0,0 +1,7 @@
1
+ module ShopifyCLI
2
+ module Utilities
3
+ def self.version_dropping_pre_and_build(version)
4
+ Semantic::Version.new("#{version.major}.#{version.minor}.#{version.patch}")
5
+ end
6
+ end
7
+ end
@@ -1,3 +1,3 @@
1
1
  module ShopifyCLI
2
- VERSION = "2.10.1"
2
+ VERSION = "2.11.2"
3
3
  end
data/lib/shopify_cli.rb CHANGED
@@ -136,6 +136,7 @@ module ShopifyCLI
136
136
  autoload :Tasks, "shopify_cli/tasks"
137
137
  autoload :TransformDataStructure, "shopify_cli/transform_data_structure"
138
138
  autoload :Tunnel, "shopify_cli/tunnel"
139
+ autoload :Utilities, "shopify_cli/utilities"
139
140
 
140
141
  require "shopify_cli/messages/messages"
141
142
  Context.load_messages(ShopifyCLI::Messages::MESSAGES)
@@ -174,11 +174,16 @@ module CLI
174
174
  end
175
175
 
176
176
  def os
177
- return :mac if /darwin/.match(RUBY_PLATFORM)
178
- return :linux if /linux/.match(RUBY_PLATFORM)
179
- return :windows if /mingw32/.match(RUBY_PLATFORM)
180
-
181
- raise "Could not determine OS from platform #{RUBY_PLATFORM}"
177
+ @current_os ||= case RbConfig::CONFIG['host_os']
178
+ when /darwin/ then :mac
179
+ when /linux/ then :linux
180
+ else
181
+ if RUBY_PLATFORM !~ /cygwin/ && ENV['OS'] == 'Windows_NT'
182
+ :windows
183
+ else
184
+ raise "Could not determine OS from host_os #{RbConfig::CONFIG["host_os"]}"
185
+ end
186
+ end
182
187
  end
183
188
 
184
189
  private
@@ -222,7 +227,7 @@ module CLI
222
227
  end
223
228
 
224
229
  def which(cmd, env)
225
- exts = os == :windows ? env.fetch('PATHEXT', ['']).split(';') : ['']
230
+ exts = (os == :windows && env['PATHEXT']&.split(';')) || ['']
226
231
  env.fetch('PATH', '').split(File::PATH_SEPARATOR).each do |path|
227
232
  exts.each do |ext|
228
233
  exe = File.join(path, "#{cmd}#{ext}")
@@ -168,9 +168,13 @@ module CLI
168
168
  @block_that_might_raise = block_that_might_raise
169
169
  end
170
170
 
171
- def retry_after(exception = StandardError, retries: 1, &before_retry)
171
+ def retry_after(exception = StandardError, retries: 1, only: nil, &before_retry)
172
172
  @block_that_might_raise.call
173
173
  rescue exception => e
174
+ should_retry = only ? only.call : true
175
+
176
+ raise unless should_retry
177
+
174
178
  raise if (retries -= 1) < 0
175
179
  if before_retry
176
180
  if before_retry.arity == 0
@@ -4,15 +4,17 @@ module CLI
4
4
  # Determines which OS is currently running the UI, to make it easier to
5
5
  # adapt its behaviour to the features of the OS.
6
6
  def self.current
7
- @current_os ||= case RUBY_PLATFORM
7
+ @current_os ||= case RbConfig::CONFIG['host_os']
8
8
  when /darwin/
9
9
  Mac
10
10
  when /linux/
11
11
  Linux
12
- when /mingw32/
13
- Windows
14
12
  else
15
- raise "Could not determine OS from platform #{RUBY_PLATFORM}"
13
+ if RUBY_PLATFORM !~ /cygwin/ && ENV['OS'] == 'Windows_NT'
14
+ Windows
15
+ else
16
+ raise "Could not determine OS from host_os #{RbConfig::CONFIG["host_os"]}"
17
+ end
16
18
  end
17
19
  end
18
20
 
@@ -21,7 +21,6 @@ module Semantic
21
21
  @version = version_str
22
22
  end
23
23
 
24
-
25
24
  def build=(b)
26
25
  @build = (!b.nil? && b.empty?) ? nil : b
27
26
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shopify-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.10.1
4
+ version: 2.11.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-28 00:00:00.000000000 Z
11
+ date: 2022-02-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -118,6 +118,9 @@ files:
118
118
  - ".github/CONTRIBUTING.md"
119
119
  - ".github/DESIGN.md"
120
120
  - ".github/ISSUE_TEMPLATE.md"
121
+ - ".github/ISSUE_TEMPLATE/bug_report.yaml"
122
+ - ".github/ISSUE_TEMPLATE/enhancement.yaml"
123
+ - ".github/ISSUE_TEMPLATE/feature.yaml"
121
124
  - ".github/PULL_REQUEST_TEMPLATE.md"
122
125
  - ".github/probots.yml"
123
126
  - ".github/workflows/shopify.yml"
@@ -273,7 +276,6 @@ files:
273
276
  - lib/project_types/php/forms/create.rb
274
277
  - lib/project_types/php/messages/messages.rb
275
278
  - lib/project_types/rails/cli.rb
276
- - lib/project_types/rails/commands/create.rb
277
279
  - lib/project_types/rails/forms/create.rb
278
280
  - lib/project_types/rails/gem.rb
279
281
  - lib/project_types/rails/messages/messages.rb
@@ -317,6 +319,9 @@ files:
317
319
  - lib/project_types/script/layers/infrastructure/languages/task_runner.rb
318
320
  - lib/project_types/script/layers/infrastructure/languages/typescript_project_creator.rb
319
321
  - lib/project_types/script/layers/infrastructure/languages/typescript_task_runner.rb
322
+ - lib/project_types/script/layers/infrastructure/languages/wasm_project_creator.rb
323
+ - lib/project_types/script/layers/infrastructure/languages/wasm_task_runner.rb
324
+ - lib/project_types/script/layers/infrastructure/metadata_repository.rb
320
325
  - lib/project_types/script/layers/infrastructure/push_package_repository.rb
321
326
  - lib/project_types/script/layers/infrastructure/script_project_repository.rb
322
327
  - lib/project_types/script/layers/infrastructure/script_service.rb
@@ -402,6 +407,7 @@ files:
402
407
  - lib/shopify_cli/heroku.rb
403
408
  - lib/shopify_cli/http_request.rb
404
409
  - lib/shopify_cli/identity_auth.rb
410
+ - lib/shopify_cli/identity_auth/env_auth_token.rb
405
411
  - lib/shopify_cli/identity_auth/servlet.rb
406
412
  - lib/shopify_cli/js_deps.rb
407
413
  - lib/shopify_cli/js_system.rb
@@ -463,6 +469,7 @@ files:
463
469
  - lib/shopify_cli/theme/dev_server/header_hash.rb
464
470
  - lib/shopify_cli/theme/dev_server/hot-reload.js
465
471
  - lib/shopify_cli/theme/dev_server/hot_reload.rb
472
+ - lib/shopify_cli/theme/dev_server/hot_reload/remote_file_reloader.rb
466
473
  - lib/shopify_cli/theme/dev_server/local_assets.rb
467
474
  - lib/shopify_cli/theme/dev_server/proxy.rb
468
475
  - lib/shopify_cli/theme/dev_server/proxy/template_param_builder.rb
@@ -485,6 +492,7 @@ files:
485
492
  - lib/shopify_cli/thread_pool/job.rb
486
493
  - lib/shopify_cli/transform_data_structure.rb
487
494
  - lib/shopify_cli/tunnel.rb
495
+ - lib/shopify_cli/utilities.rb
488
496
  - lib/shopify_cli/version.rb
489
497
  - shopify-cli.gemspec
490
498
  - shopify-dev
@@ -1,210 +0,0 @@
1
- # frozen_string_literal: true
2
- module Rails
3
- class Command
4
- class Create < ShopifyCLI::Command::AppSubCommand
5
- prerequisite_task :ensure_authenticated
6
-
7
- USER_AGENT_CODE = <<~USERAGENT
8
- module ShopifyAPI
9
- class Base < ActiveResource::Base
10
- self.headers['User-Agent'] << " | ShopifyApp/\#{ShopifyApp::VERSION} | Shopify CLI"
11
- end
12
- end
13
- USERAGENT
14
-
15
- DEFAULT_RAILS_FLAGS = %w(--skip-spring)
16
-
17
- options do |parser, flags|
18
- # backwards compatibility allow 'title' for now
19
- parser.on("--title=TITLE") { |t| flags[:title] = t }
20
- parser.on("--name=NAME") { |t| flags[:title] = t }
21
- parser.on("--organization_id=ID") { |id| flags[:organization_id] = id }
22
- parser.on("--organization-id=ID") { |id| flags[:organization_id] = id }
23
- parser.on("--store=MYSHOPIFYDOMAIN") { |url| flags[:shop_domain] = url }
24
- # backwards compatibility allow 'shop domain' for now
25
- parser.on("--shop_domain=MYSHOPIFYDOMAIN") { |url| flags[:shop_domain] = url }
26
- parser.on("--shop-domain=MYSHOPIFYDOMAIN") { |url| flags[:shop_domain] = url }
27
- parser.on("--type=APPTYPE") { |type| flags[:type] = type }
28
- parser.on("--db=DB") { |db| flags[:db] = db }
29
- parser.on("--rails_opts=RAILSOPTS") { |opts| flags[:rails_opts] = opts }
30
- parser.on("--rails-opts=RAILSOPTS") { |opts| flags[:rails_opts] = opts }
31
- end
32
-
33
- def call(args, _name)
34
- form_data = self.form_data(args)
35
- return @ctx.puts(self.class.help) if form_data.nil?
36
-
37
- ruby_version = Ruby.version(@ctx)
38
- @ctx.abort(@ctx.message("rails.create.error.invalid_ruby_version")) unless
39
- ruby_version.satisfies?("~>2.5") || ruby_version.satisfies?("~>3.0.0")
40
-
41
- check_node
42
- check_yarn
43
-
44
- build(form_data.name, form_data.db)
45
-
46
- set_custom_ua
47
- ShopifyCLI::Project.write(
48
- @ctx,
49
- project_type: "rails",
50
- organization_id: form_data.organization_id,
51
- )
52
-
53
- api_client = if ShopifyCLI::Environment.acceptance_test?
54
- {
55
- "apiKey" => "public_api_key",
56
- "apiSecretKeys" => [
57
- {
58
- "secret" => "api_secret_key",
59
- },
60
- ],
61
- }
62
- else
63
- ShopifyCLI::Tasks::CreateApiClient.call(
64
- @ctx,
65
- org_id: form_data.organization_id,
66
- title: form_data.title,
67
- type: form_data.type,
68
- )
69
- end
70
-
71
- ShopifyCLI::Resources::EnvFile.new(
72
- api_key: api_client["apiKey"],
73
- secret: api_client["apiSecretKeys"].first["secret"],
74
- shop: form_data.shop_domain,
75
- scopes: "write_products,write_customers,write_draft_orders",
76
- ).write(@ctx)
77
-
78
- partners_url = ShopifyCLI::PartnersAPI.partners_url_for(form_data.organization_id, api_client["id"])
79
-
80
- @ctx.puts(@ctx.message("apps.create.info.created", form_data.title, partners_url))
81
- @ctx.puts(@ctx.message("apps.create.info.serve", form_data.name, ShopifyCLI::TOOL_NAME, "rails"))
82
- unless ShopifyCLI::Shopifolk.acting_as_shopify_organization?
83
- @ctx.puts(@ctx.message("apps.create.info.install", partners_url, form_data.title))
84
- end
85
- end
86
-
87
- def form_data(args)
88
- if ShopifyCLI::Environment.acceptance_test?
89
- Struct.new(:title, :name, :organization_id, :type, :shop_domain, :db, keyword_init: true).new(
90
- title: options.flags[:title],
91
- name: options.flags[:title],
92
- organization_id: "123",
93
- shop_domain: "test.shopify.io",
94
- type: "public",
95
- db: options.flags[:db]
96
- )
97
- else
98
- Forms::Create.ask(@ctx, args, options.flags)
99
- end
100
- end
101
-
102
- def self.help
103
- ShopifyCLI::Context.message("rails.create.help", ShopifyCLI::TOOL_NAME, ShopifyCLI::TOOL_NAME)
104
- end
105
-
106
- private
107
-
108
- def check_node
109
- cmd_path = @ctx.which("node")
110
- if cmd_path.nil?
111
- @ctx.abort(@ctx.message("rails.create.error.node_required")) unless @ctx.windows?
112
- @ctx.puts("{{x}} {{red:" + @ctx.message("rails.create.error.node_required") + "}}")
113
- @ctx.puts(@ctx.message("rails.create.info.open_new_shell", "node"))
114
- raise ShopifyCLI::AbortSilent
115
- end
116
-
117
- version, stat = @ctx.capture2e("node", "-v")
118
- unless stat.success?
119
- @ctx.abort(@ctx.message("rails.create.error.node_version_failure")) unless @ctx.windows?
120
- # execution stops above if not Windows
121
- @ctx.puts("{{x}} {{red:" + @ctx.message("rails.create.error.node_version_failure") + "}}")
122
- @ctx.puts(@ctx.message("rails.create.info.open_new_shell", "node"))
123
- raise ShopifyCLI::AbortSilent
124
- end
125
-
126
- @ctx.done(@ctx.message("rails.create.node_version", version))
127
- end
128
-
129
- def check_yarn
130
- cmd_path = @ctx.which("yarn")
131
- if cmd_path.nil?
132
- @ctx.abort(@ctx.message("rails.create.error.yarn_required")) unless @ctx.windows?
133
- @ctx.puts("{{x}} {{red:" + @ctx.message("rails.create.error.yarn_required") + "}}")
134
- @ctx.puts(@ctx.message("rails.create.info.open_new_shell", "yarn"))
135
- raise ShopifyCLI::AbortSilent
136
- end
137
-
138
- version, stat = @ctx.capture2e("yarn", "-v")
139
- unless stat.success?
140
- @ctx.abort(@ctx.message("rails.create.error.yarn_version_failure")) unless @ctx.windows?
141
- @ctx.puts("{{x}} {{red:" + @ctx.message("rails.create.error.yarn_version_failure") + "}}")
142
- @ctx.puts(@ctx.message("rails.create.info.open_new_shell", "yarn"))
143
- raise ShopifyCLI::AbortSilent
144
- end
145
-
146
- @ctx.done(@ctx.message("rails.create.yarn_version", version))
147
- end
148
-
149
- def build(name, db)
150
- @ctx.abort(@ctx.message("rails.create.error.install_failure", "rails")) unless install_gem("rails", "<6.1")
151
- @ctx.abort(@ctx.message("rails.create.error.install_failure", "bundler ~>2.0")) unless
152
- install_gem("bundler", "~>2.0")
153
-
154
- full_path = File.join(@ctx.root, name)
155
- @ctx.abort(@ctx.message("rails.create.error.dir_exists", name)) if Dir.exist?(full_path)
156
-
157
- CLI::UI::Frame.open(@ctx.message("rails.create.generating_app", name)) do
158
- new_command = %w(rails new)
159
- new_command << name
160
- new_command += DEFAULT_RAILS_FLAGS
161
- new_command << "--database=#{db}"
162
- new_command += options.flags[:rails_opts].split unless options.flags[:rails_opts].nil?
163
-
164
- syscall(new_command)
165
- end
166
-
167
- @ctx.root = full_path
168
-
169
- File.open(File.join(@ctx.root, ".gitignore"), "a") { |f| f.write(".env") }
170
-
171
- @ctx.puts(@ctx.message("rails.create.adding_shopify_gem"))
172
- File.open(File.join(@ctx.root, "Gemfile"), "a") do |f|
173
- f.puts "\ngem 'shopify_app', '>=17.0.3'"
174
- end
175
- CLI::UI::Frame.open(@ctx.message("rails.create.running_bundle_install")) do
176
- syscall(%w(bundle install))
177
- end
178
-
179
- CLI::UI::Frame.open(@ctx.message("rails.create.running_generator")) do
180
- syscall(%w(rails generate shopify_app --new-shopify-cli-app))
181
- end
182
-
183
- CLI::UI::Frame.open(@ctx.message("rails.create.running_migrations")) do
184
- syscall(%w(rails db:create))
185
- syscall(%w(rails db:migrate RAILS_ENV=development))
186
- end
187
-
188
- unless File.exist?(File.join(@ctx.root, "config/webpacker.yml"))
189
- CLI::UI::Frame.open(@ctx.message("rails.create.running_webpacker_install")) do
190
- syscall(%w(rails webpacker:install))
191
- end
192
- end
193
- end
194
-
195
- def set_custom_ua
196
- ua_path = File.join("config", "initializers", "user_agent.rb")
197
- @ctx.write(ua_path, USER_AGENT_CODE)
198
- end
199
-
200
- def syscall(args)
201
- args[0] = Gem.binary_path_for(@ctx, args[0])
202
- @ctx.system(*args, chdir: @ctx.root)
203
- end
204
-
205
- def install_gem(name, version = nil)
206
- Gem.install(@ctx, name, version)
207
- end
208
- end
209
- end
210
- end