kettle-dev 1.1.55 → 1.1.57

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: e4782eb3b39e080e427e189f57e3aed63e153847e42a1941ab5878bbd105c2fc
4
- data.tar.gz: 4b2403df88b14c7bdab14a016eba9566412bf82df7e941d95802c6eb06148376
3
+ metadata.gz: 3913400a8582c79152894a5c27da0981401d81f08d598061582a95f567ccbb10
4
+ data.tar.gz: e9f02c0ad8952cba8e30a1fb94872637f175f91eb24ce12c3edb1f731bec773e
5
5
  SHA512:
6
- metadata.gz: 85ea8797ad85aa8fdc7e81c87c5690ea51de9d11f72c2bc3d3a27d98592677ef7b3d4586d25d57faa08d2e75d578dd474962ca3f7393f4ba84546f307e08c33c
7
- data.tar.gz: 6d1480c222f28119e4207b8b98083148c6633f94fe160f501622eff7628e06ba813cd0aa4cb756a494ec3e1751259841b0e09dd482153fae12786f767de43185
6
+ metadata.gz: 6eb29f6e550dcd1bf578ccec78a656928ab8b2171036057cf18e72546ab4e3db2ba137724317f4dfb1fde14eb14d357fd4ef9611b985b586aa219cdf5a0a461c
7
+ data.tar.gz: fe78f07d2b3fe5fcd542842b213d71447c160ae2f41820acf251879340022aabcb368d7a7a20865714666efdd98ee649fa5ddf221dbfc3141ec4e4d27cea0f63
checksums.yaml.gz.sig CHANGED
Binary file
data/.env.local.example CHANGED
@@ -25,3 +25,7 @@ export GITHUB_TOKEN=<your GH token for GHA status; NEVER COMMIT>
25
25
  export GITLAB_TOKEN=<your GitLab token for pipeline status; NEVER COMMIT>
26
26
  # Alternatively:
27
27
  # export GL_TOKEN=<your GitLab token>
