end_of_life 0.5.1 → 1.0.0.alpha
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/.standard.yml +3 -0
- data/CHANGELOG.md +19 -1
- data/Gemfile +2 -1
- data/Gemfile.lock +23 -9
- data/README.md +95 -27
- data/bin/end_of_life +1 -0
- data/end_of_life.gemspec +5 -1
- data/lib/end_of_life/api.rb +3 -0
- data/lib/end_of_life/check.rb +46 -0
- data/lib/end_of_life/cli/command/registry.rb +46 -0
- data/lib/end_of_life/cli.rb +109 -14
- data/lib/end_of_life/helpers/terminal.rb +3 -3
- data/lib/end_of_life/helpers/text.rb +11 -0
- data/lib/end_of_life/helpers/time.rb +35 -0
- data/lib/end_of_life/parsers/mise_toml.rb +15 -0
- data/lib/end_of_life/parsers/tool_versions.rb +1 -0
- data/lib/end_of_life/product/registry.rb +4 -3
- data/lib/end_of_life/product/release.rb +22 -1
- data/lib/end_of_life/product.rb +10 -9
- data/lib/end_of_life/repository/search.rb +13 -2
- data/lib/end_of_life/repository.rb +3 -0
- data/lib/end_of_life/scanner/report.rb +37 -0
- data/lib/end_of_life/scanner.rb +16 -10
- data/lib/end_of_life/version.rb +1 -1
- data/lib/end_of_life/version_detector.rb +2 -2
- data/lib/end_of_life/version_detectors/nodejs.rb +31 -0
- data/lib/end_of_life/version_detectors/ruby.rb +7 -0
- data/lib/end_of_life/version_detectors.rb +0 -2
- data/lib/end_of_life.rb +3 -7
- metadata +75 -10
- data/.tool-versions +0 -1
- data/lib/end_of_life/options.rb +0 -63
- data/lib/end_of_life/report.rb +0 -35
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
module EndOfLife
|
|
2
2
|
module Product::Registry
|
|
3
|
-
def scans_for(product_name,
|
|
3
|
+
def scans_for(product_name, label: nil)
|
|
4
4
|
product_registry[product_name.to_sym.downcase] = Product.new(
|
|
5
5
|
product_name,
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
version_detector_for(product_name),
|
|
7
|
+
label
|
|
8
8
|
)
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def find_product(name) = product_registry.fetch(name.to_sym.downcase)
|
|
12
12
|
|
|
13
13
|
def products = product_registry.values
|
|
14
|
+
def products_pattern(suffix: nil) = /\A(?:#{products.map(&:name).join("|")})#{suffix}/i
|
|
14
15
|
|
|
15
16
|
private
|
|
16
17
|
|
|
@@ -3,6 +3,17 @@ module EndOfLife
|
|
|
3
3
|
class Release < Data.define(:product, :version, :eol_date)
|
|
4
4
|
include Comparable
|
|
5
5
|
|
|
6
|
+
def self.parse!(string)
|
|
7
|
+
product, version = string.split("@", 2)
|
|
8
|
+
raise ArgumentError, "Invalid product release format: #{string}" if product.to_s.empty? || version.to_s.empty?
|
|
9
|
+
|
|
10
|
+
begin
|
|
11
|
+
new(product:, version:)
|
|
12
|
+
rescue ArgumentError
|
|
13
|
+
raise ArgumentError, "Malformed version number string: #{version}"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
6
17
|
def self.ruby(version, eol_date: nil) = new(product: "ruby", version:, eol_date:)
|
|
7
18
|
|
|
8
19
|
def initialize(product:, version:, eol_date: nil)
|
|
@@ -19,12 +30,22 @@ module EndOfLife
|
|
|
19
30
|
end
|
|
20
31
|
end
|
|
21
32
|
|
|
33
|
+
def supported?(...) = !eol?(...)
|
|
34
|
+
|
|
35
|
+
def latest_release_in_cycle
|
|
36
|
+
product.all_releases.filter { |r| r.version.to_s.start_with?(cycle_version.to_s) }.max
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def cycle_version
|
|
40
|
+
Gem::Version.new(version.segments.first(2).join("."))
|
|
41
|
+
end
|
|
42
|
+
|
|
22
43
|
ZERO = Gem::Version.new("0")
|
|
23
44
|
def zero? = version == ZERO
|
|
24
45
|
|
|
25
46
|
def <=>(other) = version <=> other.version
|
|
26
47
|
|
|
27
|
-
def to_s = version
|
|
48
|
+
def to_s = "#{product.name}@#{version}"
|
|
28
49
|
end
|
|
29
50
|
end
|
|
30
51
|
end
|
data/lib/end_of_life/product.rb
CHANGED
|
@@ -2,31 +2,32 @@ module EndOfLife
|
|
|
2
2
|
class Product
|
|
3
3
|
def self.find(name) = EndOfLife.find_product(name)
|
|
4
4
|
|
|
5
|
-
attr_reader :name, :
|
|
5
|
+
attr_reader :name, :version_detector, :label
|
|
6
6
|
|
|
7
|
-
def initialize(name,
|
|
7
|
+
def initialize(name, version_detector, label = nil)
|
|
8
8
|
@name = name.to_s.downcase
|
|
9
|
-
@search_query = search_query
|
|
10
9
|
@version_detector = version_detector
|
|
10
|
+
@label = label || @name.capitalize
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def eol_releases_at(date)
|
|
14
|
-
all_releases.filter { |release| release.eol_date <= date }
|
|
14
|
+
all_releases.filter { |release| release.eol_date.nil? || release.eol_date <= date }
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def latest_eol_release(at: Date.today)
|
|
18
18
|
eol_releases_at(at).max
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
def label = name.capitalize
|
|
22
|
-
def to_s = label
|
|
23
|
-
|
|
24
|
-
private
|
|
25
|
-
|
|
26
21
|
def all_releases
|
|
27
22
|
@all_releases ||= API.fetch_product(name)
|
|
28
23
|
.dig(:result, :releases)
|
|
29
24
|
.map { |json| Release.new(name, json[:latest][:name], json[:eolFrom]) }
|
|
30
25
|
end
|
|
26
|
+
|
|
27
|
+
def search_query
|
|
28
|
+
version_detector.relevant_files.map { |f| %(filename:"#{f}") }.join(" ")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def to_s = label
|
|
31
32
|
end
|
|
32
33
|
end
|
|
@@ -14,11 +14,22 @@ module EndOfLife
|
|
|
14
14
|
github.auto_paginate = true
|
|
15
15
|
options[:user] ||= github.user.login
|
|
16
16
|
|
|
17
|
+
# GitHub doesn't have a way to get repos that contain specific files.
|
|
18
|
+
# The language filter sort of works, but it might miss some repos that
|
|
19
|
+
# use a language, but it's not the main one.
|
|
20
|
+
#
|
|
21
|
+
# We have to use the code search endpoint to find files matching the
|
|
22
|
+
# product we're interested in and then extract the repositories from
|
|
23
|
+
# the results.
|
|
17
24
|
query = Query.new(options).to_s
|
|
18
|
-
|
|
25
|
+
repo_names = github.search_code(query).items.map { |item| item.repository.full_name }.uniq
|
|
26
|
+
return Success([]) if repo_names.empty?
|
|
27
|
+
|
|
28
|
+
repos_query = repo_names.map { |name| "repo:#{name}" }.join(" ")
|
|
29
|
+
repos = github.search_repositories(repos_query, {sort: :updated}).items
|
|
19
30
|
|
|
20
31
|
Success(
|
|
21
|
-
|
|
32
|
+
repos.filter_map do |repo|
|
|
22
33
|
next if repo.archived && options[:skip_archived]
|
|
23
34
|
|
|
24
35
|
Repository.new(
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require "stringio"
|
|
2
|
+
|
|
3
|
+
module EndOfLife
|
|
4
|
+
module Scanner
|
|
5
|
+
class Report < Data.define(:product, :repositories, :max_eol_date)
|
|
6
|
+
include Helpers::Text
|
|
7
|
+
include Helpers::Terminal
|
|
8
|
+
|
|
9
|
+
def to_s
|
|
10
|
+
report = StringIO.new
|
|
11
|
+
report.puts
|
|
12
|
+
|
|
13
|
+
if repositories.empty?
|
|
14
|
+
report.puts "No repositories using EOL #{product}."
|
|
15
|
+
else
|
|
16
|
+
report.puts "Found #{pluralize(repositories.size, "repository", "repositories")} using EOL #{product} (<= #{product.latest_eol_release(at: max_eol_date)}):"
|
|
17
|
+
report.puts end_of_life_table(repositories)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
report.string
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def failure? = repositories.any?
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def end_of_life_table(repositories)
|
|
28
|
+
headers = ["", "Repository", "#{product} version"]
|
|
29
|
+
rows = repositories.map.with_index(1) do |repo, i|
|
|
30
|
+
[i, repo.url, repo.min_release_of(product)]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
table(headers, rows)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
data/lib/end_of_life/scanner.rb
CHANGED
|
@@ -1,28 +1,34 @@
|
|
|
1
|
+
require "async"
|
|
2
|
+
require "dry-monads"
|
|
3
|
+
|
|
1
4
|
module EndOfLife
|
|
2
5
|
module Scanner
|
|
3
6
|
include Helpers::Terminal
|
|
7
|
+
include Helpers::Text
|
|
4
8
|
extend self
|
|
5
9
|
|
|
6
|
-
def scan(options)
|
|
7
|
-
fetch_repositories(options)
|
|
8
|
-
.fmap { |repositories| filter_repositories_with_eol_products(repositories,
|
|
9
|
-
.fmap { |repositories| output_report(repositories,
|
|
10
|
+
def scan(product, options)
|
|
11
|
+
fetch_repositories(product, options)
|
|
12
|
+
.fmap { |repositories| filter_repositories_with_eol_products(repositories, product, options[:max_eol_date]) }
|
|
13
|
+
.fmap { |repositories| output_report(repositories, product, options[:max_eol_date]) }
|
|
10
14
|
.or { |error| abort "\n#{error_msg(error)}" }
|
|
11
15
|
end
|
|
12
16
|
|
|
13
17
|
private
|
|
14
18
|
|
|
15
|
-
def fetch_repositories(options)
|
|
16
|
-
with_loading_spinner("Searching repositories
|
|
17
|
-
result = Repository.search(options)
|
|
19
|
+
def fetch_repositories(product, options)
|
|
20
|
+
with_loading_spinner("Searching repositories that might use #{product.label}...") do |spinner|
|
|
21
|
+
result = Repository.search(options.merge(product:))
|
|
18
22
|
spinner.error if result.failure?
|
|
19
23
|
|
|
20
24
|
result
|
|
21
25
|
end
|
|
22
26
|
end
|
|
23
27
|
|
|
24
|
-
def filter_repositories_with_eol_products(repositories, product
|
|
25
|
-
|
|
28
|
+
def filter_repositories_with_eol_products(repositories, product, max_eol_date)
|
|
29
|
+
return [] if repositories.empty?
|
|
30
|
+
|
|
31
|
+
with_loading_spinner("Scanning #{pluralize(repositories.size, "repository", "repositories")} for EOL #{product.label}...") do
|
|
26
32
|
Sync do
|
|
27
33
|
repositories
|
|
28
34
|
.map { |repo| Async { [repo, repo.using_eol?(product, at: max_eol_date)] } }.map(&:wait)
|
|
@@ -31,7 +37,7 @@ module EndOfLife
|
|
|
31
37
|
end
|
|
32
38
|
end
|
|
33
39
|
|
|
34
|
-
def output_report(repositories, product
|
|
40
|
+
def output_report(repositories, product, max_eol_date)
|
|
35
41
|
report = Report.new(product, repositories, max_eol_date)
|
|
36
42
|
puts report
|
|
37
43
|
|
data/lib/end_of_life/version.rb
CHANGED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require "bundler"
|
|
2
|
+
|
|
3
|
+
module EndOfLife
|
|
4
|
+
module VersionDetectors
|
|
5
|
+
module Nodejs
|
|
6
|
+
extend VersionDetector
|
|
7
|
+
|
|
8
|
+
detects_from ".node-version", ".nvmrc" do |file_content|
|
|
9
|
+
string_version = Gem::Version.new(file_content.strip.delete_prefix("v"))
|
|
10
|
+
|
|
11
|
+
Product::Release.new(product: "nodejs", version: string_version)
|
|
12
|
+
rescue ArgumentError
|
|
13
|
+
nil
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
detects_from ".tool-versions" do |file_content|
|
|
17
|
+
tool_versions = Parsers::ToolVersions.parse(file_content)
|
|
18
|
+
version = tool_versions["nodejs"] or next
|
|
19
|
+
|
|
20
|
+
Product::Release.new(product: "nodejs", version:)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
detects_from "mise.toml" do |file_content|
|
|
24
|
+
tools = Parsers::MiseToml.parse(file_content) or next
|
|
25
|
+
version = tools["node"] or next
|
|
26
|
+
|
|
27
|
+
Product::Release.new(product: "nodejs", version:)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -30,6 +30,13 @@ module EndOfLife
|
|
|
30
30
|
|
|
31
31
|
Product::Release.ruby(ruby_version)
|
|
32
32
|
end
|
|
33
|
+
|
|
34
|
+
detects_from "mise.toml" do |file_content|
|
|
35
|
+
tools = Parsers::MiseToml.parse(file_content) or next
|
|
36
|
+
ruby_version = tools["ruby"] or next
|
|
37
|
+
|
|
38
|
+
Product::Release.ruby(ruby_version)
|
|
39
|
+
end
|
|
33
40
|
end
|
|
34
41
|
end
|
|
35
42
|
end
|
data/lib/end_of_life.rb
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "async"
|
|
4
|
-
require "dry-monads"
|
|
5
|
-
require "json"
|
|
6
|
-
require "base64"
|
|
7
|
-
require "octokit"
|
|
8
3
|
require "zeitwerk"
|
|
9
4
|
|
|
10
5
|
Zeitwerk::Loader.for_gem.tap { |it|
|
|
@@ -15,6 +10,7 @@ module EndOfLife
|
|
|
15
10
|
extend Product::Registry
|
|
16
11
|
extend Helpers::Terminal
|
|
17
12
|
|
|
18
|
-
scans_for :ruby
|
|
19
|
-
scans_for :rails
|
|
13
|
+
scans_for :ruby
|
|
14
|
+
scans_for :rails
|
|
15
|
+
scans_for :nodejs, label: "Node.js"
|
|
20
16
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,29 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: end_of_life
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 1.0.0.alpha
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Matheus Richard
|
|
8
|
+
autorequire:
|
|
8
9
|
bindir: exe
|
|
9
10
|
cert_chain: []
|
|
10
|
-
date:
|
|
11
|
+
date: 2025-10-24 00:00:00.000000000 Z
|
|
11
12
|
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: argument_parser
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: 0.1.0
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: 0.1.0
|
|
12
27
|
- !ruby/object:Gem::Dependency
|
|
13
28
|
name: async
|
|
14
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -23,13 +38,27 @@ dependencies:
|
|
|
23
38
|
- - ">="
|
|
24
39
|
- !ruby/object:Gem::Version
|
|
25
40
|
version: '0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: base64
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
26
55
|
- !ruby/object:Gem::Dependency
|
|
27
56
|
name: bundler
|
|
28
57
|
requirement: !ruby/object:Gem::Requirement
|
|
29
58
|
requirements:
|
|
30
59
|
- - ">="
|
|
31
60
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: 2.
|
|
61
|
+
version: 2.7.2
|
|
33
62
|
- - "<"
|
|
34
63
|
- !ruby/object:Gem::Version
|
|
35
64
|
version: '3'
|
|
@@ -39,7 +68,7 @@ dependencies:
|
|
|
39
68
|
requirements:
|
|
40
69
|
- - ">="
|
|
41
70
|
- !ruby/object:Gem::Version
|
|
42
|
-
version: 2.
|
|
71
|
+
version: 2.7.2
|
|
43
72
|
- - "<"
|
|
44
73
|
- !ruby/object:Gem::Version
|
|
45
74
|
version: '3'
|
|
@@ -57,6 +86,20 @@ dependencies:
|
|
|
57
86
|
- - "~>"
|
|
58
87
|
- !ruby/object:Gem::Version
|
|
59
88
|
version: '1.3'
|
|
89
|
+
- !ruby/object:Gem::Dependency
|
|
90
|
+
name: perfect_toml
|
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - "~>"
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: 0.9.0
|
|
96
|
+
type: :runtime
|
|
97
|
+
prerelease: false
|
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - "~>"
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: 0.9.0
|
|
60
103
|
- !ruby/object:Gem::Dependency
|
|
61
104
|
name: octokit
|
|
62
105
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -71,6 +114,20 @@ dependencies:
|
|
|
71
114
|
- - "~>"
|
|
72
115
|
- !ruby/object:Gem::Version
|
|
73
116
|
version: '9.0'
|
|
117
|
+
- !ruby/object:Gem::Dependency
|
|
118
|
+
name: faraday-retry
|
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
|
120
|
+
requirements:
|
|
121
|
+
- - "~>"
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: '2.0'
|
|
124
|
+
type: :runtime
|
|
125
|
+
prerelease: false
|
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
127
|
+
requirements:
|
|
128
|
+
- - "~>"
|
|
129
|
+
- !ruby/object:Gem::Version
|
|
130
|
+
version: '2.0'
|
|
74
131
|
- !ruby/object:Gem::Dependency
|
|
75
132
|
name: pastel
|
|
76
133
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -139,7 +196,7 @@ extensions: []
|
|
|
139
196
|
extra_rdoc_files: []
|
|
140
197
|
files:
|
|
141
198
|
- ".rspec"
|
|
142
|
-
- ".
|
|
199
|
+
- ".standard.yml"
|
|
143
200
|
- CHANGELOG.md
|
|
144
201
|
- Gemfile
|
|
145
202
|
- Gemfile.lock
|
|
@@ -147,6 +204,7 @@ files:
|
|
|
147
204
|
- README.md
|
|
148
205
|
- Rakefile
|
|
149
206
|
- bin/console
|
|
207
|
+
- bin/end_of_life
|
|
150
208
|
- bin/setup
|
|
151
209
|
- demo.gif
|
|
152
210
|
- end_of_life.gemspec
|
|
@@ -154,26 +212,31 @@ files:
|
|
|
154
212
|
- exe/eol
|
|
155
213
|
- lib/end_of_life.rb
|
|
156
214
|
- lib/end_of_life/api.rb
|
|
215
|
+
- lib/end_of_life/check.rb
|
|
157
216
|
- lib/end_of_life/cli.rb
|
|
217
|
+
- lib/end_of_life/cli/command/registry.rb
|
|
158
218
|
- lib/end_of_life/helpers/silent_bundler.rb
|
|
159
219
|
- lib/end_of_life/helpers/terminal.rb
|
|
220
|
+
- lib/end_of_life/helpers/text.rb
|
|
221
|
+
- lib/end_of_life/helpers/time.rb
|
|
160
222
|
- lib/end_of_life/in_memory_file.rb
|
|
161
|
-
- lib/end_of_life/options.rb
|
|
162
223
|
- lib/end_of_life/parsers/gemfile.rb
|
|
163
224
|
- lib/end_of_life/parsers/gemfile_lock.rb
|
|
225
|
+
- lib/end_of_life/parsers/mise_toml.rb
|
|
164
226
|
- lib/end_of_life/parsers/ruby_version.rb
|
|
165
227
|
- lib/end_of_life/parsers/tool_versions.rb
|
|
166
228
|
- lib/end_of_life/product.rb
|
|
167
229
|
- lib/end_of_life/product/registry.rb
|
|
168
230
|
- lib/end_of_life/product/release.rb
|
|
169
|
-
- lib/end_of_life/report.rb
|
|
170
231
|
- lib/end_of_life/repository.rb
|
|
171
232
|
- lib/end_of_life/repository/search.rb
|
|
172
233
|
- lib/end_of_life/repository/search/query.rb
|
|
173
234
|
- lib/end_of_life/scanner.rb
|
|
235
|
+
- lib/end_of_life/scanner/report.rb
|
|
174
236
|
- lib/end_of_life/version.rb
|
|
175
237
|
- lib/end_of_life/version_detector.rb
|
|
176
238
|
- lib/end_of_life/version_detectors.rb
|
|
239
|
+
- lib/end_of_life/version_detectors/nodejs.rb
|
|
177
240
|
- lib/end_of_life/version_detectors/rails.rb
|
|
178
241
|
- lib/end_of_life/version_detectors/ruby.rb
|
|
179
242
|
homepage: https://github.com/MatheusRich/end_of_life
|
|
@@ -183,6 +246,7 @@ metadata:
|
|
|
183
246
|
homepage_uri: https://github.com/MatheusRich/end_of_life
|
|
184
247
|
source_code_uri: https://github.com/MatheusRich/end_of_life
|
|
185
248
|
changelog_uri: https://github.com/MatheusRich/end_of_life/blob/main/CHANGELOG.md
|
|
249
|
+
post_install_message:
|
|
186
250
|
rdoc_options: []
|
|
187
251
|
require_paths:
|
|
188
252
|
- lib
|
|
@@ -193,11 +257,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
193
257
|
version: 3.2.0
|
|
194
258
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
195
259
|
requirements:
|
|
196
|
-
- - "
|
|
260
|
+
- - ">"
|
|
197
261
|
- !ruby/object:Gem::Version
|
|
198
|
-
version:
|
|
262
|
+
version: 1.3.1
|
|
199
263
|
requirements: []
|
|
200
|
-
rubygems_version: 3.
|
|
264
|
+
rubygems_version: 3.4.19
|
|
265
|
+
signing_key:
|
|
201
266
|
specification_version: 4
|
|
202
267
|
summary: Lists repositories using end-of-life software
|
|
203
268
|
test_files: []
|
data/.tool-versions
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
ruby 3.4.5
|
data/lib/end_of_life/options.rb
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
require "optparse"
|
|
2
|
-
|
|
3
|
-
module EndOfLife
|
|
4
|
-
module Options
|
|
5
|
-
def self.from(argv)
|
|
6
|
-
options = {product: Product.find("ruby"), max_eol_date: Date.today, skip_archived: true}
|
|
7
|
-
OptionParser.new do |parser|
|
|
8
|
-
options[:parser] = parser
|
|
9
|
-
|
|
10
|
-
parser.banner = "Usage: end_of_life [options]"
|
|
11
|
-
|
|
12
|
-
product_names = EndOfLife.products.map(&:name)
|
|
13
|
-
parser.on("-p NAME", "--product NAME", /#{product_names.join("|")}/i, "Sets the product to scan for (default: ruby). Supported products are: #{product_names.join(", ")}.") do |name|
|
|
14
|
-
options[:product] = Product.find(name)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
parser.on("--exclude=NAME,NAME2", Array, "Exclude repositories containing a certain word in its name. You can specify up to five words.") do |excludes|
|
|
18
|
-
options[:excludes] = excludes.first(5)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
parser.on("--public-only", "Searches only public repositories") do
|
|
22
|
-
options[:visibility] = :public
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
parser.on("--private-only", "Searches only private repositories") do
|
|
26
|
-
options[:visibility] = :private
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
parser.on("--repo=USER/REPO", "--repository=USER/REPO", "Searches a specific repository") do |repository|
|
|
30
|
-
options[:repository] = repository
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
parser.on("--org=ORG,ORG2...", "--organization=ORG,ORG2", Array, "Searches within specific organizations") do |organizations|
|
|
34
|
-
options[:organizations] = organizations
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
parser.on("-u NAME", "--user=NAME", "Sets the user used on the repository search") do |user|
|
|
38
|
-
options[:user] = user
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
parser.on("--max-eol-days-away NUMBER", "Sets the maximum number of days away a version can be from EOL. It defaults to 0.") do |days|
|
|
42
|
-
options[:max_eol_date] = Date.today + days.to_i.abs
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
parser.on("--include-archived", "Includes archived repositories on the search") do
|
|
46
|
-
options[:skip_archived] = false
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
parser.on("-v", "--version", "Displays end_of_life version") do
|
|
50
|
-
options[:command] = :version
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
parser.on("-h", "--help", "Displays this help") do
|
|
54
|
-
options[:command] = :help
|
|
55
|
-
end
|
|
56
|
-
end.parse!(argv)
|
|
57
|
-
|
|
58
|
-
options
|
|
59
|
-
rescue OptionParser::ParseError => e
|
|
60
|
-
{command: :print_error, error: e}
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
end
|
data/lib/end_of_life/report.rb
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
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
|