discourse_theme 1.1.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +30 -13
- data/.streerc +1 -1
- data/CHANGELOG.md +17 -0
- data/README.md +1 -1
- data/bin/discourse_theme +1 -1
- data/discourse_theme.gemspec +2 -4
- data/lib/discourse_theme/cli.rb +22 -21
- data/lib/discourse_theme/cli_commands/rspec.rb +1 -1
- data/lib/discourse_theme/client.rb +10 -8
- data/lib/discourse_theme/scaffold.rb +83 -131
- data/lib/discourse_theme/uploader.rb +9 -32
- data/lib/discourse_theme/version.rb +1 -1
- data/lib/discourse_theme/watcher.rb +3 -25
- metadata +12 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 202bc4483d1d73df24eb1674c2d2e1f8920c3f73a7ffbf6d0a69d0fd9bc0fce8
|
4
|
+
data.tar.gz: 47e22597abb662a1fff0ba8f1678ea7533d8daa84eb63879d9dcb2c8a79e8dbf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 14f195165983249d04b48c8e80427176ba1d673541fb87054a9e1f24f64e8f59897d88e2b11612be93996aee9c6122d6772ce141485674167cf793a8c41bb818
|
7
|
+
data.tar.gz: 2b6c59248aaac23b12744c89eb83ee886326cbff563a8156cba494e372c9b5b3ccf5cd2ede58c193ae0acb17c72ebeeafec10f35767448bb3e91d64029107c37
|
data/.github/workflows/ci.yml
CHANGED
@@ -7,46 +7,63 @@ on:
|
|
7
7
|
- main
|
8
8
|
|
9
9
|
jobs:
|
10
|
-
|
10
|
+
lint:
|
11
11
|
runs-on: ubuntu-latest
|
12
12
|
|
13
|
-
strategy:
|
14
|
-
matrix:
|
15
|
-
ruby:
|
16
|
-
- "3.0"
|
17
|
-
- "3.1"
|
18
|
-
- "3.2"
|
19
|
-
|
20
13
|
steps:
|
21
|
-
- uses: actions/checkout@
|
14
|
+
- uses: actions/checkout@v4
|
22
15
|
|
23
16
|
- name: Setup ruby
|
24
17
|
uses: ruby/setup-ruby@v1
|
25
18
|
with:
|
26
|
-
ruby-version:
|
19
|
+
ruby-version: "3.3"
|
27
20
|
bundler-cache: true
|
28
21
|
|
29
22
|
- name: Lint
|
30
23
|
run: bundle exec rubocop
|
31
24
|
|
32
25
|
- name: syntax_tree
|
26
|
+
if: ${{ !cancelled() }}
|
33
27
|
run: |
|
34
28
|
bundle exec stree check Gemfile $(git ls-files '*.rb') $(git ls-files '*.rake') $(git ls-files '*.thor')
|
35
29
|
|
30
|
+
test:
|
31
|
+
runs-on: ubuntu-latest
|
32
|
+
|
33
|
+
strategy:
|
34
|
+
matrix:
|
35
|
+
ruby:
|
36
|
+
- "3.1"
|
37
|
+
- "3.2"
|
38
|
+
- "3.3"
|
39
|
+
|
40
|
+
steps:
|
41
|
+
- uses: actions/checkout@v4
|
42
|
+
|
43
|
+
- name: Setup Git
|
44
|
+
run: |
|
45
|
+
git config --global user.email "ci@ci.invalid"
|
46
|
+
git config --global user.name "Discourse CI"
|
47
|
+
|
48
|
+
- name: Setup ruby
|
49
|
+
uses: ruby/setup-ruby@v1
|
50
|
+
with:
|
51
|
+
ruby-version: ${{ matrix.ruby }}
|
52
|
+
bundler-cache: true
|
36
53
|
|
37
54
|
- name: Tests
|
38
55
|
run: bundle exec rake test
|
39
56
|
|
40
57
|
publish:
|
41
58
|
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
42
|
-
needs:
|
59
|
+
needs: [lint, test]
|
43
60
|
runs-on: ubuntu-latest
|
44
61
|
|
45
62
|
steps:
|
46
|
-
- uses: actions/checkout@
|
63
|
+
- uses: actions/checkout@v4
|
47
64
|
|
48
65
|
- name: Release Gem
|
49
|
-
uses: discourse/publish-rubygems-action@
|
66
|
+
uses: discourse/publish-rubygems-action@v3
|
50
67
|
env:
|
51
68
|
RUBYGEMS_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }}
|
52
69
|
GIT_EMAIL: team@discourse.org
|
data/.streerc
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
--print-width=100
|
2
|
-
--plugins=plugin/trailing_comma,
|
2
|
+
--plugins=plugin/trailing_comma,plugin/disable_auto_ternary
|
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,23 @@ 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
|
+
## [2.1.0] - 2024-02-28
|
9
|
+
|
10
|
+
### Changed
|
11
|
+
|
12
|
+
- `new` command now uses discourse-theme-skeleton repo (#44)
|
13
|
+
|
14
|
+
## [2.0.0] - 2024-01-31
|
15
|
+
|
16
|
+
### Added
|
17
|
+
|
18
|
+
- `watch` command for `discourse_theme` will prompt user if pending theme migrations should be run (#40)
|
19
|
+
|
20
|
+
### Removed
|
21
|
+
|
22
|
+
- Remove upload theme migrations prompt to `watch` command for `discourse_theme` CLI previously added in #38. Theme migrations
|
23
|
+
files are always uploaded going forward.
|
24
|
+
|
8
25
|
## [1.1.0] - 2024-01-10
|
9
26
|
|
10
27
|
### Added
|
data/README.md
CHANGED
@@ -45,7 +45,7 @@ On the first run for the given directory, you will be asked if you'll like to us
|
|
45
45
|
If you select 'Y' and proceeds to configure the path to the local Discourse repository, the tests will be ran using the local Discourse development environment provided by the local Discourse repository. Note that you'll have to set up the local test environment before
|
46
46
|
the tests can be ran successfully.
|
47
47
|
|
48
|
-
If the 'n' option is selected, the tests will run in a Docker container created using the [`discourse/
|
48
|
+
If the 'n' option is selected, the tests will run in a Docker container created using the [`discourse/discourse_test:release`](https://hub.docker.com/r/discourse/discourse_test) Docker image. Note that this requires [Docker](https://docs.docker.com/engine/install/) to be installed.
|
49
49
|
|
50
50
|
When the `--headless` option is used, a local installation of the [Google Chrome browser](https://www.google.com/chrome/) is required.
|
51
51
|
|
data/bin/discourse_theme
CHANGED
data/discourse_theme.gemspec
CHANGED
@@ -27,7 +27,7 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.add_runtime_dependency "listen", "~> 3.1"
|
28
28
|
spec.add_runtime_dependency "multipart-post", "~> 2.0"
|
29
29
|
spec.add_runtime_dependency "tty-prompt", "~> 0.18"
|
30
|
-
spec.add_runtime_dependency "rubyzip", "~>
|
30
|
+
spec.add_runtime_dependency "rubyzip", "~> 2.3"
|
31
31
|
spec.add_runtime_dependency "selenium-webdriver", "> 4.11"
|
32
32
|
|
33
33
|
spec.add_development_dependency "bundler"
|
@@ -36,10 +36,8 @@ Gem::Specification.new do |spec|
|
|
36
36
|
spec.add_development_dependency "guard"
|
37
37
|
spec.add_development_dependency "guard-minitest"
|
38
38
|
spec.add_development_dependency "webmock"
|
39
|
-
spec.add_development_dependency "rubocop"
|
40
|
-
spec.add_development_dependency "rubocop-discourse"
|
39
|
+
spec.add_development_dependency "rubocop-discourse", "~> 3.6.0"
|
41
40
|
spec.add_development_dependency "m"
|
42
41
|
spec.add_development_dependency "syntax_tree"
|
43
|
-
spec.add_development_dependency "syntax_tree-disable_ternary"
|
44
42
|
spec.add_development_dependency "mocha"
|
45
43
|
end
|
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)
|
40
40
|
usage unless args[1]
|
41
41
|
|
42
42
|
reset = !!args.delete("--reset")
|
@@ -57,7 +57,7 @@ module DiscourseTheme
|
|
57
57
|
raise DiscourseTheme::ThemeError.new "git is not installed" if !command?("git")
|
58
58
|
raise DiscourseTheme::ThemeError.new "yarn is not installed" if !command?("yarn")
|
59
59
|
|
60
|
-
DiscourseTheme::Scaffold.generate(dir)
|
60
|
+
DiscourseTheme::Scaffold.generate(dir, name: args[1])
|
61
61
|
watch_theme?(args)
|
62
62
|
elsif command == "watch"
|
63
63
|
raise DiscourseTheme::ThemeError.new "'#{dir} does not exist" unless Dir.exist?(dir)
|
@@ -116,7 +116,7 @@ module DiscourseTheme
|
|
116
116
|
UI.progress "Uploading theme from #{dir}"
|
117
117
|
|
118
118
|
settings.theme_id =
|
119
|
-
theme_id = uploader.upload_full_theme(
|
119
|
+
theme_id = uploader.upload_full_theme(skip_migrations: skip_migrations(theme, dir))
|
120
120
|
|
121
121
|
UI.success "Theme uploaded (id:#{theme_id})"
|
122
122
|
UI.info "Preview: #{client.url}/?preview_theme_id=#{theme_id}"
|
@@ -131,7 +131,7 @@ module DiscourseTheme
|
|
131
131
|
|
132
132
|
watcher = DiscourseTheme::Watcher.new(dir: dir, uploader: uploader)
|
133
133
|
UI.progress "Watching for changes in #{dir}..."
|
134
|
-
watcher.watch
|
134
|
+
watcher.watch
|
135
135
|
elsif command == "download"
|
136
136
|
client = DiscourseTheme::Client.new(dir, settings, reset: reset)
|
137
137
|
downloader = DiscourseTheme::Downloader.new(dir: dir, client: client)
|
@@ -205,40 +205,41 @@ module DiscourseTheme
|
|
205
205
|
|
206
206
|
private
|
207
207
|
|
208
|
-
def
|
209
|
-
return
|
208
|
+
def skip_migrations(theme, dir)
|
209
|
+
return true unless theme && Dir.exist?(File.join(dir, "migrations"))
|
210
210
|
|
211
|
-
|
211
|
+
migrated_migrations =
|
212
212
|
theme
|
213
213
|
.dig("theme_fields")
|
214
214
|
&.filter_map do |theme_field|
|
215
|
-
theme_field["
|
215
|
+
if theme_field["target"] == "migrations" && theme_field["migrated"] == true
|
216
|
+
theme_field["name"]
|
217
|
+
end
|
216
218
|
end || []
|
217
219
|
|
218
|
-
|
220
|
+
pending_migrations =
|
219
221
|
Dir["#{dir}/migrations/**/*.js"]
|
220
222
|
.reject do |f|
|
221
|
-
|
223
|
+
migrated_migrations.any? do |existing_migration|
|
222
224
|
File.basename(f).include?(existing_migration)
|
223
225
|
end
|
224
226
|
end
|
225
227
|
.map { |f| Pathname.new(f).relative_path_from(Pathname.new(dir)).to_s }
|
226
228
|
|
227
|
-
if
|
228
|
-
|
229
|
+
return true if pending_migrations.empty?
|
230
|
+
|
231
|
+
options = { "No" => :no, "Yes" => :yes }
|
229
232
|
|
230
|
-
|
231
|
-
Would you like to
|
233
|
+
choice = UI.select(<<~TEXT, options.keys)
|
234
|
+
Would you like to run the following pending theme migration(s): #{pending_migrations.join(", ")}
|
235
|
+
Select 'No' if you are in the midst of adding or modifying theme migration(s).
|
232
236
|
TEXT
|
233
237
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
else
|
238
|
-
[]
|
239
|
-
end
|
238
|
+
if options[choice] == :no
|
239
|
+
UI.warn "Pending theme migrations have not been run, run `discourse_theme upload #{dir}` if you wish to run the theme migrations."
|
240
|
+
true
|
240
241
|
else
|
241
|
-
|
242
|
+
false
|
242
243
|
end
|
243
244
|
end
|
244
245
|
|
@@ -73,7 +73,7 @@ module DiscourseTheme
|
|
73
73
|
success = exit_status.success?
|
74
74
|
|
75
75
|
unless success
|
76
|
-
UI.error "Error
|
76
|
+
UI.error "Error occurred while running: `#{command}`:\n\n#{output}" unless stream
|
77
77
|
exit 1 if exit_on_error
|
78
78
|
end
|
79
79
|
end
|
@@ -84,7 +84,7 @@ module DiscourseTheme
|
|
84
84
|
request(put)
|
85
85
|
end
|
86
86
|
|
87
|
-
def upload_full_theme(tgz, theme_id:, components:)
|
87
|
+
def upload_full_theme(tgz, theme_id:, components:, skip_migrations: false)
|
88
88
|
endpoint =
|
89
89
|
root +
|
90
90
|
(
|
@@ -95,13 +95,15 @@ module DiscourseTheme
|
|
95
95
|
end
|
96
96
|
)
|
97
97
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
98
|
+
params = {
|
99
|
+
"theme_id" => theme_id,
|
100
|
+
"components" => components,
|
101
|
+
"bundle" => UploadIO.new(tgz, "application/tar+gzip", "bundle.tar.gz"),
|
102
|
+
}
|
103
|
+
|
104
|
+
params["skip_migrations"] = true if skip_migrations
|
105
|
+
|
106
|
+
post = Net::HTTP::Post::Multipart.new(endpoint, params)
|
105
107
|
request(post)
|
106
108
|
end
|
107
109
|
|
@@ -2,159 +2,111 @@
|
|
2
2
|
|
3
3
|
require "date"
|
4
4
|
require "json"
|
5
|
+
require "yaml"
|
6
|
+
require "resolv"
|
5
7
|
|
6
8
|
module DiscourseTheme
|
7
9
|
class Scaffold
|
8
|
-
|
9
|
-
about_url: "TODO: Put your theme's public repo or Meta topic URL here",
|
10
|
-
license_url: "TODO: Put your theme's LICENSE URL here",
|
11
|
-
assets: {
|
12
|
-
},
|
13
|
-
}
|
14
|
-
|
15
|
-
HELP = <<~STR
|
16
|
-
Are you a bit lost? Be sure to read https://meta.discourse.org/t/how-to-develop-custom-themes/60848
|
17
|
-
STR
|
18
|
-
|
19
|
-
LICENSE = <<~STR
|
20
|
-
Copyright #YEAR #AUTHOR
|
21
|
-
|
22
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
23
|
-
of this software and associated documentation files (the "Software"), to deal
|
24
|
-
in the Software without restriction, including without limitation the rights
|
25
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
26
|
-
copies of the Software, and to permit persons to whom the Software is
|
27
|
-
furnished to do so, subject to the following conditions:
|
28
|
-
|
29
|
-
The above copyright notice and this permission notice shall be included in all
|
30
|
-
copies or substantial portions of the Software.
|
31
|
-
|
32
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
33
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
34
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
35
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
36
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
37
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
38
|
-
SOFTWARE.
|
39
|
-
STR
|
40
|
-
|
41
|
-
GIT_IGNORE = <<~STR
|
42
|
-
.discourse-site
|
43
|
-
node_modules
|
44
|
-
HELP
|
45
|
-
STR
|
46
|
-
|
47
|
-
API_INITIALIZER = <<~STR
|
48
|
-
import { apiInitializer } from "discourse/lib/api";
|
49
|
-
|
50
|
-
export default apiInitializer("1.8.0", (api) => {
|
51
|
-
console.log("hello world from api initializer!");
|
52
|
-
});
|
53
|
-
STR
|
54
|
-
|
55
|
-
PACKAGE_JSON = <<~STR
|
56
|
-
{
|
57
|
-
"author": "#AUTHOR",
|
58
|
-
"license": "MIT",
|
59
|
-
"devDependencies": {
|
60
|
-
"eslint-config-discourse": "latest"
|
61
|
-
}
|
62
|
-
}
|
63
|
-
STR
|
64
|
-
|
65
|
-
ESLINT_RC = <<~STR
|
66
|
-
{
|
67
|
-
"extends": "eslint-config-discourse",
|
68
|
-
"globals": {
|
69
|
-
"settings": "readonly",
|
70
|
-
"themePrefix": "readonly"
|
71
|
-
}
|
72
|
-
}
|
73
|
-
STR
|
74
|
-
|
75
|
-
TEMPLATE_LINT_RC = <<~STR
|
76
|
-
module.exports = {
|
77
|
-
plugins: ["ember-template-lint-plugin-discourse"],
|
78
|
-
extends: "discourse:recommended",
|
79
|
-
};
|
80
|
-
STR
|
81
|
-
|
82
|
-
EN_YML = <<~YAML
|
83
|
-
en:
|
84
|
-
theme_metadata:
|
85
|
-
description: "#DESCRIPTION"
|
86
|
-
YAML
|
87
|
-
|
88
|
-
SETTINGS_YML = <<~YAML
|
89
|
-
todo_rename_and_use_setting:
|
90
|
-
default: ""
|
91
|
-
YAML
|
92
|
-
|
93
|
-
def self.generate(dir)
|
10
|
+
def self.generate(dir, name:)
|
94
11
|
UI.progress "Generating a scaffold theme at #{dir}"
|
95
12
|
|
96
|
-
name =
|
97
|
-
loop do
|
98
|
-
input = UI.ask("What would you like to call your theme?").to_s.strip
|
99
|
-
if input.empty?
|
100
|
-
UI.error("Theme name cannot be empty")
|
101
|
-
else
|
102
|
-
break input
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
13
|
+
name = UI.ask("What would you like to call your theme?", default: name).to_s.strip
|
106
14
|
is_component = UI.yes?("Is this a component?")
|
107
15
|
|
108
|
-
|
109
|
-
Dir.chdir dir do
|
110
|
-
author =
|
111
|
-
loop do
|
112
|
-
input = UI.ask("Who is authoring the theme?", default: ENV["USER"]).to_s.strip
|
113
|
-
if input.empty?
|
114
|
-
UI.error("Author cannot be empty")
|
115
|
-
else
|
116
|
-
break input
|
117
|
-
end
|
118
|
-
end
|
16
|
+
get_theme_skeleton(dir)
|
119
17
|
|
18
|
+
Dir.chdir dir do
|
19
|
+
author = UI.ask("Who is authoring the theme?", default: "Discourse").to_s.strip
|
120
20
|
description = UI.ask("How would you describe this theme?").to_s.strip
|
121
21
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
22
|
+
about = JSON.parse(File.read("about.json"))
|
23
|
+
about["name"] = name
|
24
|
+
about["authors"] = author
|
25
|
+
if !is_component
|
26
|
+
about.delete("component")
|
27
|
+
about["color_schemes"] = {}
|
128
28
|
end
|
29
|
+
File.write("about.json", JSON.pretty_generate(about))
|
30
|
+
|
31
|
+
if author != "Discourse"
|
32
|
+
license = File.read("LICENSE")
|
33
|
+
license.sub!(/^(Copyright\s\(c\))\s(.+)/, "\\1 #{author}")
|
34
|
+
File.write("LICENSE", license)
|
35
|
+
end
|
36
|
+
|
37
|
+
readme = File.read("README.md")
|
38
|
+
readme.sub!("**Theme Name**", name)
|
39
|
+
File.write("README.md", readme)
|
129
40
|
|
130
|
-
encoded_name = name.downcase.gsub(/[^a-zA-Z0-9_-]+/, "
|
41
|
+
encoded_name = name.downcase.gsub(/[^a-zA-Z0-9_-]+/, "-")
|
42
|
+
FileUtils.mv(
|
43
|
+
"javascripts/discourse/api-initializers/todo.js",
|
44
|
+
"javascripts/discourse/api-initializers/#{encoded_name}.js",
|
45
|
+
)
|
131
46
|
|
132
|
-
|
133
|
-
|
134
|
-
write("
|
135
|
-
write(".eslintrc", ESLINT_RC)
|
136
|
-
write(".gitignore", GIT_IGNORE)
|
137
|
-
write(".template-lintrc.js", TEMPLATE_LINT_RC)
|
138
|
-
write("package.json", PACKAGE_JSON.sub("#AUTHOR", author))
|
139
|
-
write("settings.yml", SETTINGS_YML)
|
140
|
-
write("common/common.scss", "")
|
141
|
-
write("javascripts/discourse/api-initializers/#{encoded_name}.js", API_INITIALIZER)
|
142
|
-
write("locales/en.yml", EN_YML.sub("#DESCRIPTION", description))
|
47
|
+
i18n = YAML.safe_load(File.read("locales/en.yml"))
|
48
|
+
i18n["en"]["theme_metadata"]["description"] = description
|
49
|
+
File.write("locales/en.yml", YAML.safe_dump(i18n).sub(/\A---\n/, ""))
|
143
50
|
|
144
51
|
UI.info "Initializing git repo"
|
145
|
-
|
52
|
+
FileUtils.rm_rf(".git")
|
53
|
+
FileUtils.rm_rf("**/.gitkeep")
|
54
|
+
system "git", "init", exception: true
|
55
|
+
system "git", "symbolic-ref", "HEAD", "refs/heads/main", exception: true
|
56
|
+
root_files = Dir.glob("*").select { |f| File.file?(f) }
|
57
|
+
system "git", "add", *root_files, exception: true
|
58
|
+
system "git", "add", ".*", exception: true
|
59
|
+
system "git", "add", "locales", exception: true
|
60
|
+
system "git",
|
61
|
+
"commit",
|
62
|
+
"-m",
|
63
|
+
"Initial commit by `discourse_theme` CLI",
|
64
|
+
"--quiet",
|
65
|
+
exception: true
|
146
66
|
|
147
67
|
UI.info "Installing dependencies"
|
148
|
-
|
68
|
+
system "yarn", exception: true
|
149
69
|
end
|
70
|
+
|
71
|
+
puts "✅ Done!"
|
72
|
+
puts "See https://meta.discourse.org/t/how-to-develop-custom-themes/60848 for more information!"
|
150
73
|
end
|
151
74
|
|
152
75
|
private
|
153
76
|
|
154
|
-
def self.
|
155
|
-
|
156
|
-
|
157
|
-
|
77
|
+
def self.get_theme_skeleton(dir)
|
78
|
+
if online?
|
79
|
+
puts "Downloading discourse-theme-skeleton"
|
80
|
+
tmp = Dir.mktmpdir
|
81
|
+
system "git",
|
82
|
+
"clone",
|
83
|
+
"https://github.com/discourse/discourse-theme-skeleton",
|
84
|
+
tmp,
|
85
|
+
"--depth",
|
86
|
+
"1",
|
87
|
+
"--quiet",
|
88
|
+
exception: true
|
89
|
+
FileUtils.rm_rf(skeleton_dir)
|
90
|
+
# Store the local copy for offline use
|
91
|
+
FileUtils.cp_r(tmp, skeleton_dir)
|
92
|
+
|
93
|
+
FileUtils.cp_r(skeleton_dir, dir)
|
94
|
+
elsif Dir.exist?(skeleton_dir)
|
95
|
+
puts "⚠️ No internet connection detected, using the local copy of discourse-theme-skeleton"
|
96
|
+
FileUtils.cp_r(skeleton_dir, dir)
|
97
|
+
else
|
98
|
+
raise "🛑 Couldn't download discourse-theme-skeleton"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.online?
|
103
|
+
!!Resolv::DNS.new.getaddress("github.com")
|
104
|
+
rescue Resolv::ResolvError => e
|
105
|
+
false
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.skeleton_dir
|
109
|
+
File.expand_path("~/.discourse_theme_skeleton")
|
158
110
|
end
|
159
111
|
end
|
160
112
|
end
|
@@ -1,20 +1,6 @@
|
|
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
|
-
|
18
4
|
def initialize(dir:, client:, theme_id: nil, components: nil)
|
19
5
|
@dir = dir
|
20
6
|
@client = client
|
@@ -67,27 +53,19 @@ module DiscourseTheme
|
|
67
53
|
UI.error "(end of errors)" if diagnose_errors(json) != 0
|
68
54
|
end
|
69
55
|
|
70
|
-
def upload_full_theme(
|
56
|
+
def upload_full_theme(skip_migrations: false)
|
71
57
|
filename = "#{Pathname.new(Dir.tmpdir).realpath}/bundle_#{SecureRandom.hex}.tar.gz"
|
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
58
|
|
87
|
-
compress_dir(filename,
|
59
|
+
compress_dir(filename, @dir)
|
88
60
|
|
89
61
|
File.open(filename) do |tgz|
|
90
|
-
response =
|
62
|
+
response =
|
63
|
+
@client.upload_full_theme(
|
64
|
+
tgz,
|
65
|
+
theme_id: @theme_id,
|
66
|
+
components: @components,
|
67
|
+
skip_migrations: skip_migrations,
|
68
|
+
)
|
91
69
|
|
92
70
|
json = JSON.parse(response.body)
|
93
71
|
@theme_id = json["theme"]["id"]
|
@@ -95,7 +73,6 @@ module DiscourseTheme
|
|
95
73
|
@theme_id
|
96
74
|
end
|
97
75
|
ensure
|
98
|
-
FileUtils.rm_rf(temp_dir) if temp_dir
|
99
76
|
FileUtils.rm_f(filename)
|
100
77
|
end
|
101
78
|
end
|
@@ -1,33 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module DiscourseTheme
|
3
3
|
class Watcher
|
4
|
-
LISTEN_IGNORE_PATTERNS = [%r{migrations/.+/.+\.js}]
|
5
|
-
|
6
4
|
def self.return_immediately!
|
7
5
|
@return_immediately = true
|
8
6
|
end
|
9
7
|
|
10
|
-
def self.return_immediately=(val)
|
11
|
-
@return_immediately = val
|
12
|
-
end
|
13
|
-
|
14
8
|
def self.return_immediately?
|
15
9
|
!!@return_immediately
|
16
10
|
end
|
17
11
|
|
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
|
-
|
31
12
|
def initialize(dir:, uploader:)
|
32
13
|
@dir = dir
|
33
14
|
@uploader = uploader
|
@@ -35,9 +16,7 @@ module DiscourseTheme
|
|
35
16
|
|
36
17
|
def watch
|
37
18
|
listener =
|
38
|
-
Listen.to(@dir
|
39
|
-
yield(modified, added, removed) if block_given?
|
40
|
-
|
19
|
+
Listen.to(@dir) do |modified, added, removed|
|
41
20
|
begin
|
42
21
|
if modified.length == 1 && added.length == 0 && removed.length == 0 &&
|
43
22
|
(resolved = resolve_file(modified[0]))
|
@@ -60,7 +39,7 @@ module DiscourseTheme
|
|
60
39
|
UI.progress "Detected changes in #{filename.gsub(@dir, "")}, uploading theme"
|
61
40
|
end
|
62
41
|
|
63
|
-
@uploader.upload_full_theme
|
42
|
+
@uploader.upload_full_theme(skip_migrations: true)
|
64
43
|
end
|
65
44
|
UI.success "Done! Watching for changes..."
|
66
45
|
rescue DiscourseTheme::ThemeError => e
|
@@ -70,8 +49,7 @@ module DiscourseTheme
|
|
70
49
|
end
|
71
50
|
|
72
51
|
listener.start
|
73
|
-
self.class.
|
74
|
-
sleep 1 while !self.class.return_immediately?
|
52
|
+
sleep if !self.class.return_immediately?
|
75
53
|
end
|
76
54
|
|
77
55
|
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:
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sam Saffron
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-02-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitar
|
@@ -72,14 +72,14 @@ dependencies:
|
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
75
|
+
version: '2.3'
|
76
76
|
type: :runtime
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
82
|
+
version: '2.3'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: selenium-webdriver
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -178,34 +178,20 @@ dependencies:
|
|
178
178
|
- - ">="
|
179
179
|
- !ruby/object:Gem::Version
|
180
180
|
version: '0'
|
181
|
-
- !ruby/object:Gem::Dependency
|
182
|
-
name: rubocop
|
183
|
-
requirement: !ruby/object:Gem::Requirement
|
184
|
-
requirements:
|
185
|
-
- - ">="
|
186
|
-
- !ruby/object:Gem::Version
|
187
|
-
version: '0'
|
188
|
-
type: :development
|
189
|
-
prerelease: false
|
190
|
-
version_requirements: !ruby/object:Gem::Requirement
|
191
|
-
requirements:
|
192
|
-
- - ">="
|
193
|
-
- !ruby/object:Gem::Version
|
194
|
-
version: '0'
|
195
181
|
- !ruby/object:Gem::Dependency
|
196
182
|
name: rubocop-discourse
|
197
183
|
requirement: !ruby/object:Gem::Requirement
|
198
184
|
requirements:
|
199
|
-
- - "
|
185
|
+
- - "~>"
|
200
186
|
- !ruby/object:Gem::Version
|
201
|
-
version:
|
187
|
+
version: 3.6.0
|
202
188
|
type: :development
|
203
189
|
prerelease: false
|
204
190
|
version_requirements: !ruby/object:Gem::Requirement
|
205
191
|
requirements:
|
206
|
-
- - "
|
192
|
+
- - "~>"
|
207
193
|
- !ruby/object:Gem::Version
|
208
|
-
version:
|
194
|
+
version: 3.6.0
|
209
195
|
- !ruby/object:Gem::Dependency
|
210
196
|
name: m
|
211
197
|
requirement: !ruby/object:Gem::Requirement
|
@@ -234,20 +220,6 @@ dependencies:
|
|
234
220
|
- - ">="
|
235
221
|
- !ruby/object:Gem::Version
|
236
222
|
version: '0'
|
237
|
-
- !ruby/object:Gem::Dependency
|
238
|
-
name: syntax_tree-disable_ternary
|
239
|
-
requirement: !ruby/object:Gem::Requirement
|
240
|
-
requirements:
|
241
|
-
- - ">="
|
242
|
-
- !ruby/object:Gem::Version
|
243
|
-
version: '0'
|
244
|
-
type: :development
|
245
|
-
prerelease: false
|
246
|
-
version_requirements: !ruby/object:Gem::Requirement
|
247
|
-
requirements:
|
248
|
-
- - ">="
|
249
|
-
- !ruby/object:Gem::Version
|
250
|
-
version: '0'
|
251
223
|
- !ruby/object:Gem::Dependency
|
252
224
|
name: mocha
|
253
225
|
requirement: !ruby/object:Gem::Requirement
|
@@ -298,7 +270,7 @@ homepage: https://github.com/discourse/discourse_theme
|
|
298
270
|
licenses:
|
299
271
|
- MIT
|
300
272
|
metadata: {}
|
301
|
-
post_install_message:
|
273
|
+
post_install_message:
|
302
274
|
rdoc_options: []
|
303
275
|
require_paths:
|
304
276
|
- lib
|
@@ -313,8 +285,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
313
285
|
- !ruby/object:Gem::Version
|
314
286
|
version: '0'
|
315
287
|
requirements: []
|
316
|
-
rubygems_version: 3.
|
317
|
-
signing_key:
|
288
|
+
rubygems_version: 3.5.3
|
289
|
+
signing_key:
|
318
290
|
specification_version: 4
|
319
291
|
summary: CLI helper for creating Discourse themes
|
320
292
|
test_files: []
|