kettle-dev 1.0.27 → 1.1.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: 5262ffaac8801d10dc7399ed6f111a5878e135d79cc48a155b386c92c86eab24
4
- data.tar.gz: 6a7415eb0b8e4da2d4a4a63eb10515209a2db42f4f82d1e822edd7754861a077
3
+ metadata.gz: 7ebcfa36b8ea0a35494d287786196a8d8318b8173c204761024313bf8f47427d
4
+ data.tar.gz: f0a9336ef171cbf601db976e1d6968e0653118b75aebe67467a7fbb5a75bb5c3
5
5
  SHA512:
6
- metadata.gz: dbaa7553ea88a2a702975b5650abb04f7a9f16892b8ea4d8b54353fa8036b15fc88c81ae560819ce8d1f45c2744b69d832e3a19a20ebbb3859044aa8f8d8b221
7
- data.tar.gz: f4a3e941cf43f6f4221f1ef65601114ccf864588aca25e20ef9b1691b101c840eb43ee86dd383ab360e0b4e5da58aa863d039e1e0861e49b48562dea0cd6770f
6
+ metadata.gz: 180dbf8af4b59be5cdfca9e96bebe9c9fabff568de0d633e7650975a59b1c59ba3f8f1b23105d35519a5c39212ef31625801e76562f5dd99f15dee0cbededb2a
7
+ data.tar.gz: e61a9a80d171187880f754633460dd1438d6eac481bb93a19c1cd0161111b161636e6440a18fbde8a28a110534839d3860e1055e0d9e4b900ca42350c87010e0
checksums.yaml.gz.sig CHANGED
Binary file
data/.simplecov CHANGED
@@ -8,4 +8,9 @@ SimpleCov.start do
8
8
  track_files "lib/**/*.rb"
9
9
  track_files "lib/**/*.rake"
10
10
  track_files "exe/*.rb"
11
+
12
+ # Version *is* tested (see spec/kettle/dev/version_spec.rb).
13
+ # Due to early loading, the Version class can't be tracked by SimpleCov.
14
+ # So we disable coverage here.
15
+ add_filter "lib/kettle/dev/version.rb"
11
16
  end
data/Appraisals CHANGED
@@ -26,6 +26,8 @@ appraise "unlocked_deps" do
26
26
  eval_gemfile "modular/style.gemfile"
27
27
  eval_gemfile "modular/optional.gemfile"
28
28
  eval_gemfile "modular/recording/r3/recording.gemfile"
29
+ # Dependencies injected by the kettle-dev-setup script & kettle:dev:install rake task
30
+ # eval_gemfile "modular/injected.gemfile"
29
31
  end
30
32
 
31
33
  # Used for head (nightly) releases of ruby, truffleruby, and jruby.
@@ -38,6 +40,8 @@ appraise "head" do
38
40
  gem "stringio", ">= 3.0"
39
41
  gem "benchmark", "~> 0.4", ">= 0.4.1"
40
42
  eval_gemfile "modular/recording/r3/recording.gemfile"
43
+ # Dependencies injected by the kettle-dev-setup script & kettle:dev:install rake task
44
+ # eval_gemfile "modular/injected.gemfile"
41
45
  end
42
46
 
43
47
  # Used for current releases of ruby, truffleruby, and jruby.
@@ -47,6 +51,8 @@ appraise "current" do
47
51
  gem "mutex_m", ">= 0.2"
48
52
  gem "stringio", ">= 3.0"
49
53
  eval_gemfile "modular/recording/r3/recording.gemfile"
54
+ # Dependencies injected by the kettle-dev-setup script & kettle:dev:install rake task
55
+ # eval_gemfile "modular/injected.gemfile"
50
56
  end
51
57
 
52
58
  appraise "ruby-2-3" do
@@ -55,16 +61,22 @@ appraise "ruby-2-3" do
55
61
  # /opt/hostedtoolcache/Ruby/2.3.8/x64/lib/ruby/gems/2.3.0/gems/erb-2.2.2/lib/erb.rb:670:in `prepare_trim_mode': undefined method `match?' for "-":String (NoMethodError)
