discourse_theme 0.3.4 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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