gem_changelog_diff 0.3.0 → 0.4.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/README.md +19 -0
- data/ROADMAP.md +0 -13
- data/lib/gem_changelog_diff/cli.rb +41 -3
- data/lib/gem_changelog_diff/detector.rb +8 -1
- data/lib/gem_changelog_diff/lockfile_parser.rb +39 -0
- data/lib/gem_changelog_diff/rubygems_client.rb +15 -4
- data/lib/gem_changelog_diff/version.rb +1 -1
- data/lib/gem_changelog_diff.rb +1 -0
- data/sig/gem_changelog_diff.rbs +18 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 47e69603bad8c0641ed060fc572632c76d014dcc09f98d75322cafceefa4a1a2
|
|
4
|
+
data.tar.gz: beb52279aac1a12e5da0e19ce981d5b7bfa497a385130de9a7503cc4ac871742
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e5fa45dae9504354720cafa62e7e05768b58de06d1b0376496ba3e38b74b05dc7a23b10b3ca00338acca5e38ce2f29f17495d040d508fe6f14e03515cdf33a02
|
|
7
|
+
data.tar.gz: 537bea10e8961bff3b2d2c55530afcbe0de4fd0ab422c224b4d7b821edfe264821cb683e3d2a242d29cd551779d15a6c480e4269795347a25f190b59e56e886d
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.4.0] - 2026-06-18
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `Gemfile.lock` parsing via `Bundler::LockfileParser` with RubyGems API version lookup
|
|
15
|
+
- Automatic fallback to lockfile parsing when `bundle outdated` is unavailable
|
|
16
|
+
- `--strategy` flag: `auto` (default), `outdated`, or `lockfile`
|
|
17
|
+
- `--lockfile` flag for custom lockfile path
|
|
18
|
+
- Positional arguments to inspect specific gems: `gem_changelog_diff check rails sidekiq`
|
|
19
|
+
- `--group` flag to filter by Bundler group
|
|
20
|
+
- `--ignore` flag to exclude specific gems
|
|
21
|
+
|
|
10
22
|
## [0.3.0] - 2026-06-18
|
|
11
23
|
|
|
12
24
|
### Added
|
|
@@ -41,7 +53,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
41
53
|
- Plain text formatter for changelog output
|
|
42
54
|
- Full end-to-end pipeline: detect → lookup → fetch → format
|
|
43
55
|
|
|
44
|
-
[Unreleased]: https://github.com/eclectic-coding/gem_changelog_diff/compare/v0.
|
|
56
|
+
[Unreleased]: https://github.com/eclectic-coding/gem_changelog_diff/compare/v0.4.0...HEAD
|
|
57
|
+
[0.4.0]: https://github.com/eclectic-coding/gem_changelog_diff/releases/tag/v0.4.0
|
|
45
58
|
[0.3.0]: https://github.com/eclectic-coding/gem_changelog_diff/releases/tag/v0.3.0
|
|
46
59
|
[0.2.0]: https://github.com/eclectic-coding/gem_changelog_diff/releases/tag/v0.2.0
|
|
47
60
|
[0.1.0]: https://github.com/eclectic-coding/gem_changelog_diff/releases/tag/v0.1.0
|
data/README.md
CHANGED
|
@@ -14,6 +14,8 @@ CLI that shows you the changelog diff for each gem before you `bundle update`, p
|
|
|
14
14
|
- [Usage](#usage)
|
|
15
15
|
- [GitHub Authentication](#github-authentication)
|
|
16
16
|
- [Output Control](#output-control)
|
|
17
|
+
- [Detection Strategy](#detection-strategy)
|
|
18
|
+
- [Filtering](#filtering)
|
|
17
19
|
- [Development](#development)
|
|
18
20
|
- [Contributing](#contributing)
|
|
19
21
|
- [License](#license)
|
|
@@ -68,6 +70,23 @@ gem_changelog_diff --no-color # Disable colored output
|
|
|
68
70
|
|
|
69
71
|
The tool also respects the `$NO_COLOR` environment variable.
|
|
70
72
|
|
|
73
|
+
### Detection Strategy
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
gem_changelog_diff --strategy lockfile # Parse Gemfile.lock directly
|
|
77
|
+
gem_changelog_diff --strategy outdated # Use bundle outdated only
|
|
78
|
+
gem_changelog_diff --strategy auto # Try bundle outdated, fallback to lockfile (default)
|
|
79
|
+
gem_changelog_diff --lockfile path/to/Gemfile.lock # Custom lockfile path
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Filtering
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
gem_changelog_diff check rails sidekiq # Only check specific gems
|
|
86
|
+
gem_changelog_diff --group development # Filter by Bundler group
|
|
87
|
+
gem_changelog_diff --ignore rails rake # Exclude specific gems
|
|
88
|
+
```
|
|
89
|
+
|
|
71
90
|
[Back to top](#gemchangelogdiff)
|
|
72
91
|
|
|
73
92
|
## Development
|
data/ROADMAP.md
CHANGED
|
@@ -2,19 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
Feature roadmap for gem_changelog_diff. Each section is auto-pruned by `bin/release` when that version ships.
|
|
4
4
|
|
|
5
|
-
## 0.4.0 -- Lockfile Parsing Fallback & Filtering
|
|
6
|
-
|
|
7
|
-
Support environments where `bundle outdated` is unavailable. Let users narrow which gems to inspect.
|
|
8
|
-
|
|
9
|
-
- Parse `Gemfile.lock` directly via `Bundler::LockfileParser` and query RubyGems API for latest versions
|
|
10
|
-
- Automatic fallback when `bundle outdated` fails
|
|
11
|
-
- Positional args to inspect specific gems: `gem_changelog_diff check rails sidekiq`
|
|
12
|
-
- `--group`, `--ignore`, `--lockfile`, `--strategy` flags
|
|
13
|
-
|
|
14
|
-
**New files:** `lockfile_parser.rb`
|
|
15
|
-
|
|
16
|
-
---
|
|
17
|
-
|
|
18
5
|
## 0.5.0 -- Caching & Performance
|
|
19
6
|
|
|
20
7
|
Avoid redundant API calls. Make repeated runs fast on large dependency trees.
|
|
@@ -14,11 +14,16 @@ module GemChangelogDiff
|
|
|
14
14
|
class_option :verbose, type: :boolean, default: false, desc: "Show detailed output"
|
|
15
15
|
class_option :quiet, type: :boolean, default: false, desc: "Suppress warnings"
|
|
16
16
|
class_option :no_color, type: :boolean, default: false, desc: "Disable colored output"
|
|
17
|
+
class_option :lockfile, type: :string, desc: "Path to Gemfile.lock"
|
|
18
|
+
class_option :strategy, type: :string, default: "auto", desc: "Detection strategy (auto, outdated, lockfile)"
|
|
19
|
+
class_option :group, type: :string, desc: "Filter by Bundler group"
|
|
20
|
+
class_option :ignore, type: :array, desc: "Gems to skip"
|
|
17
21
|
|
|
18
|
-
desc "check", "Show changelog diffs for outdated gems"
|
|
19
|
-
def check
|
|
22
|
+
desc "check [GEM...]", "Show changelog diffs for outdated gems"
|
|
23
|
+
def check(*gem_names)
|
|
20
24
|
configure_token
|
|
21
|
-
gems =
|
|
25
|
+
gems = detect_gems
|
|
26
|
+
gems = filter_gems(gems, gem_names)
|
|
22
27
|
|
|
23
28
|
if gems.empty?
|
|
24
29
|
say "All gems are up to date!"
|
|
@@ -44,6 +49,39 @@ module GemChangelogDiff
|
|
|
44
49
|
GemChangelogDiff.configuration.github_token = token if token
|
|
45
50
|
end
|
|
46
51
|
|
|
52
|
+
def detect_gems
|
|
53
|
+
case options[:strategy]
|
|
54
|
+
when "lockfile"
|
|
55
|
+
detect_via_lockfile
|
|
56
|
+
when "outdated"
|
|
57
|
+
Detector.new(group: options[:group]).detect
|
|
58
|
+
else
|
|
59
|
+
detect_with_fallback
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def detect_with_fallback
|
|
64
|
+
Detector.new(group: options[:group]).detect
|
|
65
|
+
rescue Error
|
|
66
|
+
log_warning " bundle outdated failed, falling back to lockfile parsing..."
|
|
67
|
+
detect_via_lockfile
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def detect_via_lockfile
|
|
71
|
+
lockfile_path = options[:lockfile] || "Gemfile.lock"
|
|
72
|
+
LockfileParser.new.detect(lockfile_path: lockfile_path)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def filter_gems(gems, gem_names)
|
|
76
|
+
gems = gems.select { |g| gem_names.include?(g.name) } if gem_names.any?
|
|
77
|
+
gems = gems.reject { |g| ignore_list.include?(g.name) } if ignore_list.any?
|
|
78
|
+
gems
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def ignore_list
|
|
82
|
+
@ignore_list ||= options[:ignore] || []
|
|
83
|
+
end
|
|
84
|
+
|
|
47
85
|
def build_reports(gems)
|
|
48
86
|
rubygems_client = RubygemsClient.new
|
|
49
87
|
source_resolver = SourceResolver.new
|
|
@@ -13,8 +13,15 @@ module GemChangelogDiff
|
|
|
13
13
|
|
|
14
14
|
private
|
|
15
15
|
|
|
16
|
+
def initialize(group: nil)
|
|
17
|
+
@group = group
|
|
18
|
+
end
|
|
19
|
+
|
|
16
20
|
def run_bundle_outdated
|
|
17
|
-
|
|
21
|
+
cmd = ["bundle", "outdated", "--parseable"]
|
|
22
|
+
cmd.push("--group", @group) if @group
|
|
23
|
+
|
|
24
|
+
output, status = Open3.capture2(*cmd)
|
|
18
25
|
raise Error, "bundle outdated failed (exit #{status.exitstatus})" unless [0, 1].include?(status.exitstatus)
|
|
19
26
|
|
|
20
27
|
output
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler"
|
|
4
|
+
|
|
5
|
+
module GemChangelogDiff
|
|
6
|
+
class LockfileParser
|
|
7
|
+
def initialize(rubygems_client: RubygemsClient.new)
|
|
8
|
+
@rubygems_client = rubygems_client
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def detect(lockfile_path: "Gemfile.lock")
|
|
12
|
+
content = File.read(lockfile_path)
|
|
13
|
+
parser = Bundler::LockfileParser.new(content)
|
|
14
|
+
find_outdated(parser.specs)
|
|
15
|
+
rescue Errno::ENOENT
|
|
16
|
+
raise Error, "Lockfile not found: #{lockfile_path}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def find_outdated(specs)
|
|
22
|
+
specs.filter_map { |spec| check_gem(spec) }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def check_gem(spec)
|
|
26
|
+
latest = @rubygems_client.latest_version(spec.name)
|
|
27
|
+
return nil unless latest
|
|
28
|
+
|
|
29
|
+
latest_version = Gem::Version.new(latest)
|
|
30
|
+
return nil unless latest_version > spec.version
|
|
31
|
+
|
|
32
|
+
OutdatedGem.new(
|
|
33
|
+
name: spec.name,
|
|
34
|
+
current_version: spec.version.to_s,
|
|
35
|
+
newest_version: latest
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -9,19 +9,30 @@ module GemChangelogDiff
|
|
|
9
9
|
GITHUB_REPO_REGEX = %r{github\.com/([^/]+)/([^/]+)}
|
|
10
10
|
|
|
11
11
|
def repo_url(gem_name)
|
|
12
|
+
data = fetch_gem_data(gem_name)
|
|
13
|
+
return nil unless data
|
|
14
|
+
|
|
15
|
+
extract_github_repo(data)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def latest_version(gem_name)
|
|
19
|
+
data = fetch_gem_data(gem_name)
|
|
20
|
+
data&.dig("version")
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def fetch_gem_data(gem_name)
|
|
12
26
|
uri = URI(format(RUBYGEMS_API, name: gem_name))
|
|
13
27
|
response = Net::HTTP.get_response(uri)
|
|
14
28
|
return nil unless response.is_a?(Net::HTTPSuccess)
|
|
15
29
|
|
|
16
|
-
|
|
17
|
-
extract_github_repo(data)
|
|
30
|
+
JSON.parse(response.body)
|
|
18
31
|
rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH,
|
|
19
32
|
Net::OpenTimeout, Net::ReadTimeout => e
|
|
20
33
|
raise NetworkError, "RubyGems API request failed: #{e.message}"
|
|
21
34
|
end
|
|
22
35
|
|
|
23
|
-
private
|
|
24
|
-
|
|
25
36
|
def extract_github_repo(data)
|
|
26
37
|
%w[source_code_uri homepage_uri bug_tracker_uri].each do |field|
|
|
27
38
|
url = data[field]
|
data/lib/gem_changelog_diff.rb
CHANGED
|
@@ -11,6 +11,7 @@ require_relative "gem_changelog_diff/errors"
|
|
|
11
11
|
require_relative "gem_changelog_diff/outdated_gem"
|
|
12
12
|
require_relative "gem_changelog_diff/detector"
|
|
13
13
|
require_relative "gem_changelog_diff/rubygems_client"
|
|
14
|
+
require_relative "gem_changelog_diff/lockfile_parser"
|
|
14
15
|
require_relative "gem_changelog_diff/github_client"
|
|
15
16
|
require_relative "gem_changelog_diff/changelog_parser"
|
|
16
17
|
require_relative "gem_changelog_diff/source_resolver"
|
data/sig/gem_changelog_diff.rbs
CHANGED
|
@@ -37,6 +37,7 @@ module GemChangelogDiff
|
|
|
37
37
|
class Detector
|
|
38
38
|
PARSEABLE_REGEX: Regexp
|
|
39
39
|
|
|
40
|
+
def initialize: (?group: String?) -> void
|
|
40
41
|
def detect: () -> Array[OutdatedGem]
|
|
41
42
|
|
|
42
43
|
private
|
|
@@ -50,12 +51,24 @@ module GemChangelogDiff
|
|
|
50
51
|
GITHUB_REPO_REGEX: Regexp
|
|
51
52
|
|
|
52
53
|
def repo_url: (String gem_name) -> String?
|
|
54
|
+
def latest_version: (String gem_name) -> String?
|
|
53
55
|
|
|
54
56
|
private
|
|
55
57
|
|
|
58
|
+
def fetch_gem_data: (String gem_name) -> Hash[String, untyped]?
|
|
56
59
|
def extract_github_repo: (Hash[String, untyped] data) -> String?
|
|
57
60
|
end
|
|
58
61
|
|
|
62
|
+
class LockfileParser
|
|
63
|
+
def initialize: (?rubygems_client: RubygemsClient) -> void
|
|
64
|
+
def detect: (?lockfile_path: String) -> Array[OutdatedGem]
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
def find_outdated: (Array[untyped] specs) -> Array[OutdatedGem]
|
|
69
|
+
def check_gem: (untyped spec) -> OutdatedGem?
|
|
70
|
+
end
|
|
71
|
+
|
|
59
72
|
type release_hash = {
|
|
60
73
|
tag_name: String,
|
|
61
74
|
name: String?,
|
|
@@ -143,6 +156,11 @@ module GemChangelogDiff
|
|
|
143
156
|
|
|
144
157
|
def color_enabled?: () -> bool
|
|
145
158
|
def configure_token: () -> void
|
|
159
|
+
def detect_gems: () -> Array[OutdatedGem]
|
|
160
|
+
def detect_with_fallback: () -> Array[OutdatedGem]
|
|
161
|
+
def detect_via_lockfile: () -> Array[OutdatedGem]
|
|
162
|
+
def filter_gems: (Array[OutdatedGem] gems, Array[String] gem_names) -> Array[OutdatedGem]
|
|
163
|
+
def ignore_list: () -> Array[String]
|
|
146
164
|
def build_reports: (Array[OutdatedGem] gems) -> Array[gem_report]
|
|
147
165
|
def build_gem_report: (OutdatedGem gem, RubygemsClient rubygems_client, SourceResolver source_resolver) -> gem_report
|
|
148
166
|
def log: (String message) -> void
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gem_changelog_diff
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Chuck Smith
|
|
@@ -64,6 +64,7 @@ files:
|
|
|
64
64
|
- lib/gem_changelog_diff/errors.rb
|
|
65
65
|
- lib/gem_changelog_diff/formatter.rb
|
|
66
66
|
- lib/gem_changelog_diff/github_client.rb
|
|
67
|
+
- lib/gem_changelog_diff/lockfile_parser.rb
|
|
67
68
|
- lib/gem_changelog_diff/outdated_gem.rb
|
|
68
69
|
- lib/gem_changelog_diff/rubygems_client.rb
|
|
69
70
|
- lib/gem_changelog_diff/source_resolver.rb
|