shopify-cli 2.24.0 → 2.25.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -0
  3. data/Gemfile.lock +1 -1
  4. data/README.md +1 -1
  5. data/lib/project_types/extension/commands/serve.rb +57 -3
  6. data/lib/project_types/extension/extension_project.rb +8 -1
  7. data/lib/project_types/extension/loaders/project.rb +3 -2
  8. data/lib/project_types/extension/messages/messages.rb +21 -6
  9. data/lib/project_types/extension/models/server_config/development_renderer.rb +1 -1
  10. data/lib/project_types/extension/models/specification_handlers/theme_app_extension.rb +18 -6
  11. data/lib/project_types/theme/commands/serve.rb +15 -3
  12. data/lib/project_types/theme/messages/messages.rb +4 -2
  13. data/lib/shopify_cli/commands/logout.rb +13 -2
  14. data/lib/shopify_cli/environment.rb +1 -1
  15. data/lib/shopify_cli/file_system_listener.rb +30 -0
  16. data/lib/shopify_cli/git.rb +116 -33
  17. data/lib/shopify_cli/identity_auth.rb +1 -0
  18. data/lib/shopify_cli/project.rb +1 -1
  19. data/lib/shopify_cli/tasks/ensure_project_type.rb +3 -1
  20. data/lib/shopify_cli/theme/dev_server/cdn_fonts.rb +1 -1
  21. data/lib/shopify_cli/theme/dev_server/certificate_manager.rb +1 -1
  22. data/lib/shopify_cli/theme/dev_server/errors.rb +9 -0
  23. data/lib/shopify_cli/theme/dev_server/header_hash.rb +1 -1
  24. data/lib/shopify_cli/theme/dev_server/hooks/file_change_hook.rb +77 -0
  25. data/lib/shopify_cli/theme/dev_server/hot_reload/remote_file_deleter.rb +1 -1
  26. data/lib/shopify_cli/theme/dev_server/hot_reload/remote_file_reloader.rb +1 -1
  27. data/lib/shopify_cli/theme/dev_server/{hot-reload-no-script.html → hot_reload/resources/hot-reload-no-script.html} +0 -0
  28. data/lib/shopify_cli/theme/dev_server/hot_reload/resources/hot_reload.js +48 -0
  29. data/lib/shopify_cli/theme/dev_server/hot_reload/resources/sse_client.js +43 -0
  30. data/lib/shopify_cli/theme/dev_server/hot_reload/resources/theme.js +114 -0
  31. data/lib/shopify_cli/theme/dev_server/hot_reload/resources/theme_extension.js +121 -0
  32. data/lib/shopify_cli/theme/dev_server/hot_reload/script_injector.rb +57 -0
  33. data/lib/shopify_cli/theme/dev_server/hot_reload/sections_index.rb +1 -1
  34. data/lib/shopify_cli/theme/dev_server/hot_reload.rb +8 -76
  35. data/lib/shopify_cli/theme/dev_server/local_assets.rb +28 -28
  36. data/lib/shopify_cli/theme/dev_server/proxy.rb +33 -25
  37. data/lib/shopify_cli/theme/dev_server/proxy_param_builder.rb +82 -0
  38. data/lib/shopify_cli/theme/dev_server/reload_mode.rb +1 -1
  39. data/lib/shopify_cli/theme/dev_server/remote_watcher/json_files_update_job.rb +1 -1
  40. data/lib/shopify_cli/theme/dev_server/remote_watcher.rb +1 -1
  41. data/lib/shopify_cli/theme/dev_server/sse.rb +1 -1
  42. data/lib/shopify_cli/theme/dev_server/watcher.rb +8 -9
  43. data/lib/shopify_cli/theme/dev_server/web_server.rb +1 -1
  44. data/lib/shopify_cli/theme/dev_server.rb +287 -99
  45. data/lib/shopify_cli/theme/extension/app_extension.rb +40 -0
  46. data/lib/shopify_cli/theme/extension/dev_server/hooks/file_change_hook.rb +68 -0
  47. data/lib/shopify_cli/theme/extension/dev_server/hot_reload/script_injector.rb +30 -0
  48. data/lib/shopify_cli/theme/extension/dev_server/hot_reload.rb +13 -0
  49. data/lib/shopify_cli/theme/extension/dev_server/local_assets.rb +30 -0
  50. data/lib/shopify_cli/theme/{dev_server/proxy/template_param_builder.rb → extension/dev_server/proxy_param_builder.rb} +26 -16
  51. data/lib/shopify_cli/theme/extension/dev_server/watcher.rb +47 -0
  52. data/lib/shopify_cli/theme/extension/dev_server.rb +150 -0
  53. data/lib/shopify_cli/theme/extension/host_theme.rb +104 -0
  54. data/lib/shopify_cli/theme/extension/syncer/extension_serve_job.rb +133 -0
  55. data/lib/shopify_cli/theme/extension/syncer/operation.rb +21 -0
  56. data/lib/shopify_cli/theme/extension/syncer.rb +81 -0
  57. data/lib/shopify_cli/theme/extension/ui/host_theme_progress_bar.rb +35 -0
  58. data/lib/shopify_cli/theme/ignore_helper.rb +31 -0
  59. data/lib/shopify_cli/theme/root.rb +62 -0
  60. data/lib/shopify_cli/theme/syncer.rb +12 -6
  61. data/lib/shopify_cli/theme/theme.rb +10 -52
  62. data/lib/shopify_cli/version.rb +1 -1
  63. metadata +27 -7
  64. data/.github/workflows/triage.yml +0 -22
  65. data/lib/shopify_cli/theme/dev_server/hot-reload.js +0 -194
  66. data/lib/shopify_cli/theme/syncer/ignore_helper.rb +0 -33
@@ -7,7 +7,6 @@ require "forwardable"
7
7
 
8
8
  require_relative "syncer/checksums"
9
9
  require_relative "syncer/error_reporter"
10
- require_relative "syncer/ignore_helper"
11
10
  require_relative "syncer/json_delete_handler"
12
11
  require_relative "syncer/json_update_handler"
13
12
  require_relative "syncer/merger"
@@ -15,6 +14,7 @@ require_relative "syncer/operation"
15
14
  require_relative "syncer/standard_reporter"
16
15
  require_relative "syncer/unsupported_script_warning"
17
16
  require_relative "theme_admin_api"
17
+ require_relative "ignore_helper"
18
18
  require_relative "theme_admin_api_throttler"
19
19
 
20
20
  module ShopifyCLI
@@ -22,7 +22,7 @@ module ShopifyCLI
22
22
  class Syncer
23
23
  extend Forwardable
24
24
 
25
- include IgnoreHelper
25
+ include ShopifyCLI::Theme::IgnoreHelper
26
26
  include JsonDeleteHandler
27
27
  include JsonUpdateHandler
28
28
 
@@ -367,10 +367,16 @@ module ShopifyCLI
367
367
  end
368
368
 
369
369
  def parse_api_errors(operation, exception)
370
- parsed_body = if exception&.response&.is_a?(Hash)
371
- exception&.response&.[](:body)
372
- else
373
- JSON.parse(exception&.response&.body)
370
+ parsed_body = {}
371
+
372
+ if exception.respond_to?(:response)
373
+ response = exception.response
374
+
375
+ parsed_body = if response&.is_a?(Hash)
376
+ response&.[](:body)
377
+ else
378
+ JSON.parse(response&.body)
379
+ end
374
380
  end
375
381
 
376
382
  errors = parsed_body.dig("errors") # either nil or another type
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  require_relative "file"
3
+ require_relative "root"
3
4
  require_relative "theme_admin_api"
4
5
 
5
6
  require "pathname"
@@ -9,12 +10,11 @@ module ShopifyCLI
9
10
  module Theme
10
11
  class InvalidThemeRole < StandardError; end
11
12
 
12
- class Theme
13
+ class Theme < Root
13
14
  attr_reader :root, :id
14
15
 
15
16
  def initialize(ctx, root: nil, id: nil, name: nil, role: nil)
16
- @ctx = ctx
17
- @root = Pathname.new(root) if root
17
+ super(ctx, root: root)
18
18
  @id = id
19
19
  @name = name
