rubocop-discourse 2.0.1 → 2.3.0

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: 8e9b0623d47b96bbaa5a7e78f2da4e889d03bbce2f16e2ab90e9ce61530a69f9
4
- data.tar.gz: c3385aefb750fa0a379599f2ddce69a66d03186b1e0c21e1552f0c94e9347a96
3
+ metadata.gz: 954b3ae3f59036a9880d2d055c37e97e5bbc0d454207638cc390efb41cfde649
4
+ data.tar.gz: 7b5607256ae2d3190a9d7d1ef7d95f73deb23964139a8a10c3fb628663912d96
5
5
  SHA512:
6
- metadata.gz: 495b86ba2534d8d9b725628337eb70d0c96a2927aa6867f99ef59cd5b8c668530baf54637fe49f0fb08ba0b5c6b648cd2ce74a1b962af811f50d92cdb4bc6c31
7
- data.tar.gz: b37411ba21ac5c4fcf1e5586f8a5c2419c251e74937499fafe68b8ecb06b75bc881582f813ac8af8f0b8c77675c0e750b001fc75e004607f460f646399b924be
6
+ metadata.gz: 4916ff3fcd7569705f59ced1716acbbeec52d763eff392e6eb148d5bc72d4fe6cff5644a0dfedc89353b4f856d77e609159d178b2b2d9643f904bed88d59cb4a
7
+ data.tar.gz: 8c1a20229b96ef6b69085147c95c5b799c6f7c9b0d38e8dc63c5cb5dc07931a332c231771f45fe656bd03c563fd3fa85f8f1c2bf79d9d64ad96415ce6ce764e3
@@ -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
@@ -1,4 +1,2 @@
1
- inherit_from: https://raw.githubusercontent.com/discourse/discourse/master/.rubocop.yml
2
-
3
- Discourse:
4
- Enabled: true
1
+ inherit_from:
2
+ - default.yml
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
@@ -0,0 +1,11 @@
1
+ # rubocop-discourse
2
+
3
+ ## Usage
4
+
5
+ Add `gem "rubocop-discourse"` to your Gemfile.
6
+ Then add the following to `.rubocop.yml`:
7
+
8
+ ```yml
9
+ inherit_gem:
10
+ rubocop-discourse: default.yml
11
+ ```
@@ -1,14 +1,52 @@
1
1
  Discourse/NoChdir:
2
2
  Enabled: true
3
+ Exclude:
4
+ - 'spec/**/*' # Specs are run sequentially, so chdir can be used
5
+ - 'plugins/*/spec/**/*'
3
6
 
4
- Discourse/NoDirectMultisiteManipulation:
7
+ Discourse/NoTimeNewWithoutArgs:
5
8
  Enabled: true
6
9
 
7
- Discourse/NoTimeNewWithoutArgs:
10
+ Discourse/NoURIEscapeEncode:
8
11
  Enabled: true
9
12
 
10
- Discourse/NoUriEscapeEncode:
13
+ Discourse/NoAddReferenceOrAliasesActiveRecordMigration:
11
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
+
28
+ # Specs
29
+
30
+ Discourse/NoDirectMultisiteManipulation:
31
+ Enabled: true
32
+ Patterns:
33
+ - _spec.rb
34
+ - "(?:^|/)spec/"
12
35
 
13
36
  Discourse/TimeEqMatcher:
14
37
  Enabled: true
