kettle-dev 1.2.3 → 2.0.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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +176 -3
- data/CITATION.cff +2 -2
- data/CONTRIBUTING.md +11 -17
- data/README.md +390 -319
- data/exe/kettle-dev-setup +12 -63
- data/exe/kettle-gh-release +82 -0
- data/lib/kettle/dev/gem_spec_reader.rb +2 -2
- data/lib/kettle/dev/open_collective_config.rb +12 -0
- data/lib/kettle/dev/rakelib/yard.rake +15 -0
- data/lib/kettle/dev/tasks/ci_task.rb +4 -4
- data/lib/kettle/dev/version.rb +1 -1
- data/lib/kettle/dev.rb +4 -12
- data/sig/kettle/dev/source_merger.rbs +40 -56
- data.tar.gz.sig +0 -0
- metadata +15 -144
- 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/README.md.example +0 -570
- data/README.md.no-osc.example +0 -536
- data/Rakefile.example +0 -68
- 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 -622
- 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
data/lib/kettle/dev/setup_cli.rb
DELETED
|
@@ -1,403 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "fileutils"
|
|
4
|
-
require "shellwords"
|
|
5
|
-
require "open3"
|
|
6
|
-
require "optparse"
|
|
7
|
-
|
|
8
|
-
module Kettle
|
|
9
|
-
module Dev
|
|
10
|
-
# SetupCLI bootstraps a host gem repository to use kettle-dev tooling.
|
|
11
|
-
# It performs prechecks, syncs development dependencies, ensures bin/setup and
|
|
12
|
-
# Rakefile templates, runs setup tasks, and invokes kettle:dev:install.
|
|
13
|
-
#
|
|
14
|
-
# Usage:
|
|
15
|
-
# Kettle::Dev::SetupCLI.new(ARGV).run!
|
|
16
|
-
#
|
|
17
|
-
# Options are parsed from argv and passed through to the rake task as
|
|
18
|
-
# key=value pairs (e.g., --force => force=true).
|
|
19
|
-
class SetupCLI
|
|
20
|
-
# @param argv [Array<String>] CLI arguments
|
|
21
|
-
def initialize(argv)
|
|
22
|
-
@argv = argv
|
|
23
|
-
@passthrough = []
|
|
24
|
-
@options = {}
|
|
25
|
-
parse!
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# Execute the full setup workflow.
|
|
29
|
-
# @return [void]
|
|
30
|
-
def run!
|
|
31
|
-
say("Starting kettle-dev setup…")
|
|
32
|
-
prechecks!
|
|
33
|
-
ensure_dev_deps!
|
|
34
|
-
ensure_gemfile_from_example!
|
|
35
|
-
ensure_modular_gemfiles!
|
|
36
|
-
ensure_bin_setup!
|
|
37
|
-
ensure_rakefile!
|
|
38
|
-
run_bin_setup!
|
|
39
|
-
run_bundle_binstubs!
|
|
40
|
-
commit_bootstrap_changes!
|
|
41
|
-
run_kettle_install!
|
|
42
|
-
say("kettle-dev setup complete.")
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
private
|
|
46
|
-
|
|
47
|
-
def debug(msg)
|
|
48
|
-
return if ENV.fetch("DEBUG", "false").casecmp("true").nonzero?
|
|
49
|
-
|
|
50
|
-
$stderr.puts("[kettle-dev-setup] DEBUG: #{msg}")
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
# Attempt to derive a funding organization from the git remote 'origin' when
|
|
54
|
-
# not explicitly provided via env or .opencollective.yml.
|
|
55
|
-
# This is a soft helper that only sets ENV["FUNDING_ORG"] if a plausible
|
|
56
|
-
# GitHub org can be parsed from the origin URL.
|
|
57
|
-
# @return [void]
|
|
58
|
-
def derive_funding_org_from_git_if_missing!
|
|
59
|
-
# Respect explicit bypass
|
|
60
|
-
env_val = ENV["FUNDING_ORG"]
|
|
61
|
-
return if env_val && env_val.to_s.strip.casecmp("false").zero?
|
|
62
|
-
|
|
63
|
-
# If already provided via env, do nothing
|
|
64
|
-
return if ENV["FUNDING_ORG"].to_s.strip != ""
|
|
65
|
-
return if ENV["OPENCOLLECTIVE_HANDLE"].to_s.strip != ""
|
|
66
|
-
|
|
67
|
-
# If project provides an .opencollective.yml with org, do nothing
|
|
68
|
-
begin
|
|
69
|
-
oc_path = File.join(Dir.pwd, ".opencollective.yml")
|
|
70
|
-
if File.file?(oc_path)
|
|
71
|
-
txt = File.read(oc_path)
|
|
72
|
-
return if txt =~ /\borg:\s*([\w\-]+)/i
|
|
73
|
-
end
|
|
74
|
-
rescue StandardError => e
|
|
75
|
-
debug("Reading .opencollective.yml failed: #{e.class}: #{e.message}")
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
# Attempt to get origin URL and parse GitHub org
|
|
79
|
-
begin
|
|
80
|
-
ga = Kettle::Dev::GitAdapter.new
|
|
81
|
-
origin_url = nil
|
|
82
|
-
origin_url = ga.remote_url("origin") if ga.respond_to?(:remote_url)
|
|
83
|
-
if origin_url.nil? && ga.respond_to?(:remotes_with_urls)
|
|
84
|
-
begin
|
|
85
|
-
urls = ga.remotes_with_urls
|
|
86
|
-
origin_url = urls["origin"] if urls
|
|
87
|
-
rescue StandardError => e
|
|
88
|
-
# graceful fallback if adapter backend errs; keep silent behavior
|
|
89
|
-
debug("remotes_with_urls failed: #{e.class}: #{e.message}")
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
|
-
origin_url = origin_url.to_s.strip
|
|
93
|
-
if (m = origin_url.match(%r{github\.com[/:]([^/]+)/}i))
|
|
94
|
-
org = m[1].to_s
|
|
95
|
-
if !org.empty?
|
|
96
|
-
ENV["FUNDING_ORG"] = org
|
|
97
|
-
debug("Derived FUNDING_ORG from git origin: #{org}")
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
rescue StandardError => e
|
|
101
|
-
# Be silent; this is a best-effort and shouldn't fail setup
|
|
102
|
-
debug("Could not derive funding org from git: #{e.class}: #{e.message}")
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
def parse!
|
|
107
|
-
parser = OptionParser.new do |opts|
|
|
108
|
-
opts.banner = "Usage: kettle-dev-setup [options]"
|
|
109
|
-
opts.on("--allowed=VAL", "Pass through to kettle:dev:install") { |v| @passthrough << "allowed=#{v}" }
|
|
110
|
-
opts.on("--force", "Pass through to kettle:dev:install") do
|
|
111
|
-
# Ensure in-process helpers (TemplateHelpers.ask) also see force mode
|
|
112
|
-
ENV["force"] = "true"
|
|
113
|
-
@passthrough << "force=true"
|
|
114
|
-
end
|
|
115
|
-
opts.on("--hook_templates=VAL", "Pass through to kettle:dev:install") { |v| @passthrough << "hook_templates=#{v}" }
|
|
116
|
-
opts.on("--only=VAL", "Pass through to kettle:dev:install") { |v| @passthrough << "only=#{v}" }
|
|
117
|
-
opts.on("--include=VAL", "Pass through to kettle:dev:install") { |v| @passthrough << "include=#{v}" }
|
|
118
|
-
opts.on("-h", "--help", "Show help") do
|
|
119
|
-
puts opts
|
|
120
|
-
Kettle::Dev::ExitAdapter.exit(0)
|
|
121
|
-
end
|
|
122
|
-
end
|
|
123
|
-
begin
|
|
124
|
-
parser.parse!(@argv)
|
|
125
|
-
rescue OptionParser::ParseError => e
|
|
126
|
-
warn("[kettle-dev-setup] #{e.class}: #{e.message}")
|
|
127
|
-
puts parser
|
|
128
|
-
Kettle::Dev::ExitAdapter.exit(2)
|
|
129
|
-
end
|
|
130
|
-
@passthrough.concat(@argv)
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
def say(msg)
|
|
134
|
-
puts "[kettle-dev-setup] #{msg}"
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def abort!(msg)
|
|
138
|
-
Kettle::Dev::ExitAdapter.abort("[kettle-dev-setup] ERROR: #{msg}")
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
def sh!(cmd, env: {})
|
|
142
|
-
say("exec: #{cmd}")
|
|
143
|
-
stdout_str, stderr_str, status = Open3.capture3(env, cmd)
|
|
144
|
-
$stdout.print(stdout_str) unless stdout_str.empty?
|
|
145
|
-
$stderr.print(stderr_str) unless stderr_str.empty?
|
|
146
|
-
abort!("Command failed: #{cmd}") unless status.success?
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
# 1. Prechecks
|
|
150
|
-
def prechecks!
|
|
151
|
-
abort!("Not inside a git repository (missing .git).") unless Dir.exist?(".git")
|
|
152
|
-
|
|
153
|
-
# Ensure clean working tree
|
|
154
|
-
begin
|
|
155
|
-
if defined?(Kettle::Dev::GitAdapter)
|
|
156
|
-
dirty = !Kettle::Dev::GitAdapter.new.clean?
|
|
157
|
-
else
|
|
158
|
-
stdout, _stderr, _status = Open3.capture3("git status --porcelain")
|
|
159
|
-
dirty = !stdout.strip.empty?
|
|
160
|
-
end
|
|
161
|
-
abort!("Git working tree is not clean. Please commit/stash changes and try again.") if dirty
|
|
162
|
-
rescue StandardError
|
|
163
|
-
stdout, _stderr, _status = Open3.capture3("git status --porcelain")
|
|
164
|
-
abort!("Git working tree is not clean. Please commit/stash changes and try again.") unless stdout.strip.empty?
|
|
165
|
-
end
|
|
166
|
-
|
|
167
|
-
# gemspec
|
|
168
|
-
gemspecs = Dir["*.gemspec"]
|
|
169
|
-
abort!("No gemspec found in current directory.") if gemspecs.empty?
|
|
170
|
-
@gemspec_path = gemspecs.first
|
|
171
|
-
|
|
172
|
-
# Gemfile
|
|
173
|
-
abort!("No Gemfile found; bundler is required.") unless File.exist?("Gemfile")
|
|
174
|
-
|
|
175
|
-
# Seed FUNDING_ORG from git remote origin org when not provided elsewhere
|
|
176
|
-
derive_funding_org_from_git_if_missing!
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
# 3. Sync dev dependencies from this gem's example gemspec into target gemspec
|
|
180
|
-
def ensure_dev_deps!
|
|
181
|
-
source_example = installed_path("kettle-dev.gemspec.example")
|
|
182
|
-
abort!("Internal error: kettle-dev.gemspec.example not found within the installed gem.") unless source_example && File.exist?(source_example)
|
|
183
|
-
|
|
184
|
-
example = File.read(source_example)
|
|
185
|
-
example = example.gsub("{KETTLE|DEV|GEM}", "kettle-dev")
|
|
186
|
-
|
|
187
|
-
wanted_lines = example.each_line.map(&:rstrip).select { |line| line =~ /add_development_dependency\s*\(?/ }
|
|
188
|
-
return if wanted_lines.empty?
|
|
189
|
-
|
|
190
|
-
target = File.read(@gemspec_path)
|
|
191
|
-
|
|
192
|
-
# Build gem=>desired line map
|
|
193
|
-
wanted = {}
|
|
194
|
-
wanted_lines.each do |line|
|
|
195
|
-
if (m = line.match(/add_development_dependency\s*\(?\s*["']([^"']+)["']/))
|
|
196
|
-
wanted[m[1]] = line
|
|
197
|
-
end
|
|
198
|
-
end
|
|
199
|
-
|
|
200
|
-
# Use Prism-based gemspec edit to ensure development dependencies match
|
|
201
|
-
begin
|
|
202
|
-
modified = Kettle::Dev::PrismGemspec.ensure_development_dependencies(target, wanted)
|
|
203
|
-
# Check if any actual changes were made to development dependency declarations.
|
|
204
|
-
# Extract dependency lines from both and compare sets to avoid false positives
|
|
205
|
-
# from whitespace/formatting differences.
|
|
206
|
-
extract_deps = lambda do |content|
|
|
207
|
-
content.to_s.lines.select { |ln| ln =~ /add_development_dependency\s*\(?/ }.map(&:strip).sort
|
|
208
|
-
end
|
|
209
|
-
target_deps = extract_deps.call(target)
|
|
210
|
-
modified_deps = extract_deps.call(modified)
|
|
211
|
-
if modified_deps != target_deps
|
|
212
|
-
File.write(@gemspec_path, modified)
|
|
213
|
-
say("Updated development dependencies in #{@gemspec_path}.")
|
|
214
|
-
else
|
|
215
|
-
say("Development dependencies already up to date.")
|
|
216
|
-
end
|
|
217
|
-
rescue StandardError => e
|
|
218
|
-
Kettle::Dev.debug_error(e, __method__)
|
|
219
|
-
# Fall back to previous behavior: write nothing and report up-to-date
|
|
220
|
-
say("Development dependencies already up to date.")
|
|
221
|
-
end
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
# 4. Ensure bin/setup present (copy from gem if missing)
|
|
225
|
-
def ensure_bin_setup!
|
|
226
|
-
target = File.join("bin", "setup")
|
|
227
|
-
return say("bin/setup present.") if File.exist?(target)
|
|
228
|
-
|
|
229
|
-
source = installed_path(File.join("bin", "setup"))
|
|
230
|
-
abort!("Internal error: source bin/setup not found within installed gem.") unless source && File.exist?(source)
|
|
231
|
-
FileUtils.mkdir_p("bin")
|
|
232
|
-
FileUtils.cp(source, target)
|
|
233
|
-
FileUtils.chmod("+x", target)
|
|
234
|
-
say("Copied bin/setup.")
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
# 3b. Ensure Gemfile contains required lines from example without duplicating directives
|
|
238
|
-
# - Copies source, git_source, gemspec, and eval_gemfile lines that are missing
|
|
239
|
-
# - Idempotent (running multiple times does not duplicate entries)
|
|
240
|
-
def ensure_gemfile_from_example!
|
|
241
|
-
source_path = installed_path("Gemfile.example")
|
|
242
|
-
abort!("Internal error: Gemfile.example not found within installed gem.") unless source_path && File.exist?(source_path)
|
|
243
|
-
|
|
244
|
-
example = File.read(source_path)
|
|
245
|
-
target_path = "Gemfile"
|
|
246
|
-
target = File.exist?(target_path) ? File.read(target_path) : ""
|
|
247
|
-
|
|
248
|
-
# Extract interesting lines from example
|
|
249
|
-
ex_sources = []
|
|
250
|
-
ex_git_sources = [] # names (e.g., :github)
|
|
251
|
-
ex_git_source_lines = {}
|
|
252
|
-
ex_has_gemspec = false
|
|
253
|
-
ex_eval_paths = []
|
|
254
|
-
|
|
255
|
-
example.each_line do |ln|
|
|
256
|
-
s = ln.strip
|
|
257
|
-
next if s.empty?
|
|
258
|
-
|
|
259
|
-
if s.start_with?("source ")
|
|
260
|
-
ex_sources << ln.rstrip
|
|
261
|
-
elsif (m = s.match(/^git_source\(\s*:(\w+)\s*\)/))
|
|
262
|
-
name = m[1]
|
|
263
|
-
ex_git_sources << name
|
|
264
|
-
ex_git_source_lines[name] = ln.rstrip
|
|
265
|
-
elsif s.start_with?("gemspec")
|
|
266
|
-
ex_has_gemspec = true
|
|
267
|
-
elsif (m = s.match(/^eval_gemfile\s+["']([^"']+)["']/))
|
|
268
|
-
ex_eval_paths << m[1]
|
|
269
|
-
end
|
|
270
|
-
end
|
|
271
|
-
|
|
272
|
-
# Scan target for presence
|
|
273
|
-
tg_sources = target.each_line.map(&:rstrip).select { |l| l.strip.start_with?("source ") }
|
|
274
|
-
tg_git_sources = {}
|
|
275
|
-
target.each_line do |ln|
|
|
276
|
-
if (m = ln.strip.match(/^git_source\(\s*:(\w+)\s*\)/))
|
|
277
|
-
tg_git_sources[m[1]] = true
|
|
278
|
-
end
|
|
279
|
-
end
|
|
280
|
-
tg_has_gemspec = !!target.each_line.find { |l| l.strip.start_with?("gemspec") }
|
|
281
|
-
tg_eval_paths = target.each_line.map do |ln|
|
|
282
|
-
if (m = ln.strip.match(/^eval_gemfile\s+["']([^"']+)["']/))
|
|
283
|
-
m[1]
|
|
284
|
-
end
|
|
285
|
-
end.compact
|
|
286
|
-
|
|
287
|
-
additions = []
|
|
288
|
-
# Add missing sources (exact line match)
|
|
289
|
-
ex_sources.each do |src_line|
|
|
290
|
-
additions << src_line unless tg_sources.include?(src_line)
|
|
291
|
-
end
|
|
292
|
-
# Add missing git_source by name
|
|
293
|
-
ex_git_sources.each do |name|
|
|
294
|
-
additions << ex_git_source_lines[name] unless tg_git_sources[name]
|
|
295
|
-
end
|
|
296
|
-
# Add gemspec if example has it and target lacks it
|
|
297
|
-
additions << "gemspec" if ex_has_gemspec && !tg_has_gemspec
|
|
298
|
-
# Add missing eval_gemfile paths (recreate the exact example line when possible)
|
|
299
|
-
ex_eval_paths.each do |path|
|
|
300
|
-
next if tg_eval_paths.include?(path)
|
|
301
|
-
|
|
302
|
-
additions << "eval_gemfile \"#{path}\""
|
|
303
|
-
end
|
|
304
|
-
|
|
305
|
-
return say("Gemfile already contains required entries from example.") if additions.empty?
|
|
306
|
-
|
|
307
|
-
# Ensure file ends with a newline
|
|
308
|
-
target << "\n" unless target.end_with?("\n") || target.empty?
|
|
309
|
-
new_content = target + additions.join("\n") + "\n"
|
|
310
|
-
File.write(target_path, new_content)
|
|
311
|
-
say("Updated Gemfile with entries from Gemfile.example (added #{additions.size}).")
|
|
312
|
-
end
|
|
313
|
-
|
|
314
|
-
# 3c. Ensure gemfiles/modular/* are present (copied like template task)
|
|
315
|
-
def ensure_modular_gemfiles!
|
|
316
|
-
helpers = Kettle::Dev::TemplateHelpers
|
|
317
|
-
project_root = helpers.project_root
|
|
318
|
-
gem_checkout_root = helpers.gem_checkout_root
|
|
319
|
-
# Gather min_ruby for style.gemfile adjustments
|
|
320
|
-
min_ruby = begin
|
|
321
|
-
md = helpers.gemspec_metadata(project_root)
|
|
322
|
-
md[:min_ruby]
|
|
323
|
-
rescue StandardError
|
|
324
|
-
nil
|
|
325
|
-
end
|
|
326
|
-
Kettle::Dev::ModularGemfiles.sync!(
|
|
327
|
-
helpers: helpers,
|
|
328
|
-
project_root: project_root,
|
|
329
|
-
gem_checkout_root: gem_checkout_root,
|
|
330
|
-
min_ruby: min_ruby,
|
|
331
|
-
)
|
|
332
|
-
end
|
|
333
|
-
|
|
334
|
-
# 5. Ensure Rakefile matches example (replace or create)
|
|
335
|
-
def ensure_rakefile!
|
|
336
|
-
source = installed_path("Rakefile.example")
|
|
337
|
-
abort!("Internal error: Rakefile.example not found within installed gem.") unless source && File.exist?(source)
|
|
338
|
-
|
|
339
|
-
content = File.read(source)
|
|
340
|
-
if File.exist?("Rakefile")
|
|
341
|
-
say("Replacing existing Rakefile with kettle-dev Rakefile.example.")
|
|
342
|
-
else
|
|
343
|
-
say("Creating Rakefile from kettle-dev Rakefile.example.")
|
|
344
|
-
end
|
|
345
|
-
File.write("Rakefile", content)
|
|
346
|
-
end
|
|
347
|
-
|
|
348
|
-
# 6. Run bin/setup
|
|
349
|
-
def run_bin_setup!
|
|
350
|
-
sh!(Shellwords.join([File.join("bin", "setup")]))
|
|
351
|
-
end
|
|
352
|
-
|
|
353
|
-
# 7. Run bundle binstubs --all
|
|
354
|
-
def run_bundle_binstubs!
|
|
355
|
-
sh!("bundle exec bundle binstubs --all")
|
|
356
|
-
end
|
|
357
|
-
|
|
358
|
-
# 8. Commit template bootstrap changes if any
|
|
359
|
-
def commit_bootstrap_changes!
|
|
360
|
-
dirty = begin
|
|
361
|
-
if defined?(Kettle::Dev::GitAdapter)
|
|
362
|
-
!Kettle::Dev::GitAdapter.new.clean?
|
|
363
|
-
else
|
|
364
|
-
out, _st = Open3.capture2("git", "status", "--porcelain")
|
|
365
|
-
!out.strip.empty?
|
|
366
|
-
end
|
|
367
|
-
rescue StandardError
|
|
368
|
-
out, _st = Open3.capture2("git", "status", "--porcelain")
|
|
369
|
-
!out.strip.empty?
|
|
370
|
-
end
|
|
371
|
-
unless dirty
|
|
372
|
-
say("No changes to commit from template bootstrap.")
|
|
373
|
-
return
|
|
374
|
-
end
|
|
375
|
-
sh!(Shellwords.join(["git", "add", "-A"]))
|
|
376
|
-
msg = "🎨 Template bootstrap by kettle-dev-setup v#{Kettle::Dev::Version::VERSION}"
|
|
377
|
-
sh!(Shellwords.join(["git", "commit", "-m", msg]))
|
|
378
|
-
say("Committed template bootstrap changes.")
|
|
379
|
-
end
|
|
380
|
-
|
|
381
|
-
# 9. Invoke rake install task with passthrough
|
|
382
|
-
def run_kettle_install!
|
|
383
|
-
cmd = ["bin/rake", "kettle:dev:install"] + @passthrough
|
|
384
|
-
sh!(Shellwords.join(cmd))
|
|
385
|
-
end
|
|
386
|
-
|
|
387
|
-
# Resolve a path to files shipped within the gem or repo checkout
|
|
388
|
-
# @param rel [String]
|
|
389
|
-
# @return [String, nil]
|
|
390
|
-
def installed_path(rel)
|
|
391
|
-
if defined?(Gem) && (spec = Gem.loaded_specs["kettle-dev"])
|
|
392
|
-
path = File.join(spec.full_gem_path, rel)
|
|
393
|
-
return path if File.exist?(path)
|
|
394
|
-
end
|
|
395
|
-
here = File.expand_path(File.join(__dir__, "..", "..", "..")) # lib/kettle/dev/ -> project root
|
|
396
|
-
path = File.join(here, rel)
|
|
397
|
-
return path if File.exist?(path)
|
|
398
|
-
|
|
399
|
-
nil
|
|
400
|
-
end
|
|
401
|
-
end
|
|
402
|
-
end
|
|
403
|
-
end
|