rake-gem-maintenance 0.2.0 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1025716123e134ab6db2ffcfc5655a59208dd038691b73e270c92c6bd35ea977
4
- data.tar.gz: 1445566f68985cdd2b915c9958ec9daddaf07caa5002c62277481b72a122d561
3
+ metadata.gz: 7b2f1d62cfc25f917eb45338405611a64c9252991cd9dbe88f09fe1657d42056
4
+ data.tar.gz: 0415d978205a09dc495e92b530ea62ae4d0d795ee6d9b53c541ff506ef47073e
5
5
  SHA512:
6
- metadata.gz: ba35f363319b323fe927da2cc3a9e8934d7b4310f5995b31d1cc91a759b34c8462262c449ef59fa1debe3c35615c733ef8f0dc96e6f270b592a76f1f6cc76153
7
- data.tar.gz: 892b319be15819eb07cf5f254e9e7144e8387393a586442e9831585602600ade156e6d6c7c0b1dc41b6e60ee9e58b411c10a1bcebbff5e08f8510ec56f32ffad
6
+ metadata.gz: 31948df671b9368437625ed91106d4acf9a6e9d465cb7fc4827fdb00b3f942138410c146eab28077e68da9358ad59218070815b8210885dd022a8a71bbc1dcfb
7
+ data.tar.gz: 4a4bd31d89642fefd566470541cb5b052c22d714a8101d0c457d9ce328e3de54b0a162d6904d540d8fab77a6c1feb9c03a481023f245a1722835001295e009ec
@@ -34,7 +34,7 @@ steps:
34
34
  RUBYGEMS_OTP_SEED:
35
35
  from_secret: rubygems_otp_seed
36
36
  commands:
37
- - apk add --no-cache build-base
37
+ - apk add --no-cache build-base git
38
38
  - bundle install --jobs 4 --retry 3
39
39
  - ruby scripts/ci_publish_rubygems.rb
40
40
 
@@ -19,7 +19,7 @@ steps:
19
19
  environment:
20
20
  CUCUMBER_PUBLISH_QUIET: "true"
21
21
  commands:
22
- - apk add --no-cache build-base
22
+ - apk add --no-cache build-base git
23
23
  - mkdir -p /root/.local/share/ruby-advisory-db/gems
24
24
  - bundle install --jobs 4 --retry 3
25
25
  - bundle exec rake verify
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rake-gem-maintenance (0.2.0)
4
+ rake-gem-maintenance (0.2.1)
5
5
  bundler-audit
6
6
  gem-release
7
7
  rake
@@ -254,7 +254,7 @@ CHECKSUMS
254
254
  racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f
255
255
  rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a
256
256
  rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701
257
- rake-gem-maintenance (0.2.0)
257
+ rake-gem-maintenance (0.2.1)
258
258
  rb-fsevent (0.11.2) sha256=43900b972e7301d6570f64b850a5aa67833ee7d87b458ee92805d56b7318aefe
259
259
  rb-inotify (0.11.1) sha256=a0a700441239b0ff18eb65e3866236cd78613d6b9f78fea1f9ac47a85e47be6e
260
260
  rdoc (7.2.0) sha256=8650f76cd4009c3b54955eb5d7e3a075c60a57276766ebf36f9085e8c9f23192
@@ -7,6 +7,7 @@ Rake::Gem::Maintenance::Repos.rubygems_otp_seed_env_var = "RUBYGEMS_OTP_SEED"
7
7
 
8
8
  Rake::Gem::Maintenance::UpgradeTask.new
9
9
  Rake::Gem::Maintenance::VersionBumpTask.new
10
+ Rake::Gem::Maintenance::RubygemsPublishTask.new
10
11
 
