isolator 0.4.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Cult Of Martians](http://cultofmartians.com/assets/badges/badge.svg)](http://cultofmartians.com/tasks/isolator.html)
|
2
2
|
[![Gem Version](https://badge.fury.io/rb/isolator.svg)](https://badge.fury.io/rb/isolator)
|
3
|
-
|
3
|
+
![Build](https://github.com/palkan/isolator/workflows/Build/badge.svg)
|
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
|