isolator 0.4.0 → 0.7.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 +4 -4
- data/CHANGELOG.md +46 -0
- data/LICENSE.txt +1 -1
- data/README.md +38 -5
- data/lib/isolator.rb +125 -18
- data/lib/isolator/adapter_builder.rb +2 -1
- data/lib/isolator/adapters/background_jobs/active_job.rb +7 -3
- data/lib/isolator/adapters/background_jobs/resque.rb +6 -3
- data/lib/isolator/adapters/background_jobs/resque_scheduler.rb +6 -3
- data/lib/isolator/adapters/background_jobs/sidekiq.rb +8 -3
- data/lib/isolator/adapters/background_jobs/sucker_punch.rb +6 -3
- data/lib/isolator/adapters/base.rb +8 -7
- data/lib/isolator/adapters/http/sniffer.rb +5 -1
- data/lib/isolator/adapters/http/webmock.rb +5 -1
- data/lib/isolator/adapters/mailers/mail.rb +8 -2
- data/lib/isolator/configuration.rb +11 -3
- data/lib/isolator/errors.rb +2 -2
- data/lib/isolator/ignorer.rb +41 -21
- data/lib/isolator/isolate.rb +1 -1
- data/lib/isolator/notifier.rb +1 -1
- data/lib/isolator/orm_adapters/active_support_subscriber.rb +3 -2
- data/lib/isolator/railtie.rb +11 -5
- data/lib/isolator/version.rb +1 -1
- metadata +49 -56
- data/.gitignore +0 -13
- data/.rubocop.yml +0 -62
- data/.travis.yml +0 -26
- data/Gemfile +0 -18
- data/Rakefile +0 -8
- data/bin/console +0 -7
- data/bin/setup +0 -8
- data/gemfiles/activerecord42.gemfile +0 -6
- data/gemfiles/jruby.gemfile +0 -7
- data/gemfiles/railsmaster.gemfile +0 -7
- data/isolator.gemspec +0 -42
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 00d85d8a62a5a34bd39ef9295e1e8ad9c13599fc17648bbda7a5012f9a89ddfa
|
4
|
+
data.tar.gz: cf7a441154f63bc40258b4a78e57e3d3f46158b915167c1631d717530571dcd2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a088b0f2e24c8afd8a2ec3fd65df4ef5e2d550f55c8376132955db8f870f68a28f021b8079024b413ef2692a474136f3d7da56c098a89d2e3b3aa52deb0ce334
|
7
|
+
data.tar.gz: d3667e26d54697e09eaefd7cdee7e9c5586e307c371ce41215d8eca88dc514c652079088bba2af3aeb654b9bfbdad3a3ab6080c5f20b47867291cf4734f16cda
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,49 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
+
## 0.7.0 (2020-09-25)
|
6
|
+
|
7
|
+
- Add debug mode. ([@palkan][])
|
8
|
+
|
9
|
+
Use `ISOLATOR_DEBUG=true` to turn on debug mode, which prints some useful information: when a transaction is tracked,
|
10
|
+
thresholds are changed, etc.
|
11
|
+
|
12
|
+
- Track transactions for different connections independently. ([@mquan][], [@palkan][])
|
13
|
+
|
14
|
+
This, for example, makes Isolator compatible with Rails multi-database apps.
|
15
|
+
|
16
|
+
- Allow custom ignorer usage. ([@iiwo][])
|
17
|
+
|
18
|
+
- `Isolator.load_ignore_config` is deprecated in favor of `Isolator::Ignorer.prepare`. ([@iiwo][])
|
19
|
+
|
20
|
+
## 0.6.2 (2020-03-20)
|
21
|
+
|
22
|
+
- Make Sniffer version requirement open-ended. ([@palkan][])
|
23
|
+
|
24
|
+
- **Support Ruby 2.5+** ([@palkan][])
|
25
|
+
|
26
|
+
## 0.6.1 (2019-09-06)
|
27
|
+
|
28
|
+
- Fix Sniffer integration. ([@palkan][])
|
29
|
+
|
30
|
+
Fixes [#21](https://github.com/palkan/isolator/issues/21).
|
31
|
+
|
32
|
+
## 0.6.0 (2019-04-12) 🚀
|
33
|
+
|
34
|
+
- Add support for exceptions message details. ([@palkan][])
|
35
|
+
|
36
|
+
Make it possible to provide more information about the cause of the failure
|
37
|
+
(for example, job class and arguments for background jobs, URL for HTTP).
|
38
|
+
|
39
|
+
- Change backtrace filtering behaviour. ([@palkan][])
|
40
|
+
|
41
|
+
The default behaviour is to take the top five lines.
|
42
|
+
You can customize it via `Isolator.config.backtrace_filter`.
|
43
|
+
|
44
|
+
## 0.5.0 (2018-08-29)
|
45
|
+
|
46
|
+
- [PR [#19](https://github.com/palkan/isolator/pull/19)] Adding support for ruby version 2.2.2. ([@shivanshgaur][])
|
47
|
+
|
5
48
|
## 0.4.0 (2018-06-15)
|
6
49
|
|
7
50
|
- [PR [#13](https://github.com/palkan/isolator/pull/13)] Allow load ignored offences from YML file using `load_ignore_config`. ([@DmitryTsepelev][])
|
@@ -47,3 +90,6 @@
|
|
47
90
|
[@dsalahutdinov]: https://github.com/dsalahutdinov
|
48
91
|
[@Envek]: https://github.com/Envek
|
49
92
|
[@DmitryTsepelev]: https://github.com/DmitryTsepelev
|
93
|
+
[@shivanshgaur]: https://github.com/shivanshgaur
|
94
|
+
[@iiwo]: https://github.com/iiwo
|
95
|
+
[@mquan]: https://github.com/mquan
|
data/LICENSE.txt
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
The MIT License (MIT)
|
2
2
|
|
3
|
-
Copyright (c) 2018 Vladimir Dementyev
|
3
|
+
Copyright (c) 2018-2020 Vladimir Dementyev
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
[](http://cultofmartians.com/tasks/isolator.html)
|
2
2
|
[](https://badge.fury.io/rb/isolator)
|
3
|
-
|
3
|
+

|
4
4
|
|
5
5
|
# Isolator
|
6
6
|
|
@@ -79,6 +79,8 @@ However, there are some potential caveats:
|
|
79
79
|
|
80
80
|
3) Isolator tries to detect the `test` environment and slightly change its behavior: first, it respect _transactional tests_; secondly, error raising is turned on by default (see [below](#configuration)).
|
81
81
|
|
82
|
+
4) Experimental [multiple databases](https://guides.rubyonrails.org/active_record_multiple_databases.html) has been added in v0.7.0. Please, let us know if you encounter any issues.
|
83
|
+
|
82
84
|
### Configuration
|
83
85
|
|
84
86
|
```ruby
|
@@ -91,6 +93,14 @@ Isolator.configure do |config|
|
|
91
93
|
|
92
94
|
# Send notifications to uniform_notifier
|
93
95
|
config.send_notifications = false
|
96
|
+
|
97
|
+
# Customize backtrace filtering (provide a callable)
|
98
|
+
# By default, just takes the top-5 lines
|
99
|
+
config.backtrace_filter = ->(backtrace) { backtrace.take(5) }
|
100
|
+
|
101
|
+
# Define a custom ignorer class (must implement .prepare)
|
102
|
+
# uses a row number based list from the .isolator_todo.yml file
|
103
|
+
config.ignorer = Isolator::Ignorer
|
94
104
|
end
|
95
105
|
```
|
96
106
|
|
@@ -106,7 +116,7 @@ Isolator relys on [uniform_notifier][] to send custom notifications.
|
|
106
116
|
### Supported ORMs
|
107
117
|
|
108
118
|
- `ActiveRecord` >= 4.1
|
109
|
-
- `ROM::SQL` (only if Active Support instrumentation
|
119
|
+
- `ROM::SQL` (only if Active Support instrumentation extension is loaded)
|
110
120
|
|
111
121
|
### Adapters
|
112
122
|
|
@@ -163,7 +173,7 @@ All the exceptions raised in the listed lines will be ignored.
|
|
163
173
|
|
164
174
|
### Using with legacy Ruby codebases
|
165
175
|
|
166
|
-
If you are not using Rails, you'll have to load ignores from file manually, using `Isolator
|
176
|
+
If you are not using Rails, you'll have to load ignores from file manually, using `Isolator::Ignorer.prepare(path:)`, for instance `Isolator::Ignorer.prepare(path: "./config/.isolator_todo.yml")`
|
167
177
|
|
168
178
|
## Custom Adapters
|
169
179
|
|
@@ -179,13 +189,24 @@ Suppose that you have a class `Danger` with a method `#explode`, which is not sa
|
|
179
189
|
# the third one is a method name.
|
180
190
|
Isolator.isolate :danger, Danger, :explode, options
|
181
191
|
|
182
|
-
# NOTE: if you want to isolate a class method, use
|
192
|
+
# NOTE: if you want to isolate a class method, use singleton_class instead
|
183
193
|
Isolator.isolate :danger, Danger.singleton_class, :explode, options
|
184
194
|
```
|
185
195
|
|
186
196
|
Possible `options` are:
|
187
197
|
- `exception_class` – an exception class to raise in case of offense
|
188
198
|
- `exception_message` – custom exception message (could be specified without a class)
|
199
|
+
- `details_message` – a block to generate additional exceptin message information:
|
200
|
+
|
201
|
+
```ruby
|
202
|
+
Isolator.isolate :active_job,
|
203
|
+
target: ActiveJob::Base,
|
204
|
+
method_name: :enqueue,
|
205
|
+
exception_class: Isolator::BackgroundJobError,
|
206
|
+
details_message: ->(obj, _args) {
|
207
|
+
"#{obj.class.name}(#{obj.arguments})"
|
208
|
+
}
|
209
|
+
```
|
189
210
|
|
190
211
|
You can also add some callbacks to be run before and after the transaction:
|
191
212
|
|
@@ -195,10 +216,22 @@ Isolator.before_isolate do
|
|
195
216
|
end
|
196
217
|
|
197
218
|
Isolator.after_isolate do
|
198
|
-
# right after the transaction has been committed/
|
219
|
+
# right after the transaction has been committed/rolled back
|
199
220
|
end
|
200
221
|
```
|
201
222
|
|
223
|
+
## Troubleshooting
|
224
|
+
|
225
|
+
### Verbose output
|
226
|
+
|
227
|
+
In most cases, turning on verbose output for Isolator helps to identify the issue. To do that, you can either specify `ISOLATOR_DEBUG=true` environment variable or set `Isolator.debug_enabled` manually.
|
228
|
+
|
229
|
+
### Tests failing after upgrading to Rails 6.0.3 while using [Combustion](https://github.com/pat/combustion)
|
230
|
+
|
231
|
+
The reason is that Rails started using a [separate connection pool for advisory locks](https://github.com/rails/rails/pull/38235) since 6.0.3. Since Combustion usually applies migrations for every test run, this pool becomse visible to [test fixtures](https://github.com/rails/rails/blob/b738f1930f3c82f51741ef7241c1fee691d7deb2/activerecord/lib/active_record/test_fixtures.rb#L123-L127), which resulted in 2 transactional commits tracked by Isolator, which only expects one. That leads to false negatives.
|
232
|
+
|
233
|
+
To fix this disable migrations advisory locks by adding `advisory_locks: false` to your database configuration in `(spec|test)/internal/config/database.yml`.
|
234
|
+
|
202
235
|
## Contributing
|
203
236
|
|
204
237
|
Bug reports and pull requests are welcome on GitHub at https://github.com/palkan/isolator.
|
data/lib/isolator.rb
CHANGED
@@ -17,7 +17,25 @@ require "isolator/ext/thread_fetch"
|
|
17
17
|
module Isolator
|
18
18
|
using Isolator::ThreadFetch
|
19
19
|
|
20
|
+
class ThreadStateProxy
|
21
|
+
attr_reader :prefix
|
22
|
+
|
23
|
+
def initilize(prefix = "isolator_")
|
24
|
+
@prefix = prefix
|
25
|
+
end
|
26
|
+
|
27
|
+
def [](key)
|
28
|
+
Thread.current[:"#{prefix}#{key}"]
|
29
|
+
end
|
30
|
+
|
31
|
+
def []=(key, value)
|
32
|
+
Thread.current[:"#{prefix}#{key}"] = value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
20
36
|
class << self
|
37
|
+
attr_accessor :default_threshold, :default_connection_id
|
38
|
+
|
21
39
|
def config
|
22
40
|
@config ||= Configuration.new
|
23
41
|
end
|
@@ -31,11 +49,11 @@ module Isolator
|
|
31
49
|
end
|
32
50
|
|
33
51
|
def enable!
|
34
|
-
|
52
|
+
state[:disabled] = false
|
35
53
|
end
|
36
54
|
|
37
55
|
def disable!
|
38
|
-
|
56
|
+
state[:disabled] = true
|
39
57
|
end
|
40
58
|
|
41
59
|
# Accepts block and disable Isolator within
|
@@ -64,32 +82,77 @@ module Isolator
|
|
64
82
|
res
|
65
83
|
end
|
66
84
|
|
67
|
-
def transactions_threshold
|
68
|
-
|
85
|
+
def transactions_threshold=(val)
|
86
|
+
set_connection_threshold(val)
|
87
|
+
end
|
88
|
+
|
89
|
+
def transactions_threshold(connection_id = default_connection_id.call)
|
90
|
+
connection_threshold(connection_id)
|
69
91
|
end
|
70
92
|
|
71
|
-
def
|
72
|
-
|
93
|
+
def current_transactions(connection_id = default_connection_id.call)
|
94
|
+
state[:transactions]&.[](connection_id) || 0
|
73
95
|
end
|
74
96
|
|
75
|
-
def
|
76
|
-
|
77
|
-
|
78
|
-
|
97
|
+
def set_connection_threshold(val, connection_id = default_connection_id.call)
|
98
|
+
state[:thresholds] ||= Hash.new { |h, k| h[k] = Isolator.default_threshold }
|
99
|
+
state[:thresholds][connection_id] = val
|
100
|
+
|
101
|
+
debug!("Threshold value was changed for connection #{connection_id}: #{val}")
|
79
102
|
end
|
80
103
|
|
81
|
-
def
|
82
|
-
|
83
|
-
|
84
|
-
|
104
|
+
def incr_thresholds!
|
105
|
+
self.default_threshold += 1
|
106
|
+
return unless state[:thresholds]
|
107
|
+
|
108
|
+
state[:thresholds].transform_values!(&:succ)
|
109
|
+
|
110
|
+
debug!("Thresholds were incremented")
|
111
|
+
end
|
112
|
+
|
113
|
+
def decr_thresholds!
|
114
|
+
self.default_threshold -= 1
|
115
|
+
return unless state[:thresholds]
|
116
|
+
|
117
|
+
state[:thresholds].transform_values!(&:pred)
|
118
|
+
|
119
|
+
debug!("Thresholds were decremented")
|
120
|
+
end
|
121
|
+
|
122
|
+
def incr_transactions!(connection_id = default_connection_id.call)
|
123
|
+
state[:transactions] ||= Hash.new { |h, k| h[k] = 0 }
|
124
|
+
state[:transactions][connection_id] += 1
|
125
|
+
|
126
|
+
# Workaround to track threshold changes made before opening a connection
|
127
|
+
pending_threshold = state[:thresholds]&.delete(0)
|
128
|
+
if pending_threshold
|
129
|
+
state[:thresholds][connection_id] = pending_threshold
|
130
|
+
end
|
131
|
+
|
132
|
+
debug!("Transaction opened for connection #{connection_id} (total: #{state[:transactions][connection_id]}, threshold: #{state[:thresholds]&.fetch(connection_id, default_threshold)})")
|
133
|
+
|
134
|
+
start! if current_transactions(connection_id) == connection_threshold(connection_id)
|
135
|
+
end
|
136
|
+
|
137
|
+
def decr_transactions!(connection_id = default_connection_id.call)
|
138
|
+
state[:transactions][connection_id] -= 1
|
139
|
+
|
140
|
+
finish! if current_transactions(connection_id) == (connection_threshold(connection_id) - 1)
|
141
|
+
|
142
|
+
state[:transactions].delete(connection_id) if state[:transactions][connection_id].zero?
|
143
|
+
|
144
|
+
debug!("Transaction closed for connection #{connection_id} (total: #{state[:transactions][connection_id]}, threshold: #{state[:thresholds]&.[](connection_id) || default_threshold})")
|
85
145
|
end
|
86
146
|
|
87
147
|
def clear_transactions!
|
88
|
-
|
148
|
+
state[:transactions]&.clear
|
89
149
|
end
|
90
150
|
|
91
151
|
def within_transaction?
|
92
|
-
|
152
|
+
state[:transactions]&.each do |connection_id, transaction_count|
|
153
|
+
return true if transaction_count >= connection_threshold(connection_id)
|
154
|
+
end
|
155
|
+
false
|
93
156
|
end
|
94
157
|
|
95
158
|
def enabled?
|
@@ -97,17 +160,61 @@ module Isolator
|
|
97
160
|
end
|
98
161
|
|
99
162
|
def disabled?
|
100
|
-
|
163
|
+
state[:disabled] == true
|
101
164
|
end
|
102
165
|
|
103
166
|
def adapters
|
104
167
|
@adapters ||= Isolator::SimpleHashie.new
|
105
168
|
end
|
106
169
|
|
170
|
+
def load_ignore_config(path)
|
171
|
+
warn "[DEPRECATION] `load_ignore_config` is deprecated. Please use `Isolator::Ignorer.prepare` instead."
|
172
|
+
Isolator::Ignorer.prepare(path: path)
|
173
|
+
end
|
174
|
+
|
107
175
|
include Isolator::Isolate
|
108
176
|
include Isolator::Callbacks
|
109
|
-
|
177
|
+
|
178
|
+
attr_accessor :debug_enabled, :backtrace_cleaner, :backtrace_length
|
179
|
+
|
180
|
+
private
|
181
|
+
|
182
|
+
attr_accessor :state
|
183
|
+
|
184
|
+
def connection_threshold(connection_id)
|
185
|
+
state[:thresholds]&.[](connection_id) || default_threshold
|
186
|
+
end
|
187
|
+
|
188
|
+
def debug!(msg)
|
189
|
+
return unless debug_enabled
|
190
|
+
msg = "[ISOLATOR DEBUG] #{msg}"
|
191
|
+
|
192
|
+
if backtrace_cleaner && backtrace_length.positive?
|
193
|
+
source = extract_source_location(caller)
|
194
|
+
|
195
|
+
msg = "#{msg}\n ↳ #{source.join("\n")}" unless source.empty?
|
196
|
+
end
|
197
|
+
|
198
|
+
$stdout.puts(colorize_debug(msg))
|
199
|
+
end
|
200
|
+
|
201
|
+
def extract_source_location(locations)
|
202
|
+
backtrace_cleaner.call(locations.lazy)
|
203
|
+
.take(backtrace_length).to_a
|
204
|
+
end
|
205
|
+
|
206
|
+
def colorize_debug(msg)
|
207
|
+
return msg unless $stdout.tty?
|
208
|
+
|
209
|
+
"\u001b[31;1m#{msg}\u001b[0m"
|
210
|
+
end
|
110
211
|
end
|
212
|
+
|
213
|
+
self.state = ThreadStateProxy.new
|
214
|
+
self.default_threshold = 1
|
215
|
+
self.default_connection_id = -> { ActiveRecord::Base.connected? ? ActiveRecord::Base.connection.object_id : 0 }
|
216
|
+
self.debug_enabled = ENV["ISOLATOR_DEBUG"] == "true"
|
217
|
+
self.backtrace_length = ENV.fetch("ISOLATOR_BACKTRACE_LENGTH", 1).to_i
|
111
218
|
end
|
112
219
|
|
113
220
|
require "isolator/orm_adapters"
|
@@ -11,6 +11,7 @@ module Isolator
|
|
11
11
|
|
12
12
|
self.exception_class = options[:exception_class] if options.key?(:exception_class)
|
13
13
|
self.exception_message = options[:exception_message] if options.key?(:exception_message)
|
14
|
+
self.details_message = options[:details_message] if options.key?(:details_message)
|
14
15
|
end
|
15
16
|
|
16
17
|
add_patch_method(adapter, target, method_name) if
|
@@ -21,7 +22,7 @@ module Isolator
|
|
21
22
|
def self.add_patch_method(adapter, base, method_name)
|
22
23
|
mod = Module.new do
|
23
24
|
define_method method_name do |*args, &block|
|
24
|
-
adapter.notify(caller, *args)
|
25
|
+
adapter.notify(caller, self, *args)
|
25
26
|
super(*args, &block)
|
26
27
|
end
|
27
28
|
end
|
@@ -1,6 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
Isolator.isolate :active_job,
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
target: ActiveJob::Base,
|
5
|
+
method_name: :enqueue,
|
6
|
+
exception_class: Isolator::BackgroundJobError,
|
7
|
+
details_message: ->(obj, _args) {
|
8
|
+
"#{obj.class.name}" \
|
9
|
+
"#{obj.arguments.any? ? " (#{obj.arguments.join(", ")})" : ""}"
|
10
|
+
}
|
@@ -1,6 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
Isolator.isolate :resque,
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
target: Resque.singleton_class,
|
5
|
+
method_name: :enqueue,
|
6
|
+
exception_class: Isolator::BackgroundJobError,
|
7
|
+
details_message: ->(_obj, args) {
|
8
|
+
args.join(", ")
|
9
|
+
}
|
@@ -1,6 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
Isolator.isolate :resque_scheduler,
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
target: Resque.singleton_class,
|
5
|
+
method_name: :enqueue_at,
|
6
|
+
exception_class: Isolator::BackgroundJobError,
|
7
|
+
details_message: ->(_obj, (ts, *args)) {
|
8
|
+
"#{args.join(", ")} (at #{ts})"
|
9
|
+
}
|
@@ -1,6 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
Isolator.isolate :sidekiq,
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
target: Sidekiq::Client,
|
5
|
+
method_name: :raw_push,
|
6
|
+
exception_class: Isolator::BackgroundJobError,
|
7
|
+
details_message: ->(_obj, args) {
|
8
|
+
args.first.map do |job|
|
9
|
+
"#{job["class"]} (#{job["args"]})"
|
10
|
+
end.join("\n")
|
11
|
+
}
|
@@ -1,6 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
Isolator.isolate :sucker_punch,
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
target: SuckerPunch::Queue.singleton_class,
|
5
|
+
method_name: :find_or_create,
|
6
|
+
exception_class: Isolator::BackgroundJobError,
|
7
|
+
details_message: ->(_obj, args) {
|
8
|
+
args.compact.join(", ")
|
9
|
+
}
|
@@ -4,7 +4,7 @@ module Isolator
|
|
4
4
|
module Adapters
|
5
5
|
# Used as a "template" for adapters
|
6
6
|
module Base
|
7
|
-
attr_accessor :exception_class, :exception_message
|
7
|
+
attr_accessor :exception_class, :exception_message, :details_message
|
8
8
|
|
9
9
|
def disable!
|
10
10
|
@disabled = true
|
@@ -22,17 +22,17 @@ module Isolator
|
|
22
22
|
@disabled == true
|
23
23
|
end
|
24
24
|
|
25
|
-
def notify(backtrace, *args)
|
25
|
+
def notify(backtrace, obj, *args)
|
26
26
|
return unless notify?(*args)
|
27
|
-
Isolator.notify(exception: build_exception, backtrace: backtrace)
|
27
|
+
Isolator.notify(exception: build_exception(obj, args), backtrace: backtrace)
|
28
28
|
end
|
29
29
|
|
30
30
|
def notify?(*args)
|
31
31
|
enabled? && Isolator.enabled? && Isolator.within_transaction? && !ignored?(*args)
|
32
32
|
end
|
33
33
|
|
34
|
-
def ignore_if
|
35
|
-
ignores <<
|
34
|
+
def ignore_if(&block)
|
35
|
+
ignores << block
|
36
36
|
end
|
37
37
|
|
38
38
|
def ignores
|
@@ -45,9 +45,10 @@ module Isolator
|
|
45
45
|
|
46
46
|
private
|
47
47
|
|
48
|
-
def build_exception
|
48
|
+
def build_exception(obj, args)
|
49
49
|
klass = exception_class || Isolator::UnsafeOperationError
|
50
|
-
|
50
|
+
details = details_message.call(obj, args) if details_message
|
51
|
+
klass.new(exception_message, details: details)
|
51
52
|
end
|
52
53
|
end
|
53
54
|
end
|
@@ -7,7 +7,11 @@ Sniffer::Config.defaults["logger"] = nil
|
|
7
7
|
|
8
8
|
Isolator.isolate :http, target: Sniffer.singleton_class,
|
9
9
|
method_name: :store,
|
10
|
-
exception_class: Isolator::HTTPError
|
10
|
+
exception_class: Isolator::HTTPError,
|
11
|
+
details_message: ->(_obj, args) {
|
12
|
+
req = args.first.request
|
13
|
+
"#{req.method} #{req.host}:#{req.port}#{req.query}"
|
14
|
+
}
|
11
15
|
|
12
16
|
Isolator.before_isolate do
|
13
17
|
next if Isolator.adapters.http.disabled?
|
@@ -1,6 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
adapter = Isolator.isolate :webmock,
|
3
|
+
adapter = Isolator.isolate :webmock,
|
4
|
+
exception_class: Isolator::HTTPError,
|
5
|
+
details_message: ->(obj, _args) {
|
6
|
+
"#{obj.method.to_s.upcase} #{obj.uri}"
|
7
|
+
}
|
4
8
|
|
5
9
|
WebMock.after_request do |*args|
|
6
10
|
adapter.notify(caller, *args)
|
@@ -1,4 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
Isolator.isolate :mailer, target: Mail::Message,
|
4
|
-
|
3
|
+
Isolator.isolate :mailer, target: Mail::Message,
|
4
|
+
method_name: :deliver,
|
5
|
+
exception_class: Isolator::MailerError,
|
6
|
+
details_message: ->(obj, _args) {
|
7
|
+
"From: #{obj.from}\n" \
|
8
|
+
"To: #{obj.to}\n" \
|
9
|
+
"Subject: #{obj.subject}"
|
10
|
+
}
|
@@ -5,19 +5,27 @@ module Isolator
|
|
5
5
|
#
|
6
6
|
# - `raise_exceptions` - whether to raise an exception in case of offense;
|
7
7
|
# defaults to true in test env and false otherwise.
|
8
|
-
# NOTE: env is
|
8
|
+
# NOTE: env is inferred from RACK_ENV and RAILS_ENV.
|
9
9
|
#
|
10
10
|
# - `logger` - logger instance (nil by default)
|
11
11
|
#
|
12
12
|
# - `send_notifications` - whether to send notifications (through uniform_notifier);
|
13
|
-
#
|
13
|
+
# defaults to false
|
14
|
+
#
|
15
|
+
# - `backtrace_filter` - define a custom backtrace filtering (provide a callable)
|
16
|
+
#
|
17
|
+
# - `ignorer` - define a custom ignorer (must implement .prepare)
|
18
|
+
#
|
14
19
|
class Configuration
|
15
|
-
attr_accessor :raise_exceptions, :logger, :send_notifications
|
20
|
+
attr_accessor :raise_exceptions, :logger, :send_notifications,
|
21
|
+
:backtrace_filter, :ignorer
|
16
22
|
|
17
23
|
def initialize
|
18
24
|
@logger = nil
|
19
25
|
@raise_exceptions = test_env?
|
20
26
|
@send_notifications = false
|
27
|
+
@backtrace_filter = ->(backtrace) { backtrace.take(5) }
|
28
|
+
@ignorer = Isolator::Ignorer
|
21
29
|
end
|
22
30
|
|
23
31
|
alias raise_exceptions? raise_exceptions
|
data/lib/isolator/errors.rb
CHANGED
@@ -4,9 +4,9 @@ module Isolator # :nodoc: all
|
|
4
4
|
class UnsafeOperationError < StandardError
|
5
5
|
MESSAGE = "You are trying to do unsafe operation inside db transaction"
|
6
6
|
|
7
|
-
def initialize(msg = nil)
|
7
|
+
def initialize(msg = nil, details: nil)
|
8
8
|
msg ||= self.class::MESSAGE
|
9
|
-
super
|
9
|
+
super(details ? "#{msg}\nDetails: #{details}" : msg)
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
data/lib/isolator/ignorer.rb
CHANGED
@@ -1,39 +1,59 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Isolator
|
4
|
-
#
|
5
|
-
|
6
|
-
|
7
|
-
return unless File.exist?(path)
|
4
|
+
# Handle ignoring isolator errors using a yml file
|
5
|
+
class Ignorer
|
6
|
+
TODO_PATH = ".isolator_todo.yml"
|
8
7
|
|
9
|
-
|
8
|
+
class << self
|
9
|
+
def prepare(path: TODO_PATH, regex_string: "^.*(#ignores#):.*$")
|
10
|
+
return unless File.exist?(path)
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
12
|
+
todos = YAML.load_file(path)
|
13
|
+
|
14
|
+
Isolator.adapters.each do |id, adapter|
|
15
|
+
ignored_paths = todos.fetch(id, [])
|
16
|
+
AdapterIgnore.new(adapter: adapter, ignored_paths: ignored_paths, regex_string: regex_string).prepare
|
17
|
+
end
|
14
18
|
end
|
15
19
|
end
|
16
20
|
|
17
21
|
private
|
18
22
|
|
19
|
-
|
20
|
-
|
21
|
-
|
23
|
+
class AdapterIgnore
|
24
|
+
def initialize(adapter:, ignored_paths:, regex_string:)
|
25
|
+
self.adapter = adapter
|
26
|
+
self.ignored_paths = ignored_paths
|
27
|
+
self.regex_string = regex_string
|
28
|
+
end
|
29
|
+
|
30
|
+
def prepare
|
31
|
+
return if ignores.blank?
|
22
32
|
|
23
|
-
|
24
|
-
|
25
|
-
end
|
33
|
+
adapter.ignore_if { caller.any? { |row| regex =~ row } }
|
34
|
+
end
|
26
35
|
|
27
|
-
|
28
|
-
ignored_paths.each_with_object([]) do |path, result|
|
29
|
-
ignored_files = Dir[path]
|
36
|
+
private
|
30
37
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
38
|
+
attr_accessor :adapter, :ignored_paths, :regex_string
|
39
|
+
|
40
|
+
def ignores
|
41
|
+
return @ignores if defined? @ignores
|
42
|
+
|
43
|
+
@ignores = ignored_paths.each_with_object([]) do |path, result|
|
44
|
+
ignored_files = Dir[path]
|
45
|
+
|
46
|
+
if ignored_files.blank?
|
47
|
+
result << path.to_s
|
48
|
+
else
|
49
|
+
result.concat(ignored_files)
|
50
|
+
end
|
35
51
|
end
|
36
52
|
end
|
53
|
+
|
54
|
+
def regex
|
55
|
+
Regexp.new(regex_string.gsub("#ignores#", ignores.join("|")))
|
56
|
+
end
|
37
57
|
end
|
38
58
|
end
|
39
59
|
end
|
data/lib/isolator/isolate.rb
CHANGED
@@ -5,7 +5,7 @@ module Isolator
|
|
5
5
|
module Isolate
|
6
6
|
def isolate(id, **options)
|
7
7
|
raise "Adapter already registered: #{id}" if Isolator.adapters.key?(id.to_s)
|
8
|
-
adapter = AdapterBuilder.call(options)
|
8
|
+
adapter = AdapterBuilder.call(**options)
|
9
9
|
Isolator.adapters[id.to_s] = adapter
|
10
10
|
end
|
11
11
|
end
|
data/lib/isolator/notifier.rb
CHANGED
@@ -9,8 +9,9 @@ module Isolator
|
|
9
9
|
|
10
10
|
def self.subscribe!(event)
|
11
11
|
::ActiveSupport::Notifications.subscribe(event) do |_name, _start, _finish, _id, query|
|
12
|
-
|
13
|
-
Isolator.
|
12
|
+
connection_id = query[:connection_id] || query[:connection]&.object_id || 0
|
13
|
+
Isolator.incr_transactions!(connection_id) if START_PATTERN.match?(query[:sql])
|
14
|
+
Isolator.decr_transactions!(connection_id) if FINISH_PATTERN.match?(query[:sql])
|
14
15
|
end
|
15
16
|
end
|
16
17
|
end
|
data/lib/isolator/railtie.rb
CHANGED
@@ -2,12 +2,20 @@
|
|
2
2
|
|
3
3
|
module Isolator
|
4
4
|
class Railtie < ::Rails::Railtie # :nodoc:
|
5
|
+
initializer "isolator.backtrace_cleaner" do
|
6
|
+
ActiveSupport.on_load(:active_record) do
|
7
|
+
Isolator.backtrace_cleaner = lambda do |locations|
|
8
|
+
::Rails.backtrace_cleaner.clean(locations)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
5
13
|
config.after_initialize do
|
6
14
|
# Forec load adapters after application initialization
|
7
15
|
# (when all deps are likely to be loaded).
|
8
16
|
load File.join(__dir__, "adapters.rb")
|
9
17
|
|
10
|
-
Isolator.
|
18
|
+
Isolator.config.ignorer&.prepare
|
11
19
|
|
12
20
|
next unless Rails.env.test?
|
13
21
|
|
@@ -18,14 +26,12 @@ module Isolator
|
|
18
26
|
super
|
19
27
|
return unless run_in_transaction?
|
20
28
|
|
21
|
-
|
22
|
-
Isolator.transactions_threshold += open_count
|
29
|
+
Isolator.incr_thresholds!
|
23
30
|
end
|
24
31
|
|
25
32
|
def teardown_fixtures(*)
|
26
33
|
if run_in_transaction?
|
27
|
-
|
28
|
-
Isolator.transactions_threshold -= open_count
|
34
|
+
Isolator.decr_thresholds!
|
29
35
|
end
|
30
36
|
super
|
31
37
|
end
|
data/lib/isolator/version.rb
CHANGED
metadata
CHANGED
@@ -1,57 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: isolator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vladimir Dementyev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-09-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sniffer
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 0.3.1
|
20
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
26
|
version: 0.3.1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '1.
|
33
|
+
version: '1.16'
|
34
34
|
type: :development
|
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: '1.
|
40
|
+
version: '1.16'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '13.0'
|
48
48
|
type: :development
|
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: '
|
54
|
+
version: '13.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rspec
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -70,14 +70,14 @@ dependencies:
|
|
70
70
|
name: rspec-rails
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - "
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '3.0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - "
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '3.0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
@@ -95,91 +95,91 @@ dependencies:
|
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: 5.10.0
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
98
|
+
name: sidekiq
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
103
|
+
version: '5.0'
|
104
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:
|
110
|
+
version: '5.0'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
112
|
+
name: webmock
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
115
|
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: '
|
117
|
+
version: '3.1'
|
118
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: '
|
124
|
+
version: '3.1'
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
|
-
name:
|
126
|
+
name: test_after_commit
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
129
|
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: '1.
|
131
|
+
version: '1.1'
|
132
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: '1.
|
138
|
+
version: '1.1'
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
|
-
name:
|
140
|
+
name: resque
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
142
142
|
requirements:
|
143
|
-
- - "
|
143
|
+
- - ">="
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version: '
|
145
|
+
version: '0'
|
146
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: '
|
152
|
+
version: '0'
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
|
-
name:
|
154
|
+
name: fakeredis
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
156
156
|
requirements:
|
157
|
-
- - "
|
157
|
+
- - ">="
|
158
158
|
- !ruby/object:Gem::Version
|
159
|
-
version: '
|
159
|
+
version: '0'
|
160
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: '
|
166
|
+
version: '0'
|
167
167
|
- !ruby/object:Gem::Dependency
|
168
|
-
name:
|
168
|
+
name: resque-scheduler
|
169
169
|
requirement: !ruby/object:Gem::Requirement
|
170
170
|
requirements:
|
171
|
-
- - "
|
171
|
+
- - ">="
|
172
172
|
- !ruby/object:Gem::Version
|
173
|
-
version: '
|
173
|
+
version: '0'
|
174
174
|
type: :development
|
175
175
|
prerelease: false
|
176
176
|
version_requirements: !ruby/object:Gem::Requirement
|
177
177
|
requirements:
|
178
|
-
- - "
|
178
|
+
- - ">="
|
179
179
|
- !ruby/object:Gem::Version
|
180
|
-
version: '
|
180
|
+
version: '0'
|
181
181
|
- !ruby/object:Gem::Dependency
|
182
|
-
name:
|
182
|
+
name: sucker_punch
|
183
183
|
requirement: !ruby/object:Gem::Requirement
|
184
184
|
requirements:
|
185
185
|
- - ">="
|
@@ -193,7 +193,7 @@ dependencies:
|
|
193
193
|
- !ruby/object:Gem::Version
|
194
194
|
version: '0'
|
195
195
|
- !ruby/object:Gem::Dependency
|
196
|
-
name:
|
196
|
+
name: database_cleaner
|
197
197
|
requirement: !ruby/object:Gem::Requirement
|
198
198
|
requirements:
|
199
199
|
- - ">="
|
@@ -207,7 +207,7 @@ dependencies:
|
|
207
207
|
- !ruby/object:Gem::Version
|
208
208
|
version: '0'
|
209
209
|
- !ruby/object:Gem::Dependency
|
210
|
-
name:
|
210
|
+
name: database_cleaner-active_record
|
211
211
|
requirement: !ruby/object:Gem::Requirement
|
212
212
|
requirements:
|
213
213
|
- - ">="
|
@@ -221,7 +221,7 @@ dependencies:
|
|
221
221
|
- !ruby/object:Gem::Version
|
222
222
|
version: '0'
|
223
223
|
- !ruby/object:Gem::Dependency
|
224
|
-
name:
|
224
|
+
name: after_commit_everywhere
|
225
225
|
requirement: !ruby/object:Gem::Requirement
|
226
226
|
requirements:
|
227
227
|
- - ">="
|
@@ -235,7 +235,7 @@ dependencies:
|
|
235
235
|
- !ruby/object:Gem::Version
|
236
236
|
version: '0'
|
237
237
|
- !ruby/object:Gem::Dependency
|
238
|
-
name:
|
238
|
+
name: uniform_notifier
|
239
239
|
requirement: !ruby/object:Gem::Requirement
|
240
240
|
requirements:
|
241
241
|
- - ">="
|
@@ -255,20 +255,9 @@ executables: []
|
|
255
255
|
extensions: []
|
256
256
|
extra_rdoc_files: []
|
257
257
|
files:
|
258
|
-
- ".gitignore"
|
259
|
-
- ".rubocop.yml"
|
260
|
-
- ".travis.yml"
|
261
258
|
- CHANGELOG.md
|
262
|
-
- Gemfile
|
263
259
|
- LICENSE.txt
|
264
260
|
- README.md
|
265
|
-
- Rakefile
|
266
|
-
- bin/console
|
267
|
-
- bin/setup
|
268
|
-
- gemfiles/activerecord42.gemfile
|
269
|
-
- gemfiles/jruby.gemfile
|
270
|
-
- gemfiles/railsmaster.gemfile
|
271
|
-
- isolator.gemspec
|
272
261
|
- lib/isolator.rb
|
273
262
|
- lib/isolator/adapter_builder.rb
|
274
263
|
- lib/isolator/adapters.rb
|
@@ -303,7 +292,12 @@ files:
|
|
303
292
|
homepage: https://github.com/palkan/isolator
|
304
293
|
licenses:
|
305
294
|
- MIT
|
306
|
-
metadata:
|
295
|
+
metadata:
|
296
|
+
bug_tracker_uri: http://github.com/palkan/isolator/issues
|
297
|
+
changelog_uri: https://github.com/palkan/isolator/blob/master/CHANGELOG.md
|
298
|
+
documentation_uri: http://github.com/palkan/isolator
|
299
|
+
homepage_uri: http://github.com/palkan/isolator
|
300
|
+
source_code_uri: http://github.com/palkan/isolator
|
307
301
|
post_install_message:
|
308
302
|
rdoc_options: []
|
309
303
|
require_paths:
|
@@ -312,15 +306,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
312
306
|
requirements:
|
313
307
|
- - ">="
|
314
308
|
- !ruby/object:Gem::Version
|
315
|
-
version: 2.
|
309
|
+
version: 2.5.0
|
316
310
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
317
311
|
requirements:
|
318
312
|
- - ">="
|
319
313
|
- !ruby/object:Gem::Version
|
320
314
|
version: '0'
|
321
315
|
requirements: []
|
322
|
-
|
323
|
-
rubygems_version: 2.7.6
|
316
|
+
rubygems_version: 3.0.6
|
324
317
|
signing_key:
|
325
318
|
specification_version: 4
|
326
319
|
summary: Detect non-atomic interactions within DB transactions
|
data/.gitignore
DELETED
data/.rubocop.yml
DELETED
@@ -1,62 +0,0 @@
|
|
1
|
-
require:
|
2
|
-
- rubocop-md
|
3
|
-
|
4
|
-
AllCops:
|
5
|
-
Include:
|
6
|
-
- 'lib/**/*.rb'
|
7
|
-
- 'lib/**/*.rake'
|
8
|
-
- 'spec/**/*.rb'
|
9
|
-
Exclude:
|
10
|
-
- 'bin/**/*'
|
11
|
-
- 'gemfiles/**/*'
|
12
|
-
- 'spec/dummy/**/*'
|
13
|
-
- 'vendor/**/*'
|
14
|
-
- 'tmp/**/*'
|
15
|
-
- 'Rakefile'
|
16
|
-
- 'Gemfile'
|
17
|
-
- '*.gemspec'
|
18
|
-
DisplayCopNames: true
|
19
|
-
StyleGuideCopsOnly: false
|
20
|
-
TargetRubyVersion: 2.3
|
21
|
-
|
22
|
-
Rails:
|
23
|
-
Enabled: false
|
24
|
-
|
25
|
-
Bundler/OrderedGems:
|
26
|
-
Enabled: false
|
27
|
-
|
28
|
-
Naming/UncommunicativeMethodParamName:
|
29
|
-
Enabled: false
|
30
|
-
|
31
|
-
Style/SymbolArray:
|
32
|
-
Enabled: false
|
33
|
-
|
34
|
-
Style/Documentation:
|
35
|
-
Exclude:
|
36
|
-
- 'spec/**/*.rb'
|
37
|
-
|
38
|
-
Style/StringLiterals:
|
39
|
-
EnforcedStyle: double_quotes
|
40
|
-
|
41
|
-
Style/RegexpLiteral:
|
42
|
-
Enabled: false
|
43
|
-
|
44
|
-
Style/BlockDelimiters:
|
45
|
-
Exclude:
|
46
|
-
- 'spec/**/*.rb'
|
47
|
-
|
48
|
-
Style/NumericPredicate:
|
49
|
-
Enabled: false
|
50
|
-
|
51
|
-
Layout/SpaceInsideStringInterpolation:
|
52
|
-
EnforcedStyle: no_space
|
53
|
-
|
54
|
-
Lint/AmbiguousRegexpLiteral:
|
55
|
-
Enabled: false
|
56
|
-
|
57
|
-
Metrics/LineLength:
|
58
|
-
Max: 100
|
59
|
-
|
60
|
-
Metrics/BlockLength:
|
61
|
-
Exclude:
|
62
|
-
- 'spec/**/*.rb'
|
data/.travis.yml
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
sudo: false
|
2
|
-
language: ruby
|
3
|
-
rvm:
|
4
|
-
- 2.5.0
|
5
|
-
|
6
|
-
notifications:
|
7
|
-
email: false
|
8
|
-
|
9
|
-
matrix:
|
10
|
-
fast_finish: true
|
11
|
-
include:
|
12
|
-
- rvm: ruby-head
|
13
|
-
gemfile: gemfiles/railsmaster.gemfile
|
14
|
-
- rvm: jruby-9.1.0.0
|
15
|
-
gemfile: gemfiles/jruby.gemfile
|
16
|
-
- rvm: 2.5.0
|
17
|
-
gemfile: Gemfile
|
18
|
-
- rvm: 2.4.3
|
19
|
-
gemfile: Gemfile
|
20
|
-
- rvm: 2.3.1
|
21
|
-
gemfile: gemfiles/activerecord42.gemfile
|
22
|
-
allow_failures:
|
23
|
-
- rvm: ruby-head
|
24
|
-
gemfile: gemfiles/railsmaster.gemfile
|
25
|
-
- rvm: jruby-9.1.0.0
|
26
|
-
gemfile: gemfiles/jruby.gemfile
|
data/Gemfile
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
source "https://rubygems.org"
|
2
|
-
|
3
|
-
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
|
4
|
-
|
5
|
-
# Specify your gem's dependencies in isolator.gemspec
|
6
|
-
gemspec
|
7
|
-
|
8
|
-
gem "pry-byebug"
|
9
|
-
|
10
|
-
gem "sqlite3"
|
11
|
-
|
12
|
-
local_gemfile = File.join(__dir__, "Gemfile.local")
|
13
|
-
|
14
|
-
if File.exist?(local_gemfile)
|
15
|
-
eval(File.read(local_gemfile)) # rubocop:disable Security/Eval
|
16
|
-
else
|
17
|
-
gem "rails", "~> 5.0"
|
18
|
-
end
|
data/Rakefile
DELETED
data/bin/console
DELETED
data/bin/setup
DELETED
data/gemfiles/jruby.gemfile
DELETED
data/isolator.gemspec
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
lib = File.expand_path("../lib", __FILE__)
|
2
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
-
require "isolator/version"
|
4
|
-
|
5
|
-
Gem::Specification.new do |spec|
|
6
|
-
spec.name = "isolator"
|
7
|
-
spec.version = Isolator::VERSION
|
8
|
-
spec.authors = ["Vladimir Dementyev"]
|
9
|
-
spec.email = ["dementiev.vm@gmail.com"]
|
10
|
-
|
11
|
-
spec.summary = "Detect non-atomic interactions within DB transactions"
|
12
|
-
spec.description = "Detect non-atomic interactions within DB transactions"
|
13
|
-
spec.homepage = "https://github.com/palkan/isolator"
|
14
|
-
spec.license = "MIT"
|
15
|
-
|
16
|
-
spec.required_ruby_version = ">= 2.3.0"
|
17
|
-
|
18
|
-
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
19
|
-
f.match(%r{^(test|spec|features)/})
|
20
|
-
end
|
21
|
-
spec.require_paths = ["lib"]
|
22
|
-
|
23
|
-
spec.add_runtime_dependency "sniffer", "~> 0.3.1"
|
24
|
-
|
25
|
-
spec.add_development_dependency "bundler", "~> 1.14"
|
26
|
-
spec.add_development_dependency "rake", "~> 10.0"
|
27
|
-
spec.add_development_dependency "rspec", "~> 3.0"
|
28
|
-
spec.add_development_dependency "rspec-rails", "~> 3.0"
|
29
|
-
spec.add_development_dependency "minitest", "~> 5.10.0"
|
30
|
-
spec.add_development_dependency "rubocop", "~> 0.56.0"
|
31
|
-
spec.add_development_dependency "rubocop-md", "~> 0.2"
|
32
|
-
|
33
|
-
spec.add_development_dependency "uniform_notifier", "~> 1.11"
|
34
|
-
spec.add_development_dependency "sidekiq", "~> 5.0"
|
35
|
-
spec.add_development_dependency "webmock", "~> 3.1"
|
36
|
-
spec.add_development_dependency "test_after_commit", "~> 1.1"
|
37
|
-
spec.add_development_dependency "resque"
|
38
|
-
spec.add_development_dependency "fakeredis"
|
39
|
-
spec.add_development_dependency "resque-scheduler"
|
40
|
-
spec.add_development_dependency "sucker_punch"
|
41
|
-
spec.add_development_dependency "database_cleaner"
|
42
|
-
end
|