discourse_dev 0.1.0 → 0.2.0

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: ee90422d22b330921c72be89d86be91edf94966537d869c06efb2687762853f4
4
- data.tar.gz: cb5b3d27e5a93011c2ef10ff77d73b5393ed9a1f04a7efb538ef2f6a67776e12
3
+ metadata.gz: 7b049db0091c35d6b2a6cdfe9cb8edd13d6c9223fc6db11d470b63b2086ca1b6
4
+ data.tar.gz: 245fada164d5df70e92b0bab7a300ac9e7e1c46f45413aefa1a560f401daf45c
5
5
  SHA512:
6
- metadata.gz: 396e17d2e66c01d8a8e75381bd3a36264ddfc7d01ffc1dc3a578ee938a328805b35eda592d603388d38cba278a9c089a7a71a2ea03ba67a5bc3c30130b94a37a
7
- data.tar.gz: b8fe74f3a03140cad606e9479b043e30b23c7eaf9b1f098e06613ad7c8662b3c742aab901e03965e64c0dfa0110b6c7cfa7a2a77d97e8e97b1cda63ac4c6e0db
6
+ metadata.gz: fdfdfd17d4dfcd3296f2bd5ee33624735137b32be17fc6323744bf3a84e1342aff90d842dbcea1190cce77fca695cd7d90aae535a9885ad7cd680e0504da4823
7
+ data.tar.gz: f87c9a09964b560cf535e49065d58b8fc0009e0d44b391ae721fec3d78bf725a9e46bb29f559c7988792ecd37deb40f467c6cd647d95c952122677d450af9c40
data/.rubocop.yml ADDED
@@ -0,0 +1,2 @@
1
+ inherit_gem:
2
+ rubocop-discourse: default.yml
data/auth/plugin.rb CHANGED
@@ -36,7 +36,7 @@ module ::OmniAuth
36
36
  data = request.params.slice(*FIELDS)
37
37
 
38
38
  r = Rack::Response.new
39
- r.set_cookie(COOKIE, {value: data.to_json, path: "/", expires: 1.month.from_now})
39
+ r.set_cookie(COOKIE, { value: data.to_json, path: "/", expires: 1.month.from_now })
40
40
 
41
41
  uri = URI.parse(callback_path)
42
42
  uri.query = URI.encode_www_form(data)
@@ -61,7 +61,7 @@ module ::OmniAuth
61
61
  defaults["uid"] = SecureRandom.hex(8) unless defaults["uid"].present?
62
62
  defaults["email_verified"] = "true" unless defaults["email_verified"].present?
63
63
 
64
- OmniAuth::Form.build(:title => "Fake Authentication Provider") do
64
+ OmniAuth::Form.build(title: "Fake Authentication Provider") do
65
65
  html "\n<input type='hidden' name='authenticity_token' value='#{token}'/>"
66
66
 
67
67
  FIELDS.each do |f|
@@ -128,7 +128,6 @@ end
128
128
 
129
129
  auth_provider authenticator: DevelopmentAuthenticator.new
130
130
 
131
-
132
131
  ### DiscourseConnect
133
132
  after_initialize do
134
133
  module ::DevelopmentAuth
@@ -191,7 +190,7 @@ after_initialize do
191
190
  append_view_path(File.expand_path("../app/views", __FILE__))
192
191
  render template: "fake_discourse_connect/form", layout: false
193
192
  end
194
- end
193
+ end
195
194
 
196
195
  DevelopmentAuth::Engine.routes.draw do
197
196
  get "/fake-discourse-connect" => "fake_discourse_connect#auth"
data/config/dev.yml CHANGED
@@ -1,11 +1,38 @@
1
1
  site_settings:
2
2
  tagging_enabled: true
3
3
  verbose_discourse_connect_logging: true
4
+
4
5
  seed: 1
5
- start_date: "01/01/2020"
6
- max_likes_count: 10
6
+ start_date: 2020-01-01
7
7
  auth_plugin_enabled: true
8
8
  allow_anonymous_to_impersonate: false
