discourse_theme 0.4.0 → 0.5.2

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: de1cb65ed52d9dd44bbe0039b0a40f00f55897e68106d5193cfb0717937b4ff9
4
- data.tar.gz: 8192308474973266925422876401c974c3daf0ffb331d7423ac06d2368c3db68
3
+ metadata.gz: 20a594e3cf6429ad7b721ca546710a1f57706a74bb0c8346301dea8b76a58cea
4
+ data.tar.gz: 477808a79184cc9251865a86a77ccfa33a64318a90a774207a5441b683499546
5
5
  SHA512:
6
- metadata.gz: 2dcbaf4918cf88082c27270a05e1fb888d5d2e462160834c7a2b82ab79acfb3eaf62d0732ea5da840f83d1656f36d6aadda4633cdec86b77149d57c5188c0514
7
- data.tar.gz: 3c095bcfcc224691d30405353a06eb6ccf64446331175dc28e7f8eebf1347b8b2707c37313e1c29668a35937a4a550c8ef81bc2701201674a5baf8b525d72211
6
+ metadata.gz: 8d5ad9c41ca00b3172167b1985cdb5da36ef6d8073ad6b4882f6760da05006f550a12447007d64fb8486e078245eab618979c80e18e78eaa4cc1487269dd780a
7
+ data.tar.gz: 7e40d9ec1727422c4875307b35b38a3d178330598c4a0b1c207779564fe8cf4dbbd07864e964e8e7eee1d5ffec47ad9cdc2821f28fd24ebe1bdb44677cd659cf
@@ -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.6.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'
@@ -13,14 +14,15 @@ require 'json'
13
14
  require 'yaml'
14
15
  require 'tty/prompt'
15
16
 
16
- require 'discourse_theme/version'
17
- require 'discourse_theme/config'
18
- require 'discourse_theme/cli'
19
- require 'discourse_theme/client'
20
- require 'discourse_theme/downloader'
21
- require 'discourse_theme/uploader'
22
- require 'discourse_theme/watcher'
23
- require 'discourse_theme/scaffold'
17
+ require_relative 'discourse_theme/version'
18
+ require_relative 'discourse_theme/config'
19
+ require_relative 'discourse_theme/ui'
20
+ require_relative 'discourse_theme/cli'
21
+ require_relative 'discourse_theme/client'
22
+ require_relative 'discourse_theme/downloader'
23
+ require_relative 'discourse_theme/uploader'
24
+ require_relative 'discourse_theme/watcher'
25
+ require_relative 'discourse_theme/scaffold'
24
26
 
25
27
  module DiscourseTheme
26
28
  class ThemeError < StandardError; end
@@ -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
@@ -60,13 +29,12 @@ module DiscourseTheme
60
29
  components = settings.components
61
30
 
62
31
  if command == "new"
63
- raise DiscourseTheme::ThemeError.new "'#{dir} is not empty" if Dir.exists?(dir) && !Dir.empty?(dir)
32
+ raise DiscourseTheme::ThemeError.new "'#{dir}' is not empty" if Dir.exists?(dir) && !Dir.empty?(dir)
33
+ raise DiscourseTheme::ThemeError.new "git is not installed" if !command?("git")
34
+ raise DiscourseTheme::ThemeError.new "yarn is not installed" if !command?("yarn")
35
+
64
36
  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
37
+ watch_theme?(args)
70
38
  elsif command == "watch"
71
39
  raise DiscourseTheme::ThemeError.new "'#{dir} does not exist" unless Dir.exists?(dir)
72
40
  client = DiscourseTheme::Client.new(dir, settings, reset: reset)
@@ -80,13 +48,13 @@ module DiscourseTheme
80
48
  options["Create and sync with a new theme"] = :create
81
49
  options["Select a different theme"] = :select
82
50
 
83
- choice = Cli.select('How would you like to sync this theme?', options.keys)
51
+ choice = UI.select('How would you like to sync this theme?', options.keys)
84
52
 
85
53
  if options[choice] == :create
