shopify-cli 2.15.1 → 2.15.4

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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/.vscode/settings.json +1 -2
  3. data/CHANGELOG.md +68 -20
  4. data/Gemfile.lock +1 -1
  5. data/Rakefile +21 -0
  6. data/ext/javy/hashes/javy-arm-macos-v0.3.0.gz.sha256 +1 -0
  7. data/ext/javy/hashes/javy-x86_64-linux-v0.3.0.gz.sha256 +1 -0
  8. data/ext/javy/hashes/javy-x86_64-macos-v0.3.0.gz.sha256 +1 -0
  9. data/ext/javy/hashes/javy-x86_64-windows-v0.3.0.gz.sha256 +1 -0
  10. data/ext/javy/version +1 -1
  11. data/ext/shopify-extensions/version +1 -1
  12. data/lib/project_types/extension/cli.rb +4 -0
  13. data/lib/project_types/extension/commands/check.rb +6 -1
  14. data/lib/project_types/extension/forms/questions/ask_template.rb +1 -2
  15. data/lib/project_types/extension/messages/messages.rb +1 -3
  16. data/lib/project_types/extension/models/development_server_requirements.rb +1 -0
  17. data/lib/project_types/extension/models/specification_handlers/beacon_extension.rb +57 -0
  18. data/lib/project_types/extension/models/specification_handlers/beacon_extension_utils/script_config.rb +33 -0
  19. data/lib/project_types/extension/models/specification_handlers/beacon_extension_utils/script_config_repository.rb +75 -0
  20. data/lib/project_types/extension/models/specification_handlers/checkout_ui_extension.rb +16 -1
  21. data/lib/project_types/extension/models/specification_handlers/theme_app_extension.rb +4 -1
  22. data/lib/project_types/extension/tasks/configure_options.rb +2 -1
  23. data/lib/project_types/extension/tasks/convert_server_config.rb +13 -2
  24. data/lib/project_types/extension/tasks/merge_server_config.rb +5 -2
  25. data/lib/project_types/script/cli.rb +1 -0
  26. data/lib/project_types/script/layers/application/create_script.rb +14 -6
  27. data/lib/project_types/script/layers/infrastructure/errors.rb +17 -0
  28. data/lib/project_types/script/layers/infrastructure/languages/project_creator.rb +6 -21
  29. data/lib/project_types/script/layers/infrastructure/script_service.rb +2 -0
  30. data/lib/project_types/script/layers/infrastructure/sparse_checkout_details.rb +35 -0
  31. data/lib/project_types/script/messages/messages.rb +3 -0
  32. data/lib/project_types/script/ui/error_handler.rb +11 -0
  33. data/lib/project_types/theme/cli.rb +1 -0
  34. data/lib/project_types/theme/commands/check.rb +4 -1
  35. data/lib/project_types/theme/commands/open.rb +2 -2
  36. data/lib/project_types/theme/commands/push.rb +1 -3
  37. data/lib/project_types/theme/commands/serve.rb +1 -0
  38. data/lib/project_types/theme/commands/share.rb +56 -0
  39. data/lib/project_types/theme/messages/messages.rb +64 -11
  40. data/lib/shopify_cli/changelog.rb +97 -25
  41. data/lib/shopify_cli/command_options/command_serve_options.rb +10 -0
  42. data/lib/shopify_cli/commands/app/serve.rb +7 -7
  43. data/lib/shopify_cli/commands/login.rb +5 -2
  44. data/lib/shopify_cli/context.rb +13 -0
  45. data/lib/shopify_cli/git.rb +36 -0
  46. data/lib/shopify_cli/identity_auth.rb +24 -4
  47. data/lib/shopify_cli/messages/messages.rb +22 -11
  48. data/lib/shopify_cli/release.rb +120 -20
  49. data/lib/shopify_cli/services/app/create/rails_service.rb +9 -1
  50. data/lib/shopify_cli/services/app/serve/node_service.rb +2 -25
  51. data/lib/shopify_cli/services/app/serve/php_service.rb +2 -25
  52. data/lib/shopify_cli/services/app/serve/rails_service.rb +8 -28
  53. data/lib/shopify_cli/services/app/serve/serve_service.rb +57 -0
  54. data/lib/shopify_cli/services.rb +1 -0
  55. data/lib/shopify_cli/tasks/update_dashboard_urls.rb +7 -9
  56. data/lib/shopify_cli/theme/dev_server/hot-reload.js +40 -13
  57. data/lib/shopify_cli/theme/dev_server/hot_reload/remote_file_reloader.rb +1 -1
  58. data/lib/shopify_cli/theme/dev_server/hot_reload/sections_index.rb +51 -0
  59. data/lib/shopify_cli/theme/dev_server/hot_reload.rb +6 -1
  60. data/lib/shopify_cli/theme/dev_server/local_assets.rb +1 -1
  61. data/lib/shopify_cli/theme/dev_server/remote_watcher/json_files_update_job.rb +35 -0
  62. data/lib/shopify_cli/theme/dev_server/remote_watcher.rb +44 -0
  63. data/lib/shopify_cli/theme/dev_server/watcher.rb +2 -8
  64. data/lib/shopify_cli/theme/dev_server.rb +18 -5
  65. data/lib/shopify_cli/theme/file.rb +15 -4
  66. data/lib/shopify_cli/theme/syncer/checksums.rb +60 -0
  67. data/lib/shopify_cli/theme/syncer/forms/apply_to_all.rb +39 -0
  68. data/lib/shopify_cli/theme/syncer/forms/apply_to_all_form.rb +35 -0
  69. data/lib/shopify_cli/theme/syncer/forms/base_strategy_form.rb +62 -0
  70. data/lib/shopify_cli/theme/syncer/forms/select_delete_strategy.rb +27 -0
  71. data/lib/shopify_cli/theme/syncer/forms/select_update_strategy.rb +28 -0
  72. data/lib/shopify_cli/theme/syncer/ignore_helper.rb +33 -0
  73. data/lib/shopify_cli/theme/syncer/json_delete_handler.rb +51 -0
  74. data/lib/shopify_cli/theme/syncer/json_update_handler.rb +82 -0
  75. data/lib/shopify_cli/theme/syncer/merger.rb +53 -0
  76. data/lib/shopify_cli/theme/syncer/operation.rb +1 -1
  77. data/lib/shopify_cli/theme/syncer.rb +79 -63
  78. data/lib/shopify_cli/theme/theme.rb +21 -7
  79. data/lib/shopify_cli/theme/theme_admin_api.rb +23 -8
  80. data/lib/shopify_cli/thread_pool/job.rb +10 -2
  81. data/lib/shopify_cli/thread_pool.rb +15 -3
  82. data/lib/shopify_cli/tunnel.rb +3 -13
  83. data/lib/shopify_cli/version.rb +1 -1
  84. data/vendor/deps/cli-ui/lib/cli/ui/os.rb +8 -0
  85. metadata +25 -2