38
+ Patterns:
39
+ - _spec.rb
40
+ - "(?:^|/)spec/"
41
+
42
+ Discourse/NoJsonParseResponse:
43
+ Enabled: false
44
+ Patterns:
45
+ - _spec.rb
46
+ - "(?:^|/)spec/"
47
+
48
+ Discourse/NoMockingJobs:
49
+ Enabled: true
50
+ Patterns:
51
+ - _spec.rb
52
+ - "(?:^|/)spec/"
@@ -0,0 +1,20 @@
1
+ require:
2
+ - rubocop-discourse
3
+
4
+ inherit_from:
5
+ - ./rubocop-core.yml
6
+ - ./rubocop-rspec.yml
7
+
8
+ AllCops:
9
+ TargetRubyVersion: 2.6
10
+ DisabledByDefault: true
11
+ Exclude:
12
+ - "db/schema.rb"
13
+ - "bundle/**/*"
14
+ - "vendor/**/*"
15
+ - "**/node_modules/**/*"
16
+ - "public/**/*"
17
+ - "plugins/**/gems/**/*"
18
+
19
+ Discourse:
20
+ Enabled: true
@@ -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,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Discourse
6
+ # Use `response.parsed_body` instead of `JSON.parse(response.body)` in specs.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # expect(::JSON.parse(response.body)).to eq({})
11
+ #
12
+ # # good
13
+ # expect(response.parsed_body).to eq({})
14
+ class NoJsonParseResponse < Cop
15
+ MSG = "Use `response.parsed_body` instead of `JSON.parse(response.body)` in specs."
16
+
17
+ def_node_matcher :json_parse_body?, <<-MATCHER
18
+ (send
19
+ (const {cbase nil?} :JSON) :parse
20
+ (send
21
+ (send nil? :response) :body))
22
+ MATCHER
23
+
24
+ def on_send(node)
25
+ return unless json_parse_body?(node)
26
+
27
+ add_offense(node, message: MSG)
28
+ end
29
+
30
+ def autocorrect(node)
31
+ lambda do |corrector|
32
+ corrector.replace(node.loc.expression, "response.parsed_body")
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Discourse
6
+ class NoMockingJobs < Cop
7
+ MSG = "Use the test helpers provided by Sidekiq instead of mocking `Jobs`."
8
+
9
+ def_node_matcher :mocking_jobs?, <<~MATCHER
10
+ (send (const nil? :Jobs) :expects ...)
11
+ MATCHER
12
+
13
+ def on_send(node)
14
+ return unless mocking_jobs?(node)
15
+ add_offense(node, message: MSG)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ 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
@@ -0,0 +1,123 @@
1
+ # Prefer &&/|| over and/or.
2
+ Style/AndOr:
3
+ Enabled: true
4
+
5
+ Style/FrozenStringLiteralComment:
6
+ Enabled: true
7
+
8
+ # Use Ruby >= 1.9 syntax for hashes. Prefer { a: :b } over { :a => :b }.
9
+ Style/HashSyntax:
10
+ Enabled: true
11
+
12
+ # Defining a method with parameters needs parentheses.
13
+ Style/MethodDefParentheses:
14
+ Enabled: true
15
+
16
+ Style/SingleLineMethods:
17
+ Enabled: true
18
+
19
+ Style/Semicolon:
20
+ Enabled: true
21
+ AllowAsExpressionSeparator: true
22
+
23
+ Style/RedundantReturn:
24
+ Enabled: true
25
+
26
+ Style/GlobalVars:
27
+ Enabled: true
28
+ Severity: warning
29
+ Exclude:
30
+ - 'lib/tasks/**/*'
31
+ - 'script/**/*'
32
+ - 'spec/**/*.rb'
33
+ - 'plugins/*/spec/**/*'
34
+
35
+ # Align `when` with `case`.
36
+ Layout/CaseIndentation:
37
+ Enabled: true
38
+
39
+ # Align comments with method definitions.
40
+ Layout/CommentIndentation:
41
+ Enabled: true
42
+
43
+ # No extra empty lines.
44
+ Layout/EmptyLines:
45
+ Enabled: true
46
+
47
+ # Two spaces, no tabs (for indentation).
48
+ Layout/IndentationWidth:
49
+ Enabled: true
50
+
51
+ Layout/SpaceAfterColon:
52
+ Enabled: true
53
+
54
+ Layout/SpaceAfterComma:
55
+ Enabled: true
56
+
57
+ Layout/SpaceAroundEqualsInParameterDefault:
58
+ Enabled: true
59
+
60
+ Layout/SpaceAroundKeyword:
61
+ Enabled: true
62
+
63
+ Layout/SpaceAroundOperators:
64
+ Enabled: true
65
+
66
+ Layout/SpaceBeforeFirstArg:
67
+ Enabled: true
68
+
69
+ # Use `foo {}` not `foo{}`.
70
+ Layout/SpaceBeforeBlockBraces:
71
+ Enabled: true
72
+
73
+ # Use `foo { bar }` not `foo {bar}`.
74
+ Layout/SpaceInsideBlockBraces:
75
+ Enabled: true
76
+
77
+ # Use `{ a: 1 }` not `{a:1}`.
78
+ Layout/SpaceInsideHashLiteralBraces:
79
+ Enabled: true
80
+
81
+ Layout/SpaceInsideParens:
82
+ Enabled: true
83
+
84
+ # Detect hard tabs, no hard tabs.
85
+ Layout/IndentationStyle:
86
+ Enabled: true
87
+
88
+ # Blank lines should not have any spaces.
89
+ Layout/TrailingEmptyLines:
90
+ Enabled: true
91
+
92
+ # No trailing whitespace.
93
+ Layout/TrailingWhitespace:
94
+ Enabled: true
95
+
96
+ Layout/BlockAlignment:
97
+ Enabled: true
98
+
99
+ # Align `end` with the matching keyword or starting expression except for
100
+ # assignments, where it should be aligned with the LHS.
101
+ Layout/EndAlignment:
102
+ Enabled: true
103
+ EnforcedStyleAlignWith: variable
104
+
105
+ Layout/MultilineMethodCallIndentation:
106
+ Enabled: true
107
+ EnforcedStyle: indented
108
+
109
+ Layout/HashAlignment:
110
+ Enabled: true
111
+
112
+ Lint/Debugger:
113
+ Enabled: true
114
+
115
+ # Use my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
116
+ Lint/RequireParentheses:
117
+ Enabled: true
118
+
119
+ Lint/ShadowingOuterLocalVariable:
120
+ Enabled: true
121
+
122
+ Bundler/OrderedGems:
123
+ Enabled: false
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "rubocop-discourse"
5
- s.version = "2.0.1"
5
+ s.version = "2.3.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($/)
@@ -10,6 +10,8 @@ Gem::Specification.new do |s|
10
10
  s.require_paths = ["lib"]
