rubocop-discourse 2.1.2 → 2.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: 938e8b3d2af662cc5d3a325fa317cf727164287036c47203481262f0fb00839c
4
- data.tar.gz: d7c47414ffccdd5e240f152a9994c1eba1bf96497f8d5ec96f5e11ec1972a8e7
3
+ metadata.gz: 4393a2ad64c2662ce3c1dcdb1608501b93b6c13bc31b9a7a2a25b2c8a1404e89
4
+ data.tar.gz: eabd1def336f6290d8a694c209256827585b4a28baa2f0a84fa74f65cfc76f07
5
5
  SHA512:
6
- metadata.gz: a8f462667a26681e75d9a492f7b07c836d249ba6f653acf200c66513ec890c7d5b97fddec986525994f1968e24563382d8504da8cd2ff6a070edde3e9b317a22
7
- data.tar.gz: 2f79d3ff37c7689fcea71e84ff4dffed726db49cca9063a79a212acd35a281b57231aa844093b63d50fcb2d8b89e1cf0e4477740b49e4dfdaab99a4fd3ed7b63
6
+ metadata.gz: 40a5a38b088a3ab91c3a155ab4a2bcf78ed44ecd62a4fc98ccbf2b21cba5aac0d6d906b460e5be293f48dace6be3295d73841b0c147f9c4296002b094971d95b
7
+ data.tar.gz: 72b08959eb26c04941c3fc972a3d9725f6465355f02c0fb1913dfa7826a76ca42ad716327a1a40ea541eebadbfc01715783dc2467fa255d204cff7d09c36f213
@@ -29,6 +29,9 @@ jobs:
29
29
 
30
30
  - name: Rubocop
31
31
  run: bundle exec rubocop
32
+
33
+ - name: Rspec
34
+ run: bundle exec rspec spec
32
35
 
33
36
  publish:
34
37
  if: contains(github.ref, 'refs/tags/v')
data/.gitignore CHANGED
@@ -1,2 +1,3 @@
1
1
  .rubocop-http*
2
2
  Gemfile.lock
3
+ .byebug_history
data/Gemfile CHANGED
@@ -4,3 +4,7 @@ source "https://rubygems.org"
4
4
 
5
5
  # Specify dependencies in gemspec
6
6
  gemspec
7
+
8
+ group :development, :test do
9
+ gem 'byebug'
10
+ end
@@ -7,9 +7,24 @@ Discourse/NoChdir:
7
7
  Discourse/NoTimeNewWithoutArgs:
8
8
  Enabled: true
9
9
 
10
- Discourse/NoUriEscapeEncode:
10
+ Discourse/NoURIEscapeEncode:
11
11
  Enabled: true
12
12
 
13
+ Discourse/NoAddReferenceOrAliasesActiveRecordMigration:
14
+ Enabled: true
15
+ Include:
16
+ - "**/db/migrate/*"
17
+ - "**/db/post_migrate/*"
18
+
19
+ Discourse/NoNokogiriHtmlFragment:
20
+ Enabled: true
21
+
22
+ Discourse/NoResetColumnInformationInMigrations:
23
+ Enabled: false
24
+ Include:
25
+ - "**/db/migrate/*"
26
+ - "**/db/post_migrate/*"
27
+
13
28
  # Specs
14
29
 
15
30
  Discourse/NoDirectMultisiteManipulation:
@@ -12,7 +12,7 @@ AllCops:
12
12
  - "db/schema.rb"
13
13
  - "bundle/**/*"
14
14
  - "vendor/**/*"
15
- - "node_modules/**/*"
15
+ - "**/node_modules/**/*"
16
16
  - "public/**/*"
17
17
  - "plugins/**/gems/**/*"