@@ -8,12 +8,9 @@ module ShopifyCLI
8
8
 
9
9
  recommend_default_ruby_range
10
10
 
11
- options do |parser, flags|
12
- parser.on("--host=HOST") do |h|
13
- flags[:host] = h.gsub('"', "")
14
- end
15
- parser.on("--port=PORT") { |port| flags[:port] = port }
16
- end
11
+ parse_host_option
12
+ parse_port_option
13
+ parse_no_update_option
17
14
 
18
15
  def call(*)
19
16
  case detect_app
@@ -21,18 +18,21 @@ module ShopifyCLI
21
18
  Services::App::Serve::RailsService.call(
22
19
  host: host,
23
20
  port: port,
21
+ no_update: no_update,
24
22
  context: @ctx
25
23
  )
26
24
  when :node
27
25
  Services::App::Serve::NodeService.call(
28
26
  host: host,
29
27
  port: port,
28
+ no_update: no_update,
30
29
  context: @ctx
31
30
  )
32
31
  when :php
33
32
  Services::App::Serve::PHPService.call(
34
33
  host: host,
35
34
  port: port,
35
+ no_update: no_update,
36
36
  context: @ctx
37
37
  )
38
38
  end
@@ -43,7 +43,7 @@ module ShopifyCLI
43
43
  end