9
+
10
+ category:
11
+ count: 30
12
+ group:
13
+ count: 15
14
+ post:
15
+ include_images: false
16
+ max_likes_count: 10
17
+ tag:
18
+ count: 30
19
+ topic:
20
+ count: 30
21
+ replies:
22
+ # number of replies per topic between min and max
23
+ min: 0
24
+ max: 12
25
+ overrides:
26
+ # topic titles can be found in config/locales/faker.en.yml
27
+ - title: "Coolest thing you have seen today"
28
+ count: 99
29
+ tags:
30
+ # number of tags per topic between min and max
31
+ min: 0
32
+ max: 3
33
+ user:
34
+ count: 30
35
+
9
36
  new_user:
10
37
  username: new_user
11
38
  email: new_user@example.com
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
22
22
 
23
23
  spec.add_development_dependency "bundler", "~> 2.0"
24
24
  spec.add_development_dependency "rake", ">= 12.3.3"
25
+ spec.add_development_dependency "rubocop-discourse"
25
26
 
26
27
  spec.required_ruby_version = '>= 2.6.0'
27
28
  end
data/lib/discourse_dev.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'i18n'
4
4
 
5
- Dir[File.dirname(__FILE__) + '/**/*.rb'].each {|file| require file }
5
+ Dir[File.dirname(__FILE__) + '/**/*.rb'].each { |file| require file }
6
6
 
7
7
  module DiscourseDev
8
8
  require 'discourse_dev/railtie'
@@ -48,7 +48,10 @@ ActiveRecord::Tasks::DatabaseTasks.module_eval do
48
48
  private
49
49
  def each_current_configuration(environment, name = nil)
50
50
  rails_each_current_configuration(environment, name) { |db_config|
51
- next if environment == "development" && ENV["SKIP_TEST_DATABASE"] == "1" && db_config["database"] != "discourse_development"
51
+ next if environment == "development" &&
52
+ ENV["SKIP_TEST_DATABASE"] == "1" &&
53
+ db_config.configuration_hash[:database] != "discourse_development"
54
+
52
55
  yield db_config
53
56
  }
54
57
  end
@@ -7,8 +7,8 @@ require 'faker'
7
7
  module DiscourseDev
8
8
  class Category < Record
9
9
 
10
- def initialize(count = DEFAULT_COUNT)
11
- super(::Category, count)
10
+ def initialize
11
+ super(::Category, DiscourseDev.config.category[:count])
12
12
  @parent_category_ids = ::Category.where(parent_category_id: nil).pluck(:id)
13
13
  end
14
14
 
@@ -36,7 +36,7 @@ module DiscourseDev
36
36
  def permissions
37
37
  return @permissions if @permissions.present?
38
38
  return { everyone: :full } if Faker::Boolean.boolean(true_ratio: 0.75)
39
-
39
+
40
40
  permission = {}
41
41
  group = Group.random
42
42
  permission[group.id] = Faker::Number.between(from: 1, to: 3)
@@ -5,20 +5,22 @@ require 'highline/import'
5
5
 
6
6
  module DiscourseDev
7
7
  class Config
8
- attr_reader :config, :default_config, :file_path
8
+ attr_reader :config, :file_path
9
9
 
10
10
  def initialize
11
11
  default_file_path = File.join(DiscourseDev.root, "config", "dev.yml")
12
12
  @file_path = File.join(Rails.root, "config", "dev.yml")
13
- @default_config = YAML.load_file(default_file_path)
13
+ default_config = YAML.load_file(default_file_path)
14
14
 
15
15
  if File.exists?(file_path)
16
- @config = YAML.load_file(file_path)
16
+ user_config = YAML.load_file(file_path)
17
17
  else
18
18
  puts "I did no detect a custom `config/dev.yml` file, creating one for you where you can amend defaults."
19
19
  FileUtils.cp(default_file_path, file_path)
20
- @config = {}
20
+ user_config = {}
21
21
  end
22
+
23
+ @config = default_config.deep_merge(user_config).deep_symbolize_keys
22
24
  end