56
62
  # spec.add_development_dependency("erb", ">= 2.2") # ruby >= 2.3.0, not SemVer, old rubies get dropped in a patch.
57
63
  eval_gemfile "modular/recording/r2.3/recording.gemfile"
64
+ # Dependencies injected by the kettle-dev-setup script & kettle:dev:install rake task
65
+ # eval_gemfile "modular/injected.gemfile"
58
66
  end
59
67
 
60
68
  appraise "ruby-2-4" do
61
69
  gem "erb"
62
70
  eval_gemfile "modular/recording/r2.4/recording.gemfile"
71
+ # Dependencies injected by the kettle-dev-setup script & kettle:dev:install rake task
72
+ # eval_gemfile "modular/injected.gemfile"
63
73
  end
64
74
 
65
75
  appraise "ruby-2-5" do
66
76
  gem "erb"
67
77
  eval_gemfile "modular/recording/r2.5/recording.gemfile"
78
+ # Dependencies injected by the kettle-dev-setup script & kettle:dev:install rake task
79
+ # eval_gemfile "modular/injected.gemfile"
68
80
  end
69
81
 
70
82
  appraise "ruby-2-6" do
@@ -72,6 +84,8 @@ appraise "ruby-2-6" do
72
84
  gem "mutex_m", "~> 0.2"
73
85
  gem "stringio", "~> 3.0"
74
86
  eval_gemfile "modular/recording/r2.5/recording.gemfile"
87
+ # Dependencies injected by the kettle-dev-setup script & kettle:dev:install rake task
88
+ # eval_gemfile "modular/injected.gemfile"
75
89
  end
76
90
 
77
91
  appraise "ruby-2-7" do
@@ -79,6 +93,8 @@ appraise "ruby-2-7" do
79
93
  gem "mutex_m", "~> 0.2"
80
94
  gem "stringio", "~> 3.0"
81
95
  eval_gemfile "modular/recording/r2.5/recording.gemfile"
96
+ # Dependencies injected by the kettle-dev-setup script & kettle:dev:install rake task
97
+ # eval_gemfile "modular/injected.gemfile"
82
98
  end
83
99
 
84
100
  appraise "ruby-3-0" do
@@ -86,6 +102,8 @@ appraise "ruby-3-0" do
86
102
  gem "mutex_m", "~> 0.2"
87
103
  gem "stringio", "~> 3.0"
88
104
  eval_gemfile "modular/recording/r3/recording.gemfile"
105
+ # Dependencies injected by the kettle-dev-setup script & kettle:dev:install rake task
106
+ # eval_gemfile "modular/injected.gemfile"
89
107
  end
90
108
 
91
109
  appraise "ruby-3-1" do
@@ -95,6 +113,8 @@ appraise "ruby-3-1" do
95
113
  gem "mutex_m", "~> 0.2"
96
114
  gem "stringio", "~> 3.0"
97
115
  eval_gemfile "modular/recording/r3/recording.gemfile"
116
+ # Dependencies injected by the kettle-dev-setup script & kettle:dev:install rake task
117
+ # eval_gemfile "modular/injected.gemfile"
98
118
  end
99
119
 
100
120
  appraise "ruby-3-2" do
@@ -104,6 +124,8 @@ appraise "ruby-3-2" do
104
124
  gem "mutex_m", "~> 0.2"
105
125
  gem "stringio", "~> 3.0"
106
126
  eval_gemfile "modular/recording/r3/recording.gemfile"
127
+ # Dependencies injected by the kettle-dev-setup script & kettle:dev:install rake task
128
+ # eval_gemfile "modular/injected.gemfile"
107
129
  end
108
130
 
109
131
  appraise "ruby-3-3" do
@@ -111,6 +133,8 @@ appraise "ruby-3-3" do
111
133
  gem "erb"
112
134
  gem "mutex_m", "~> 0.2"
113
135
  gem "stringio", "~> 3.0"
136
+ # Dependencies injected by the kettle-dev-setup script & kettle:dev:install rake task
137
+ # eval_gemfile "modular/injected.gemfile"
114
138
  end
115
139
 
116
140
  # Only run security audit on the latest version of Ruby