44
44
 
45
45
  def self.extended_help
46
- ShopifyCLI::Context.message("app.core.serve.extended_help")
46
+ ShopifyCLI::Context.message("core.app.serve.extended_help")
47
47
  end
48
48
  end
49
49
  end
@@ -30,7 +30,7 @@ module ShopifyCLI
30
30
  if @ctx.ci? && (password = options.flags[:password] || @ctx.getenv("SHOPIFY_PASSWORD"))
31
31
  ShopifyCLI::DB.set(shopify_exchange_token: password)
32
32
  else
33
- IdentityAuth.new(ctx: @ctx).authenticate
33
+ IdentityAuth.new(ctx: @ctx).authenticate(spinner: true)
34
34
  org = select_organization
35
35
  ShopifyCLI::DB.set(organization_id: org["id"].to_i) unless org.nil?
36
36
  Whoami.call([], "whoami")
@@ -75,7 +75,10 @@ module ShopifyCLI
75
75
  private
76
76
 
77
77
  def select_organization
78
- organizations = ShopifyCLI::PartnersAPI::Organizations.fetch_all(@ctx)
78
+ organizations = []
79
+ CLI::UI::Spinner.spin(@ctx.message("core.login.spinner.loading_organizations")) do
80
+ organizations = ShopifyCLI::PartnersAPI::Organizations.fetch_all(@ctx)
81
+ end
79
82
 
80
83
  if organizations.count == 0
81
84
  nil
@@ -4,6 +4,7 @@ require "fileutils"
4
4
  require "rbconfig"
5
5
  require "net/http"
6
6
  require "json"
7
+ require "bundler"
7
8
 
8
9
  module ShopifyCLI
9
10
  ##
@@ -642,6 +643,18 @@ module ShopifyCLI
642
643
  end
643
644
  end
644
645
 
646
+ # Uses bundle to grab the version of a gem
647
+ #
648
+ # #### Parameters
649
+ # - gem: the name of the gem to check
650
+ #
651
+ # #### Returns
652
+ # - version: a Semantic::Version object with the gem version
653
+ def ruby_gem_version(gem)
654
+ version = Bundler.load.specs.find { |s| s.name == gem }.version
655
+ ::Semantic::Version.new(version.to_s)
656
+ end
657
+
645
658
  private
646
659
 
647
660
  def ctx_path(fname)
@@ -102,6 +102,42 @@ module ShopifyCLI
102
102
  branches
103
103
  end
104
104
 
105
+ ##
106
+ # Run git three-way file merge (it doesn't require an initialized git repository)
107
+ #
108
+ # #### Parameters
109
+ #
110
+ # * `current_file - string path of the current file
111
+ # * `base_file` - string path of the base file
112
+ # * `other_file` - string path of the other file
113
+ # * `opts` - list of "git merge-file" options. Valid values:
114
+ # - "-q" - do not warn about conflicts
115
+ # - "--diff3" - show conflicts
116
+ # - "--ours" - resolve conflicts favoring lines from `current_file`
117
+ # - "--theirs" - resolve conflicts favoring lines from `other_file`
118
+ # - "--union" - resolve conflicts favoring lines from both files
119
+ # - "-p" - send results to standard output instead of
120
+ # overwriting the `current_file`
121
+ # * `ctx` - the current running context of your command, defaults to a new context
122
+ #
123
+ # #### Returns
124
+ #
125
+ # * standard output from git
126
+ #
127
+ # #### Example
128
+ #
129
+ # output = ShopifyCLI::Git.merge_file(current_file, base_file, other_file, opts, ctx: ctx)
130
+ #
131
+ def merge_file(current_file, base_file, other_file, opts = [], ctx: Context.new)
132
+ output, status = ctx.capture2e("git", "merge-file", current_file, base_file, other_file, *opts)
133
+
134
+ unless status.success?
135
+ ctx.abort(ctx.message("core.git.error.merge_failed"))
136
+ end
137
+
138
+ output
139
+ end
140
+
105
141
  ##