23
25
 
24
26
  def update!
@@ -28,32 +30,25 @@ module DiscourseDev
28
30
  set_seed
29
31
  end
30
32
 
33
+ private
34
+
31
35
  def update_site_settings
32
36
  puts "Updating site settings..."
33
37
 
34
- site_settings = config["site_settings"] || {}
38
+ site_settings = config[:site_settings] || {}
35
39
 
36
40
  site_settings.each do |key, value|
37
41
  puts "#{key} = #{value}"
38
42
  SiteSetting.set(key, value)
39
43
  end
40
44
 
41
- keys = site_settings.keys
42
-
43
- default_config["site_settings"].each do |key, value|
44
- next if keys.include?(key)
45
-
46
- puts "#{key} = #{value}"
47
- SiteSetting.set(key, value)
48
- end
49
-
50
45
  SiteSetting.refresh!
51
46
  end
52
47
 
53
48
  def create_admin_user
54
49
  puts "Creating default admin user account..."
55
50
 
56
- settings = config["admin"]
51
+ settings = config[:admin]
57
52
 
58
53
  if settings.present?
59
54
  create_admin_user_from_settings(settings)
@@ -63,14 +58,14 @@ module DiscourseDev
63
58
  end
64
59
 
65
60
  def create_new_user
66
- settings = config["new_user"]
61
+ settings = config[:new_user]
67
62
 
68
63
  if settings.present?
69
- email = settings["email"] || "new_user@example.com"
64
+ email = settings[:email] || "new_user@example.com"
70
65
 
71
66
  new_user = ::User.create!(
72
67
  email: email,
73
- username: settings["username"] || UserNameSuggester.suggest(email)
68
+ username: settings[:username] || UserNameSuggester.suggest(email)
74
69
  )
75
70
  new_user.email_tokens.update_all confirmed: true
76
71
  new_user.activate
@@ -83,22 +78,20 @@ module DiscourseDev
83
78
  end
84
79
 
85
80
  def start_date
86
- DateTime.parse(config["start_date"] || default_config["start_date"])
81
+ DateTime.parse(config[:start_date])
87
82
  end
88
83
 
89
84
  def method_missing(name)
90
- name = name.to_s
91
- return config[name] if config.keys.include?(name)
92
- default_config[name]
85
+ config[name.to_sym]
93
86
  end
94
87
 
95
88
  def create_admin_user_from_settings(settings)
96
- email = settings["email"]
89
+ email = settings[:email]
97
90
 
98
91
  admin = ::User.create!(
99
92
  email: email,
100
- username: settings["username"] || UserNameSuggester.suggest(email),
101
- password: settings["password"]
93
+ username: settings[:username] || UserNameSuggester.suggest(email),
94
+ password: settings[:password]
102
95
  )
103
96
  admin.grant_admin!
104
97
  if admin.trust_level < 1
@@ -7,10 +7,8 @@ require 'faker'
7
7
  module DiscourseDev
8
8
  class Group < Record
9
9
 
10
- DEFAULT_COUNT = 15.freeze
11
-
12
- def initialize(count = DEFAULT_COUNT)
13
- super(::Group, count)
10
+ def initialize
11
+ super(::Group, DiscourseDev.config.group[:count])
14
12
  end
15
13
 
16
14
  def data
@@ -8,12 +8,12 @@ module DiscourseDev
8
8
 
9
9
  attr_reader :topic
10
10
 
11
- def initialize(topic, count = DEFAULT_COUNT)
11
+ def initialize(topic, count)
12
12
  super(::Post, count)
13
13
  @topic = topic
14
14
 
15
15
  category = topic.category
16
- @max_likes_count = DiscourseDev.config.max_likes_count
16
+ @max_likes_count = DiscourseDev.config.post[:max_likes_count]
17
17
  unless category.groups.blank?
18
18
  group_ids = category.groups.pluck(:id)
19
19
  @user_ids = ::GroupUser.where(group_id: group_ids).pluck(:user_id)