11
12
  Rake::Gem::Maintenance::CredentialStore.new.apply_to_env(
12
13
  username_env_var: "RUBYGEMS_USERNAME",
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "json"
5
+
6
+ module Rake
7
+ module Gem
8
+ module Maintenance
9
+ # Fetches the latest stable Ruby version and maintained minors from endoflife.date.
10
+ class RubyVersionChecker
11
+ API_URL = "https://endoflife.date/api/ruby.json"
12
+
13
+ def latest_stable
14
+ cycles.max_by { |c| ::Gem::Version.new(c[:latest]) }&.fetch(:latest)
15
+ end
16
+
17
+ def maintained_minors
18
+ cycles.map { |c| c[:cycle] }.sort_by { |v| ::Gem::Version.new(v) }
19
+ end
20
+
21
+ private
22
+
23
+ def cycles
24
+ @cycles ||= fetch_cycles
25
+ end
26
+
27
+ def fetch_cycles
28
+ response = Net::HTTP.get(URI(API_URL))
29
+ JSON.parse(response, symbolize_names: true).reject { |c| c[:eol] }
30
+ rescue StandardError
31
+ []
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rake
4
+ module Gem
5
+ module Maintenance
6
+ # Updates Ruby version references in .ruby-version, gemspec, and CI config files.
7
+ class RubyVersionUpdater
8
+ def initialize(
9
+ ruby_version_file: ".ruby-version",
10
+ gemspec_files: Dir.glob("*.gemspec"),
11
+ github_workflow_files: Dir.glob(".github/workflows/*.yml"),
12
+ woodpecker_config_files: Dir.glob(".woodpecker/*.yml")
13
+ )
14
+ @ruby_version_file = ruby_version_file
15
+ @gemspec_files = Array(gemspec_files)
16
+ @github_workflow_files = Array(github_workflow_files)
17
+ @woodpecker_config_files = Array(woodpecker_config_files)
18
+ end
19
+
20
+ def update(checker:)
21
+ latest = checker.latest_stable
22
+ minors = checker.maintained_minors
23
+ return [] if latest.nil? || minors.empty?
24
+
25
+ [
26
+ write_ruby_version_file(latest),
27
+ *@gemspec_files.map { |f| patch_gemspec(f, latest) },
28
+ *@github_workflow_files.map { |f| patch_github_workflow(f, minors) },
29
+ *@woodpecker_config_files.map { |f| patch_woodpecker_config(f, latest) }
30
+ ].compact
31
+ end
32
+
33
+ private
34
+
35
+ def write_ruby_version_file(latest)
36
+ current = File.exist?(@ruby_version_file) ? File.read(@ruby_version_file).strip : nil
37
+ return if current == latest
38
+
39
+ File.write(@ruby_version_file, "#{latest}\n")
40
+ @ruby_version_file
41
+ end
42
+
43
+ def patch_gemspec(path, latest)
44
+ return unless File.exist?(path)
45
+
46
+ content = File.read(path)
47
+ updated = rewrite_required_ruby_version(content, latest)
48
+ return if updated == content
49
+
50
+ File.write(path, updated)
51
+ path
52
+ end
53
+
54
+ def patch_github_workflow(path, minors)
55
+ return unless File.exist?(path)
56
+
57
+ matrix_value = (minors + ["truffleruby"]).map { |v| "'#{v}'" }.join(", ")
58
+ content = File.read(path)
59
+ updated = content.gsub(/ruby-version:\s*\[.*?\]/, "ruby-version: [ #{matrix_value} ]")
60
+ return if updated == content
61
+
62
+ File.write(path, updated)
63
+ path
64
+ end
65
+
66
+ def patch_woodpecker_config(path, latest)
67
+ return unless File.exist?(path)
68
+
69
+ content = File.read(path)
70
+ updated = content.gsub(/\bruby:(\d+\.\d+\.\d+)([-\w]*)/, "ruby:#{latest}\\2")
71
+ return if updated == content
72
+
73
+ File.write(path, updated)
74
+ path
75
+ end
76
+
77
+ def rewrite_required_ruby_version(content, latest)
78
+ latest_parts = latest.split(".").map(&:to_i)
79
+ content.gsub(/required_ruby_version\s*=\s*["'](>=\s*)(\d+)\.(\d+)\.\d+["']/) do
80
+ prefix = ::Regexp.last_match(1)
81
+ req_major = ::Regexp.last_match(2).to_i
82
+ req_minor = ::Regexp.last_match(3).to_i
83
+ next ::Regexp.last_match(0) unless same_minor?(req_major, req_minor, latest_parts)
84
+
85
+ "required_ruby_version = \"#{prefix}#{latest}\""
86
+ end
87
+ end
88
+
89
+ def same_minor?(major, minor, latest_parts)
90
+ latest_parts[0] == major && latest_parts[1] == minor
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rake"
4
+ require "rake/tasklib"
5
+ require_relative "gem_publisher"
6
+ require_relative "repos"
7
+
8
+ module Rake
9
+ module Gem
10
+ module Maintenance
11
+ # Defines the publish:rubygems Rake task for pushing a built .gem to rubygems.org.
12
+ #
13
+ # Expects a .gem file to already exist in the working directory (run gem build first).
14
+ # Uses the GEM_HOST_API_KEY and RUBYGEMS_OTP_SEED env vars configured via Repos.
15
+ class RubygemsPublishTask < ::Rake::TaskLib
16
+ GEM_FILE_GLOB = "*.gem"
17
+
18
+ attr_accessor :gem_file_glob, :gem_publisher_class
19
+
20
+ def initialize
21
+ super
22
+ @gem_file_glob = GEM_FILE_GLOB
23
+ @gem_publisher_class = GemPublisher
24
+
25
+ yield self if block_given?
26
+ define_tasks
27
+ end
28
+
29
+ private
30
+
31
+ def define_tasks
32
+ task_instance = self
33
+ namespace :publish do
34
+ desc "Push the built .gem file to rubygems.org"
35
+ task :rubygems do
36
+ task_instance.send(:publish_to_rubygems)
37
+ end
38
+ end
39
+ end
40
+
41
+ def publish_to_rubygems
42
+ publisher = gem_publisher_class.new(Repos.rubygems)
43
+ publisher.publish(gem_file)
44
+ return if publisher.successful_repos.include?("rubygems")
45
+
46
+ raise "Publish to rubygems.org failed — check output above"
47
+ end
48
+
49
+ def gem_file
50
+ file = Dir.glob(gem_file_glob).first
51
+ raise "No .gem file found — run gem build first" unless file
52
+
53
+ file
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -8,6 +8,8 @@ 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
15
  module Gem
@@ -22,7 +24,8 @@ module Rake
22
24
  :files_to_commit, :verification_task, :release_task,
23
25
  :version_bump_task, :update_rubygems, :update_gems,
24
26
  :run_bundle_audit, :auto_pipeline, :gem_repositories,
25
- :gem_publisher_class, :gem_name, :gem_version
27
+ :gem_publisher_class, :gem_name, :gem_version,
28
+ :update_ruby, :ruby_version_checker_class, :ruby_version_updater_class
26
29
 
27
30
  attr_writer :renew_api_key_task_class
28
31
 
@@ -47,14 +50,25 @@ module Rake
47
50
  @verification_task = :verify
48
51
  @release_task = :release
49
52
  @version_bump_task = "version:bump"
50
- @update_rubygems = true
51
- @update_gems = true
52
- @run_bundle_audit = true
53
53
  @auto_pipeline = nil
54
54
  @gem_repositories = Repos.rubygems
55
55
  @gem_publisher_class = GemPublisher
56
56
  @gem_name = detect_gem_name
57
57
  @gem_version = detect_gem_version
58
+ apply_default_gem_update_configuration
59
+ apply_default_ruby_version_configuration
60
+ end
61
+
62
+ def apply_default_gem_update_configuration
63
+ @update_rubygems = true
64
+ @update_gems = true
65
+ @run_bundle_audit = true
66
+ end
67
+
68
+ def apply_default_ruby_version_configuration
69
+ @update_ruby = true
70
+ @ruby_version_checker_class = RubyVersionChecker
71
+ @ruby_version_updater_class = RubyVersionUpdater
58
72
  end
59
73
 
60
74
  private
@@ -216,6 +230,7 @@ module Rake
216
230
  end
217
231
 
218
232
  def do_upgrade_gems
233
+ update_ruby_versions if update_ruby
219
234
  sh "gem update --system" if update_rubygems
220
235
  sh "gem update" if update_gems
221
236
  sh "bundle update --bundler"
@@ -223,6 +238,16 @@ module Rake
223
238
  sh "bundle audit" if run_bundle_audit
224
239
  end
225
240
 
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
250
+
226
251
  def commit_changes
227
252
  sh "git add #{files_to_commit.join(' ')}"
228
253
  sh "git commit -m '#{commit_message}'"
@@ -3,7 +3,7 @@
3
3
  module Rake
4
4
  module Gem
5
5
  module Maintenance
6
- VERSION = "0.2.0"
6
+ VERSION = "0.2.1"
7
7
  end
8
8
  end
9
9
  end
@@ -4,6 +4,8 @@ require_relative "maintenance/version"
4
4
  require_relative "maintenance/version_bump_task"
5
5
  require_relative "maintenance/ci_environment"
6
6
  require_relative "maintenance/credential_store"
7
+ require_relative "maintenance/ruby_version_checker"
8
+ require_relative "maintenance/ruby_version_updater"
7
9
  require_relative "maintenance/otp_provider"
8
10
  require_relative "maintenance/ruby_gems_api_key_creator"
9
11
  require_relative "maintenance/woodpecker_secret_store"
@@ -13,3 +15,4 @@ require_relative "maintenance/gem_push"
13
15
  require_relative "maintenance/gem_publisher"
14
16
  require_relative "maintenance/repos"
15
17
  require_relative "maintenance/upgrade_task"
18
+ require_relative "maintenance/rubygems_publish_task"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rake-gem-maintenance
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christophe Broult
@@ -85,7 +85,6 @@ files:
85
85
  - LICENSE.txt
86
86
  - README.md
87
87
  - Rakefile
88
- - TODO.md
89
88
  - cucumber.yml
90
89
  - lib/rake/gem/maintenance.rb
91
90
  - lib/rake/gem/maintenance/api_key_renewer.rb
@@ -98,6 +97,9 @@ files:
98
97
  - lib/rake/gem/maintenance/renew_api_key_task.rb
99
98
  - lib/rake/gem/maintenance/repos.rb
100
99
  - lib/rake/gem/maintenance/ruby_gems_api_key_creator.rb
100
+ - lib/rake/gem/maintenance/ruby_version_checker.rb
101
+ - lib/rake/gem/maintenance/ruby_version_updater.rb
102
+ - lib/rake/gem/maintenance/rubygems_publish_task.rb
101
103
  - lib/rake/gem/maintenance/upgrade_task.rb
102
104
  - lib/rake/gem/maintenance/version.rb
103
105
  - lib/rake/gem/maintenance/version_bump_task.rb
data/TODO.md DELETED
@@ -1,4 +0,0 @@
1
- # Packwerk
2
-
3
- Packwerk is Shopify's package enforcement tool designed for large Rails monoliths.
4
- With ~15 files in this library gem, the overhead is not warranted — close without implementing.