106
142
  # will initialize a new repo in the current directory. This will output
107
143
  # if it was successful or not.
@@ -56,8 +56,10 @@ module ShopifyCLI
56
56
 
57
57
  attr_accessor :response_query
58
58
 
59
- def authenticate
60
- return if refresh_exchange_tokens || refresh_access_tokens
59
+ def authenticate(spinner: false)
60
+ return if with_spinner(spinner, ctx.message("core.login.spinner.initiating")) do
61
+ attempt_reauthenticate
62
+ end
61
63
 
62
64
  initiate_authentication
63
65
 
@@ -66,7 +68,21 @@ module ShopifyCLI
66
68
  rescue IdentityAuth::Timeout => e
67
69
  ctx.abort(e.message)
68
70
  end
69
- request_exchange_tokens
71
+ with_spinner(spinner, ctx.message("core.login.spinner.finalizing")) do
72
+ request_exchange_tokens
73
+ end
74
+ end
75
+
76
+ def with_spinner(spinner, message, &block)
77
+ result = nil
78
+ if spinner
79
+ CLI::UI::Spinner.spin(message) do
80
+ result = block.call
81
+ end
82
+ else
83
+ result = block.call
84
+ end
85
+ result
70
86
  end
71
87
 
72
88
  def fetch_or_auth_partners_token
@@ -100,10 +116,14 @@ module ShopifyCLI
100
116
  end
101
117
 
102
118
  def reauthenticate
103
- return if refresh_exchange_tokens || refresh_access_tokens
119
+ return if attempt_reauthenticate
104
120
  ctx.abort(ctx.message("core.identity_auth.error.reauthenticate", ShopifyCLI::TOOL_NAME))
105
121
  end
106
122
 
123
+ def attempt_reauthenticate
124
+ refresh_exchange_tokens || refresh_access_tokens
125
+ end
126
+
107
127
  def code_challenge
