discourse_theme 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -1
- data/lib/discourse_theme/cli.rb +45 -3
- data/lib/discourse_theme/cli_commands/rspec.rb +6 -6
- data/lib/discourse_theme/ui.rb +4 -0
- data/lib/discourse_theme/uploader.rb +33 -3
- data/lib/discourse_theme/version.rb +1 -1
- data/lib/discourse_theme/watcher.rb +26 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1e3352f4282ac30c46402e5cdf6f7c9ba504e7c8b5980884e4a42b700eef3e90
|
4
|
+
data.tar.gz: b13f657e0e023c3a6bee4eca8dc3a9090c55333f444bc5b9a55d67781baac017
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9900153835d064382bdde7fbd395345a66cdeb5bd4b5df85f825c2d8ac12556bc4c329d56bd91030a5efae836c567db79ab219d7276d3e5cef784e51aedeba82
|
7
|
+
data.tar.gz: 26aec19d02acf892b7f5434ec7f141c1afa7e3d8e099917e40d15cafa6d8a2ff27a7076769eaa6319b44d0d46a4561d12374fa295929b140e2e0938789334792
|
data/CHANGELOG.md
CHANGED
@@ -5,9 +5,22 @@ 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
|
+
|
14
|
+
## [1.0.2] - 2023-12-08
|
15
|
+
|
16
|
+
### Fixed
|
17
|
+
|
18
|
+
- `discourse_theme rspec` command using Docker container not copying theme to the right directory that is mounted inside
|
19
|
+
the Docker container.
|
20
|
+
|
8
21
|
## [1.0.1] - 2023-10-19
|
9
22
|
|
10
|
-
|
23
|
+
### Fixed
|
11
24
|
|
12
25
|
- Spec path was not preserved when running rspec against a local Discourse repository.
|
13
26
|
|
data/lib/discourse_theme/cli.rb
CHANGED
@@ -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
|
-
|
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"]
|
@@ -37,7 +37,7 @@ module DiscourseTheme
|
|
37
37
|
|
38
38
|
if settings.local_discourse_directory.empty?
|
39
39
|
run_tests_with_docker(
|
40
|
-
|
40
|
+
dir,
|
41
41
|
spec_directory,
|
42
42
|
spec_path,
|
43
43
|
headless: headless,
|
@@ -93,13 +93,15 @@ module DiscourseTheme
|
|
93
93
|
end
|
94
94
|
|
95
95
|
def run_tests_with_docker(
|
96
|
-
|
96
|
+
theme_directory,
|
97
97
|
spec_directory,
|
98
98
|
spec_path,
|
99
99
|
headless: false,
|
100
100
|
verbose: false,
|
101
101
|
rebuild: false
|
102
102
|
)
|
103
|
+
theme_directory_name = File.basename(theme_directory)
|
104
|
+
|
103
105
|
image = "discourse/discourse_test:release"
|
104
106
|
UI.progress("Running RSpec tests using '#{image}' Docker image...")
|
105
107
|
|
@@ -191,9 +193,7 @@ module DiscourseTheme
|
|
191
193
|
rspec_envs = rspec_envs.map { |env| "-e #{env}" }.join(" ")
|
192
194
|
|
193
195
|
begin
|
194
|
-
|
195
|
-
FileUtils.mkdir_p(tmp_theme_directory) if !Dir.exist?(tmp_theme_directory)
|
196
|
-
FileUtils.cp_r(spec_directory, File.join(tmp_theme_directory))
|
196
|
+
FileUtils.cp_r(theme_directory, DISCOURSE_THEME_TEST_TMP_DIR)
|
197
197
|
|
198
198
|
execute(
|
199
199
|
command:
|
@@ -203,7 +203,7 @@ module DiscourseTheme
|
|
203
203
|
stream: true,
|
204
204
|
)
|
205
205
|
ensure
|
206
|
-
FileUtils.rm_rf(File.join(
|
206
|
+
FileUtils.rm_rf(File.join(DISCOURSE_THEME_TEST_TMP_DIR, theme_directory_name))
|
207
207
|
end
|
208
208
|
end
|
209
209
|
|
data/lib/discourse_theme/ui.rb
CHANGED
@@ -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
|
-
|
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.
|
98
|
+
FileUtils.rm_rf(temp_dir) if temp_dir
|
99
|
+
FileUtils.rm_f(filename)
|
70
100
|
end
|
71
101
|
end
|
72
102
|
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
|
-
|
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
|
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:
|
11
|
+
date: 2024-01-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitar
|