20
20
  @role = role
@@ -24,48 +24,10 @@ module ShopifyCLI
24
24
  (glob(["**/*.liquid", "**/*.json"]) + static_asset_files).uniq
25
25
  end
26
26
 
27
- def static_asset_files
28
- glob("assets/*", raise_on_dir: true).reject(&:liquid?)
29
- end
30
-
31
- def liquid_files
32
- glob("**/*.liquid")
33
- end
34
-
35
- def json_files
36
- glob("**/*.json")
37
- end
38
-
39
- def glob(pattern, raise_on_dir: false)
40
- root
41
- .glob(pattern)
42
- .select { |path| file?(path, raise_on_dir) }
43
- .map { |path| File.new(path, root) }
44
- end
45
-
46
27
  def theme_file?(file)
47
28
  theme_files.include?(self[file])
48
29
  end
49
30
 
50
- def static_asset_file?(file)
51
- static_asset_files.include?(self[file])
52
- end
53
-
54
- def static_asset_paths
55
- static_asset_files.map(&:relative_path)
56
- end
57
-
58
- def [](file)
59
- case file
60
- when File
61
- file
62
- when Pathname
63
- File.new(file, root)
64
- when String
65
- File.new(root.join(file), root)
66
- end
67
- end
68
-
69
31
  def shop
70
32
  api_client.get_shop_or_abort
71
33
  end
@@ -124,9 +86,7 @@ module ShopifyCLI
124
86
  end
125
87
 
126
88
  def delete
127
- api_client.delete(
128
- path: "themes/#{id}.json"
129
- )
89
+ delete_theme
130
90
  end
131
91
 
132
92
  def publish
@@ -231,6 +191,12 @@ module ShopifyCLI
231
191
  @api_client ||= ThemeAdminAPI.new(@ctx)
232
192
  end
233
193
 
194
+ def delete_theme
195
+ api_client.delete(
196
+ path: "themes/#{id}.json"
197
+ )
198
+ end
199
+
234
200
  def load_info_from_api
235
201
  _status, body = api_client.get(
236
202
  path: "themes/#{id}.json"
@@ -241,14 +207,6 @@ module ShopifyCLI
241
207
 
242
208
  self
243
209
  end
244
-
245
- def file?(path, raise_on_dir = false)
246
- if raise_on_dir && ::File.directory?(path)
247
- @ctx.abort(@ctx.message("theme.serve.error.invalid_subdirectory", path.to_s))
248
- end
249
-
250
- ::File.file?(path)
251
- end
252
210
  end
253
211
  end
254
212
  end
@@ -1,3 +1,3 @@
1
1
  module ShopifyCLI
2
- VERSION = "2.24.0"
2
+ VERSION = "2.25.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shopify-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.24.0
4
+ version: 2.25.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-29 00:00:00.000000000 Z
11
+ date: 2022-09-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -127,7 +127,6 @@ files:
127
127
  - ".github/workflows/cla.yml"
128
128
  - ".github/workflows/shopify.yml"
129
129
  - ".github/workflows/stale.yml"
130
- - ".github/workflows/triage.yml"
131
130
  - ".gitignore"
132
131
  - ".rubocop.yml"
133
132
  - ".rubocop_todo.yml"
@@ -432,6 +431,7 @@ files:
432
431
  - lib/shopify_cli/environment.rb
433
432
  - lib/shopify_cli/exception_reporter.rb
434
433
  - lib/shopify_cli/feature.rb
434
+ - lib/shopify_cli/file_system_listener.rb
435
435
  - lib/shopify_cli/form.rb
436
436
  - lib/shopify_cli/git.rb
437
437
  - lib/shopify_cli/github.rb
@@ -504,16 +504,22 @@ files:
504
504
  - lib/shopify_cli/theme/dev_server.rb
505
505
  - lib/shopify_cli/theme/dev_server/cdn_fonts.rb
506
506
  - lib/shopify_cli/theme/dev_server/certificate_manager.rb
507
+ - lib/shopify_cli/theme/dev_server/errors.rb
507
508
  - lib/shopify_cli/theme/dev_server/header_hash.rb
508
- - lib/shopify_cli/theme/dev_server/hot-reload-no-script.html
509
- - lib/shopify_cli/theme/dev_server/hot-reload.js
509
+ - lib/shopify_cli/theme/dev_server/hooks/file_change_hook.rb
510
510
  - lib/shopify_cli/theme/dev_server/hot_reload.rb
511
511
  - lib/shopify_cli/theme/dev_server/hot_reload/remote_file_deleter.rb
512
512
  - lib/shopify_cli/theme/dev_server/hot_reload/remote_file_reloader.rb
513
+ - lib/shopify_cli/theme/dev_server/hot_reload/resources/hot-reload-no-script.html
514
+ - lib/shopify_cli/theme/dev_server/hot_reload/resources/hot_reload.js
515
+ - lib/shopify_cli/theme/dev_server/hot_reload/resources/sse_client.js
516
+ - lib/shopify_cli/theme/dev_server/hot_reload/resources/theme.js
517
+ - lib/shopify_cli/theme/dev_server/hot_reload/resources/theme_extension.js
518
+ - lib/shopify_cli/theme/dev_server/hot_reload/script_injector.rb
513
519
  - lib/shopify_cli/theme/dev_server/hot_reload/sections_index.rb
514
520
  - lib/shopify_cli/theme/dev_server/local_assets.rb
515
521
  - lib/shopify_cli/theme/dev_server/proxy.rb
516
- - lib/shopify_cli/theme/dev_server/proxy/template_param_builder.rb
522
+ - lib/shopify_cli/theme/dev_server/proxy_param_builder.rb
517
523
  - lib/shopify_cli/theme/dev_server/reload_mode.rb
518
524
  - lib/shopify_cli/theme/dev_server/remote_watcher.rb
519
525
  - lib/shopify_cli/theme/dev_server/remote_watcher/json_files_update_job.rb
@@ -521,11 +527,26 @@ files:
521
527
  - lib/shopify_cli/theme/dev_server/watcher.rb
522
528
  - lib/shopify_cli/theme/dev_server/web_server.rb
523
529
  - lib/shopify_cli/theme/development_theme.rb
530
+ - lib/shopify_cli/theme/extension/app_extension.rb
531
+ - lib/shopify_cli/theme/extension/dev_server.rb
532
+ - lib/shopify_cli/theme/extension/dev_server/hooks/file_change_hook.rb
533
+ - lib/shopify_cli/theme/extension/dev_server/hot_reload.rb
534
+ - lib/shopify_cli/theme/extension/dev_server/hot_reload/script_injector.rb
535
+ - lib/shopify_cli/theme/extension/dev_server/local_assets.rb
536
+ - lib/shopify_cli/theme/extension/dev_server/proxy_param_builder.rb
537
+ - lib/shopify_cli/theme/extension/dev_server/watcher.rb
538
+ - lib/shopify_cli/theme/extension/host_theme.rb
539
+ - lib/shopify_cli/theme/extension/syncer.rb
540
+ - lib/shopify_cli/theme/extension/syncer/extension_serve_job.rb
541
+ - lib/shopify_cli/theme/extension/syncer/operation.rb
542
+ - lib/shopify_cli/theme/extension/ui/host_theme_progress_bar.rb
524
543
  - lib/shopify_cli/theme/file.rb
525
544
  - lib/shopify_cli/theme/filter/path_matcher.rb
526
545
  - lib/shopify_cli/theme/ignore_filter.rb
546
+ - lib/shopify_cli/theme/ignore_helper.rb
527
547
  - lib/shopify_cli/theme/include_filter.rb
528
548
  - lib/shopify_cli/theme/mime_type.rb
549
+ - lib/shopify_cli/theme/root.rb
529
550
  - lib/shopify_cli/theme/syncer.rb
530
551
  - lib/shopify_cli/theme/syncer/checksums.rb
531
552
  - lib/shopify_cli/theme/syncer/error_reporter.rb
@@ -534,7 +555,6 @@ files:
534
555
  - lib/shopify_cli/theme/syncer/forms/base_strategy_form.rb
535
556
  - lib/shopify_cli/theme/syncer/forms/select_delete_strategy.rb
536
557
  - lib/shopify_cli/theme/syncer/forms/select_update_strategy.rb
537
- - lib/shopify_cli/theme/syncer/ignore_helper.rb
538
558
  - lib/shopify_cli/theme/syncer/json_delete_handler.rb
539
559
  - lib/shopify_cli/theme/syncer/json_update_handler.rb
540
560
  - lib/shopify_cli/theme/syncer/merger.rb
@@ -1,22 +0,0 @@
1
- name: Triage new issues to DTE oncall project board ("Needs triage" column)
2
-
3
- on:
4
- issues:
5
- types: [opened, reopened]
6
-
7
- jobs:
8
- triage-issue:
9
- runs-on: ubuntu-latest
10
- steps:
11
- - name: Extract issue id
12
- id: issue
13
- run: echo "::set-output name=id::$(jq -r '.issue.id' < "$GITHUB_EVENT_PATH")"
14
-
15
- - name: Create card
16
- env:
17
- TOKEN: ${{ secrets.ACTIONS_TOKEN }}
18
- run: |
19
- curl -s -X POST -u "$GITHUB_ACTOR:$TOKEN" --retry 3 \
20
- -H 'Accept: application/vnd.github.inertia-preview+json' \
21
- -d "{\"content_type\": \"Issue\", \"content_id\": ${{ steps.issue.outputs.id }}}" \
22
- "https://api.github.com/projects/columns/10507989/cards"
@@ -1,194 +0,0 @@
1
- (() => {
2
- function verifySSE() {
3
- if (typeof (EventSource) === "undefined") {
4
- console.error("[HotReload] Error: SSE features are not supported. Try a different browser.");
5
- }
6
- }
7
-
8
- console.log("[HotReload] Initializing...");
9
-
10
- verifySSE();
11
- })();
12
-
13
- (() => {
14
- function connect() {
15
- const eventSource = new EventSource('/hot-reload');
16
-
17
- eventSource.onmessage = onMessage;
18
-
19
- eventSource.onopen = () => console.log('[HotReload] SSE connected.');
20
-
21
- eventSource.onclose = () => {
22
- console.log('[HotReload] SSE closed. Attempting to reconnect...');
23
-
24
- setTimeout(connect, 5000);
25
- }
26
-
27
- eventSource.onerror = () => eventSource.close();
28
- }
29
-
30
- function sectionNamesByType(type) {
31
- const namespace = window.__SHOPIFY_CLI_ENV__;
32
- return namespace.section_names_by_type[type] || [];
33
- }
34
-
35
- function reloadMode() {
36
- const namespace = window.__SHOPIFY_CLI_ENV__;
37
- return namespace.mode;
38
- }
39
-
40
- function querySelectDOMSections(idSuffix) {
41
- const elements = document.querySelectorAll(`[id^='shopify-section'][id$='${idSuffix}']`);
42
- return Array.from(elements);
43
- }
44
-
45
- function fetchDOMSections(name) {
46
- const domSections = sectionNamesByType(name).flatMap((n) => querySelectDOMSections(n));
47
-
48
- if (domSections.length > 0) {
49
- return domSections;
50
- }
51
-
52
- return querySelectDOMSections(name);
53
- }
54
-
55
- function isFullPageReloadMode() {
56
- return reloadMode() === 'full-page';
57
- }
58
-
59
- function isReloadModeActive() {
60
- return reloadMode() !== 'off';
61
- }
62
-
63
- function isRefreshRequired(files) {
64
- if (isFullPageReloadMode()) {
65
- return true;
66
- }
67
- return files.some((file) => !isCssFile(file) && !isSectionFile(file));
68
- }
69
-
70
- function refreshFile(file) {
71
- if (isCssFile(file)) {
72
- reloadCssFile(file);
73
- return;
74
- }
75
-
76
- if (isSectionFile(file)) {
77
- reloadSection(file);
78
- return;
79
- }
80
- }
81
-
82
- function setHotReloadCookie(files) {
83
- var date = new Date();
84
-
85
- // Hot reload cookie expires in 3 seconds
86
- date.setSeconds(date.getSeconds() + 3);
87
-
88
- var sections = files.join(',');
89
- var expires = date.toUTCString();
90
-
91
- document.cookie = `hot_reload_sections=${sections}; expires=${expires}; path=/`;
92
- }
93
-
94
- function refreshPage(files) {
95
- setHotReloadCookie(files);
96
- console.log('[HotReload] Refreshing entire page');
97
- window.location.reload();
98
- }
99
-
100
- function onMessage(message) {
101
- const data = JSON.parse(message.data);
102
- if (data.reload_page) {
103
- refreshPage([]);
104
- return;
105
- }
106
-
107
- handleUpdate(data);
108
- }
109
-
110
- function handleUpdate(data) {
111
- var modifiedFiles = data.modified;
112
-
113
- if (modifiedFiles === undefined) {
114
- return;
115
- }
116
-
117
- if (isRefreshRequired(modifiedFiles)) {
118
- refreshPage(modifiedFiles);
119
- } else {
120
- modifiedFiles.forEach(refreshFile);
121
- }
122
- }
123
-
124
- function isCssFile(filename) {
125
- return filename.endsWith('.css');
126
- }
127
-
128
- function reloadCssFile(filename) {
129
- // Find a stylesheet link starting with /assets (locally-served only) containing the filename
130
- let links = document.querySelectorAll(`link[href^="/assets"][href*="${filename}"][rel="stylesheet"]`);
131
-
132
- if (!links.length) {
133
- console.log(`[HotReload] Could not find link for stylesheet ${filename}`);
134
- } else {
135
- links.forEach(link => {
136
- link.href = new URL(link.href).pathname + `?v=${Date.now()}`;
137
- console.log(`[HotReload] Reloaded stylesheet ${filename}`);
138
- })
139
- }
140
- }
141
-
142
- function isSectionFile(filename) {
143
- return new Section(filename).valid();
144
- }
145
-
146
- function reloadSection(filename) {
147
- new Section(filename).refresh();
148
- }
149
-
150
- class Section {
151
- constructor(filename) {
152
- this.filename = filename;
153
- this.name = filename.split('/').pop().replace('.liquid', '');
154
- this.elements = fetchDOMSections(this.name);
155
- }
156
-
157
- valid() {
158
- return this.filename.startsWith('sections/') && this.elements.length > 0;
159
- }
160
-
161
- async refreshElement(element) {
162
-
163
- const sectionId = element.id.replace(/^shopify-section-/, '');
164
- const url = new URL(window.location.href);
165
-
166
- url.searchParams.append('section_id', sectionId);
167
-
168
- const response = await fetch(url);
169
-
170
- try {
171
- if (response.headers.get('x-templates-from-params') == '1') {
172
- const html = await response.text();
173
- element.outerHTML = html;
174
- } else {
175
- window.location.reload();
176
-
177
- console.log(`[HotReload] Hot-reloading not supported, fully reloading ${this.name} section`);
178
- }
179
-
180
- } catch (e) {
181
- console.log(`[HotReload] Failed to reload ${this.name} section: ${e.message}`);
182
- }
183
- }
184
-
185
- async refresh() {
186
- console.log(`[HotReload] Reloaded ${this.name} sections`);
187
- this.elements.forEach(this.refreshElement);
188
- }
189
- }
190
-
191
- if (isReloadModeActive()) {
192
- connect();
193
- }
194
- })();
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ShopifyCLI
4
- module Theme
5
- class Syncer
6
- module IgnoreHelper
7
- def ignore_operation?(operation)
8
- path = operation.file_path
9
- ignore_path?(path)
10
- end
11
-
12
- def ignore_file?(file)
13
- path = file.relative_path
14
- ignore_path?(path)
15
- end
16
-
17
- def ignore_path?(path)
18
- ignored_by_ignore_filter?(path) || ignored_by_include_filter?(path)
19
- end
20
-
21
- private
22
-
23
- def ignored_by_ignore_filter?(path)
24
- ignore_filter&.ignore?(path)
25
- end
26
-
27
- def ignored_by_include_filter?(path)
28
- !!include_filter && !include_filter.match?(path)
29
- end
30
- end
31
- end
32
- end
33
- end