discourse_theme 1.0.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f330872d917c9b14b0e2ab7827f7fa16c41f5dce83ad4ec960888dc91e13a368
4
- data.tar.gz: e19bf6dfde320a3a616890abe72ff9a72021c25a5168dccada18824007540fcb
3
+ metadata.gz: 1e3352f4282ac30c46402e5cdf6f7c9ba504e7c8b5980884e4a42b700eef3e90
4
+ data.tar.gz: b13f657e0e023c3a6bee4eca8dc3a9090c55333f444bc5b9a55d67781baac017
5
5
  SHA512:
6
- metadata.gz: fee66903932cf9fb014e7e5c637daf2995756f8a122219cb4e5616d87229eff1fba8ed20aa59bcd07b5d58773c5f3ee07fc1801d44f07506d28c767b2c2adb92
7
- data.tar.gz: bf7b0fd4078e802e0039daa8499fc369a7befbb15349208361dae8678093d4402c7f938779c91c760a2141ab4f64fcf93693708a21564f4f3fda08fca0a25f1b
6
+ metadata.gz: 9900153835d064382bdde7fbd395345a66cdeb5bd4b5df85f825c2d8ac12556bc4c329d56bd91030a5efae836c567db79ab219d7276d3e5cef784e51aedeba82
7
+ data.tar.gz: 26aec19d02acf892b7f5434ec7f141c1afa7e3d8e099917e40d15cafa6d8a2ff27a7076769eaa6319b44d0d46a4561d12374fa295929b140e2e0938789334792
data/CHANGELOG.md CHANGED
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.1.0] - 2024-01-10
9
+
10
+ ### Added
11
+
12
+ - Add upload theme migrations prompt to `watch` command for `discourse_theme` CLI (#38)
13
+
8
14
  ## [1.0.2] - 2023-12-08
9
15
 
10
16
  ### Fixed
@@ -36,7 +36,7 @@ module DiscourseTheme
36
36
  exit 1
37
37
  end
38
38
 
39
- def run(args)
39
+ def run(args, &block)
40
40
  usage unless args[1]
41
41
 
42
42
  reset = !!args.delete("--reset")
@@ -66,9 +66,11 @@ module DiscourseTheme
66
66
  theme_list = client.get_themes_list
67
67
 
68
68
  options = {}
69
+
69
70
  if theme_id && theme = theme_list.find { |t| t["id"] == theme_id }
70
71
  options["Sync with existing theme: '#{theme["name"]}' (id:#{theme_id})"] = :default
71
72
  end
73
+
72
74
  options["Create and sync with a new theme"] = :create
73
75
  options["Select a different theme"] = :select
74
76
 
@@ -89,6 +91,7 @@ module DiscourseTheme
89
91
  rescue StandardError
90
92
  nil
91
93
  end
94
+
92
95
  already_uploaded = !!theme
93
96
  is_component = theme&.[]("component")
94
97
  component_count = about_json&.[]("components")&.length || 0
@@ -111,7 +114,9 @@ module DiscourseTheme
111
114
  )
112
115
 
113
116
  UI.progress "Uploading theme from #{dir}"
114
- settings.theme_id = theme_id = uploader.upload_full_theme
117
+
118
+ settings.theme_id =
119
+ theme_id = uploader.upload_full_theme(ignore_files: ignored_migrations(theme, dir))
115
120
 
116
121
  UI.success "Theme uploaded (id:#{theme_id})"
117
122
  UI.info "Preview: #{client.url}/?preview_theme_id=#{theme_id}"
@@ -126,7 +131,7 @@ module DiscourseTheme
126
131
 
127
132
  watcher = DiscourseTheme::Watcher.new(dir: dir, uploader: uploader)
128
133
  UI.progress "Watching for changes in #{dir}..."
129
- watcher.watch
134
+ watcher.watch(&block)
130
135
  elsif command == "download"
131
136
  client = DiscourseTheme::Client.new(dir, settings, reset: reset)
132
137
  downloader = DiscourseTheme::Downloader.new(dir: dir, client: client)
@@ -200,6 +205,43 @@ module DiscourseTheme
200
205
 
201
206
  private
202
207
 
208
+ def ignored_migrations(theme, dir)
209
+ return [] unless theme && Dir.exist?(File.join(dir, "migrations"))
210
+
211
+ existing_migrations =
212
+ theme
213
+ .dig("theme_fields")
214
+ &.filter_map do |theme_field|
215
+ theme_field["name"] if theme_field["target"] == "migrations"
216
+ end || []
217
+
218
+ new_migrations =
219
+ Dir["#{dir}/migrations/**/*.js"]
220
+ .reject do |f|
221
+ existing_migrations.any? do |existing_migration|
222
+ File.basename(f).include?(existing_migration)
223
+ end
224
+ end
225
+ .map { |f| Pathname.new(f).relative_path_from(Pathname.new(dir)).to_s }
226
+
227
+ if !new_migrations.empty?
228
+ options = { "Yes" => :yes, "No" => :no }
229
+
230
+ choice = UI.select(<<~TEXT, options.keys)
231
+ Would you like to upload and run the following pending theme migration(s): #{new_migrations.join(", ")}
232
+ TEXT
233
+
234
+ if options[choice] == :no
235
+ UI.warn "Pending theme migrations have not been uploaded, run `discourse_theme upload #{dir}` if you wish to upload and run the theme migrations."
236
+ new_migrations
237
+ else
238
+ []
239
+ end
240
+ else
241
+ []
242
+ end
243
+ end
244
+
203
245
  def command?(cmd)
