gem_changelog_diff 0.6.0 → 0.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c58884878cc207c11af411418fb33ec4390458388c078e83197c0cad35f1b50d
4
- data.tar.gz: 73f6403bc48d9a991d67d7f3da53e327acd08c004fefc3813729794dd2438112
3
+ metadata.gz: cb1f64ee5cd989dcb791da00dde70d752f297d0cc640e455cac541eedf09bc8b
4
+ data.tar.gz: 303b4fa0ce947b0ad9dab918294674f8fb90881c9017d30279e6afbf8e02ca03
5
5
  SHA512:
6
- metadata.gz: 231a6934a5924d3b192261bb22e9dfbf419b439e3332cb0d05623bcba85e7a712a49155351c216e36c4fd5e43d3055780fa2ef16d2e644892dc8bfcff8d6eae3
7
- data.tar.gz: 740990db45157a3661635beb030fa8e57885e9da9e0373ffe1d0c3a847ace03ef7b7219ce1baac7da85d568d24091eccd67859f3079ded0e49812780cebde030
6
+ metadata.gz: 7f9897600fc4fd863d2f99d2152c6e2c4ae68669be8ec6fa37e824356dd952cd80367742587a91a53e13ffd6e1b4d5bbe7cc435e2fe96aac4970b9fe6dc9b443
7
+ data.tar.gz: c3f9b5411ac024a224b0f0b25926a2f33dda76cf6a1a5689831c4a616788aa8659310a68bd379558ee9ed1fe9e5eeb2166127953147f8b30580d4be0a36d3453
data/CHANGELOG.md CHANGED
@@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.7.0] - 2026-06-18
11
+
12
+ ### Added
13
+
14
+ - YAML config file support: `.gem_changelog_diff.yml` (project) and `~/.config/gem_changelog_diff/config.yml` (user)
15
+ - Supported config keys: `github_token`, `default_format`, `cache_ttl`, `concurrency`, `ignore_gems`, `no_color`
16
+ - `init` subcommand: generate a commented config file template
17
+ - Config file token used as fallback when `--token` and `GITHUB_TOKEN` are not set
18
+ - `--dry-run` flag: show which gems would be checked without fetching changelogs
19
+ - Dry-run output respects `--format` flag (text, JSON, markdown)
20
+ - Rails credentials token support: reads from `Rails.application.credentials.dig(:gem_changelog_diff, :github_token)` when running inside a Rails app
21
+ - Token priority: `--token` flag → `GITHUB_TOKEN` env → Rails credentials → config file
22
+
10
23
  ## [0.6.0] - 2026-06-18
11
24
 
12
25
  ### Added
@@ -76,7 +89,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
76
89
  - Plain text formatter for changelog output
77
90
  - Full end-to-end pipeline: detect → lookup → fetch → format
78
91
 
79
- [Unreleased]: https://github.com/eclectic-coding/gem_changelog_diff/compare/v0.6.0...HEAD
92
+ [Unreleased]: https://github.com/eclectic-coding/gem_changelog_diff/compare/v0.7.0...HEAD
93
+ [0.7.0]: https://github.com/eclectic-coding/gem_changelog_diff/releases/tag/v0.7.0
80
94
  [0.6.0]: https://github.com/eclectic-coding/gem_changelog_diff/releases/tag/v0.6.0
81
95
  [0.5.0]: https://github.com/eclectic-coding/gem_changelog_diff/releases/tag/v0.5.0
82
96
  [0.4.0]: https://github.com/eclectic-coding/gem_changelog_diff/releases/tag/v0.4.0
