shopify-cli 2.15.1 → 2.15.2
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.
- 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
|