204
246
  exts = ENV["PATHEXT"] ? ENV["PATHEXT"].split(";") : [""]
205
247
  ENV["PATH"]
@@ -28,6 +28,10 @@ module DiscourseTheme
28
28
  puts @@pastel.red("✘ #{message}")
29
29
  end
30
30
 
31
+ def self.warn(message)
32
+ puts @@pastel.yellow("⚠ #{message}")
33
+ end
34
+
31
35
  def self.success(message)
32
36
  puts @@pastel.green("✔ #{message}")
33
37
  end
@@ -1,6 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
  module DiscourseTheme
3
3
  class Uploader
4
+ def self.upload_full_theme_callbacks
5
+ @upload_callbacks ||= []
6
+ end
7
+
8
+ # Used in the test environment to register a callback that is called with the directory of the theme being uploaded.
9
+ def self.register_upload_full_theme_callback(&block)
10
+ self.upload_full_theme_callbacks << block
11
+ end
12
+
13
+ # Used in the test environment to clear the registered callbacks.
14
+ def self.reset_upload_full_theme_callbacks
15
+ self.upload_full_theme_callbacks.clear
16
+ end
17
+
4
18
  def initialize(dir:, client:, theme_id: nil, components: nil)
5
19
  @dir = dir
6
20
  @client = client
@@ -53,9 +67,24 @@ module DiscourseTheme
53
67
  UI.error "(end of errors)" if diagnose_errors(json) != 0
54
68
  end
55
69
 
56
- def upload_full_theme
70
+ def upload_full_theme(ignore_files: [])
57
71
  filename = "#{Pathname.new(Dir.tmpdir).realpath}/bundle_#{SecureRandom.hex}.tar.gz"
58
- compress_dir(filename, @dir)
72
+ temp_dir = nil
73
+
74
+ theme_dir =
75
+ if !ignore_files.empty?
76
+ temp_dir = Dir.mktmpdir
77
+ FileUtils.copy_entry(@dir, temp_dir)
78
+ dir_pathname = Pathname.new(@dir)
79
+ ignore_files.each { |file| FileUtils.rm_f(File.join(temp_dir, file)) }
80
+ temp_dir
81
+ else
82
+ @dir
83
+ end
84
+
85
+ self.class.upload_full_theme_callbacks.each { |cb| cb.call(theme_dir) }
86
+
87
+ compress_dir(filename, theme_dir)
59
88
 
60
89
  File.open(filename) do |tgz|
61
90
  response = @client.upload_full_theme(tgz, theme_id: @theme_id, components: @components)
@@ -66,7 +95,8 @@ module DiscourseTheme
66
95
  @theme_id
67
96
  end
68
97
  ensure
69
- FileUtils.rm_f filename
98
+ FileUtils.rm_rf(temp_dir) if temp_dir
99
+ FileUtils.rm_f(filename)
70
100
  end
71
101
  end
72
102
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module DiscourseTheme
3
- VERSION = "1.0.2"
3
+ VERSION = "1.1.0"
4
4
  end
@@ -1,14 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
  module DiscourseTheme
3
3
  class Watcher
4
+ LISTEN_IGNORE_PATTERNS = [%r{migrations/.+/.+\.js}]
5
+
4
6
  def self.return_immediately!
5
7
  @return_immediately = true
6
8
  end
7
9
 
10
+ def self.return_immediately=(val)
11
+ @return_immediately = val
12
+ end
13
+
8
14
  def self.return_immediately?
9
15
  !!@return_immediately
10
16
  end
11
17
 
18
+ def self.subscribe_start(&block)
19
+ @subscribers ||= []
20
+ @subscribers << block
21
+ end
22
+
23
+ def self.call_start_subscribers
24
+ @subscribers&.each(&:call)
25
+ end
26
+
27
+ def self.reset_start_subscribers
28
+ @subscribers = []
29
+ end
30
+
12
31
  def initialize(dir:, uploader:)
13
32
  @dir = dir
14
33
  @uploader = uploader
@@ -16,7 +35,9 @@ module DiscourseTheme
16
35
 
17
36
  def watch
18
37
  listener =
19
- Listen.to(@dir) do |modified, added, removed|
38
+ Listen.to(@dir, ignore: LISTEN_IGNORE_PATTERNS) do |modified, added, removed|
39
+ yield(modified, added, removed) if block_given?
40
+
20
41
  begin
21
42
  if modified.length == 1 && added.length == 0 && removed.length == 0 &&
22
43
  (resolved = resolve_file(modified[0]))
@@ -31,12 +52,14 @@ module DiscourseTheme
31
52
  )
32
53
  else
33
54
  count = modified.length + added.length + removed.length
55
+
34
56
  if count > 1
35
57
  UI.progress "Detected changes in #{count} files, uploading theme"
36
58
  else
37
59
  filename = modified[0] || added[0] || removed[0]
38
60
  UI.progress "Detected changes in #{filename.gsub(@dir, "")}, uploading theme"
39
61
  end
62
+
40
63
  @uploader.upload_full_theme
41
64
  end
42
65
  UI.success "Done! Watching for changes..."
@@ -47,7 +70,8 @@ module DiscourseTheme
47
70
  end
48
71
 
49
72
  listener.start
50
- sleep unless self.class.return_immediately?
73
+ self.class.call_start_subscribers
74
+ sleep 1 while !self.class.return_immediately?
51
75
  end
52
76
 
53
77
  protected
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: discourse_theme
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Saffron
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-12-08 00:00:00.000000000 Z
11
+ date: 2024-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitar