end_of_life 0.4.1 → 0.5.1
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/.tool-versions +1 -1
- data/CHANGELOG.md +13 -1
- data/Gemfile +1 -1
- data/Gemfile.lock +44 -33
- data/README.md +23 -14
- data/end_of_life.gemspec +7 -3
- data/lib/end_of_life/api.rb +17 -0
- data/lib/end_of_life/cli.rb +7 -58
- data/lib/end_of_life/helpers/silent_bundler.rb +18 -0
- data/lib/end_of_life/{terminal_helper.rb → helpers/terminal.rb} +1 -1
- data/lib/end_of_life/in_memory_file.rb +3 -0
- data/lib/end_of_life/options.rb +18 -14
- data/lib/end_of_life/parsers/gemfile.rb +31 -0
- data/lib/end_of_life/parsers/gemfile_lock.rb +16 -0
- data/lib/end_of_life/parsers/ruby_version.rb +11 -0
- data/lib/end_of_life/parsers/tool_versions.rb +23 -0
- data/lib/end_of_life/product/registry.rb +23 -0
- data/lib/end_of_life/product/release.rb +30 -0
- data/lib/end_of_life/product.rb +32 -0
- data/lib/end_of_life/report.rb +35 -0
- data/lib/end_of_life/repository/search/query.rb +31 -0
- data/lib/end_of_life/repository/search.rb +45 -0
- data/lib/end_of_life/repository.rb +17 -81
- data/lib/end_of_life/scanner.rb +41 -0
- data/lib/end_of_life/version.rb +1 -1
- data/lib/end_of_life/version_detector.rb +27 -0
- data/lib/end_of_life/version_detectors/rails.rb +26 -0
- data/lib/end_of_life/version_detectors/ruby.rb +35 -0
- data/lib/end_of_life/version_detectors.rb +17 -0
- data/lib/end_of_life.rb +10 -7
- metadata +60 -10
- data/lib/end_of_life/ruby_version/parser.rb +0 -96
- data/lib/end_of_life/ruby_version.rb +0 -69
- data/lib/end_of_life.json +0 -98
@@ -0,0 +1,30 @@
|
|
1
|
+
module EndOfLife
|
2
|
+
class Product
|
3
|
+
class Release < Data.define(:product, :version, :eol_date)
|
4
|
+
include Comparable
|
5
|
+
|
6
|
+
def self.ruby(version, eol_date: nil) = new(product: "ruby", version:, eol_date:)
|
7
|
+
|
8
|
+
def initialize(product:, version:, eol_date: nil)
|
9
|
+
product = Product.find(product.to_s)
|
10
|
+
eol_date = Date.parse(eol_date.to_s) if eol_date
|
11
|
+
super(product:, eol_date:, version: Gem::Version.new(version))
|
12
|
+
end
|
13
|
+
|
14
|
+
def eol?(at: Date.today)
|
15
|
+
if eol_date
|
16
|
+
eol_date <= at
|
17
|
+
else
|
18
|
+
self <= product.latest_eol_release(at: at)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
ZERO = Gem::Version.new("0")
|
23
|
+
def zero? = version == ZERO
|
24
|
+
|
25
|
+
def <=>(other) = version <=> other.version
|
26
|
+
|
27
|
+
def to_s = version.to_s
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module EndOfLife
|
2
|
+
class Product
|
3
|
+
def self.find(name) = EndOfLife.find_product(name)
|
4
|
+
|
5
|
+
attr_reader :name, :search_query, :version_detector
|
6
|
+
|
7
|
+
def initialize(name, search_query, version_detector)
|
8
|
+
@name = name.to_s.downcase
|
9
|
+
@search_query = search_query
|
10
|
+
@version_detector = version_detector
|
11
|
+
end
|
12
|
+
|
13
|
+
def eol_releases_at(date)
|
14
|
+
all_releases.filter { |release| release.eol_date <= date }
|
15
|
+
end
|
16
|
+
|
17
|
+
def latest_eol_release(at: Date.today)
|
18
|
+
eol_releases_at(at).max
|
19
|
+
end
|
20
|
+
|
21
|
+
def label = name.capitalize
|
22
|
+
def to_s = label
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def all_releases
|
27
|
+
@all_releases ||= API.fetch_product(name)
|
28
|
+
.dig(:result, :releases)
|
29
|
+
.map { |json| Release.new(name, json[:latest][:name], json[:eolFrom]) }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "stringio"
|
2
|
+
|
3
|
+
module EndOfLife
|
4
|
+
class Report < Data.define(:product, :repositories, :max_eol_date)
|
5
|
+
include Helpers::Terminal
|
6
|
+
|
7
|
+
def to_s
|
8
|
+
report = StringIO.new
|
9
|
+
report.puts
|
10
|
+
|
11
|
+
if repositories.empty?
|
12
|
+
report.puts "No repositories using EOL #{product}."
|
13
|
+
else
|
14
|
+
word = (repositories.size == 1) ? "repository" : "repositories"
|
15
|
+
report.puts "Found #{repositories.size} #{word} using EOL #{product} (<= #{product.latest_eol_release(at: max_eol_date)}):"
|
16
|
+
report.puts end_of_life_table(repositories)
|
17
|
+
end
|
18
|
+
|
19
|
+
report.string
|
20
|
+
end
|
21
|
+
|
22
|
+
def failure? = repositories.any?
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def end_of_life_table(repositories)
|
27
|
+
headers = ["", "Repository", "#{product} version"]
|
28
|
+
rows = repositories.map.with_index(1) do |repo, i|
|
29
|
+
[i, repo.url, repo.min_release_of(product)]
|
30
|
+
end
|
31
|
+
|
32
|
+
table(headers, rows)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module EndOfLife
|
2
|
+
class Repository
|
3
|
+
class Search
|
4
|
+
Query = Data.define(:options) do
|
5
|
+
def to_s
|
6
|
+
query = options[:product].search_query
|
7
|
+
|
8
|
+
query += if options[:repository]
|
9
|
+
" repo:#{options[:repository]}"
|
10
|
+
elsif options[:organizations]
|
11
|
+
options[:organizations].map { |org| " org:#{org}" }.join
|
12
|
+
else
|
13
|
+
" user:#{options[:user]}"
|
14
|
+
end
|
15
|
+
|
16
|
+
if options[:visibility]
|
17
|
+
query += " is:#{options[:visibility]}"
|
18
|
+
end
|
19
|
+
|
20
|
+
if options[:excludes]
|
21
|
+
words_to_exclude = options[:excludes].map { |word| "NOT #{word} " }.join
|
22
|
+
|
23
|
+
query += " #{words_to_exclude} in:name"
|
24
|
+
end
|
25
|
+
|
26
|
+
query
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module EndOfLife
|
2
|
+
class Repository
|
3
|
+
class Search
|
4
|
+
include Dry::Monads[:result, :maybe]
|
5
|
+
|
6
|
+
attr_reader :options
|
7
|
+
|
8
|
+
def initialize(options)
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
def result
|
13
|
+
github_client.bind do |github|
|
14
|
+
github.auto_paginate = true
|
15
|
+
options[:user] ||= github.user.login
|
16
|
+
|
17
|
+
query = Query.new(options).to_s
|
18
|
+
items = github.search_repositories(query, {sort: :updated}).items
|
19
|
+
|
20
|
+
Success(
|
21
|
+
items.filter_map do |repo|
|
22
|
+
next if repo.archived && options[:skip_archived]
|
23
|
+
|
24
|
+
Repository.new(
|
25
|
+
full_name: repo.full_name,
|
26
|
+
url: repo.html_url,
|
27
|
+
github_client: github
|
28
|
+
)
|
29
|
+
end
|
30
|
+
)
|
31
|
+
rescue => e
|
32
|
+
Failure("Unexpected error: #{e}")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def github_client
|
39
|
+
Maybe(ENV["GITHUB_TOKEN"])
|
40
|
+
.fmap { |token| Octokit::Client.new(access_token: token) }
|
41
|
+
.or { Failure("Please set GITHUB_TOKEN environment variable") }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -1,61 +1,7 @@
|
|
1
1
|
module EndOfLife
|
2
2
|
class Repository
|
3
3
|
class << self
|
4
|
-
|
5
|
-
|
6
|
-
def fetch(options)
|
7
|
-
github_client.bind do |github|
|
8
|
-
github.auto_paginate = true
|
9
|
-
options[:user] ||= github.user.login
|
10
|
-
|
11
|
-
query = search_query_for(options)
|
12
|
-
items = github.search_repositories(query, {sort: :updated}).items
|
13
|
-
|
14
|
-
Success(
|
15
|
-
items.filter_map do |repo|
|
16
|
-
next if repo.archived && options[:skip_archived]
|
17
|
-
|
18
|
-
Repository.new(
|
19
|
-
full_name: repo.full_name,
|
20
|
-
url: repo.html_url,
|
21
|
-
github_client: github
|
22
|
-
)
|
23
|
-
end
|
24
|
-
)
|
25
|
-
rescue => e
|
26
|
-
Failure("Unexpected error: #{e}")
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def github_client
|
31
|
-
Maybe(ENV["GITHUB_TOKEN"])
|
32
|
-
.fmap { |token| Octokit::Client.new(access_token: token) }
|
33
|
-
.or { Failure("Please set GITHUB_TOKEN environment variable") }
|
34
|
-
end
|
35
|
-
|
36
|
-
def search_query_for(options)
|
37
|
-
query = "language:ruby"
|
38
|
-
|
39
|
-
query += if options[:repository]
|
40
|
-
" repo:#{options[:repository]}"
|
41
|
-
elsif options[:organizations]
|
42
|
-
options[:organizations].map { |org| " org:#{org}" }.join
|
43
|
-
else
|
44
|
-
" user:#{options[:user]}"
|
45
|
-
end
|
46
|
-
|
47
|
-
if options[:visibility]
|
48
|
-
query += " is:#{options[:visibility]}"
|
49
|
-
end
|
50
|
-
|
51
|
-
if options[:excludes]
|
52
|
-
words_to_exclude = options[:excludes].map { |word| "NOT #{word} " }.join
|
53
|
-
|
54
|
-
query += " #{words_to_exclude} in:name"
|
55
|
-
end
|
56
|
-
|
57
|
-
query
|
58
|
-
end
|
4
|
+
def search(options) = Search.new(options).result
|
59
5
|
end
|
60
6
|
|
61
7
|
attr_reader :full_name, :url
|
@@ -64,39 +10,33 @@ module EndOfLife
|
|
64
10
|
@full_name = full_name
|
65
11
|
@url = url
|
66
12
|
@github_client = github_client
|
13
|
+
@product_releases = {}
|
67
14
|
end
|
68
15
|
|
69
|
-
def
|
70
|
-
|
16
|
+
def using_eol?(product, at: Date.today)
|
17
|
+
min_release_of(product)&.eol?(at: at)
|
71
18
|
end
|
72
19
|
|
73
|
-
def
|
74
|
-
return @ruby_version if defined?(@ruby_version)
|
75
|
-
|
76
|
-
@ruby_version = ruby_versions.min
|
77
|
-
end
|
20
|
+
def min_release_of(product) = releases_for(product).min
|
78
21
|
|
79
22
|
private
|
80
23
|
|
81
|
-
def
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
parse_version_file(file)
|
86
|
-
}
|
24
|
+
def releases_for(product)
|
25
|
+
@product_releases[product] ||= product.version_detector.detect_all(
|
26
|
+
fetch_files(product.version_detector.relevant_files)
|
27
|
+
)
|
87
28
|
end
|
88
29
|
|
89
|
-
|
90
|
-
".ruby-version",
|
91
|
-
"Gemfile.lock",
|
92
|
-
"Gemfile",
|
93
|
-
".tool-versions"
|
94
|
-
]
|
95
|
-
def fetch_ruby_version_files
|
30
|
+
def fetch_files(file_paths)
|
96
31
|
Sync do
|
97
|
-
|
32
|
+
file_paths
|
98
33
|
.map { |file_path| Async { fetch_file(file_path) } }
|
99
|
-
.filter_map
|
34
|
+
.filter_map { |task|
|
35
|
+
file = task.wait
|
36
|
+
next if file.nil?
|
37
|
+
|
38
|
+
InMemoryFile.new(file.path, decode_file(file))
|
39
|
+
}
|
100
40
|
end
|
101
41
|
end
|
102
42
|
|
@@ -106,10 +46,6 @@ module EndOfLife
|
|
106
46
|
nil
|
107
47
|
end
|
108
48
|
|
109
|
-
def parse_version_file(file)
|
110
|
-
RubyVersion.from_file(file_name: file.name, content: decode_file(file))
|
111
|
-
end
|
112
|
-
|
113
49
|
def decode_file(file)
|
114
50
|
return file.content if file.encoding.nil?
|
115
51
|
return Base64.decode64(file.content) if file.encoding == "base64"
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module EndOfLife
|
2
|
+
module Scanner
|
3
|
+
include Helpers::Terminal
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def scan(options)
|
7
|
+
fetch_repositories(options)
|
8
|
+
.fmap { |repositories| filter_repositories_with_eol_products(repositories, **options.slice(:product, :max_eol_date)) }
|
9
|
+
.fmap { |repositories| output_report(repositories, **options.slice(:product, :max_eol_date)) }
|
10
|
+
.or { |error| abort "\n#{error_msg(error)}" }
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def fetch_repositories(options)
|
16
|
+
with_loading_spinner("Searching repositories with #{options[:product].label}...") do |spinner|
|
17
|
+
result = Repository.search(options)
|
18
|
+
spinner.error if result.failure?
|
19
|
+
|
20
|
+
result
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def filter_repositories_with_eol_products(repositories, product:, max_eol_date:)
|
25
|
+
with_loading_spinner("Searching for EOL #{product} in your repositories...") do
|
26
|
+
Sync do
|
27
|
+
repositories
|
28
|
+
.map { |repo| Async { [repo, repo.using_eol?(product, at: max_eol_date)] } }.map(&:wait)
|
29
|
+
.filter_map { |repo, contains_eol| contains_eol ? repo : nil }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def output_report(repositories, product:, max_eol_date:)
|
35
|
+
report = Report.new(product, repositories, max_eol_date)
|
36
|
+
puts report
|
37
|
+
|
38
|
+
exit(1) if report.failure?
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/end_of_life/version.rb
CHANGED
@@ -0,0 +1,27 @@
|
|
1
|
+
module EndOfLife
|
2
|
+
module VersionDetector
|
3
|
+
def file_detectors
|
4
|
+
@file_detectors ||= {}
|
5
|
+
end
|
6
|
+
|
7
|
+
def detects_from(file, &block)
|
8
|
+
file_detectors[file] = block
|
9
|
+
end
|
10
|
+
|
11
|
+
def relevant_files = file_detectors.keys
|
12
|
+
|
13
|
+
def detect_all(files)
|
14
|
+
files.filter_map { |file| detect(file) }
|
15
|
+
end
|
16
|
+
|
17
|
+
def detect(file)
|
18
|
+
return if file.read.strip.empty?
|
19
|
+
detector = file_detectors[File.basename(file.path)] or return
|
20
|
+
version = detector.call(file.read) or return
|
21
|
+
|
22
|
+
return if version.zero?
|
23
|
+
|
24
|
+
version
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module EndOfLife
|
2
|
+
module VersionDetectors
|
3
|
+
module Rails
|
4
|
+
extend VersionDetector
|
5
|
+
|
6
|
+
detects_from "Gemfile.lock" do |file_content|
|
7
|
+
gemfile_lock = Parsers::GemfileLock.parse(file_content) or next
|
8
|
+
rails = gemfile_lock.specs.find { |it| it.name == "rails" } or next
|
9
|
+
|
10
|
+
Product::Release.new(product: "rails", version: rails.version)
|
11
|
+
end
|
12
|
+
|
13
|
+
detects_from "Gemfile" do |file_content|
|
14
|
+
gemfile = Parsers::Gemfile.parse(file_content) or next
|
15
|
+
rails_dep = gemfile.dependencies.find { |it| it.name == "rails" } or next
|
16
|
+
exact_version = rails_dep
|
17
|
+
.requirement
|
18
|
+
.requirements
|
19
|
+
.filter { |op, _| op == "=" } # standard:disable Style/HashSlice
|
20
|
+
.max_by { |_, version| version } or next
|
21
|
+
|
22
|
+
Product::Release.new(product: "rails", version: exact_version.last)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "bundler"
|
2
|
+
|
3
|
+
module EndOfLife
|
4
|
+
module VersionDetectors
|
5
|
+
module Ruby
|
6
|
+
extend VersionDetector
|
7
|
+
|
8
|
+
detects_from ".ruby-version" do |file_content|
|
9
|
+
string_version = Parsers::RubyVersion.parse(file_content)
|
10
|
+
|
11
|
+
Product::Release.ruby(string_version)
|
12
|
+
end
|
13
|
+
|
14
|
+
detects_from "Gemfile.lock" do |file_content|
|
15
|
+
gemfile_lock_version = Parsers::GemfileLock.parse(file_content)&.ruby_version or next
|
16
|
+
|
17
|
+
Product::Release.ruby(gemfile_lock_version.delete_prefix("ruby "))
|
18
|
+
end
|
19
|
+
|
20
|
+
detects_from "Gemfile" do |file_content|
|
21
|
+
gemfile = Parsers::Gemfile.parse(file_content)
|
22
|
+
gemfile_version = gemfile&.ruby_version&.gem_version or next
|
23
|
+
|
24
|
+
Product::Release.ruby(gemfile_version)
|
25
|
+
end
|
26
|
+
|
27
|
+
detects_from ".tool-versions" do |file_content|
|
28
|
+
tool_versions = Parsers::ToolVersions.parse(file_content)
|
29
|
+
ruby_version = tool_versions["ruby"] or next
|
30
|
+
|
31
|
+
Product::Release.ruby(ruby_version)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module EndOfLife
|
2
|
+
module VersionDetectors
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def for_product(product)
|
6
|
+
detector_class = "#{self}::#{camelize(product.to_s)}"
|
7
|
+
|
8
|
+
const_get(detector_class)
|
9
|
+
rescue NameError
|
10
|
+
raise ArgumentError, "Undefined version detector for product: #{product}"
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def camelize(word) = Zeitwerk::Inflector.new.camelize(word, nil)
|
16
|
+
end
|
17
|
+
end
|
data/lib/end_of_life.rb
CHANGED
@@ -5,13 +5,16 @@ require "dry-monads"
|
|
5
5
|
require "json"
|
6
6
|
require "base64"
|
7
7
|
require "octokit"
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
require_relative "end_of_life/cli"
|
8
|
+
require "zeitwerk"
|
9
|
+
|
10
|
+
Zeitwerk::Loader.for_gem.tap { |it|
|
11
|
+
it.inflector.inflect("cli" => "CLI", "api" => "API")
|
12
|
+
}.setup
|
14
13
|
|
15
14
|
module EndOfLife
|
16
|
-
extend
|
15
|
+
extend Product::Registry
|
16
|
+
extend Helpers::Terminal
|
17
|
+
|
18
|
+
scans_for :ruby, search_query: "language:ruby"
|
19
|
+
scans_for :rails, search_query: "language:ruby"
|
17
20
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: end_of_life
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matheus Richard
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: async
|
@@ -23,6 +23,26 @@ dependencies:
|
|
23
23
|
- - ">="
|
24
24
|
- !ruby/object:Gem::Version
|
25
25
|
version: '0'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: bundler
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 2.3.0
|
33
|
+
- - "<"
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '3'
|
36
|
+
type: :runtime
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 2.3.0
|
43
|
+
- - "<"
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '3'
|
26
46
|
- !ruby/object:Gem::Dependency
|
27
47
|
name: dry-monads
|
28
48
|
requirement: !ruby/object:Gem::Requirement
|
@@ -93,8 +113,23 @@ dependencies:
|
|
93
113
|
- - "~>"
|
94
114
|
- !ruby/object:Gem::Version
|
95
115
|
version: 0.12.0
|
96
|
-
|
97
|
-
|
116
|
+
- !ruby/object:Gem::Dependency
|
117
|
+
name: zeitwerk
|
118
|
+
requirement: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - "~>"
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '2.7'
|
123
|
+
type: :runtime
|
124
|
+
prerelease: false
|
125
|
+
version_requirements: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - "~>"
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '2.7'
|
130
|
+
description: |
|
131
|
+
Searches your GitHub repositores and lists the ones using end-of-life, i.e.
|
132
|
+
unmaintained, software.
|
98
133
|
email:
|
99
134
|
- matheusrichardt@gmail.com
|
100
135
|
executables:
|
@@ -117,15 +152,30 @@ files:
|
|
117
152
|
- end_of_life.gemspec
|
118
153
|
- exe/end_of_life
|
119
154
|
- exe/eol
|
120
|
-
- lib/end_of_life.json
|
121
155
|
- lib/end_of_life.rb
|
156
|
+
- lib/end_of_life/api.rb
|
122
157
|
- lib/end_of_life/cli.rb
|
158
|
+
- lib/end_of_life/helpers/silent_bundler.rb
|
159
|
+
- lib/end_of_life/helpers/terminal.rb
|
160
|
+
- lib/end_of_life/in_memory_file.rb
|
123
161
|
- lib/end_of_life/options.rb
|
162
|
+
- lib/end_of_life/parsers/gemfile.rb
|
163
|
+
- lib/end_of_life/parsers/gemfile_lock.rb
|
164
|
+
- lib/end_of_life/parsers/ruby_version.rb
|
165
|
+
- lib/end_of_life/parsers/tool_versions.rb
|
166
|
+
- lib/end_of_life/product.rb
|
167
|
+
- lib/end_of_life/product/registry.rb
|
168
|
+
- lib/end_of_life/product/release.rb
|
169
|
+
- lib/end_of_life/report.rb
|
124
170
|
- lib/end_of_life/repository.rb
|
125
|
-
- lib/end_of_life/
|
126
|
-
- lib/end_of_life/
|
127
|
-
- lib/end_of_life/
|
171
|
+
- lib/end_of_life/repository/search.rb
|
172
|
+
- lib/end_of_life/repository/search/query.rb
|
173
|
+
- lib/end_of_life/scanner.rb
|
128
174
|
- lib/end_of_life/version.rb
|
175
|
+
- lib/end_of_life/version_detector.rb
|
176
|
+
- lib/end_of_life/version_detectors.rb
|
177
|
+
- lib/end_of_life/version_detectors/rails.rb
|
178
|
+
- lib/end_of_life/version_detectors/ruby.rb
|
129
179
|
homepage: https://github.com/MatheusRich/end_of_life
|
130
180
|
licenses:
|
131
181
|
- MIT
|
@@ -147,7 +197,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
147
197
|
- !ruby/object:Gem::Version
|
148
198
|
version: '0'
|
149
199
|
requirements: []
|
150
|
-
rubygems_version: 3.6.
|
200
|
+
rubygems_version: 3.6.9
|
151
201
|
specification_version: 4
|
152
|
-
summary: Lists repositories using end-of-life
|
202
|
+
summary: Lists repositories using end-of-life software
|
153
203
|
test_files: []
|