rake-gem-maintenance 0.1.7 → 0.2.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.
@@ -8,313 +8,341 @@ require_relative "otp_provider"
8
8
  require_relative "renew_api_key_task"
9
9
  require_relative "gem_publisher"
10
10
  require_relative "repos"
11
+ require_relative "ruby_version_checker"
12
+ require_relative "ruby_version_updater"
11
13
 
12
14
  module Rake
13
- module GemMaintenance
14
- # Defines Rake tasks for upgrading gem dependencies and publishing to multiple repositories.
15
- #
16
- # Creates: upgrade, upgrade:auto, upgrade:branch, upgrade:gems, upgrade:commit,
17
- # upgrade:prepare_version, upgrade:push
18
- # rubocop:disable Metrics/ClassLength, Metrics/MethodLength
19
- class UpgradeTask < ::Rake::TaskLib
20
- attr_accessor :name, :main_branch, :upgrade_branch, :commit_message,
21
- :files_to_commit, :verification_task, :release_task,
22
- :version_bump_task, :update_rubygems, :update_gems,
23
- :run_bundle_audit, :auto_pipeline, :gem_repositories,
24
- :gem_publisher_class, :gem_name, :gem_version
25
-
26
- attr_writer :renew_api_key_task_class
27
-
28
- def renew_api_key_task_class
29
- @renew_api_key_task_class || RenewApiKeyTask
30
- end
15
+ module Gem
16
+ module Maintenance
17
+ # Defines Rake tasks for upgrading gem dependencies and publishing to multiple repositories.
18
+ #
19
+ # Creates: upgrade, upgrade:auto, upgrade:branch, upgrade:gems, upgrade:commit,
20
+ # upgrade:prepare_version, upgrade:push
21
+ # rubocop:disable Metrics/ClassLength, Metrics/MethodLength
22
+ class UpgradeTask < ::Rake::TaskLib
23
+ attr_accessor :name, :main_branch, :upgrade_branch, :commit_message,
24
+ :files_to_commit, :verification_task, :release_task,
25
+ :version_bump_task, :update_rubygems, :update_gems,
26
+ :run_bundle_audit, :auto_pipeline, :gem_repositories,
27
+ :gem_publisher_class, :gem_name, :gem_version,
28
+ :update_ruby, :ruby_version_checker_class, :ruby_version_updater_class
29
+
30
+ attr_writer :renew_api_key_task_class
31
+
32
+ def renew_api_key_task_class
33
+ @renew_api_key_task_class || RenewApiKeyTask
34
+ end
31
35
 
32
- def initialize(name = :upgrade)
33
- super()
34
- apply_default_configuration(name)
36
+ def initialize(name = :upgrade)
37
+ super()
38
+ apply_default_configuration(name)
35
39
 
36
- yield self if block_given?
37
- define_tasks
38
- end
40
+ yield self if block_given?
41
+ define_tasks
42
+ end
39
43
 
40
- def apply_default_configuration(name)
41
- @name = name
42
- @main_branch = "main"
43
- @upgrade_branch = "upgrade/gems"
44
- @commit_message = "chore(deps): upgrade gems"
45
- @files_to_commit = %w[Gemfile Gemfile.lock]
46
- @verification_task = :verify
47
- @release_task = :release
48
- @version_bump_task = "version:bump"
49
- @update_rubygems = true
50
- @update_gems = true
51
- @run_bundle_audit = true
52
- @auto_pipeline = nil
53
- @gem_repositories = Repos.rubygems
54
- @gem_publisher_class = GemPublisher
55
- @gem_name = detect_gem_name
56
- @gem_version = detect_gem_version
57
- end
44
+ def apply_default_configuration(name)
45
+ @name = name
46
+ @main_branch = "main"
47
+ @upgrade_branch = "upgrade/gems"
48
+ @commit_message = "chore(deps): upgrade gems"
49
+ @files_to_commit = %w[Gemfile Gemfile.lock]
50
+ @verification_task = :verify
51
+ @release_task = :release
52
+ @version_bump_task = "version:bump"
53
+ @auto_pipeline = nil
54
+ @gem_repositories = Repos.rubygems
55
+ @gem_publisher_class = GemPublisher
56
+ @gem_name = detect_gem_name
57
+ @gem_version = detect_gem_version
58
+ apply_default_gem_update_configuration
59
+ apply_default_ruby_version_configuration
60
+ end
58
61
 
59
- private
62
+ def apply_default_gem_update_configuration
63
+ @update_rubygems = true
64
+ @update_gems = true
65
+ @run_bundle_audit = true
66
+ end
60
67
 