@@ -25,7 +25,7 @@ module DiscourseDev
25
25
  def data
26
26
  {
27
27
  topic_id: topic.id,
28
- raw: Faker::Markdown.sandwich(sentences: 5),
28
+ raw: Faker::DiscourseMarkdown.sandwich(sentences: 5),
29
29
  created_at: Faker::Time.between(from: topic.last_posted_at, to: DateTime.now),
30
30
  skip_validations: true,
31
31
  skip_guardian: true
@@ -33,6 +33,8 @@ module DiscourseDev
33
33
  end
34
34
 
35
35
  def create!
36
+ user = self.user
37
+ data = Faker::DiscourseMarkdown.with_user(user.id) { self.data }
36
38
  post = PostCreator.new(user, data).create!
37
39
  topic.reload
38
40
  generate_likes(post)
@@ -86,12 +88,15 @@ module DiscourseDev
86
88
  count.times do |i|
87
89
  @index = i
88
90
  begin
89
- reply = {
90
- topic_id: topic.id,
91
- raw: Faker::Markdown.sandwich(sentences: 5),
92
- skip_validations: true
93
- }
94
- PostCreator.new(User.random, reply).create!
91
+ user = User.random
92
+ reply = Faker::DiscourseMarkdown.with_user(user.id) do
93
+ {
94
+ topic_id: topic.id,
95
+ raw: Faker::DiscourseMarkdown.sandwich(sentences: 5),
96
+ skip_validations: true
97
+ }
98
+ end
99
+ PostCreator.new(user, reply).create!
95
100
  rescue ActiveRecord::RecordNotSaved => e
96
101
  puts e
97
102
  end
@@ -11,8 +11,11 @@ module DiscourseDev
11
11
  attr_reader :model, :type
12
12
 
13
13
  def initialize(model, count = DEFAULT_COUNT)
14
- Faker::Discourse.unique.clear
15
- RateLimiter.disable
14
+ @@initialized ||= begin
15
+ Faker::Discourse.unique.clear
16
+ RateLimiter.disable
17
+ true
18
+ end
16
19
 
17
20
  @model = model
18
21
  @type = model.to_s
@@ -7,8 +7,8 @@ require 'faker'
7
7
  module DiscourseDev
8
8
  class Tag < Record
9
9
 
10
- def initialize(count = DEFAULT_COUNT)
11
- super(::Tag, count)
10
+ def initialize
11
+ super(::Tag, DiscourseDev.config.tag[:count])
12
12
  end
13
13
 
14
14
  def data
@@ -25,12 +25,12 @@ end
25
25
 
26
26
  desc 'Populate sample content for development environment'
27
27
  task 'dev:populate' => ['db:load_config'] do |_, args|
28
+ system("redis-cli flushall")
28
29
  Rake::Task['groups:populate'].invoke
29
30
  Rake::Task['users:populate'].invoke
30
31
  Rake::Task['categories:populate'].invoke
31
32
  Rake::Task['tags:populate'].invoke
32
33
  Rake::Task['topics:populate'].invoke
33
- system("redis-cli flushall")
34
34
  end
35
35
 
36
36
  desc 'Repopulate sample datas in development environment'
@@ -6,8 +6,9 @@ require 'faker'
6
6
  module DiscourseDev
7
7
  class Topic < Record
8
8
 
9
- def initialize(count = DEFAULT_COUNT)
10
- super(::Topic, count)
9
+ def initialize
10
+ @settings = DiscourseDev.config.topic
11
+ super(::Topic, @settings[:count])
11
12
  end
12
13
 
13
14
  def data
@@ -30,7 +31,7 @@ module DiscourseDev
30
31
 
31
32
  {
32
33
  title: title[0, SiteSetting.max_topic_title_length],
33
- raw: Faker::Markdown.sandwich(sentences: 5),
34
+ raw: Faker::DiscourseMarkdown.sandwich(sentences: 5),
34
35
  category: @category.id,
35
36
  created_at: Faker::Time.between(from: DiscourseDev.config.start_date, to: DateTime.now),
36
37
  tags: tags,
@@ -44,17 +45,17 @@ module DiscourseDev
44
45
  end
45
46
 
46
47
  def title
47
- if index <= I18n.t("faker.discourse.topics").count
48
+ if index < I18n.t("faker.discourse.topics").count
48
49
  Faker::Discourse.unique.topic
49
50
  else
50
- Faker::Lorem.unique.sentence(word_count: 3, supplemental: true, random_words_to_add: 4).chomp(".")
51
+ Faker::Lorem.unique.sentence(word_count: 5, supplemental: true, random_words_to_add: 4).chomp(".")
51
52
  end
52
53
  end
53
54
 
54
55
  def tags
55
56
  @tags = []
56
57
 
57
- Faker::Number.between(from: 0, to: 3).times do
58
+ Faker::Number.between(from: @settings.dig(:tags, :min), to: @settings.dig(:tags, :max)).times do
58
59
  @tags << Faker::Discourse.tag
59
60
  end
60
61
 
@@ -63,18 +64,24 @@ module DiscourseDev
63
64
 
64
65
  def create!
65
66
  @category = Category.random
66
- topic = data
67
+ user = self.user
68
+ topic = Faker::DiscourseMarkdown.with_user(user.id) { data }
67
69
  post = PostCreator.new(user, topic).create!
68
70
 
69
- if topic[:title] == "Coolest thing you have seen today"
70
- reply_count = 99
71
+ if override = @settings.dig(:replies, :overrides).find { |o| o[:title] == topic[:title] }
72
+ reply_count = override[:count]
71
73
  else
72
- reply_count = Faker::Number.between(from: 0, to: 12)
74
+ reply_count = Faker::Number.between(from: @settings.dig(:replies, :min), to: @settings.dig(:replies, :max))
73
75
  end
74
76
 
75
77
  Post.new(post.topic, reply_count).populate!
76
78
  end
77
79
 
80
+ def populate!
81
+ super
82
+ delete_unwanted_sidekiq_jobs
83
+ end
84
+
78
85
  def user
79
86
  return User.random if @category.groups.blank?
80
87
 
@@ -89,5 +96,11 @@ module DiscourseDev
89
96
  category_definition_topic_ids = ::Category.pluck(:topic_id)
90
97
  ::Topic.where(archetype: :regular).where.not(id: category_definition_topic_ids).count
91
98
  end
99
+
100
+ def delete_unwanted_sidekiq_jobs
101
+ Sidekiq::ScheduledSet.new.each do |job|
102
+ job.delete if job.item["class"] == "Jobs::UserEmail"
103
+ end
104
+ end
92
105
  end
93
106
  end
@@ -8,8 +8,8 @@ module DiscourseDev
8
8
  class User < Record
9
9
  attr_reader :images
10
10
 
11
- def initialize(count = DEFAULT_COUNT)
12
- super(::User, count)
11
+ def initialize
12
+ super(::User, DiscourseDev.config.user[:count])
13
13
 
14
14
  # Using the stock avatar images from https://tinyfac.es
15
15
  # Tiny Faces is a free crowd-sourced avatar gallery
@@ -18,9 +18,10 @@ module DiscourseDev
18
18
 
19
19
  def data
20
20
  name = Faker::Name.unique.name
21
- email = Faker::Internet.unique.email(name: name)
22
- username = Faker::Internet.unique.username(specifier: name)[0, SiteSetting.max_username_length]
23
- username_lower = username.downcase
21
+ email = Faker::Internet.unique.email(name: name, domain: "faker.invalid")
22
+ username = Faker::Internet.unique.username(specifier: ::User.username_length)
23
+ username = UserNameSuggester.suggest(username)
24
+ username_lower = ::User.normalize_username(username)
24
25
 
25
26
  {
26
27
  name: name,
@@ -39,7 +40,7 @@ module DiscourseDev
39
40
  set_random_avatar(user)
40
41
  Faker::Number.between(from: 0, to: 2).times do
41
42
  group = Group.random
42
-
43
+
43
44
  group.add(user)
44
45
  end
45
46
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DiscourseDev
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faker'
4
+ require 'net/http'
5
+ require 'json'
6
+
7
+ module Faker
8
+ class DiscourseMarkdown < Markdown
9
+ class << self
10
+ attr_writer(:user_id)
11
+
12
+ def user_id
13
+ @user_id || ::Discourse::SYSTEM_USER_ID
14
+ end
15
+
16
+ def with_user(user_id)
17
+ current_user_id = self.user_id
18
+ self.user_id = user_id
19
+ begin
20
+ yield
21
+ ensure
22
+ self.user_id = current_user_id
23
+ end
24
+ end
25
+
26
+ def image
27
+ image = next_image
28
+ image_file = load_image(image)
29
+
30
+ upload = ::UploadCreator.new(
31
+ image_file,
32
+ image[:filename],
33
+ origin: image[:url]
34
+ ).create_for(user_id)
35
+
36
+ ::UploadMarkdown.new(upload).to_markdown if upload.present? && upload.persisted?
37
+ rescue => e
38
+ STDERR.puts e
39
+ STDERR.puts e.backtrace.join("\n")
40
+ end
41
+
42
+ private
43
+
44
+ def next_image
45
+ if @images.blank?
46
+ if @stop_loading_images
47
+ @images = @all_images.dup
48
+ else
49
+ @next_page = (@next_page || 0) + 1
50
+ url = URI("https://picsum.photos/v2/list?page=#{@next_page}&limit=50")
51
+ response = Net::HTTP.get(url)
52
+ json = JSON.parse(response)
53
+
54
+ if json.blank?
55
+ @stop_loading_images = true
56
+ @images = @all_images.dup
57
+ else
58
+ @images = json.sort_by { |image| image["id"] }
59
+ @all_images = (@all_images || []).concat(@images)
60
+ end
61
+ end
62
+ end
63
+
64
+ image = @images.pop
65
+ { filename: "#{image['id']}.jpg", url: "#{image['download_url']}.jpg" }
66
+ end
67
+
68
+ def image_cache_dir
69
+ @image_cache_dir ||= ::File.join(Rails.root, "tmp", "discourse_dev", "images")
70
+ end
71
+
72
+ def load_image(image)
73
+ cache_path = ::File.join(image_cache_dir, image[:filename])
74
+
75
+ if !::File.exists?(cache_path)
76
+ FileUtils.mkdir_p(image_cache_dir)
77
+ temp_file = ::FileHelper.download(
78
+ image[:url],
79
+ max_file_size: [SiteSetting.max_image_size_kb.kilobytes, 10.megabytes].max,
80
+ tmp_file_name: "image",
81
+ follow_redirect: true
82
+ )
83
+ FileUtils.cp(temp_file, cache_path)
84
+ end
85
+
86
+ ::File.open(cache_path)
87
+ end
88
+
89
+ def available_methods
90
+ methods = super
91
+ methods << :image if ::DiscourseDev.config.post[:include_images]
92
+ methods
93
+ end
94
+ end
95
+ end
96
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: discourse_dev
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vinoth Kannan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-15 00:00:00.000000000 Z
11
+ date: 2021-04-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faker
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: 12.3.3
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop-discourse
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  description: Rake helper tasks for Discourse developers
56
70
  email:
57
71
  - svkn.87@gmail.com
@@ -61,6 +75,7 @@ extra_rdoc_files: []
61
75
  files:
62
76
  - ".github/workflows/gem-push.yml"
63
77
  - ".gitignore"
78
+ - ".rubocop.yml"
64
79
  - Gemfile
65
80
  - LICENSE.txt
66
81
  - README.md
@@ -100,6 +115,7 @@ files:
100
115
  - lib/discourse_dev/user.rb
101
116
  - lib/discourse_dev/version.rb
102
117
  - lib/faker/discourse.rb
118
+ - lib/faker/discourse_markdown.rb
103
119
  homepage: https://github.com/discourse/discourse_dev
104
120
  licenses:
105
121
  - MIT