@@ -118,6 +142,8 @@ appraise "audit" do
118
142
  gem "erb"
119
143
  gem "mutex_m", "~> 0.2"
120
144
  gem "stringio", "~> 3.0"
145
+ # Dependencies injected by the kettle-dev-setup script & kettle:dev:install rake task
146
+ # eval_gemfile "modular/injected.gemfile"
121
147
  end
122
148
 
123
149
  # Only run coverage on the latest version of Ruby
@@ -128,6 +154,8 @@ appraise "coverage" do
128
154
  eval_gemfile "modular/coverage.gemfile"
129
155
  eval_gemfile "modular/optional.gemfile"
130
156
  eval_gemfile "modular/recording/r3/recording.gemfile"
157
+ # Dependencies injected by the kettle-dev-setup script & kettle:dev:install rake task
158
+ # eval_gemfile "modular/injected.gemfile"
131
159
  end
132
160
 
133
161
  # Only run linter on the latest version of Ruby (but, in support of oldest supported Ruby version)
@@ -136,4 +164,6 @@ appraise "style" do
136
164
  gem "mutex_m", "~> 0.2"
137
165
  gem "stringio", "~> 3.0"
138
166
  eval_gemfile "modular/style.gemfile"
167
+ # Dependencies injected by the kettle-dev-setup script & kettle:dev:install rake task
168
+ # eval_gemfile "modular/injected.gemfile"
139
169
  end
data/CHANGELOG.md CHANGED
@@ -24,6 +24,19 @@ Please file a bug if you notice a violation of semantic versioning.
24
24
  ### Fixed
25
25
  ### Security
26
26
 
27
+ ## [1.1.0] - 2025-09-02
28
+ - TAG: [v1.1.0][1.1.0t]
29
+ - COVERAGE: 97.03% -- 2649/2730 lines in 21 files
30
+ - BRANCH COVERAGE: 82.16% -- 1105/1345 branches in 21 files
31
+ - 76.81% documented
32
+ ### Added
33
+ - exe/kettle-dev-setup - bootstrap templating in any RubyGem
34
+ ### Removed
35
+ - all runtime deps
36
+ - dependencies haven't really changed; will be injected into the gemspec of the including gem
37
+ - **almost** a breaking change; but this gem re-templates other gems
38
+ - so non-breaking via re-templating.
39
+
27
40
  ## [1.0.27] - 2025-09-01
28
41
  - TAG: [v1.0.27][1.0.27t]
29
42
  - COVERAGE: 97.77% -- 2629/2689 lines in 22 files
@@ -403,7 +416,9 @@ Please file a bug if you notice a violation of semantic versioning.
403
416
  - Selecting will run the selected workflow via `act`
404
417
  - This may move to its own gem in the future.
405
418
 
406
- [Unreleased]: https://github.com/kettle-rb/kettle-dev/compare/v1.0.27...HEAD
419
+ [Unreleased]: https://github.com/kettle-rb/kettle-dev/compare/v1.1.0...HEAD
420
+ [1.1.0]: https://github.com/kettle-rb/kettle-dev/compare/v1.0.27...v1.1.0
421
+ [1.1.0t]: https://github.com/kettle-rb/kettle-dev/releases/tag/v1.1.0
407
422
  [1.0.27]: https://github.com/kettle-rb/kettle-dev/compare/v1.0.26...v1.0.27
408
423
  [1.0.27t]: https://github.com/kettle-rb/kettle-dev/releases/tag/v1.0.27
409
424
  [1.0.26]: https://github.com/kettle-rb/kettle-dev/compare/v1.0.25...v1.0.26
data/Gemfile CHANGED
@@ -36,3 +36,6 @@ eval_gemfile "gemfiles/modular/documentation.gemfile"
36
36
 
37
37
  # Optional
38
38
  eval_gemfile "gemfiles/modular/optional.gemfile"
39
+
40
+ # Dependencies injected by the kettle-dev-setup script & kettle:dev:install rake task
41
+ # eval_gemfile "gemfiles/modular/injected.gemfile"
data/README.md CHANGED
@@ -21,25 +21,35 @@ OTOH, if `ci_badges.map(&:color).all? { it == "green"}` 👇️ send money so I
21
21
 