61
- def detect_gem_name
62
- gemspec = Dir.glob("*.gemspec").first
63
- return nil unless gemspec
68
+ def apply_default_ruby_version_configuration
69
+ @update_ruby = true
70
+ @ruby_version_checker_class = RubyVersionChecker
71
+ @ruby_version_updater_class = RubyVersionUpdater
72
+ end
64
73
 
65
- Gem::Specification.load(gemspec).name
66
- end
74
+ private
67
75
 
68
- def detect_gem_version
69
- gemspec = Dir.glob("*.gemspec").first
70
- return nil unless gemspec
76
+ def detect_gem_name
77
+ gemspec = Dir.glob("*.gemspec").first
78
+ return nil unless gemspec
71
79
 
72
- Gem::Specification.load(gemspec).version.to_s
73
- end
80
+ ::Gem::Specification.load(gemspec).name
81
+ end
74
82
 
75
- def repo_available?(repo)
76
- url = repo[:url]
77
- uri = URI.parse(url)
78
- http = Net::HTTP.new(uri.host, uri.port)
79
- http.use_ssl = uri.scheme == "https"
80
- http.open_timeout = 5
81
- http.start { |h| h.head("/").code.to_i < 400 }
82
- rescue StandardError
83
- false
84
- end
83
+ def detect_gem_version
84
+ gemspec = Dir.glob("*.gemspec").first
85
+ return nil unless gemspec
85
86
 
86
- public
87
-
88
- def define_tasks
89
- define_top_level_task
90
- define_info_tasks
91
- define_prepare_version_task
92
- define_auto_task
93
- define_branch_task
94
- define_gems_task
95
- define_commit_task
96
- define_push_task
97
- define_renew_api_key_task
98
- end
87
+ ::Gem::Specification.load(gemspec).version.to_s
88
+ end
99
89
 
100
- def define_info_tasks
101
- task_instance = self
102
- namespace name do
103
- namespace :info do
104
- define_info_repos_task(task_instance)
105
- define_info_version_task(task_instance)
106
- define_info_name_task(task_instance)
90
+ def repo_available?(repo)
91
+ url = repo[:url]
92
+ uri = URI.parse(url)
93
+ http = Net::HTTP.new(uri.host, uri.port)
94
+ http.use_ssl = uri.scheme == "https"
95
+ http.open_timeout = 5
96
+ http.start { |h| h.head("/").code.to_i < 400 }
97
+ rescue StandardError
98
+ false
99
+ end
100
+
101
+ public
102
+
103
+ def define_tasks
104
+ define_top_level_task
105
+ define_info_tasks
106
+ define_prepare_version_task
107
+ define_auto_task
108
+ define_branch_task
109
+ define_gems_task
110
+ define_commit_task
111
+ define_push_task
112
+ define_renew_api_key_task
113
+ end
114
+
115
+ def define_info_tasks
116
+ task_instance = self
117
+ namespace name do
118
+ namespace :info do
119
+ define_info_repos_task(task_instance)
120
+ define_info_version_task(task_instance)
121
+ define_info_name_task(task_instance)
122
+ desc "Show all upgrade info"
123
+ task all: %i[name version repos]
124
+ end
107
125
  desc "Show all upgrade info"
108
- task all: %i[name version repos]
126
+ task info: "#{name}:info:all"
109
127
  end
110
- desc "Show all upgrade info"
111
- task info: "#{name}:info:all"
112
128
  end
113
- end
114
129
 
115
- def define_info_repos_task(task_instance)
116
- desc "Show configured gem repositories"
117
- task :repos do
118
- puts "Gem repositories:"
119
- task_instance.gem_repositories.each do |repo|
120
- available = task_instance.send(:repo_available?, repo)
121
- status = available ? "✓" : "✗"
122
- avail_text = available ? "AVAILABLE" : "NOT AVAILABLE"
123
- puts " - #{repo[:name]} (#{status}) - #{avail_text}: #{repo[:url]}"
130
+ def define_info_repos_task(task_instance)
131
+ desc "Show configured gem repositories"
132
+ task :repos do
133
+ puts "Gem repositories:"
134
+ task_instance.gem_repositories.each do |repo|
135
+ available = task_instance.send(:repo_available?, repo)
136
+ status = available ? "✓" : "✗"
137
+ avail_text = available ? "AVAILABLE" : "NOT AVAILABLE"
138
+ puts " - #{repo[:name]} (#{status}) - #{avail_text}: #{repo[:url]}"
139
+ end
124
140
  end
