end_of_life 0.3.0 → 0.4.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 +22 -1
- data/Gemfile +4 -4
- data/Gemfile.lock +116 -91
- data/README.md +5 -4
- data/end_of_life.gemspec +3 -2
- data/lib/end_of_life/cli.rb +80 -0
- data/lib/end_of_life/options.rb +8 -4
- data/lib/end_of_life/repository.rb +20 -11
- data/lib/end_of_life/ruby_version/parser.rb +12 -4
- data/lib/end_of_life/ruby_version.rb +5 -1
- data/lib/end_of_life/version.rb +1 -1
- data/lib/end_of_life.json +96 -11
- data/lib/end_of_life.rb +3 -74
- metadata +21 -10
- data/.standard.yml +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b8e0689d1cdf6da1fa737f8d699a060a8544184dfb345d6af4093e6e5e000c13
|
4
|
+
data.tar.gz: 608169452246f72b9351b07ae4f243d4ce74c3416c451a5fdf600b97dbc3f529
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 57c0401637ca7d60d59d27ab35f4bee948f09bf188df6189a41be14ceb906c50ee77059a550076122f14a3b118c9e6fdd2f10dd520d19b562670c8fe229cf5df
|
7
|
+
data.tar.gz: 8cf1db7f6007559d3066696e1f3820fdaae1b055654456d47d48d67b6828530315992aae95ac9ea2ecf3927b3a39b80f84df7a762d24cc6c4f073bc2956d648e
|
data/.tool-versions
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby 3.
|
1
|
+
ruby 3.4.2
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,24 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.4.1] - 2025-05-23
|
4
|
+
|
5
|
+
- [BUGFIX] Handle empty/invalid version files
|
6
|
+
- if a file like `.ruby-version` was empty, we would parse it it's version as
|
7
|
+
`0` which would take precedence over any other file when comparing versions.
|
8
|
+
- We now ignore those files and any file which version parses to `0`.
|
9
|
+
|
10
|
+
## [0.4.0] - 2025-05-23
|
11
|
+
|
12
|
+
- Skip archived repos (by default)
|
13
|
+
|
14
|
+
It's possible to include them with the `--include-archived` flag.
|
15
|
+
|
16
|
+
- Sort repositories by most recently updated
|
17
|
+
|
18
|
+
These are likely the ones one cares more about.
|
19
|
+
|
20
|
+
- Require Ruby >= 3.2.0
|
21
|
+
|
3
22
|
## [0.3.0]
|
4
23
|
|
5
24
|
### Added
|
@@ -142,7 +161,9 @@ $ end_of_life --user=matz # searches on matz's repositories
|
|
142
161
|
|
143
162
|
- Initial release
|
144
163
|
|
145
|
-
[unreleased]: https://github.com/MatheusRich/end_of_life/compare/v0.
|
164
|
+
[unreleased]: https://github.com/MatheusRich/end_of_life/compare/v0.4.1...HEAD
|
165
|
+
[0.4.1]: https://github.com/MatheusRich/end_of_life/releases/tag/v0.4.1
|
166
|
+
[0.4.0]: https://github.com/MatheusRich/end_of_life/releases/tag/v0.4.0
|
146
167
|
[0.3.0]: https://github.com/MatheusRich/end_of_life/releases/tag/v0.3.0
|
147
168
|
[0.2.0]: https://github.com/MatheusRich/end_of_life/releases/tag/v0.2.0
|
148
169
|
[0.1.0]: https://github.com/MatheusRich/end_of_life/releases/tag/v0.1.0
|
data/Gemfile
CHANGED
@@ -5,11 +5,11 @@ source "https://rubygems.org"
|
|
5
5
|
# Specify your gem's dependencies in end_of_life.gemspec
|
6
6
|
gemspec
|
7
7
|
|
8
|
-
gem "climate_control", "~> 1.0
|
8
|
+
gem "climate_control", "~> 1.0"
|
9
9
|
gem "rake", "~> 13.0"
|
10
10
|
gem "rspec", "~> 3.10"
|
11
11
|
gem "rspec-mocks", "~> 3.10"
|
12
|
-
gem "simplecov", "~> 0.
|
13
|
-
gem "standard", "~> 1.
|
14
|
-
gem "vcr", "~> 6.0
|
12
|
+
gem "simplecov", "~> 0.22.0"
|
13
|
+
gem "standard", "~> 1.26"
|
14
|
+
gem "vcr", "~> 6.0"
|
15
15
|
gem "webmock", "~> 3.13"
|
data/Gemfile.lock
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
end_of_life (0.
|
4
|
+
end_of_life (0.4.1)
|
5
|
+
async
|
5
6
|
dry-monads (~> 1.3)
|
6
|
-
octokit (~>
|
7
|
+
octokit (~> 9.0)
|
7
8
|
pastel (~> 0.8.0)
|
8
9
|
tty-spinner (~> 0.9.0)
|
9
10
|
tty-table (~> 0.12.0)
|
@@ -11,135 +12,159 @@ PATH
|
|
11
12
|
GEM
|
12
13
|
remote: https://rubygems.org/
|
13
14
|
specs:
|
14
|
-
addressable (2.8.
|
15
|
-
public_suffix (>= 2.0.2, <
|
15
|
+
addressable (2.8.7)
|
16
|
+
public_suffix (>= 2.0.2, < 7.0)
|
16
17
|
ast (2.4.2)
|
17
|
-
|
18
|
-
|
19
|
-
|
18
|
+
async (2.24.0)
|
19
|
+
console (~> 1.29)
|
20
|
+
fiber-annotation
|
21
|
+
io-event (~> 1.9)
|
22
|
+
metrics (~> 0.12)
|
23
|
+
traces (~> 0.15)
|
24
|
+
base64 (0.2.0)
|
25
|
+
bigdecimal (3.1.9)
|
26
|
+
climate_control (1.2.0)
|
27
|
+
concurrent-ruby (1.3.5)
|
28
|
+
console (1.30.2)
|
29
|
+
fiber-annotation
|
30
|
+
fiber-local (~> 1.1)
|
31
|
+
json
|
32
|
+
crack (1.0.0)
|
33
|
+
bigdecimal
|
20
34
|
rexml
|
21
|
-
diff-lcs (1.
|
22
|
-
docile (1.4.
|
23
|
-
dry-core (
|
35
|
+
diff-lcs (1.5.1)
|
36
|
+
docile (1.4.1)
|
37
|
+
dry-core (1.1.0)
|
24
38
|
concurrent-ruby (~> 1.0)
|
25
|
-
|
39
|
+
logger
|
40
|
+
zeitwerk (~> 2.6)
|
41
|
+
dry-monads (1.8.3)
|
26
42
|
concurrent-ruby (~> 1.0)
|
27
|
-
dry-core (~>
|
28
|
-
|
29
|
-
|
30
|
-
faraday-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
octokit (4.22.0)
|
54
|
-
faraday (>= 0.9)
|
55
|
-
sawyer (~> 0.8.0, >= 0.5.3)
|
56
|
-
parallel (1.21.0)
|
57
|
-
parser (3.1.0.0)
|
43
|
+
dry-core (~> 1.1)
|
44
|
+
zeitwerk (~> 2.6)
|
45
|
+
faraday (2.13.1)
|
46
|
+
faraday-net_http (>= 2.0, < 3.5)
|
47
|
+
json
|
48
|
+
logger
|
49
|
+
faraday-net_http (3.4.0)
|
50
|
+
net-http (>= 0.5.0)
|
51
|
+
fiber-annotation (0.2.0)
|
52
|
+
fiber-local (1.1.0)
|
53
|
+
fiber-storage
|
54
|
+
fiber-storage (1.0.1)
|
55
|
+
hashdiff (1.1.2)
|
56
|
+
io-event (1.10.1)
|
57
|
+
json (2.9.1)
|
58
|
+
language_server-protocol (3.17.0.3)
|
59
|
+
lint_roller (1.1.0)
|
60
|
+
logger (1.7.0)
|
61
|
+
metrics (0.12.2)
|
62
|
+
net-http (0.6.0)
|
63
|
+
uri
|
64
|
+
octokit (9.2.0)
|
65
|
+
faraday (>= 1, < 3)
|
66
|
+
sawyer (~> 0.9)
|
67
|
+
parallel (1.26.3)
|
68
|
+
parser (3.3.6.0)
|
58
69
|
ast (~> 2.4.1)
|
70
|
+
racc
|
59
71
|
pastel (0.8.0)
|
60
72
|
tty-color (~> 0.5)
|
61
|
-
public_suffix (
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
rspec-
|
69
|
-
rspec-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
+
public_suffix (6.0.1)
|
74
|
+
racc (1.8.1)
|
75
|
+
rainbow (3.1.1)
|
76
|
+
rake (13.2.1)
|
77
|
+
regexp_parser (2.10.0)
|
78
|
+
rexml (3.4.0)
|
79
|
+
rspec (3.13.0)
|
80
|
+
rspec-core (~> 3.13.0)
|
81
|
+
rspec-expectations (~> 3.13.0)
|
82
|
+
rspec-mocks (~> 3.13.0)
|
83
|
+
rspec-core (3.13.2)
|
84
|
+
rspec-support (~> 3.13.0)
|
85
|
+
rspec-expectations (3.13.3)
|
73
86
|
diff-lcs (>= 1.2.0, < 2.0)
|
74
|
-
rspec-support (~> 3.
|
75
|
-
rspec-mocks (3.
|
87
|
+
rspec-support (~> 3.13.0)
|
88
|
+
rspec-mocks (3.13.2)
|
76
89
|
diff-lcs (>= 1.2.0, < 2.0)
|
77
|
-
rspec-support (~> 3.
|
78
|
-
rspec-support (3.
|
79
|
-
rubocop (1.
|
90
|
+
rspec-support (~> 3.13.0)
|
91
|
+
rspec-support (3.13.2)
|
92
|
+
rubocop (1.69.2)
|
93
|
+
json (~> 2.3)
|
94
|
+
language_server-protocol (>= 3.17.0)
|
80
95
|
parallel (~> 1.10)
|
81
|
-
parser (>= 3.
|
96
|
+
parser (>= 3.3.0.2)
|
82
97
|
rainbow (>= 2.2.2, < 4.0)
|
83
|
-
regexp_parser (>=
|
84
|
-
|
85
|
-
rubocop-ast (>= 1.15.1, < 2.0)
|
98
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
99
|
+
rubocop-ast (>= 1.36.2, < 2.0)
|
86
100
|
ruby-progressbar (~> 1.7)
|
87
|
-
unicode-display_width (>=
|
88
|
-
rubocop-ast (1.
|
89
|
-
parser (>= 3.
|
90
|
-
rubocop-performance (1.
|
91
|
-
rubocop (>= 1.
|
92
|
-
rubocop-ast (>=
|
93
|
-
ruby-progressbar (1.
|
94
|
-
|
95
|
-
sawyer (0.8.2)
|
101
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
102
|
+
rubocop-ast (1.37.0)
|
103
|
+
parser (>= 3.3.1.0)
|
104
|
+
rubocop-performance (1.23.0)
|
105
|
+
rubocop (>= 1.48.1, < 2.0)
|
106
|
+
rubocop-ast (>= 1.31.1, < 2.0)
|
107
|
+
ruby-progressbar (1.13.0)
|
108
|
+
sawyer (0.9.2)
|
96
109
|
addressable (>= 2.3.5)
|
97
|
-
faraday (
|
98
|
-
simplecov (0.
|
110
|
+
faraday (>= 0.17.3, < 3)
|
111
|
+
simplecov (0.22.0)
|
99
112
|
docile (~> 1.1)
|
100
113
|
simplecov-html (~> 0.11)
|
101
114
|
simplecov_json_formatter (~> 0.1)
|
102
|
-
simplecov-html (0.
|
103
|
-
simplecov_json_formatter (0.1.
|
104
|
-
standard (1.
|
105
|
-
|
106
|
-
|
115
|
+
simplecov-html (0.13.1)
|
116
|
+
simplecov_json_formatter (0.1.4)
|
117
|
+
standard (1.43.0)
|
118
|
+
language_server-protocol (~> 3.17.0.2)
|
119
|
+
lint_roller (~> 1.0)
|
120
|
+
rubocop (~> 1.69.1)
|
121
|
+
standard-custom (~> 1.0.0)
|
122
|
+
standard-performance (~> 1.6)
|
123
|
+
standard-custom (1.0.2)
|
124
|
+
lint_roller (~> 1.0)
|
125
|
+
rubocop (~> 1.50)
|
126
|
+
standard-performance (1.6.0)
|
127
|
+
lint_roller (~> 1.1)
|
128
|
+
rubocop-performance (~> 1.23.0)
|
107
129
|
strings (0.2.1)
|
108
130
|
strings-ansi (~> 0.2)
|
109
131
|
unicode-display_width (>= 1.5, < 3.0)
|
110
132
|
unicode_utils (~> 1.4)
|
111
133
|
strings-ansi (0.2.0)
|
134
|
+
traces (0.15.2)
|
112
135
|
tty-color (0.6.0)
|
113
136
|
tty-cursor (0.7.1)
|
114
|
-
tty-screen (0.8.
|
137
|
+
tty-screen (0.8.2)
|
115
138
|
tty-spinner (0.9.3)
|
116
139
|
tty-cursor (~> 0.7)
|
117
140
|
tty-table (0.12.0)
|
118
141
|
pastel (~> 0.8)
|
119
142
|
strings (~> 0.2.0)
|
120
143
|
tty-screen (~> 0.8)
|
121
|
-
unicode-display_width (2.
|
144
|
+
unicode-display_width (2.6.0)
|
122
145
|
unicode_utils (1.4.0)
|
123
|
-
|
124
|
-
|
125
|
-
|
146
|
+
uri (1.0.3)
|
147
|
+
vcr (6.3.1)
|
148
|
+
base64
|
149
|
+
webmock (3.24.0)
|
150
|
+
addressable (>= 2.8.0)
|
126
151
|
crack (>= 0.3.2)
|
127
152
|
hashdiff (>= 0.4.0, < 2.0.0)
|
153
|
+
zeitwerk (2.7.3)
|
128
154
|
|
129
155
|
PLATFORMS
|
130
|
-
|
131
|
-
x86_64-linux
|
156
|
+
ruby
|
132
157
|
|
133
158
|
DEPENDENCIES
|
134
|
-
climate_control (~> 1.0
|
159
|
+
climate_control (~> 1.0)
|
135
160
|
end_of_life!
|
136
161
|
rake (~> 13.0)
|
137
162
|
rspec (~> 3.10)
|
138
163
|
rspec-mocks (~> 3.10)
|
139
|
-
simplecov (~> 0.
|
140
|
-
standard (~> 1.
|
141
|
-
vcr (~> 6.0
|
164
|
+
simplecov (~> 0.22.0)
|
165
|
+
standard (~> 1.26)
|
166
|
+
vcr (~> 6.0)
|
142
167
|
webmock (~> 3.13)
|
143
168
|
|
144
169
|
BUNDLED WITH
|
145
|
-
2.3.
|
170
|
+
2.3.9
|
data/README.md
CHANGED
@@ -25,7 +25,7 @@ $ GITHUB_TOKEN=something end_of_life # if your platform supports symlinks, you c
|
|
25
25
|
[✔] Fetching repositories...
|
26
26
|
[✔] Searching for EOL Ruby in repositories...
|
27
27
|
|
28
|
-
Found 2 repositories using EOL Ruby (<= 2.
|
28
|
+
Found 2 repositories using EOL Ruby (<= 2.7.8):
|
29
29
|
┌───┬──────────────────────────────────────────────┬──────────────┐
|
30
30
|
│ │ Repository │ Ruby version │
|
31
31
|
├───┼──────────────────────────────────────────────┼──────────────┤
|
@@ -41,12 +41,13 @@ There are some options to help you filter down the results:
|
|
41
41
|
```
|
42
42
|
Usage: end_of_life [options]
|
43
43
|
--exclude=NAME,NAME2 Exclude repositories containing a certain word in its name. You can specify up to five words.
|
44
|
-
--public-only Searches only public
|
45
|
-
--private-only Searches only private
|
46
|
-
--repo, --repository=USER/REPO Searches a specific
|
44
|
+
--public-only Searches only public repositories
|
45
|
+
--private-only Searches only private repositories
|
46
|
+
--repo, --repository=USER/REPO Searches a specific repository
|
47
47
|
--org, --organization=ORG,ORG2 Searches within specific organizations
|
48
48
|
-u, --user=NAME Sets the user used on the repository search
|
49
49
|
--max-eol-days-away NUMBER Sets the maximum number of days away a version can be from EOL. It defaults to 0.
|
50
|
+
--include-archived Includes archived repositories on the search
|
50
51
|
-v, --version Displays end_of_life version
|
51
52
|
-h, --help Displays this help
|
52
53
|
```
|
data/end_of_life.gemspec
CHANGED
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
|
|
13
13
|
"unmaintained, Ruby versions."
|
14
14
|
spec.homepage = "https://github.com/MatheusRich/end_of_life"
|
15
15
|
spec.license = "MIT"
|
16
|
-
spec.required_ruby_version = ">= 2.
|
16
|
+
spec.required_ruby_version = ">= 3.2.0"
|
17
17
|
|
18
18
|
# spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
|
19
19
|
|
@@ -32,8 +32,9 @@ Gem::Specification.new do |spec|
|
|
32
32
|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
33
33
|
spec.require_paths = ["lib"]
|
34
34
|
|
35
|
+
spec.add_dependency "async"
|
35
36
|
spec.add_dependency "dry-monads", "~> 1.3"
|
36
|
-
spec.add_dependency "octokit", "~>
|
37
|
+
spec.add_dependency "octokit", "~> 9.0"
|
37
38
|
spec.add_dependency "pastel", "~> 0.8.0"
|
38
39
|
spec.add_dependency "tty-spinner", "~> 0.9.0"
|
39
40
|
spec.add_dependency "tty-table", "~> 0.12.0"
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module EndOfLife
|
2
|
+
class CLI
|
3
|
+
include TerminalHelper
|
4
|
+
|
5
|
+
def call(argv)
|
6
|
+
parse_options(argv)
|
7
|
+
.then { |options| execute_command(options) }
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def execute_command(options)
|
13
|
+
case options[:command]
|
14
|
+
when :help
|
15
|
+
puts options[:parser]
|
16
|
+
when :version
|
17
|
+
puts "end_of_life v#{EndOfLife::VERSION}"
|
18
|
+
when :print_error
|
19
|
+
puts error_msg(options[:error])
|
20
|
+
exit(-1)
|
21
|
+
else
|
22
|
+
check_eol_ruby_on_repositories(options)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def check_eol_ruby_on_repositories(options)
|
27
|
+
fetch_repositories(options)
|
28
|
+
.fmap { |repositories| filter_repositories_with_end_of_life(repositories, max_eol_date: options[:max_eol_date]) }
|
29
|
+
.fmap { |repositories| print_diagnose_for(repositories, max_eol_date: options[:max_eol_date]) }
|
30
|
+
.or { |error| puts "\n#{error_msg(error)}" }
|
31
|
+
end
|
32
|
+
|
33
|
+
def parse_options(argv)
|
34
|
+
Options.from(argv)
|
35
|
+
end
|
36
|
+
|
37
|
+
def fetch_repositories(options)
|
38
|
+
with_loading_spinner("Fetching repositories...") do |spinner|
|
39
|
+
result = Repository.fetch(options)
|
40
|
+
|
41
|
+
spinner.error if result.failure?
|
42
|
+
|
43
|
+
result
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def filter_repositories_with_end_of_life(repositories, max_eol_date:)
|
48
|
+
with_loading_spinner("Searching for EOL Ruby in repositories...") do
|
49
|
+
Sync do
|
50
|
+
repositories
|
51
|
+
.tap { |repos| repos.map { |repo| Async { repo.ruby_version } }.map(&:wait) }
|
52
|
+
.filter { |repo| repo.eol_ruby?(at: max_eol_date) }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def print_diagnose_for(repositories, max_eol_date:)
|
58
|
+
puts
|
59
|
+
|
60
|
+
if repositories.empty?
|
61
|
+
puts "No repositories using EOL Ruby."
|
62
|
+
return
|
63
|
+
end
|
64
|
+
|
65
|
+
word = (repositories.size == 1) ? "repository" : "repositories"
|
66
|
+
puts "Found #{repositories.size} #{word} using EOL Ruby (<= #{RubyVersion.latest_eol(at: max_eol_date)}):"
|
67
|
+
puts end_of_life_table(repositories)
|
68
|
+
exit(-1)
|
69
|
+
end
|
70
|
+
|
71
|
+
def end_of_life_table(repositories)
|
72
|
+
headers = ["", "Repository", "Ruby version"]
|
73
|
+
rows = repositories.map.with_index(1) do |repo, i|
|
74
|
+
[i, repo.url, repo.ruby_version]
|
75
|
+
end
|
76
|
+
|
77
|
+
table(headers, rows)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/end_of_life/options.rb
CHANGED
@@ -3,7 +3,7 @@ require "optparse"
|
|
3
3
|
module EndOfLife
|
4
4
|
module Options
|
5
5
|
def self.from(argv)
|
6
|
-
options = {max_eol_date: Date.today}
|
6
|
+
options = {max_eol_date: Date.today, skip_archived: true}
|
7
7
|
|
8
8
|
OptionParser.new do |opts|
|
9
9
|
options[:parser] = opts
|
@@ -14,15 +14,15 @@ module EndOfLife
|
|
14
14
|
options[:excludes] = excludes.first(5)
|
15
15
|
end
|
16
16
|
|
17
|
-
opts.on("--public-only", "Searches only public
|
17
|
+
opts.on("--public-only", "Searches only public repositories") do
|
18
18
|
options[:visibility] = :public
|
19
19
|
end
|
20
20
|
|
21
|
-
opts.on("--private-only", "Searches only private
|
21
|
+
opts.on("--private-only", "Searches only private repositories") do
|
22
22
|
options[:visibility] = :private
|
23
23
|
end
|
24
24
|
|
25
|
-
opts.on("--repo=USER/REPO", "--repository=USER/REPO", "Searches a specific
|
25
|
+
opts.on("--repo=USER/REPO", "--repository=USER/REPO", "Searches a specific repository") do |repository|
|
26
26
|
options[:repository] = repository
|
27
27
|
end
|
28
28
|
|
@@ -38,6 +38,10 @@ module EndOfLife
|
|
38
38
|
options[:max_eol_date] = Date.today + days.to_i.abs
|
39
39
|
end
|
40
40
|
|
41
|
+
opts.on("--include-archived", "Includes archived repositories on the search") do
|
42
|
+
options[:skip_archived] = false
|
43
|
+
end
|
44
|
+
|
41
45
|
opts.on("-v", "--version", "Displays end_of_life version") do
|
42
46
|
options[:command] = :version
|
43
47
|
end
|
@@ -9,10 +9,12 @@ module EndOfLife
|
|
9
9
|
options[:user] ||= github.user.login
|
10
10
|
|
11
11
|
query = search_query_for(options)
|
12
|
-
items = github.search_repositories(query).items
|
12
|
+
items = github.search_repositories(query, {sort: :updated}).items
|
13
13
|
|
14
14
|
Success(
|
15
|
-
items.
|
15
|
+
items.filter_map do |repo|
|
16
|
+
next if repo.archived && options[:skip_archived]
|
17
|
+
|
16
18
|
Repository.new(
|
17
19
|
full_name: repo.full_name,
|
18
20
|
url: repo.html_url,
|
@@ -56,7 +58,7 @@ module EndOfLife
|
|
56
58
|
end
|
57
59
|
end
|
58
60
|
|
59
|
-
|
61
|
+
attr_reader :full_name, :url
|
60
62
|
|
61
63
|
def initialize(full_name:, url:, github_client:)
|
62
64
|
@full_name = full_name
|
@@ -79,15 +81,22 @@ module EndOfLife
|
|
79
81
|
def ruby_versions
|
80
82
|
return @ruby_versions if defined?(@ruby_versions)
|
81
83
|
|
82
|
-
@ruby_versions =
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
fetch_file("Gemfile.lock"),
|
87
|
-
fetch_file(".tool-versions")
|
88
|
-
].compact
|
84
|
+
@ruby_versions = fetch_ruby_version_files.filter_map { |file|
|
85
|
+
parse_version_file(file)
|
86
|
+
}
|
87
|
+
end
|
89
88
|
|
90
|
-
|
89
|
+
POSSIBLE_RUBY_VERSION_FILES = [
|
90
|
+
".ruby-version",
|
91
|
+
"Gemfile.lock",
|
92
|
+
"Gemfile",
|
93
|
+
".tool-versions"
|
94
|
+
]
|
95
|
+
def fetch_ruby_version_files
|
96
|
+
Sync do
|
97
|
+
POSSIBLE_RUBY_VERSION_FILES
|
98
|
+
.map { |file_path| Async { fetch_file(file_path) } }
|
99
|
+
.filter_map(&:wait)
|
91
100
|
end
|
92
101
|
end
|
93
102
|
|
@@ -7,7 +7,9 @@ module EndOfLife
|
|
7
7
|
extend self
|
8
8
|
|
9
9
|
def parse_file(file_name:, content:)
|
10
|
-
if
|
10
|
+
return if content.strip.empty?
|
11
|
+
|
12
|
+
version = if file_name == ".ruby-version"
|
11
13
|
parse_ruby_version_file(content)
|
12
14
|
elsif file_name == "Gemfile.lock"
|
13
15
|
parse_gemfile_lock_file(content)
|
@@ -18,6 +20,14 @@ module EndOfLife
|
|
18
20
|
else
|
19
21
|
raise ArgumentError, "Unsupported file #{file_name}"
|
20
22
|
end
|
23
|
+
|
24
|
+
# Gem::Version is pretty forgiving and will accept empty strings
|
25
|
+
# as valid versions. This is a catch-all to ensure we don't return
|
26
|
+
# a version 0, which always takes precedence over any other version
|
27
|
+
# when comparing.
|
28
|
+
return if version&.zero?
|
29
|
+
|
30
|
+
version
|
21
31
|
end
|
22
32
|
|
23
33
|
private
|
@@ -38,11 +48,9 @@ module EndOfLife
|
|
38
48
|
end
|
39
49
|
|
40
50
|
def parse_gemfile_file(file_content)
|
41
|
-
return if file_content.empty?
|
42
|
-
|
43
51
|
with_temp_gemfile(file_content) do |temp_gemfile|
|
44
52
|
gemfile_version = temp_gemfile.ruby_version&.gem_version
|
45
|
-
return
|
53
|
+
return if gemfile_version.nil?
|
46
54
|
|
47
55
|
RubyVersion.new(gemfile_version)
|
48
56
|
end
|
@@ -6,6 +6,8 @@ module EndOfLife
|
|
6
6
|
class RubyVersion
|
7
7
|
include Comparable
|
8
8
|
|
9
|
+
ZERO = Gem::Version.new("0")
|
10
|
+
|
9
11
|
class << self
|
10
12
|
include Dry::Monads[:try]
|
11
13
|
|
@@ -41,7 +43,7 @@ module EndOfLife
|
|
41
43
|
end
|
42
44
|
end
|
43
45
|
|
44
|
-
|
46
|
+
attr_reader :version, :eol_date
|
45
47
|
|
46
48
|
def initialize(version_string, eol_date: nil)
|
47
49
|
@version = Gem::Version.new(version_string)
|
@@ -58,6 +60,8 @@ module EndOfLife
|
|
58
60
|
@version <=> other.version
|
59
61
|
end
|
60
62
|
|
63
|
+
def zero? = @version == ZERO
|
64
|
+
|
61
65
|
def to_s
|
62
66
|
@version.to_s
|
63
67
|
end
|
data/lib/end_of_life/version.rb
CHANGED
data/lib/end_of_life.json
CHANGED
@@ -1,13 +1,98 @@
|
|
1
1
|
[
|
2
|
-
{
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
{
|
11
|
-
|
12
|
-
|
2
|
+
{
|
3
|
+
"cycle": "3.2",
|
4
|
+
"eol": "2026-03-31",
|
5
|
+
"latest": "3.2.2",
|
6
|
+
"latestReleaseDate": "2023-03-30",
|
7
|
+
"releaseDate": "2022-12-25",
|
8
|
+
"lts": false
|
9
|
+
},
|
10
|
+
{
|
11
|
+
"cycle": "3.1",
|
12
|
+
"eol": "2025-03-31",
|
13
|
+
"latest": "3.1.4",
|
14
|
+
"latestReleaseDate": "2023-03-30",
|
15
|
+
"releaseDate": "2021-12-25",
|
16
|
+
"lts": false
|
17
|
+
},
|
18
|
+
{
|
19
|
+
"cycle": "3.0",
|
20
|
+
"eol": "2024-03-31",
|
21
|
+
"latest": "3.0.6",
|
22
|
+
"latestReleaseDate": "2023-03-30",
|
23
|
+
"releaseDate": "2020-12-25",
|
24
|
+
"lts": false
|
25
|
+
},
|
26
|
+
{
|
27
|
+
"cycle": "2.7",
|
28
|
+
"eol": "2023-03-31",
|
29
|
+
"latest": "2.7.8",
|
30
|
+
"latestReleaseDate": "2023-03-30",
|
31
|
+
"releaseDate": "2019-12-25",
|
32
|
+
"lts": false
|
33
|
+
},
|
34
|
+
{
|
35
|
+
"cycle": "2.6",
|
36
|
+
"eol": "2022-03-31",
|
37
|
+
"latest": "2.6.10",
|
38
|
+
"latestReleaseDate": "2022-04-12",
|
39
|
+
"releaseDate": "2018-12-25",
|
40
|
+
"lts": false
|
41
|
+
},
|
42
|
+
{
|
43
|
+
"cycle": "2.5",
|
44
|
+
"eol": "2021-03-31",
|
45
|
+
"latest": "2.5.9",
|
46
|
+
"latestReleaseDate": "2021-04-05",
|
47
|
+
"releaseDate": "2017-12-25",
|
48
|
+
"lts": false
|
49
|
+
},
|
50
|
+
{
|
51
|
+
"cycle": "2.4",
|
52
|
+
"eol": "2020-03-31",
|
53
|
+
"latest": "2.4.10",
|
54
|
+
"latestReleaseDate": "2020-03-31",
|
55
|
+
"releaseDate": "2016-12-23",
|
56
|
+
"lts": false
|
57
|
+
},
|
58
|
+
{
|
59
|
+
"cycle": "2.3",
|
60
|
+
"eol": "2019-03-31",
|
61
|
+
"latest": "2.3.8",
|
62
|
+
"latestReleaseDate": "2018-10-17",
|
63
|
+
"releaseDate": "2015-12-24",
|
64
|
+
"lts": false
|
65
|
+
},
|
66
|
+
{
|
67
|
+
"cycle": "2.2",
|
68
|
+
"eol": "2018-03-31",
|
69
|
+
"latest": "2.2.10",
|
70
|
+
"latestReleaseDate": "2018-03-28",
|
71
|
+
"releaseDate": "2014-12-25",
|
72
|
+
"lts": false
|
73
|
+
},
|
74
|
+
{
|
75
|
+
"cycle": "2.1",
|
76
|
+
"eol": "2017-03-31",
|
77
|
+
"latest": "2.1.10",
|
78
|
+
"latestReleaseDate": "2016-03-31",
|
79
|
+
"releaseDate": "2013-12-25",
|
80
|
+
"lts": false
|
81
|
+
},
|
82
|
+
{
|
83
|
+
"cycle": "2.0.0",
|
84
|
+
"eol": "2016-02-24",
|
85
|
+
"latest": "2.0.0p648",
|
86
|
+
"latestReleaseDate": "2015-12-16",
|
87
|
+
"releaseDate": "2013-02-24",
|
88
|
+
"lts": false
|
89
|
+
},
|
90
|
+
{
|
91
|
+
"cycle": "1.9.3",
|
92
|
+
"eol": "2015-02-23",
|
93
|
+
"latest": "1.9.3p551",
|
94
|
+
"latestReleaseDate": "2014-11-13",
|
95
|
+
"releaseDate": "2011-10-30",
|
96
|
+
"lts": false
|
97
|
+
}
|
13
98
|
]
|
data/lib/end_of_life.rb
CHANGED
@@ -1,88 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "async"
|
3
4
|
require "dry-monads"
|
4
5
|
require "json"
|
6
|
+
require "base64"
|
5
7
|
require "octokit"
|
6
8
|
require_relative "end_of_life/options"
|
7
9
|
require_relative "end_of_life/repository"
|
8
10
|
require_relative "end_of_life/ruby_version"
|
9
11
|
require_relative "end_of_life/terminal_helper"
|
10
12
|
require_relative "end_of_life/version"
|
13
|
+
require_relative "end_of_life/cli"
|
11
14
|
|
12
15
|
module EndOfLife
|
13
16
|
extend TerminalHelper
|
14
|
-
|
15
|
-
class CLI
|
16
|
-
include TerminalHelper
|
17
|
-
|
18
|
-
def call(argv)
|
19
|
-
parse_options(argv)
|
20
|
-
.then { |options| execute_command(options) }
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
def execute_command(options)
|
26
|
-
case options[:command]
|
27
|
-
when :help
|
28
|
-
puts options[:parser]
|
29
|
-
when :version
|
30
|
-
puts "end_of_life v#{EndOfLife::VERSION}"
|
31
|
-
when :print_error
|
32
|
-
puts error_msg(options[:error])
|
33
|
-
exit(-1)
|
34
|
-
else
|
35
|
-
check_eol_ruby_on_repositories(options)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def check_eol_ruby_on_repositories(options)
|
40
|
-
fetch_repositories(options)
|
41
|
-
.fmap { |repositories| filter_repositories_with_end_of_life(repositories, max_eol_date: options[:max_eol_date]) }
|
42
|
-
.fmap { |repositories| print_diagnose_for(repositories, max_eol_date: options[:max_eol_date]) }
|
43
|
-
.or { |error| puts "\n#{error_msg(error)}" }
|
44
|
-
end
|
45
|
-
|
46
|
-
def parse_options(argv)
|
47
|
-
Options.from(argv)
|
48
|
-
end
|
49
|
-
|
50
|
-
def fetch_repositories(options)
|
51
|
-
with_loading_spinner("Fetching repositories...") do |spinner|
|
52
|
-
result = Repository.fetch(options)
|
53
|
-
|
54
|
-
spinner.error if result.failure?
|
55
|
-
|
56
|
-
result
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def filter_repositories_with_end_of_life(repositories, max_eol_date:)
|
61
|
-
with_loading_spinner("Searching for EOL Ruby in repositories...") do
|
62
|
-
repositories.filter { |repo| repo.eol_ruby?(at: max_eol_date) }
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def print_diagnose_for(repositories, max_eol_date:)
|
67
|
-
puts
|
68
|
-
|
69
|
-
if repositories.empty?
|
70
|
-
puts "No repositories using EOL Ruby."
|
71
|
-
return
|
72
|
-
end
|
73
|
-
|
74
|
-
puts "Found #{repositories.size} repositories using EOL Ruby (<= #{RubyVersion.latest_eol(at: max_eol_date)}):"
|
75
|
-
puts end_of_life_table(repositories)
|
76
|
-
exit(-1)
|
77
|
-
end
|
78
|
-
|
79
|
-
def end_of_life_table(repositories)
|
80
|
-
headers = ["", "Repository", "Ruby version"]
|
81
|
-
rows = repositories.map.with_index(1) do |repo, i|
|
82
|
-
[i, repo.url, repo.ruby_version]
|
83
|
-
end
|
84
|
-
|
85
|
-
table(headers, rows)
|
86
|
-
end
|
87
|
-
end
|
88
17
|
end
|
metadata
CHANGED
@@ -1,15 +1,28 @@
|
|
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.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matheus Richard
|
8
|
-
autorequire:
|
9
8
|
bindir: exe
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-05-23 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: async
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - ">="
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '0'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - ">="
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '0'
|
13
26
|
- !ruby/object:Gem::Dependency
|
14
27
|
name: dry-monads
|
15
28
|
requirement: !ruby/object:Gem::Requirement
|
@@ -30,14 +43,14 @@ dependencies:
|
|
30
43
|
requirements:
|
31
44
|
- - "~>"
|
32
45
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
46
|
+
version: '9.0'
|
34
47
|
type: :runtime
|
35
48
|
prerelease: false
|
36
49
|
version_requirements: !ruby/object:Gem::Requirement
|
37
50
|
requirements:
|
38
51
|
- - "~>"
|
39
52
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
53
|
+
version: '9.0'
|
41
54
|
- !ruby/object:Gem::Dependency
|
42
55
|
name: pastel
|
43
56
|
requirement: !ruby/object:Gem::Requirement
|
@@ -91,7 +104,6 @@ extensions: []
|
|
91
104
|
extra_rdoc_files: []
|
92
105
|
files:
|
93
106
|
- ".rspec"
|
94
|
-
- ".standard.yml"
|
95
107
|
- ".tool-versions"
|
96
108
|
- CHANGELOG.md
|
97
109
|
- Gemfile
|
@@ -107,6 +119,7 @@ files:
|
|
107
119
|
- exe/eol
|
108
120
|
- lib/end_of_life.json
|
109
121
|
- lib/end_of_life.rb
|
122
|
+
- lib/end_of_life/cli.rb
|
110
123
|
- lib/end_of_life/options.rb
|
111
124
|
- lib/end_of_life/repository.rb
|
112
125
|
- lib/end_of_life/ruby_version.rb
|
@@ -120,7 +133,6 @@ metadata:
|
|
120
133
|
homepage_uri: https://github.com/MatheusRich/end_of_life
|
121
134
|
source_code_uri: https://github.com/MatheusRich/end_of_life
|
122
135
|
changelog_uri: https://github.com/MatheusRich/end_of_life/blob/main/CHANGELOG.md
|
123
|
-
post_install_message:
|
124
136
|
rdoc_options: []
|
125
137
|
require_paths:
|
126
138
|
- lib
|
@@ -128,15 +140,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
128
140
|
requirements:
|
129
141
|
- - ">="
|
130
142
|
- !ruby/object:Gem::Version
|
131
|
-
version: 2.
|
143
|
+
version: 3.2.0
|
132
144
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
133
145
|
requirements:
|
134
146
|
- - ">="
|
135
147
|
- !ruby/object:Gem::Version
|
136
148
|
version: '0'
|
137
149
|
requirements: []
|
138
|
-
rubygems_version: 3.2
|
139
|
-
signing_key:
|
150
|
+
rubygems_version: 3.6.2
|
140
151
|
specification_version: 4
|
141
152
|
summary: Lists repositories using end-of-life Ruby versions.
|
142
153
|
test_files: []
|
data/.standard.yml
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
ruby_version: 2.7.1
|