28
+
29
+ # If this gem does not have an open source collective uncomment and set these to false.
30
+ # export OPENCOLLECTIVE_HANDLE=false
31
+ # export FUNDING_ORG=false
data/.envrc.example ADDED
@@ -0,0 +1,50 @@
1
+ # Run any command in this library's bin/ without the bin/ prefix!
2
+ # Prefer exe version over binstub
3
+ PATH_add exe
4
+ PATH_add bin
5
+
6
+ # Only add things to this file that should be shared with the team.
7
+
8
+ # **dotenv** (See end of file for .env.local integration)
9
+ # .env would override anything in this file, if enabled.
10
+ # .env is a DOCKER standard, and if we use it, it would be in deployed, or DOCKER, environments.
11
+ # Override and customize anything below in your own .env.local
12
+ # If you are using dotenv and not direnv,
13
+ # copy the following `export` statements to your own .env file.
14
+
15
+ ### General Ruby ###
16
+ # Turn off Ruby Warnings about deprecated code
17
+ # export RUBYOPT="-W0"
18
+
19
+ ### External Testing Controls
20
+ export K_SOUP_COV_DO=true # Means you want code coverage
21
+ export K_SOUP_COV_COMMAND_NAME="Test Coverage"
22
+ # Available formats are html, xml, rcov, lcov, json, tty
23
+ export K_SOUP_COV_FORMATTERS="html,xml,rcov,lcov,json,tty"
24
+ export K_SOUP_COV_MIN_BRANCH=76 # Means you want to enforce X% branch coverage
25
+ export K_SOUP_COV_MIN_LINE=92 # Means you want to enforce X% line coverage
26
+ export K_SOUP_COV_MIN_HARD=true # Means you want the build to fail if the coverage thresholds are not met
27
+ export K_SOUP_COV_MULTI_FORMATTERS=true
28
+ export K_SOUP_COV_OPEN_BIN= # Means don't try to open coverage results in browser
29
+ export MAX_ROWS=1 # Setting for simplecov-console gem for tty output, limits to the worst N rows of bad coverage
30
+ export KETTLE_TEST_SILENT=true
31
+
32
+ # Internal Debugging Controls
33
+ export DEBUG=false # do not allow byebug statements (override in .env.local)
34
+ export FLOSS_CFG_FUND_DEBUG=false # extra logging to help diagnose issues (override in .env.local)
35
+ export FLOSS_CFG_FUND_LOGFILE=tmp/log/debug.log
36
+
37
+ # Concurrently developing the rubocop-lts suite?
38
+ export RUBOCOP_LTS_LOCAL=false
39
+
40
+ # If {TARGET|GEM|NAME} does not have an open source collective set these to false.
41
+ export OPENCOLLECTIVE_HANDLE={OPENCOLLECTIVE|ORG_NAME}
42
+ export FUNDING_ORG={OPENCOLLECTIVE|ORG_NAME}
43
+
44
+ # .env would override anything in this file, if `dotenv` is uncommented below.
45
+ # .env is a DOCKER standard, and if we use it, it would be in deployed, or DOCKER, environments,
46
+ # and that is why we generally want to leave it commented out.
47
+ # dotenv
48
+
49
+ # .env.local will override anything in this file.
50
+ dotenv_if_exists .env.local
@@ -0,0 +1,50 @@
1
+ # Run any command in this library's bin/ without the bin/ prefix!
2
+ # Prefer exe version over binstub
3
+ PATH_add exe
4
+ PATH_add bin
5
+
6
+ # Only add things to this file that should be shared with the team.
7
+
8
+ # **dotenv** (See end of file for .env.local integration)
9
+ # .env would override anything in this file, if enabled.
10
+ # .env is a DOCKER standard, and if we use it, it would be in deployed, or DOCKER, environments.
11
+ # Override and customize anything below in your own .env.local
12
+ # If you are using dotenv and not direnv,
13
+ # copy the following `export` statements to your own .env file.
14
+
15
+ ### General Ruby ###
16
+ # Turn off Ruby Warnings about deprecated code
17
+ # export RUBYOPT="-W0"
18
+
19
+ ### External Testing Controls
20
+ export K_SOUP_COV_DO=true # Means you want code coverage
21
+ export K_SOUP_COV_COMMAND_NAME="Test Coverage"
22
+ # Available formats are html, xml, rcov, lcov, json, tty
23
+ export K_SOUP_COV_FORMATTERS="html,xml,rcov,lcov,json,tty"
24
+ export K_SOUP_COV_MIN_BRANCH=76 # Means you want to enforce X% branch coverage
25
+ export K_SOUP_COV_MIN_LINE=92 # Means you want to enforce X% line coverage
26
+ export K_SOUP_COV_MIN_HARD=true # Means you want the build to fail if the coverage thresholds are not met
27
+ export K_SOUP_COV_MULTI_FORMATTERS=true
28
+ export K_SOUP_COV_OPEN_BIN= # Means don't try to open coverage results in browser
29
+ export MAX_ROWS=1 # Setting for simplecov-console gem for tty output, limits to the worst N rows of bad coverage
30
+ export KETTLE_TEST_SILENT=true
31
+
32
+ # Internal Debugging Controls
33
+ export DEBUG=false # do not allow byebug statements (override in .env.local)
34
+ export FLOSS_CFG_FUND_DEBUG=false # extra logging to help diagnose issues (override in .env.local)
35
+ export FLOSS_CFG_FUND_LOGFILE=tmp/log/debug.log
36
+
37
+ # Concurrently developing the rubocop-lts suite?
38
+ export RUBOCOP_LTS_LOCAL=false
39
+
40
+ # {TARGET|GEM|NAME} has no open source collective.
41
+ export OPENCOLLECTIVE_HANDLE=false
42
+ export FUNDING_ORG=false
43
+
44
+ # .env would override anything in this file, if `dotenv` is uncommented below.
45
+ # .env is a DOCKER standard, and if we use it, it would be in deployed, or DOCKER, environments,
46
+ # and that is why we generally want to leave it commented out.
47
+ # dotenv
48
+
49
+ # .env.local will override anything in this file.
50
+ dotenv_if_exists .env.local
@@ -55,7 +55,7 @@ jobs:
55
55
  include:
56
56
  # Ruby <whichever version is current, e.g., 3.4 as of 2025-07-12>
57
57
  - ruby: "ruby"
58
- appraisal_name: "unlocked_deps"
58
+ appraisal: "unlocked_deps"
59
59
  exec_cmd: "rake"
60
60
  gemfile: "Appraisal.root"
61
61
  rubygems: latest
