rubocop-discourse 2.0.1 → 2.3.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: 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