deprecation_collector 0.5.1 → 0.6.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 +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 +13 -9
- 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,13 +62,15 @@ 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?
|
71
|
+
%w[trigger_kwargs_error_warning trigger_rails_deprecation].any? do |method|
|
72
|
+
deprecation[:message].to_s.include?(method)
|
73
|
+
end
|
72
74
|
end
|
73
75
|
|
74
76
|
def deprecation_tags(deprecation)
|
@@ -80,11 +82,13 @@ class DeprecationCollector
|
|
80
82
|
tags << deprecation[:realm] if deprecation[:realm] && deprecation[:realm] != "rails"
|
81
83
|
tags.merge(deprecation.dig(:notes, :tags) || [])
|
82
84
|
|
83
|
-
tags.
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
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
|
88
92
|
end
|
89
93
|
end
|
90
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
|
;
|