kettle-dev 1.2.4 → 2.0.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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +232 -3
- data/CITATION.cff +6 -6
- data/CONTRIBUTING.md +64 -46
- data/FUNDING.md +1 -1
- data/LICENSE.md +12 -0
- data/README.md +448 -457
- data/certs/pboling.pem +27 -0
- data/exe/kettle-changelog +24 -13
- data/exe/kettle-check-eof +7 -0
- data/exe/kettle-check-eof.sh +118 -0
- data/exe/kettle-dev-setup +12 -63
- data/exe/kettle-gh-release +82 -0
- data/lib/kettle/dev/changelog_cli.rb +373 -62
- data/lib/kettle/dev/ci_monitor.rb +2 -2
- data/lib/kettle/dev/dvcs_cli.rb +1 -1
- data/lib/kettle/dev/gem_spec_reader.rb +100 -10
- data/lib/kettle/dev/git_adapter.rb +37 -1
- data/lib/kettle/dev/open_collective_config.rb +15 -3
- data/lib/kettle/dev/pre_release_cli.rb +4 -4
- data/lib/kettle/dev/rakelib/reek.rake +9 -6
- data/lib/kettle/dev/rakelib/spec_test.rake +25 -25
- data/lib/kettle/dev/rakelib/yard.rake +17 -17
- data/lib/kettle/dev/readme_backers.rb +4 -4
- data/lib/kettle/dev/release_cli.rb +27 -24
- data/lib/kettle/dev/tasks/ci_task.rb +4 -4
- data/lib/kettle/dev/version.rb +2 -87
- data/lib/kettle/dev.rb +31 -17
- data/sig/kettle/dev/source_merger.rbs +40 -56
- data/sig/kettle/dev/version.rbs +8 -0
- data.tar.gz.sig +0 -0
- metadata +63 -165
- metadata.gz.sig +0 -0
- data/.aiignore.example +0 -19
- data/.devcontainer/apt-install/devcontainer-feature.json +0 -9
- data/.devcontainer/apt-install/install.sh +0 -11
- data/.devcontainer/devcontainer.json +0 -28
- data/.env.local.example +0 -31
- data/.envrc +0 -47
- data/.envrc.example +0 -51
- data/.envrc.no-osc.example +0 -51
- data/.git-hooks/commit-msg +0 -54
- data/.git-hooks/commit-subjects-goalie.txt +0 -8
- data/.git-hooks/footer-template.erb.txt +0 -16
- data/.git-hooks/prepare-commit-msg +0 -8
- data/.github/.codecov.yml.example +0 -14
- data/.github/FUNDING.yml +0 -13
- data/.github/FUNDING.yml.no-osc.example +0 -13
- data/.github/dependabot.yml +0 -13
- data/.github/workflows/ancient.yml +0 -83
- data/.github/workflows/ancient.yml.example +0 -81
- data/.github/workflows/auto-assign.yml +0 -21
- data/.github/workflows/codeql-analysis.yml +0 -70
- data/.github/workflows/coverage.yml +0 -127
- data/.github/workflows/coverage.yml.example +0 -127
- data/.github/workflows/current.yml +0 -116
- data/.github/workflows/current.yml.example +0 -115
- data/.github/workflows/dep-heads.yml +0 -117
- data/.github/workflows/dependency-review.yml +0 -20
- data/.github/workflows/discord-notifier.yml.example +0 -39
- data/.github/workflows/heads.yml +0 -117
- data/.github/workflows/heads.yml.example +0 -116
- data/.github/workflows/jruby.yml +0 -82
- data/.github/workflows/jruby.yml.example +0 -72
- data/.github/workflows/legacy.yml +0 -76
- data/.github/workflows/license-eye.yml +0 -40
- data/.github/workflows/locked_deps.yml +0 -85
- data/.github/workflows/opencollective.yml +0 -40
- data/.github/workflows/style.yml +0 -67
- data/.github/workflows/supported.yml +0 -75
- data/.github/workflows/truffle.yml +0 -99
- data/.github/workflows/unlocked_deps.yml +0 -84
- data/.github/workflows/unsupported.yml +0 -76
- data/.gitignore +0 -50
- data/.gitlab-ci.yml.example +0 -134
- data/.idea/.gitignore +0 -45
- data/.junie/guidelines-rbs.md +0 -49
- data/.junie/guidelines.md +0 -141
- data/.junie/guidelines.md.example +0 -140
- data/.licenserc.yaml +0 -7
- data/.opencollective.yml +0 -3
- data/.opencollective.yml.example +0 -3
- data/.qlty/qlty.toml +0 -79
- data/.rspec +0 -9
- data/.rubocop.yml +0 -13
- data/.rubocop_rspec.yml +0 -33
- data/.simplecov +0 -16
- data/.simplecov.example +0 -11
- data/.tool-versions +0 -1
- data/.yardignore +0 -13
- data/.yardopts +0 -14
- data/Appraisal.root.gemfile +0 -10
- data/Appraisals +0 -151
- data/Appraisals.example +0 -102
- data/CHANGELOG.md.example +0 -47
- data/CONTRIBUTING.md.example +0 -227
- data/FUNDING.md.no-osc.example +0 -63
- data/Gemfile +0 -40
- data/Gemfile.example +0 -34
- data/LICENSE.txt +0 -21
- data/README.md.example +0 -570
- data/README.md.no-osc.example +0 -536
- data/REEK +0 -0
- data/Rakefile.example +0 -68
- data/bin/setup +0 -8
- data/gemfiles/modular/coverage.gemfile +0 -6
- data/gemfiles/modular/debug.gemfile +0 -13
- data/gemfiles/modular/documentation.gemfile +0 -14
- data/gemfiles/modular/erb/r2/v3.0.gemfile +0 -1
- data/gemfiles/modular/erb/r2.3/default.gemfile +0 -6
- data/gemfiles/modular/erb/r2.6/v2.2.gemfile +0 -3
- data/gemfiles/modular/erb/r3/v5.0.gemfile +0 -1
- data/gemfiles/modular/erb/r3.1/v4.0.gemfile +0 -2
- data/gemfiles/modular/erb/vHEAD.gemfile +0 -2
- data/gemfiles/modular/injected.gemfile +0 -60
- data/gemfiles/modular/mutex_m/r2/v0.3.gemfile +0 -2
- data/gemfiles/modular/mutex_m/r2.4/v0.1.gemfile +0 -3
- data/gemfiles/modular/mutex_m/r3/v0.3.gemfile +0 -2
- data/gemfiles/modular/mutex_m/vHEAD.gemfile +0 -2
- data/gemfiles/modular/optional.gemfile +0 -8
- data/gemfiles/modular/optional.gemfile.example +0 -5
- data/gemfiles/modular/runtime_heads.gemfile +0 -10
- data/gemfiles/modular/runtime_heads.gemfile.example +0 -8
- data/gemfiles/modular/stringio/r2/v3.0.gemfile +0 -5
- data/gemfiles/modular/stringio/r2.4/v0.0.2.gemfile +0 -4
- data/gemfiles/modular/stringio/r3/v3.0.gemfile +0 -5
- data/gemfiles/modular/stringio/vHEAD.gemfile +0 -2
- data/gemfiles/modular/style.gemfile +0 -25
- data/gemfiles/modular/style.gemfile.example +0 -25
- data/gemfiles/modular/templating.gemfile +0 -3
- data/gemfiles/modular/x_std_libs/r2/libs.gemfile +0 -3
- data/gemfiles/modular/x_std_libs/r2.3/libs.gemfile +0 -3
- data/gemfiles/modular/x_std_libs/r2.4/libs.gemfile +0 -3
- data/gemfiles/modular/x_std_libs/r2.6/libs.gemfile +0 -3
- data/gemfiles/modular/x_std_libs/r3/libs.gemfile +0 -3
- data/gemfiles/modular/x_std_libs/r3.1/libs.gemfile +0 -3
- data/gemfiles/modular/x_std_libs/vHEAD.gemfile +0 -3
- data/gemfiles/modular/x_std_libs.gemfile +0 -2
- data/kettle-dev.gemspec.example +0 -154
- data/lib/kettle/dev/modular_gemfiles.rb +0 -119
- data/lib/kettle/dev/prism_appraisals.rb +0 -351
- data/lib/kettle/dev/prism_gemfile.rb +0 -177
- data/lib/kettle/dev/prism_gemspec.rb +0 -284
- data/lib/kettle/dev/prism_utils.rb +0 -201
- data/lib/kettle/dev/rakelib/install.rake +0 -10
- data/lib/kettle/dev/rakelib/template.rake +0 -10
- data/lib/kettle/dev/setup_cli.rb +0 -403
- data/lib/kettle/dev/source_merger.rb +0 -655
- data/lib/kettle/dev/tasks/install_task.rb +0 -553
- data/lib/kettle/dev/tasks/template_task.rb +0 -975
- data/lib/kettle/dev/template_helpers.rb +0 -685
|
@@ -21,7 +21,7 @@ module Kettle
|
|
|
21
21
|
# For Bundler-invoked build/release, explicitly prefix SKIP_GEM_SIGNING so
|
|
22
22
|
# the signing step is skipped even when Bundler scrubs ENV.
|
|
23
23
|
# Always do this on CI to avoid interactive prompts; locally only when explicitly requested.
|
|
24
|
-
if ENV["SKIP_GEM_SIGNING"] &&
|
|
24
|
+
if ENV["SKIP_GEM_SIGNING"] && /\Abundle(\s+exec)?\s+rake\s+(build|release)\b/.match?(cmd)
|
|
25
25
|
cmd = "SKIP_GEM_SIGNING=true #{cmd}"
|
|
26
26
|
end
|
|
27
27
|
puts "$ #{cmd}"
|
|
@@ -31,7 +31,7 @@ module Kettle
|
|
|
31
31
|
# Some commands are interactive (e.g., `bundle exec rake release` prompting for RubyGems MFA).
|
|
32
32
|
# Using capture3 detaches STDIN, preventing prompts from working. For such commands, use system
|
|
33
33
|
# so they inherit the current TTY and can read the user's input.
|
|
34
|
-
interactive =
|
|
34
|
+
interactive = /\Abundle(\s+exec)?\s+rake\s+release\b/.match?(cmd) || /\Agem\s+push\b/.match?(cmd)
|
|
35
35
|
if interactive
|
|
36
36
|
ok = system(env_hash, cmd)
|
|
37
37
|
unless ok
|
|
@@ -97,9 +97,9 @@ module Kettle
|
|
|
97
97
|
gem_name = detect_gem_name
|
|
98
98
|
latest_overall, latest_for_series = latest_released_versions(gem_name, version)
|
|
99
99
|
rescue StandardError => e
|
|
100
|
-
warn("[kettle-release]
|
|
101
|
-
warn(e.backtrace.first(3).map { |l| " " + l }.join("\n")) if ENV["
|
|
102
|
-
warn("Proceeding without
|
|
100
|
+
warn("[kettle-release] gem.coop release check failed: #{e.class}: #{e.message}")
|
|
101
|
+
warn(e.backtrace.first(3).map { |l| " " + l }.join("\n")) if ENV["KETTLE_DEV_DEBUG"]
|
|
102
|
+
warn("Proceeding without gem.coop latest version info.")
|
|
103
103
|
end
|
|
104
104
|
|
|
105
105
|
if latest_overall
|
|
@@ -121,7 +121,7 @@ module Kettle
|
|
|
121
121
|
latest_for_series = nil unless lfs_series == cur_series
|
|
122
122
|
end
|
|
123
123
|
# Determine the sanity-check target correctly for the current series.
|
|
124
|
-
# If
|
|
124
|
+
# If gem.coop has a newer overall series than our current series, only compare
|
|
125
125
|
# against the latest published in our current series. If that cannot be determined
|
|
126
126
|
# (e.g., offline), skip the sanity check rather than treating the overall as target.
|
|
127
127
|
target = if (cur_series <=> overall_series) == -1
|
|
@@ -130,10 +130,10 @@ module Kettle
|
|
|
130
130
|
latest_overall
|
|
131
131
|
end
|
|
132
132
|
# IMPORTANT: Never treat a higher different-series "latest_overall" as a downgrade target.
|
|
133
|
-
# If our current series is behind overall and
|
|
133
|
+
# If our current series is behind overall and gem.coop does not report a latest_for_series,
|
|
134
134
|
# then we cannot determine the correct target for this series and should skip the check.
|
|
135
135
|
if (cur_series <=> overall_series) == -1 && target.nil?
|
|
136
|
-
puts "Could not determine latest released version from
|
|
136
|
+
puts "Could not determine latest released version from gem.coop (offline?). Proceeding without sanity check."
|
|
137
137
|
elsif target
|
|
138
138
|
bump = Kettle::Dev::Versioning.classify_bump(target, version)
|
|
139
139
|
case bump
|
|
@@ -150,10 +150,10 @@ module Kettle
|
|
|
150
150
|
puts "Proposed bump type: #{label} (from #{target} -> #{version})"
|
|
151
151
|
end
|
|
152
152
|
else
|
|
153
|
-
puts "Could not determine latest released version from
|
|
153
|
+
puts "Could not determine latest released version from gem.coop (offline?). Proceeding without sanity check."
|
|
154
154
|
end
|
|
155
155
|
else
|
|
156
|
-
puts "Could not determine latest released version from
|
|
156
|
+
puts "Could not determine latest released version from gem.coop (offline?). Proceeding without sanity check."
|
|
157
157
|
end
|
|
158
158
|
|
|
159
159
|
puts "Have you updated lib/**/version.rb and CHANGELOG.md for v#{version}? [y/N]"
|
|
@@ -184,15 +184,18 @@ module Kettle
|
|
|
184
184
|
# 4. bin/rake
|
|
185
185
|
run_cmd!("bin/rake") if @start_step <= 4
|
|
186
186
|
|
|
187
|
-
# 5. appraisal:update (optional)
|
|
187
|
+
# 5. appraisal:update (optional) + canonical docs build
|
|
188
188
|
if @start_step <= 5
|
|
189
189
|
appraisals_path = File.join(@root, "Appraisals")
|
|
190
190
|
if File.file?(appraisals_path)
|
|
191
|
-
puts "Appraisals detected at #{appraisals_path}. Running: bin/rake appraisal:update"
|
|
191
|
+
puts "Appraisals detected at #{Kettle::Dev.display_path(appraisals_path)}. Running: bin/rake appraisal:update"
|
|
192
192
|
run_cmd!("bin/rake appraisal:update")
|
|
193
193
|
else
|
|
194
194
|
puts "No Appraisals file found; skipping appraisal:update"
|
|
195
195
|
end
|
|
196
|
+
|
|
197
|
+
puts "Generating docs site via canonical task: bin/rake yard"
|
|
198
|
+
run_cmd!("bin/rake yard")
|
|
196
199
|
end
|
|
197
200
|
|
|
198
201
|
# 6. git user + commit release prep
|
|
@@ -317,7 +320,7 @@ module Kettle
|
|
|
317
320
|
return unless section
|
|
318
321
|
|
|
319
322
|
# Example match: "- COVERAGE: 97.70% -- 2125/2175 lines in 20 files"
|
|
320
|
-
m = section.lines.find { |l|
|
|
323
|
+
m = section.lines.find { |l| /-\s*COVERAGE:\s*.+--\s*\d+\/(\d+)\s+lines/i.match?(l) }
|
|
321
324
|
return unless m
|
|
322
325
|
|
|
323
326
|
denom = m.match(/-\s*COVERAGE:\s*.+--\s*\d+\/(\d+)\s+lines/i)[1].to_i
|
|
@@ -408,7 +411,7 @@ module Kettle
|
|
|
408
411
|
content = File.read(path)
|
|
409
412
|
# Only consider lines that look like copyright notices to reduce false positives
|
|
410
413
|
content.each_line do |line|
|
|
411
|
-
next unless
|
|
414
|
+
next unless /copyright/i.match?(line)
|
|
412
415
|
|
|
413
416
|
# Expand ranges first (supports hyphen-minus and en dash)
|
|
414
417
|
line.scan(/\b(19\d{2}|20\d{2})\s*[\-–]\s*(19\d{2}|20\d{2})\b/).each do |a, b|
|
|
@@ -459,7 +462,7 @@ module Kettle
|
|
|
459
462
|
changed = false
|
|
460
463
|
canonical_all = collapse_years(years_set)
|
|
461
464
|
new_lines = content.each_line.map do |line|
|
|
462
|
-
unless
|
|
465
|
+
unless /copyright/i.match?(line)
|
|
463
466
|
next line
|
|
464
467
|
end
|
|
465
468
|
|
|
@@ -483,7 +486,7 @@ module Kettle
|
|
|
483
486
|
content = File.read(path)
|
|
484
487
|
changed = false
|
|
485
488
|
new_lines = content.each_line.map do |line|
|
|
486
|
-
unless
|
|
489
|
+
unless /copyright/i.match?(line)
|
|
487
490
|
next line
|
|
488
491
|
end
|
|
489
492
|
|
|
@@ -556,7 +559,7 @@ module Kettle
|
|
|
556
559
|
when "ask"
|
|
557
560
|
print("Run local CI with 'act' before pushing? [Y/n] ")
|
|
558
561
|
ans = Kettle::Dev::InputAdapter.gets&.strip
|
|
559
|
-
ans.nil? || ans.empty? ||
|
|
562
|
+
ans.nil? || ans.empty? || /\Ay(es)?\z/i.match?(ans)
|
|
560
563
|
else
|
|
561
564
|
false
|
|
562
565
|
end
|
|
@@ -579,7 +582,7 @@ module Kettle
|
|
|
579
582
|
|
|
580
583
|
chosen = (ENV["K_RELEASE_LOCAL_CI_WORKFLOW"] || "").strip
|
|
581
584
|
if !chosen.empty?
|
|
582
|
-
chosen = "#{chosen}.yml" unless
|
|
585
|
+
chosen = "#{chosen}.yml" unless /\.ya?ml\z/.match?(chosen)
|
|
583
586
|
else
|
|
584
587
|
chosen = if candidates.include?("locked_deps.yml")
|
|
585
588
|
"locked_deps.yml"
|
|
@@ -597,7 +600,7 @@ module Kettle
|
|
|
597
600
|
|
|
598
601
|
file_path = File.join(workflows_dir, chosen)
|
|
599
602
|
unless File.file?(file_path)
|
|
600
|
-
puts "Skipping local CI: selected workflow not found: #{file_path}"
|
|
603
|
+
puts "Skipping local CI: selected workflow not found: #{Kettle::Dev.display_path(file_path)}"
|
|
601
604
|
return
|
|
602
605
|
end
|
|
603
606
|
|
|
@@ -625,18 +628,18 @@ module Kettle
|
|
|
625
628
|
path = gemspecs.min
|
|
626
629
|
content = File.read(path)
|
|
627
630
|
m = content.match(/spec\.name\s*=\s*(["'])([^"']+)\1/)
|
|
628
|
-
abort("Could not determine gem name from #{path}.") unless m
|
|
631
|
+
abort("Could not determine gem name from #{Kettle::Dev.display_path(path)}.") unless m
|
|
629
632
|
m[2]
|
|
630
633
|
end
|
|
631
634
|
|
|
632
635
|
def latest_released_versions(gem_name, current_version)
|
|
633
|
-
uri = URI("https://
|
|
636
|
+
uri = URI("https://gem.coop/api/v1/versions/#{gem_name}.json")
|
|
634
637
|
res = Net::HTTP.get_response(uri)
|
|
635
638
|
return [nil, nil] unless res.is_a?(Net::HTTPSuccess)
|
|
636
639
|
|
|
637
640
|
data = JSON.parse(res.body)
|
|
638
641
|
versions = data.map { |h| h["number"] }.compact
|
|
639
|
-
versions.reject! { |v| v.to_s.include?("-pre") || v.to_s.include?(".pre") ||
|
|
642
|
+
versions.reject! { |v| v.to_s.include?("-pre") || v.to_s.include?(".pre") || /[a-zA-Z]/.match?(v.to_s) }
|
|
640
643
|
gversions = versions.map { |s| Gem::Version.new(s) }.sort
|
|
641
644
|
latest_overall = gversions.last&.to_s
|
|
642
645
|
|
|
@@ -924,11 +927,11 @@ module Kettle
|
|
|
924
927
|
unless File.exist?(cert_path)
|
|
925
928
|
abort(<<~MSG)
|
|
926
929
|
Gem signing appears enabled but no public cert found at:
|
|
927
|
-
#{cert_path}
|
|
930
|
+
#{Kettle::Dev.display_path(cert_path)}
|
|
928
931
|
Add your public key to certs/<USER>.pem (or set GEM_CERT_USER), or set SKIP_GEM_SIGNING to build unsigned.
|
|
929
932
|
MSG
|
|
930
933
|
end
|
|
931
|
-
puts "Found signing cert: #{cert_path}"
|
|
934
|
+
puts "Found signing cert: #{Kettle::Dev.display_path(cert_path)}"
|
|
932
935
|
puts "When prompted during build/release, enter the PEM password for ~/.ssh/gem-private_key.pem"
|
|
933
936
|
end
|
|
934
937
|
|
|
@@ -265,11 +265,11 @@ module Kettle
|
|
|
265
265
|
selected = nil
|
|
266
266
|
# Create input thread always so specs that assert its cleanup/exception behavior can exercise it,
|
|
267
267
|
# but guard against non-interactive stdin by rescuing 'bad tty' and similar errors immediately.
|
|
268
|
-
input_thread = Thread.new do
|
|
268
|
+
input_thread = Thread.new do # rubocop:disable ThreadSafety/NewThread
|
|
269
269
|
begin
|
|
270
270
|
selected = Kettle::Dev::InputAdapter.gets&.strip
|
|
271
|
-
rescue
|
|
272
|
-
# Catch
|
|
271
|
+
rescue StandardError, SystemExit, Interrupt => error
|
|
272
|
+
# Catch exceptions in background thread, including SystemExit
|
|
273
273
|
# NOTE: look into refactoring to minimize potential SystemExit.
|
|
274
274
|
puts "Error in background thread: #{error.class}: #{error.message}" if Kettle::Dev::DEBUGGING
|
|
275
275
|
selected = :input_error
|
|
@@ -281,7 +281,7 @@ module Kettle
|
|
|
281
281
|
start_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
282
282
|
|
|
283
283
|
options.each do |code, file|
|
|
284
|
-
workers << Thread.new(code, file, owner, repo, branch, token, start_at) do |c, f, ow, rp, br, tk, st_at|
|
|
284
|
+
workers << Thread.new(code, file, owner, repo, branch, token, start_at) do |c, f, ow, rp, br, tk, st_at| # rubocop:disable ThreadSafety/NewThread
|
|
285
285
|
begin
|
|
286
286
|
now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
287
287
|
delay = 0.12 - (now - st_at)
|
data/lib/kettle/dev/version.rb
CHANGED
|
@@ -2,94 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
module Kettle
|
|
4
4
|
module Dev
|
|
5
|
-
# Version namespace for kettle-dev.
|
|
6
5
|
module Version
|
|
7
|
-
|
|
8
|
-
# @return [String]
|
|
9
|
-
VERSION = "1.2.4"
|
|
10
|
-
|
|
11
|
-
module_function
|
|
12
|
-
|
|
13
|
-
# rubocop:disable ThreadSafety/ClassInstanceVariable
|
|
14
|
-
#
|
|
15
|
-
# The logic below, through the end of the file, comes from version_gem.
|
|
16
|
-
# Extracted because version_gem depends on this gem, and circular dependencies are bad.
|
|
17
|
-
#
|
|
18
|
-
# A Gem::Version for this version string
|
|
19
|
-
#
|
|
20
|
-
# Useful when you need to compare versions or pass a Gem::Version instance
|
|
21
|
-
# to APIs that expect it. This is equivalent to `Gem::Version.new(to_s)`.
|
|
22
|
-
#
|
|
23
|
-
# @return [Gem::Version]
|
|
24
|
-
def gem_version
|
|
25
|
-
@gem_version ||= ::Gem::Version.new(to_s)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# The version number as a string
|
|
29
|
-
#
|
|
30
|
-
# @return [String]
|
|
31
|
-
def to_s
|
|
32
|
-
self::VERSION
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
# The major version
|
|
36
|
-
#
|
|
37
|
-
# @return [Integer]
|
|
38
|
-
def major
|
|
39
|
-
@major ||= _to_a[0].to_i
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# The minor version
|
|
43
|
-
#
|
|
44
|
-
# @return [Integer]
|
|
45
|
-
def minor
|
|
46
|
-
@minor ||= _to_a[1].to_i
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
# The patch version
|
|
50
|
-
#
|
|
51
|
-
# @return [Integer]
|
|
52
|
-
def patch
|
|
53
|
-
@patch ||= _to_a[2].to_i
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
# The pre-release version, if any
|
|
57
|
-
#
|
|
58
|
-
# @return [String, NilClass]
|
|
59
|
-
def pre
|
|
60
|
-
@pre ||= _to_a[3]
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
# The version number as a hash
|
|
64
|
-
#
|
|
65
|
-
# @return [Hash]
|
|
66
|
-
def to_h
|
|
67
|
-
@to_h ||= {
|
|
68
|
-
major: major,
|
|
69
|
-
minor: minor,
|
|
70
|
-
patch: patch,
|
|
71
|
-
pre: pre,
|
|
72
|
-
}
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
# The version number as an array of cast values
|
|
76
|
-
#
|
|
77
|
-
# @return [Array<[Integer, String, NilClass]>]
|
|
78
|
-
def to_a
|
|
79
|
-
@to_a ||= [major, minor, patch, pre]
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
private
|
|
83
|
-
|
|
84
|
-
module_function
|
|
85
|
-
|
|
86
|
-
# The version number as an array of strings
|
|
87
|
-
#
|
|
88
|
-
# @return [Array<String>]
|
|
89
|
-
def _to_a
|
|
90
|
-
@_to_a = self::VERSION.split(".")
|
|
91
|
-
end
|
|
92
|
-
# rubocop:enable ThreadSafety/ClassInstanceVariable
|
|
6
|
+
VERSION = "2.0.1"
|
|
93
7
|
end
|
|
8
|
+
VERSION = Version::VERSION # Traditional Constant Location
|
|
94
9
|
end
|
|
95
10
|
end
|
data/lib/kettle/dev.rb
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "version_gem"
|
|
4
|
+
require_relative "dev/version"
|
|
5
|
+
|
|
6
|
+
Kettle::Dev::Version.class_eval do
|
|
7
|
+
extend VersionGem::Basic
|
|
8
|
+
end
|
|
3
9
|
# External gems
|
|
10
|
+
|
|
4
11
|
# It's not reasonable to test this ENV variable
|
|
5
12
|
# :nocov:
|
|
6
13
|
require "require_bench" if ENV.fetch("REQUIRE_BENCH", "false").casecmp("true").zero?
|
|
@@ -21,35 +28,25 @@ module Kettle
|
|
|
21
28
|
autoload :GitAdapter, "kettle/dev/git_adapter"
|
|
22
29
|
autoload :GitCommitFooter, "kettle/dev/git_commit_footer"
|
|
23
30
|
autoload :InputAdapter, "kettle/dev/input_adapter"
|
|
24
|
-
autoload :PrismUtils, "kettle/dev/prism_utils"
|
|
25
|
-
autoload :PrismGemspec, "kettle/dev/prism_gemspec"
|
|
26
|
-
autoload :PrismGemfile, "kettle/dev/prism_gemfile"
|
|
27
|
-
autoload :PrismAppraisals, "kettle/dev/prism_appraisals"
|
|
28
31
|
autoload :ReadmeBackers, "kettle/dev/readme_backers"
|
|
29
32
|
autoload :OpenCollectiveConfig, "kettle/dev/open_collective_config"
|
|
30
|
-
autoload :SourceMerger, "kettle/dev/source_merger"
|
|
31
33
|
autoload :ReleaseCLI, "kettle/dev/release_cli"
|
|
32
34
|
autoload :PreReleaseCLI, "kettle/dev/pre_release_cli"
|
|
33
|
-
autoload :SetupCLI, "kettle/dev/setup_cli"
|
|
34
|
-
autoload :TemplateHelpers, "kettle/dev/template_helpers"
|
|
35
|
-
autoload :ModularGemfiles, "kettle/dev/modular_gemfiles"
|
|
36
35
|
autoload :Version, "kettle/dev/version"
|
|
37
36
|
autoload :Versioning, "kettle/dev/versioning"
|
|
38
37
|
|
|
39
38
|
# Nested tasks namespace with autoloaded task modules
|
|
40
39
|
module Tasks
|
|
41
40
|
autoload :CITask, "kettle/dev/tasks/ci_task"
|
|
42
|
-
autoload :InstallTask, "kettle/dev/tasks/install_task"
|
|
43
|
-
autoload :TemplateTask, "kettle/dev/tasks/template_task"
|
|
44
41
|
end
|
|
45
42
|
|
|
46
43
|
# Base error type for kettle-dev.
|
|
47
44
|
class Error < StandardError; end
|
|
48
45
|
|
|
49
46
|
# Whether debug logging is enabled for kettle-dev internals.
|
|
50
|
-
#
|
|
47
|
+
# Controlled by KETTLE_DEV_DEBUG=true.
|
|
51
48
|
# @return [Boolean]
|
|
52
|
-
DEBUGGING = ENV.fetch("KETTLE_DEV_DEBUG",
|
|
49
|
+
DEBUGGING = ENV.fetch("KETTLE_DEV_DEBUG", "false").casecmp("true").zero?
|
|
53
50
|
# Whether we are running on CI.
|
|
54
51
|
# @return [Boolean]
|
|
55
52
|
IS_CI = ENV.fetch("CI", "false").casecmp("true") == 0
|
|
@@ -76,25 +73,42 @@ module Kettle
|
|
|
76
73
|
# @return [String]
|
|
77
74
|
GEM_ROOT = File.expand_path("../..", __dir__)
|
|
78
75
|
|
|
79
|
-
@defaults = []
|
|
76
|
+
@defaults = [].freeze
|
|
80
77
|
|
|
81
78
|
class << self
|
|
79
|
+
VAR_HOME_PREFIX = %r{\A/var/home(?=/|\z)}
|
|
80
|
+
VAR_HOME_TEXT = %r{/var/home(?=/|\z)}
|
|
81
|
+
|
|
82
|
+
def display_path(path)
|
|
83
|
+
return path if path.nil?
|
|
84
|
+
|
|
85
|
+
path.to_s.sub(VAR_HOME_PREFIX, "/home")
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def display_text(text)
|
|
89
|
+
return text if text.nil?
|
|
90
|
+
|
|
91
|
+
text.to_s.gsub(VAR_HOME_TEXT, "/home")
|
|
92
|
+
end
|
|
93
|
+
|
|
82
94
|
# Emit a debug warning for rescued errors when kettle-dev debugging is enabled.
|
|
83
|
-
# Controlled by KETTLE_DEV_DEBUG=true
|
|
95
|
+
# Controlled by KETTLE_DEV_DEBUG=true.
|
|
84
96
|
# @param error [Exception]
|
|
85
97
|
# @param context [String, Symbol, nil] optional label, often __method__
|
|
98
|
+
# @param backtrace [Boolean] whether to emit the rescued error backtrace
|
|
86
99
|
# @return [void]
|
|
87
|
-
def debug_error(error, context = nil)
|
|
100
|
+
def debug_error(error, context = nil, backtrace: true)
|
|
88
101
|
return unless DEBUGGING
|
|
89
102
|
|
|
90
103
|
ctx = context ? context.to_s : "KETTLE-DEV-RESCUE"
|
|
91
104
|
Kernel.warn("[#{ctx}] #{error.class}: #{error.message}")
|
|
105
|
+
Kernel.warn(Array(error.backtrace).first(5).join("\n")) if backtrace && error.respond_to?(:backtrace) && error.backtrace
|
|
92
106
|
rescue StandardError
|
|
93
107
|
# never raise from debug logging
|
|
94
108
|
end
|
|
95
109
|
|
|
96
110
|
# Emit a debug log line when kettle-dev debugging is enabled.
|
|
97
|
-
# Controlled by KETTLE_DEV_DEBUG=true
|
|
111
|
+
# Controlled by KETTLE_DEV_DEBUG=true.
|
|
98
112
|
# @param msg [String]
|
|
99
113
|
# @return [void]
|
|
100
114
|
def debug_log(msg, context = nil)
|
|
@@ -128,7 +142,7 @@ module Kettle
|
|
|
128
142
|
def register_default(task_name)
|
|
129
143
|
task_name = task_name.to_s
|
|
130
144
|
unless defaults.include?(task_name)
|
|
131
|
-
defaults
|
|
145
|
+
@defaults = (defaults + [task_name]).freeze # rubocop:disable ThreadSafety/ClassInstanceVariable
|
|
132
146
|
if defined?(Rake) && Rake::Task.task_defined?(:default)
|
|
133
147
|
begin
|
|
134
148
|
Rake::Task[:default].enhance([task_name])
|
|
@@ -2,15 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
module Kettle
|
|
4
4
|
module Dev
|
|
5
|
-
# Prism-based AST merging for templated Ruby files
|
|
5
|
+
# Prism-based AST merging for templated Ruby files.
|
|
6
|
+
# Handles strategy dispatch (skip/replace/append/merge).
|
|
7
|
+
#
|
|
8
|
+
# Uses prism-merge for AST-aware merging with support for:
|
|
9
|
+
# - Freeze blocks (kettle-dev:freeze / kettle-dev:unfreeze)
|
|
10
|
+
# - Comment preservation
|
|
11
|
+
# - Signature-based node matching
|
|
6
12
|
module SourceMerger
|
|
7
|
-
FREEZE_START: Regexp
|
|
8
|
-
FREEZE_END: Regexp
|
|
9
|
-
FREEZE_BLOCK: Regexp
|
|
10
|
-
FREEZE_REMINDER: String
|
|
11
13
|
BUG_URL: String
|
|
12
14
|
|
|
13
15
|
# Apply a templating strategy to merge source and destination Ruby files
|
|
16
|
+
#
|
|
17
|
+
# @param strategy [Symbol] Merge strategy - :skip, :replace, :append, or :merge
|
|
18
|
+
# @param src [String] Template source content
|
|
19
|
+
# @param dest [String] Destination file content
|
|
20
|
+
# @param path [String] File path (for error messages)
|
|
21
|
+
# @return [String] Merged content with comments preserved
|
|
22
|
+
# @raise [Kettle::Dev::Error] If strategy is unknown or merge fails
|
|
14
23
|
def self.apply: (
|
|
15
24
|
strategy: Symbol,
|
|
16
25
|
src: String,
|
|
@@ -18,69 +27,44 @@ module Kettle
|
|
|
18
27
|
path: String
|
|
19
28
|
) -> String
|
|
20
29
|
|
|
21
|
-
# Ensure freeze reminder comment is present at the top of content
|
|
22
|
-
def self.ensure_reminder: (String content) -> String
|
|
23
|
-
|
|
24
|
-
# Normalize source code while preserving formatting
|
|
25
|
-
def self.normalize_source: (String source) -> String
|
|
26
|
-
|
|
27
|
-
# Check if freeze reminder is present in content
|
|
28
|
-
def self.reminder_present?: (String content) -> bool
|
|
29
|
-
|
|
30
|
-
# Find index where freeze reminder should be inserted
|
|
31
|
-
def self.reminder_insertion_index: (String content) -> Integer
|
|
32
|
-
|
|
33
|
-
# Check if line is a shebang
|
|
34
|
-
def self.shebang?: (String line) -> bool
|
|
35
|
-
|
|
36
|
-
# Check if line is a frozen_string_literal comment
|
|
37
|
-
def self.frozen_comment?: (String line) -> bool
|
|
38
|
-
|
|
39
|
-
# Merge kettle-dev:freeze blocks from destination into source content
|
|
40
|
-
def self.merge_freeze_blocks: (String src_content, String dest_content) -> String
|
|
41
|
-
|
|
42
|
-
# Extract freeze blocks from text
|
|
43
|
-
def self.freeze_blocks: (String? text) -> Array[Hash[Symbol, untyped]]
|
|
44
|
-
|
|
45
30
|
# Normalize strategy symbol
|
|
31
|
+
#
|
|
32
|
+
# @param strategy [Symbol, nil] Strategy to normalize
|
|
33
|
+
# @return [Symbol] Normalized strategy (:skip if nil)
|
|
46
34
|
def self.normalize_strategy: (Symbol? strategy) -> Symbol
|
|
47
35
|
|
|
48
36
|
# Warn about bugs and print error information
|
|
37
|
+
#
|
|
38
|
+
# @param path [String] File path that caused the error
|
|
39
|
+
# @param error [StandardError] The error that occurred
|
|
40
|
+
# @return [void]
|
|
49
41
|
def self.warn_bug: (String path, StandardError error) -> void
|
|
50
42
|
|
|
51
43
|
# Ensure text ends with newline
|
|
44
|
+
#
|
|
45
|
+
# @param text [String, nil] Text to process
|
|
46
|
+
# @return [String] Text with trailing newline
|
|
52
47
|
def self.ensure_trailing_newline: (String? text) -> String
|
|
53
48
|
|
|
54
|
-
# Apply append strategy
|
|
49
|
+
# Apply append strategy using prism-merge
|
|
50
|
+
#
|
|
51
|
+
# @param src_content [String] Template source content
|
|
52
|
+
# @param dest_content [String] Destination content
|
|
53
|
+
# @return [String] Merged content with destination preference
|
|
55
54
|
def self.apply_append: (String src_content, String dest_content) -> String
|
|
56
55
|
|
|
57
|
-
# Apply merge strategy
|
|
56
|
+
# Apply merge strategy using prism-merge
|
|
57
|
+
#
|
|
58
|
+
# @param src_content [String] Template source content
|
|
59
|
+
# @param dest_content [String] Destination content
|
|
60
|
+
# @return [String] Merged content with template preference
|
|
58
61
|
def self.apply_merge: (String src_content, String dest_content) -> String
|
|
59
62
|
|
|
60
|
-
#
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
#
|
|
64
|
-
def self.
|
|
65
|
-
|
|
66
|
-
# Perform Prism-based merge with block
|
|
67
|
-
def self.prism_merge: (String src_content, String dest_content) { (Array[Hash[Symbol, untyped]], Array[Hash[Symbol, untyped]], Prism::ParseResult, Prism::ParseResult) -> Array[Hash[Symbol, untyped]] } -> String
|
|
68
|
-
|
|
69
|
-
# Extract nodes with comments from parse result
|
|
70
|
-
def self.extract_nodes_with_comments: (Prism::ParseResult parse_result) -> Array[Hash[Symbol, untyped]]
|
|
71
|
-
|
|
72
|
-
# Build source from node information array
|
|
73
|
-
def self.build_source_from_nodes: (Array[Hash[Symbol, untyped]] node_infos) -> String
|
|
74
|
-
|
|
75
|
-
# Generate signature for node
|
|
76
|
-
def self.node_signature: (Prism::Node? node) -> Array[untyped]
|
|
77
|
-
|
|
78
|
-
# Restore custom leading comments from destination
|
|
79
|
-
def self.restore_custom_leading_comments: (String dest_content, String merged_content) -> String
|
|
80
|
-
|
|
81
|
-
# Extract leading comment block from content
|
|
82
|
-
def self.leading_comment_block: (String content) -> String
|
|
63
|
+
# Create a signature generator for prism-merge
|
|
64
|
+
# Handles various Ruby node types for proper matching during merge operations
|
|
65
|
+
#
|
|
66
|
+
# @return [Proc] Signature generator lambda
|
|
67
|
+
def self.create_signature_generator: () -> ^(Prism::Node) -> (Array[untyped] | Prism::Node)
|
|
83
68
|
end
|
|
84
69
|
end
|
|
85
|
-
end
|
|
86
|
-
|
|
70
|
+
end
|
data/sig/kettle/dev/version.rbs
CHANGED
data.tar.gz.sig
CHANGED
|
Binary file
|