end_of_life 0.4.0 → 0.5.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 +14 -1
- data/Gemfile +1 -1
- data/Gemfile.lock +43 -33
- data/README.md +26 -17
- data/end_of_life.gemspec +3 -2
- data/lib/end_of_life/api.rb +17 -0
- data/lib/end_of_life/cli.rb +7 -57
- 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 +14 -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 +38 -10
- data/.standard.yml +0 -1
- data/lib/end_of_life/ruby_version/parser.rb +0 -88
- data/lib/end_of_life/ruby_version.rb +0 -65
- data/lib/end_of_life.json +0 -98
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b96d774296476963033c1a52121ce717a47a3f20e6463294729b852eb9c9504
|
4
|
+
data.tar.gz: 63e2e455e67bae56b2dfe58a848785604f5d88662f317dc11e2e40e4783d4b4e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7ebbccd62beca6dfd89b4e91ecbaf14c043c7a65d6cb8818018834e439db6212ca62834b414614e1db57872d305e82af8219afdb7cfbdf1bf8c95571cf801be9
|
7
|
+
data.tar.gz: 4e9750c6f5e880db427baac01d8d06d1e08dd3afb666249ba19174315d1ae9b0f402e60848fa792bb562ff7fbcb7040a48a03efa2dda0a6344d8a68938edb553
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
- 🎉 Add support for scanning EOL Rails versions!
|
4
|
+
- Use the `--product=rails` option to scan for Rails instead of Ruby.
|
5
|
+
- End of Life looks for an exact Rails version on the `Gemfile` file or `Gemfile.lock`.
|
6
|
+
|
7
|
+
## [0.4.1] - 2025-05-23
|
8
|
+
|
9
|
+
- [BUGFIX] Handle empty/invalid version files
|
10
|
+
- if a file like `.ruby-version` was empty, we would parse it it's version as
|
11
|
+
`0` which would take precedence over any other file when comparing versions.
|
12
|
+
- We now ignore those files and any file which version parses to `0`.
|
13
|
+
|
3
14
|
## [0.4.0] - 2025-05-23
|
4
15
|
|
5
16
|
- Skip archived repos (by default)
|
@@ -154,7 +165,9 @@ $ end_of_life --user=matz # searches on matz's repositories
|
|
154
165
|
|
155
166
|
- Initial release
|
156
167
|
|
157
|
-
[unreleased]: https://github.com/MatheusRich/end_of_life/compare/v0.
|
168
|
+
[unreleased]: https://github.com/MatheusRich/end_of_life/compare/v0.4.1...HEAD
|
169
|
+
[0.4.1]: https://github.com/MatheusRich/end_of_life/releases/tag/v0.4.1
|
170
|
+
[0.4.0]: https://github.com/MatheusRich/end_of_life/releases/tag/v0.4.0
|
158
171
|
[0.3.0]: https://github.com/MatheusRich/end_of_life/releases/tag/v0.3.0
|
159
172
|
[0.2.0]: https://github.com/MatheusRich/end_of_life/releases/tag/v0.2.0
|
160
173
|
[0.1.0]: https://github.com/MatheusRich/end_of_life/releases/tag/v0.1.0
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,31 +1,43 @@
|
|
1
|
+
GIT
|
2
|
+
remote: https://github.com/testdouble/standard.git
|
3
|
+
revision: 2a0584ed57122065d0972fe5a55eb83aec150b54
|
4
|
+
specs:
|
5
|
+
standard (1.50.0)
|
6
|
+
language_server-protocol (~> 3.17.0.2)
|
7
|
+
lint_roller (~> 1.0)
|
8
|
+
rubocop (~> 1.75.5)
|
9
|
+
standard-custom (~> 1.0.0)
|
10
|
+
standard-performance (~> 1.8)
|
11
|
+
|
1
12
|
PATH
|
2
13
|
remote: .
|
3
14
|
specs:
|
4
|
-
end_of_life (0.
|
15
|
+
end_of_life (0.5.0)
|
5
16
|
async
|
6
17
|
dry-monads (~> 1.3)
|
7
18
|
octokit (~> 9.0)
|
8
19
|
pastel (~> 0.8.0)
|
9
20
|
tty-spinner (~> 0.9.0)
|
10
21
|
tty-table (~> 0.12.0)
|
22
|
+
zeitwerk (~> 2.7)
|
11
23
|
|
12
24
|
GEM
|
13
25
|
remote: https://rubygems.org/
|
14
26
|
specs:
|
15
27
|
addressable (2.8.7)
|
16
28
|
public_suffix (>= 2.0.2, < 7.0)
|
17
|
-
ast (2.4.
|
18
|
-
async (2.
|
29
|
+
ast (2.4.3)
|
30
|
+
async (2.30.0)
|
19
31
|
console (~> 1.29)
|
20
32
|
fiber-annotation
|
21
|
-
io-event (~> 1.
|
33
|
+
io-event (~> 1.11)
|
22
34
|
metrics (~> 0.12)
|
23
|
-
traces (~> 0.
|
35
|
+
traces (~> 0.18)
|
24
36
|
base64 (0.2.0)
|
25
37
|
bigdecimal (3.1.9)
|
26
38
|
climate_control (1.2.0)
|
27
39
|
concurrent-ruby (1.3.5)
|
28
|
-
console (1.
|
40
|
+
console (1.34.0)
|
29
41
|
fiber-annotation
|
30
42
|
fiber-local (~> 1.1)
|
31
43
|
json
|
@@ -38,43 +50,44 @@ GEM
|
|
38
50
|
concurrent-ruby (~> 1.0)
|
39
51
|
logger
|
40
52
|
zeitwerk (~> 2.6)
|
41
|
-
dry-monads (1.
|
53
|
+
dry-monads (1.9.0)
|
42
54
|
concurrent-ruby (~> 1.0)
|
43
55
|
dry-core (~> 1.1)
|
44
56
|
zeitwerk (~> 2.6)
|
45
|
-
faraday (2.13.
|
57
|
+
faraday (2.13.4)
|
46
58
|
faraday-net_http (>= 2.0, < 3.5)
|
47
59
|
json
|
48
60
|
logger
|
49
|
-
faraday-net_http (3.4.
|
61
|
+
faraday-net_http (3.4.1)
|
50
62
|
net-http (>= 0.5.0)
|
51
63
|
fiber-annotation (0.2.0)
|
52
64
|
fiber-local (1.1.0)
|
53
65
|
fiber-storage
|
54
66
|
fiber-storage (1.0.1)
|
55
67
|
hashdiff (1.1.2)
|
56
|
-
io-event (1.
|
68
|
+
io-event (1.14.0)
|
57
69
|
json (2.9.1)
|
58
|
-
language_server-protocol (3.17.0.
|
70
|
+
language_server-protocol (3.17.0.5)
|
59
71
|
lint_roller (1.1.0)
|
60
72
|
logger (1.7.0)
|
61
|
-
metrics (0.
|
73
|
+
metrics (0.14.0)
|
62
74
|
net-http (0.6.0)
|
63
75
|
uri
|
64
76
|
octokit (9.2.0)
|
65
77
|
faraday (>= 1, < 3)
|
66
78
|
sawyer (~> 0.9)
|
67
|
-
parallel (1.
|
68
|
-
parser (3.3.
|
79
|
+
parallel (1.27.0)
|
80
|
+
parser (3.3.9.0)
|
69
81
|
ast (~> 2.4.1)
|
70
82
|
racc
|
71
83
|
pastel (0.8.0)
|
72
84
|
tty-color (~> 0.5)
|
85
|
+
prism (1.4.0)
|
73
86
|
public_suffix (6.0.1)
|
74
87
|
racc (1.8.1)
|
75
88
|
rainbow (3.1.1)
|
76
89
|
rake (13.2.1)
|
77
|
-
regexp_parser (2.
|
90
|
+
regexp_parser (2.11.2)
|
78
91
|
rexml (3.4.0)
|
79
92
|
rspec (3.13.0)
|
80
93
|
rspec-core (~> 3.13.0)
|
@@ -89,21 +102,24 @@ GEM
|
|
89
102
|
diff-lcs (>= 1.2.0, < 2.0)
|
90
103
|
rspec-support (~> 3.13.0)
|
91
104
|
rspec-support (3.13.2)
|
92
|
-
rubocop (1.
|
105
|
+
rubocop (1.75.8)
|
93
106
|
json (~> 2.3)
|
94
|
-
language_server-protocol (
|
107
|
+
language_server-protocol (~> 3.17.0.2)
|
108
|
+
lint_roller (~> 1.1.0)
|
95
109
|
parallel (~> 1.10)
|
96
110
|
parser (>= 3.3.0.2)
|
97
111
|
rainbow (>= 2.2.2, < 4.0)
|
98
112
|
regexp_parser (>= 2.9.3, < 3.0)
|
99
|
-
rubocop-ast (>= 1.
|
113
|
+
rubocop-ast (>= 1.44.0, < 2.0)
|
100
114
|
ruby-progressbar (~> 1.7)
|
101
115
|
unicode-display_width (>= 2.4.0, < 4.0)
|
102
|
-
rubocop-ast (1.
|
103
|
-
parser (>= 3.3.
|
104
|
-
|
105
|
-
|
106
|
-
|
116
|
+
rubocop-ast (1.46.0)
|
117
|
+
parser (>= 3.3.7.2)
|
118
|
+
prism (~> 1.4)
|
119
|
+
rubocop-performance (1.25.0)
|
120
|
+
lint_roller (~> 1.1)
|
121
|
+
rubocop (>= 1.75.0, < 2.0)
|
122
|
+
rubocop-ast (>= 1.38.0, < 2.0)
|
107
123
|
ruby-progressbar (1.13.0)
|
108
124
|
sawyer (0.9.2)
|
109
125
|
addressable (>= 2.3.5)
|
@@ -114,24 +130,18 @@ GEM
|
|
114
130
|
simplecov_json_formatter (~> 0.1)
|
115
131
|
simplecov-html (0.13.1)
|
116
132
|
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
133
|
standard-custom (1.0.2)
|
124
134
|
lint_roller (~> 1.0)
|
125
135
|
rubocop (~> 1.50)
|
126
|
-
standard-performance (1.
|
136
|
+
standard-performance (1.8.0)
|
127
137
|
lint_roller (~> 1.1)
|
128
|
-
rubocop-performance (~> 1.
|
138
|
+
rubocop-performance (~> 1.25.0)
|
129
139
|
strings (0.2.1)
|
130
140
|
strings-ansi (~> 0.2)
|
131
141
|
unicode-display_width (>= 1.5, < 3.0)
|
132
142
|
unicode_utils (~> 1.4)
|
133
143
|
strings-ansi (0.2.0)
|
134
|
-
traces (0.
|
144
|
+
traces (0.18.1)
|
135
145
|
tty-color (0.6.0)
|
136
146
|
tty-cursor (0.7.1)
|
137
147
|
tty-screen (0.8.2)
|
@@ -162,7 +172,7 @@ DEPENDENCIES
|
|
162
172
|
rspec (~> 3.10)
|
163
173
|
rspec-mocks (~> 3.10)
|
164
174
|
simplecov (~> 0.22.0)
|
165
|
-
standard
|
175
|
+
standard!
|
166
176
|
vcr (~> 6.0)
|
167
177
|
webmock (~> 3.13)
|
168
178
|
|
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# End of Life
|
2
2
|
|
3
|
-
This gem lists GitHub repositories using end-of-life
|
3
|
+
This gem lists GitHub repositories using end-of-life versions of various
|
4
|
+
products.
|
4
5
|
|
5
6
|

|
6
7
|
|
@@ -14,18 +15,20 @@ gem install end_of_life
|
|
14
15
|
|
15
16
|
1. Set up a [GitHub access token][] (we recommend using a read-only token);
|
16
17
|
|
17
|
-
[github access token]:
|
18
|
+
[github access token]:
|
19
|
+
https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token#creating-a-token
|
18
20
|
|
19
|
-
2. Export the `GITHUB_TOKEN` environment variable or set it when calling
|
21
|
+
2. Export the `GITHUB_TOKEN` environment variable or set it when calling
|
22
|
+
`end_of_life`;
|
20
23
|
|
21
24
|
3. Use the `end_of_life` command to list the repositories:
|
22
25
|
|
23
26
|
```sh
|
24
27
|
$ GITHUB_TOKEN=something end_of_life # if your platform supports symlinks, you can use the `eol` command instead
|
25
|
-
[✔]
|
28
|
+
[✔] Searching repositories with Ruby...
|
26
29
|
[✔] Searching for EOL Ruby in repositories...
|
27
30
|
|
28
|
-
Found 2 repositories using EOL Ruby (<=
|
31
|
+
Found 2 repositories using EOL Ruby (<= 3.1.7):
|
29
32
|
┌───┬──────────────────────────────────────────────┬──────────────┐
|
30
33
|
│ │ Repository │ Ruby version │
|
31
34
|
├───┼──────────────────────────────────────────────┼──────────────┤
|
@@ -40,10 +43,11 @@ There are some options to help you filter down the results:
|
|
40
43
|
|
41
44
|
```
|
42
45
|
Usage: end_of_life [options]
|
46
|
+
-p, --product NAME Sets the product to scan for (default: ruby). Supported products are: ruby, rails.
|
43
47
|
--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
|
48
|
+
--public-only Searches only public repositories
|
49
|
+
--private-only Searches only private repositories
|
50
|
+
--repo, --repository=USER/REPO Searches a specific repository
|
47
51
|
--org, --organization=ORG,ORG2 Searches within specific organizations
|
48
52
|
-u, --user=NAME Sets the user used on the repository search
|
49
53
|
--max-eol-days-away NUMBER Sets the maximum number of days away a version can be from EOL. It defaults to 0.
|
@@ -54,17 +58,19 @@ Usage: end_of_life [options]
|
|
54
58
|
|
55
59
|
## How it works
|
56
60
|
|
57
|
-
This gem fetches all your GitHub repositories that contain
|
58
|
-
searches for files that may
|
59
|
-
`.ruby-version`, `Gemfile`, `Gemfile.lock`, and
|
60
|
-
|
61
|
+
This gem fetches all your GitHub repositories that contain code for the
|
62
|
+
specified product, then searches for files that may contain version information.
|
63
|
+
For Ruby, those files are: `.ruby-version`, `Gemfile`, `Gemfile.lock`, and
|
64
|
+
`.tool-version`. End of Life parses these files and extracts the minimum version
|
65
|
+
used in the repository.
|
61
66
|
|
62
|
-
The EOL
|
67
|
+
The EOL version information is provided by https://endoflife.date/, with a file
|
63
68
|
[fallback].
|
64
69
|
|
65
|
-
>
|
66
|
-
>
|
67
|
-
>
|
70
|
+
> [!ATTENTION]
|
71
|
+
> To parse Gemfiles, we need to execute the code inside them.
|
72
|
+
> **Be careful** because this may be a security risk. We plan to add secure
|
73
|
+
> parsers for these files in the future.
|
68
74
|
|
69
75
|
Some other limitations are listed on the [issues page].
|
70
76
|
|
@@ -86,7 +92,10 @@ git commits and the created tag, and push the `.gem` file to
|
|
86
92
|
## Contributing
|
87
93
|
|
88
94
|
Bug reports and pull requests are welcome on GitHub at
|
89
|
-
https://github.com/MatheusRich/end_of_life.
|
95
|
+
https://github.com/MatheusRich/end_of_life. If you want to add a new product,
|
96
|
+
[check out this commit for reference].
|
97
|
+
|
98
|
+
[check out this commit for reference]: ba9a92a690e0d61ea09e508c1cd76b8309fb89df
|
90
99
|
|
91
100
|
## License
|
92
101
|
|
data/end_of_life.gemspec
CHANGED
@@ -8,9 +8,9 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.authors = ["Matheus Richard"]
|
9
9
|
spec.email = ["matheusrichardt@gmail.com"]
|
10
10
|
|
11
|
-
spec.summary = "Lists repositories using end-of-life
|
11
|
+
spec.summary = "Lists repositories using end-of-life software"
|
12
12
|
spec.description = "Searches your GitHub repositores and lists the ones using end-of-life, i.e. " \
|
13
|
-
"unmaintained,
|
13
|
+
"unmaintained, software versions."
|
14
14
|
spec.homepage = "https://github.com/MatheusRich/end_of_life"
|
15
15
|
spec.license = "MIT"
|
16
16
|
spec.required_ruby_version = ">= 3.2.0"
|
@@ -38,6 +38,7 @@ Gem::Specification.new do |spec|
|
|
38
38
|
spec.add_dependency "pastel", "~> 0.8.0"
|
39
39
|
spec.add_dependency "tty-spinner", "~> 0.9.0"
|
40
40
|
spec.add_dependency "tty-table", "~> 0.12.0"
|
41
|
+
spec.add_dependency "zeitwerk", "~> 2.7"
|
41
42
|
|
42
43
|
# For more information and examples about making a new gem, check out our
|
43
44
|
# guide at: https://bundler.io/guides/creating_gem.html
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module EndOfLife
|
2
|
+
module API
|
3
|
+
extend self
|
4
|
+
|
5
|
+
BASE_URL = "https://endoflife.date/api/v1/"
|
6
|
+
|
7
|
+
def fetch_product(product) = get("products/#{product}")
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def get(path)
|
12
|
+
response = Net::HTTP.get(URI("#{BASE_URL}#{path}"))
|
13
|
+
|
14
|
+
JSON.parse(response, symbolize_names: true)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/end_of_life/cli.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module EndOfLife
|
2
2
|
class CLI
|
3
|
-
include
|
3
|
+
include Helpers::Terminal
|
4
4
|
|
5
5
|
def call(argv)
|
6
6
|
parse_options(argv)
|
@@ -9,6 +9,10 @@ module EndOfLife
|
|
9
9
|
|
10
10
|
private
|
11
11
|
|
12
|
+
def parse_options(argv)
|
13
|
+
Options.from(argv)
|
14
|
+
end
|
15
|
+
|
12
16
|
def execute_command(options)
|
13
17
|
case options[:command]
|
14
18
|
when :help
|
@@ -16,64 +20,10 @@ module EndOfLife
|
|
16
20
|
when :version
|
17
21
|
puts "end_of_life v#{EndOfLife::VERSION}"
|
18
22
|
when :print_error
|
19
|
-
|
20
|
-
exit(-1)
|
23
|
+
abort error_msg(options[:error])
|
21
24
|
else
|
22
|
-
|
25
|
+
Scanner.scan(options)
|
23
26
|
end
|
24
27
|
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
|
-
puts "Found #{repositories.size} repositories using EOL Ruby (<= #{RubyVersion.latest_eol(at: max_eol_date)}):"
|
66
|
-
puts end_of_life_table(repositories)
|
67
|
-
exit(-1)
|
68
|
-
end
|
69
|
-
|
70
|
-
def end_of_life_table(repositories)
|
71
|
-
headers = ["", "Repository", "Ruby version"]
|
72
|
-
rows = repositories.map.with_index(1) do |repo, i|
|
73
|
-
[i, repo.url, repo.ruby_version]
|
74
|
-
end
|
75
|
-
|
76
|
-
table(headers, rows)
|
77
|
-
end
|
78
28
|
end
|
79
29
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "bundler"
|
2
|
+
|
3
|
+
module EndOfLife
|
4
|
+
module Helpers
|
5
|
+
module SilentBundler
|
6
|
+
extend self
|
7
|
+
|
8
|
+
def silence_bundler
|
9
|
+
previous_ui = Bundler.ui
|
10
|
+
Bundler.ui = Bundler::UI::Silent.new
|
11
|
+
|
12
|
+
yield
|
13
|
+
ensure
|
14
|
+
Bundler.ui = previous_ui
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/end_of_life/options.rb
CHANGED
@@ -3,50 +3,54 @@ require "optparse"
|
|
3
3
|
module EndOfLife
|
4
4
|
module Options
|
5
5
|
def self.from(argv)
|
6
|
-
options = {max_eol_date: Date.today, skip_archived: true}
|
6
|
+
options = {product: Product.find("ruby"), max_eol_date: Date.today, skip_archived: true}
|
7
|
+
OptionParser.new do |parser|
|
8
|
+
options[:parser] = parser
|
7
9
|
|
8
|
-
|
9
|
-
options[:parser] = opts
|
10
|
+
parser.banner = "Usage: end_of_life [options]"
|
10
11
|
|
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
|
12
16
|
|
13
|
-
|
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|
|
14
18
|
options[:excludes] = excludes.first(5)
|
15
19
|
end
|
16
20
|
|
17
|
-
|
21
|
+
parser.on("--public-only", "Searches only public repositories") do
|
18
22
|
options[:visibility] = :public
|
19
23
|
end
|
20
24
|
|
21
|
-
|
25
|
+
parser.on("--private-only", "Searches only private repositories") do
|
22
26
|
options[:visibility] = :private
|
23
27
|
end
|
24
28
|
|
25
|
-
|
29
|
+
parser.on("--repo=USER/REPO", "--repository=USER/REPO", "Searches a specific repository") do |repository|
|
26
30
|
options[:repository] = repository
|
27
31
|
end
|
28
32
|
|
29
|
-
|
33
|
+
parser.on("--org=ORG,ORG2...", "--organization=ORG,ORG2", Array, "Searches within specific organizations") do |organizations|
|
30
34
|
options[:organizations] = organizations
|
31
35
|
end
|
32
36
|
|
33
|
-
|
37
|
+
parser.on("-u NAME", "--user=NAME", "Sets the user used on the repository search") do |user|
|
34
38
|
options[:user] = user
|
35
39
|
end
|
36
40
|
|
37
|
-
|
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|
|
38
42
|
options[:max_eol_date] = Date.today + days.to_i.abs
|
39
43
|
end
|
40
44
|
|
41
|
-
|
45
|
+
parser.on("--include-archived", "Includes archived repositories on the search") do
|
42
46
|
options[:skip_archived] = false
|
43
47
|
end
|
44
48
|
|
45
|
-
|
49
|
+
parser.on("-v", "--version", "Displays end_of_life version") do
|
46
50
|
options[:command] = :version
|
47
51
|
end
|
48
52
|
|
49
|
-
|
53
|
+
parser.on("-h", "--help", "Displays this help") do
|
50
54
|
options[:command] = :help
|
51
55
|
end
|
52
56
|
end.parse!(argv)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module EndOfLife
|
2
|
+
module Parsers
|
3
|
+
module Gemfile
|
4
|
+
extend Helpers::SilentBundler
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def parse(file_content)
|
8
|
+
with_temp_gemfile(file_content) do |gemfile|
|
9
|
+
silence_bundler do
|
10
|
+
# This is security problem, since it runs the code inside the file
|
11
|
+
Bundler::Definition.build(gemfile.path, nil, {})
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def with_temp_gemfile(contents)
|
19
|
+
# Bundler requires a file to parse, so we need to create a temporary file
|
20
|
+
Tempfile.create("tempGemfile") do |tempfile|
|
21
|
+
tempfile.write(contents)
|
22
|
+
tempfile.rewind
|
23
|
+
|
24
|
+
yield(tempfile)
|
25
|
+
rescue Bundler::BundlerError
|
26
|
+
nil # NOTE: maybe a Null object would be cleaner
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module EndOfLife
|
2
|
+
module Parsers
|
3
|
+
module ToolVersions
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def parse(file_content)
|
7
|
+
file_content
|
8
|
+
.lines
|
9
|
+
.filter_map { |line|
|
10
|
+
line = line.strip
|
11
|
+
next if line.start_with?("#") || line.empty?
|
12
|
+
|
13
|
+
tool, version, * = line.split
|
14
|
+
|
15
|
+
next if version == "latest"
|
16
|
+
|
17
|
+
[tool, Gem::Version.new(version)]
|
18
|
+
}
|
19
|
+
.to_h
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module EndOfLife
|
2
|
+
module Product::Registry
|
3
|
+
def scans_for(product_name, search_query:)
|
4
|
+
product_registry[product_name.to_sym.downcase] = Product.new(
|
5
|
+
product_name,
|
6
|
+
search_query,
|
7
|
+
version_detector_for(product_name)
|
8
|
+
)
|
9
|
+
end
|
10
|
+
|
11
|
+
def find_product(name) = product_registry.fetch(name.to_sym.downcase)
|
12
|
+
|
13
|
+
def products = product_registry.values
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def product_registry
|
18
|
+
@@product_registry ||= {}
|
19
|
+
end
|
20
|
+
|
21
|
+
def version_detector_for(product) = VersionDetectors.for_product(product)
|
22
|
+
end
|
23
|
+
end
|