@@ -78,7 +78,7 @@ jobs:
78
78
  # NOTE: This does not use the primary Gemfile at all.
79
79
  - name: Install Root Appraisal
80
80
  run: bundle
81
- - name: Appraisal for ${{ matrix.ruby }}@${{ matrix.appraisal_name }}
82
- run: bundle exec appraisal ${{ matrix.appraisal_name }} bundle
83
- - name: Run ${{ matrix.exec_cmd }} on ${{ matrix.ruby }}@${{ matrix.appraisal_name }}
84
- run: bundle exec appraisal ${{ matrix.appraisal_name }} bundle exec ${{ matrix.exec_cmd }}
81
+ - name: Appraisal for ${{ matrix.ruby }}@${{ matrix.appraisal }}
82
+ run: bundle exec appraisal ${{ matrix.appraisal }} bundle
83
+ - name: Run ${{ matrix.exec_cmd }} on ${{ matrix.ruby }}@${{ matrix.appraisal }}
84
+ run: bundle exec appraisal ${{ matrix.appraisal }} bundle exec ${{ matrix.exec_cmd }}
@@ -22,7 +22,6 @@ variables:
22
22
  K_SOUP_COV_DEBUG: true
23
23
  K_SOUP_COV_DO: true
24
24
  K_SOUP_COV_HARD: true
25
- # Lower than local, which is at 100/100, because rubocop-lts isn't installed in the coverage workflow
26
25
  K_SOUP_COV_MIN_BRANCH: 74
27
26
  K_SOUP_COV_MIN_LINE: 90
28
27
  K_SOUP_COV_VERBOSE: true
data/.yardignore CHANGED
@@ -1,5 +1,13 @@
1
1
  # Ignore built gem artifacts and package dir
2
- pkg/*.gem
2
+ bin/**/*
3
+ certs/**/*
4
+ checksums/**/*
5
+ gemfiles/**/*
6
+ pkg/**/*
7
+ spec/**/*
8
+ spec*/**/*
9
+ test/**/*
10
+ tmp/**/*
3
11
  *.gem
4
12
  # Also ignore yardoc cache
5
13
  .yardoc/
data/CHANGELOG.md CHANGED
@@ -30,6 +30,36 @@ Please file a bug if you notice a violation of semantic versioning.
30
30
 
31
31
  ### Security
32
32
 
33
+ ## [1.1.57] - 2025-11-13
34
+
35
+ - TAG: [v1.1.57][1.1.57t]
36
+ - COVERAGE: 94.36% -- 4065/4308 lines in 26 files
37
+ - BRANCH COVERAGE: 78.81% -- 1674/2124 branches in 26 files
38
+ - 79.89% documented
39
+
40
+ ### Added
41
+
42
+ - New Rake task: `appraisal:reset` — deletes all Appraisal lockfiles (`gemfiles/*.gemfile.lock`).
43
+ - Improved .env.local.example template
44
+
45
+ ### Fixed
46
+
47
+ - .yardignore more comprehensively ignores directories that are not relevant to documentation
48
+
49
+ ## [1.1.56] - 2025-11-11
50
+
51
+ - TAG: [v1.1.56][1.1.56t]
52
+ - COVERAGE: 94.38% -- 4066/4308 lines in 26 files
53
+ - BRANCH COVERAGE: 78.77% -- 1673/2124 branches in 26 files
54
+ - 79.89% documented
55
+
56
+ ### Fixed
57
+
58
+ - Appraisals template merge with existing header
59
+ - Don't set opencollective in FUNDING.yml when osc is disabled
60
+ - handling of open source collective ENV variables in .envrc templates
61
+ - Don't invent an open collective handle when open collective is not enabled
62
+
33
63
  ## [1.1.55] - 2025-11-11
34
64
 
35
65
  - TAG: [v1.1.55][1.1.55t]
@@ -1380,7 +1410,11 @@ Please file a bug if you notice a violation of semantic versioning.
1380
1410
  - Selecting will run the selected workflow via `act`
1381
1411
  - This may move to its own gem in the future.
1382
1412
 