125
141
  end
126
- end
127
142
 
128
- def define_info_version_task(task_instance)
129
- desc "Show current gem version"
130
- task :version do
131
- ver = task_instance.gem_version || "unknown"
132
- puts "Current version: #{ver}"
143
+ def define_info_version_task(task_instance)
144
+ desc "Show current gem version"
145
+ task :version do
146
+ ver = task_instance.gem_version || "unknown"
147
+ puts "Current version: #{ver}"
148
+ end
133
149
  end
134
- end
135
150
 
136
- def define_info_name_task(task_instance)
137
- desc "Show current gem name"
138
- task :name do
139
- name = task_instance.gem_name || "unknown"
140
- puts "Gem name: #{name}"
151
+ def define_info_name_task(task_instance)
152
+ desc "Show current gem name"
153
+ task :name do
154
+ name = task_instance.gem_name || "unknown"
155
+ puts "Gem name: #{name}"
156
+ end
141
157
  end
142
- end
143
158
 
144
- def define_top_level_task
145
- desc "Alias for #{name}:auto"
146
- task name => "#{name}:auto"
147
- end
159
+ def define_top_level_task
160
+ desc "Alias for #{name}:auto"
161
+ task name => "#{name}:auto"
162
+ end
148
163
 
149
- def define_prepare_version_task
150
- task_instance = self
151
- namespace name do
152
- desc "Check version on all repositories before bumping"
153
- task :prepare_version do
154
- task_instance.send(:check_version_on_repositories)
164
+ def define_prepare_version_task
165
+ task_instance = self
166
+ namespace name do
167
+ desc "Check version on all repositories before bumping"
168
+ task :prepare_version do
169
+ task_instance.send(:check_version_on_repositories)
170
+ end
155
171
  end
156
172
  end
157
- end
158
173
 
159
- def define_auto_task
160
- task_instance = self
161
- namespace name do
162
- desc "Update gems automatically (branch to push and release)"
163
- task auto: task_instance.send(:pipeline_tasks)
174
+ def define_auto_task
175
+ task_instance = self
176
+ namespace name do
177
+ desc "Update gems automatically (branch to push and release)"
178
+ task auto: task_instance.send(:pipeline_tasks)
179
+ end
164
180
  end
165
- end
166
181
 
167
- def define_branch_task
168
- task_instance = self
169
- namespace name do
170
- desc "Create a branch for the upgrade"
171
- task(:branch) { task_instance.send(:create_upgrade_branch) }
182
+ def define_branch_task
183
+ task_instance = self
184
+ namespace name do
185
+ desc "Create a branch for the upgrade"
186
+ task(:branch) { task_instance.send(:create_upgrade_branch) }
187
+ end
172
188
  end
173
- end
174
189
 
175
- def define_gems_task
176
- task_instance = self
177
- namespace name do
178
- desc "Upgrade gems, including bundler and gem"
179
- task(:gems) { task_instance.send(:do_upgrade_gems) }
190
+ def define_gems_task
191
+ task_instance = self
192
+ namespace name do
193
+ desc "Upgrade gems, including bundler and gem"
194
+ task(:gems) { task_instance.send(:do_upgrade_gems) }
195
+ end
180
196
  end
181
- end
182
197
 
183
- def define_commit_task
184
- task_instance = self
185
- namespace name do
186
- desc "Commit the upgrade branch"
187
- task(:commit) { task_instance.send(:commit_changes) }
198
+ def define_commit_task
199
+ task_instance = self
200
+ namespace name do
201
+ desc "Commit the upgrade branch"
202
+ task(:commit) { task_instance.send(:commit_changes) }
203
+ end
188
204
  end
189
- end
190
205
 
191
- def define_push_task
192
- task_instance = self
193
- namespace name do
194
- desc "Push the upgrade"
195
- task(:push) { task_instance.send(:push_branch) }
206
+ def define_push_task
207
+ task_instance = self
208
+ namespace name do
209
+ desc "Push the upgrade"
210
+ task(:push) { task_instance.send(:push_branch) }
211
+ end
196
212
  end
197
- end
198
213
 
199
- def define_renew_api_key_task
200
- renew_api_key_task_class.new(name)
201
- end
214
+ def define_renew_api_key_task
215
+ renew_api_key_task_class.new(name)
216
+ end
202
217
 
203
- def pipeline_tasks
204
- return auto_pipeline if auto_pipeline
218
+ def pipeline_tasks
219
+ return auto_pipeline if auto_pipeline
205
220
 