86
54
  theme_id = nil
87
55
  elsif options[choice] == :select
88
56
  themes = render_theme_list(theme_list)
89
- choice = Cli.select('Which theme would you like to sync with?', themes)
57
+ choice = UI.select('Which theme would you like to sync with?', themes)
90
58
  theme_id = extract_theme_id(choice)
91
59
  theme = theme_list.find { |t| t["id"] == theme_id }
92
60
  end
@@ -101,27 +69,26 @@ module DiscourseTheme
101
69
  options["Yes"] = :sync
102
70
  options["No"] = :none
103
71
  options = options.sort_by { |_, b| b == components.to_sym ? 0 : 1 }.to_h if components
104
- choice = Cli.select('Would you like to update child theme components?', options.keys)
72
+ choice = UI.select('Would you like to update child theme components?', options.keys)
105
73
  settings.components = components = options[choice].to_s
106
74
  end
107
75
 
108
76
  uploader = DiscourseTheme::Uploader.new(dir: dir, client: client, theme_id: theme_id, components: components)
109
77
 
110
- Cli.progress "Uploading theme from #{dir}"
78
+ UI.progress "Uploading theme from #{dir}"
111
79
  settings.theme_id = theme_id = uploader.upload_full_theme
112
80
 
113
- Cli.success "Theme uploaded (id:#{theme_id})"
114
- Cli.info "Preview: #{client.root}/?preview_theme_id=#{theme_id}"
81
+ UI.success "Theme uploaded (id:#{theme_id})"
82
+ UI.info "Preview: #{client.root}/?preview_theme_id=#{theme_id}"
115
83
  if client.is_theme_creator
116
- Cli.info "Manage: #{client.root}/my/themes"
84
+ UI.info "Manage: #{client.root}/my/themes"
117
85
  else
118
- Cli.info "Manage: #{client.root}/admin/customize/themes/#{theme_id}"
86
+ UI.info "Manage: #{client.root}/admin/customize/themes/#{theme_id}"
119
87
  end
120
88
  watcher = DiscourseTheme::Watcher.new(dir: dir, uploader: uploader)
121
89
 
122
- Cli.progress "Watching for changes in #{dir}..."
90
+ UI.progress "Watching for changes in #{dir}..."
123
91
  watcher.watch
124
-
125
92
  elsif command == "download"
126
93
  client = DiscourseTheme::Client.new(dir, settings, reset: reset)
127
94
  downloader = DiscourseTheme::Downloader.new(dir: dir, client: client)
@@ -129,33 +96,51 @@ module DiscourseTheme
129
96
  FileUtils.mkdir_p dir unless Dir.exists?(dir)
130
97
  raise DiscourseTheme::ThemeError.new "'#{dir} is not empty" unless Dir.empty?(dir)
131
98
 
132
- Cli.progress "Loading theme list..."
99
+ UI.progress "Loading theme list..."
133
100
  themes = render_theme_list(client.get_themes_list)
134
101
 
135
- choice = Cli.select('Which theme would you like to download?', themes)
102
+ choice = UI.select('Which theme would you like to download?', themes)
136
103
  theme_id = extract_theme_id(choice)
137
104
 
138
- Cli.progress "Downloading theme into #{dir}"
105
+ UI.progress "Downloading theme into #{dir}"
139
106
 
140
107
  downloader.download_theme(theme_id)
141
108
  settings.theme_id = theme_id
142
109
 
143
- Cli.success "Theme downloaded"
110
+ UI.success "Theme downloaded"
144
111
 
145
- if Cli.yes?("Would you like to start 'watching' this theme?")
146
- args[0] = "watch"
147
- Cli.progress "Running discourse_theme #{args.join(' ')}"
148
- run(args)
149
- end
112
+ watch_theme?(args)
150
113
  else
151
114
  usage
152
115
  end
153
116
 
154
- Cli.progress "Exiting..."
117
+ UI.progress "Exiting..."
155
118
  rescue DiscourseTheme::ThemeError => e
