gem_radar 0.1.0 → 0.1.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/.github/PULL_REQUEST_TEMPLATE.md +12 -0
- data/.github/workflows/ci.yml +31 -0
- data/.gitignore +0 -4
- data/.rspec +3 -0
- data/.rubocop.yml +37 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +11 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +113 -0
- data/README.md +37 -0
- data/Rakefile +7 -0
- data/gem_radar.gemspec +4 -3
- data/lib/gem_radar/cli.rb +80 -36
- data/lib/gem_radar/version.rb +2 -2
- metadata +13 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fd10085592b6dd19c31f335c1db17bab91f7560c872fcc2f22e04d44cff5277b
|
|
4
|
+
data.tar.gz: 614f4cb6f16377b96bc57f638009d3f1e80648ea3d0b5d035f7c54fafc82576d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2284fb0a8557cc8b08d1a2396341874f76f5589218d454f4192f58833231afaf6dd05ab90ca4bc5d96a9b83b6b11e053ed730da8de491e905a3686485361ef98
|
|
7
|
+
data.tar.gz: f31e50cee88d03e1d06d3d7f286a74a67f61142257ac9b4df058bb22a3b2ff4782c1eafd06f47ef2219bd811916fc223ea247b1f04525002f16802606de44cee
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
## Why
|
|
2
|
+
|
|
3
|
+
<!-- What problem does this solve, or what's the motivation? -->
|
|
4
|
+
|
|
5
|
+
## What
|
|
6
|
+
|
|
7
|
+
<!-- What did you change, at a high level? -->
|
|
8
|
+
|
|
9
|
+
## Evidence
|
|
10
|
+
|
|
11
|
+
<!-- Test output, logs, or screenshots showing it works (e.g. a run of
|
|
12
|
+
`bundle exec rspec`, or a sample report generated with your change). -->
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
|
|
14
|
+
- uses: ruby/setup-ruby@v1
|
|
15
|
+
with:
|
|
16
|
+
bundler-cache: true
|
|
17
|
+
|
|
18
|
+
- name: Run tests
|
|
19
|
+
run: bundle exec rspec
|
|
20
|
+
|
|
21
|
+
lint:
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v4
|
|
25
|
+
|
|
26
|
+
- uses: ruby/setup-ruby@v1
|
|
27
|
+
with:
|
|
28
|
+
bundler-cache: true
|
|
29
|
+
|
|
30
|
+
- name: Run rubocop
|
|
31
|
+
run: bundle exec rubocop
|
data/.gitignore
CHANGED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
AllCops:
|
|
2
|
+
TargetRubyVersion: 2.7
|
|
3
|
+
NewCops: enable
|
|
4
|
+
SuggestExtensions: false
|
|
5
|
+
Exclude:
|
|
6
|
+
- "vendor/**/*"
|
|
7
|
+
|
|
8
|
+
Style/Documentation:
|
|
9
|
+
Enabled: false
|
|
10
|
+
|
|
11
|
+
Style/StringLiterals:
|
|
12
|
+
EnforcedStyle: double_quotes
|
|
13
|
+
|
|
14
|
+
Metrics/MethodLength:
|
|
15
|
+
Max: 30
|
|
16
|
+
|
|
17
|
+
Metrics/AbcSize:
|
|
18
|
+
Max: 46
|
|
19
|
+
|
|
20
|
+
Metrics/CyclomaticComplexity:
|
|
21
|
+
Max: 18
|
|
22
|
+
|
|
23
|
+
Metrics/PerceivedComplexity:
|
|
24
|
+
Max: 18
|
|
25
|
+
|
|
26
|
+
Metrics/ParameterLists:
|
|
27
|
+
Max: 6
|
|
28
|
+
|
|
29
|
+
Metrics/ModuleLength:
|
|
30
|
+
Max: 350
|
|
31
|
+
|
|
32
|
+
Metrics/BlockLength:
|
|
33
|
+
Exclude:
|
|
34
|
+
- "spec/**/*"
|
|
35
|
+
|
|
36
|
+
Gemspec/DevelopmentDependencies:
|
|
37
|
+
EnforcedStyle: Gemfile
|
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
4.0.6
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.1 (26-08-2026) - Blue Velvet
|
|
4
|
+
|
|
5
|
+
[FIX]
|
|
6
|
+
- A gem whose own description just mentions "deprecated" (like this one,
|
|
7
|
+
which describes detecting deprecated gems) no longer flags itself as deprecated. Only actual deprecation notices are detected now.
|
|
8
|
+
|
|
9
|
+
[INTERNAL]
|
|
10
|
+
- Only test in current ruby version.
|
|
11
|
+
- Lowered `required_ruby_version` to `>= 2.7.0` so the gem can be added to
|
|
12
|
+
older projects. Verified with a new spec (`spec/ruby_compatibility_spec.rb`) that shells out to every installed Ruby version from 2.7 up and confirms the library loads correctly.
|
|
13
|
+
|
|
3
14
|
## 0.1.0 (26-08-2026) - Brazil
|
|
4
15
|
|
|
5
16
|
Initial public release.
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
gem_radar (0.1.1)
|
|
5
|
+
|
|
6
|
+
GEM
|
|
7
|
+
remote: https://rubygems.org/
|
|
8
|
+
specs:
|
|
9
|
+
addressable (2.9.0)
|
|
10
|
+
public_suffix (>= 2.0.2, < 8.0)
|
|
11
|
+
ast (2.4.3)
|
|
12
|
+
bigdecimal (4.1.2)
|
|
13
|
+
crack (1.0.1)
|
|
14
|
+
bigdecimal
|
|
15
|
+
rexml
|
|
16
|
+
diff-lcs (1.6.2)
|
|
17
|
+
hashdiff (1.2.1)
|
|
18
|
+
json (2.21.2)
|
|
19
|
+
language_server-protocol (3.17.0.6)
|
|
20
|
+
lint_roller (1.1.0)
|
|
21
|
+
parallel (2.1.0)
|
|
22
|
+
parser (3.3.12.0)
|
|
23
|
+
ast (~> 2.4.1)
|
|
24
|
+
racc
|
|
25
|
+
prism (1.9.0)
|
|
26
|
+
public_suffix (7.0.5)
|
|
27
|
+
racc (1.8.1)
|
|
28
|
+
rainbow (3.1.1)
|
|
29
|
+
rake (13.4.2)
|
|
30
|
+
regexp_parser (2.12.0)
|
|
31
|
+
rexml (3.4.4)
|
|
32
|
+
rspec (3.13.2)
|
|
33
|
+
rspec-core (~> 3.13.0)
|
|
34
|
+
rspec-expectations (~> 3.13.0)
|
|
35
|
+
rspec-mocks (~> 3.13.0)
|
|
36
|
+
rspec-core (3.13.6)
|
|
37
|
+
rspec-support (~> 3.13.0)
|
|
38
|
+
rspec-expectations (3.13.5)
|
|
39
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
40
|
+
rspec-support (~> 3.13.0)
|
|
41
|
+
rspec-mocks (3.13.8)
|
|
42
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
43
|
+
rspec-support (~> 3.13.0)
|
|
44
|
+
rspec-support (3.13.7)
|
|
45
|
+
rubocop (1.90.0)
|
|
46
|
+
json (>= 2.3)
|
|
47
|
+
language_server-protocol (~> 3.17.0.2)
|
|
48
|
+
lint_roller (~> 1.1.0)
|
|
49
|
+
parallel (>= 1.10)
|
|
50
|
+
parser (>= 3.3.0.2)
|
|
51
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
52
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
|
53
|
+
rubocop-ast (>= 1.49.0, < 2.0)
|
|
54
|
+
ruby-progressbar (~> 1.7)
|
|
55
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
|
56
|
+
rubocop-ast (1.50.0)
|
|
57
|
+
parser (>= 3.3.7.2)
|
|
58
|
+
prism (~> 1.7)
|
|
59
|
+
ruby-progressbar (1.13.0)
|
|
60
|
+
unicode-display_width (3.2.0)
|
|
61
|
+
unicode-emoji (~> 4.1)
|
|
62
|
+
unicode-emoji (4.2.0)
|
|
63
|
+
webmock (3.26.3)
|
|
64
|
+
addressable (>= 2.8.0)
|
|
65
|
+
crack (>= 0.3.2)
|
|
66
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
|
67
|
+
|
|
68
|
+
PLATFORMS
|
|
69
|
+
ruby
|
|
70
|
+
x86_64-linux
|
|
71
|
+
|
|
72
|
+
DEPENDENCIES
|
|
73
|
+
gem_radar!
|
|
74
|
+
rake (~> 13.0)
|
|
75
|
+
rspec (~> 3.13)
|
|
76
|
+
rubocop (~> 1.75)
|
|
77
|
+
webmock (~> 3.19)
|
|
78
|
+
|
|
79
|
+
CHECKSUMS
|
|
80
|
+
addressable (2.9.0) sha256=7fdf6ac3660f7f4e867a0838be3f6cf722ace541dd97767fa42bc6cfa980c7af
|
|
81
|
+
ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383
|
|
82
|
+
bigdecimal (4.1.2) sha256=53d217666027eab4280346fba98e7d5b66baaae1b9c3c1c0ffe89d48188a3fbd
|
|
83
|
+
bundler (4.0.18) sha256=02d9a17429de1847b4e0c9f27a9ee4b20c0a74c0a641b4e77195d6019e3618ac
|
|
84
|
+
crack (1.0.1) sha256=ff4a10390cd31d66440b7524eb1841874db86201d5b70032028553130b6d4c7e
|
|
85
|
+
diff-lcs (1.6.2) sha256=9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962
|
|
86
|
+
gem_radar (0.1.1)
|
|
87
|
+
hashdiff (1.2.1) sha256=9c079dbc513dfc8833ab59c0c2d8f230fa28499cc5efb4b8dd276cf931457cd1
|
|
88
|
+
json (2.21.2) sha256=1f1d3b7cf2b3ba1a69beca0bb6db13d5438b80bff3cd54cdaaa620b9b07c1c6a
|
|
89
|
+
language_server-protocol (3.17.0.6) sha256=5ef2c0c138f8267e1bc631d3328347d354f96724b0af22f2c79516120443b7f0
|
|
90
|
+
lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87
|
|
91
|
+
parallel (2.1.0) sha256=b35258865c2e31134c5ecb708beaaf6772adf9d5efae28e93e99260877b09356
|
|
92
|
+
parser (3.3.12.0) sha256=21a6d7f755d5a24dfbdc6e6b772e4e879a52e7631a88bc5a3a134606052c9828
|
|
93
|
+
prism (1.9.0) sha256=7b530c6a9f92c24300014919c9dcbc055bf4cdf51ec30aed099b06cd6674ef85
|
|
94
|
+
public_suffix (7.0.5) sha256=1a8bb08f1bbea19228d3bed6e5ed908d1cb4f7c2726d18bd9cadf60bc676f623
|
|
95
|
+
racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f
|
|
96
|
+
rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a
|
|
97
|
+
rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701
|
|
98
|
+
regexp_parser (2.12.0) sha256=35a916a1d63190ab5c9009457136ae5f3c0c7512d60291d0d1378ba18ce08ebb
|
|
99
|
+
rexml (3.4.4) sha256=19e0a2c3425dfbf2d4fc1189747bdb2f849b6c5e74180401b15734bc97b5d142
|
|
100
|
+
rspec (3.13.2) sha256=206284a08ad798e61f86d7ca3e376718d52c0bc944626b2349266f239f820587
|
|
101
|
+
rspec-core (3.13.6) sha256=a8823c6411667b60a8bca135364351dda34cd55e44ff94c4be4633b37d828b2d
|
|
102
|
+
rspec-expectations (3.13.5) sha256=33a4d3a1d95060aea4c94e9f237030a8f9eae5615e9bd85718fe3a09e4b58836
|
|
103
|
+
rspec-mocks (3.13.8) sha256=086ad3d3d17533f4237643de0b5c42f04b66348c28bf6b9c2d3f4a3b01af1d47
|
|
104
|
+
rspec-support (3.13.7) sha256=0640e5570872aafefd79867901deeeeb40b0c9875a36b983d85f54fb7381c47c
|
|
105
|
+
rubocop (1.90.0) sha256=9eb4c065b5c5154e4ef554c547972f3905a9eb6b53e657e580b6796b54bf8242
|
|
106
|
+
rubocop-ast (1.50.0) sha256=b9ca88300da0803ee222ad20cdb30494c0a784eed06fdc35d254b06d662788db
|
|
107
|
+
ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
|
|
108
|
+
unicode-display_width (3.2.0) sha256=0cdd96b5681a5949cdbc2c55e7b420facae74c4aaf9a9815eee1087cb1853c42
|
|
109
|
+
unicode-emoji (4.2.0) sha256=519e69150f75652e40bf736106cfbc8f0f73aa3fb6a65afe62fefa7f80b0f80f
|
|
110
|
+
webmock (3.26.3) sha256=77c612816bdcb2fc43db0e42fd98b19be7d4770fd708816fdde65a006664ddec
|
|
111
|
+
|
|
112
|
+
BUNDLED WITH
|
|
113
|
+
4.0.18
|
data/README.md
CHANGED
|
@@ -8,6 +8,16 @@ compatibility and update status.
|
|
|
8
8
|
For each gem, the report links only to its repository — it does not
|
|
9
9
|
download or embed changelog content.
|
|
10
10
|
|
|
11
|
+
## Ruby compatibility
|
|
12
|
+
|
|
13
|
+
Works on **>= Ruby 2.7**.
|
|
14
|
+
|
|
15
|
+
No runtime dependencies means adding `gem_radar` to an old project's `Gemfile` doesn't drag in anything that would clash with it.
|
|
16
|
+
|
|
17
|
+
This is **deliberate**: the projects that most need help
|
|
18
|
+
figuring out an upgrade path are exactly the ones still stuck on an old RoR apps.
|
|
19
|
+
|
|
20
|
+
|
|
11
21
|
## Installation
|
|
12
22
|
|
|
13
23
|
Add it to your project's `Gemfile`:
|
|
@@ -73,6 +83,33 @@ whether a gem's repository has been archived.
|
|
|
73
83
|
|
|
74
84
|
Ruby standard library only — no runtime dependencies.
|
|
75
85
|
|
|
86
|
+
## How to contribute
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
git clone https://github.com/laurajaime/gem_radar.git
|
|
90
|
+
cd gem_radar
|
|
91
|
+
bundle install
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Run the test suite:
|
|
95
|
+
|
|
96
|
+
```sh
|
|
97
|
+
bundle exec rspec
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Run the linter:
|
|
101
|
+
|
|
102
|
+
```sh
|
|
103
|
+
bundle exec rubocop
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Both run in CI on every push and pull request (see
|
|
107
|
+
[.github/workflows/ci.yml](.github/workflows/ci.yml)).
|
|
108
|
+
|
|
109
|
+
Open your PR explaining **why** the change is needed and **what** it does,
|
|
110
|
+
with evidence that it works (test output, logs, or screenshots) — see the
|
|
111
|
+
[PR template](.github/PULL_REQUEST_TEMPLATE.md).
|
|
112
|
+
|
|
76
113
|
## License
|
|
77
114
|
|
|
78
115
|
MIT
|
data/Rakefile
ADDED
data/gem_radar.gemspec
CHANGED
|
@@ -9,13 +9,14 @@ Gem::Specification.new do |spec|
|
|
|
9
9
|
|
|
10
10
|
spec.summary = "Audits your Ruby/Rails project's gems and reports their compatibility and update status."
|
|
11
11
|
spec.description = "Reads a project's Gemfile.lock and reports, for each direct gem, whether it's " \
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
"compatible with the project's Ruby/Rails, needs a mandatory update, is " \
|
|
13
|
+
"deprecated or archived, or can be upgraded safely vs. with breaking changes."
|
|
14
14
|
spec.homepage = "https://github.com/laurajaime/gem_radar"
|
|
15
15
|
spec.license = "MIT"
|
|
16
|
-
spec.required_ruby_version = ">=
|
|
16
|
+
spec.required_ruby_version = ">= 2.7.0"
|
|
17
17
|
|
|
18
18
|
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
|
|
19
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
|
19
20
|
|
|
20
21
|
spec.files = Dir.chdir(__dir__) do
|
|
21
22
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
data/lib/gem_radar/cli.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
#
|
|
3
4
|
# gem_radar — generates a Markdown report on the health of a Ruby/Rails
|
|
4
5
|
# project's direct gems, grouped into categories:
|
|
@@ -45,14 +46,17 @@ module GemRadar
|
|
|
45
46
|
lock = parse_lockfile(options[:lockfile])
|
|
46
47
|
ruby_version = detect_ruby_version(options, lock)
|
|
47
48
|
rails_version = detect_rails_version(options, lock)
|
|
48
|
-
|
|
49
|
+
lockfile_dir = File.dirname(options[:lockfile])
|
|
50
|
+
project = File.basename(File.expand_path(lockfile_dir == "." ? Dir.pwd : lockfile_dir))
|
|
49
51
|
|
|
50
52
|
warn "Project: #{project} · Ruby: #{ruby_version || 'not detected (use --ruby)'} · " \
|
|
51
53
|
"Rails: #{rails_version || 'not detected (use --rails)'} · #{lock[:dependencies].size} direct gems"
|
|
52
|
-
|
|
54
|
+
unless github_token
|
|
55
|
+
warn "Warning: no GITHUB_TOKEN and no authenticated `gh`; GitHub's API is limited to 60 requests/hour."
|
|
56
|
+
end
|
|
53
57
|
|
|
54
58
|
results = lock[:dependencies].each_with_index.map do |name, i|
|
|
55
|
-
warn format(" [
|
|
59
|
+
warn format(" [%<index>d/%<total>d] %<name>s…", index: i + 1, total: lock[:dependencies].size, name: name)
|
|
56
60
|
process_gem(name, lock[:specs][name], ruby_version, rails_version)
|
|
57
61
|
end
|
|
58
62
|
|
|
@@ -69,12 +73,22 @@ module GemRadar
|
|
|
69
73
|
options = { output: "gem_radar.md", lockfile: "Gemfile.lock" }
|
|
70
74
|
OptionParser.new do |o|
|
|
71
75
|
o.banner = "Usage: gem_radar [options] (run from inside the project directory)"
|
|
72
|
-
o.on("--ruby VERSION", "Project's Ruby version (default: .ruby-version or Gemfile.lock)")
|
|
73
|
-
|
|
76
|
+
o.on("--ruby VERSION", "Project's Ruby version (default: .ruby-version or Gemfile.lock)") do |v|
|
|
77
|
+
options[:ruby] = v
|
|
78
|
+
end
|
|
79
|
+
o.on("--rails VERSION", "Project's Rails version (default: the one in Gemfile.lock)") do |v|
|
|
80
|
+
options[:rails] = v
|
|
81
|
+
end
|
|
74
82
|
o.on("--lockfile PATH", "Path to Gemfile.lock (default: ./Gemfile.lock)") { |v| options[:lockfile] = v }
|
|
75
83
|
o.on("-o", "--output PATH", "Output file (default: gem_radar.md)") { |v| options[:output] = v }
|
|
76
|
-
o.on("-h", "--help", "Shows this help")
|
|
77
|
-
|
|
84
|
+
o.on("-h", "--help", "Shows this help") do
|
|
85
|
+
puts o
|
|
86
|
+
exit
|
|
87
|
+
end
|
|
88
|
+
o.on("--version", "Shows the version") do
|
|
89
|
+
puts "gem_radar #{VERSION} (\"#{CODENAME}\")"
|
|
90
|
+
exit
|
|
91
|
+
end
|
|
78
92
|
end.parse!(argv)
|
|
79
93
|
options
|
|
80
94
|
end
|
|
@@ -83,12 +97,13 @@ module GemRadar
|
|
|
83
97
|
|
|
84
98
|
def http_get(url, headers = {}, limit = 5)
|
|
85
99
|
return nil if limit.zero?
|
|
100
|
+
|
|
86
101
|
uri = URI(url)
|
|
87
102
|
req = Net::HTTP::Get.new(uri)
|
|
88
103
|
req["User-Agent"] = USER_AGENT
|
|
89
104
|
headers.each { |k, v| req[k] = v }
|
|
90
105
|
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https",
|
|
91
|
-
|
|
106
|
+
open_timeout: 10, read_timeout: 30) { |h| h.request(req) }
|
|
92
107
|
if res.is_a?(Net::HTTPRedirection) && res["location"]
|
|
93
108
|
http_get(URI.join(url, res["location"]).to_s, headers, limit - 1)
|
|
94
109
|
else
|
|
@@ -101,7 +116,8 @@ module GemRadar
|
|
|
101
116
|
|
|
102
117
|
def github_token
|
|
103
118
|
return @github_token if defined?(@github_token)
|
|
104
|
-
|
|
119
|
+
|
|
120
|
+
token = ENV["GITHUB_TOKEN"] || ENV.fetch("GH_TOKEN", nil)
|
|
105
121
|
token ||= begin
|
|
106
122
|
out = `gh auth token 2>/dev/null`.strip
|
|
107
123
|
out.empty? ? nil : out
|
|
@@ -116,6 +132,7 @@ module GemRadar
|
|
|
116
132
|
headers["Authorization"] = "Bearer #{github_token}" if github_token
|
|
117
133
|
res = http_get("https://api.github.com#{path}", headers)
|
|
118
134
|
return nil unless res.is_a?(Net::HTTPSuccess)
|
|
135
|
+
|
|
119
136
|
JSON.parse(res.body)
|
|
120
137
|
rescue JSON::ParserError
|
|
121
138
|
nil
|
|
@@ -137,11 +154,11 @@ module GemRadar
|
|
|
137
154
|
end
|
|
138
155
|
case section
|
|
139
156
|
when "GEM", "GIT", "PATH"
|
|
140
|
-
specs[
|
|
157
|
+
specs[::Regexp.last_match(1)] = ::Regexp.last_match(2) if line =~ /\A (\S+) \(([^)\s]+)\)/
|
|
141
158
|
when "DEPENDENCIES"
|
|
142
|
-
deps <<
|
|
159
|
+
deps << ::Regexp.last_match(1) if line =~ /\A ([^\s!(]+)/
|
|
143
160
|
when "RUBY VERSION"
|
|
144
|
-
ruby =
|
|
161
|
+
ruby = ::Regexp.last_match(1) if line =~ /ruby (\d+\.\d+\.\d+)/
|
|
145
162
|
end
|
|
146
163
|
end
|
|
147
164
|
{ dependencies: deps.uniq.sort, specs: specs, ruby: ruby }
|
|
@@ -149,6 +166,7 @@ module GemRadar
|
|
|
149
166
|
|
|
150
167
|
def detect_ruby_version(options, lockfile_data)
|
|
151
168
|
return options[:ruby] if options[:ruby]
|
|
169
|
+
|
|
152
170
|
if File.file?(".ruby-version")
|
|
153
171
|
v = File.read(".ruby-version").strip.sub(/\Aruby-/, "")
|
|
154
172
|
return v unless v.empty?
|
|
@@ -165,6 +183,7 @@ module GemRadar
|
|
|
165
183
|
def rubygems_info(name)
|
|
166
184
|
res = http_get("https://rubygems.org/api/v1/gems/#{name}.json")
|
|
167
185
|
return nil unless res.is_a?(Net::HTTPSuccess)
|
|
186
|
+
|
|
168
187
|
JSON.parse(res.body)
|
|
169
188
|
rescue JSON::ParserError
|
|
170
189
|
nil
|
|
@@ -173,6 +192,7 @@ module GemRadar
|
|
|
173
192
|
def rubygems_versions(name)
|
|
174
193
|
res = http_get("https://rubygems.org/api/v1/versions/#{name}.json")
|
|
175
194
|
return [] unless res.is_a?(Net::HTTPSuccess)
|
|
195
|
+
|
|
176
196
|
JSON.parse(res.body)
|
|
177
197
|
rescue JSON::ParserError
|
|
178
198
|
[]
|
|
@@ -182,6 +202,7 @@ module GemRadar
|
|
|
182
202
|
@version_deps_cache ||= {}
|
|
183
203
|
key = "#{name}@#{version}"
|
|
184
204
|
return @version_deps_cache[key] if @version_deps_cache.key?(key)
|
|
205
|
+
|
|
185
206
|
res = http_get("https://rubygems.org/api/v2/rubygems/#{name}/versions/#{version}.json")
|
|
186
207
|
@version_deps_cache[key] =
|
|
187
208
|
begin
|
|
@@ -199,6 +220,7 @@ module GemRadar
|
|
|
199
220
|
|
|
200
221
|
def requirement_satisfied?(requirement_str, version)
|
|
201
222
|
return true if requirement_str.nil? || requirement_str.to_s.empty?
|
|
223
|
+
|
|
202
224
|
Gem::Requirement.new(*requirement_str.split(",").map(&:strip)).satisfied_by?(version)
|
|
203
225
|
rescue StandardError
|
|
204
226
|
true
|
|
@@ -210,8 +232,10 @@ module GemRadar
|
|
|
210
232
|
|
|
211
233
|
def rails_requirement_satisfied?(runtime_deps, rails_version)
|
|
212
234
|
return true unless rails_version
|
|
235
|
+
|
|
213
236
|
rails_deps = Array(runtime_deps).select { |d| RAILS_FAMILY.include?(d["name"]) }
|
|
214
237
|
return true if rails_deps.empty?
|
|
238
|
+
|
|
215
239
|
rails_deps.all? { |d| requirement_satisfied?(d["requirements"], rails_version) }
|
|
216
240
|
end
|
|
217
241
|
|
|
@@ -248,6 +272,7 @@ module GemRadar
|
|
|
248
272
|
# not just a recommendation (unlike the "updatable" categories).
|
|
249
273
|
def mandatory_update_reasons(name, installed, versions, ruby_version, rails_version, latest_runtime_deps)
|
|
250
274
|
return [] unless installed
|
|
275
|
+
|
|
251
276
|
entry = versions.find { |v| gem_version(v["number"]) == installed }
|
|
252
277
|
return [] unless entry # installed version not indexed on rubygems.org (yanked, etc.)
|
|
253
278
|
|
|
@@ -280,6 +305,7 @@ module GemRadar
|
|
|
280
305
|
|
|
281
306
|
def github_repo(url)
|
|
282
307
|
return nil unless url && !url.empty?
|
|
308
|
+
|
|
283
309
|
m = url.match(%r{github\.com/([^/]+)/([^/#?]+)})
|
|
284
310
|
m && "#{m[1]}/#{m[2].sub(/\.git\z/, '')}"
|
|
285
311
|
end
|
|
@@ -294,10 +320,24 @@ module GemRadar
|
|
|
294
320
|
[info["source_code_uri"] || info["homepage_uri"], nil]
|
|
295
321
|
end
|
|
296
322
|
|
|
323
|
+
# Matches an actual deprecation notice ("DEPRECATED: ...", "this gem is
|
|
324
|
+
# deprecated", "no longer maintained"), not just any mention of the word
|
|
325
|
+
# — a gem *about* deprecation (like this one) can otherwise flag itself.
|
|
326
|
+
DEPRECATION_NOTICE = /
|
|
327
|
+
(?:\A|[.!]\s*) \W*
|
|
328
|
+
(?: this \s gem \s (?:is|has \s been) \s deprecated
|
|
329
|
+
| deprecated \s*[:-]
|
|
330
|
+
| \[deprecated\]
|
|
331
|
+
| no \s longer \s maintained
|
|
332
|
+
| unmaintained
|
|
333
|
+
)
|
|
334
|
+
/ix.freeze
|
|
335
|
+
|
|
297
336
|
def deprecated?(info, repo_info)
|
|
298
337
|
return true if repo_info && repo_info["archived"]
|
|
338
|
+
|
|
299
339
|
text = "#{info['info']} #{info['description']}"
|
|
300
|
-
!!(text =~
|
|
340
|
+
!!(text =~ DEPRECATION_NOTICE)
|
|
301
341
|
end
|
|
302
342
|
|
|
303
343
|
# --- Classification -----------------------------------------------------------
|
|
@@ -323,15 +363,17 @@ module GemRadar
|
|
|
323
363
|
end
|
|
324
364
|
end
|
|
325
365
|
|
|
326
|
-
def classify(
|
|
327
|
-
return :not_found unless
|
|
328
|
-
return :mandatory if
|
|
329
|
-
return :deprecated if
|
|
330
|
-
return :compatible unless
|
|
366
|
+
def classify(result)
|
|
367
|
+
return :not_found unless result[:found]
|
|
368
|
+
return :mandatory if result[:mandatory_reasons] && !result[:mandatory_reasons].empty?
|
|
369
|
+
return :deprecated if result[:deprecated]
|
|
370
|
+
return :compatible unless result[:installed] && result[:latest]
|
|
331
371
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
372
|
+
no_compatible_update = result[:compatible].nil? || result[:compatible] <= result[:installed]
|
|
373
|
+
|
|
374
|
+
if result[:compatible] && result[:compatible] > result[:installed]
|
|
375
|
+
same_compat_line?(result[:installed], result[:compatible]) ? :updatable_safe : :updatable_breaking
|
|
376
|
+
elsif result[:latest] > result[:installed] && no_compatible_update
|
|
335
377
|
# A newer version exists, but none was found compatible with the
|
|
336
378
|
# current Ruby/Rails: updating means upgrading the framework too.
|
|
337
379
|
:updatable_breaking
|
|
@@ -342,24 +384,24 @@ module GemRadar
|
|
|
342
384
|
|
|
343
385
|
# --- Report -------------------------------------------------------------------
|
|
344
386
|
|
|
345
|
-
def format_gem_line(
|
|
346
|
-
parts = ["**#{
|
|
347
|
-
parts << "installed `#{
|
|
348
|
-
if
|
|
349
|
-
parts << "recommended `#{
|
|
387
|
+
def format_gem_line(result)
|
|
388
|
+
parts = ["**#{result[:name]}**"]
|
|
389
|
+
parts << "installed `#{result[:installed]}`" if result[:installed]
|
|
390
|
+
if result[:compatible] && result[:installed] && result[:compatible] > result[:installed]
|
|
391
|
+
parts << "recommended `#{result[:compatible]}`"
|
|
350
392
|
end
|
|
351
|
-
if
|
|
352
|
-
parts << "latest published `#{
|
|
393
|
+
if result[:latest] && (result[:compatible].nil? || result[:latest] > result[:compatible])
|
|
394
|
+
parts << "latest published `#{result[:latest]}`"
|
|
353
395
|
end
|
|
354
396
|
line = "- #{parts.join(' · ')}"
|
|
355
|
-
line += " — [repository](#{
|
|
356
|
-
line += "\n\n > #{
|
|
357
|
-
Array(
|
|
397
|
+
line += " — [repository](#{result[:repo_url]})" if result[:repo_url]
|
|
398
|
+
line += "\n\n > #{result[:error]}" if result[:error]
|
|
399
|
+
Array(result[:mandatory_reasons]).each { |reason| line += "\n\n > #{reason}" }
|
|
358
400
|
line
|
|
359
401
|
end
|
|
360
402
|
|
|
361
|
-
def build_report(project, ruby_version, rails_version, results,
|
|
362
|
-
grouped = results.group_by { |
|
|
403
|
+
def build_report(project, ruby_version, rails_version, results, _options)
|
|
404
|
+
grouped = results.group_by { |result| classify(result) }
|
|
363
405
|
|
|
364
406
|
lines = []
|
|
365
407
|
lines << "# Gems in #{project}"
|
|
@@ -381,12 +423,13 @@ module GemRadar
|
|
|
381
423
|
CATEGORY_ORDER.each do |cat|
|
|
382
424
|
items = grouped[cat]
|
|
383
425
|
next if items.nil? || items.empty?
|
|
426
|
+
|
|
384
427
|
lines << ""
|
|
385
428
|
lines << "## #{CATEGORY_TITLES[cat]}"
|
|
386
429
|
lines << ""
|
|
387
|
-
items.each { |
|
|
430
|
+
items.each { |result| lines << format_gem_line(result) }
|
|
388
431
|
end
|
|
389
|
-
lines.join("\n")
|
|
432
|
+
"#{lines.join("\n")}\n"
|
|
390
433
|
end
|
|
391
434
|
|
|
392
435
|
# --- Per-gem processing ------------------------------------------------------
|
|
@@ -403,7 +446,8 @@ module GemRadar
|
|
|
403
446
|
versions = rubygems_versions(name)
|
|
404
447
|
latest_runtime_deps = info.dig("dependencies", "runtime") || []
|
|
405
448
|
compatible = latest_compatible(name, versions, ruby_version, rails_version, latest_runtime_deps)
|
|
406
|
-
mandatory_reasons = mandatory_update_reasons(name, installed, versions, ruby_version, rails_version,
|
|
449
|
+
mandatory_reasons = mandatory_update_reasons(name, installed, versions, ruby_version, rails_version,
|
|
450
|
+
latest_runtime_deps)
|
|
407
451
|
|
|
408
452
|
url, repo = repo_url_for(info)
|
|
409
453
|
repo_info = repo && github_api("/repos/#{repo}")
|
data/lib/gem_radar/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,28 +1,34 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gem_radar
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Laura Jaime
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies: []
|
|
13
12
|
description: Reads a project's Gemfile.lock and reports, for each direct gem, whether
|
|
14
13
|
it's compatible with the project's Ruby/Rails, needs a mandatory update, is deprecated
|
|
15
14
|
or archived, or can be upgraded safely vs. with breaking changes.
|
|
16
|
-
email:
|
|
17
15
|
executables:
|
|
18
16
|
- gem_radar
|
|
19
17
|
extensions: []
|
|
20
18
|
extra_rdoc_files: []
|
|
21
19
|
files:
|
|
20
|
+
- ".github/PULL_REQUEST_TEMPLATE.md"
|
|
21
|
+
- ".github/workflows/ci.yml"
|
|
22
22
|
- ".gitignore"
|
|
23
|
+
- ".rspec"
|
|
24
|
+
- ".rubocop.yml"
|
|
25
|
+
- ".ruby-version"
|
|
23
26
|
- CHANGELOG.md
|
|
27
|
+
- Gemfile
|
|
28
|
+
- Gemfile.lock
|
|
24
29
|
- LICENSE
|
|
25
30
|
- README.md
|
|
31
|
+
- Rakefile
|
|
26
32
|
- assets/banner.png
|
|
27
33
|
- exe/gem_radar
|
|
28
34
|
- gem_radar.gemspec
|
|
@@ -34,7 +40,7 @@ licenses:
|
|
|
34
40
|
- MIT
|
|
35
41
|
metadata:
|
|
36
42
|
changelog_uri: https://github.com/laurajaime/gem_radar/blob/main/CHANGELOG.md
|
|
37
|
-
|
|
43
|
+
rubygems_mfa_required: 'true'
|
|
38
44
|
rdoc_options: []
|
|
39
45
|
require_paths:
|
|
40
46
|
- lib
|
|
@@ -42,15 +48,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
42
48
|
requirements:
|
|
43
49
|
- - ">="
|
|
44
50
|
- !ruby/object:Gem::Version
|
|
45
|
-
version:
|
|
51
|
+
version: 2.7.0
|
|
46
52
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
47
53
|
requirements:
|
|
48
54
|
- - ">="
|
|
49
55
|
- !ruby/object:Gem::Version
|
|
50
56
|
version: '0'
|
|
51
57
|
requirements: []
|
|
52
|
-
rubygems_version:
|
|
53
|
-
signing_key:
|
|
58
|
+
rubygems_version: 4.0.16
|
|
54
59
|
specification_version: 4
|
|
55
60
|
summary: Audits your Ruby/Rails project's gems and reports their compatibility and
|
|
56
61
|
update status.
|