deprecation_collector 0.5.2 → 0.6.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 +5 -0
- data/deprecation_collector.gemspec +1 -8
- data/lib/deprecation_collector/storage/active_record.rb +155 -0
- data/lib/deprecation_collector/storage.rb +6 -1
- data/lib/deprecation_collector/version.rb +1 -1
- data/lib/deprecation_collector/web/application.rb +6 -5
- data/lib/deprecation_collector/web/helpers.rb +12 -10
- data/lib/deprecation_collector/web/router.rb +7 -5
- data/lib/deprecation_collector/web/views/import.html.slim +12 -0
- data/lib/deprecation_collector/web/views/import.html.template.rb +1 -1
- data/lib/deprecation_collector/web/views/index.html.slim +121 -0
- data/lib/deprecation_collector/web/views/index.html.template.rb +6 -6
- data/lib/deprecation_collector/web/views/layout.html.slim +90 -0
- data/lib/deprecation_collector/web/views/layout.html.template.rb +1 -1
- data/lib/deprecation_collector/web/views/show.html.slim +81 -0
- data/lib/deprecation_collector/web/views/show.html.template.rb +2 -2
- data/lib/deprecation_collector.rb +11 -1
- metadata +7 -15
- data/.rspec +0 -3
- data/.rubocop.yml +0 -34
- data/Appraisals +0 -13
- data/Gemfile +0 -33
- data/Gemfile.lock +0 -249
- data/LICENSE +0 -21
- data/Rakefile +0 -30
- data/gemfiles/rails_6.gemfile +0 -15
- data/gemfiles/rails_6.gemfile.lock +0 -198
- data/gemfiles/rails_7.gemfile +0 -15
- data/gemfiles/rails_7.gemfile.lock +0 -197
- data/gemfiles/rails_none.gemfile +0 -14
- data/gemfiles/rails_none.gemfile.lock +0 -62
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e119a79e2c879e9e0ec02476523620eab84c6ae4c354d382207cd8be6bde7a9a
|
4
|
+
data.tar.gz: e2f7f495ee705f5dada2456b425fa739a9a67b801dce461c86e5f4a04c6266d0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8857214426445395aa62c0c56dae0d598d5f673f2d1b8d42bd00a7a8ba1ef037513ca5449a93c182f0556ef45fe6e6345bd798ffa2137a7e78f92f5f1902f0a1
|
7
|
+
data.tar.gz: 9de452b1a5d98b40777ac59224e57a134368ae91c9c24ecc7d792a199c66fd5f92c22d62689c6cadbc409d3d330057d4c487e50f6100dc697ea5295b83761066
|
data/CHANGELOG.md
CHANGED
@@ -18,14 +18,7 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.metadata["source_code_uri"] = "https://github.com/Vasfed/deprecation_collector"
|
19
19
|
spec.metadata["changelog_uri"] = "https://github.com/Vasfed/deprecation_collector/blob/main/CHANGELOG.md"
|
20
20
|
|
21
|
-
|
22
|
-
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
23
|
-
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
24
|
-
`git ls-files -z`.split("\x0").reject do |f|
|
25
|
-
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)}) ||
|
26
|
-
f.match(%r{\Alib/deprecation_collector/web/views/.+\.slim\z})
|
27
|
-
end
|
28
|
-
end + Dir["lib/deprecation_collector/web/views/*.slim"].map { |template| template.sub(/\.slim\z/, ".template.rb") }
|
21
|
+
spec.files = Dir['lib/**/*', 'sig/**/*', '*.md', '*.txt', '*.gemspec'].select { |f| File.file?(f) }
|
29
22
|
spec.require_paths = ["lib"]
|
30
23
|
|
31
24
|
spec.add_dependency "redis", ">= 3.0"
|
@@ -0,0 +1,155 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class DeprecationCollector
|
4
|
+
module Storage
|
5
|
+
# NB: this will not work in tests because of transactions, and may be affected by transactions of the app
|
6
|
+
# TODO: use separate db connection to mitigate this
|
7
|
+
class ActiveRecord < DeprecationCollector::Storage::Base
|
8
|
+
def initialize(model: nil, mutex: nil, count: false, write_interval: 900, write_interval_jitter: 60,
|
9
|
+
key_prefix: nil)
|
10
|
+
super
|
11
|
+
raise "key prefix not supported in AR" if key_prefix && key_prefix != "deprecations"
|
12
|
+
|
13
|
+
self.model = model if model
|
14
|
+
@last_write_time = current_time
|
15
|
+
@count = count
|
16
|
+
@write_interval = write_interval
|
17
|
+
@write_interval_jitter = write_interval_jitter
|
18
|
+
# on cruby hash itself is threadsafe, but we need to prevent races
|
19
|
+
@deprecations_mutex = mutex || Mutex.new
|
20
|
+
@deprecations = {}
|
21
|
+
@known_digests = Set.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def model=(model)
|
25
|
+
expected_class_methods = %i[column_names where pluck delete_all upsert_all find_in_batches find_by]
|
26
|
+
unless expected_class_methods.all? { |method_name| model.respond_to?(method_name) }
|
27
|
+
raise ArgumentError, "model expected to be a AR-like class responding to #{expected_class_methods.join(', ')}"
|
28
|
+
end
|
29
|
+
|
30
|
+
expected_fields = %w[digest data notes created_at updated_at]
|
31
|
+
unless expected_fields.all? { |column_name| model.column_names.include?(column_name) }
|
32
|
+
raise ArgumentError, "model expected to be a AR-like class with fields #{expected_fields.join(', ')}"
|
33
|
+
end
|
34
|
+
|
35
|
+
@model = model
|
36
|
+
end
|
37
|
+
|
38
|
+
def model
|
39
|
+
@model ||= ::Deprecation
|
40
|
+
end
|
41
|
+
|
42
|
+
attr_writer :key_prefix
|
43
|
+
|
44
|
+
def unsent_deprecations
|
45
|
+
@deprecations
|
46
|
+
end
|
47
|
+
|
48
|
+
def delete(remove_digests)
|
49
|
+
model.where(digest: remove_digests).delete_all
|
50
|
+
end
|
51
|
+
|
52
|
+
def clear(enable: false) # rubocop:disable Lint/UnusedMethodArgument
|
53
|
+
model.delete_all
|
54
|
+
@known_digests.clear
|
55
|
+
@deprecations.clear
|
56
|
+
end
|
57
|
+
|
58
|
+
def fetch_known_digests
|
59
|
+
@known_digests.merge(model.pluck(:digest))
|
60
|
+
end
|
61
|
+
|
62
|
+
def store(deprecation)
|
63
|
+
fresh = !@deprecations.key?(deprecation.digest)
|
64
|
+
@deprecations_mutex.synchronize do
|
65
|
+
(@deprecations[deprecation.digest] ||= deprecation).touch
|
66
|
+
end
|
67
|
+
|
68
|
+
flush if current_time - @last_write_time > (@write_interval + rand(@write_interval_jitter))
|
69
|
+
fresh
|
70
|
+
end
|
71
|
+
|
72
|
+
def flush(force: false)
|
73
|
+
return unless force || (current_time > @last_write_time + @write_interval)
|
74
|
+
|
75
|
+
deprecations_to_flush = nil
|
76
|
+
@deprecations_mutex.synchronize do
|
77
|
+
deprecations_to_flush = @deprecations
|
78
|
+
@deprecations = {}
|
79
|
+
@last_write_time = current_time
|
80
|
+
# checking in this section to prevent multiple parallel check requests
|
81
|
+
return DeprecationCollector.instance.instance_variable_set(:@enabled, false) unless enabled?
|
82
|
+
end
|
83
|
+
|
84
|
+
# write_count_to_redis(deprecations_to_flush) if @count
|
85
|
+
|
86
|
+
# make as few writes as possible, other workers may already have reported our warning
|
87
|
+
fetch_known_digests
|
88
|
+
deprecations_to_flush.reject! { |digest, _val| @known_digests.include?(digest) }
|
89
|
+
return unless deprecations_to_flush.any?
|
90
|
+
|
91
|
+
@known_digests.merge(deprecations_to_flush.keys)
|
92
|
+
|
93
|
+
model.upsert_all(
|
94
|
+
deprecations_to_flush.map do |key, deprecation|
|
95
|
+
{
|
96
|
+
digest: key, data: deprecation.as_json,
|
97
|
+
created_at: timestamp_to_time(deprecation.first_timestamp),
|
98
|
+
updated_at: timestamp_to_time(deprecation.first_timestamp)
|
99
|
+
}
|
100
|
+
end,
|
101
|
+
unique_by: :digest # , update_only: %i[data updated_at] # rails 7
|
102
|
+
)
|
103
|
+
end
|
104
|
+
|
105
|
+
def read_each
|
106
|
+
model.find_in_batches do |batch| # this is find_each, but do not require it to be implemented
|
107
|
+
batch.each do |record|
|
108
|
+
yield(record.digest, record.data.to_json, record.data&.dig("count"), record.notes)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def read_one(digest)
|
114
|
+
return [nil] * 4 unless (record = model.find_by(digest: digest))
|
115
|
+
|
116
|
+
[record.digest, record.data.to_json, record.data&.dig("count"), record.notes]
|
117
|
+
end
|
118
|
+
|
119
|
+
def import(dump_hash)
|
120
|
+
attrs = dump_hash.map do |key, deprecation|
|
121
|
+
time = deprecation["first_timestamp"] || deprecation[:first_timestamp]
|
122
|
+
time = time&.yield_self { |tme| timestamp_to_time(tme) } || current_time
|
123
|
+
{ digest: key, data: deprecation, created_at: time, updated_at: time }
|
124
|
+
end
|
125
|
+
model.upsert_all(attrs, unique_by: :digest) # , update_only: %i[data updated_at])
|
126
|
+
end
|
127
|
+
|
128
|
+
def cleanup(&_block)
|
129
|
+
removed = total = 0
|
130
|
+
|
131
|
+
model.find_in_batches do |batch|
|
132
|
+
total += batch.size
|
133
|
+
removed += delete(
|
134
|
+
batch.select { |record| yield(record.data.deep_symbolize_keys) }.map(&:digest)
|
135
|
+
)
|
136
|
+
end
|
137
|
+
"#{removed} removed, #{total - removed} left"
|
138
|
+
end
|
139
|
+
|
140
|
+
protected
|
141
|
+
|
142
|
+
def current_time
|
143
|
+
return Time.zone.now if Time.respond_to?(:zone) && Time.zone
|
144
|
+
|
145
|
+
Time.now
|
146
|
+
end
|
147
|
+
|
148
|
+
def timestamp_to_time(timestamp)
|
149
|
+
return Time.zone.at(timestamp) if Time.respond_to?(:zone) && Time.zone
|
150
|
+
|
151
|
+
Time.at(timestamp)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
@@ -21,6 +21,11 @@ class DeprecationCollector
|
|
21
21
|
def flush(**); end
|
22
22
|
|
23
23
|
def store(_deprecation); raise("Not implemented"); end
|
24
|
+
|
25
|
+
def read_each; end
|
26
|
+
def read_one(_digest); [nil] * 4 end
|
27
|
+
|
28
|
+
def import(_dump); end
|
24
29
|
# rubocop:enable Style/SingleLineMethods
|
25
30
|
end
|
26
31
|
|
@@ -36,7 +41,7 @@ class DeprecationCollector
|
|
36
41
|
attr_accessor :write_interval, :write_interval_jitter, :redis, :count
|
37
42
|
|
38
43
|
def initialize(redis: nil, mutex: nil, count: false, write_interval: 900, write_interval_jitter: 60,
|
39
|
-
|
44
|
+
key_prefix: nil)
|
40
45
|
super
|
41
46
|
@key_prefix = key_prefix || "deprecations"
|
42
47
|
@redis = redis
|
@@ -24,17 +24,17 @@ class DeprecationCollector
|
|
24
24
|
|
25
25
|
root do # index
|
26
26
|
@deprecations = collector_instance.read_each.to_a.compact
|
27
|
-
@deprecations = @deprecations.sort_by { |dep| dep[:message] } unless params[:sort] == "0"
|
27
|
+
@deprecations = @deprecations.sort_by { |dep| dep[:message].to_s } unless params[:sort] == "0"
|
28
28
|
|
29
29
|
if params[:reject]
|
30
|
-
@deprecations = @deprecations.reject { |dep| dep[:message]
|
30
|
+
@deprecations = @deprecations.reject { |dep| dep[:message]&.match?(Regexp.union(Array(params[:reject]))) }
|
31
31
|
end
|
32
32
|
|
33
33
|
if params[:realm]
|
34
|
-
@deprecations = @deprecations.select { |dep| dep[:realm]
|
34
|
+
@deprecations = @deprecations.select { |dep| dep[:realm]&.match?(Regexp.union(Array(params[:realm]))) }
|
35
35
|
end
|
36
36
|
|
37
|
-
render slim: "index.html"
|
37
|
+
render slim: "index.html", locals: { deprecations: @deprecations }
|
38
38
|
end
|
39
39
|
|
40
40
|
get "/dump.json" do
|
@@ -42,12 +42,13 @@ class DeprecationCollector
|
|
42
42
|
end
|
43
43
|
|
44
44
|
get "/import" do
|
45
|
-
|
45
|
+
halt 403, "Import not enabled" unless import_enabled?
|
46
46
|
|
47
47
|
render slim: "import.html"
|
48
48
|
end
|
49
49
|
|
50
50
|
post "/import" do
|
51
|
+
halt 403, "Import not enabled" unless import_enabled?
|
51
52
|
unless env["CONTENT_TYPE"]&.start_with?("multipart/form-data") && params.dig(:file, :tempfile)
|
52
53
|
halt 422, "need multipart json file"
|
53
54
|
end
|
@@ -14,7 +14,7 @@ class DeprecationCollector
|
|
14
14
|
|
15
15
|
def root_path
|
16
16
|
# request.base_url ?
|
17
|
-
"#{env[
|
17
|
+
"#{env['SCRIPT_NAME']}/"
|
18
18
|
end
|
19
19
|
|
20
20
|
def current_path
|
@@ -26,7 +26,7 @@ class DeprecationCollector
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def deprecation_path(id, format: nil)
|
29
|
-
["#{root_path}#{id}", format].compact.join(
|
29
|
+
["#{root_path}#{id}", format].compact.join(".")
|
30
30
|
end
|
31
31
|
|
32
32
|
def enable_deprecations_path
|
@@ -62,14 +62,14 @@ class DeprecationCollector
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def detect_tag(deprecation)
|
65
|
-
msg = deprecation[:message]
|
65
|
+
msg = deprecation[:message].to_s
|
66
66
|
return :kwargs if msg.include?("Using the last argument as keyword parameters is deprecated") ||
|
67
67
|
msg.include?("Passing the keyword argument as the last hash parameter is deprecated")
|
68
68
|
end
|
69
69
|
|
70
70
|
def test_deprecation?(deprecation)
|
71
|
-
%w[trigger_kwargs_error_warning trigger_rails_deprecation].any? do
|
72
|
-
|
71
|
+
%w[trigger_kwargs_error_warning trigger_rails_deprecation].any? do |method|
|
72
|
+
deprecation[:message].to_s.include?(method)
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
@@ -82,11 +82,13 @@ class DeprecationCollector
|
|
82
82
|
tags << deprecation[:realm] if deprecation[:realm] && deprecation[:realm] != "rails"
|
83
83
|
tags.merge(deprecation.dig(:notes, :tags) || [])
|
84
84
|
|
85
|
-
tags.
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
85
|
+
tags.map do |tag|
|
86
|
+
if tag == :test
|
87
|
+
[tag, "bg-success"]
|
88
|
+
else
|
89
|
+
[tag, "bg-secondary"]
|
90
|
+
end
|
91
|
+
end.to_h
|
90
92
|
end
|
91
93
|
end
|
92
94
|
end
|
@@ -54,7 +54,7 @@ class DeprecationCollector
|
|
54
54
|
return [
|
55
55
|
404,
|
56
56
|
{ "content-type" => "text/plain", "x-cascade" => "pass" },
|
57
|
-
["Not Found #{env[
|
57
|
+
["Not Found #{env['REQUEST_METHOD'].inspect} #{env[PATH_INFO].inspect}"]
|
58
58
|
]
|
59
59
|
end
|
60
60
|
|
@@ -178,12 +178,10 @@ class DeprecationCollector
|
|
178
178
|
|
179
179
|
def render_template(template, &block)
|
180
180
|
template_target = template.gsub(/\.slim\z/, ".template.rb")
|
181
|
-
template_method_name = "_template_#{template_target.gsub(/[^\w]/,
|
181
|
+
template_method_name = "_template_#{template_target.gsub(/[^\w]/, '_')}"
|
182
182
|
template_filename = File.join(VIEW_PATH, template_target.to_s)
|
183
183
|
|
184
|
-
if
|
185
|
-
_recompile_template(template, template_filename, template_method_name)
|
186
|
-
end
|
184
|
+
_recompile_template(template, template_filename, template_method_name) if _recompile_enabled?
|
187
185
|
|
188
186
|
_load_template(template_filename, template_method_name) unless respond_to?(template_method_name)
|
189
187
|
|
@@ -202,6 +200,10 @@ class DeprecationCollector
|
|
202
200
|
ActionContext.class_eval(src, template_filename.gsub(/\.template\.rb\z/, ".slim"), 1)
|
203
201
|
end
|
204
202
|
|
203
|
+
def _recompile_enabled?
|
204
|
+
ENV["DEPRECATION_COLLECTOR_RELOAD_WEB_TEMPLATES"]
|
205
|
+
end
|
206
|
+
|
205
207
|
def _recompile_template(template, template_filename, template_method_name)
|
206
208
|
original_template_name = File.join(VIEW_PATH, template.to_s)
|
207
209
|
puts "Recompiling #{original_template_name}"
|
@@ -0,0 +1,12 @@
|
|
1
|
+
header
|
2
|
+
h1 Import dump
|
3
|
+
|
4
|
+
main
|
5
|
+
form method="post" action=import_deprecations_path enctype="multipart/form-data"
|
6
|
+
.mb-3
|
7
|
+
label.form-label> for="file" Choose a JSON file to upload:
|
8
|
+
input.form-comtrol type="file" name="file" id="file"
|
9
|
+
.mb-3
|
10
|
+
button.btn.btn-primary> type="submit" Upload
|
11
|
+
a.btn.btn-secondary> href=dump_deprecations_path Dump
|
12
|
+
a.btn.btn-secondary> href=deprecations_path Back
|
@@ -0,0 +1,121 @@
|
|
1
|
+
header.mb-3
|
2
|
+
h1 Deprecations
|
3
|
+
|
4
|
+
a.btn.btn-primary>(data-method="post" href=deprecation_path(:trigger) rel="nofollow") Trigger a couple
|
5
|
+
a.btn.btn-danger>(data-method="delete" data-confirm="Sure?" href=deprecation_path(:all) rel="nofollow")
|
6
|
+
i.bi.bi-trash
|
7
|
+
' Delete all
|
8
|
+
|
9
|
+
- if DeprecationCollector.instance.storage.support_disabling?
|
10
|
+
- if DeprecationCollector.instance.storage.enabled?
|
11
|
+
a.btn.btn-danger>(
|
12
|
+
data-method="delete" href=disable_deprecations_path rel="nofollow"
|
13
|
+
data-confirm="Sure? Will need to restart workers after enabling"
|
14
|
+
) Disable
|
15
|
+
- else
|
16
|
+
a.btn.btn-secondary>(
|
17
|
+
data-method="post" href=enable_deprecations_path rel="nofollow"
|
18
|
+
) Turn on (after workers restart)
|
19
|
+
|
20
|
+
main
|
21
|
+
table.table.table-striped
|
22
|
+
tr
|
23
|
+
th Count
|
24
|
+
th Message
|
25
|
+
th Location
|
26
|
+
th Ruby/Rails
|
27
|
+
|
28
|
+
- total = 0
|
29
|
+
- by_realm = Hash.new(0)
|
30
|
+
- deprecations.each do |deprecation|
|
31
|
+
- total += 1
|
32
|
+
- by_realm[deprecation[:realm]] += 1
|
33
|
+
tr data-digest=deprecation[:digest]
|
34
|
+
td
|
35
|
+
a href=deprecation_path(deprecation[:digest]) = deprecation[:count]
|
36
|
+
br
|
37
|
+
- deprecation_tags(deprecation).each_pair do |tag, cls|
|
38
|
+
.badge> class=cls = tag
|
39
|
+
|
40
|
+
td
|
41
|
+
ruby:
|
42
|
+
msg = deprecation[:message].to_s
|
43
|
+
delete_prefixes = Gem.path + [defined?(Rails) && Rails.root.to_s].compact
|
44
|
+
delete_prefixes.each { |path| msg = msg.gsub(path, '') }
|
45
|
+
msg.delete_prefix! deprecation[:gem_traceline].gsub(/:in .+/, ':') if deprecation[:gem_traceline]
|
46
|
+
msg.delete_prefix! deprecation[:app_traceline].gsub(/:in .+/, ':') if deprecation[:app_traceline]
|
47
|
+
msg.strip!
|
48
|
+
msg.delete_prefix!("DEPRECATION WARNING: ")
|
49
|
+
msg.delete_prefix!("warning: ")
|
50
|
+
|
51
|
+
- if msg.lines.size > 2
|
52
|
+
pre.pre-scrollable.p-1(style="overflow: auto; max-width: 700px; max-height: 200px; font-size: 11px")
|
53
|
+
code = msg
|
54
|
+
- else
|
55
|
+
.msg = msg
|
56
|
+
- if deprecation.dig(:notes, :comment)
|
57
|
+
= deprecation.dig(:notes, :comment)
|
58
|
+
|
59
|
+
- if deprecation.dig(:context, :action)
|
60
|
+
i.small.controller = deprecation.dig(:context, :action)
|
61
|
+
- elsif deprecation.dig(:context, :params, :controller)
|
62
|
+
i.small.controller = deprecation.dig(:context, :params).slice(:controller, :action).values.join('#')
|
63
|
+
|
64
|
+
td.small
|
65
|
+
- if deprecation[:gem_traceline]
|
66
|
+
.gem_location
|
67
|
+
- location, function = deprecation[:gem_traceline].split(':in `', 2)
|
68
|
+
- full_gemname = location.delete_prefix('/gems/').gsub(%r{/.*}, '')
|
69
|
+
- location_in_gem = location.delete_prefix("/gems/#{full_gemname}/")
|
70
|
+
i>= full_gemname
|
71
|
+
code.code_location> data-copy-value=location_in_gem = location_in_gem.delete_prefix('lib/')
|
72
|
+
i= function.delete_suffix("'")
|
73
|
+
- if deprecation[:app_traceline]
|
74
|
+
.app_location
|
75
|
+
- location, function = deprecation[:app_traceline].split(':in `', 2)
|
76
|
+
code.code_location>= location
|
77
|
+
i= function.delete_suffix("'")
|
78
|
+
td
|
79
|
+
.small.ruby = deprecation[:ruby_version]
|
80
|
+
.small.rails = deprecation[:rails_version]
|
81
|
+
|
82
|
+
a href=deprecation_path(deprecation[:digest]) data-method="delete" data-confirm="Delete?" rel="nofollow" title="Delete"
|
83
|
+
i.bi.bi-trash
|
84
|
+
- if total.zero?
|
85
|
+
tr
|
86
|
+
td colspan=4
|
87
|
+
p Looks like there're no deprecations (or workers have not yet wrote to redis)
|
88
|
+
p
|
89
|
+
' You can try
|
90
|
+
a href=deprecation_path(:trigger) data-method="post" rel="nofollow" trigger a couple
|
91
|
+
- if import_enabled?
|
92
|
+
|> , or
|
93
|
+
a> href=import_deprecations_path import
|
94
|
+
|
95
|
+
|
96
|
+
footer
|
97
|
+
- if total > 3
|
98
|
+
=> total
|
99
|
+
' deprecations
|
100
|
+
- by_realm.each_pair do |realm, count|
|
101
|
+
a.btn.btn-sm.btn-outline-secondary> href="?realm=#{realm}"
|
102
|
+
=> realm
|
103
|
+
.badge> class=(count == 0 ? 'bg-success' : 'bg-secondary') = count
|
104
|
+
- if params[:realm] && params[:realm] != ''
|
105
|
+
a.btn.btn-sm.btn-outline-primary> href="?realm="
|
106
|
+
' Other realms
|
107
|
+
|
108
|
+
css:
|
109
|
+
.code_location {
|
110
|
+
cursor: pointer;
|
111
|
+
}
|
112
|
+
|
113
|
+
javascript:
|
114
|
+
document.querySelectorAll('.code_location').forEach(function(elem){
|
115
|
+
elem.addEventListener('click', function () {
|
116
|
+
let textToCopy = elem.getAttribute('data-copy-value');
|
117
|
+
if(!textToCopy) textToCopy = elem.innerText;
|
118
|
+
console.log("Copying", textToCopy)
|
119
|
+
navigator.clipboard.writeText(textToCopy);
|
120
|
+
}, false);
|
121
|
+
});
|
@@ -1,4 +1,4 @@
|
|
1
|
-
_buf = ''; _buf << ("<header class=\"mb-3\"><h1>Deprecations</h1><a class=\"btn btn-primary\" data-method=\"post\"".freeze);
|
1
|
+
_buf = ''.dup; _buf << ("<header class=\"mb-3\"><h1>Deprecations</h1><a class=\"btn btn-primary\" data-method=\"post\"".freeze);
|
2
2
|
;
|
3
3
|
;
|
4
4
|
; _slim_codeattributes1 = deprecation_path(:trigger); if _slim_codeattributes1; if _slim_codeattributes1 == true; _buf << (" href=\"\"".freeze); else; _buf << (" href=\"".freeze); _buf << ((::Temple::Utils.escape_html((_slim_codeattributes1))).to_s); _buf << ("\"".freeze); end; end; _buf << (" rel=\"nofollow\">Trigger a couple</a> <a class=\"btn btn-danger\" data-confirm=\"Sure?\" data-method=\"delete\"".freeze);
|
@@ -27,7 +27,7 @@ _buf = ''; _buf << ("<header class=\"mb-3\"><h1>Deprecations</h1><a class=\"btn
|
|
27
27
|
;
|
28
28
|
; total = 0;
|
29
29
|
; by_realm = Hash.new(0);
|
30
|
-
;
|
30
|
+
; deprecations.each do |deprecation|;
|
31
31
|
; total += 1;
|
32
32
|
; by_realm[deprecation[:realm]] += 1;
|
33
33
|
; _buf << ("<tr".freeze); _slim_codeattributes5 = deprecation[:digest]; if _slim_codeattributes5; if _slim_codeattributes5 == true; _buf << (" data-digest=\"\"".freeze); else; _buf << (" data-digest=\"".freeze); _buf << ((::Temple::Utils.escape_html((_slim_codeattributes5))).to_s); _buf << ("\"".freeze); end; end; _buf << ("><td><a".freeze);
|
@@ -35,13 +35,13 @@ _buf = ''; _buf << ("<header class=\"mb-3\"><h1>Deprecations</h1><a class=\"btn
|
|
35
35
|
; _slim_codeattributes6 = deprecation_path(deprecation[:digest]); if _slim_codeattributes6; if _slim_codeattributes6 == true; _buf << (" href=\"\"".freeze); else; _buf << (" href=\"".freeze); _buf << ((::Temple::Utils.escape_html((_slim_codeattributes6))).to_s); _buf << ("\"".freeze); end; end; _buf << (">".freeze); _buf << ((::Temple::Utils.escape_html((deprecation[:count]))).to_s);
|
36
36
|
; _buf << ("</a><br />".freeze);
|
37
37
|
; deprecation_tags(deprecation).each_pair do |tag, cls|;
|
38
|
-
; _buf << ("<div".freeze); _temple_html_attributeremover1 = ''; _temple_html_attributemerger1 = []; _temple_html_attributemerger1[0] = "badge"; _temple_html_attributemerger1[1] = ''; _slim_codeattributes7 = cls; if Array === _slim_codeattributes7; _slim_codeattributes7 = _slim_codeattributes7.flatten; _slim_codeattributes7.map!(&:to_s); _slim_codeattributes7.reject!(&:empty?); _temple_html_attributemerger1[1] << ((::Temple::Utils.escape_html((_slim_codeattributes7.join(" ")))).to_s); else; _temple_html_attributemerger1[1] << ((::Temple::Utils.escape_html((_slim_codeattributes7))).to_s); end; _temple_html_attributemerger1[1]; _temple_html_attributeremover1 << ((_temple_html_attributemerger1.reject(&:empty?).join(" ")).to_s); _temple_html_attributeremover1; if !_temple_html_attributeremover1.empty?; _buf << (" class=\"".freeze); _buf << ((_temple_html_attributeremover1).to_s); _buf << ("\"".freeze); end; _buf << (">".freeze); _buf << ((::Temple::Utils.escape_html((tag))).to_s);
|
38
|
+
; _buf << ("<div".freeze); _temple_html_attributeremover1 = ''.dup; _temple_html_attributemerger1 = []; _temple_html_attributemerger1[0] = "badge"; _temple_html_attributemerger1[1] = ''.dup; _slim_codeattributes7 = cls; if Array === _slim_codeattributes7; _slim_codeattributes7 = _slim_codeattributes7.flatten; _slim_codeattributes7.map!(&:to_s); _slim_codeattributes7.reject!(&:empty?); _temple_html_attributemerger1[1] << ((::Temple::Utils.escape_html((_slim_codeattributes7.join(" ")))).to_s); else; _temple_html_attributemerger1[1] << ((::Temple::Utils.escape_html((_slim_codeattributes7))).to_s); end; _temple_html_attributemerger1[1]; _temple_html_attributeremover1 << ((_temple_html_attributemerger1.reject(&:empty?).join(" ")).to_s); _temple_html_attributeremover1; if !_temple_html_attributeremover1.empty?; _buf << (" class=\"".freeze); _buf << ((_temple_html_attributeremover1).to_s); _buf << ("\"".freeze); end; _buf << (">".freeze); _buf << ((::Temple::Utils.escape_html((tag))).to_s);
|
39
39
|
;
|
40
40
|
; _buf << ("</div> ".freeze); end; _buf << ("</td><td>".freeze);
|
41
41
|
;
|
42
|
-
; msg = deprecation[:message]
|
42
|
+
; msg = deprecation[:message].to_s
|
43
43
|
delete_prefixes = Gem.path + [defined?(Rails) && Rails.root.to_s].compact
|
44
|
-
delete_prefixes.each { |path| msg.gsub
|
44
|
+
delete_prefixes.each { |path| msg = msg.gsub(path, '') }
|
45
45
|
msg.delete_prefix! deprecation[:gem_traceline].gsub(/:in .+/, ':') if deprecation[:gem_traceline]
|
46
46
|
msg.delete_prefix! deprecation[:app_traceline].gsub(/:in .+/, ':') if deprecation[:app_traceline]
|
47
47
|
msg.strip!
|
@@ -100,7 +100,7 @@ msg.delete_prefix!("warning: ")
|
|
100
100
|
; end; by_realm.each_pair do |realm, count|;
|
101
101
|
; _buf << ("<a class=\"btn btn-sm btn-outline-secondary\" href=\"?realm=".freeze); _buf << ((::Temple::Utils.escape_html((realm))).to_s); _buf << ("\">".freeze);
|
102
102
|
; _buf << ((::Temple::Utils.escape_html((realm))).to_s);
|
103
|
-
; _buf << (" <div".freeze); _temple_html_attributeremover2 = ''; _temple_html_attributemerger2 = []; _temple_html_attributemerger2[0] = "badge"; _temple_html_attributemerger2[1] = ''; _slim_codeattributes13 = (count == 0 ? 'bg-success' : 'bg-secondary'); if Array === _slim_codeattributes13; _slim_codeattributes13 = _slim_codeattributes13.flatten; _slim_codeattributes13.map!(&:to_s); _slim_codeattributes13.reject!(&:empty?); _temple_html_attributemerger2[1] << ((::Temple::Utils.escape_html((_slim_codeattributes13.join(" ")))).to_s); else; _temple_html_attributemerger2[1] << ((::Temple::Utils.escape_html((_slim_codeattributes13))).to_s); end; _temple_html_attributemerger2[1]; _temple_html_attributeremover2 << ((_temple_html_attributemerger2.reject(&:empty?).join(" ")).to_s); _temple_html_attributeremover2; if !_temple_html_attributeremover2.empty?; _buf << (" class=\"".freeze); _buf << ((_temple_html_attributeremover2).to_s); _buf << ("\"".freeze); end; _buf << (">".freeze); _buf << ((::Temple::Utils.escape_html((count))).to_s);
|
103
|
+
; _buf << (" <div".freeze); _temple_html_attributeremover2 = ''.dup; _temple_html_attributemerger2 = []; _temple_html_attributemerger2[0] = "badge"; _temple_html_attributemerger2[1] = ''.dup; _slim_codeattributes13 = (count == 0 ? 'bg-success' : 'bg-secondary'); if Array === _slim_codeattributes13; _slim_codeattributes13 = _slim_codeattributes13.flatten; _slim_codeattributes13.map!(&:to_s); _slim_codeattributes13.reject!(&:empty?); _temple_html_attributemerger2[1] << ((::Temple::Utils.escape_html((_slim_codeattributes13.join(" ")))).to_s); else; _temple_html_attributemerger2[1] << ((::Temple::Utils.escape_html((_slim_codeattributes13))).to_s); end; _temple_html_attributemerger2[1]; _temple_html_attributeremover2 << ((_temple_html_attributemerger2.reject(&:empty?).join(" ")).to_s); _temple_html_attributeremover2; if !_temple_html_attributeremover2.empty?; _buf << (" class=\"".freeze); _buf << ((_temple_html_attributeremover2).to_s); _buf << ("\"".freeze); end; _buf << (">".freeze); _buf << ((::Temple::Utils.escape_html((count))).to_s);
|
104
104
|
; _buf << ("</div> </a> ".freeze); end; if params[:realm] && params[:realm] != '';
|
105
105
|
; _buf << ("<a class=\"btn btn-sm btn-outline-primary\" href=\"?realm=\">Other realms </a> ".freeze);
|
106
106
|
;
|
@@ -0,0 +1,90 @@
|
|
1
|
+
doctype html
|
2
|
+
html data-bs-theme=current_color_theme lang="en"
|
3
|
+
head
|
4
|
+
meta charset="utf-8"
|
5
|
+
meta http-equiv="X-UA-Compatible" content="IE=edge;chrome=1"
|
6
|
+
|
7
|
+
title="Deprecations"
|
8
|
+
meta name="description" content="Deprecation collector ui"
|
9
|
+
meta name="viewport" content="width=device-width"
|
10
|
+
|
11
|
+
link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" integrity="sha256-Fu5/PVNGJlC70y4mPEjA6nWVdPz2IMaBrXGQCJEsRho= sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous"
|
12
|
+
link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.2/font/bootstrap-icons.css" integrity="sha256-4RctOgogjPAdwGbwq+rxfwAmSpZhWaafcZR9btzUk18= sha384-b6lVK+yci+bfDmaY1u0zE8YYJt0TZxLEAFyYSLHId4xoVvsrQu3INevFKo+Xir8e" crossorigin="anonymous"
|
13
|
+
|
14
|
+
body
|
15
|
+
.container-fluid== yield
|
16
|
+
|
17
|
+
script async=true src="https://cdn.jsdelivr.net/npm/@rails/ujs@7.0.4-3/lib/assets/compiled/rails-ujs.js" integrity="sha256-9Mbe9mGA7d+AJbnz0O6CoLGabCbe6JAYnGshvGIADiE=" crossorigin="anonymous"
|
18
|
+
script async=true src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.min.js" integrity="sha256-QucgBAKNM4KKPJHqTfH8e+JON1G/gmPPqtMmBb+wHpc= sha384-Y4oOpwW3duJdCWv5ly8SCFYWqFDsfob/3GkgExXKV4idmbt98QcxXYs9UoXAB7BZ" crossorigin="anonymous"
|
19
|
+
|
20
|
+
javascript:
|
21
|
+
(() => {
|
22
|
+
'use strict'
|
23
|
+
|
24
|
+
const storedTheme = localStorage.getItem('theme')
|
25
|
+
|
26
|
+
const getPreferredTheme = () => {
|
27
|
+
if (storedTheme) { return storedTheme }
|
28
|
+
let fromServer = document.documentElement.getAttribute('data-bs-theme')
|
29
|
+
if(fromServer) { return fromServer }
|
30
|
+
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
|
31
|
+
}
|
32
|
+
|
33
|
+
const setTheme = function (theme) {
|
34
|
+
if (theme === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
35
|
+
document.documentElement.setAttribute('data-bs-theme', 'dark')
|
36
|
+
} else {
|
37
|
+
document.documentElement.setAttribute('data-bs-theme', theme)
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
setTheme(getPreferredTheme())
|
42
|
+
|
43
|
+
const showActiveTheme = (theme, focus = false) => {
|
44
|
+
const themeSwitcher = document.querySelector('#bd-theme')
|
45
|
+
|
46
|
+
if (!themeSwitcher) {
|
47
|
+
return
|
48
|
+
}
|
49
|
+
|
50
|
+
const themeSwitcherText = document.querySelector('#bd-theme-text')
|
51
|
+
const activeThemeIcon = document.querySelector('.theme-icon-active use')
|
52
|
+
const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`)
|
53
|
+
const svgOfActiveBtn = btnToActive.querySelector('svg use').getAttribute('href')
|
54
|
+
|
55
|
+
document.querySelectorAll('[data-bs-theme-value]').forEach(element => {
|
56
|
+
element.classList.remove('active')
|
57
|
+
element.setAttribute('aria-pressed', 'false')
|
58
|
+
})
|
59
|
+
|
60
|
+
btnToActive.classList.add('active')
|
61
|
+
btnToActive.setAttribute('aria-pressed', 'true')
|
62
|
+
activeThemeIcon.setAttribute('href', svgOfActiveBtn)
|
63
|
+
const themeSwitcherLabel = `${themeSwitcherText.textContent} (${btnToActive.dataset.bsThemeValue})`
|
64
|
+
themeSwitcher.setAttribute('aria-label', themeSwitcherLabel)
|
65
|
+
|
66
|
+
if (focus) {
|
67
|
+
themeSwitcher.focus()
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
|
72
|
+
if (storedTheme !== 'light' || storedTheme !== 'dark') {
|
73
|
+
setTheme(getPreferredTheme())
|
74
|
+
}
|
75
|
+
})
|
76
|
+
|
77
|
+
window.addEventListener('DOMContentLoaded', () => {
|
78
|
+
showActiveTheme(getPreferredTheme())
|
79
|
+
|
80
|
+
document.querySelectorAll('[data-bs-theme-value]')
|
81
|
+
.forEach(toggle => {
|
82
|
+
toggle.addEventListener('click', () => {
|
83
|
+
const theme = toggle.getAttribute('data-bs-theme-value')
|
84
|
+
localStorage.setItem('theme', theme)
|
85
|
+
setTheme(theme)
|
86
|
+
showActiveTheme(theme, true)
|
87
|
+
})
|
88
|
+
})
|
89
|
+
})
|
90
|
+
})()
|
@@ -1,4 +1,4 @@
|
|
1
|
-
_buf = ''; _buf << ("<!DOCTYPE html><html".freeze);
|
1
|
+
_buf = ''.dup; _buf << ("<!DOCTYPE html><html".freeze);
|
2
2
|
; _slim_codeattributes1 = current_color_theme; if _slim_codeattributes1; if _slim_codeattributes1 == true; _buf << (" data-bs-theme=\"\"".freeze); else; _buf << (" data-bs-theme=\"".freeze); _buf << ((::Temple::Utils.escape_html((_slim_codeattributes1))).to_s); _buf << ("\"".freeze); end; end; _buf << (" lang=\"en\"><head><meta charset=\"utf-8\" /><meta content=\"IE=edge;chrome=1\" http-equiv=\"X-UA-Compatible\" /><title>".freeze);
|
3
3
|
;
|
4
4
|
;
|