156
- Cli.error "#{e.message}"
119
+ UI.error "#{e.message}"
157
120
  rescue Interrupt, TTY::Reader::InputInterrupt => e
158
- Cli.error "Interrupted"
121
+ UI.error "Interrupted"
122
+ end
123
+
124
+ private
125
+
126
+ def command?(cmd)
127
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
128
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
129
+ exts.each do |ext|
130
+ exe = File.join(path, "#{cmd}#{ext}")
131
+ return true if File.executable?(exe) && !File.directory?(exe)
132
+ end
133
+ end
134
+
135
+ false
136
+ end
137
+
138
+ def watch_theme?(args)
139
+ if UI.yes?("Would you like to start 'watching' this theme?")
140
+ args[0] = "watch"
141
+ UI.progress "Running discourse_theme #{args.join(' ')}"
142
+ run(args)
143
+ end
159
144
  end
160
145
 
161
146
  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
 
@@ -141,26 +142,26 @@ module DiscourseTheme
141
142
  def guess_url(settings)
142
143
  url = ENV['DISCOURSE_URL']
143
144
  if url
144
- Cli.progress "Using #{url} from DISCOURSE_URL"
145
+ UI.progress "Using #{url} from DISCOURSE_URL"
145
146
  end
146
147
 
147
148
  if !url && settings.url
148
149
  url = settings.url
149
- Cli.progress "Using #{url} from #{DiscourseTheme::Cli::SETTINGS_FILE}"
150
+ UI.progress "Using #{url} from #{DiscourseTheme::Cli::SETTINGS_FILE}"
150
151
  end
151
152
 
152
153
  if !url || @reset
153
- 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
154
155
  url = "http://#{url}" unless url =~ /^https?:\/\//
155
156
 
156
157
  # maybe this is an HTTPS redirect
157
158
  uri = URI.parse(url)
158
159
  if URI::HTTP === uri && uri.port == 80 && is_https_redirect?(url)
159
- Cli.info "Detected that #{url} should be accessed over https"
160
+ UI.info "Detected that #{url} should be accessed over https"
160
161
  url = url.sub("http", "https")
161
162
  end
162
163
 
163
- 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}?")
164
165
  settings.url = url
165
166
  else
166
167
  settings.url = nil
@@ -173,17 +174,17 @@ module DiscourseTheme
173
174
  def guess_api_key(settings)
174
175
  api_key = ENV['DISCOURSE_API_KEY']
175
176
  if api_key
176
- Cli.progress "Using api key from DISCOURSE_API_KEY"
177
+ UI.progress "Using api key from DISCOURSE_API_KEY"
177
178
  end
178
179
 
179
180
  if !api_key && settings.api_key
180
181
  api_key = settings.api_key
181
- Cli.progress "Using api key from #{DiscourseTheme::Cli::SETTINGS_FILE}"
182
+ UI.progress "Using api key from #{DiscourseTheme::Cli::SETTINGS_FILE}"
182
183
  end
183
184
 
184
185
  if !api_key || @reset
185
- api_key = Cli.ask("What is your API key?", default: api_key).strip
186
- 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}?")
187
188
  settings.api_key = api_key
188
189
  else
189
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,143 @@
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 = loop do
71
+ input = UI.ask("What would you like to call your theme?").to_s.strip
72
+ if input.empty?
73
+ UI.error("Theme name cannot be empty")
74
+ else
75
+ break input
76
+ end
77
+ end
78
+
79
+ is_component = UI.yes?("Is this a component?")
57
80
 
58
81
  FileUtils.mkdir_p dir
59
82
  Dir.chdir dir do