1383
- [Unreleased]: https://github.com/kettle-rb/kettle-dev/compare/v1.1.55...HEAD
1413
+ [Unreleased]: https://github.com/kettle-rb/kettle-dev/compare/v1.1.57...HEAD
1414
+ [1.1.57]: https://github.com/kettle-rb/kettle-dev/compare/v1.1.56...v1.1.57
1415
+ [1.1.57t]: https://github.com/kettle-rb/kettle-dev/releases/tag/v1.1.57
1416
+ [1.1.56]: https://github.com/kettle-rb/kettle-dev/compare/v1.1.55...v1.1.56
1417
+ [1.1.56t]: https://github.com/kettle-rb/kettle-dev/releases/tag/v1.1.56
1384
1418
  [1.1.55]: https://github.com/kettle-rb/kettle-dev/compare/v1.1.54...v1.1.55
1385
1419
  [1.1.55t]: https://github.com/kettle-rb/kettle-dev/releases/tag/v1.1.55
1386
1420
  [1.1.54]: https://github.com/kettle-rb/kettle-dev/compare/v1.1.53...v1.1.54
data/CONTRIBUTING.md CHANGED
@@ -96,6 +96,12 @@ They are created and updated with the commands:
96
96
  bin/rake appraisal:update
97
97
  ```
98
98
 
99
+ If you need to reset all gemfiles/*.gemfile.lock files:
100
+
101
+ ```console
102
+ bin/rake appraisal:reset
103
+ ```
104
+
99
105
  When adding an appraisal to CI, check the [runner tool cache][🏃‍♂️runner-tool-cache] to see which runner to use.
100
106
 
101
107
  ## The Reek List
@@ -89,6 +89,12 @@ They are created and updated with the commands:
89
89
  bin/rake appraisal:update
90
90
  ```
91
91
 