18
18
 
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Discourse
6
+ # The methods:
7
+ #
8
+ # * add_reference
9
+ # * add_belongs_to
10
+ # * t.references
11
+ # * t.belongs_to
12
+ #
13
+ # in ActiveRecord migrations are magic, and they all do
14
+ # some unexpected things in the background. For example, by default
15
+ # add_reference adds an index at the same time, but not concurrently,
16
+ # which is a nightmare for large tables.
17
+ #
18
+ # Instead, inside a disable_ddl_transaction! migration we should create
19
+ # the new column (with any defaults and options required) and the index
20
+ # concurrently using hand-written SQL. This also allows us to handle
21
+ # IF NOT EXISTS cases, which enable re-runnable migrations. Also we
22
+ # can pick a better name for the index at the same time.
23
+ #
24
+ # @example
25
+ #
26
+ # # bad
27
+ # def up
28
+ # add_reference :posts, :image_upload
29
+ # # or add_belongs_to :posts, :image_upload
30
+ # # or t.references :image_upload when doing create_table do |t|
31
+ # # or t.belongs_to :image_upload when doing create_table do |t|
32
+ # end
33
+ #
34
+ # # good
35
+ # disable_ddl_transaction!
36
+ # def up
37
+ # execute <<~SQL
38
+ # ALTER TABLE posts
39
+ # ADD COLUMN IF NOT EXISTS image_upload_id bigint
40
+ # SQL
41
+ #
42
+ # execute <<~SQL
43
+ # CREATE INDEX CONCURRENTLY IF NOT EXISTS
44
+ # index_posts_on_image_upload_id ON posts USING btree (image_upload_id)
45
+ # SQL
46
+ # end
47
+ class NoAddReferenceOrAliasesActiveRecordMigration < Cop
48
+ MSG = <<~MSG
49
+ AR methods add_reference, add_belongs_to, t.references, and t.belongs_to are
50
+ high-risk for large tables and have too many background magic operations.
51
+ Instead, write a disable_ddl_transactions! migration and write custom SQL to
52
+ add the new column and CREATE INDEX CONCURRENTLY. Use the IF NOT EXISTS clause
53
+ to make the migration re-runnable if it fails partway through.
54
+ MSG
55
+
56
+ def_node_matcher :using_add_reference?, <<-MATCHER
57
+ (send nil? :add_reference ...)
58
+ MATCHER
59
+
60
+ def_node_matcher :using_add_belongs_to?, <<-MATCHER
61
+ (send nil? :add_belongs_to ...)
62
+ MATCHER
63
+
64
+ def_node_matcher :using_t_references?, <<-MATCHER
65
+ (send (lvar _) :references ...)
66
+ MATCHER
67
+
68
+ def_node_matcher :using_t_belongs_to?, <<-MATCHER
69
+ (send (lvar _) :belongs_to ...)
70
+ MATCHER
71
+
72
+ def on_send(node)
73
+ return if [
74
+ using_add_reference?(node),
75
+ using_add_belongs_to?(node),
76
+ using_t_references?(node),
77
+ using_t_belongs_to?(node)
78
+ ].none?
79
+ add_offense(node, message: MSG)
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Discourse
6
+ # Do not use Nokogiri::HTML.fragment
7
+ # Instead use Nokogiri::HTML5.fragment, which is using Nokogumbo parser
8
+ #
9
+ # @example
10
+ # # bad
11
+ # Nokogiri::HTML.fragment("<p>test</p>")
12
+ #
13
+ # # good
14
+ # Nokogiri::HTML5.fragment("<p>test</p>")
15
+ class NoNokogiriHtmlFragment < Cop
16
+ MSG = "Nokogiri::HTML.fragment is deprecated and should not be used."
17
+
18
+ def_node_matcher :using_nokogiri_html_fragment?, <<-MATCHER
19
+ (send
20
+ (const
21
+ (const nil? :Nokogiri) :HTML) :fragment ...)
22
+ MATCHER
23
+
24
+ def on_send(node)
25
+ return if !using_nokogiri_html_fragment?(node)
26
+ add_offense(node, message: MSG)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Discourse
6
+ # Do not use `ActiveRecord::ModelSchema.reset_column_information` in
7
+ # migrations. The method is not thread safe and we run migrations
8
+ # concurrently for multisites. Also, we don't encourage the use of
9
+ # ActiveRecord methods in migrations and prefer to write SQL directly.
10
+ class NoResetColumnInformationInMigrations < Cop
11
+ MSG = "ActiveRecord::ModelSchema.reset_column_information is not thread-safe " \
12
+ "and we run migrations concurrently on multisite clusters. Using this " \
13
+ "method also means ActiveRecord methods are being used in migration "\
14
+ "which is discouraged at Discourse. Instead, you should write SQL in your migrations instead."
15
+
16
+ def on_send(node)
17
+ return if node.method_name != :reset_column_information
18
+ add_offense(node, message: MSG)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "rubocop-discourse"
5
- s.version = "2.1.2"
5
+ s.version = "2.2.0"
6
6
  s.summary = "Custom rubocop cops used by Discourse"
7
7
  s.authors = ["David Taylor"]
8
8
  s.files = `git ls-files`.split($/)
@@ -13,4 +13,5 @@ Gem::Specification.new do |s|
13
13
  s.add_runtime_dependency "rubocop-rspec", ">= 1.39.0"
14
14
 
15
15
  s.add_development_dependency "rake", "~> 13.0"
16
+ s.add_development_dependency "rspec"
16
17
  end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe RuboCop::Cop::Discourse::NoAddReferenceOrAliasesActiveRecordMigration, :config do