108
128
  @code_challenge ||= Base64.urlsafe_encode64(
109
129
  OpenSSL::Digest::SHA256.digest(code_verifier),
@@ -18,6 +18,7 @@ module ShopifyCLI
18
18
  missing_node: "Node.js is required to continue. Install Node.js here: https://nodejs.org/en/download.",
19
19
  missing_npm: "npm is required to continue. Install npm here: https://www.npmjs.com/get-npm.",
20
20
  missing_ruby: "Ruby is required to continue. Install Ruby here: https://www.ruby-lang.org/en/downloads.",
21
+ bundle_info_failure: "Error getting version for %s gem",
21
22
  option_parser: {
22
23
  invalid_option: "The option {{command:%s}} is not supported.",
23
24
  invalid_option_store_equals: <<~MESSAGE,
@@ -263,6 +264,7 @@ module ShopifyCLI
263
264
  {{bold:Options:}}
264
265
  {{cyan:--host=HOST}}: Bypass running tunnel and use custom host. HOST must be HTTPS url.
265
266
  {{cyan:--port=PORT}}: Use custom port.
267
+ {{cyan:--no-update}}: Skips the dashboard URL update step
266
268
  HELP
267
269
  open_info: <<~MESSAGE,
268
270
  {{*}} To install and start using your app, open this URL in your browser:
@@ -283,6 +285,13 @@ module ShopifyCLI
283
285
  },
284
286
  extension: {
285
287
  push: {
288
+ beacon_extension: {
289
+ error: {
290
+ file_read_error: "There was a problem reading %s",
291
+ missing_config_key_error: "Configuration is missing key: %s",
292
+ invalid_config_value_error: "Configuration value is invalid: %s",
293
+ },
294
+ },
286
295
  checkout_ui_extension: {
287
296
  localization: {
288
297
  error: {
@@ -294,6 +303,7 @@ module ShopifyCLI
294
303
  invalid_file_extension: "Invalid locale filename: `%s`; only .json files are allowed.",
295
304
  invalid_locale_code: "Invalid locale filename: `%s`; locale code should be 2 or 3 letters,"\
296
305
  " optionally followed by a two-letter region code, e.g. `fr-CA`.",
306
+ invalid_file_encoding: "Invalid file encoding for `%s`; file encoding should be UTF-8.",
297
307
  single_default_locale: "There must be one and only one locale identified as the default locale,"\
298
308
  " e.g. `en.default.json`",
299
309
  },
@@ -388,6 +398,7 @@ module ShopifyCLI
388
398
  sparse_checkout_not_set: "Sparse checkout set command failed.",
389
399
  pull_failed: "Pull failed.",
390
400
  pull_failed_bad_branch: "Pull failed. Branch %s cannot be found. Check the branch name and try again.",
401
+ merge_failed: "The file %s merge failed.",
391
402
  },
392
403
 
393
404
  cloning: "Cloning %s into %s…",
@@ -438,7 +449,7 @@ module ShopifyCLI
438
449
  login: {
439
450
  help: <<~HELP,
440
451
  Log in to the Shopify CLI by authenticating with a store or partner organization
441
- Usage: {{command:%s login [--store=STORE]}}
452
+ Usage: {{command:%s login [--store STORE]}}
442
453
  HELP
443
454
  invalid_shop: <<~MESSAGE,
444
455
  Invalid store provided (%s). Please provide the store in the following format: my-store.myshopify.com
@@ -446,6 +457,11 @@ module ShopifyCLI
446
457
  shop_prompt: <<~PROMPT,
447
458
  What store are you connecting to? (e.g. my-store.myshopify.com; do {{bold:NOT}} include protocol part, e.g., https://)
448
459
  PROMPT
460
+ spinner: {
461
+ initiating: "Initiating authentication",
462
+ finalizing: "Finalizing authentication",
463
+ loading_organizations: "Loading available partner organizations",
464
+ },
449
465
  },
450
466
 
451
467
  logout: {
@@ -460,7 +476,7 @@ module ShopifyCLI
460
476
  switch: {
461
477
  help: <<~HELP,
462
478
  Switch between development stores in your partner organization
463
- Usage: {{command:%s switch [--store=STORE]}}
479
+ Usage: {{command:%s switch [--store STORE]}}
464
480
  HELP
465
481
  disabled_as_shopify_org: "Can't switch development stores logged in as {{green:Shopify partners org}}",
466
482
  success: "Switched development store to {{green:%s}}",
@@ -573,7 +589,7 @@ module ShopifyCLI
573
589
  HELP
574
590
 
575
591
  error: {
576
- no_shop: "No store found. Please run {{command:%s login --store=STORE}} to login to a specific store",
592
+ no_shop: "No store found. Please run {{command:%s login --store STORE}} to login to a specific store",
577
593
  },
578
594
 
579
595
  customer: {
@@ -713,7 +729,6 @@ module ShopifyCLI
713
729
  updated: "{{v}} Whitelist URLS updated in Partners Dashboard}}",
714
730
  update_error:
715
731
  "{{x}} error: For authentication issues, run {{command:%s logout}} to clear invalid credentials",
716
- update_prompt: "Do you want to update your application url?",
717
732
  },
718
733
  select_org_and_shop: {
719
734
  authentication_issue: "For authentication issues, run {{command:%s logout}} to clear invalid credentials",
@@ -745,16 +760,12 @@ module ShopifyCLI
745
760
  " package manager for your system.",
746
761
  ngrok: "Something went wrong with ngrok installation,"\
747
762
  "please make sure %s exists within %s before trying again",
763
+ signup_required: "A free ngrok account is required: {{underline:https://ngrok.com/signup}}. After you "\
764
+ "signup, install your personal authorization token using {{command:%s app tunnel auth <token>}}.",
748
765
  },
749
766
  installing: "Installing ngrok…",
750
767
  not_running: "{{green:x}} ngrok tunnel not running",
751
768
  prereq_command_location: "%s @ %s",
752
- signup_suggestion: <<~MESSAGE,
753
- {{*}} To avoid tunnels that timeout, it is recommended to signup for a free ngrok
754
- account at {{underline:https://ngrok.com/signup}}. After you signup, install your
755
- personalized authorization token using {{command:%s app tunnel auth <token>}}.
756
- MESSAGE
757
- start: "{{v}} ngrok tunnel running at {{underline:%s}}",
758
769
  start_with_account: "{{v}} ngrok tunnel running at {{underline:%s}}, with account %s",
759
770
  stopped: "{{green:x}} ngrok tunnel stopped",
760
771
  timed_out: "{{x}} ngrok tunnel has timed out, restarting…",
@@ -809,7 +820,7 @@ module ShopifyCLI
809
820
  not_logged_in: <<~MESSAGE,
810
821
  It doesn't appear that you're logged in. You must log into a partner organization or a store staff account.
811
822
 
812
- If trying to log into a store staff account, please use {{command:%s login --store=STORE}} to log in.
823
+ If trying to log into a store staff account, please use {{command:%s login --store STORE}} to log in.
813
824
  MESSAGE
814
825
  logged_in_shop_only: <<~MESSAGE,
815
826
  Logged into store {{green:%s}} as staff (no partner organizations available for this login)
@@ -1,3 +1,5 @@
1
+ require "net/http"
2
+ require "fileutils"
1
3
  require "shopify_cli/sed"
2
4
  require "shopify_cli/changelog"
3
5
  require "octokit"
@@ -15,20 +17,34 @@ module ShopifyCLI
15
17
  create_release_branch
16
18
  update_changelog
17
19
  update_versions_in_files
18
- commit
20
+ commit_packaging
19
21
  pr = create_pr
20
22
  system("open #{pr["html_url"]}")
21
23
  end
22
24
 
25
+ def package!
26
+ ensure_updated_main
27
+ ensure_correct_gem_version
28
+ Rake::Task["package"].invoke
29
+ update_homebrew
30
+ create_github_release
31
+ end
32
+
23
33
  private
24
34
 
25
35
  attr_reader :new_version, :changelog, :github
26
36
 
27
37
  def ensure_updated_main
28
- current_branch = %x(git branch --show-current)
29
- unless current_branch == "main"
30
- raise "Must be on the main branch to package a release!"
38
+ # We can't be sure what is the correct action to take if changes have been
39
+ # made but not committed. Ensure the user handles the situation before
40
+ # moving on.
41
+ unless %x(git status --porcelain).empty?
42
+ raise <<~MESSAGE
43
+ Uncommitted changes have been made to the repository.
44
+ Please make sure `git status` does not show any changes before continuing.
45
+ MESSAGE
31
46
  end
47
+ system_or_fail("git checkout main", "check out main branch")
32
48
  unless system("git pull")
33
49
  raise "git pull failed, cannot be sure there aren't new commits!"
34
50
  end
@@ -36,13 +52,11 @@ module ShopifyCLI
36
52
 
37
53
  def create_release_branch
38
54
  puts "Checking out release branch"
39
- unless system("git checkout -b #{release_branch_name}")
40
- puts "Cannot check out release branch!"
41
- end
55
+ system_or_fail("git checkout -b #{release_branch_name}", "check out release branch")
42
56
  end
43
57
 
44
58
  def update_changelog
45
- if release_notes.empty?
59
+ if release_notes("Unreleased").empty?
46
60
  puts "No unreleased CHANGELOG updates found!"
47
61
  else
48
62
  puts "Updating CHANGELOG"
@@ -63,32 +77,118 @@ module ShopifyCLI
63
77
  )
64
78
  end
65
79
 
66
- def commit
80
+ def commit_packaging
67
81
  puts "Committing"
68
- unless system("git commit -am 'Packaging for release v#{new_version}'")
69
- puts "Commit failed!"
70
- end
71
- unless system("git push -u origin #{release_branch_name}")
72
- puts "Failed to push branch!"
73
- end
82
+ system_or_fail("git commit -am 'Packaging for release v#{new_version}'", "commit")
83
+ system_or_fail("git push -u origin #{release_branch_name}", "push branch")
74
84
  end
75
85
 
76
86
  def create_pr
87
+ repo = "Shopify/shopify-cli"
77
88
  github.create_pull_request(
78
- "Shopify/shopify-cli",
89
+ repo,
79
90
  "main",
80
91
  release_branch_name,
81
92
  "Packaging for release v#{new_version}",
82
- release_notes
83
- ).tap { |results| puts "Created PR ##{results["number"]}" }
93
+ release_notes(new_version)
94
+ ).tap { |results| puts "Created #{repo} PR ##{results["number"]}" }
95
+ end
96
+
97
+ def ensure_correct_gem_version
98
+ response = Net::HTTP.get(URI("https://rubygems.org/api/v1/versions/shopify-cli/latest.json"))
99
+ latest_version = JSON.parse(response)["version"]
100
+ unless latest_version == new_version
101
+ raise "Attempted to update to #{new_version}, but latest on RubyGems is #{latest_version}"
102
+ end
103
+ end
104
+
105
+ def update_homebrew
106
+ ensure_updated_homebrew_repo
107
+ update_homebrew_repo
108
+ pr = create_homebrew_pr
109
+ system("open #{pr["html_url"]}")
110
+ end
111
+
112
+ def ensure_updated_homebrew_repo
113
+ unless File.exist?(homebrew_path)
114
+ system_or_fail("/opt/dev/bin/dev clone homebrew-shopify", "clone homebrew-shopify repo")
115
+ end
116
+
117
+ Dir.chdir(homebrew_path) do
118
+ system_or_fail("git checkout master && git pull", "pull latest homebrew-shopify")
119
+ system_or_fail("git checkout -b #{homebrew_release_branch}", "check out homebrew branch")
120
+ end
121
+ end
122
+
123
+ def update_homebrew_repo
124
+ source_file = File.join(package_dir, "shopify-cli.rb")
125
+ FileUtils.copy(source_file, homebrew_path)
126
+ Dir.chdir(homebrew_path) do
127
+ system_or_fail("git commit -am '#{homebrew_update_message}'", "commit homebrew update")
128
+ system_or_fail("git push -u origin #{homebrew_release_branch}", "push homebrew branch")
129
+ end
130
+ end
131
+
132
+ def create_homebrew_pr
133
+ repo = "Shopify/homebrew-shopify"
134
+ github.create_pull_request(
135
+ repo,
136
+ "master",
137
+ homebrew_release_branch,
138
+ homebrew_update_message,
139
+ homebrew_release_notes
140
+ ).tap { |results| puts "Created #{repo} PR ##{results["number"]}" }
141
+ end
142
+
143
+ def create_github_release
144
+ release = github.create_release(
145
+ "Shopify/shopify-cli",
146
+ "v#{new_version}",
147
+ {
148
+ name: "Version #{new_version}",
149
+ body: release_notes(new_version),
150
+ }
151
+ )
152
+ %w(.deb -1.noarch.rpm).each do |suffix|
153
+ github.upload_asset(
154
+ release["url"],
155
+ File.join(package_dir, "shopify-cli-#{new_version}#{suffix}")
156
+ )
157
+ end
158
+ system("open #{release["html_url"]}")
159
+ end
160
+
161
+ def homebrew_path
162
+ @homebrew_path ||= %x(/opt/dev/bin/dev project-path homebrew-shopify).chomp
163
+ end
164
+
165
+ def homebrew_update_message
166
+ @homebrew_update_message ||= "Update Shopify CLI to #{new_version}"
167
+ end
168
+
169
+ def package_dir
170
+ @package_dir ||= File.join(ShopifyCLI::ROOT, "packaging", "builds", new_version)
171
+ end
172
+
173
+ def homebrew_release_branch
174
+ "release_#{new_version.split(".").join("_")}_of_shopify-cli"
175
+ end
176
+
177
+ def homebrew_release_notes
178
+ "I'm releasing a new version of the Shopify CLI, " \
179
+ "[#{new_version}](https://github.com/Shopify/shopify-cli/releases/tag/v#{new_version})"
84
180
  end
85
181
 
86
182
  def release_branch_name
87
183
  @release_branch_name ||= "release_#{new_version.split(".").join("_")}"
88
184
  end
89
185
 
90
- def release_notes
91
- @release_notes ||= changelog.release_notes("Unreleased")
186
+ def release_notes(version)
187
+ changelog.release_notes(version)
188
+ end
189
+
190
+ def system_or_fail(command, action)
191
+ raise "Failed to #{action}!" unless system(command)
92
192
  end
93
193
  end
94
194
  end
@@ -109,7 +109,9 @@ module ShopifyCLI
109
109
 
110
110
  def check_ruby
111
111
  ruby_version = Environment.ruby_version(context: context)
112
- return if ruby_version.satisfies?("~>2.5") || ruby_version.satisfies?("~>3.1.0")
112
+ return if ruby_version.satisfies?("~>2.5") ||
113
+ ruby_version.satisfies?("~>3.0.0") ||
114
+ ruby_version.satisfies?("~>3.1.0")
113
115
  context.abort(context.message("core.app.create.rails.error.invalid_ruby_version"))
114
116
  end
115
117
 
@@ -205,6 +207,12 @@ module ShopifyCLI
205
207
  end
206
208
 
207
209
  def set_custom_ua
210
+ requires_ua_file = Dir.chdir(context.root) do
211
+ context.ruby_gem_version("shopify_app") < ::Semantic::Version.new("19.0.0")
212
+ end
213
+
214
+ return unless requires_ua_file
215
+
208
216
  ua_path = File.join("config", "initializers", "user_agent.rb")
209
217
  context.write(ua_path, USER_AGENT_CODE)
210
218
  end
@@ -2,32 +2,9 @@ module ShopifyCLI
2
2
  module Services
3
3
  module App
4
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
-
5
+ class NodeService < ServeService
15
6
  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}/auth?shop=#{project.env.shop}"
29
- context.puts("\n" + context.message("core.app.serve.open_info", project_url) + "\n")
30
- end
7
+ generate_url
31
8
 
32
9
  CLI::UI::Frame.open(context.message("core.app.serve.running_server")) do
33
10
  env = project.env.to_h
@@ -2,32 +2,9 @@ module ShopifyCLI
2
2
  module Services
3
3
  module App
4
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
-
5
+ class PHPService < ServeService
15
6
  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
7
+ generate_url
31
8
 
32
9
  CLI::UI::Frame.open(context.message("core.app.serve.running_server")) do
33
10
  if ShopifyCLI::ProcessSupervision.running?(:npm_watch)
@@ -2,38 +2,18 @@ module ShopifyCLI
2
2
  module Services
3
3
  module App
4
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
-
5
+ class RailsService < ServeService
15
6
  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/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
7
+ generate_url
31
8
 
32
9
  CLI::UI::Frame.open(context.message("core.app.serve.running_server")) do
33
- env = ShopifyCLI::Project.current.env.to_h
34
- env.delete("HOST")
10
+ original_env = JSON.parse(ENV["ORIGINAL_ENV"] || "{}")
11
+ env = original_env.merge(ShopifyCLI::Project.current.env.to_h)
12
+ env.delete("HOST") if context.ruby_gem_version("shopify_app") < ::Semantic::Version.new("19.0.0")
35
13
  env["PORT"] = port.to_s
36
- env["GEM_PATH"] = Rails::Gem.gem_path(context)
14
+ env["GEM_PATH"] =
15
+ [env["GEM_PATH"], Rails::Gem.gem_path(context)].compact
16
+ .join(CLI::UI::OS.current.path_separator)
37
17
  if context.windows?
38
18
  context.system("ruby bin\\rails server", env: env)
39
19
  else