discourse_theme 0.3.4 → 0.5.1

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: 8fd5f66fdfa679cb8f4dc50546a4a3bf968de6b4718f64bb3ac96c0bbd614eda
4
- data.tar.gz: 9541e02e302a4d443c6a0c52b0a71b97aa1774c310c42f7f126a7940a7734615
3
+ metadata.gz: e820c35e9086c9f9e72fd374815e5514279db2ebb9609ef83482490313829586
4
+ data.tar.gz: 974908e9946ff58d402e94dbbf8bdb375f640c8fe017cbd091d397dc48771758
5
5
  SHA512:
6
- metadata.gz: 6c4a264ad197c92d762cf7b1e8f48fe60f865f6ea693ad0d52d4fd383a90465d3a81267804ab6af0f2c1d76852edb36198b6bb8bd99de38e3b30965bf7b2aeea
7
- data.tar.gz: 315305cdd465294a7904d77031a3bc76666566cd85b1fb93ecf0f63ae0602b4598feea964d017a53271cbb5791b75f5abc9cf811a19ed9f3a5bc178232342a0c
6
+ metadata.gz: d62b36ed3b6c05522af40b2ea7b88dee89b80b0a35262bd99cdecdb6f4dcd2330ba621b65603f703291b3322f73e9c1338f398c136db2c9453f9f76e1d5b2a88
7
+ data.tar.gz: 21c02268e21bb43a231ed0667ffdc4e9887b467f4da280fd02f63bf358ecad3be43972b69c9c98e8b179907d2b04b7e0ad3c409141f3935c920e43e061527088
@@ -1,21 +1,50 @@
1
1
  name: CI
2
2
 
3
3
  on:
4
+ pull_request:
4
5
  push:
5
6
  branches:
6
7
  - master
7
- tags:
8
- - v*
8
+ - main
9
9
 
10
10
  jobs:
11
+ build:
12
+ runs-on: ubuntu-latest
13
+
14
+ strategy:
15
+ matrix:
16
+ ruby:
17
+ - 2.5
18
+ - 2.6
19
+ - 2.7
20
+ - 3.0
21
+
22
+ steps:
23
+ - uses: actions/checkout@v2
24
+
25
+ - name: Setup ruby
26
+ uses: ruby/setup-ruby@v1
27
+ with:
28
+ ruby-version: ${{ matrix.ruby }}
29
+ bundler-cache: true
30
+
31
+ - name: Lint
32
+ run: bundle exec rubocop
33
+
34
+ - name: Tests
35
+ run: bundle exec rake test
36
+
11
37
  publish:
12
- if: contains(github.ref, 'refs/tags/v')
38
+ if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master')
39
+ needs: build
13
40
  runs-on: ubuntu-latest
14
41
 
15
42
  steps:
16
43
  - uses: actions/checkout@v2
17
44
 
18
45
  - name: Release Gem
19
- uses: CvX/publish-rubygems-action@master
46
+ uses: discourse/publish-rubygems-action@v2-beta
20
47
  env:
21
- RUBYGEMS_API_KEY: ${{secrets.RUBYGEMS_API_KEY}}
48
+ RUBYGEMS_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }}
49
+ GIT_EMAIL: team@discourse.org
50
+ GIT_NAME: discoursebot
data/.gitignore CHANGED
@@ -1,11 +1 @@
1
- /.bundle/
2
- /.yardoc
3
- /_yardoc/
4
- /coverage/
5
- /doc/
6
- /pkg/
7
- /spec/reports/
8
- /tmp/
9
1
  Gemfile.lock
10
-
11
- .rubocop-https---raw-githubusercontent-com-discourse-discourse-master--rubocop-yml
data/.rubocop.yml CHANGED
@@ -1 +1,7 @@
1
- inherit_from: https://raw.githubusercontent.com/discourse/discourse/master/.rubocop.yml
1
+ inherit_gem:
2
+ rubocop-discourse: default.yml
3
+ inherit_mode:
4
+ merge:
5
+ - Exclude
6
+ Discourse/NoChdir:
7
+ Enabled: false
data/Gemfile CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  source "https://rubygems.org"
2
3
 
3
4
  git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