6
+ subject(:cop) { described_class.new(config) }
7
+ let(:config) do
8
+ RuboCop::Config.new
9
+ end
10
+
11
+ it "raises an offense if add_reference is used, with or without arguments" do
12
+ inspect_source(<<~RUBY)
13
+ add_reference :posts, :users, foreign_key: true, null: false
14
+ RUBY
15
+ expect(cop.offenses.first.message).to eq(described_class::MSG)
16
+ end
17
+
18
+ it "raises an offense if add_belongs_to is used, with or without arguments" do
19
+ inspect_source(<<~RUBY)
20
+ add_belongs_to :posts, :users, foreign_key: true, null: false
21
+ RUBY
22
+ expect(cop.offenses.first.message).to eq(described_class::MSG)
23
+ end
24
+
25
+ it "raises an offense if t.references, or any variable.references is used, with or without arguments" do
26
+ inspect_source(<<~RUBY)
27
+ create_table do |t|
28
+ t.references :topic, null: false
29
+ end
30
+ create_table do |mytable|
31
+ mytable.references :topic, null: false
32
+ end
33
+ RUBY
34
+ expect(cop.offenses.count).to eq(2)
35
+ expect(cop.offenses.first.message).to eq(described_class::MSG)
36
+ end
37
+
38
+ it "raises an offense if t.belongs_to, or any variable.belongs_to is used, with or without arguments" do
39
+ inspect_source(<<~RUBY)
40
+ create_table do |t|
41
+ t.belongs_to :topic, null: false
42
+ end
43
+ create_table do |mytable|
44
+ mytable.belongs_to :topic, null: false
45
+ end
46
+ RUBY
47
+ expect(cop.offenses.count).to eq(2)
48
+ expect(cop.offenses.first.message).to eq(described_class::MSG)
49
+ end
50
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe RuboCop::Cop::Discourse::NoResetColumnInformationInMigrations, :config do
6
+ subject(:cop) { described_class.new(config) }
7
+
8
+ let(:config) do
9
+ RuboCop::Config.new
10
+ end
11
+
12
+ it "raises an offense if reset_column_information is used" do
13
+ inspect_source(<<~RUBY)
14
+ class SomeMigration < ActiveRecord::Migration[6.0]
15
+ def up
16
+ Post.reset_column_information
17
+ end
18
+ end
19
+ RUBY
20
+
21
+ expect(cop.offenses.first.message).to eq(described_class::MSG)
22
+ end
23
+
24
+ it "raise an offense if reset_column_information is used without AR model" do
25
+ inspect_source(<<~RUBY)
26
+ class SomeMigration < ActiveRecord::Migration[6.0]
27
+ def up
28
+ "post".classify.constantize.reset_column_information
29
+ end
30
+ end
31
+ RUBY
32
+
33
+ expect(cop.offenses.first.message).to eq(described_class::MSG)
34
+ end
35
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ Bundler.setup
5
+
6
+ # Require supporting files exposed for testing.
7
+ require 'rubocop'
8
+ require 'rubocop/rspec/support'
9
+
10
+ require 'rubocop-discourse' # and any other gems you need
11
+
12
+ RSpec.configure do |config|
13
+ config.include RuboCop::RSpec::ExpectOffense
14
+ # some (optional) config here
15
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-discourse
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.2
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Taylor
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-03 00:00:00.000000000 Z
11
+ date: 2020-06-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '13.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
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:
56
70
  email:
57
71
  executables: []
@@ -68,9 +82,12 @@ files:
68
82
  - config/default.yml
69
83
  - default.yml
70
84
  - lib/rubocop-discourse.rb
85
+ - lib/rubocop/cop/discourse/no_add_reference_active_record_migrations.rb
71
86
  - lib/rubocop/cop/discourse/no_chdir.rb
72
87
  - lib/rubocop/cop/discourse/no_direct_multisite_manipulation.rb
73
88
  - lib/rubocop/cop/discourse/no_json_parse_response.rb
89
+ - lib/rubocop/cop/discourse/no_nokogiri_html_fragment.rb
90
+ - lib/rubocop/cop/discourse/no_reset_column_information_in_migrations.rb
74
91
  - lib/rubocop/cop/discourse/no_time_new_without_args.rb
75
92
  - lib/rubocop/cop/discourse/no_uri_escape_encode.rb
76
93
  - lib/rubocop/cop/discourse/time_eq_matcher.rb
@@ -80,6 +97,9 @@ files:
80
97
  - rubocop-core.yml
81
98
  - rubocop-discourse.gemspec
82
99
  - rubocop-rspec.yml
100
+ - spec/lib/rubocop/cop/no_add_reference_active_record_migrations_spec.rb
101
+ - spec/lib/rubocop/cop/no_reset_column_information_migrations_spec.rb
102
+ - spec/spec_helper.rb
83
103
  homepage:
84
104
  licenses:
85
105
  - MIT