22
22
  ## 🌻 Synopsis
23
23
 
24
- This gem integrates tightly with [kettle-test](https://github.com/kettle-rb/kettle-test).
24
+ Run the one-time project bootstrapper:
25
25
 
26
- ```ruby
27
- require "kettle/test/rspec"
26
+ ```console
27
+ kettle-dev-setup
28
28
  ```
29
29
 
30
- Then, add to your `Rakefile`:
30
+ This gem integrates tightly with [kettle-test](https://github.com/kettle-rb/kettle-test).
31
+
32
+ Add this to your `spec/spec_helper.rb`:
31
33
 
32
34
  ```ruby
33
- require "kettle/dev"
35
+ require "kettle/test/rspec"
34
36
  ```
35
37
 
36
- Then run:
38
+ Now you have many powerful development and testing tools at your disposal, all fully [documented](#-configuration) and tested.
39
+
40
+ If you need to top-up an old setup to get the latest goodies, just re-template:
37
41
 
38
42
  ```console
39
43
  bundle exec rake kettle:dev:install
40
44
  ```
41
45
 
42
- Now you have many powerful development and testing tools at your disposal, all fully [documented](#-configuration) and tested.
46
+ Making sure to review the changes, and retain overwritten bits that matter.
47
+
48
+ Later, when ready to release:
49
+ ```console
50
+ bin/kettle-changelog
51
+ bin/kettle-release
52
+ ```
43
53
 
44
54
  ## 💡 Info you can shake a stick at
45
55
 
@@ -171,7 +181,15 @@ Add to your `Rakefile`:
171
181
  require "kettle/dev"
172
182
  ```
173
183
 
174
- Then run:
184
+ Then run the one-time project bootstrapper:
185
+
186
+ ```console
187
+ kettle-dev-setup
188
+ ```
189
+
190
+ After bootstrapping you may want to update the template.
191
+
192
+ Invoke the rake task directly:
175
193
 
176
194
  ```console
177
195
  bundle exec rake kettle:dev:install
@@ -732,7 +750,7 @@ Thanks for RTFM. ☺️
732
750
  [📌gitmoji]:https://gitmoji.dev
733
751
  [📌gitmoji-img]:https://img.shields.io/badge/gitmoji_commits-%20😜%20😍-34495e.svg?style=flat-square
734
752
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
735
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-2.689-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
753
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-2.730-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
736
754
  [🔐security]: SECURITY.md
737
755
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
738
756
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
data/README.md.example CHANGED
@@ -505,7 +505,7 @@ Thanks for RTFM. ☺️
505
505
  [📌gitmoji]:https://gitmoji.dev
506
506
  [📌gitmoji-img]:https://img.shields.io/badge/gitmoji_commits-%20😜%20😍-34495e.svg?style=flat-square
507
507
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
508
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-2.689-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
508
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-2.730-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
509
509
  [🔐security]: SECURITY.md
510
510
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
511
511
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
data/Rakefile.example CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # kettle-dev Rakefile v1.0.27 - 2025-09-01
3
+ # kettle-dev Rakefile v1.1.0 - 2025-09-02
4
4
  # Ruby 2.3 (Safe Navigation) or higher required
5
5
  #
6
6
  # MIT License (see License.txt)
@@ -0,0 +1,302 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # vim: set syntax=ruby
5
+
6
+ # kettle-dev-setup: initialize a target gem repo to use kettle-dev tooling.
7
+ # This script is installed into PATH when the kettle-dev gem is installed.
8
+ # It is designed to be run from inside the target gem's repository working
9
+ # directory. It will not assume kettle-dev is already a dependency.
10
+
11
+ require "fileutils"
12
+ require "shellwords"
13
+ require "open3"
14
+ require "optparse"
15
+ require "rubygems"
16
+
17
+ # Ensure output is flushed promptly even if we exit early
18
+ $stdout.sync = true
19
+ $stderr.sync = true
20
+
21
+ script_basename = File.basename(__FILE__)
22
+ running_as_script = File.basename($PROGRAM_NAME)
23
+
24
+ begin
25
+ require "kettle/dev"
26
+ puts "== #{script_basename} v#{Kettle::Dev::Version::VERSION} begin =="
27
+ rescue StandardError => e
28
+ # Requiring kettle/dev should generally work since this script ships with the gem.
29
+ # But if autoloads try to pull optional deps, we should still proceed as most
30
+ # of this script does not rely on those parts.
31
+ warn("[kettle-dev-setup] Warning: could not fully load kettle/dev (#{e.class}: #{e.message}). Proceeding with limited features.")
32
+ end
33
+
34
+ module Kettle
35
+ module Dev
36
+ class SetupCLI
37
+ def initialize(argv)
38
+ debug("initialize(argv=#{argv.inspect})")
39
+ @argv = argv
40
+ @passthrough = []
41
+ @options = {}
42
+ parse!
43
+ end
44
+
45
+ def run!
46
+ debug("run!")
47
+ say("Starting kettle-dev setup…")
48
+ prechecks!
49
+ ensure_dev_deps!
50
+ ensure_bin_setup!
51
+ ensure_rakefile!
52
+ run_bin_setup!
53
+ run_bundle_binstubs!
54
+ commit_bootstrap_changes!
55
+ run_kettle_install!
56
+ say("kettle-dev setup complete.")
57
+ end
58
+
59
+ private
60
+
61
+ def debug(msg)
62
+ return unless ENV.fetch("DEBUG", "false").casecmp("true").zero?
63
+ $stderr.puts("[kettle-dev-setup] DEBUG: #{msg}")
64
+ end
65
+
66
+ def parse!
67
+ debug("parse! argv_before=#{@argv.inspect}")
68
+ parser = OptionParser.new do |opts|
69
+ opts.banner = "Usage: kettle-dev-setup [options]"
70
+ # Map CLI flags to environment-style assignments for Rake (key=value)
71
+ opts.on("--allowed=VAL", "Pass through to kettle:dev:install") { |v| @passthrough << "allowed=#{v}" }
72
+ opts.on("--force", "Pass through to kettle:dev:install") { @passthrough << "force=true" }
73
+ opts.on("--hook_templates=VAL", "Pass through to kettle:dev:install") { |v| @passthrough << "hook_templates=#{v}" }
74
+ opts.on("-h", "--help", "Show help") do
75
+ puts opts
76
+ exit(0)
77
+ end
78
+ end
79
+ begin
80
+ parser.parse!(@argv)
81
+ rescue OptionParser::ParseError => e
82
+ warn("[kettle-dev-setup] #{e.class}: #{e.message}")
83
+ puts parser
84
+ exit(2)
85
+ end
86
+ # Any remaining args pass through as-is
87
+ @passthrough.concat(@argv)
88
+ debug("parse! argv_after=#{@argv.inspect} passthrough=#{@passthrough.inspect}")
89
+ end
90
+
91
+ def say(msg)
92
+ puts "[kettle-dev-setup] #{msg}"
93
+ end
94
+
95
+ def abort!(msg)
96
+ debug("abort!(msg=#{msg.inspect})")
97
+ raise SystemExit, "[kettle-dev-setup] ERROR: #{msg}"
98
+ end
99
+
100
+ def sh!(cmd, env: {})
101
+ debug("sh!(cmd=#{cmd.inspect}, env_keys=#{env.keys.inspect})")
102
+ say("exec: #{cmd}")
103
+ stdout_str, stderr_str, status = Open3.capture3(env, cmd)
104
+ $stdout.print(stdout_str) unless stdout_str.empty?
105
+ $stderr.print(stderr_str) unless stderr_str.empty?
106
+ abort!("Command failed: #{cmd}") unless status.success?
107
+ end
108
+
109
+ # 1. Prechecks
110
+ def prechecks!
111
+ debug("prechecks!")
112
+ abort!("Not inside a git repository (missing .git).") unless Dir.exist?(".git")
113
+
114
+ # 1a. git clean
115
+ begin
116
+ # Use GitAdapter if available; otherwise shell out
117
+ if defined?(Kettle::Dev::GitAdapter)
118
+ ga = Kettle::Dev::GitAdapter.new
119
+ dirty = !ga.clean?
120
+ else
121
+ stdout, _stderr, _status = Open3.capture3("git status --porcelain")
122
+ dirty = !stdout.strip.empty?
123
+ end
124
+ abort!("Git working tree is not clean. Please commit/stash changes and try again.") if dirty
125
+ rescue StandardError
126
+ # Fallback if anything goes wrong: be conservative and require clean tree via shell
127
+ stdout, _stderr, _status = Open3.capture3("git status --porcelain")
128
+ abort!("Git working tree is not clean. Please commit/stash changes and try again.") unless stdout.strip.empty?
129
+ end
130
+
131
+ # 1b. target is a gem (has *.gemspec)
132
+ gemspecs = Dir["*.gemspec"]
133
+ abort!("No gemspec found in current directory.") if gemspecs.empty?
134
+ @gemspec_path = gemspecs.first
135
+
136
+ # 1c. target uses bundler (Gemfile)
137
+ abort!("No Gemfile found; bundler is required.") unless File.exist?("Gemfile")
138
+ end
139
+
140
+ # 3. Sync dev dependencies from this gem's example gemspec into target gemspec
141
+ def ensure_dev_deps!
142
+ debug("ensure_dev_deps!")
143
+ source_example = installed_path("kettle-dev.gemspec.example")
144
+ abort!("Internal error: kettle-dev.gemspec.example not found within the installed gem.") unless source_example && File.exist?(source_example)
145
+
146
+ example = File.read(source_example)
147
+ example = example.gsub("{KETTLE|DEV|GEM}", "kettle-dev")
148
+
149
+ wanted_lines = example.each_line.map(&:rstrip).select do |line|
150
+ line =~ /add_development_dependency\s*\(/
151
+ end
152
+
153
+ return if wanted_lines.empty?
154
+
155
+ target = File.read(@gemspec_path)
156
+
157
+ # Build a map from gem name to the desired line
158
+ wanted = {}
159
+ wanted_lines.each do |line|
160
+ if (m = line.match(/add_development_dependency\s*\(\s*["']([^"']+)["']/))
161
+ wanted[m[1]] = line
162
+ end
163
+ end
164
+
165
+ modified = target.dup
166
+ wanted.each do |gem_name, desired_line|
167
+ # Replace existing add_development_dependency for this gem, else append near the end
168
+ if modified.match?(/add_development_dependency\s*\(\s*["']#{Regexp.escape(gem_name)}["']/)
169
+ modified = modified.gsub(/^[^\n]*add_development_dependency\s*\(\s*["']#{Regexp.escape(gem_name)}["'][^\n]*\)$/) do |_|
170
+ desired_line
171
+ end
172
+ elsif (idx = modified.rindex(/\nend\s*\z/))
173
+ # Insert before the last end, if present, otherwise append
174
+ before = modified[0...idx]
175
+ after = modified[idx..-1]
176
+ insertion = "\n #{desired_line.strip}\n"
177
+ modified = before + insertion + after
178
+ else
179
+ modified << "\n#{desired_line}\n"
180
+ end
181
+ end
182
+
183
+ if modified != target
184
+ File.write(@gemspec_path, modified)
185
+ say("Updated development dependencies in #{@gemspec_path}.")
186
+ else
187
+ say("Development dependencies already up to date.")
188
+ end
189
+ end
190
+
191
+ # 4. Ensure bin/setup present (copy from gem if missing)
192
+ def ensure_bin_setup!
193
+ debug("ensure_bin_setup!")
194
+ target = File.join("bin", "setup")
195
+ return say("bin/setup present.") if File.exist?(target)
196
+
197
+ source = installed_path(File.join("bin", "setup"))
198
+ abort!("Internal error: source bin/setup not found within installed gem.") unless source && File.exist?(source)
199
+ FileUtils.mkdir_p("bin")
200
+ FileUtils.cp(source, target)
201
+ FileUtils.chmod("+x", target)
202
+ say("Copied bin/setup.")
203
+ end
204
+
205
+ # 5. Ensure Rakefile matches example (replace or create)
206
+ def ensure_rakefile!
207
+ debug("ensure_rakefile!")
208
+ source = installed_path("Rakefile.example")
209
+ abort!("Internal error: Rakefile.example not found within installed gem.") unless source && File.exist?(source)
210
+
211
+ content = File.read(source)
212
+ if File.exist?("Rakefile")
213
+ say("Replacing existing Rakefile with kettle-dev Rakefile.example.")
214
+ else
215
+ say("Creating Rakefile from kettle-dev Rakefile.example.")
216
+ end
217
+ File.write("Rakefile", content)
218
+ end
219
+
220
+ # 6. Run bin/setup
221
+ def run_bin_setup!
222
+ debug("run_bin_setup!")
223
+ sh!(Shellwords.join([File.join("bin", "setup")]))
224
+ end
225
+
226
+ # 7. Run bundle binstubs --all
227
+ def run_bundle_binstubs!
228
+ debug("run_bundle_binstubs!")
229
+ sh!("bundle exec bundle binstubs --all")
230
+ end
231
+
232
+ # 8. Stage and commit any changes made by the setup before install
233
+ def commit_bootstrap_changes!
234
+ debug("commit_bootstrap_changes!")
235
+ # Only operate if we are inside a git repo (prechecked earlier), and if dirty
236
+ dirty = begin
237
+ if defined?(Kettle::Dev::GitAdapter)
238
+ !Kettle::Dev::GitAdapter.new.clean?
239
+ else
240
+ out, _st = Open3.capture2("git", "status", "--porcelain")
241
+ !out.strip.empty?
242
+ end
243
+ rescue StandardError
244
+ out, _st = Open3.capture2("git", "status", "--porcelain")
245
+ !out.strip.empty?
246
+ end
247
+ unless dirty
248
+ say("No changes to commit from template bootstrap.")
249
+ return
250
+ end
251
+ # Stage all changes
252
+ sh!(Shellwords.join(["git", "add", "-A"]))
253
+ # Compose commit message exactly as required
254
+ script_name = File.basename(__FILE__)
255
+ msg = "🎨 Template bootstrap by #{script_name} v#{Kettle::Dev::Version::VERSION}"
256
+ # Commit; allow empty to be false (we already detected dirty)
257
+ sh!(Shellwords.join(["git", "commit", "-m", msg]))
258
+ say("Committed template bootstrap changes.")
259
+ end
260
+
261
+ # 9. Run rake kettle:dev:install with passthrough args
262
+ def run_kettle_install!
263
+ debug("run_kettle_install! passthrough=#{@passthrough.inspect}")
264
+ cmd = ["bin/rake", "kettle:dev:install"] + @passthrough
265
+ sh!(Shellwords.join(cmd))
266
+ end
267
+
268
+ # Locate files shipped with this gem installation. Handles execution under a checkout as well.
269
+ def installed_path(rel)
270
+ debug("installed_path(rel=#{rel.inspect})")
271
+ # Prefer real gem installation location
272
+ if defined?(Gem) && (spec = Gem.loaded_specs["kettle-dev"])
273
+ path = File.join(spec.full_gem_path, rel)
274
+ return path if File.exist?(path)
275
+ end
276
+ # Fallback: relative to this file (useful when running from repo)
277
+ here = File.expand_path(File.join(__dir__, "..")) # move from exe/ to project root
278
+ path = File.join(here, rel)
279
+ return path if File.exist?(path)
280
+ nil
281
+ end
282
+ end
283
+ end
284
+ end
285
+
286
+ if running_as_script == script_basename
287
+ begin
288
+ puts "== Kettle::Dev::SetupCLI.new => run! =="
289
+ Kettle::Dev::SetupCLI.new(ARGV).run!
290
+ rescue SystemExit => e
291
+ warn(e.message)
292
+ exit(e.status || 1)
293
+ rescue Exception => e
294
+ warn("[kettle-dev-setup] FATAL: #{e.class}: #{e.message}")
295
+ if ENV.fetch("DEBUG", "false").casecmp("true").zero?
296
+ warn(e.backtrace.join("\n"))
297
+ end
298
+ exit(1)
299
+ end
300
+ else
301
+ puts "== #{script_basename} v#{Kettle::Dev::Version::VERSION} fin (#{running_as_script}) == (#{script_basename}) =="
302
+ end
@@ -0,0 +1,60 @@
1
+ # NOTE: It is preferable to list development dependencies in the gemspec due to increased
2
+ # visibility and discoverability on RubyGems.org.
3
+ # However, this gem sits underneath all my other gems, and also "depends on" many of them.
4
+ # So instead of depending on them directly it injects them into the other gem's gemspec on install.
5
+ # This gem its injected dev dependencies, will install on Ruby down to 2.3.x.
6
+ # This gem does not inject runtime dependencies.
7
+ # Thus, dev dependencies injected into gemspecs must have
8
+ #
9
+ # required_ruby_version ">= 2.3" (or lower)
10
+ #
11
+ # Development dependencies that require strictly newer Ruby versions should be in a "gemfile",
12
+ # and preferably a modular one (see gemfiles/modular/*.gemfile).
13
+
14
+ # Security
15
+ gem "bundler-audit", "~> 0.9.2" # ruby >= 2.0.0
16
+
17
+ # Tasks
18
+ gem "rake", "~> 13.0" # ruby >= 2.2.0
19
+
20
+ # Debugging
21
+ gem "require_bench", "~> 1.0", ">= 1.0.4" # ruby >= 2.2.0
22
+
23
+ # Testing
24
+ gem "appraisal2", "~> 3.0" # ruby >= 1.8.7, for testing against multiple versions of dependencies
25
+ gem "kettle-test", "~> 1.0" # ruby >= 2.3
26
+ gem "rspec-pending_for" # ruby >= 2.3, used to skip specs on incompatible Rubies
27
+
28
+ # Releasing
29
+ gem "ruby-progressbar", "~> 1.13" # ruby >= 0
30
+ gem "stone_checksums", "~> 1.0", ">= 1.0.2" # ruby >= 2.2.0
31
+
32
+ # Git integration (optional)
33
+ # The 'git' gem is optional; kettle-dev falls back to shelling out to `git` if it is not present.
34
+ # The current release of the git gem depends on activesupport, which makes it too heavy to depend on directly
35
+ # Compatibility with the git gem is tested via appraisals instead.
36
+ # gem("git", ">= 1.19.1") # ruby >= 2.3
37
+
38
+ # Development tasks
39
+ gem "gitmoji-regex", "~> 1.0", ">= 1.0.3" # ruby >= 2.3.0
40
+
41
+ # The cake is a lie. erb v2.2, the oldest release on RubyGems.org, was never compatible with Ruby 2.3.
42
+ # This means we have no choice but to use the erb that shipped with Ruby 2.3
43
+ # /opt/hostedtoolcache/Ruby/2.3.8/x64/lib/ruby/gems/2.3.0/gems/erb-2.2.2/lib/erb.rb:670:in `prepare_trim_mode': undefined method `match?' for "-":String (NoMethodError)
44
+ # gem "erb", ">= 2.2" # ruby >= 2.3.0, not SemVer, old rubies get dropped in a patch.
45
+
46
+ # HTTP recording for deterministic specs
47
+ # It seems that somehow just having a newer version of appraisal installed breaks
48
+ # Ruby 2.3 and 2.4 even if their bundle specifies an older version,
49
+ # and as a result it can only be a dependency in the appraisals.
50
+ # | An error occurred while loading spec_helper.
51
+ # | Failure/Error: require "vcr"
52
+ # |
53
+ # | NoMethodError:
54
+ # | undefined method `delete_prefix' for "CONTENT_LENGTH":String
55
+ # | # ./spec/config/vcr.rb:3:in `require'
56
+ # | # ./spec/config/vcr.rb:3:in `<top (required)>'
57
+ # | # ./spec/spec_helper.rb:8:in `require_relative'
58
+ # | # ./spec/spec_helper.rb:8:in `<top (required)>'
59
+ # gem "vcr", ">= 4" # 6.0 claims to support ruby >= 2.3, but fails on ruby 2.4
60
+ # gem "webmock", ">= 3" # Last version to support ruby >= 2.3