92
+ If you need to reset all gemfiles/*.gemfile.lock files:
93
+
94
+ ```console
95
+ bin/rake appraisal:reset
96
+ ```
97
+
92
98
  When adding an appraisal to CI, check the [runner tool cache][🏃‍♂️runner-tool-cache] to see which runner to use.
93
99
 
94
100
  ## The Reek List
data/README.md CHANGED
@@ -362,6 +362,11 @@ Common flows
362
362
  - `bundle exec rake reek` or `bundle exec rake reek:update`
363
363
  - `bundle exec rake yard`
364
364
 
365
+ [Appraisals][💎appraisal2] helpers
366
+ - `bundle exec rake appraisal:isntall` — First time Appraisal setup.
367
+ - `bundle exec rake appraisal:update` — Update Appraisal gemfiles and run RuboCop Gradual autocorrect.
368
+ - `bundle exec rake appraisal:reset` — Delete all Appraisal lockfiles in gemfiles/ (*.gemfile.lock). Useful before regenerating appraisals or when switching Ruby versions.
369
+
365
370
  GitHub Actions local runner helper
366
371
  - `bundle exec rake ci:act` — interactive menu shows workflows from `.github/workflows` with live status and short codes (first 3 letters of file name). Type a number or short code.
367
372
  - Non-interactive: `bundle exec rake ci:act[loc]` (short code), or `bundle exec rake ci:act[locked_deps.yml]` (filename).
@@ -374,7 +379,7 @@ Setup tokens for API status (GitHub and GitLab)
374
379
  - Classic (fallback): “Tokens (classic)” → Generate new token
375
380
  - Minimum permissions:
376
381
  - Fine-grained: Repository access: Read-only for the target repository (or your org); Permissions → Actions: Read
377
- - Classic: For public repos, no scopes are strictly required but rate limits are very low; for private repos, include the repo scope
382
+ - Classic: For public repos, no scopes are strictly required, but rate limits are very low; for private repos, include the repo scope
378
383
  - Add to environment (.env.local via direnv):
379
384
  - GITHUB_TOKEN=your_token_here (or GH_TOKEN=…)
380
385
  - GitLab token:
@@ -968,7 +973,7 @@ Thanks for RTFM. ☺️
968
973
  [📌gitmoji]: https://gitmoji.dev
969
974
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
970
975
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
971
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-4.278-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
976
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-4.308-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
972
977
  [🔐security]: SECURITY.md
973
978
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
974
979
  [📄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
@@ -544,7 +544,7 @@ Thanks for RTFM. ☺️
544
544
  [📌gitmoji]: https://gitmoji.dev
545
545
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
546
546
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
547
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-4.278-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
547
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-4.308-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
548
548
  [🔐security]: SECURITY.md
549
549
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
550
550
  [📄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.1.55 - 2025-11-11
3
+ # kettle-dev Rakefile v1.1.57 - 2025-11-13
4
4
  # Ruby 2.3 (Safe Navigation) or higher required
5
5
  #
6
6
  # MIT License (see License.txt)
@@ -11,6 +11,8 @@
11
11
  #
12
12
  # Sets up tasks for appraisal, floss_funding, rspec, minitest, rubocop, reek, yard, and stone_checksums.
13
13
  #
14
+ # rake appraisal:install # Install Appraisal gemfiles (initial setup...
15
+ # rake appraisal:reset # Delete Appraisal lockfiles (gemfiles/*.gemfile.lock)
14
16
  # rake appraisal:update # Update Appraisal gemfiles and run RuboCop...
15
17
  # rake bench # Run all benchmarks (alias for bench:run)
16
18
  # rake bench:list # List available benchmark scripts
@@ -61,6 +61,43 @@ begin
61
61
  run_in_unbundled.call
62
62
  end
63
63
  end
64
+
65
+ # Delete all Appraisal lockfiles in gemfiles/ (*.gemfile.lock)
66
+ desc("Delete Appraisal lockfiles (gemfiles/*.gemfile.lock)")
67
+ task("appraisal:reset") do
68
+ run_in_unbundled = proc do
69
+ lock_glob = File.join("gemfiles", "*.gemfile.lock")
70
+ locks = Dir.glob(lock_glob)
71
+
72
+ if locks.empty?
73
+ puts("[kettle-dev][appraisal:reset] no files matching #{lock_glob}")
74
+ else
75
+ failures = []
76
+ locks.each do |f|
77
+ begin
78
+ File.delete(f)
79
+ rescue Errno::ENOENT
80
+ # Ignore if already gone
81
+ rescue StandardError => e
82
+ failures << [f, e]
83
+ end
84
+ end
85
+
86
+ unless failures.empty?
87
+ failed_list = failures.map { |(f, e)| "#{f} (#{e.class}: #{e.message})" }.join(", ")
88
+ abort("appraisal:reset failed: unable to delete #{failed_list}")
89
+ end
90
+
91
+ puts("[kettle-dev][appraisal:reset] deleted #{locks.size} file(s)")
92
+ end
93
+ end
94
+
95
+ if defined?(Bundler)
96
+ Bundler.with_unbundled_env(&run_in_unbundled)
97
+ else
98
+ run_in_unbundled.call
99
+ end
100
+ end
64
101
  rescue LoadError
65
102
  warn("[kettle-dev][appraisal.rake] failed to load appraisal/tasks") if Kettle::Dev::DEBUGGING
66
103
  end
@@ -66,7 +66,7 @@ module Kettle
66
66
  gem_name = meta[:gem_name]
67
67
  min_ruby = meta[:min_ruby]
68
68
  forge_org = meta[:forge_org] || meta[:gh_org]
69
- funding_org = meta[:funding_org] || forge_org
69
+ funding_org = helpers.opencollective_disabled? ? nil : meta[:funding_org] || forge_org
70
70
  entrypoint_require = meta[:entrypoint_require]
71
71
  namespace = meta[:namespace]
72
72
  namespace_shield = meta[:namespace_shield]
@@ -143,15 +143,22 @@ module Kettle
143
143
  if File.basename(rel) == "FUNDING.yml"
144
144
  helpers.copy_file_with_prompt(src, dest, allow_create: true, allow_replace: true) do |content|
145
145
  c = content.dup
146
- c = c.gsub(/^open_collective:\s+.*$/i) { |line| funding_org ? "open_collective: #{funding_org}" : line }
146
+ # Effective funding handle should fall back to forge_org when funding_org is nil.
147
+ # This allows tests to stub FUNDING_ORG=false to bypass explicit funding detection
148
+ # while still templating the line with the derived organization (e.g., from homepage URL).
149
+ effective_funding = funding_org || forge_org
150
+ c = if helpers.opencollective_disabled?
151
+ c.gsub(/^open_collective:\s+.*$/i) { |line| "open_collective: # Replace with a single Open Collective username" }
152
+ else
153
+ c.gsub(/^open_collective:\s+.*$/i) { |line| effective_funding ? "open_collective: #{effective_funding}" : line }
154
+ end
147
155
  if gem_name && !gem_name.empty?
148
156
  c = c.gsub(/^tidelift:\s+.*$/i, "tidelift: rubygems/#{gem_name}")
149
157
  end
150
- # Also apply common replacements for org/gem/namespace/shields
151
158
  helpers.apply_common_replacements(
152
159
  c,
153
160
  org: forge_org,
154
- funding_org: funding_org,
161
+ funding_org: effective_funding, # pass effective funding for downstream tokens
155
162
  gem_name: gem_name,
156
163
  namespace: namespace,
157
164
  namespace_shield: namespace_shield,
@@ -469,6 +469,21 @@ module Kettle
469
469
  # - Preamble (content before first appraise) comes from template when present, else destination.
470
470
  def merge_appraisals(template_content, dest_content)
471
471
  begin
472
+ # Helper: extract contiguous leading header lines (comments and blank lines)
473
+ extract_leading_header = lambda do |text|
474
+ lines = text.lines
475
+ header_lines = []
476
+ idx = 0
477
+ while idx < lines.length
478
+ ln = lines[idx]
479
+ break unless ln.strip.empty? || ln.lstrip.start_with?("#")
480
+ header_lines << ln
481
+ idx += 1
482
+ end
483
+ body = (idx < lines.length) ? lines[idx..-1].join : ""
484
+ {header: header_lines.join, body: body}
485
+ end
486
+
472
487
  parse_blocks = lambda do |text|
473
488
  lines = text.lines
474
489
  blocks = []
@@ -526,8 +541,22 @@ module Kettle
526
541
  {blocks: blocks, preamble: preamble}
527
542
  end
528
543
 
529
- tmpl = parse_blocks.call(template_content)
530
- dest = parse_blocks.call(dest_content)
544
+ # Extract leading headers from template and destination and parse their bodies
545
+ tmpl_parts = extract_leading_header.call(template_content)
546
+ dest_parts = extract_leading_header.call(dest_content)
547
+
548
+ # If the template does not provide a leading header, preserve the destination as-is
549
+ # so that per-block adjacent header comments (including those at the top of file)
550
+ # are still parsed and preserved. Only strip the destination leading header when
551
+ # the template has a leading header to replace it.
552
+ dest_parse_source = if tmpl_parts[:header].to_s.strip.empty?
553
+ dest_content
554
+ else
555
+ dest_parts[:body]
556
+ end
557
+
558
+ tmpl = parse_blocks.call(tmpl_parts[:body])
559
+ dest = parse_blocks.call(dest_parse_source)
531
560
  tmpl_blocks = tmpl[:blocks]
532
561
  dest_blocks = dest[:blocks]
533
562
  dest_by_name = dest_blocks.map { |b| [b[:name], b] }.to_h
@@ -553,9 +582,17 @@ module Kettle
553
582
  merged_body += additions
554
583
  end
555
584
  header = tb[:header].any? ? tb[:header] : db[:header]
585
+ # If the template provides no leading header and the destination preamble
586
+ # already ends with this header, skip emitting the header for this block
587
+ # to avoid duplicating it (it will already be present at the top of the file).
588
+ header_to_emit = if tmpl_parts[:header].to_s.strip.empty? && !dest[:preamble].to_s.strip.empty? && !header.empty? && dest[:preamble].to_s.end_with?(header.join)
589
+ []
590
+ else
591
+ header
592
+ end
556
593
  block_text = +""
557
594
  block_text << "\n" unless merged_blocks_strings.empty?
558
- header.each { |hl| block_text << hl } if header.any?
595
+ header_to_emit.each { |hl| block_text << hl } if header_to_emit.any?
559
596
  block_text << "appraise \"#{tb[:name]}\" do\n"
560
597
  merged_body.each { |bl| block_text << bl }
561
598
  block_text << db[:end_line]
@@ -584,7 +621,21 @@ module Kettle
584
621
  merged_blocks_strings << block_text
585
622
  end
586
623
 
587
- preamble = tmpl[:preamble].to_s.strip.empty? ? dest[:preamble] : tmpl[:preamble]
624
+ # Build final preamble:
625
+ # - If template provides a leading header, use that header and then prefer the
626
+ # template's body preamble when present, otherwise fall back to the
627
+ # destination's body preamble.
628
+ # - If template does NOT provide a leading header, leave the destination
629
+ # preamble (including any leading header/comments) intact.
630
+ preamble = +""
631
+ if tmpl_parts[:header].to_s.strip.empty?
632
+ preamble << dest[:preamble].to_s
633
+ else
634
+ body_preamble = tmpl[:preamble].to_s.strip.empty? ? dest[:preamble].to_s : tmpl[:preamble].to_s
635
+ preamble << tmpl_parts[:header].to_s
636
+ preamble << body_preamble.to_s
637
+ end
638
+
588
639
  out = +""
589
640
  out << preamble unless preamble.nil? || preamble.empty?
590
641
  out << "\n" unless out.end_with?("\n")
@@ -792,7 +843,7 @@ module Kettle
792
843
 
793
844
  c = content.dup
794
845
  c = c.gsub("kettle-rb", org.to_s)
795
- c = c.gsub("{OPENCOLLECTIVE|ORG_NAME}", funding_org)
846
+ c = c.gsub("{OPENCOLLECTIVE|ORG_NAME}", funding_org || "opencollective")
796
847
  # Replace min ruby token if present
797
848
  begin
798
849
  if min_ruby && !min_ruby.to_s.empty? && c.include?("{K_D_MIN_RUBY}")
@@ -813,6 +864,15 @@ module Kettle
813
864
  # ignore
814
865
  end
815
866
 
867
+ # Replace target gem name token if present
868
+ begin
869
+ token = "{TARGET|GEM|NAME}"
870
+ c = c.gsub(token, gem_name) if c.include?(token)
871
+ rescue StandardError => e
872
+ Kettle::Dev.debug_error(e, __method__)
873
+ # If replacement fails unexpectedly, proceed with content as-is
874
+ end
875
+
816
876
  # Special-case: yard-head link uses the gem name as a subdomain and must be dashes-only.
817
877
  # Apply this BEFORE other generic replacements so it isn't altered incorrectly.
818
878
  begin
@@ -6,7 +6,7 @@ module Kettle
6
6
  module Version
7
7
  # The gem version.
8
8
  # @return [String]
9
- VERSION = "1.1.55"
9
+ VERSION = "1.1.57"
10
10
 
11
11
  module_function
12
12
 
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kettle-dev
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.55
4
+ version: 1.1.57
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter H. Boling
@@ -203,6 +203,8 @@ extra_rdoc_files:
203
203
  files:
204
204
  - "./.aiignore.example"
205
205
  - "./.env.local.example"
206
+ - "./.envrc.example"
207
+ - "./.envrc.no-osc.example"
206
208
  - "./.gitlab-ci.yml.example"
207
209
  - "./.opencollective.yml.example"
208
210
  - "./.simplecov.example"
@@ -219,6 +221,8 @@ files:
219
221
  - ".devcontainer/devcontainer.json"
220
222
  - ".env.local.example"
221
223
  - ".envrc"
224
+ - ".envrc.example"
225
+ - ".envrc.no-osc.example"
222
226
  - ".git-hooks/commit-msg"
223
227
  - ".git-hooks/commit-subjects-goalie.txt"
224
228
  - ".git-hooks/footer-template.erb.txt"
@@ -397,10 +401,10 @@ licenses:
397
401
  - MIT
398
402
  metadata:
399
403
  homepage_uri: https://kettle-dev.galtzo.com/
400
- source_code_uri: https://github.com/kettle-rb/kettle-dev/tree/v1.1.55
401
- changelog_uri: https://github.com/kettle-rb/kettle-dev/blob/v1.1.55/CHANGELOG.md
404
+ source_code_uri: https://github.com/kettle-rb/kettle-dev/tree/v1.1.57
405
+ changelog_uri: https://github.com/kettle-rb/kettle-dev/blob/v1.1.57/CHANGELOG.md
402
406
  bug_tracker_uri: https://github.com/kettle-rb/kettle-dev/issues
403
- documentation_uri: https://www.rubydoc.info/gems/kettle-dev/1.1.55
407
+ documentation_uri: https://www.rubydoc.info/gems/kettle-dev/1.1.57
404
408
  funding_uri: https://github.com/sponsors/pboling
405
409
  wiki_uri: https://github.com/kettle-rb/kettle-dev/wiki
406
410
  news_uri: https://www.railsbling.com/tags/kettle-dev
metadata.gz.sig CHANGED
Binary file