shopify-cli 2.15.1 → 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/CHANGELOG.md +6 -0
- data/Gemfile.lock +1 -1
- data/Rakefile +13 -0
- data/lib/project_types/extension/messages/messages.rb +1 -1
- 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/serve.rb +1 -0
- data/lib/project_types/theme/messages/messages.rb +40 -8
- data/lib/shopify_cli/git.rb +36 -0
- data/lib/shopify_cli/messages/messages.rb +5 -4
- data/lib/shopify_cli/release.rb +120 -20
- 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/thread_pool/job.rb +10 -2
- data/lib/shopify_cli/thread_pool.rb +15 -3
- data/lib/shopify_cli/version.rb +1 -1
- metadata +15 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a06f3c09c3e5e000956befefcbb7b8108096236d9b03cd021959881324c7cfe5
|
4
|
+
data.tar.gz: b1daa60127f1b93ceed1f00d151e67f9709bca8ae77a962913f6fd1edfaac0c9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 31e29e63fd9f7e569f7d4834549645b1ca206489274709aa7577f57b6888b3bd28d06eb5bd5899721cf9478239fa524b7937c009575a93c0ac096cd56c911fa6
|
7
|
+
data.tar.gz: '09f19940da497bf3fab8d8c78c801fc127c2a8cad8fe49887f86b05de373dc96acb805c8c282ce76c72d7ea89526d65f0ec0ef3732d6854110a50d02de2f240b'
|
data/CHANGELOG.md
CHANGED
@@ -2,11 +2,17 @@ From version 2.6.0, the sections in this file adhere to the [keep a changelog](h
|
|
2
2
|
|
3
3
|
## [Unreleased]
|
4
4
|
|
5
|
+
## Version 2.15.2
|
6
|
+
|
7
|
+
### Fixed
|
8
|
+
* [#2121](https://github.com/Shopify/shopify-cli/pull/2121): Fix the hot-reload to work when the section name is not equal to the type
|
9
|
+
|
5
10
|
## Version 2.15.1
|
6
11
|
|
7
12
|
### Added
|
8
13
|
* [#1934](https://github.com/Shopify/shopify-cli/pull/1934): Block directories in theme assets
|
9
14
|
* [#1880](https://github.com/Shopify/shopify-cli/pull/1880): Recognize attempts to pass a store name and suggest correction
|
15
|
+
* [#2174](https://github.com/Shopify/shopify-cli/pull/2174): Add optional 2-way sync between the CLI (`theme serve`) and the Theme Editor
|
10
16
|
|
11
17
|
### Fixed
|
12
18
|
* [#1874](https://github.com/Shopify/shopify-cli/pull/1874): Make ngrok errors more robust and helpful
|
data/Gemfile.lock
CHANGED
data/Rakefile
CHANGED
@@ -154,6 +154,19 @@ namespace :release do
|
|
154
154
|
ShopifyCLI::Release.new(new_version, github_access_token).prepare!
|
155
155
|
puts "Completed!"
|
156
156
|
end
|
157
|
+
|
158
|
+
task :package do
|
159
|
+
github_access_token = ENV["GITHUB_ACCESS_TOKEN"]
|
160
|
+
unless github_access_token
|
161
|
+
raise <<~NO_GITHUB_ACCESS_TOKEN
|
162
|
+
GitHub access token must be provided, e.g.:
|
163
|
+
|
164
|
+
$ GITHUB_ACCESS_TOKEN=abcdef rake release:package
|
165
|
+
NO_GITHUB_ACCESS_TOKEN
|
166
|
+
end
|
167
|
+
ShopifyCLI::Release.new(ShopifyCLI::VERSION, github_access_token).package!
|
168
|
+
puts "Completed!"
|
169
|
+
end
|
157
170
|
end
|
158
171
|
|
159
172
|
namespace :extensions do
|
@@ -41,7 +41,7 @@ module Extension
|
|
41
41
|
invalid_api_key: "The API key %s does not match any of your apps.",
|
42
42
|
ask_app: "Which app would you like to register this extension with?",
|
43
43
|
no_apps: "{{x}} You don’t have any apps.",
|
44
|
-
learn_about_apps: "{{*}} Learn more about building apps at <https://shopify.dev/
|
44
|
+
learn_about_apps: "{{*}} Learn more about building apps at <https://shopify.dev/apps>, " \
|
45
45
|
"or try creating a new app using {{command:shopify [node|rails] create}}.",
|
46
46
|
loading_apps: "Loading your apps…",
|
47
47
|
no_available_extensions: "{{x}} There are no available extensions for this app.",
|
@@ -180,6 +180,23 @@ module Script
|
|
180
180
|
@max_size = max_size
|
181
181
|
end
|
182
182
|
end
|
183
|
+
|
184
|
+
class InvalidInputQueryErrors < ScriptProjectError
|
185
|
+
attr_reader :messages
|
186
|
+
|
187
|
+
def initialize(messages)
|
188
|
+
@messages = messages
|
189
|
+
super()
|
190
|
+
end
|
191
|
+
|
192
|
+
def input_query_path
|
193
|
+
ScriptProjectRepository::INPUT_QUERY_PATH
|
194
|
+
end
|
195
|
+
|
196
|
+
def message
|
197
|
+
messages.join("\n")
|
198
|
+
end
|
199
|
+
end
|
183
200
|
end
|
184
201
|
end
|
185
202
|
end
|
@@ -83,6 +83,8 @@ module Script
|
|
83
83
|
valid_types: e["message"],
|
84
84
|
filename: script_config.filename,
|
85
85
|
)
|
86
|
+
elsif (errors = user_errors.filter { |err| err["tag"] == "input_query_validation_error" }).any?
|
87
|
+
raise Errors::InvalidInputQueryErrors, errors.map { |err| err["message"] }
|
86
88
|
elsif user_errors.find { |err| %w(not_use_msgpack_error schema_version_argument_error).include?(err["tag"]) }
|
87
89
|
raise Domain::Errors::MetadataValidationError
|
88
90
|
else
|
@@ -86,6 +86,9 @@ module Script
|
|
86
86
|
"type(s): %{valid_types}.",
|
87
87
|
configuration_schema_field_invalid_value_error_help: "Change the value of the type.",
|
88
88
|
|
89
|
+
input_query_error_cause: "Input query is invalid:\n%{messages}\n\n",
|
90
|
+
input_query_error_help: "Fix the query in the `%{input_query_path}` file.",
|
91
|
+
|
89
92
|
script_not_found_cause: "Can't find script %s for Script API %s",
|
90
93
|
|
91
94
|
system_call_failure_cause: "Something went wrong while running: {{command:%{cmd}}}.",
|
@@ -216,6 +216,17 @@ module Script
|
|
216
216
|
"script.error.configuration_schema_field_invalid_value_error_help"
|
217
217
|
),
|
218
218
|
}
|
219
|
+
when Layers::Infrastructure::Errors::InvalidInputQueryErrors
|
220
|
+
{
|
221
|
+
cause_of_error: ShopifyCLI::Context.message(
|
222
|
+
"script.error.input_query_error_cause",
|
223
|
+
messages: e.messages.map { |message| " {{x}} #{message}." }.join("\n"),
|
224
|
+
),
|
225
|
+
help_suggestion: ShopifyCLI::Context.message(
|
226
|
+
"script.error.input_query_error_help",
|
227
|
+
input_query_path: e.input_query_path,
|
228
|
+
),
|
229
|
+
}
|
219
230
|
when Layers::Infrastructure::Errors::DependencyInstallError
|
220
231
|
{
|
221
232
|
cause_of_error: ShopifyCLI::Context.message("script.error.dependency_install_cause"),
|
@@ -16,6 +16,7 @@ module Theme
|
|
16
16
|
parser.on("--port=PORT") { |port| flags[:port] = port.to_i }
|
17
17
|
parser.on("--poll") { flags[:poll] = true }
|
18
18
|
parser.on("--live-reload=MODE") { |mode| flags[:mode] = as_reload_mode(mode) }
|
19
|
+
parser.on("--theme-editor-sync") { flags[:editor_sync] = true }
|
19
20
|
end
|
20
21
|
|
21
22
|
def call(_args, name)
|
@@ -101,13 +101,14 @@ module Theme
|
|
101
101
|
Usage: {{command:%s theme serve [ ROOT ]}}
|
102
102
|
|
103
103
|
Options:
|
104
|
-
{{command:--port=PORT}}
|
105
|
-
{{command:--poll}}
|
106
|
-
{{command:--host=HOST}}
|
107
|
-
{{command:--
|
108
|
-
|
109
|
-
|
110
|
-
|
104
|
+
{{command:--port=PORT}} Local port to serve theme preview from.
|
105
|
+
{{command:--poll}} Force polling to detect file changes.
|
106
|
+
{{command:--host=HOST}} Set which network interface the web server listens on. The default value is 127.0.0.1.
|
107
|
+
{{command:--theme-editor-sync}} Synchronize Theme Editor updates in the local theme files.
|
108
|
+
{{command:--live-reload=MODE}} The live reload mode switches the server behavior when a file is modified:
|
109
|
+
- {{command:hot-reload}} Hot reloads local changes to CSS and sections (default)
|
110
|
+
- {{command:full-page}} Always refreshes the entire page
|
111
|
+
- {{command:off}} Deactivate live reload
|
111
112
|
HELP
|
112
113
|
reload_mode_is_not_valid: "The live reload mode `%s` is not valid.",
|
113
114
|
try_a_valid_reload_mode: "Try a valid live reload mode: %s.",
|
@@ -121,6 +122,36 @@ module Theme
|
|
121
122
|
fixed: "Fixed",
|
122
123
|
},
|
123
124
|
},
|
125
|
+
syncer: {
|
126
|
+
forms: {
|
127
|
+
apply_to_all: {
|
128
|
+
title: "Would like apply this to all the other %s files?",
|
129
|
+
yes: "Yes",
|
130
|
+
no: "No",
|
131
|
+
},
|
132
|
+
update_strategy: {
|
133
|
+
title_context: <<~TITLE,
|
134
|
+
|
135
|
+
The local file {{command:%s}} is different from the remote version in the development theme."
|
136
|
+
TITLE
|
137
|
+
title_question: "What would you like to do?",
|
138
|
+
keep_remote: "Keep the remote version",
|
139
|
+
keep_local: "Keep the local version",
|
140
|
+
union_merge: "Merge files (it may break the local file)",
|
141
|
+
exit: "Exit",
|
142
|
+
},
|
143
|
+
delete_strategy: {
|
144
|
+
title_context: <<~TITLE,
|
145
|
+
|
146
|
+
The local file {{command:%s}} has been recently removed, but it's present on your remote development theme.",
|
147
|
+
TITLE
|
148
|
+
title_question: "What would you like to do?",
|
149
|
+
delete: "Delete permanently",
|
150
|
+
restore: "Restore with the remote version",
|
151
|
+
exit: "Exit",
|
152
|
+
},
|
153
|
+
},
|
154
|
+
},
|
124
155
|
error: {
|
125
156
|
address_binding_error: "Couldn't bind to localhost."\
|
126
157
|
" To serve your theme, set a different address with {{command:%s theme serve --host=<address>}}",
|
@@ -137,9 +168,10 @@ module Theme
|
|
137
168
|
Serving %s
|
138
169
|
|
139
170
|
SERVING
|
171
|
+
download_changes: ", and use 'theme pull' to get the changes",
|
140
172
|
customize_or_preview: <<~CUSTOMIZE_OR_PREVIEW,
|
141
173
|
|
142
|
-
Customize this theme in the Theme Editor:
|
174
|
+
Customize this theme in the Theme Editor%s:
|
143
175
|
{{green:%s}}
|
144
176
|
|
145
177
|
Share this theme preview:
|
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.
|
@@ -388,6 +388,7 @@ module ShopifyCLI
|
|
388
388
|
sparse_checkout_not_set: "Sparse checkout set command failed.",
|
389
389
|
pull_failed: "Pull failed.",
|
390
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.",
|
391
392
|
},
|
392
393
|
|
393
394
|
cloning: "Cloning %s into %s…",
|
@@ -438,7 +439,7 @@ module ShopifyCLI
|
|
438
439
|
login: {
|
439
440
|
help: <<~HELP,
|
440
441
|
Log in to the Shopify CLI by authenticating with a store or partner organization
|
441
|
-
Usage: {{command:%s login [--store
|
442
|
+
Usage: {{command:%s login [--store STORE]}}
|
442
443
|
HELP
|
443
444
|
invalid_shop: <<~MESSAGE,
|
444
445
|
Invalid store provided (%s). Please provide the store in the following format: my-store.myshopify.com
|
@@ -460,7 +461,7 @@ module ShopifyCLI
|
|
460
461
|
switch: {
|
461
462
|
help: <<~HELP,
|
462
463
|
Switch between development stores in your partner organization
|
463
|
-
Usage: {{command:%s switch [--store
|
464
|
+
Usage: {{command:%s switch [--store STORE]}}
|
464
465
|
HELP
|
465
466
|
disabled_as_shopify_org: "Can't switch development stores logged in as {{green:Shopify partners org}}",
|
466
467
|
success: "Switched development store to {{green:%s}}",
|
@@ -573,7 +574,7 @@ module ShopifyCLI
|
|
573
574
|
HELP
|
574
575
|
|
575
576
|
error: {
|
576
|
-
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",
|
577
578
|
},
|
578
579
|
|
579
580
|
customer: {
|
@@ -809,7 +810,7 @@ module ShopifyCLI
|
|
809
810
|
not_logged_in: <<~MESSAGE,
|
810
811
|
It doesn't appear that you're logged in. You must log into a partner organization or a store staff account.
|
811
812
|
|
812
|
-
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.
|
813
814
|
MESSAGE
|
814
815
|
logged_in_shop_only: <<~MESSAGE,
|
815
816
|
Logged into store {{green:%s}} as staff (no partner organizations available for this login)
|
data/lib/shopify_cli/release.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
29
|
-
|
30
|
-
|
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
|
-
|
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
|
80
|
+
def commit_packaging
|
67
81
|
puts "Committing"
|
68
|
-
|
69
|
-
|
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
|
-
|
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("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})"
|
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
|
-
|
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
|
@@ -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, {}]
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShopifyCLI
|
4
|
+
module Theme
|
5
|
+
module DevServer
|
6
|
+
class HotReload
|
7
|
+
class SectionsIndex
|
8
|
+
def initialize(theme)
|
9
|
+
@theme = theme
|
10
|
+
end
|
11
|
+
|
12
|
+
def section_names_by_type
|
13
|
+
index = {}
|
14
|
+
|
15
|
+
files.each do |file|
|
16
|
+
section_hash(file).each do |key, value|
|
17
|
+
name = key
|
18
|
+
type = value&.dig("type")
|
19
|
+
|
20
|
+
next if !name || !type
|
21
|
+
|
22
|
+
index[type] = [] unless index[type]
|
23
|
+
index[type] << name
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
index
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def section_hash(file)
|
33
|
+
content = JSON.parse(file.read)
|
34
|
+
return [] unless content.is_a?(Hash)
|
35
|
+
|
36
|
+
sections = content["sections"]
|
37
|
+
return [] if sections.nil?
|
38
|
+
|
39
|
+
sections
|
40
|
+
rescue JSON::JSONError
|
41
|
+
[]
|
42
|
+
end
|
43
|
+
|
44
|
+
def files
|
45
|
+
@theme.json_files
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|