206
- %i[branch gems] + [verification_task, :commit, version_bump_task.to_sym, :prepare_version, release_task, :push]
207
- end
221
+ %i[branch
222
+ gems] + [verification_task, :commit, version_bump_task.to_sym, :prepare_version, release_task, :push]
223
+ end
208
224
 
209
- def create_upgrade_branch
210
- sh "git checkout #{main_branch}"
211
- sh "git pull"
212
- sh "git branch -D #{upgrade_branch}" unless `git branch --list #{upgrade_branch}`.chomp.empty?
213
- sh "git checkout -b #{upgrade_branch}"
214
- end
225
+ def create_upgrade_branch
226
+ sh "git checkout #{main_branch}"
227
+ sh "git pull"
228
+ sh "git branch -D #{upgrade_branch}" unless `git branch --list #{upgrade_branch}`.chomp.empty?
229
+ sh "git checkout -b #{upgrade_branch}"
230
+ end
215
231
 
216
- def do_upgrade_gems
217
- sh "gem update --system" if update_rubygems
218
- sh "gem update" if update_gems
219
- sh "bundle update --bundler"
220
- sh "bundle update --all"
221
- sh "bundle audit" if run_bundle_audit
222
- end
232
+ def do_upgrade_gems
233
+ update_ruby_versions if update_ruby
234
+ sh "gem update --system" if update_rubygems
235
+ sh "gem update" if update_gems
236
+ sh "bundle update --bundler"
237
+ sh "bundle update --all"
238
+ sh "bundle audit" if run_bundle_audit
239
+ end
223
240
 
224
- def commit_changes
225
- sh "git add #{files_to_commit.join(' ')}"
226
- sh "git commit -m '#{commit_message}'"
227
- end
241
+ def update_ruby_versions
242
+ checker = ruby_version_checker_class.new
243
+ if checker.latest_stable.nil?
244
+ puts "[WARN] Could not fetch Ruby version info — skipping Ruby update"
245
+ return
246
+ end
247
+ modified = ruby_version_updater_class.new.update(checker: checker)
248
+ files_to_commit.concat(modified) if modified.any?
249
+ end
228
250
 
229
- def push_branch
230
- sh "git push origin #{upgrade_branch}"
231
- end
251
+ def commit_changes
252
+ sh "git add #{files_to_commit.join(' ')}"
253
+ sh "git commit -m '#{commit_message}'"
254
+ end
232
255
 
233
- # rubocop:disable Metrics/AbcSize
234
- def check_version_on_repositories
235
- unless gem_name && gem_version
236
- puts "[ERROR] No gemspec found - cannot check version/upgrade"
237
- abort
256
+ def push_branch
257
+ sh "git push origin #{upgrade_branch}"
238
258
  end
239
259
 
240
- publisher = gem_publisher_class.new(gem_repositories)
241
- gemspec_repos = gem_repositories.select { |repo| repo_available?(repo) }
260
+ # rubocop:disable Metrics/AbcSize
261
+ def check_version_on_repositories
262
+ unless gem_name && gem_version
263
+ puts "[ERROR] No gemspec found - cannot check version/upgrade"
264
+ abort
265
+ end
242
266
 
243
- if gemspec_repos.empty?
244
- puts "[ERROR] No repositories available. Cannot check version."
245
- abort
246
- end
267
+ publisher = gem_publisher_class.new(gem_repositories)
268
+ gemspec_repos = gem_repositories.select { |repo| repo_available?(repo) }
247
269
 
248
- publisher.check_all_repositories(gem_name)
270
+ if gemspec_repos.empty?
271
+ puts "[ERROR] No repositories available. Cannot check version."
272
+ abort
273
+ end
249
274
 
250
- print_failed_repository_warnings(publisher)
251
- version = gem_version
252
- next_ver = publisher.next_version(gem_name, version)
275
+ publisher.check_all_repositories(gem_name)
253
276
 
254
- if next_ver == version
255
- puts "[INFO] Version #{version} not found on any repository - will publish"
256
- else
257
- puts "[INFO] Version #{version} already published to all repositories"
258
- puts "[INFO] Next available version: #{next_ver}"
259
- end
277
+ print_failed_repository_warnings(publisher)
278
+ version = gem_version
279
+ next_ver = publisher.next_version(gem_name, version)
260
280
 
261
- handle_partial_publish_warning(publisher, version)
262
- end
263
- # rubocop:enable Metrics/AbcSize
281
+ if next_ver == version
282
+ puts "[INFO] Version #{version} not found on any repository - will publish"
283
+ else
284
+ puts "[INFO] Version #{version} already published to all repositories"
285
+ puts "[INFO] Next available version: #{next_ver}"
286
+ end
264
287
 
