gem_changelog_diff 0.1.0 → 0.2.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 +16 -0
- data/README.md +18 -0
- data/ROADMAP.md +0 -14
- data/lib/gem_changelog_diff/cli.rb +23 -0
- data/lib/gem_changelog_diff/configuration.rb +19 -0
- data/lib/gem_changelog_diff/errors.rb +8 -0
- data/lib/gem_changelog_diff/github_client.rb +32 -3
- data/lib/gem_changelog_diff/rubygems_client.rb +3 -0
- data/lib/gem_changelog_diff/version.rb +1 -1
- data/lib/gem_changelog_diff.rb +7 -4
- data/sig/gem_changelog_diff.rbs +29 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 157c1e084602c25e10cec4fde2c24b1999a9894ebe1232901cb9536bae50f33b
|
|
4
|
+
data.tar.gz: aa0be940c412f3b1a9b3ee08190d8a6e64ad0bed9cf1b2011979650b87264640
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0714bc35cee74f49ac0b09cda00e58b931c90a9f0a7688e122f5c8f2c790aedd269244d6e5a0af2dd538a33e8a91e2f8024b313f2c94b6227a4b3fa6901a160c
|
|
7
|
+
data.tar.gz: 8fb0ab418ac9c7e42adfd240360594ef1134536fe9ffa04a2dad8052d3355620d79d224b8f4342336bf853875ac60491ed6968ad8d105860dd770bccb6682fae
|
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.2.0] - 2026-06-17
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- GitHub personal access token support via `--token` flag or `GITHUB_TOKEN` env var
|
|
15
|
+
- `Configuration` singleton for managing runtime settings
|
|
16
|
+
- Custom error hierarchy: `RepoNotFoundError`, `GitHubAPIError`, `RateLimitError`, `NetworkError`
|
|
17
|
+
- Graceful degradation: failed gems are skipped with a warning instead of aborting
|
|
18
|
+
- Rate limit awareness: warns when GitHub API requests remaining drops below 10
|
|
19
|
+
- `--verbose` flag for detailed status output
|
|
20
|
+
- `--quiet` flag to suppress warnings
|
|
21
|
+
|
|
10
22
|
## [0.1.0] - 2026-06-17
|
|
11
23
|
|
|
12
24
|
### Added
|
|
@@ -18,3 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
18
30
|
- GitHub API client to fetch releases between locked and latest versions
|
|
19
31
|
- Plain text formatter for changelog output
|
|
20
32
|
- Full end-to-end pipeline: detect → lookup → fetch → format
|
|
33
|
+
|
|
34
|
+
[Unreleased]: https://github.com/eclectic-coding/gem_changelog_diff/compare/v0.2.0...HEAD
|
|
35
|
+
[0.2.0]: https://github.com/eclectic-coding/gem_changelog_diff/releases/tag/v0.2.0
|
|
36
|
+
[0.1.0]: https://github.com/eclectic-coding/gem_changelog_diff/releases/tag/v0.1.0
|
data/README.md
CHANGED
|
@@ -35,6 +35,24 @@ gem_changelog_diff version # Print version
|
|
|
35
35
|
gem_changelog_diff --version # Same as above
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
+
### GitHub Authentication
|
|
39
|
+
|
|
40
|
+
To avoid the 60 requests/hour unauthenticated rate limit, provide a GitHub personal access token:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
gem_changelog_diff --token ghp_your_token
|
|
44
|
+
# or
|
|
45
|
+
export GITHUB_TOKEN=ghp_your_token
|
|
46
|
+
gem_changelog_diff
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Output Control
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
gem_changelog_diff --verbose # Show detailed status messages
|
|
53
|
+
gem_changelog_diff --quiet # Suppress warnings
|
|
54
|
+
```
|
|
55
|
+
|
|
38
56
|
## Development
|
|
39
57
|
|
|
40
58
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/ROADMAP.md
CHANGED
|
@@ -2,20 +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.2.0 -- Error Handling & GitHub Authentication
|
|
6
|
-
|
|
7
|
-
Handle real-world failures and unblock power users hitting the 60 req/hr unauthenticated rate limit.
|
|
8
|
-
|
|
9
|
-
- GitHub personal access token via `--token` flag or `GITHUB_TOKEN` env var
|
|
10
|
-
- Custom error hierarchy (`RepoNotFoundError`, `GitHubAPIError`, `RateLimitError`, `NetworkError`)
|
|
11
|
-
- Graceful degradation: skip failed gems with a warning, do not abort the run
|
|
12
|
-
- Rate limit awareness: read `X-RateLimit-Remaining` headers, warn when approaching the limit
|
|
13
|
-
- `--verbose` and `--quiet` flags
|
|
14
|
-
|
|
15
|
-
**New files:** `errors.rb`, `configuration.rb`
|
|
16
|
-
|
|
17
|
-
---
|
|
18
|
-
|
|
19
5
|
## 0.3.0 -- CHANGELOG.md Fallback & Colored Output
|
|
20
6
|
|
|
21
7
|
Many gems do not use GitHub Releases. Fall back to parsing CHANGELOG.md from the repository.
|
|
@@ -10,8 +10,13 @@ module GemChangelogDiff
|
|
|
10
10
|
|
|
11
11
|
default_task :check
|
|
12
12
|
|
|
13
|
+
class_option :token, type: :string, desc: "GitHub personal access token"
|
|
14
|
+
class_option :verbose, type: :boolean, default: false, desc: "Show detailed output"
|
|
15
|
+
class_option :quiet, type: :boolean, default: false, desc: "Suppress warnings"
|
|
16
|
+
|
|
13
17
|
desc "check", "Show changelog diffs for outdated gems"
|
|
14
18
|
def check
|
|
19
|
+
configure_token
|
|
15
20
|
gems = Detector.new.detect
|
|
16
21
|
|
|
17
22
|
if gems.empty?
|
|
@@ -32,6 +37,11 @@ module GemChangelogDiff
|
|
|
32
37
|
|
|
33
38
|
private
|
|
34
39
|
|
|
40
|
+
def configure_token
|
|
41
|
+
token = options[:token] || ENV.fetch("GITHUB_TOKEN", nil)
|
|
42
|
+
GemChangelogDiff.configuration.github_token = token if token
|
|
43
|
+
end
|
|
44
|
+
|
|
35
45
|
def build_reports(gems)
|
|
36
46
|
rubygems_client = RubygemsClient.new
|
|
37
47
|
github_client = GithubClient.new
|
|
@@ -40,11 +50,24 @@ module GemChangelogDiff
|
|
|
40
50
|
end
|
|
41
51
|
|
|
42
52
|
def build_gem_report(gem, rubygems_client, github_client)
|
|
53
|
+
log "Checking #{gem.name}..."
|
|
43
54
|
repo = rubygems_client.repo_url(gem.name)
|
|
44
55
|
return { gem: gem, releases: [], error: " Could not find GitHub repository." } if repo.nil?
|
|
45
56
|
|
|
57
|
+
log " Found repo: #{repo}"
|
|
46
58
|
releases = github_client.releases_between(repo, gem.current_version, gem.newest_version)
|
|
47
59
|
{ gem: gem, releases: releases }
|
|
60
|
+
rescue GemChangelogDiff::Error => e
|
|
61
|
+
log_warning " Skipping #{gem.name}: #{e.message}"
|
|
62
|
+
{ gem: gem, releases: [], error: " #{e.message}" }
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def log(message)
|
|
66
|
+
warn message if options[:verbose]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def log_warning(message)
|
|
70
|
+
warn message unless options[:quiet]
|
|
48
71
|
end
|
|
49
72
|
end
|
|
50
73
|
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GemChangelogDiff
|
|
4
|
+
class Configuration
|
|
5
|
+
attr_accessor :github_token
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def self.configuration
|
|
9
|
+
@configuration ||= Configuration.new
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.configure
|
|
13
|
+
yield(configuration)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.reset_configuration!
|
|
17
|
+
@configuration = Configuration.new
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -7,6 +7,7 @@ module GemChangelogDiff
|
|
|
7
7
|
class GithubClient
|
|
8
8
|
RELEASES_URL = "https://api.github.com/repos/%<repo>s/releases"
|
|
9
9
|
TAG_VERSION_REGEX = /\Av?(\d+\..+)\z/
|
|
10
|
+
RATE_LIMIT_WARNING_THRESHOLD = 10
|
|
10
11
|
|
|
11
12
|
def releases_between(repo, current_version, newest_version)
|
|
12
13
|
releases = fetch_releases(repo)
|
|
@@ -19,19 +20,47 @@ module GemChangelogDiff
|
|
|
19
20
|
uri = URI(format(RELEASES_URL, repo: repo))
|
|
20
21
|
uri.query = URI.encode_www_form(per_page: 30)
|
|
21
22
|
|
|
23
|
+
response = execute_request(uri)
|
|
24
|
+
check_rate_limit(response)
|
|
25
|
+
handle_response(response)
|
|
26
|
+
rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH,
|
|
27
|
+
Net::OpenTimeout, Net::ReadTimeout => e
|
|
28
|
+
raise NetworkError, "GitHub API request failed: #{e.message}"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def execute_request(uri)
|
|
22
32
|
request = Net::HTTP::Get.new(uri)
|
|
23
33
|
request["Accept"] = "application/vnd.github.v3+json"
|
|
24
34
|
request["User-Agent"] = "gem_changelog_diff/#{VERSION}"
|
|
35
|
+
apply_auth(request)
|
|
36
|
+
|
|
37
|
+
Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def apply_auth(request)
|
|
41
|
+
token = GemChangelogDiff.configuration.github_token
|
|
42
|
+
request["Authorization"] = "token #{token}" if token
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def handle_response(response)
|
|
46
|
+
return [] if response.code == "404"
|
|
25
47
|
|
|
26
|
-
response
|
|
27
|
-
|
|
48
|
+
if response.code == "403" && response["X-RateLimit-Remaining"] == "0"
|
|
49
|
+
raise RateLimitError, "GitHub API rate limit exceeded. Use --token to authenticate."
|
|
28
50
|
end
|
|
29
51
|
|
|
30
|
-
|
|
52
|
+
raise GitHubAPIError, "GitHub API error (HTTP #{response.code})" unless response.is_a?(Net::HTTPSuccess)
|
|
31
53
|
|
|
32
54
|
JSON.parse(response.body)
|
|
33
55
|
end
|
|
34
56
|
|
|
57
|
+
def check_rate_limit(response)
|
|
58
|
+
remaining = response["X-RateLimit-Remaining"]&.to_i
|
|
59
|
+
return if remaining.nil? || remaining >= RATE_LIMIT_WARNING_THRESHOLD
|
|
60
|
+
|
|
61
|
+
warn "Warning: GitHub API rate limit low (#{remaining} requests remaining). Use --token to authenticate."
|
|
62
|
+
end
|
|
63
|
+
|
|
35
64
|
def filter_releases(releases, current_version, newest_version)
|
|
36
65
|
current = Gem::Version.new(current_version)
|
|
37
66
|
newest = Gem::Version.new(newest_version)
|
|
@@ -15,6 +15,9 @@ module GemChangelogDiff
|
|
|
15
15
|
|
|
16
16
|
data = JSON.parse(response.body)
|
|
17
17
|
extract_github_repo(data)
|
|
18
|
+
rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH,
|
|
19
|
+
Net::OpenTimeout, Net::ReadTimeout => e
|
|
20
|
+
raise NetworkError, "RubyGems API request failed: #{e.message}"
|
|
18
21
|
end
|
|
19
22
|
|
|
20
23
|
private
|
data/lib/gem_changelog_diff.rb
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "gem_changelog_diff/version"
|
|
4
|
+
require_relative "gem_changelog_diff/configuration"
|
|
5
|
+
|
|
6
|
+
module GemChangelogDiff
|
|
7
|
+
class Error < StandardError; end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
require_relative "gem_changelog_diff/errors"
|
|
4
11
|
require_relative "gem_changelog_diff/outdated_gem"
|
|
5
12
|
require_relative "gem_changelog_diff/detector"
|
|
6
13
|
require_relative "gem_changelog_diff/rubygems_client"
|
|
7
14
|
require_relative "gem_changelog_diff/github_client"
|
|
8
15
|
require_relative "gem_changelog_diff/formatter"
|
|
9
16
|
require_relative "gem_changelog_diff/cli"
|
|
10
|
-
|
|
11
|
-
module GemChangelogDiff
|
|
12
|
-
class Error < StandardError; end
|
|
13
|
-
end
|
data/sig/gem_changelog_diff.rbs
CHANGED
|
@@ -1,9 +1,31 @@
|
|
|
1
1
|
module GemChangelogDiff
|
|
2
2
|
VERSION: String
|
|
3
3
|
|
|
4
|
+
self.@configuration: Configuration
|
|
5
|
+
|
|
6
|
+
def self.configuration: () -> Configuration
|
|
7
|
+
def self.configure: () { (Configuration) -> void } -> void
|
|
8
|
+
def self.reset_configuration!: () -> Configuration
|
|
9
|
+
|
|
4
10
|
class Error < StandardError
|
|
5
11
|
end
|
|
6
12
|
|
|
13
|
+
class RepoNotFoundError < Error
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class GitHubAPIError < Error
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
class RateLimitError < GitHubAPIError
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
class NetworkError < Error
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
class Configuration
|
|
26
|
+
attr_accessor github_token: String?
|
|
27
|
+
end
|
|
28
|
+
|
|
7
29
|
class OutdatedGem
|
|
8
30
|
attr_reader name: String
|
|
9
31
|
attr_reader current_version: String
|
|
@@ -50,6 +72,10 @@ module GemChangelogDiff
|
|
|
50
72
|
private
|
|
51
73
|
|
|
52
74
|
def fetch_releases: (String repo) -> Array[Hash[String, untyped]]
|
|
75
|
+
def execute_request: (URI::Generic uri) -> Net::HTTPResponse
|
|
76
|
+
def apply_auth: (Net::HTTPRequest request) -> void
|
|
77
|
+
def handle_response: (Net::HTTPResponse response) -> Array[Hash[String, untyped]]
|
|
78
|
+
def check_rate_limit: (Net::HTTPResponse response) -> void
|
|
53
79
|
def filter_releases: (Array[Hash[String, untyped]] releases, String current_version, String newest_version) -> Array[release_hash]
|
|
54
80
|
def build_release: (Hash[String, untyped] release, Gem::Version current, Gem::Version newest) -> release_hash?
|
|
55
81
|
def sort_releases: (Array[release_hash] releases) -> Array[release_hash]
|
|
@@ -79,7 +105,10 @@ module GemChangelogDiff
|
|
|
79
105
|
|
|
80
106
|
private
|
|
81
107
|
|
|
108
|
+
def configure_token: () -> void
|
|
82
109
|
def build_reports: (Array[OutdatedGem] gems) -> Array[gem_report]
|
|
83
110
|
def build_gem_report: (OutdatedGem gem, RubygemsClient rubygems_client, GithubClient github_client) -> gem_report
|
|
111
|
+
def log: (String message) -> void
|
|
112
|
+
def log_warning: (String message) -> void
|
|
84
113
|
end
|
|
85
114
|
end
|
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.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Chuck Smith
|
|
@@ -44,7 +44,9 @@ files:
|
|
|
44
44
|
- exe/gem_changelog_diff
|
|
45
45
|
- lib/gem_changelog_diff.rb
|
|
46
46
|
- lib/gem_changelog_diff/cli.rb
|
|
47
|
+
- lib/gem_changelog_diff/configuration.rb
|
|
47
48
|
- lib/gem_changelog_diff/detector.rb
|
|
49
|
+
- lib/gem_changelog_diff/errors.rb
|
|
48
50
|
- lib/gem_changelog_diff/formatter.rb
|
|
49
51
|
- lib/gem_changelog_diff/github_client.rb
|
|
50
52
|
- lib/gem_changelog_diff/outdated_gem.rb
|