11
11
 
12
12
  s.add_runtime_dependency "rubocop", ">= 0.69.0"
13
+ s.add_runtime_dependency "rubocop-rspec", ">= 1.39.0"
13
14
 
14
15
  s.add_development_dependency "rake", "~> 13.0"
16
+ s.add_development_dependency "rspec"
15
17
  end
@@ -0,0 +1,211 @@
1
+ require:
2
+ - rubocop-rspec
3
+
4
+ RSpec/AnyInstance:
5
+ Enabled: false # To be decided
6
+
7
+ RSpec/AroundBlock:
8
+ Enabled: true
9
+
10
+ RSpec/BeforeAfterAll:
11
+ Enabled: false # To be decided
12
+
13
+ RSpec/ContextMethod:
14
+ Enabled: false # TODO
15
+
16
+ RSpec/ContextWording:
17
+ Enabled: false # To be decided
18
+
19
+ RSpec/DescribeClass:
20
+ Enabled: false # To be decided
21
+
22
+ RSpec/DescribeMethod:
23
+ Enabled: true
24
+
25
+ RSpec/DescribeSymbol:
26
+ Enabled: false # To be decided
27
+
28
+ RSpec/DescribedClass:
29
+ Enabled: false # To be decided
30
+
31
+ RSpec/DescribedClassModuleWrapping:
32
+ Enabled: false # To be decided
33
+
34
+ RSpec/EmptyExampleGroup:
35
+ Enabled: true
36
+ Exclude:
37
+ - 'spec/requests/api/*'
38
+
39
+ RSpec/EmptyLineAfterExample:
40
+ Enabled: false # TODO
41
+
42
+ RSpec/EmptyLineAfterExampleGroup:
43
+ Enabled: false # TODO
44
+
45
+ RSpec/EmptyLineAfterFinalLet:
46
+ Enabled: false # TODO
47
+
48
+ RSpec/EmptyLineAfterHook:
49
+ Enabled: false # TODO
50
+
51
+ RSpec/EmptyLineAfterSubject:
52
+ Enabled: false # TODO
53
+
54
+ RSpec/ExampleLength:
55
+ Enabled: false # To be decided
56
+
57
+ RSpec/ExampleWithoutDescription:
58
+ Enabled: true
59
+
60
+ RSpec/ExampleWording:
61
+ Enabled: false # TODO
62
+
63
+ RSpec/ExpectActual:
64
+ Enabled: true
65
+
66
+ RSpec/ExpectChange:
67
+ Enabled: false # To be decided
68
+
69
+ RSpec/ExpectInHook:
70
+ Enabled: false # To be decided
71
+
72
+ RSpec/ExpectOutput:
73
+ Enabled: true
74
+
75
+ RSpec/FilePath:
76
+ Enabled: false # To be decided
77
+
78
+ RSpec/Focus:
79
+ Enabled: true
80
+
81
+ RSpec/HookArgument:
82
+ Enabled: false # TODO
83
+
84
+ RSpec/HooksBeforeExamples:
85
+ Enabled: false # TODO
86
+
87
+ RSpec/ImplicitBlockExpectation:
88
+ Enabled: true
89
+
90
+ RSpec/ImplicitExpect:
91
+ Enabled: false # To be decided
92
+
93
+ RSpec/ImplicitSubject:
94
+ Enabled: false # To be decided
95
+
96
+ RSpec/InstanceSpy:
97
+ Enabled: true
98
+
99
+ RSpec/InstanceVariable:
100
+ Enabled: false # TODO
101
+
102
+ RSpec/InvalidPredicateMatcher:
103
+ Enabled: true
104
+
105
+ RSpec/ItBehavesLike:
106
+ Enabled: true
107
+
108
+ RSpec/IteratedExpectation:
109
+ Enabled: false # To be decided
110
+
111
+ RSpec/LeadingSubject:
112
+ Enabled: false # TODO
113
+
114
+ RSpec/LeakyConstantDeclaration:
115
+ Enabled: false # To be decided
116
+
117
+ RSpec/LetBeforeExamples:
118
+ Enabled: false # TODO
119
+
120
+ RSpec/LetSetup:
121
+ Enabled: false # TODO
122
+
123
+ RSpec/MessageChain:
124
+ Enabled: true
125
+
126
+ RSpec/MessageSpies:
127
+ Enabled: true
128
+
129
+ RSpec/MissingExampleGroupArgument:
130
+ Enabled: true
131
+
132
+ RSpec/MultipleDescribes:
133
+ Enabled: false # TODO
134
+
135
+ RSpec/MultipleSubjects:
136
+ Enabled: true
137
+
138
+ RSpec/NamedSubject:
139
+ Enabled: false # To be decided
140
+
141
+ RSpec/NestedGroups:
142
+ Enabled: false # To be decided
143
+
144
+ RSpec/OverwritingSetup:
145
+ Enabled: true
146
+
147
+ RSpec/ReceiveCounts:
148
+ Enabled: true
149
+
150
+ RSpec/ReceiveNever:
151
+ Enabled: true
152
+
153
+ RSpec/RepeatedDescription:
154
+ Enabled: false # TODO
155
+
156
+ RSpec/RepeatedExample:
157
+ Enabled: false # TODO
158
+
159
+ RSpec/RepeatedExampleGroupBody:
160
+ Enabled: false # TODO
161
+
162
+ RSpec/RepeatedExampleGroupDescription:
163
+ Enabled: false # TODO
164
+
165
+ RSpec/ReturnFromStub:
166
+ Enabled: true
167
+
168
+ RSpec/ScatteredSetup:
169
+ Enabled: false # TODO
170
+
171
+ RSpec/SharedContext:
172
+ Enabled: true
173
+
174
+ RSpec/SharedExamples:
175
+ Enabled: true
176
+
177
+ RSpec/SingleArgumentMessageChain:
178
+ Enabled: true
179
+
180
+ RSpec/SubjectStub:
181
+ Enabled: true
182
+
183
+ RSpec/UnspecifiedException:
184
+ Enabled: true
185
+
186
+ RSpec/VerifiedDoubles:
187
+ Enabled: true
188
+
189
+ RSpec/VoidExpect:
190
+ Enabled: true
191
+
192
+ RSpec/Yield:
193
+ Enabled: true
194
+
195
+ Capybara/CurrentPathExpectation:
196
+ Enabled: true
197
+
198
+ Capybara/FeatureMethods:
199
+ Enabled: true
200
+
201
+ FactoryBot/AttributeDefinedStatically:
202
+ Enabled: true
203
+
204
+ FactoryBot/CreateList:
205
+ Enabled: true
206
+
207
+ FactoryBot/FactoryClassName:
208
+ Enabled: true
209
+
210
+ Rails/HttpStatus:
211
+ Enabled: true
@@ -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,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe RuboCop::Cop::Discourse::NoMockingJobs, :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 Jobs is mocked" do
13
+ inspect_source(<<~RUBY)
14
+ Jobs.expects(:enqueue)
15
+ RUBY
16
+
17
+ expect(cop.offenses.first.message).to eq(described_class::MSG)
18
+ end
19
+
20
+ it "does not raise an offense if Jobs is not mocked" do
21
+ inspect_source(<<~RUBY)
22
+ Jobs.enqueue(:some_job)
23
+ RUBY
24
+
25
+ expect(cop.offenses).to eq([])
26
+ end
27
+ 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.0.1
4
+ version: 2.3.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-03-24 00:00:00.000000000 Z
11
+ date: 2020-07-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 0.69.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: rubocop-rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.39.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 1.39.0
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rake
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +52,20 @@ dependencies:
38
52
  - - "~>"
