From a3a017f44c3f96af8efb547cdd0fdd9e41795319 Mon Sep 17 00:00:00 2001 From: "Peter H. Boling" Date: Sun, 8 Nov 2026 07:55:28 +0000 Subject: [PATCH] Preserve documents when Markdown merge is empty --- gems/kettle-jem/lib/kettle/jem.rb | 6 +++++ .../integration/template_bootstrap_spec.rb | 22 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/gems/kettle-jem/lib/kettle/jem.rb b/gems/kettle-jem/lib/kettle/jem.rb index fe525f35b..7a41a3dda 100644 --- a/gems/kettle-jem/lib/kettle/jem.rb +++ b/gems/kettle-jem/lib/kettle/jem.rb @@ -7782,6 +7782,12 @@ def merge_config_template_source(recipe, template_content, destination_content, return merge_changelog_template_source(template_content, destination_content, facts: facts) if recipe.fetch(:target_path) == "CHANGELOG.md" merge_result = Ast::Template::MergeDispatch.dispatch(:markdown, template_content, destination_content) + # A successful structural merge can still produce no document (for + # example, a license containing only unheaded prose). Never replace a + # nonempty destination with that empty result. + if merge_result[:ok] && merge_result.fetch(:output).strip.empty? && !destination_content.strip.empty? + return destination_content + end when :dotenv merge_result = merge_dotenv_template_source(template_content, destination_content, recipe) when :rbs diff --git a/gems/kettle-jem/spec/integration/template_bootstrap_spec.rb b/gems/kettle-jem/spec/integration/template_bootstrap_spec.rb index 65365e03a..4c993c4ed 100644 --- a/gems/kettle-jem/spec/integration/template_bootstrap_spec.rb +++ b/gems/kettle-jem/spec/integration/template_bootstrap_spec.rb @@ -1073,6 +1073,28 @@ end end + it "preserves a complete existing AGPL license when templating a monorepo subgem" do + Dir.mktmpdir("kettle-jem-agpl-license") do |root| + license = File.read(File.expand_path("../../lib/kettle/jem/templates/AGPL-3.0-only.md.example", __dir__)) + destination = license.sub("GNU AFFERO GENERAL PUBLIC LICENSE", "GNU Affero General Public License") + write_tree(root, { + "example.gemspec" => <<~RUBY, + Gem::Specification.new do |spec| + spec.name = "example" + spec.summary = "Example gem" + spec.licenses = ["AGPL-3.0-only"] + spec.required_ruby_version = ">= 3.2" + end + RUBY + "AGPL-3.0-only.md" => destination + }) + described_class.setup_project(root, env: {}, run_options: {bootstrap_mode: true, template_profile: "monorepo-subgem-release", skip_commit: true}) + described_class.apply_project(root, env: {}, run_options: {only: "AGPL-3.0-only.md", accept: true, skip_commit: true}) + + expect(File.read(File.join(root, "AGPL-3.0-only.md"))).to eq(destination) + end + end + it "bootstraps a monorepo subgem release profile with per-gem harness entries" do tmp_root = File.expand_path("../tmp", __dir__) FileUtils.mkdir_p(tmp_root)