shopify-cli 2.14.0 → 2.15.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/CONTRIBUTING.md +1 -1
- data/.github/workflows/stale.yml +46 -0
- data/CHANGELOG.md +24 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +39 -7
- data/Rakefile +40 -0
- data/ext/shopify-extensions/version +1 -1
- data/lib/project_types/extension/forms/questions/ask_template.rb +5 -8
- data/lib/project_types/extension/messages/messages.rb +11 -1
- data/lib/project_types/extension/models/development_server_requirements.rb +13 -7
- data/lib/project_types/extension/models/server_config/root.rb +2 -0
- data/lib/project_types/extension/models/specification_handlers/checkout_ui_extension.rb +13 -0
- data/lib/project_types/script/config/extension_points.yml +18 -0
- data/lib/project_types/script/layers/infrastructure/errors.rb +17 -0
- data/lib/project_types/script/layers/infrastructure/script_service.rb +2 -0
- data/lib/project_types/script/messages/messages.rb +3 -0
- data/lib/project_types/script/ui/error_handler.rb +11 -0
- data/lib/project_types/theme/commands/pull.rb +2 -2
- data/lib/project_types/theme/commands/push.rb +2 -2
- data/lib/project_types/theme/commands/serve.rb +1 -0
- data/lib/project_types/theme/conversions/base_glob.rb +20 -5
- data/lib/project_types/theme/messages/messages.rb +47 -8
- data/lib/shopify_cli/changelog.rb +76 -0
- data/lib/shopify_cli/command.rb +8 -7
- data/lib/shopify_cli/environment.rb +19 -11
- data/lib/shopify_cli/git.rb +36 -0
- data/lib/shopify_cli/messages/messages.rb +16 -9
- data/lib/shopify_cli/release.rb +194 -0
- data/lib/shopify_cli/sed.rb +19 -0
- data/lib/shopify_cli/services/app/create/node_service.rb +2 -14
- data/lib/shopify_cli/services/app/create/php_service.rb +1 -6
- data/lib/shopify_cli/services/app/create/rails_service.rb +4 -12
- data/lib/shopify_cli/theme/dev_server/hot-reload.js +40 -13
- data/lib/shopify_cli/theme/dev_server/hot_reload/remote_file_reloader.rb +1 -1
- data/lib/shopify_cli/theme/dev_server/hot_reload/sections_index.rb +51 -0
- data/lib/shopify_cli/theme/dev_server/hot_reload.rb +6 -1
- data/lib/shopify_cli/theme/dev_server/local_assets.rb +1 -1
- data/lib/shopify_cli/theme/dev_server/remote_watcher/json_files_update_job.rb +34 -0
- data/lib/shopify_cli/theme/dev_server/remote_watcher.rb +44 -0
- data/lib/shopify_cli/theme/dev_server/watcher.rb +1 -1
- data/lib/shopify_cli/theme/dev_server.rb +15 -3
- data/lib/shopify_cli/theme/file.rb +15 -4
- data/lib/shopify_cli/theme/syncer/checksums.rb +60 -0
- data/lib/shopify_cli/theme/syncer/forms/apply_to_all.rb +39 -0
- data/lib/shopify_cli/theme/syncer/forms/apply_to_all_form.rb +35 -0
- data/lib/shopify_cli/theme/syncer/forms/base_strategy_form.rb +62 -0
- data/lib/shopify_cli/theme/syncer/forms/select_delete_strategy.rb +27 -0
- data/lib/shopify_cli/theme/syncer/forms/select_update_strategy.rb +28 -0
- data/lib/shopify_cli/theme/syncer/ignore_helper.rb +33 -0
- data/lib/shopify_cli/theme/syncer/json_delete_handler.rb +51 -0
- data/lib/shopify_cli/theme/syncer/json_update_handler.rb +82 -0
- data/lib/shopify_cli/theme/syncer/merger.rb +53 -0
- data/lib/shopify_cli/theme/syncer/operation.rb +1 -1
- data/lib/shopify_cli/theme/syncer.rb +79 -63
- data/lib/shopify_cli/theme/theme.rb +12 -4
- data/lib/shopify_cli/theme/theme_admin_api.rb +24 -23
- data/lib/shopify_cli/thread_pool/job.rb +10 -2
- data/lib/shopify_cli/thread_pool.rb +15 -3
- data/lib/shopify_cli/tunnel.rb +9 -0
- data/lib/shopify_cli/version.rb +1 -1
- data/shopify-cli.gemspec +3 -1
- metadata +21 -4
- data/lib/project_types/rails/ruby.rb +0 -17
@@ -0,0 +1,76 @@
|
|
1
|
+
require "shopify_cli/sed"
|
2
|
+
|
3
|
+
module ShopifyCLI
|
4
|
+
class Changelog
|
5
|
+
CHANGELOG_FILE = File.join(ShopifyCLI::ROOT, "CHANGELOG.md")
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
load(File.read(CHANGELOG_FILE))
|
9
|
+
end
|
10
|
+
|
11
|
+
def update_version!(new_version)
|
12
|
+
Sed.new.replace_inline(
|
13
|
+
CHANGELOG_FILE,
|
14
|
+
"## \\[Unreleased\\]",
|
15
|
+
"## [Unreleased]\\n\\n## Version #{new_version}"
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
def release_notes(version)
|
20
|
+
changes[version].map do |change_category, changes|
|
21
|
+
<<~CHANGES
|
22
|
+
### #{change_category}
|
23
|
+
#{changes.map { |change| entry(**change) }.join("\n")}
|
24
|
+
CHANGES
|
25
|
+
end.join("\n")
|
26
|
+
end
|
27
|
+
|
28
|
+
def entry(pr_id:, desc:)
|
29
|
+
"* [##{pr_id}](https://github.com/Shopify/shopify-cli/pull/#{pr_id}): #{desc}"
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def changes
|
35
|
+
@changes ||= Hash.new do |h, k|
|
36
|
+
h[k] = Hash.new do |h2, k2|
|
37
|
+
h2[k2] = []
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def load(log)
|
43
|
+
state = :initial
|
44
|
+
change_category = nil
|
45
|
+
current_version = nil
|
46
|
+
@remainder = ""
|
47
|
+
log.each_line do |line|
|
48
|
+
case state
|
49
|
+
when :initial
|
50
|
+
next unless line.chomp == "\#\# [Unreleased]"
|
51
|
+
state = :unreleased
|
52
|
+
current_version = "Unreleased"
|
53
|
+
when :unreleased, :last_version
|
54
|
+
if /\A\#\#\# (?<category>\w+)/ =~ line
|
55
|
+
change_category = category
|
56
|
+
elsif %r{\A\* \[\#(?<pr_id>\d+)\]\(https://github.com/Shopify/shopify-cli/pull/\d+\): (?<desc>.+)\n} =~ line
|
57
|
+
changes[current_version][change_category] << { pr_id: pr_id, desc: desc }
|
58
|
+
elsif /\A\#\# Version (?<version>\d+\.\d+\.\d+)/ =~ line
|
59
|
+
current_version = version
|
60
|
+
state =
|
61
|
+
case state
|
62
|
+
when :unreleased
|
63
|
+
:last_version
|
64
|
+
else
|
65
|
+
:finished
|
66
|
+
end
|
67
|
+
elsif !line.match?(/\s*\n/)
|
68
|
+
raise "Unrecognized line: #{line.inspect}"
|
69
|
+
end
|
70
|
+
when :finished
|
71
|
+
@remainder << line
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/lib/shopify_cli/command.rb
CHANGED
@@ -36,6 +36,13 @@ module ShopifyCLI
|
|
36
36
|
end
|
37
37
|
rescue OptionParser::InvalidOption => error
|
38
38
|
arg = error.args.first
|
39
|
+
store_name = arg.match(/\A--(?<store_name>.*\.myshopify\.com)\z/)&.[](:store_name)
|
40
|
+
if store_name && !arg.match?(/\A--(store|shop)=/)
|
41
|
+
# Sometimes it may look like --invalidoption=https://storename.myshopify.com
|
42
|
+
store_name = store_name.sub(%r{\A(.*=)?(https?://)?}, "")
|
43
|
+
raise ShopifyCLI::Abort,
|
44
|
+
@ctx.message("core.errors.option_parser.invalid_option_store_equals", arg, store_name)
|
45
|
+
end
|
39
46
|
raise ShopifyCLI::Abort, @ctx.message("core.errors.option_parser.invalid_option", arg)
|
40
47
|
rescue OptionParser::MissingArgument => error
|
41
48
|
arg = error.args.first
|
@@ -102,16 +109,10 @@ module ShopifyCLI
|
|
102
109
|
def check_node_version
|
103
110
|
return unless @compatible_node_range
|
104
111
|
|
105
|
-
context = Context.new
|
106
|
-
if context.which("node").nil?
|
107
|
-
raise ShopifyCLI::Abort, context.message("core.errors.missing_node")
|
108
|
-
end
|
109
|
-
|
110
112
|
check_version(
|
111
113
|
Environment.node_version,
|
112
114
|
range: @compatible_node_range,
|
113
|
-
runtime: "Node"
|
114
|
-
context: context
|
115
|
+
runtime: "Node"
|
115
116
|
)
|
116
117
|
end
|
117
118
|
|
@@ -12,23 +12,31 @@ module ShopifyCLI
|
|
12
12
|
]
|
13
13
|
|
14
14
|
def self.ruby_version(context: Context.new)
|
15
|
-
|
16
|
-
raise ShopifyCLI::Abort,
|
17
|
-
|
18
|
-
::Semantic::Version.new(
|
15
|
+
output, status = context.capture2e("ruby", "--version")
|
16
|
+
raise ShopifyCLI::Abort, context.message("core.errors.missing_ruby") unless status.success?
|
17
|
+
version = output.match(/ruby (\d+\.\d+\.\d+)/)[1]
|
18
|
+
::Semantic::Version.new(version)
|
19
19
|
end
|
20
20
|
|
21
21
|
def self.node_version(context: Context.new)
|
22
|
-
|
23
|
-
raise ShopifyCLI::Abort,
|
24
|
-
|
25
|
-
::Semantic::Version.new(
|
22
|
+
output, status = context.capture2e("node", "--version")
|
23
|
+
raise ShopifyCLI::Abort, context.message("core.errors.missing_node") unless status.success?
|
24
|
+
version = output.match(/v(\d+\.\d+\.\d+)/)[1]
|
25
|
+
::Semantic::Version.new(version)
|
26
26
|
end
|
27
27
|
|
28
28
|
def self.npm_version(context: Context.new)
|
29
|
-
|
30
|
-
raise ShopifyCLI::Abort,
|
31
|
-
|
29
|
+
output, status = context.capture2e("npm", "--version")
|
30
|
+
raise ShopifyCLI::Abort, context.message("core.errors.missing_npm") unless status.success?
|
31
|
+
version = output.match(/(\d+\.\d+\.\d+)/)[1]
|
32
|
+
::Semantic::Version.new(version)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.rails_version(context: Context.new)
|
36
|
+
output, status = context.capture2e("rails", "--version")
|
37
|
+
context.abort(context.message("core.app.create.rails.error.install_failure", "rails")) unless status.success?
|
38
|
+
version = output.match(/Rails (\d+\.\d+\.\d+)/)[1]
|
39
|
+
::Semantic::Version.new(version)
|
32
40
|
end
|
33
41
|
|
34
42
|
def self.interactive=(interactive)
|
data/lib/shopify_cli/git.rb
CHANGED
@@ -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.
|
@@ -15,9 +15,17 @@ module ShopifyCLI
|
|
15
15
|
},
|
16
16
|
core: {
|
17
17
|
errors: {
|
18
|
-
missing_node: "Node is required to continue. Install
|
18
|
+
missing_node: "Node.js is required to continue. Install Node.js here: https://nodejs.org/en/download.",
|
19
|
+
missing_npm: "npm is required to continue. Install npm here: https://www.npmjs.com/get-npm.",
|
20
|
+
missing_ruby: "Ruby is required to continue. Install Ruby here: https://www.ruby-lang.org/en/downloads.",
|
19
21
|
option_parser: {
|
20
22
|
invalid_option: "The option {{command:%s}} is not supported.",
|
23
|
+
invalid_option_store_equals: <<~MESSAGE,
|
24
|
+
The option {{command:%s}} isn't recognized.
|
25
|
+
|
26
|
+
Try this:
|
27
|
+
{{command:--store=%s}}.
|
28
|
+
MESSAGE
|
21
29
|
missing_argument: "The required argument {{command:%s}} is missing.",
|
22
30
|
},
|
23
31
|
},
|
@@ -95,8 +103,6 @@ module ShopifyCLI
|
|
95
103
|
HELP
|
96
104
|
error: {
|
97
105
|
node_required: "node is required to create an app project. Download at https://nodejs.org/en/download.",
|
98
|
-
node_version_failure: "Failed to get the current node version. Please make sure it is installed as " \
|
99
|
-
"per the instructions at https://nodejs.org/en.",
|
100
106
|
npm_required: "npm is required to create an app project. Download at https://www.npmjs.com/get-npm.",
|
101
107
|
npm_version_failure: "Failed to get the current npm version. Please make sure it is installed as per " \
|
102
108
|
"the instructions at https://www.npmjs.com/get-npm.",
|
@@ -131,8 +137,6 @@ module ShopifyCLI
|
|
131
137
|
{{underline:https://getcomposer.org/download/}}
|
132
138
|
COMPOSER
|
133
139
|
npm_required: "npm is required to create an app project. Download at https://www.npmjs.com/get-npm.",
|
134
|
-
npm_version_failure: "Failed to get the current npm version. Please make sure it is installed as per " \
|
135
|
-
"the instructions at https://www.npmjs.com/get-npm.",
|
136
140
|
app_setup: "Failed to set up the app",
|
137
141
|
},
|
138
142
|
|
@@ -283,6 +287,8 @@ module ShopifyCLI
|
|
283
287
|
localization: {
|
284
288
|
error: {
|
285
289
|
bundle_too_large: "Total size of all locale files must be less than %s.",
|
290
|
+
duplicate_locale_code: "Duplicate locale found: `%s`; locale codes"\
|
291
|
+
" should be unique and are case insensitive.",
|
286
292
|
file_empty: "Locale file `%s` is empty.",
|
287
293
|
file_too_large: "Locale file `%s` too large; size must be less than %s.",
|
288
294
|
invalid_file_extension: "Invalid locale filename: `%s`; only .json files are allowed.",
|
@@ -382,6 +388,7 @@ module ShopifyCLI
|
|
382
388
|
sparse_checkout_not_set: "Sparse checkout set command failed.",
|
383
389
|
pull_failed: "Pull failed.",
|
384
390
|
pull_failed_bad_branch: "Pull failed. Branch %s cannot be found. Check the branch name and try again.",
|
391
|
+
merge_failed: "The file %s merge failed.",
|
385
392
|
},
|
386
393
|
|
387
394
|
cloning: "Cloning %s into %s…",
|
@@ -432,7 +439,7 @@ module ShopifyCLI
|
|
432
439
|
login: {
|
433
440
|
help: <<~HELP,
|
434
441
|
Log in to the Shopify CLI by authenticating with a store or partner organization
|
435
|
-
Usage: {{command:%s login [--store
|
442
|
+
Usage: {{command:%s login [--store STORE]}}
|
436
443
|
HELP
|
437
444
|
invalid_shop: <<~MESSAGE,
|
438
445
|
Invalid store provided (%s). Please provide the store in the following format: my-store.myshopify.com
|
@@ -454,7 +461,7 @@ module ShopifyCLI
|
|
454
461
|
switch: {
|
455
462
|
help: <<~HELP,
|
456
463
|
Switch between development stores in your partner organization
|
457
|
-
Usage: {{command:%s switch [--store
|
464
|
+
Usage: {{command:%s switch [--store STORE]}}
|
458
465
|
HELP
|
459
466
|
disabled_as_shopify_org: "Can't switch development stores logged in as {{green:Shopify partners org}}",
|
460
467
|
success: "Switched development store to {{green:%s}}",
|
@@ -567,7 +574,7 @@ module ShopifyCLI
|
|
567
574
|
HELP
|
568
575
|
|
569
576
|
error: {
|
570
|
-
no_shop: "No store found. Please run {{command:%s login --store
|
577
|
+
no_shop: "No store found. Please run {{command:%s login --store STORE}} to login to a specific store",
|
571
578
|
},
|
572
579
|
|
573
580
|
customer: {
|
@@ -803,7 +810,7 @@ module ShopifyCLI
|
|
803
810
|
not_logged_in: <<~MESSAGE,
|
804
811
|
It doesn't appear that you're logged in. You must log into a partner organization or a store staff account.
|
805
812
|
|
806
|
-
If trying to log into a store staff account, please use {{command:%s login --store
|
813
|
+
If trying to log into a store staff account, please use {{command:%s login --store STORE}} to log in.
|
807
814
|
MESSAGE
|
808
815
|
logged_in_shop_only: <<~MESSAGE,
|
809
816
|
Logged into store {{green:%s}} as staff (no partner organizations available for this login)
|
@@ -0,0 +1,194 @@
|
|
1
|
+
require "net/http"
|
2
|
+
require "fileutils"
|
3
|
+
require "shopify_cli/sed"
|
4
|
+
require "shopify_cli/changelog"
|
5
|
+
require "octokit"
|
6
|
+
|
7
|
+
module ShopifyCLI
|
8
|
+
class Release
|
9
|
+
def initialize(new_version, github_access_token)
|
10
|
+
@new_version = new_version
|
11
|
+
@changelog = ShopifyCLI::Changelog.new
|
12
|
+
@github = Octokit::Client.new(access_token: github_access_token)
|
13
|
+
end
|
14
|
+
|
15
|
+
def prepare!
|
16
|
+
ensure_updated_main
|
17
|
+
create_release_branch
|
18
|
+
update_changelog
|
19
|
+
update_versions_in_files
|
20
|
+
commit_packaging
|
21
|
+
pr = create_pr
|
22
|
+
system("open #{pr["html_url"]}")
|
23
|
+
end
|
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
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
attr_reader :new_version, :changelog, :github
|
36
|
+
|
37
|
+
def ensure_updated_main
|
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
|
46
|
+
end
|
47
|
+
system_or_fail("git checkout main", "check out main branch")
|
48
|
+
unless system("git pull")
|
49
|
+
raise "git pull failed, cannot be sure there aren't new commits!"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def create_release_branch
|
54
|
+
puts "Checking out release branch"
|
55
|
+
system_or_fail("git checkout -b #{release_branch_name}", "check out release branch")
|
56
|
+
end
|
57
|
+
|
58
|
+
def update_changelog
|
59
|
+
if release_notes("Unreleased").empty?
|
60
|
+
puts "No unreleased CHANGELOG updates found!"
|
61
|
+
else
|
62
|
+
puts "Updating CHANGELOG"
|
63
|
+
changelog.update_version!(new_version)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def update_versions_in_files
|
68
|
+
version_file = File.join(ShopifyCLI::ROOT, "lib/shopify_cli/version.rb")
|
69
|
+
puts "Updating version.rb"
|
70
|
+
ShopifyCLI::Sed.new.replace_inline(version_file, ShopifyCLI::VERSION, new_version)
|
71
|
+
gemfile_lock = File.join(ShopifyCLI::ROOT, "Gemfile.lock")
|
72
|
+
puts "Updating Gemfile.lock"
|
73
|
+
ShopifyCLI::Sed.new.replace_inline(
|
74
|
+
gemfile_lock,
|
75
|
+
"shopify-cli (#{ShopifyCLI::VERSION})",
|
76
|
+
"shopify-cli (#{new_version})",
|
77
|
+
)
|
78
|
+
end
|
79
|
+
|
80
|
+
def commit_packaging
|
81
|
+
puts "Committing"
|
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")
|
84
|
+
end
|
85
|
+
|
86
|
+
def create_pr
|
87
|
+
repo = "Shopify/shopify-cli"
|
88
|
+
github.create_pull_request(
|
89
|
+
repo,
|
90
|
+
"main",
|
91
|
+
release_branch_name,
|
92
|
+
"Packaging for release v#{new_version}",
|
93
|
+
release_notes("Unreleased")
|
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})"
|
180
|
+
end
|
181
|
+
|
182
|
+
def release_branch_name
|
183
|
+
@release_branch_name ||= "release_#{new_version.split(".").join("_")}"
|
184
|
+
end
|
185
|
+
|
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)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module ShopifyCLI
|
2
|
+
class Sed
|
3
|
+
class SedError < StandardError; end
|
4
|
+
|
5
|
+
def replace_inline(filename, pattern, output)
|
6
|
+
command =
|
7
|
+
case CLI::Kit::System.os
|
8
|
+
when :mac
|
9
|
+
"sed -i ''"
|
10
|
+
when :linux
|
11
|
+
"sed -i"
|
12
|
+
else
|
13
|
+
raise "Unrecognized system!"
|
14
|
+
end
|
15
|
+
success = system("#{command} 's/#{pattern}/#{output}/' #{filename}")
|
16
|
+
raise SedError unless success
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -88,24 +88,12 @@ module ShopifyCLI
|
|
88
88
|
end
|
89
89
|
|
90
90
|
def check_node
|
91
|
-
|
92
|
-
context.abort(context.message("core.app.create.node.error.node_required")) if cmd_path.nil?
|
93
|
-
|
94
|
-
version, stat = context.capture2e("node", "-v")
|
95
|
-
unless stat.success?
|
96
|
-
context.abort(context.message("core.app.create.node.error.node_version_failure"))
|
97
|
-
end
|
98
|
-
|
91
|
+
version = ShopifyCLI::Environment.node_version(context: context)
|
99
92
|
context.done(context.message("core.app.create.node.node_version", version))
|
100
93
|
end
|
101
94
|
|
102
95
|
def check_npm
|
103
|
-
|
104
|
-
context.abort(context.message("core.app.create.node.error.npm_required")) if cmd_path.nil?
|
105
|
-
|
106
|
-
version, stat = context.capture2e("npm", "-v")
|
107
|
-
context.abort(context.message("core.app.create.node.error.npm_version_failure")) unless stat.success?
|
108
|
-
|
96
|
+
version = ShopifyCLI::Environment.npm_version(context: context)
|
109
97
|
context.done(context.message("core.app.create.node.npm_version", version))
|
110
98
|
end
|
111
99
|
|
@@ -69,12 +69,7 @@ module ShopifyCLI
|
|
69
69
|
end
|
70
70
|
|
71
71
|
def check_npm
|
72
|
-
|
73
|
-
context.abort(context.message("core.app.create.php.error.npm_required")) if cmd_path.nil?
|
74
|
-
|
75
|
-
version, stat = context.capture2e("npm", "-v")
|
76
|
-
context.abort(context.message("core.app.create.php.error.npm_version_failure")) unless stat.success?
|
77
|
-
|
72
|
+
version = ShopifyCLI::Environment.npm_version(context: context)
|
78
73
|
context.done(context.message("core.app.create.php.npm_version", version))
|
79
74
|
end
|
80
75
|
|
@@ -108,7 +108,7 @@ module ShopifyCLI
|
|
108
108
|
end
|
109
109
|
|
110
110
|
def check_ruby
|
111
|
-
ruby_version =
|
111
|
+
ruby_version = Environment.ruby_version(context: context)
|
112
112
|
return if ruby_version.satisfies?("~>2.5") || ruby_version.satisfies?("~>3.1.0")
|
113
113
|
context.abort(context.message("core.app.create.rails.error.invalid_ruby_version"))
|
114
114
|
end
|
@@ -219,18 +219,10 @@ module ShopifyCLI
|
|
219
219
|
end
|
220
220
|
|
221
221
|
def install_webpacker?
|
222
|
-
rails_version
|
223
|
-
|
224
|
-
end
|
225
|
-
|
226
|
-
def rails_version
|
227
|
-
output, status = context.capture2e("rails", "--version")
|
228
|
-
unless status.success?
|
229
|
-
context.abort(context.message("core.app.create.rails.error.install_failure", "rails"))
|
230
|
-
end
|
222
|
+
rails_version = Environment.rails_version(context: context)
|
223
|
+
webpacker_config = File.exist?(File.join(context.root, "config/webpacker.yml"))
|
231
224
|
|
232
|
-
|
233
|
-
::Semantic::Version.new(version)
|
225
|
+
rails_version < ::Semantic::Version.new("7.0.0") && !webpacker_config
|
234
226
|
end
|
235
227
|
end
|
236
228
|
end
|
@@ -15,17 +15,37 @@
|
|
15
15
|
eventSource.onerror = () => eventSource.close();
|
16
16
|
}
|
17
17
|
|
18
|
+
function sectionNamesByType(type) {
|
19
|
+
const namespace = window.__SHOPIFY_CLI_ENV__;
|
20
|
+
return namespace.section_names_by_type[type] || [];
|
21
|
+
}
|
22
|
+
|
18
23
|
function reloadMode() {
|
19
|
-
|
24
|
+
const namespace = window.__SHOPIFY_CLI_ENV__;
|
20
25
|
return namespace.mode;
|
21
26
|
}
|
22
27
|
|
28
|
+
function querySelectDOMSections(idSuffix) {
|
29
|
+
const elements = document.querySelectorAll(`[id^='shopify-section'][id$='${idSuffix}']`);
|
30
|
+
return Array.from(elements);
|
31
|
+
}
|
32
|
+
|
33
|
+
function fetchDOMSections(name) {
|
34
|
+
const domSections = sectionNamesByType(name).flatMap((n) => querySelectDOMSections(n));
|
35
|
+
|
36
|
+
if (domSections.length > 0) {
|
37
|
+
return domSections;
|
38
|
+
}
|
39
|
+
|
40
|
+
return querySelectDOMSections(name);
|
41
|
+
}
|
42
|
+
|
23
43
|
function isFullPageReloadMode(){
|
24
|
-
return reloadMode() ===
|
44
|
+
return reloadMode() === 'full-page';
|
25
45
|
}
|
26
46
|
|
27
47
|
function isReloadModeActive(){
|
28
|
-
return reloadMode() !==
|
48
|
+
return reloadMode() !== 'off';
|
29
49
|
}
|
30
50
|
|
31
51
|
function isRefreshRequired(files) {
|
@@ -104,26 +124,28 @@
|
|
104
124
|
constructor(filename) {
|
105
125
|
this.filename = filename;
|
106
126
|
this.name = filename.split('/').pop().replace('.liquid', '');
|
107
|
-
this.
|
127
|
+
this.elements = fetchDOMSections(this.name);
|
108
128
|
}
|
109
129
|
|
110
130
|
valid() {
|
111
|
-
return this.filename.startsWith('sections/') && this.
|
131
|
+
return this.filename.startsWith('sections/') && this.elements.length > 0;
|
112
132
|
}
|
113
133
|
|
114
|
-
async
|
115
|
-
|
116
|
-
|
134
|
+
async refreshElement(element) {
|
135
|
+
|
136
|
+
const sectionId = element.id.replace(/^shopify-section-/, '');
|
137
|
+
const url = new URL(window.location.href);
|
138
|
+
|
139
|
+
url.searchParams.append('section_id', sectionId);
|
140
|
+
|
141
|
+
const response = await fetch(url);
|
117
142
|
|
118
143
|
try {
|
119
|
-
const response = await fetch(url);
|
120
144
|
if (response.headers.get('x-templates-from-params') == '1') {
|
121
145
|
const html = await response.text();
|
122
|
-
|
123
|
-
|
124
|
-
console.log(`[HotReload] Reloaded ${this.name} section`);
|
146
|
+
element.outerHTML = html;
|
125
147
|
} else {
|
126
|
-
window.location.reload()
|
148
|
+
window.location.reload();
|
127
149
|
|
128
150
|
console.log(`[HotReload] Hot-reloading not supported, fully reloading ${this.name} section`);
|
129
151
|
}
|
@@ -132,6 +154,11 @@
|
|
132
154
|
console.log(`[HotReload] Failed to reload ${this.name} section: ${e.message}`);
|
133
155
|
}
|
134
156
|
}
|
157
|
+
|
158
|
+
async refresh() {
|
159
|
+
console.log(`[HotReload] Reloaded ${this.name} sections`);
|
160
|
+
this.elements.forEach(this.refreshElement);
|
161
|
+
}
|
135
162
|
}
|
136
163
|
|
137
164
|
if (isReloadModeActive()) {
|
@@ -51,7 +51,7 @@ module ShopifyCLI
|
|
51
51
|
def fetch_asset(file)
|
52
52
|
api_client.get(
|
53
53
|
path: "themes/#{@theme.id}/assets.json",
|
54
|
-
query: URI.encode_www_form("asset[key]" => file.relative_path
|
54
|
+
query: URI.encode_www_form("asset[key]" => file.relative_path),
|
55
55
|
)
|
56
56
|
rescue ShopifyCLI::API::APIRequestNotFoundError
|
57
57
|
[404, {}]
|