265
- def handle_partial_publish_warning(publisher, version)
266
- return if publisher.successful_repos.empty?
288
+ handle_partial_publish_warning(publisher, version)
289
+ end
290
+ # rubocop:enable Metrics/AbcSize
267
291
 
268
- published = publisher.successful_repos
269
- total = gem_repositories.size
270
- return unless published.size < total
292
+ def handle_partial_publish_warning(publisher, version)
293
+ return if publisher.successful_repos.empty?
271
294
 
272
- puts "[WARN] Version #{version} was only published to #{published.size} of #{total} repositories"
273
- puts "[WARN] Run 'rake upgrade:prepare_version' manually to check status"
274
- end
295
+ published = publisher.successful_repos
296
+ total = gem_repositories.size
297
+ return unless published.size < total
275
298
 
276
- def repos_available?(publisher)
277
- return true if publisher.any_available?
299
+ puts "[WARN] Version #{version} was only published to #{published.size} of #{total} repositories"
300
+ puts "[WARN] Run 'rake upgrade:prepare_version' manually to check status"
301
+ end
278
302
 
279
- puts "[ERROR] No repositories available. Cannot check version."
280
- abort
281
- end
303
+ def repos_available?(publisher)
304
+ return true if publisher.any_available?
305
+
306
+ puts "[ERROR] No repositories available. Cannot check version."
307
+ abort
308
+ end
282
309
 
283
- def print_failed_repository_warnings(publisher)
284
- return if publisher.failed_repositories.empty?
310
+ def print_failed_repository_warnings(publisher)
311
+ return if publisher.failed_repositories.empty?
285
312
 
286
- puts "[WARN] The following repositories were unavailable:"
287
- publisher.failed_repositories.each do |repo_name|
288
- puts " - #{repo_name}"
313
+ puts "[WARN] The following repositories were unavailable:"
314
+ publisher.failed_repositories.each do |repo_name|
315
+ puts " - #{repo_name}"
316
+ end
289
317
  end
318
+ # rubocop:enable Metrics/ClassLength, Metrics/MethodLength
290
319
  end
291
- # rubocop:enable Metrics/ClassLength, Metrics/MethodLength
292
- end
293
320
 
294
- # Upgrades gems and publishes to cbp-org only (internal gems).
295
- # Uses Repos.internal as default repositories.
296
- class InternalUpgradeTask < UpgradeTask
297
- def apply_default_configuration(name)
298
- super
299
- @gem_repositories = Repos.internal
321
+ # Upgrades gems and publishes to cbp-org only (internal gems).
322
+ # Uses Repos.internal as default repositories.
323
+ class InternalUpgradeTask < UpgradeTask
324
+ def apply_default_configuration(name)
325
+ super
326
+ @gem_repositories = Repos.internal
327
+ end
300
328
  end
301
- end
302
329
 
303
- # Upgrades gems and publishes to both rubygems.org and cbp-org.
304
- # Uses Repos.all as default repositories.
305
- class DualUpgradeTask < UpgradeTask
306
- def apply_default_configuration(name)
307
- super
308
- @gem_repositories = Repos.all
330
+ # Upgrades gems and publishes to both rubygems.org and cbp-org.
331
+ # Uses Repos.all as default repositories.
332
+ class DualUpgradeTask < UpgradeTask
333
+ def apply_default_configuration(name)
334
+ super
335
+ @gem_repositories = Repos.all
336
+ end
309
337
  end
310
- end
311
338
 
312
- # Upgrades gems and publishes to a local geminabox instance only.
313
- # Uses Repos.geminabox as default repositories.
314
- class GeminaboxUpgradeTask < UpgradeTask
315
- def apply_default_configuration(name)
316
- super
317
- @gem_repositories = Repos.geminabox
339
+ # Upgrades gems and publishes to a local geminabox instance only.
340
+ # Uses Repos.geminabox as default repositories.
341
+ class GeminaboxUpgradeTask < UpgradeTask
342
+ def apply_default_configuration(name)
343
+ super
344
+ @gem_repositories = Repos.geminabox
345
+ end
318
346
  end
319
347
  end
320
348
  end
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rake
4
- module GemMaintenance
5
- VERSION = "0.1.7"
4
+ module Gem
5
+ module Maintenance
6
+ VERSION = "0.2.1"
7
+ end
6
8
  end
7
9
  end