39
53
  - !ruby/object:Gem::Version
40
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'
41
69
  description:
42
70
  email:
43
71
  executables: []
@@ -49,18 +77,31 @@ files:
49
77
  - ".rubocop.yml"
50
78
  - Gemfile
51
79
  - LICENSE
80
+ - README.md
52
81
  - Rakefile
53
82
  - config/default.yml
83
+ - default.yml
54
84
  - lib/rubocop-discourse.rb
85
+ - lib/rubocop/cop/discourse/no_add_reference_active_record_migrations.rb
55
86
  - lib/rubocop/cop/discourse/no_chdir.rb
56
87
  - lib/rubocop/cop/discourse/no_direct_multisite_manipulation.rb
88
+ - lib/rubocop/cop/discourse/no_json_parse_response.rb
89
+ - lib/rubocop/cop/discourse/no_mocking_jobs.rb
90
+ - lib/rubocop/cop/discourse/no_nokogiri_html_fragment.rb
91
+ - lib/rubocop/cop/discourse/no_reset_column_information_in_migrations.rb
57
92
  - lib/rubocop/cop/discourse/no_time_new_without_args.rb
58
93
  - lib/rubocop/cop/discourse/no_uri_escape_encode.rb
59
94
  - lib/rubocop/cop/discourse/time_eq_matcher.rb
60
95
  - lib/rubocop/cop/discourse_cops.rb
61
96
  - lib/rubocop/discourse.rb
62
97
  - lib/rubocop/discourse/inject.rb
98
+ - rubocop-core.yml
63
99
  - rubocop-discourse.gemspec
100
+ - rubocop-rspec.yml
101
+ - spec/lib/rubocop/cop/no_add_reference_active_record_migrations_spec.rb
102
+ - spec/lib/rubocop/cop/no_mocking_jobs_spec.rb
103
+ - spec/lib/rubocop/cop/no_reset_column_information_migrations_spec.rb
104
+ - spec/spec_helper.rb
64
105
  homepage:
65
106
  licenses:
66
107
  - MIT