data/README.md CHANGED
@@ -20,6 +20,8 @@ CLI that shows you the changelog diff for each gem before you `bundle update`, p
20
20
  - [Interactive Mode](#interactive-mode)
21
21
  - [Show Subcommand](#show-subcommand)
22
22
  - [Caching](#caching)
23
+ - [Dry Run](#dry-run)
24
+ - [Configuration File](#configuration-file)
23
25
  - [Development](#development)
24
26
  - [Contributing](#contributing)
25
27
  - [License](#license)
@@ -64,6 +66,23 @@ export GITHUB_TOKEN=ghp_your_token
64
66
  gem_changelog_diff
65
67
  ```
66
68
 
69
+ Token resolution priority: `--token` flag → `GITHUB_TOKEN` env → Rails credentials → config file.
70
+
71
+ #### Rails Credentials
72
+
73
+ When running inside a Rails app, the token is automatically read from Rails credentials:
74
+
75
+ ```ruby
76
+ Rails.application.credentials.dig(:gem_changelog_diff, :github_token)
77
+ ```
78
+
79
+ Set it via `rails credentials:edit`:
80
+
81
+ ```yaml
82
+ gem_changelog_diff:
83
+ github_token: ghp_your_token
84
+ ```
85
+
67
86
  ### Output Formats
68
87
 
69
88
  ```bash
@@ -128,6 +147,44 @@ gem_changelog_diff --cache-ttl 3600 # Set TTL to 1 hour
128
147
  gem_changelog_diff cache clear # Clear all cached data
129
148
  ```
130
149
 
150
+ ### Dry Run
151
+
152
+ Preview which gems would be checked without fetching changelogs:
153
+
154
+ ```bash
155
+ gem_changelog_diff --dry-run # List gems in text format
156
+ gem_changelog_diff --dry-run --format json # JSON array of gem objects
157
+ gem_changelog_diff --dry-run --format markdown # Markdown bullet list
158
+ ```
159
+
160
+ ### Configuration File
161
+
162
+ Generate a config file template:
163
+
164
+ ```bash
165
+ gem_changelog_diff init # Creates .gem_changelog_diff.yml
166
+ ```
167
+
168
+ The tool loads settings from two locations (project overrides user):
169
+
170
+ 1. `~/.config/gem_changelog_diff/config.yml` (user-level defaults)
171
+ 2. `.gem_changelog_diff.yml` (project-level overrides)
172
+
173
+ Supported keys:
174
+
175
+ ```yaml
176
+ github_token: ghp_xxx
177
+ default_format: text # text, json, markdown
178
+ cache_ttl: 86400 # seconds (default: 24 hours)
179
+ concurrency: 4
180
+ ignore_gems:
181
+ - rake
182
+ - bundler
183
+ no_color: false
184
+ ```
185
+
186
+ CLI flags always take priority over config file values.
187
+
131
188
  [Back to top](#gemchangelogdiff)
132
189
 
133
190
  ## Development
data/ROADMAP.md CHANGED
@@ -2,21 +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.7.0 -- Configuration File & Polish
6
-
7
- Persistent preferences so users don't repeat flags every run.
8
-
9
- - Config file: `.gem_changelog_diff.yml` (project root) and `~/.config/gem_changelog_diff/config.yml` (user); project overrides user
10
- - Supported keys: `github_token`, `default_format`, `cache_ttl`, `concurrency`, `ignore_gems`, `no_color`
11
- - `init` subcommand: generate a commented config template
12
- - `version` subcommand
13
- - `--dry-run` flag: show which gems would be checked without fetching
14
- - Rails credentials support: read token from `Rails.application.credentials.dig(:gem_changelog_diff, :github_token)` when running inside a Rails app
15
-
16
- **New files:** `config_loader.rb`
17
-
18
- ---
19
-
20
5
  ## 0.8.0 -- Robustness & Edge Cases
21
6
 
22
7
  Handle the long tail of real-world gem repository patterns.
@@ -25,9 +25,11 @@ module GemChangelogDiff
25
25
  class_option :output, type: :string, desc: "Write output to file instead of stdout"
26
26
  class_option :interactive, type: :boolean, default: false, aliases: "-i",
27
27
  desc: "Interactively select gems to check"
28
+ class_option :dry_run, type: :boolean, default: false, desc: "Show which gems would be checked"
28
29
 
29
30
  desc "check [GEM...]", "Show changelog diffs for outdated gems"
30
31
  def check(*gem_names)
32
+ load_config
31
33
  configure_token
32
34
  gems = detect_gems
33
35
  gems = filter_gems(gems, gem_names)
@@ -35,16 +37,18 @@ module GemChangelogDiff
35
37
 
36
38
  gems = Interactive.new(gems: gems).select if options[:interactive]
37
39
  return say("No gems selected.") if gems.empty?
40
+ return dry_run_output(gems) if options[:dry_run]
38
41
 
39
42
  output_results(gems)
40
43
  end
41
44
 
42
45
  desc "show GEM FROM_VERSION TO_VERSION", "Show changelog between two versions of a gem"
43
46
  def show(gem_name, from_version, to_version)
47
+ load_config
44
48
  configure_token
45
49
  gem = OutdatedGem.new(name: gem_name, current_version: from_version, newest_version: to_version)
46
50
  report = build_single_report(gem)
47
- formatter = Formatters.build(format: options[:format], color: color_enabled?)
51
+ formatter = Formatters.build(format: resolved_format, color: color_enabled?)
48
52
  write_output(formatter.format([report]))
49
53
  end
50
54
 
@@ -59,6 +63,18 @@ module GemChangelogDiff
59
63
  end
60
64
  end
61
65
 
66
+ desc "init", "Generate a config file template"
67
+ def init
68
+ path = ConfigLoader::PROJECT_CONFIG_NAME
69
+ if File.exist?(path)
70
+ say "#{path} already exists."
71
+ return
72
+ end
73
+
74
+ File.write(path, config_template)
75
+ say "Created #{path}"
76
+ end
77
+
62
78
  desc "version", "Print version"
63
79
  def version
64
80
  say "gem_changelog_diff #{VERSION}"
@@ -68,11 +84,26 @@ module GemChangelogDiff
68
84
 
69
85
  private
70
86
 
87
+ def load_config
88
+ config = ConfigLoader.new.load
89
+ GemChangelogDiff.configuration.apply(config)
90
+ end
91
+
71
92
  def configure_token
72
93
  token = options[:token] || ENV.fetch("GITHUB_TOKEN", nil)
94
+ token ||= rails_credentials_token
95
+ token ||= GemChangelogDiff.configuration.github_token
73
96
  GemChangelogDiff.configuration.github_token = token if token
74
97
  end
75
98
 
99
+ def rails_credentials_token
100
+ return unless defined?(Rails) && Rails.application.respond_to?(:credentials)
101
+
102
+ Rails.application.credentials.dig(:gem_changelog_diff, :github_token)
103
+ rescue StandardError
104
+ nil
105
+ end
106
+
76
107
  def build_cache
77
108
  ttl = options[:cache_ttl] || GemChangelogDiff.configuration.cache_ttl
78
109
  enabled = !options[:no_cache] && GemChangelogDiff.configuration.cache_enabled
@@ -109,7 +140,7 @@ module GemChangelogDiff
109
140
  end
110
141
 
111
142
  def ignore_list
112
- @ignore_list ||= options[:ignore] || []
143
+ @ignore_list ||= (options[:ignore] || []) | GemChangelogDiff.configuration.ignore_gems
113
144
  end
114
145
 
115
146
  def build_reports(gems)
@@ -119,7 +150,7 @@ module GemChangelogDiff
119
150
  github_client: GithubClient.new(cache: cache),
120
151
  changelog_parser: ChangelogParser.new(cache: cache)
121
152
  )
122
- fetcher = ConcurrentFetcher.new(concurrency: options[:concurrency])
153
+ fetcher = ConcurrentFetcher.new(concurrency: resolved_concurrency)
123
154
 
124
155
  fetcher.fetch_all(gems) { |gem| build_gem_report(gem, rubygems_client, source_resolver) }
125
156
  end
@@ -149,12 +180,36 @@ module GemChangelogDiff
149
180
  result
150
181
  end
151
182
 
183
+ def dry_run_output(gems)
184
+ write_output(format_dry_run(gems))
185
+ end
186
+
187
+ def format_dry_run(gems)
188
+ case resolved_format
189
+ when "json"
190
+ require "json"
191
+ JSON.pretty_generate(gems.map(&:to_h))
192
+ when "markdown"
193
+ gems.map { |g| "- **#{g.name}** (#{g.current_version} → #{g.newest_version})" }.join("\n")
194
+ else
195
+ gems.map { |g| "#{g.name} (#{g.current_version} → #{g.newest_version})" }.join("\n")
196
+ end
197
+ end
198
+
152
199
  def output_results(gems)
153
200
  reports = with_spinner { build_reports(gems) }
154
- formatter = Formatters.build(format: options[:format], color: color_enabled?)
201
+ formatter = Formatters.build(format: resolved_format, color: color_enabled?)
155
202
  write_output(formatter.format(reports))
156
203
  end
157
204
 
205
+ def resolved_format
206
+ options[:format] || GemChangelogDiff.configuration.default_format
207
+ end
208
+
209
+ def resolved_concurrency
210
+ options[:concurrency] || GemChangelogDiff.configuration.concurrency
211
+ end
212
+
158
213
  def build_single_report(gem)
159
214
  cache = build_cache
160
215
  rubygems_client = RubygemsClient.new(cache: cache)
@@ -175,7 +230,34 @@ module GemChangelogDiff
175
230
  end
176
231
 
177
232
  def color_enabled?
178
- !options[:no_color]
233
+ !options[:no_color] && !GemChangelogDiff.configuration.no_color
234
+ end
235
+
236
+ def config_template
237
+ <<~YAML
238
+ # gem_changelog_diff configuration
239
+ # See: https://github.com/eclectic-coding/gem_changelog_diff
240
+
241
+ # GitHub personal access token (or use GITHUB_TOKEN env var)
242
+ # github_token: ghp_xxx
243
+
244
+ # Default output format: text, json, markdown
245
+ # default_format: text
246
+
247
+ # Cache TTL in seconds (default: 86400 = 24 hours)
248
+ # cache_ttl: 86400
249
+
250
+ # Number of concurrent fetches (default: 4)
251
+ # concurrency: 4
252
+
253
+ # Gems to always ignore
254
+ # ignore_gems:
255
+ # - rake
256
+ # - bundler
257
+
258
+ # Disable colored output
259
+ # no_color: false
260
+ YAML
179
261
  end
180
262
 
181
263
  def log(message)
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+
5
+ module GemChangelogDiff
6
+ class ConfigLoader
7
+ USER_CONFIG_DIR = File.join(Dir.home, ".config", "gem_changelog_diff")
8
+ USER_CONFIG_PATH = File.join(USER_CONFIG_DIR, "config.yml")
9
+ PROJECT_CONFIG_NAME = ".gem_changelog_diff.yml"
10
+
11
+ def initialize(project_dir: Dir.pwd)
12
+ @project_dir = project_dir
13
+ end
14
+
15
+ def load
16
+ user_config = load_file(USER_CONFIG_PATH)
17
+ project_config = load_file(project_config_path)
18
+ user_config.merge(project_config)
19
+ end
20
+
21
+ private
22
+
23
+ def project_config_path
24
+ File.join(@project_dir, PROJECT_CONFIG_NAME)
25
+ end
26
+
27
+ def load_file(path)
28
+ return {} unless File.exist?(path)
29
+
30
+ result = YAML.safe_load_file(path, permitted_classes: [], symbolize_names: true)
31
+ result.is_a?(Hash) ? result : {}
32
+ rescue Psych::SyntaxError
33
+ {}
34
+ end
35
+ end
36
+ end
@@ -2,11 +2,24 @@
2
2
 
3
3
  module GemChangelogDiff
4
4
  class Configuration
5
- attr_accessor :github_token, :cache_enabled, :cache_ttl
5
+ attr_accessor :github_token, :cache_enabled, :cache_ttl,
6
+ :default_format, :concurrency, :ignore_gems, :no_color
7
+
8
+ VALID_KEYS = %i[github_token cache_enabled cache_ttl default_format concurrency ignore_gems no_color].freeze
6
9
 
7
10
  def initialize
8
11
  @cache_enabled = true
9
12
  @cache_ttl = 86_400
13
+ @default_format = "text"
14
+ @concurrency = 4
15
+ @ignore_gems = []
16
+ @no_color = false
17
+ end
18
+
19
+ def apply(hash)
20
+ hash.each do |key, value|
21
+ public_send(:"#{key}=", value) if VALID_KEYS.include?(key) && !value.nil?
22
+ end
10
23
  end
11
24
  end
12
25
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GemChangelogDiff
4
- VERSION = "0.6.0"
4
+ VERSION = "0.7.0"
5
5
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative "gem_changelog_diff/version"
4
4
  require_relative "gem_changelog_diff/configuration"
5
+ require_relative "gem_changelog_diff/config_loader"
5
6
 
6
7
  module GemChangelogDiff
7
8
  class Error < StandardError; end
@@ -26,8 +26,29 @@ module GemChangelogDiff
26
26
  attr_accessor github_token: String?
27
27
  attr_accessor cache_enabled: bool
28
28
  attr_accessor cache_ttl: Integer
29
+ attr_accessor default_format: String
30
+ attr_accessor concurrency: Integer
31
+ attr_accessor ignore_gems: Array[String]
32
+ attr_accessor no_color: bool
33
+
34
+ VALID_KEYS: Array[Symbol]
29
35
 
30
36
  def initialize: () -> void
37
+ def apply: (Hash[Symbol, untyped] hash) -> void
38
+ end
39
+
40
+ class ConfigLoader
41
+ USER_CONFIG_DIR: String
42
+ USER_CONFIG_PATH: String
43
+ PROJECT_CONFIG_NAME: String
44
+
45
+ def initialize: (?project_dir: String) -> void
46
+ def load: () -> Hash[Symbol, untyped]
47
+
48
+ private
49
+
50
+ def project_config_path: () -> String
51
+ def load_file: (String path) -> Hash[Symbol, untyped]
31
52
  end
32
53
 
33
54
  class Cache
@@ -241,12 +262,20 @@ module GemChangelogDiff
241
262
  def check: (*String gem_names) -> void
242
263
  def show: (String gem_name, String from_version, String to_version) -> void
243
264
  def cache: (?String? subcommand) -> void
265
+ def init: () -> void
244
266
  def version: () -> void
245
267
 
246
268
  private
247
269
 
270
+ def load_config: () -> void
271
+ def dry_run_output: (Array[OutdatedGem] gems) -> void
272
+ def format_dry_run: (Array[OutdatedGem] gems) -> String
273
+ def rails_credentials_token: () -> String?
248
274
  def output_results: (Array[OutdatedGem] gems) -> void
275
+ def resolved_format: () -> String
276
+ def resolved_concurrency: () -> Integer
249
277
  def build_single_report: (OutdatedGem gem) -> gem_report
278
+ def config_template: () -> String
250
279
  def with_spinner: [T] () { () -> T } -> T
251
280
  def color_enabled?: () -> bool
252
281
  def configure_token: () -> 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.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chuck Smith
@@ -89,6 +89,7 @@ files:
89
89
  - lib/gem_changelog_diff/changelog_parser.rb
90
90
  - lib/gem_changelog_diff/cli.rb
91
91
  - lib/gem_changelog_diff/concurrent_fetcher.rb
92
+ - lib/gem_changelog_diff/config_loader.rb
92
93
  - lib/gem_changelog_diff/configuration.rb
93
94
  - lib/gem_changelog_diff/detector.rb
94
95
  - lib/gem_changelog_diff/errors.rb