data/Guardfile CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  directories %w(app lib test) \
2
3
  .select { |d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist") }
3
4
 
data/README.md CHANGED
@@ -20,11 +20,17 @@ For help run:
20
20
  discourse_theme
21
21
  ```
22
22
 
23
- it contains two helpers:
23
+ ### `discourse_theme new PATH`
24
24
 
25
- You can use `discourse_theme new PATH` to crate a new blank theme, the CLI will guide you through the process.
25
+ Creates a new blank theme. The CLI will guide you through the process.
26
26
 
27
- You can use `discourse_theme watch PATH` to monitor your theme or component for changes, when changed the program will synchronize the theme or component to your Discourse of choice.
27
+ ### `discourse_theme download PATH`
28
+
29
+ Downloads a theme from the server and stores in the designated directory.
30
+
31
+ ### `discourse_theme watch PATH`
32
+
33
+ Monitors a theme or component for changes. When changed the program will synchronize the theme or component to your Discourse of choice.
28
34
 
29
35
  ## Contributing
30
36
 
data/Rakefile CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "bundler/gem_tasks"
2
3
  require "rake/testtask"
3
4
 
data/bin/discourse_theme CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require_relative '../lib/discourse_theme'
4
5
 
@@ -23,18 +23,20 @@ Gem::Specification.new do |spec|
23
23
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
24
24
  spec.require_paths = ["lib"]
25
25
 
26
+ spec.required_ruby_version = '>= 2.5.0'
27
+
28
+ spec.add_runtime_dependency "minitar", "~> 0.6"
29
+ spec.add_runtime_dependency "listen", "~> 3.1"
30
+ spec.add_runtime_dependency "multipart-post", "~> 2.0"
31
+ spec.add_runtime_dependency "tty-prompt", "~> 0.18"
32
+ spec.add_runtime_dependency "rubyzip", "~> 1.2"
33
+
26
34
  spec.add_development_dependency "bundler", "~> 2.0"
27
- spec.add_development_dependency "rake", "~> 10.0"
35
+ spec.add_development_dependency "rake", "~> 13.0"
28
36
  spec.add_development_dependency "minitest", "~> 5.0"
29
37
  spec.add_development_dependency "guard", "~> 2.14"
30
38
  spec.add_development_dependency "guard-minitest", "~> 2.4"
31
39
  spec.add_development_dependency "webmock", "~> 3.5"
32
-
33
- spec.add_dependency "minitar", "~> 0.6"
34
- spec.add_dependency "listen", "~> 3.1"
35
- spec.add_dependency "multipart-post", "~> 2.0"
36
- spec.add_dependency "tty-prompt", "~> 0.18"
37
- spec.add_dependency "rubyzip", "~> 1.2"
38
-
39
- spec.required_ruby_version = '>= 2.2.0'
40
+ spec.add_development_dependency "rubocop"
41
+ spec.add_development_dependency "rubocop-discourse"
40
42
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'fileutils'
2
3
  require 'pathname'
3
4
  require 'tempfile'
@@ -15,6 +16,7 @@ require 'tty/prompt'
15
16
 
16
17
  require 'discourse_theme/version'
17
18
  require 'discourse_theme/config'
19
+ require 'discourse_theme/ui'
18
20
  require 'discourse_theme/cli'
19
21
  require 'discourse_theme/client'
20
22
  require 'discourse_theme/downloader'
@@ -1,45 +1,14 @@
1
+ # frozen_string_literal: true
1
2
  module DiscourseTheme
2
3
  class Cli
3
-
4
- @@prompt = ::TTY::Prompt.new(help_color: :cyan)
5
- @@pastel = Pastel.new
6
-
7
- def self.yes?(message)
8
- @@prompt.yes?(@@pastel.cyan("? ") + message)
9
- end
10
-
11
- def self.ask(message, default: nil)
12
- @@prompt.ask(@@pastel.cyan("? ") + message, default: default)
13
- end
14
-
15
- def self.select(message, options)
16
- @@prompt.select(@@pastel.cyan("? ") + message, options)
17
- end
18
-
19
- def self.info(message)
20
- puts @@pastel.blue("i ") + message
21
- end
22
-
23
- def self.progress(message)
24
- puts @@pastel.yellow("» ") + message
25
- end
26
-
27
- def self.error(message)
28
- puts @@pastel.red("✘ #{message}")
29
- end
30
-
31
- def self.success(message)
32
- puts @@pastel.green("✔ #{message}")
33
- end
34
-
35
4
  SETTINGS_FILE = File.expand_path("~/.discourse_theme")
36
5
 
37
6
  def usage
38
7
  puts "Usage: discourse_theme COMMAND [--reset]"
39
8
  puts
40
- puts "discourse_theme new DIR : Creates a new theme in the designated directory"
41
- puts "discourse_theme download DIR : Download a theme from the server, and store in the designated directory"
42
- puts "discourse_theme watch DIR : Watches the theme directory and synchronizes with Discourse"
9
+ puts "discourse_theme new DIR - Creates a new theme in the designated directory"
10
+ puts "discourse_theme download DIR - Downloads a theme from the server and stores in the designated directory"
11
+ puts "discourse_theme watch DIR - Watches the theme directory and synchronizes with Discourse"
43
12
  puts
44
13
  puts "Use --reset to change the configuration for a directory"
45
14
  exit 1
@@ -62,11 +31,7 @@ module DiscourseTheme
62
31
  if command == "new"
63
32
  raise DiscourseTheme::ThemeError.new "'#{dir} is not empty" if Dir.exists?(dir) && !Dir.empty?(dir)
64
33
  DiscourseTheme::Scaffold.generate(dir)
65
- if Cli.yes?("Would you like to start 'watching' this theme?")
66
- args[0] = "watch"
67
- Cli.progress "Running discourse_theme #{args.join(' ')}"
68
- run(args)
69
- end
34
+ watch_theme?(args)
70
35
  elsif command == "watch"
71
36
  raise DiscourseTheme::ThemeError.new "'#{dir} does not exist" unless Dir.exists?(dir)
72
37
  client = DiscourseTheme::Client.new(dir, settings, reset: reset)
@@ -80,37 +45,47 @@ module DiscourseTheme
80
45
  options["Create and sync with a new theme"] = :create
81
46
  options["Select a different theme"] = :select
82
47
 
83
- choice = Cli.select('How would you like to sync this theme?', options.keys)
48
+ choice = UI.select('How would you like to sync this theme?', options.keys)
84
49
 
85
50
  if options[choice] == :create
86
51
  theme_id = nil
87
52
  elsif options[choice] == :select
88
53
  themes = render_theme_list(theme_list)
89
- choice = Cli.select('Which theme would you like to sync with?', themes)
54
+ choice = UI.select('Which theme would you like to sync with?', themes)
90
55
  theme_id = extract_theme_id(choice)
91
56
  theme = theme_list.find { |t| t["id"] == theme_id }
92
57
  end
93
58
 
94
- if !theme || theme["component"] == false
59
+ about_json = JSON.parse(File.read(File.join(dir, 'about.json'))) rescue nil
60
+ already_uploaded = !!theme
61
+ is_component = theme&.[]("component")
62
+ component_count = about_json&.[]("components")&.length || 0
63
+
64
+ if !already_uploaded && !is_component && component_count > 0
95
65
  options = {}
96
66
  options["Yes"] = :sync
97
67
  options["No"] = :none
98
68
  options = options.sort_by { |_, b| b == components.to_sym ? 0 : 1 }.to_h if components
99
- choice = Cli.select('Would you like to update child theme components?', options.keys)
69
+ choice = UI.select('Would you like to update child theme components?', options.keys)
100
70
  settings.components = components = options[choice].to_s
101
71
  end
102
72
 
103
73
  uploader = DiscourseTheme::Uploader.new(dir: dir, client: client, theme_id: theme_id, components: components)
104
74
 
105
- Cli.progress "Uploading theme from #{dir}"
75
+ UI.progress "Uploading theme from #{dir}"
106
76
  settings.theme_id = theme_id = uploader.upload_full_theme
107
77
 
108
- Cli.success "Theme uploaded (id:#{theme_id})"
78
+ UI.success "Theme uploaded (id:#{theme_id})"
79
+ UI.info "Preview: #{client.root}/?preview_theme_id=#{theme_id}"
80
+ if client.is_theme_creator
81
+ UI.info "Manage: #{client.root}/my/themes"
82
+ else
83
+ UI.info "Manage: #{client.root}/admin/customize/themes/#{theme_id}"
84
+ end
109
85
  watcher = DiscourseTheme::Watcher.new(dir: dir, uploader: uploader)
110
86
 
111
- Cli.progress "Watching for changes in #{dir}..."
87
+ UI.progress "Watching for changes in #{dir}..."
112
88
  watcher.watch
113
-
114
89
  elsif command == "download"
115
90
  client = DiscourseTheme::Client.new(dir, settings, reset: reset)
116
91
  downloader = DiscourseTheme::Downloader.new(dir: dir, client: client)
@@ -118,33 +93,39 @@ module DiscourseTheme
118
93
  FileUtils.mkdir_p dir unless Dir.exists?(dir)
119
94
  raise DiscourseTheme::ThemeError.new "'#{dir} is not empty" unless Dir.empty?(dir)
120
95
 
121
- Cli.progress "Loading theme list..."
96
+ UI.progress "Loading theme list..."
122
97
  themes = render_theme_list(client.get_themes_list)
123
98
 
124
- choice = Cli.select('Which theme would you like to download?', themes)
99
+ choice = UI.select('Which theme would you like to download?', themes)
125
100
  theme_id = extract_theme_id(choice)
126
101
 
127
- Cli.progress "Downloading theme into #{dir}"
102
+ UI.progress "Downloading theme into #{dir}"
128
103
 
129
104
  downloader.download_theme(theme_id)
130
105
  settings.theme_id = theme_id
131
106
 
132
- Cli.success "Theme downloaded"
107
+ UI.success "Theme downloaded"
133
108
 
134
- if Cli.yes?("Would you like to start 'watching' this theme?")
135
- args[0] = "watch"
136
- Cli.progress "Running discourse_theme #{args.join(' ')}"
137
- run(args)
138
- end
109
+ watch_theme?(args)
139
110
  else
140
111
  usage
141
112
  end
142
113
 
143
- Cli.progress "Exiting..."
114
+ UI.progress "Exiting..."
144
115
  rescue DiscourseTheme::ThemeError => e
145
- Cli.error "#{e.message}"
116
+ UI.error "#{e.message}"
146
117
  rescue Interrupt, TTY::Reader::InputInterrupt => e
147
- Cli.error "Interrupted"
118
+ UI.error "Interrupted"
119
+ end
120
+
121
+ private
122
+
123
+ def watch_theme?(args)
124
+ if UI.yes?("Would you like to start 'watching' this theme?")
125
+ args[0] = "watch"
126
+ UI.progress "Running discourse_theme #{args.join(' ')}"
127
+ run(args)
128
+ end
148
129
  end
149
130
 
150
131
  def render_theme_list(themes)
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module DiscourseTheme
2
3
  class Client
3
4
  THEME_CREATOR_REGEX = /^https:\/\/theme-creator.discourse.org$/i
@@ -13,8 +14,8 @@ module DiscourseTheme
13
14
  @is_theme_creator = !!(THEME_CREATOR_REGEX =~ @url)
14
15
 
15
16
  if !self.class.has_needed_version?(discourse_version, "2.3.0.beta1")
16
- Cli.info "discourse_theme is designed for Discourse 2.3.0.beta1 or above"
17
- Cli.info "download will not function, and syncing destination will be unpredictable"
17
+ UI.info "discourse_theme is designed for Discourse 2.3.0.beta1 or above"
18
+ UI.info "download will not function, and syncing destination will be unpredictable"
18
19
  end
19
20
  end
20
21
 
@@ -103,12 +104,16 @@ module DiscourseTheme
103
104
  json["about"]["version"]
104
105
  end
105
106
 
106
- private
107
-
108
107
  def root
109
108
  @url
110
109
  end
111
110
 
111
+ def is_theme_creator
112
+ @is_theme_creator
113
+ end
114
+
115
+ private
116
+
112
117
  def request(request, never_404: false)
113
118
  uri = URI.parse(@url)
114
119
  http = Net::HTTP.new(uri.host, uri.port)
@@ -137,26 +142,26 @@ module DiscourseTheme
137
142
  def guess_url(settings)
138
143
  url = ENV['DISCOURSE_URL']
139
144
  if url
140
- Cli.progress "Using #{url} from DISCOURSE_URL"
145
+ UI.progress "Using #{url} from DISCOURSE_URL"
141
146
  end
142
147
 
143
148
  if !url && settings.url
144
149
  url = settings.url
145
- Cli.progress "Using #{url} from #{DiscourseTheme::Cli::SETTINGS_FILE}"
150
+ UI.progress "Using #{url} from #{DiscourseTheme::Cli::SETTINGS_FILE}"
146
151
  end
147
152
 
148
153
  if !url || @reset
149
- url = Cli.ask("What is the root URL of your Discourse site?", default: url).strip
154
+ url = UI.ask("What is the root URL of your Discourse site?", default: url).strip
150
155
  url = "http://#{url}" unless url =~ /^https?:\/\//
151
156
 
152
157
  # maybe this is an HTTPS redirect
153
158
  uri = URI.parse(url)
154
159
  if URI::HTTP === uri && uri.port == 80 && is_https_redirect?(url)
155
- Cli.info "Detected that #{url} should be accessed over https"
160
+ UI.info "Detected that #{url} should be accessed over https"
156
161
  url = url.sub("http", "https")
157
162
  end
158
163
 
159
- if Cli.yes?("Would you like this site name stored in #{DiscourseTheme::Cli::SETTINGS_FILE}?")
164
+ if UI.yes?("Would you like this site name stored in #{DiscourseTheme::Cli::SETTINGS_FILE}?")
160
165
  settings.url = url
161
166
  else
162
167
  settings.url = nil
@@ -169,17 +174,17 @@ module DiscourseTheme
169
174
  def guess_api_key(settings)
170
175
  api_key = ENV['DISCOURSE_API_KEY']
171
176
  if api_key
172
- Cli.progress "Using api key from DISCOURSE_API_KEY"
177
+ UI.progress "Using api key from DISCOURSE_API_KEY"
173
178
  end
174
179
 
175
180
  if !api_key && settings.api_key
176
181
  api_key = settings.api_key
177
- Cli.progress "Using api key from #{DiscourseTheme::Cli::SETTINGS_FILE}"
182
+ UI.progress "Using api key from #{DiscourseTheme::Cli::SETTINGS_FILE}"
178
183
  end
179
184
 
180
185
  if !api_key || @reset
181
- api_key = Cli.ask("What is your API key?", default: api_key).strip
182
- if Cli.yes?("Would you like this API key stored in #{DiscourseTheme::Cli::SETTINGS_FILE}?")
186
+ api_key = UI.ask("What is your API key?", default: api_key).strip
187
+ if UI.yes?("Would you like this API key stored in #{DiscourseTheme::Cli::SETTINGS_FILE}?")
183
188
  settings.api_key = api_key
184
189
  else
185
190
  settings.api_key = nil
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class DiscourseTheme::Config
2
3
 
3
4
  class PathSetting
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'zip'
2
3
 
3
4
  class DiscourseTheme::Downloader
@@ -1,74 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
1
5
  module DiscourseTheme
2
6
  class Scaffold
3
7
 
4
8
  BLANK_FILES = %w{
5
9
  common/common.scss
6
- common/header.html
7
- common/after_header.html
8
- common/footer.html
9
- common/head_tag.html
10
- common/body_tag.html
11
- common/embedded.scss
12
-
13
- desktop/desktop.scss
14
- desktop/header.html
15
- desktop/after_header.html
16
- desktop/footer.html
17
- desktop/head_tag.html
18
- desktop/body_tag.html
19
-
20
- mobile/mobile.scss
21
- mobile/header.html
22
- mobile/after_header.html
23
- mobile/footer.html
24
- mobile/head_tag.html
25
- mobile/body_tag.html
26
-
27
- locales/en.yml
28
10
 
29
11
  settings.yml
30
12
  }
31
13
 
32
- ABOUT_JSON = <<~STR
33
- {
34
- "name": "#NAME#",
35
- "about_url": null,
36
- "license_url": null,
37
- "assets": {
38
- },
39
- "color_schemes": {
40
- }
14
+ ABOUT_JSON = {
15
+ about_url: nil,
16
+ license_url: nil,
17
+ assets: {}
41
18
  }
42
- STR
43
19
 
44
20
  HELP = <<~STR
45
21
  Are you a bit lost? Be sure to read https://meta.discourse.org/t/how-to-develop-custom-themes/60848
46
22
  STR
47
23
 
48
24
  GIT_IGNORE = <<~STR
49
- .discourse-site
50
- HELP
51
- STR
25
+ .discourse-site
26
+ node_modules
27
+ HELP
28
+ STR
29
+
30
+ API_INITIALIZER = <<~STR
31
+ import { apiInitializer } from "discourse/lib/api";
32
+
33
+ export default apiInitializer("0.11.1", api => {
34
+ console.log("hello world from api initializer!");
35
+ });
36
+ STR
37
+
38
+ PACKAGE_JSON = <<~STR
39
+ {
40
+ "author": "#AUTHOR",
41
+ "license": "MIT",
42
+ "devDependencies": {
43
+ "eslint-config-discourse": "latest"
44
+ }
45
+ }
46
+ STR
47
+
48
+ ESLINT_RC = <<~STR
49
+ {
50
+ "extends": "eslint-config-discourse"
51
+ }
52
+ STR
53
+
54
+ TEMPLATE_LINT_RC = <<~STR
55
+ module.exports = {
56
+ plugins: ["ember-template-lint-plugin-discourse"],
57
+ extends: "discourse:recommended",
58
+ };
59
+ STR
60
+
61
+ EN_YML = <<~YAML
62
+ en:
63
+ theme_metadata:
64
+ description: "#DESCRIPTION"
65
+ YAML
52
66
 
53
67
  def self.generate(dir)
54
- Cli.progress "Generating a scaffold theme at #{dir}"
68
+ UI.progress "Generating a scaffold theme at #{dir}"
55
69
 
56
- name = Cli.ask("What would you like to call your theme?").strip
70
+ name = UI.ask("What would you like to call your theme?").strip
71
+ is_component = UI.yes?("Is this a component?")
57
72
 
58
73
  FileUtils.mkdir_p dir
59
74
  Dir.chdir dir do
60
- File.write('about.json', ABOUT_JSON.sub("#NAME#", name))
75
+ UI.info "Creating about.json"
76
+ about_template = ABOUT_JSON.dup
77
+ about_template[:name] = name
78
+ if is_component
79
+ about_template[:component] = true
80
+ else
81
+ about_template[:color_schemes] = {}
82
+ end
83
+ File.write('about.json', JSON.pretty_generate(about_template))
84
+
85
+ UI.info "Creating HELP"
61
86
  File.write('HELP', HELP)
87
+
88
+ UI.info "Creating package.json"
89
+ author = UI.ask("Who is authoring the theme?").strip
90
+ File.write('package.json', PACKAGE_JSON.sub("#AUTHOR", author))
91
+
92
+ UI.info "Creating .template-lintrc.js"
93
+ File.write('.template-lintrc.js', TEMPLATE_LINT_RC)
94
+
95
+ UI.info "Creating .eslintrc"
96
+ File.write('.eslintrc', ESLINT_RC)
97
+
98
+ UI.info "Creating .gitignore"
62
99
  File.write('.gitignore', GIT_IGNORE)
63
100
 
101
+ locale = "locales/en.yml"
102
+ UI.info "Creating #{locale}"
103
+ FileUtils.mkdir_p(File.dirname(locale))
104
+ description = UI.ask("How would you describe this theme?").strip
105
+ File.write(locale, EN_YML.sub("#DESCRIPTION", description))
106
+
107
+ initializer = "javascripts/discourse/api-initializers/#{name}.js"
108
+ UI.info "Creating #{initializer}"
109
+ FileUtils.mkdir_p(File.dirname(initializer))
110
+ File.write(initializer, API_INITIALIZER)
111
+
64
112
  BLANK_FILES.each do |f|
65
- Cli.info "Creating #{f}"
113
+ UI.info "Creating #{f}"
66
114
  FileUtils.mkdir_p File.dirname(f)
67
115
  FileUtils.touch f
68
116
  end
69
117
 
70
- Cli.info "Initializing git repo"
118
+ UI.info "Initializing git repo"
71
119
  puts `git init .`
120
+
121
+ UI.info "Installing dependencies"
122
+ puts `yarn`
72
123
  end
73
124
  end
74
125
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+ module DiscourseTheme
3
+ class UI
4
+ @@prompt = ::TTY::Prompt.new(help_color: :cyan)
5
+ @@pastel = Pastel.new
6
+
7
+ def self.yes?(message)
8
+ @@prompt.yes?(@@pastel.cyan("? ") + message)
9
+ end
10
+
11
+ def self.ask(message, default: nil)
12
+ @@prompt.ask(@@pastel.cyan("? ") + message, default: default)
13
+ end
14
+
15
+ def self.select(message, options)
16
+ @@prompt.select(@@pastel.cyan("? ") + message, options)
17
+ end
18
+
19
+ def self.info(message)
20
+ puts @@pastel.blue("i ") + message
21
+ end
22
+
23
+ def self.progress(message)
24
+ puts @@pastel.yellow("» ") + message
25
+ end
26
+
27
+ def self.error(message)
28
+ puts @@pastel.red("✘ #{message}")
29
+ end
30
+
31
+ def self.success(message)
32
+ puts @@pastel.green("✔ #{message}")
33
+ end
34
+ end
35
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module DiscourseTheme
2
3
  class Uploader
3
4
 
@@ -33,9 +34,9 @@ module DiscourseTheme
33
34
  json["theme"]["theme_fields"].each do |row|
34
35
  if (error = row["error"]) && error.length > 0
35
36
  count += 1
36
- Cli.error ""
37
- Cli.error "Error in #{row["target"]} #{row["name"]}: #{row["error"]}"
38
- Cli.error ""
37
+ UI.error ""
38
+ UI.error "Error in #{row["target"]} #{row["name"]}: #{row["error"]}"
39
+ UI.error ""
39
40
  end
40
41
  end
41
42
  count
@@ -58,7 +59,7 @@ module DiscourseTheme
58
59
  response = @client.update_theme(@theme_id, args)
59
60
  json = JSON.parse(response.body)
60
61
  if diagnose_errors(json) != 0
61
- Cli.error "(end of errors)"
62
+ UI.error "(end of errors)"
62
63
  end
63
64
  end
64
65
 
@@ -72,7 +73,7 @@ module DiscourseTheme
72
73
  json = JSON.parse(response.body)
73
74
  @theme_id = json["theme"]["id"]
74
75
  if diagnose_errors(json) != 0
75
- Cli.error "(end of errors)"
76
+ UI.error "(end of errors)"
76
77
  end
77
78
  @theme_id
78
79
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module DiscourseTheme
3
- VERSION = "0.3.4"
3
+ VERSION = "0.5.1"
4
4
  end
@@ -1,5 +1,14 @@
1
+ # frozen_string_literal: true
1
2
  module DiscourseTheme
2
3
  class Watcher
4
+ def self.return_immediately!
5
+ @return_immediately = true
6
+ end
7
+
8
+ def self.return_immediately?
9
+ !!@return_immediately
10
+ end
11
+
3
12
  def initialize(dir:, uploader:)
4
13
  @dir = dir
5
14
  @uploader = uploader
@@ -14,7 +23,7 @@ module DiscourseTheme
14
23
  (resolved = resolve_file(modified[0]))
15
24
 
16
25
  target, name, type_id = resolved
17
- Cli.progress "Fast updating #{target}.scss"
26
+ UI.progress "Fast updating #{target}.scss"
18
27
 
19
28
  @uploader.upload_theme_field(
20
29
  target: target,
@@ -25,22 +34,22 @@ module DiscourseTheme
25
34
  else
26
35
  count = modified.length + added.length + removed.length
27
36
  if count > 1
28
- Cli.progress "Detected changes in #{count} files, uploading theme"
37
+ UI.progress "Detected changes in #{count} files, uploading theme"
29
38
  else
30
39
  filename = modified[0] || added[0] || removed[0]
31
- Cli.progress "Detected changes in #{filename.gsub(@dir, '')}, uploading theme"
40
+ UI.progress "Detected changes in #{filename.gsub(@dir, '')}, uploading theme"
32
41
  end
33
42
  @uploader.upload_full_theme
34
43
  end
35
- Cli.success "Done! Watching for changes..."
44
+ UI.success "Done! Watching for changes..."
36
45
  rescue DiscourseTheme::ThemeError => e
37
- Cli.error "#{e.message}"
38
- Cli.progress "Watching for changes..."
46
+ UI.error "#{e.message}"
47
+ UI.progress "Watching for changes..."
39
48
  end
40
49
  end
41
50
 
42
51
  listener.start
43
- sleep
52
+ sleep unless self.class.return_immediately?
44
53
  end
45
54
 
46
55
  protected
metadata CHANGED
@@ -1,169 +1,197 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: discourse_theme
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.4
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Saffron
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-08 00:00:00.000000000 Z
11
+ date: 2021-05-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: bundler
14
+ name: minitar
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '2.0'
20
- type: :development
19
+ version: '0.6'
20
+ type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '2.0'
26
+ version: '0.6'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rake
28
+ name: listen
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
34
- type: :development
33
+ version: '3.1'
34
+ type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '3.1'
41
41
  - !ruby/object:Gem::Dependency
42
- name: minitest
42
+ name: multipart-post
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '5.0'
48
- type: :development
47
+ version: '2.0'
48
+ type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '5.0'
54
+ version: '2.0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: guard
56
+ name: tty-prompt
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '2.14'
62
- type: :development
61
+ version: '0.18'
62
+ type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '2.14'
68
+ version: '0.18'
69
69
  - !ruby/object:Gem::Dependency
70
- name: guard-minitest
70
+ name: rubyzip
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '2.4'
76
- type: :development
75
+ version: '1.2'
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: '2.4'
82
+ version: '1.2'
83
83
  - !ruby/object:Gem::Dependency
84
- name: webmock
84
+ name: bundler
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '3.5'
89
+ version: '2.0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '3.5'
96
+ version: '2.0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: minitar
98
+ name: rake
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '0.6'
104
- type: :runtime
103
+ version: '13.0'
104
+ type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '0.6'
110
+ version: '13.0'
111
111
  - !ruby/object:Gem::Dependency
112
- name: listen
112
+ name: minitest
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: '3.1'
118
- type: :runtime
117
+ version: '5.0'
118
+ type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: '3.1'
124
+ version: '5.0'
125
125
  - !ruby/object:Gem::Dependency
126
- name: multipart-post
126
+ name: guard
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: '2.0'
132
- type: :runtime
131
+ version: '2.14'
132
+ type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: '2.0'
138
+ version: '2.14'
139
139
  - !ruby/object:Gem::Dependency
140
- name: tty-prompt
140
+ name: guard-minitest
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
143
  - - "~>"
144
144
  - !ruby/object:Gem::Version
145
- version: '0.18'
146
- type: :runtime
145
+ version: '2.4'
146
+ type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
- version: '0.18'
152
+ version: '2.4'
153
153
  - !ruby/object:Gem::Dependency
154
- name: rubyzip
154
+ name: webmock
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
157
  - - "~>"
158
158
  - !ruby/object:Gem::Version
159
- version: '1.2'
160
- type: :runtime
159
+ version: '3.5'
160
+ type: :development
161
161
  prerelease: false
162
162
  version_requirements: !ruby/object:Gem::Requirement
163
163
  requirements:
164
164
  - - "~>"
165
165
  - !ruby/object:Gem::Version
166
- version: '1.2'
166
+ version: '3.5'
167
+ - !ruby/object:Gem::Dependency
168
+ name: rubocop
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: rubocop-discourse
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'
167
195
  description: CLI helper for creating Discourse themes
168
196
  email:
169
197
  - sam.saffron@gmail.com
@@ -175,7 +203,6 @@ files:
175
203
  - ".github/workflows/ci.yml"
176
204
  - ".gitignore"
177
205
  - ".rubocop.yml"
178
- - ".travis.yml"
179
206
  - CODE_OF_CONDUCT.md
180
207
  - Gemfile
181
208
  - Guardfile
@@ -190,6 +217,7 @@ files:
190
217
  - lib/discourse_theme/config.rb
191
218
  - lib/discourse_theme/downloader.rb
192
219
  - lib/discourse_theme/scaffold.rb
220
+ - lib/discourse_theme/ui.rb
193
221
  - lib/discourse_theme/uploader.rb
194
222
  - lib/discourse_theme/version.rb
195
223
  - lib/discourse_theme/watcher.rb
@@ -205,14 +233,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
205
233
  requirements:
206
234
  - - ">="
207
235
  - !ruby/object:Gem::Version
208
- version: 2.2.0
236
+ version: 2.5.0
209
237
  required_rubygems_version: !ruby/object:Gem::Requirement
210
238
  requirements:
211
239
  - - ">="
212
240
  - !ruby/object:Gem::Version
213
241
  version: '0'
214
242
  requirements: []
215
- rubygems_version: 3.0.3
243
+ rubygems_version: 3.1.6
216
244
  signing_key:
217
245
  specification_version: 4
218
246
  summary: CLI helper for creating Discourse themes
data/.travis.yml DELETED
@@ -1,5 +0,0 @@
1
- sudo: false
2
- language: ruby
3
- rvm:
4
- - 2.4.2
5
- before_install: gem install bundler -v 1.16.1