60
- File.write('about.json', ABOUT_JSON.sub("#NAME#", name))
83
+ author = loop do
84
+ input = UI.ask("Who is authoring the theme?", default: ENV['USER']).to_s.strip
85
+ if input.empty?
86
+ UI.error("Author cannot be empty")
87
+ else
88
+ break input
89
+ end
90
+ end
91
+
92
+ description = UI.ask("How would you describe this theme?").to_s.strip
93
+
94
+ UI.info "Creating about.json"
95
+ about_template = ABOUT_JSON.dup
96
+ about_template[:name] = name
97
+ if is_component
98
+ about_template[:component] = true
99
+ else
100
+ about_template[:color_schemes] = {}
101
+ end
102
+ File.write('about.json', JSON.pretty_generate(about_template))
103
+
104
+ UI.info "Creating HELP"
61
105
  File.write('HELP', HELP)
106
+
107
+ UI.info "Creating package.json"
108
+ File.write('package.json', PACKAGE_JSON.sub("#AUTHOR", author))
109
+
110
+ UI.info "Creating .template-lintrc.js"
111
+ File.write('.template-lintrc.js', TEMPLATE_LINT_RC)
112
+
113
+ UI.info "Creating .eslintrc"
114
+ File.write('.eslintrc', ESLINT_RC)
115
+
116
+ UI.info "Creating .gitignore"
62
117
  File.write('.gitignore', GIT_IGNORE)
63
118
 
119
+ locale = "locales/en.yml"
120
+ UI.info "Creating #{locale}"
121
+ FileUtils.mkdir_p(File.dirname(locale))
122
+ File.write(locale, EN_YML.sub("#DESCRIPTION", description))
123
+
124
+ encoded_name = name.downcase.gsub(/[^\w_-]+/, '_')
125
+ initializer = "javascripts/discourse/api-initializers/#{encoded_name}.js"
126
+ UI.info "Creating #{initializer}"
127
+ FileUtils.mkdir_p(File.dirname(initializer))
128
+ File.write(initializer, API_INITIALIZER)
129
+
64
130
  BLANK_FILES.each do |f|
65
- Cli.info "Creating #{f}"
131
+ UI.info "Creating #{f}"
66
132
  FileUtils.mkdir_p File.dirname(f)
67
133
  FileUtils.touch f
68
134
  end
69
135
 
70
- Cli.info "Initializing git repo"
71
- puts `git init .`
136
+ UI.info "Initializing git repo"
137
+ puts `git init . --initial-branch=main`
138
+
139
+ UI.info "Installing dependencies"
140
+ puts `yarn`
72
141
  end
73
142
  end
74
143
  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.4.0"
3
+ VERSION = "0.5.2"
4
4
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module DiscourseTheme
2
3
  class Watcher
3
4
  def self.return_immediately!
@@ -22,7 +23,7 @@ module DiscourseTheme
22
23
  (resolved = resolve_file(modified[0]))
23
24
 
24
25
  target, name, type_id = resolved
25
- Cli.progress "Fast updating #{target}.scss"
26
+ UI.progress "Fast updating #{target}.scss"
26
27
 
27
28
  @uploader.upload_theme_field(
28
29
  target: target,
@@ -33,17 +34,17 @@ module DiscourseTheme
33
34
  else
34
35
  count = modified.length + added.length + removed.length
35
36
  if count > 1
36
- Cli.progress "Detected changes in #{count} files, uploading theme"
37
+ UI.progress "Detected changes in #{count} files, uploading theme"
37
38
  else
38
39
  filename = modified[0] || added[0] || removed[0]
39
- Cli.progress "Detected changes in #{filename.gsub(@dir, '')}, uploading theme"
40
+ UI.progress "Detected changes in #{filename.gsub(@dir, '')}, uploading theme"
40
41
  end
41
42
  @uploader.upload_full_theme
42
43
  end
43
- Cli.success "Done! Watching for changes..."
44
+ UI.success "Done! Watching for changes..."
44
45
  rescue DiscourseTheme::ThemeError => e
45
- Cli.error "#{e.message}"
46
- Cli.progress "Watching for changes..."
46
+ UI.error "#{e.message}"
47
+ UI.progress "Watching for changes..."
47
48
  end
48
49
  end
49
50
 
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.4.0
4
+ version: 0.5.2
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-11-24 00:00:00.000000000 Z
11
+ date: 2021-07-15 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.6.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