kettle-jem 7.1.1 → 7.1.4

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.
@@ -17,6 +17,7 @@ structuredmerge_local_gems = %w[
17
17
  citrus-toml-merge
18
18
  dotenv-merge
19
19
  go-merge
20
+ html-merge
20
21
  json-merge
21
22
  kettle-jem
22
23
  kramdown-merge
@@ -43,7 +44,7 @@ kettle_dev_local_gems = %w[
43
44
  {KJ|KETTLE_DEV_LOCAL_GEMS}
44
45
  ]
45
46
  declared_gems = instance_variable_get(:@dependencies).to_a.map(&:name)
46
- structuredmerge_local_gems_to_eval = structuredmerge_local_gems - %w[{KJ|PACKAGE_NAME}] - declared_gems
47
+ structuredmerge_local_gems_to_eval = structuredmerge_local_gems - %w[{KJ|PACKAGE_NAME}]
47
48
  kettle_dev_local_gems_to_eval = kettle_dev_local_gems - %w[{KJ|PACKAGE_NAME}] - (declared_gems - %w[kettle-dev])
48
49
 
49
50
  platform :mri do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  eval_gemfile "../../erb/r3.1/v4.0.gemfile"
2
4
  eval_gemfile "../../mutex_m/r3/v0.3.gemfile"
3
5
  eval_gemfile "../../stringio/r3/v3.0.gemfile"
@@ -30,7 +30,7 @@ Gem::Specification.new do |spec|
30
30
  spec.add_dependency "{KJ|SHIMMED_GEM_NAME}"
31
31
 
32
32
  # Dev, Test, & Release Tasks
33
- spec.add_development_dependency("kettle-dev", "~> 2.5", ">= 2.5.24") # ruby >= {KJ|MIN_TEST_RUBY}
33
+ spec.add_development_dependency("kettle-dev", "~> 3.0", ">= 3.0.6") # ruby >= {KJ|MIN_TEST_RUBY}
34
34
 
35
35
  # Tasks
36
36
  spec.add_development_dependency "rake", "~> 13.0"
@@ -5,7 +5,7 @@ module Kettle
5
5
  # Version namespace for this gem.
6
6
  module Version
7
7
  # Current gem version.
8
- VERSION = "7.1.1"
8
+ VERSION = "7.1.4"
9
9
  end
10
10
  # Current gem version exposed at the traditional constant location.
11
11
  VERSION = Version::VERSION # Traditional Constant Location
data/lib/kettle/jem.rb CHANGED
@@ -20,9 +20,11 @@ require "ast/crispr/markdown/markly"
20
20
  require "kettle/ndjson"
21
21
  require "rbs"
22
22
  require "kettle/dev"
23
+ require "kettle/changelog"
23
24
  require "kettle/rb/compat_matrix"
24
25
  require_relative "jem/version"
25
26
  require_relative "jem/license_txt_migrator"
27
+ require_relative "jem/maintenance_changelog"
26
28
 
27
29
  begin
28
30
  require "kettle/drift"
@@ -38,7 +40,7 @@ module Kettle
38
40
  CONTENT_RECIPE_TRANSPORT_VERSION = Ast::Merge::STRUCTURED_EDIT_TRANSPORT_VERSION
39
41
  TEMPLATE_SOURCE_APPLICATION_FINGERPRINT_VERSION = 1
40
42
  APPRAISALS_TEMPLATE_POLICY_FINGERPRINT_VERSION = 2
41
- GEMSPEC_TEMPLATE_POLICY_FINGERPRINT_VERSION = 1
43
+ GEMSPEC_TEMPLATE_POLICY_FINGERPRINT_VERSION = 2
42
44
  SPEC_HELPER_TEMPLATE_POLICY_FINGERPRINT_VERSION = 1
43
45
  VERSION_NAMESPACE_TEMPLATE_POLICY_FINGERPRINT_VERSION = 2
44
46
  KETTLE_CONFIG_PATH = ".structuredmerge/kettle-jem.yml"
@@ -50,6 +52,9 @@ module Kettle
50
52
  GEMSPEC_DEPENDENCY_MINIMUM_REQUIREMENTS = {
51
53
  "rspec-stubbed_env" => ">= 1.0.6"
52
54
  }.freeze
55
+ DEFAULT_GEMSPEC_METADATA_VALUES = {
56
+ "allowed_push_host" => "TODO: Set to your gem server 'https://example.com'"
57
+ }.freeze
53
58
  OBSOLETE_GITHUB_WORKFLOWS = %w[
54
59
  ancient.yml
55
60
  legacy.yml
@@ -439,6 +444,7 @@ module Kettle
439
444
  KJ|MAIN_GEMFILE_NOMONO_BOOTSTRAP
440
445
  KJ|MIN_DIVERGENCE_THRESHOLD
441
446
  KJ|MIN_RUBY
447
+ KJ|KETTLE_CHANGELOG_GEMFILE_DEPENDENCY
442
448
  KJ|OPENCOLLECTIVE_ORG
443
449
  KJ|README:COPYRIGHT_NOTICE
444
450
  KJ|README:CORPORATE_SPONSORS
@@ -848,6 +854,9 @@ module Kettle
848
854
  label = owner.label.to_s
849
855
  label if patterns.fetch(:ref_prefixes).any? { |pattern| pattern.match?(label) }
850
856
  end
857
+ ref_labels.each do |label|
858
+ processed = remove_markdown_inline_references(processed, label)
859
+ end
851
860
  processed = delete_markdown_link_definitions(processed, ref_labels)
852
861
  end
853
862
 
@@ -1399,6 +1408,7 @@ module Kettle
1399
1408
  "🖇osc-sponsors-bottom-img"
1400
1409
  ].freeze
1401
1410
  README_INTEGRATIONS = %w[codecov coveralls qlty codeql skywalking-eyes].freeze
1411
+ README_STAR_HISTORY_MIN_STARS = 150
1402
1412
  README_DISCOVERED_INTEGRATIONS = (README_INTEGRATIONS - [SKYWALKING_EYES_INTEGRATION]).freeze
1403
1413
  COVERAGE_INTEGRATIONS = %w[codecov coveralls qlty].freeze
1404
1414
  MANAGED_INTEGRATIONS = (COVERAGE_INTEGRATIONS + [SKYWALKING_EYES_INTEGRATION]).freeze
@@ -4790,6 +4800,10 @@ module Kettle
4790
4800
  end
4791
4801
 
4792
4802
  def post_apply_steps(project_root, report)
4803
+ selection = report.fetch(:template_selection, {})
4804
+ scoped_template = Array(selection[:only]).any?
4805
+ return [kettle_jem_state_sync_step(project_root, report)].compact if scoped_template
4806
+
4793
4807
  [
4794
4808
  *[template_version_gem_bootstrap_step(project_root, report)].flatten,
4795
4809
  executable_version_entrypoint_sync_step(project_root, report),
@@ -5164,6 +5178,7 @@ module Kettle
5164
5178
  updated.insert(profile_index + 1, *entries_lines)
5165
5179
  end
5166
5180
  sync_kettle_config_gemspec_strategy_lines!(updated, gemspec_path)
5181
+ sync_kettle_config_rakefile_strategy_lines!(updated)
5167
5182
  ensure_trailing_newline(updated.join("\n"))
5168
5183
  end
5169
5184
 
@@ -5194,6 +5209,33 @@ module Kettle
5194
5209
  end
5195
5210
  end
5196
5211
 
5212
+ def sync_kettle_config_rakefile_strategy_lines!(lines)
5213
+ files_index = lines.index("files:")
5214
+ return unless files_index
5215
+
5216
+ rakefile_index = ((files_index + 1)...lines.length).find do |index|
5217
+ line = lines.fetch(index)
5218
+ break nil if top_level_yaml_key_line?(line)
5219
+
5220
+ line == " Rakefile:"
5221
+ end
5222
+ unless rakefile_index
5223
+ insertion_index = kettle_config_gemspec_override_insertion_index(lines, files_index)
5224
+ lines.insert(insertion_index, " Rakefile:", " strategy: accept_template")
5225
+ return
5226
+ end
5227
+
5228
+ block_end = kettle_config_file_override_block_end(lines, rakefile_index)
5229
+ strategy_index = ((rakefile_index + 1)...block_end).find do |index|
5230
+ lines.fetch(index).start_with?(" strategy:")
5231
+ end
5232
+ if strategy_index
5233
+ lines[strategy_index] = " strategy: accept_template"
5234
+ else
5235
+ lines.insert(rakefile_index + 1, " strategy: accept_template")
5236
+ end
5237
+ end
5238
+
5197
5239
  def remove_stale_gemspec_file_override_blocks!(lines, files_index, gemspec)
5198
5240
  index = files_index + 1
5199
5241
  while index < lines.length
@@ -5278,15 +5320,15 @@ module Kettle
5278
5320
  [
5279
5321
  {name: "appraisal2", source: %(gem "appraisal2", "~> 3.2", ">= 3.2.2"\n)},
5280
5322
  {name: "bundler-audit", source: %(gem "bundler-audit", "~> 0.9.3"\n)},
5281
- {name: "kettle-dev", source: %(gem "kettle-dev", "~> 2.5", ">= 2.5.24"\n)},
5323
+ {name: "kettle-dev", source: %(gem "kettle-dev", "~> 3.0", ">= 3.0.6"\n)},
5282
5324
  {name: "kettle-drift", source: %(gem "kettle-drift", "~> 1.0", ">= 1.0.12"\n)},
5283
- {name: "kettle-family", source: %(gem "kettle-family", "~> 1.2", ">= 1.2.41"\n)},
5284
- {name: "kettle-jem", source: %(gem "kettle-jem", "~> 7.0", ">= 7.0.0"\n)},
5325
+ {name: "kettle-family", source: %(gem "kettle-family", "~> 1.2", ">= 1.2.51"\n)},
5326
+ {name: "kettle-jem", source: %(gem "kettle-jem", "~> 7.1", ">= 7.1.3"\n)},
5285
5327
  {name: "kettle-test", source: %(gem "kettle-test", "~> 2.0", ">= 2.0.19"\n)},
5286
5328
  {name: "rake", source: %(gem "rake", "~> 13.0"\n)},
5287
5329
  {name: "rspec", source: %(gem "rspec", "~> 3.0"\n)},
5288
5330
  {name: "stone_checksums", source: %(gem "stone_checksums", "~> 1.0", ">= 1.0.8"\n)},
5289
- {name: "turbo_tests2", source: %(gem "turbo_tests2", "~> 3.2", ">= 3.2.4"\n)}
5331
+ {name: "turbo_tests2", source: %(gem "turbo_tests2", "~> 3.2", ">= 3.2.5"\n)}
5290
5332
  ].freeze
5291
5333
  end
5292
5334
 
@@ -6350,37 +6392,11 @@ module Kettle
6350
6392
  end
6351
6393
 
6352
6394
  def apply_changelog_transfer_entries(content, entries, excluded_keys: [])
6353
- transfer_entries = Array(entries).select do |entry|
6354
- entry.is_a?(Hash) && entry[:key].to_s != "" && Array(entry[:lines]).any?
6355
- end
6356
-
6357
- normalized = normalize_changelog(content, {})
6358
- normalized = remove_excluded_changelog_transfer_entries(normalized, excluded_keys)
6359
- existing_keys = changelog_transfer_keys(normalized)
6360
- missing = transfer_entries.reject { |entry| existing_keys.include?(entry.fetch(:key)) }
6361
- return ensure_trailing_newline(normalized) if missing.empty?
6362
-
6363
- lines = markdown_source_lines(normalized)
6364
- unreleased = changelog_unreleased_line_index(lines)
6365
- return ensure_trailing_newline(normalized) unless unreleased
6366
-
6367
- destination_end = changelog_unreleased_end_index(lines, unreleased)
6368
- destination_body = lines[(unreleased + 1)...destination_end] || []
6369
- items = changelog_unreleased_items(destination_body)
6370
- missing.group_by { |entry| entry.fetch(:section, "### Changed") }.each do |section, section_entries|
6371
- section = CHANGELOG_STANDARD_HEADINGS.include?(section) ? section : "### Changed"
6372
- items[section] ||= []
6373
- items[section].pop while items[section].any? && items[section].last.to_s.strip.empty?
6374
- items[section] << "" if items[section].any?
6375
- section_entries.each do |entry|
6376
- items[section].concat(Array(entry.fetch(:lines)).map(&:rstrip))
6377
- end
6378
- end
6379
-
6380
- merged_lines = lines[0...unreleased] +
6381
- build_changelog_unreleased_section(lines.fetch(unreleased), items) +
6382
- lines[destination_end..].to_a
6383
- ensure_trailing_newline(merged_lines.join("\n").gsub(/\n{3,}/, "\n\n"))
6395
+ Kettle::Changelog::TransferMerger.apply(
6396
+ content: normalize_changelog(content, {}),
6397
+ entries: entries,
6398
+ excluded_keys: excluded_keys
6399
+ )
6384
6400
  end
6385
6401
 
6386
6402
  def remove_excluded_changelog_transfer_entries(content, excluded_keys)
@@ -6988,7 +7004,13 @@ module Kettle
6988
7004
  destination_content: original
6989
7005
  )
6990
7006
  return with_readme_timing("readme.append_used_link_definitions") do
6991
- append_used_markdown_link_definitions(processed, resolved)
7007
+ appended = append_used_markdown_link_definitions(processed, resolved)
7008
+ postprocess_readme_content(
7009
+ appended,
7010
+ facts,
7011
+ project_root: project_root,
7012
+ destination_content: original
7013
+ )
6992
7014
  end
6993
7015
  end
6994
7016
  if strategy.empty? || strategy == "merge"
@@ -7164,7 +7186,9 @@ module Kettle
7164
7186
 
7165
7187
  def delete_yaml_top_level_mapping_entries(content, parent_key:, child_keys:)
7166
7188
  document = Psych.parse(content.to_s)
7167
- root = document&.root
7189
+ # Psych returns `false` for a comment-only document under some versions.
7190
+ # Such content has no mapping to prune and must pass through unchanged.
7191
+ root = document.root if document.respond_to?(:root)
7168
7192
  return content unless root.is_a?(Psych::Nodes::Mapping)
7169
7193
 
7170
7194
  parent = yaml_mapping_value(root, parent_key)
@@ -7174,7 +7198,7 @@ module Kettle
7174
7198
  ranges = parent.children.each_slice(2).filter_map do |key_node, value_node|
7175
7199
  next unless child_key_set.include?(key_node.value.to_s)
7176
7200
 
7177
- key_node.start_line..value_node.end_line
7201
+ key_node.start_line...value_node.end_line
7178
7202
  end
7179
7203
  return content if ranges.empty?
7180
7204
 
@@ -7232,6 +7256,13 @@ module Kettle
7232
7256
  engines: facts.dig(:rubygems, :engines)
7233
7257
  )
7234
7258
  end
7259
+ processed = with_readme_timing("postprocess.compatibility_summary") do
7260
+ normalize_readme_compatibility_summary(
7261
+ processed,
7262
+ facts.dig(:rubygems, :engines),
7263
+ minimum_ruby_token(facts.dig(:rubygems, :min_ruby))
7264
+ )
7265
+ end
7235
7266
  processed = with_readme_timing("postprocess.project_heading") { normalize_readme_project_heading(processed, facts) }
7236
7267
  processed = with_readme_timing("postprocess.synopsis_heading") { normalize_readme_synopsis_heading(processed, facts) }
7237
7268
  processed = with_readme_timing("postprocess.conditional_blocks") { apply_readme_conditional_blocks(processed, facts) }
@@ -7334,7 +7365,17 @@ module Kettle
7334
7365
  def apply_readme_conditional_blocks(content, facts)
7335
7366
  open_collective_enabled = !facts.dig(:funding, :open_collective_disabled)
7336
7367
  processed = apply_markdown_conditional_block(content, "OPEN_COLLECTIVE", keep: open_collective_enabled)
7337
- apply_markdown_conditional_block(processed, "NO_OPEN_COLLECTIVE", keep: !open_collective_enabled)
7368
+ processed = apply_markdown_conditional_block(processed, "NO_OPEN_COLLECTIVE", keep: !open_collective_enabled)
7369
+ star_history_enabled = facts.dig(:repository, :star_history, :enabled) == true
7370
+ return processed if star_history_enabled
7371
+
7372
+ delete_markdown_with_ast_crispr(
7373
+ processed,
7374
+ Ast::Crispr::Markdown::Markly::Selectors.html_details(
7375
+ summary_text: "⭐️ Star History",
7376
+ limit: {at_least: 0}
7377
+ )
7378
+ )
7338
7379
  end
7339
7380
 
7340
7381
  def apply_readme_badge_policy(content, facts)
@@ -7364,9 +7405,31 @@ module Kettle
7364
7405
  )
7365
7406
  end
7366
7407
  end
7408
+ Array(facts.dig(:readme_style, :disabled_integrations)).each do |integration|
7409
+ patterns = README_INTEGRATION_BADGE_PATTERNS.fetch(integration.to_s, [])
7410
+ labels = README_INTEGRATION_LINK_LABELS.fetch(integration.to_s, [])
7411
+ processed = patterns.reduce(processed) { |content, pattern| content.gsub(pattern, "") }
7412
+ processed = ReadmePostProcessor.delete_markdown_link_definitions(processed, labels)
7413
+ end
7367
7414
  processed
7368
7415
  end
7369
7416
 
7417
+ def normalize_readme_compatibility_summary(content, engines, min_ruby = "")
7418
+ enabled = Array(engines).map { |engine| engine.to_s.strip.downcase }.reject(&:empty?).uniq
7419
+ return content if enabled.empty?
7420
+
7421
+ runtime_floor = min_ruby.to_s.strip
7422
+ runtime_floor = " #{runtime_floor}+" unless runtime_floor.empty?
7423
+ runtime_engines = ["MRI Ruby#{runtime_floor}"]
7424
+ runtime_engines << "JRuby" if enabled.include?("jruby")
7425
+ runtime_engines << "TruffleRuby" if enabled.include?("truffleruby") || enabled.include?("truby")
7426
+ description = runtime_engines.one? ? runtime_engines.first : runtime_engines[0...-1].join(", ") + ", and #{runtime_engines.last}"
7427
+ content.to_s.sub(
7428
+ /Compatible with MRI Ruby [^\n]+\./,
7429
+ "Compatible with #{description}."
7430
+ )
7431
+ end
7432
+
7370
7433
  def remove_readme_badge_and_refs(content, badge_source, link_labels)
7371
7434
  ensure_runtime_dependencies!
7372
7435
  processed = content.to_s.gsub(badge_source, "").lines.map(&:rstrip).join("\n")
@@ -9646,7 +9709,7 @@ module Kettle
9646
9709
  replacement = if record.fetch(:source).lines.one?
9647
9710
  "%w[#{kept.join(" ")}]"
9648
9711
  else
9649
- ruby_multiline_word_array_source(kept, indent: record.fetch(:start_column))
9712
+ ruby_multiline_word_array_source(kept, indent: record.fetch(:line_indent))
9650
9713
  end
9651
9714
  {start_offset: record.fetch(:start_offset), end_offset: record.fetch(:end_offset), replacement: replacement}
9652
9715
  end
@@ -9657,13 +9720,15 @@ module Kettle
9657
9720
  end
9658
9721
 
9659
9722
  def ruby_word_array_records(content)
9723
+ lines = content.to_s.lines
9660
9724
  ruby_word_array_nodes(content).map do |node|
9725
+ source_line = lines.fetch(node.location.start_line - 1)
9661
9726
  {
9662
9727
  names: ruby_word_array_names(node),
9663
9728
  source: node.location.slice,
9664
9729
  start_line: node.location.start_line,
9665
9730
  end_line: node.location.end_line,
9666
- start_column: node.location.start_column,
9731
+ line_indent: source_line.length - source_line.lstrip.length,
9667
9732
  start_offset: node.location.start_offset,
9668
9733
  end_offset: node.location.end_offset
9669
9734
  }
@@ -9690,9 +9755,9 @@ module Kettle
9690
9755
  end
9691
9756
 
9692
9757
  def ruby_multiline_word_array_source(names, indent:)
9693
- prefix = " " * indent.to_i
9694
- element_prefix = "#{prefix} "
9695
- (["#{prefix}%w["] + names.map { |name| "#{element_prefix}#{name}" } + ["#{prefix}]"]).join("\n")
9758
+ element_prefix = " " * (indent.to_i + 2)
9759
+ closing_prefix = " " * indent.to_i
9760
+ (["%w["] + names.map { |name| "#{element_prefix}#{name}" } + ["#{closing_prefix}]"]).join("\n")
9696
9761
  end
9697
9762
 
9698
9763
  def replace_source_offsets(content, replacements)
@@ -10259,6 +10324,13 @@ module Kettle
10259
10324
  merged = apply_configured_gemspec_licenses(merged, facts, receiver: template_receiver)
10260
10325
  merged = apply_configured_gemspec_required_ruby_version(merged, facts, receiver: template_receiver)
10261
10326
  merged = apply_configured_gemspec_metadata(merged, facts, receiver: template_receiver)
10327
+ merged = preserve_destination_only_gemspec_metadata(
10328
+ merged,
10329
+ template_content: template_content,
10330
+ destination_content: destination_content,
10331
+ template_receiver: template_receiver,
10332
+ destination_receiver: destination_receiver
10333
+ )
10262
10334
  merged = remove_duplicate_gemspec_assignments(merged, receiver: template_receiver, fields: %w[homepage])
10263
10335
  merged = remove_gemspec_self_dependency_lines(merged, package_name, receiver: template_receiver)
10264
10336
  merged = remove_gemspec_version_gem_dependency_when_disabled(
@@ -10527,6 +10599,36 @@ module Kettle
10527
10599
  content
10528
10600
  end
10529
10601
 
10602
+ def preserve_destination_only_gemspec_metadata(
10603
+ content,
10604
+ template_content:,
10605
+ destination_content:,
10606
+ template_receiver:,
10607
+ destination_receiver:
10608
+ )
10609
+ template_keys = gemspec_metadata_assignment_records(template_content, receiver: template_receiver).map do |record|
10610
+ record.fetch(:key)
10611
+ end
10612
+ merged_keys = gemspec_metadata_assignment_records(content, receiver: template_receiver).map do |record|
10613
+ record.fetch(:key)
10614
+ end
10615
+ destination_records = gemspec_metadata_assignment_records(destination_content, receiver: destination_receiver).select do |record|
10616
+ !template_keys.include?(record.fetch(:key)) &&
10617
+ !merged_keys.include?(record.fetch(:key)) &&
10618
+ !default_gemspec_metadata_assignment?(record)
10619
+ end
10620
+ return content if destination_records.empty?
10621
+
10622
+ insertion = destination_records.map do |record|
10623
+ normalize_gemspec_receiver(record.fetch(:source).rstrip, from: destination_receiver, to: template_receiver)
10624
+ end.join("\n") + "\n"
10625
+ anchor = gemspec_metadata_assignment_records(content, receiver: template_receiver).last
10626
+ anchor ||= gemspec_assignment_records(content, receiver: template_receiver).find { |record| record.fetch(:field) == "homepage" }
10627
+ return content unless anchor
10628
+
10629
+ insert_lines_after(content, anchor.fetch(:end_line), insertion)
10630
+ end
10631
+
10530
10632
  def gemspec_metadata_assignment_records(content, receiver:)
10531
10633
  lines = content.to_s.lines
10532
10634
  ruby_call_records(content, :[]=).filter_map do |call|
@@ -10540,6 +10642,7 @@ module Kettle
10540
10642
  end_line = ruby_node_source_end_line(call)
10541
10643
  {
10542
10644
  key: key,
10645
+ value: ruby_static_string_value(args[1]),
10543
10646
  start_line: start_line,
10544
10647
  end_line: end_line,
10545
10648
  source: lines[(start_line - 1)..(end_line - 1)].to_a.join
@@ -10549,6 +10652,10 @@ module Kettle
10549
10652
  []
10550
10653
  end
10551
10654
 
10655
+ def default_gemspec_metadata_assignment?(record)
10656
+ DEFAULT_GEMSPEC_METADATA_VALUES[record.fetch(:key)] == record[:value]
10657
+ end
10658
+
10552
10659
  def remove_gemspec_version_gem_dependency_when_disabled(content, facts, receiver:, template_declares_version_gem: false)
10553
10660
  return content if version_gem_enabled?(facts)
10554
10661
  return content if template_declares_version_gem && !version_gem_explicitly_disabled?(facts) && version_gem_runtime_compatible?(facts)
@@ -12576,7 +12683,9 @@ module Kettle
12576
12683
  def add_monorepo_subgem_file_overrides(content, gemspec_path, profile = MONOREPO_SUBGEM_TEMPLATE_PROFILE)
12577
12684
  override_lines = [
12578
12685
  " README.md:",
12579
- " strategy: merge"
12686
+ " strategy: merge",
12687
+ " Rakefile:",
12688
+ " strategy: accept_template"
12580
12689
  ]
12581
12690
  gemspec = gemspec_path.to_s.strip
12582
12691
  unless gemspec.empty?
@@ -13768,6 +13877,9 @@ module Kettle
13768
13877
  "KJ|MIN_RUBY" => minimum_ruby_token(rubygems[:min_ruby]),
13769
13878
  "KJ|MIN_DEV_RUBY" => facts.dig(:project_runtime, :test_min_ruby).to_s,
13770
13879
  "KJ|MIN_TEST_RUBY" => facts.dig(:project_runtime, :test_min_ruby).to_s,
13880
+ "KJ|KETTLE_CHANGELOG_GEMFILE_DEPENDENCY" => kettle_changelog_gemfile_dependency_token(
13881
+ package.fetch(:name).to_s
13882
+ ),
13771
13883
  "KJ|CI:EXEC_CMD" => facts.dig(:ci, :exec_cmd).to_s,
13772
13884
  "KJ|GITHUB_ACTIONS:COVERAGE_UPLOAD_STEPS" => github_actions_coverage_steps(disabled_integrations: facts.dig(:integrations, :disabled))
13773
13885
  }.merge(
@@ -13806,6 +13918,30 @@ module Kettle
13806
13918
  tokens.reject { |key, value| value.empty? && !EMPTY_TEMPLATE_TOKENS.include?(key) }
13807
13919
  end
13808
13920
 
13921
+ def kettle_changelog_gemfile_dependency_token(package_name)
13922
+ return "" if package_name == "kettle-changelog"
13923
+
13924
+ <<~RUBY.chomp
13925
+ kettle_changelog_skip = ENV.fetch("KETTLE_DEV_SKIP_CHANGELOG", "false").downcase
13926
+ kettle_changelog_skip = %w[true 1 yes on].include?(kettle_changelog_skip)
13927
+ kettle_changelog_local = ENV.fetch("KETTLE_DEV_DEV", "false").downcase
13928
+ kettle_changelog_local = !%w[false 0 no off].include?(kettle_changelog_local)
13929
+ unless kettle_changelog_skip
13930
+ if kettle_changelog_local
13931
+ require "nomono/bundler"
13932
+ eval_nomono_gems(
13933
+ gems: ["kettle-changelog"],
13934
+ prefix: "KETTLE_DEV",
13935
+ path_env: "KETTLE_DEV_DEV",
13936
+ root: ["src", "my", "kettle-dev"]
13937
+ )
13938
+ elsif Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("4.0.0")
13939
+ gem "kettle-changelog", "~> 1.0", ">= 1.0.2"
13940
+ end
13941
+ end
13942
+ RUBY
13943
+ end
13944
+
13809
13945
  def readme_title_token(package, rubygems)
13810
13946
  package_name = package.fetch(:name).to_s.strip
13811
13947
  default_entrypoint = package_name.tr("-", "/")
@@ -14751,7 +14887,7 @@ module Kettle
14751
14887
  end
14752
14888
 
14753
14889
  def kettle_dev_local_gems(config)
14754
- gems = %w[kettle-dev kettle-family kettle-test kettle-soup-cover]
14890
+ gems = %w[kettle-dev kettle-family kettle-test kettle-soup-cover kettle-changelog]
14755
14891
  plugin_names = PluginLoader.normalize_plugin_names(plugin_names_from_config(config))
14756
14892
  gems.concat(plugin_names.select { |plugin_name| plugin_name.start_with?("kettle-") })
14757
14893
  gems.uniq.join(" ")
@@ -14760,7 +14896,7 @@ module Kettle
14760
14896
  def main_gemfile_kettle_family_gem(package_name)
14761
14897
  return "" if package_name.to_s == "kettle-family"
14762
14898
 
14763
- %(gem "kettle-family", "~> 1.2", ">= 1.2.41"\n)
14899
+ %(gem "kettle-family", "~> 1.2", ">= 1.2.51"\n)
14764
14900
  end
14765
14901
 
14766
14902
  def main_gemfile_nomono_bootstrap(package_name)
@@ -15870,8 +16006,10 @@ module Kettle
15870
16006
  topology = normalize_repository_topology(repository_topology)
15871
16007
  monorepo_subproject = topology == REPOSITORY_TOPOLOGY_MONOREPO_SUBPROJECT
15872
16008
  local_root = monorepo_subproject ? git_worktree_root(project_root) : nil
16009
+ repository_root = local_root || project_root
16010
+ git_source_url = git_remote_source_url(repository_root)
15873
16011
  repo_url = if monorepo_subproject
15874
- repository_root_url(git_remote_source_url(local_root || project_root) || source_url)
16012
+ repository_root_url(git_source_url || source_url)
15875
16013
  else
15876
16014
  repository_root_url(source_url)
15877
16015
  end
@@ -15883,7 +16021,8 @@ module Kettle
15883
16021
  topology: topology,
15884
16022
  url: repo_url,
15885
16023
  name: repo_name,
15886
- slug: slug
16024
+ slug: slug,
16025
+ star_history: readme_star_history_facts(repository_root, git_source_url)
15887
16026
  )
15888
16027
  return facts unless monorepo_subproject
15889
16028
 
@@ -16030,6 +16169,54 @@ module Kettle
16030
16169
  nil
16031
16170
  end
16032
16171
 
16172
+ def readme_star_history_facts(project_root, git_source_url)
16173
+ repository_slug = github_repository_slug(git_source_url)
16174
+ return {enabled: false, reason: "no_github_remote"} if repository_slug.to_s.empty?
16175
+
16176
+ stars = github_repository_star_count(project_root, repository_slug)
16177
+ unless stars
16178
+ return {
16179
+ enabled: false,
16180
+ repository: repository_slug,
16181
+ reason: "star_count_unavailable"
16182
+ }
16183
+ end
16184
+
16185
+ {
16186
+ enabled: stars >= README_STAR_HISTORY_MIN_STARS,
16187
+ repository: repository_slug,
16188
+ stars: stars,
16189
+ minimum_stars: README_STAR_HISTORY_MIN_STARS
16190
+ }
16191
+ end
16192
+
16193
+ def github_repository_slug(url)
16194
+ normalized = normalize_git_source_url(url)
16195
+ match = normalized.to_s.match(%r{\Ahttps?://github\.com/([^/]+)/([^/?#]+)})
16196
+ return unless match
16197
+
16198
+ repository = match[2].delete_suffix(".git")
16199
+ return if match[1].empty? || repository.empty?
16200
+
16201
+ "#{match[1]}/#{repository}"
16202
+ end
16203
+
16204
+ def github_repository_star_count(project_root, repository_slug)
16205
+ stdout, _stderr, status = Open3.capture3(
16206
+ "gh",
16207
+ "api",
16208
+ "repos/#{repository_slug}",
16209
+ "--jq",
16210
+ ".stargazers_count",
16211
+ chdir: project_root.to_s
16212
+ )
16213
+ return unless status.success?
16214
+
16215
+ Integer(stdout.to_s.strip)
16216
+ rescue ArgumentError, IOError, SystemCallError
16217
+ nil
16218
+ end
16219
+
16033
16220
  def normalize_git_source_url(url)
16034
16221
  value = url.to_s.strip
16035
16222
  return if value.empty?
@@ -16040,6 +16227,11 @@ module Kettle
16040
16227
  end
16041
16228
 
16042
16229
  uri = URI.parse(value)
16230
+ if uri.scheme == "ssh" && uri.host == "github.com"
16231
+ slug = uri.path.to_s.delete_prefix("/").delete_suffix(".git")
16232
+ return "https://github.com/#{slug}" if slug.split("/").length >= 2
16233
+ end
16234
+
16043
16235
  if %w[http https].include?(uri.scheme) && uri.host == "github.com"
16044
16236
  slug = uri.path.to_s.delete_prefix("/").delete_suffix(".git")
16045
16237
  return "https://github.com/#{slug}" if slug.split("/").length >= 2
@@ -17614,7 +17806,7 @@ module Kettle
17614
17806
  relative_path = path.delete_prefix("#{project_root}/")
17615
17807
  next unless preferred_template_source(PACKAGED_TEMPLATE_ROOT, relative_path)
17616
17808
 
17617
- {target_path: relative_path} if skip_packaged_gemfile_template?(relative_path, config)
17809
+ {target_path: relative_path} if skip_packaged_gemfile_template?(relative_path, config, project_root: project_root)
17618
17810
  end
17619
17811
  (gemfile_cleanups + disabled_integration_config_cleanups(project_root, config)).sort_by { |cleanup| cleanup.fetch(:target_path) }
17620
17812
  end
@@ -17697,7 +17889,7 @@ module Kettle
17697
17889
  return if source_path.to_s.empty? || target_path.to_s.empty?
17698
17890
  return if skip_packaged_workflow_template?(target_path, config, include_patterns: include_patterns)
17699
17891
  return if skip_disabled_integration_template?(target_path, config)
17700
- return if skip_packaged_gemfile_template?(target_path, config)
17892
+ return if skip_packaged_gemfile_template?(target_path, config, project_root: project_root, template_root_path: template_root.fetch(:path))
17701
17893
  return if skip_packaged_license_template?(target_path, config)
17702
17894
  return if skip_packaged_version_gem_entrypoint_template?(project_root, source_path, target_path, config)
17703
17895
  return if template_root.fetch(:kind) == "packaged" && opencollective_disabled && opencollective_disabled_file?(target_path)
@@ -17933,9 +18125,11 @@ module Kettle
17933
18125
  Gem::Version.new(version) < min_ruby
17934
18126
  end
17935
18127
 
17936
- def skip_packaged_gemfile_template?(target_path, config)
18128
+ def skip_packaged_gemfile_template?(target_path, config, project_root: nil, template_root_path: PACKAGED_TEMPLATE_ROOT)
17937
18129
  return true if target_path.to_s.include?("gemfiles/modular/recording/") && !appraisal_recording_enabled?(config)
17938
18130
 
18131
+ return false if packaged_gemfile_referenced_by_x_std_libs?(target_path, project_root: project_root, template_root_path: template_root_path)
18132
+
17939
18133
  version = packaged_gemfile_template_ruby_floor(target_path)
17940
18134
  return false unless version
17941
18135
 
@@ -17945,6 +18139,21 @@ module Kettle
17945
18139
  Gem::Version.new(version) < min_ruby
17946
18140
  end
17947
18141
 
18142
+ def packaged_gemfile_referenced_by_x_std_libs?(target_path, project_root:, template_root_path:)
18143
+ relative_path = target_path.to_s.delete_prefix("gemfiles/modular/")
18144
+ return false unless relative_path.start_with?("x_std_libs/")
18145
+
18146
+ aggregate_paths = [
18147
+ File.join(template_root_path.to_s, "gemfiles/modular/x_std_libs.gemfile.example"),
18148
+ File.join(project_root.to_s, "gemfiles/modular/x_std_libs.gemfile")
18149
+ ].select { |path| File.file?(path) }
18150
+ aggregate_paths.any? do |path|
18151
+ gemfile_eval_paths(File.read(path)).include?(relative_path)
18152
+ end
18153
+ rescue
18154
+ false
18155
+ end
18156
+
17948
18157
  def skip_disabled_integration_template?(target_path, config)
17949
18158
  disabled_integration_template_path?(target_path, config)
17950
18159
  end
@@ -19198,9 +19407,9 @@ module Kettle
19198
19407
  "actions/upload-artifact" => "actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1",
19199
19408
  "amancevice/setup-code-climate" => "amancevice/setup-code-climate@0daf2985a225e8ac15975b4d233010e94d65b76a # v2",
19200
19409
  "actions/dependency-review-action" => "actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0",
19201
- "github/codeql-action/init" => "github/codeql-action/init@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4",
19202
- "github/codeql-action/autobuild" => "github/codeql-action/autobuild@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4",
19203
- "github/codeql-action/analyze" => "github/codeql-action/analyze@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4",
19410
+ "github/codeql-action/init" => "github/codeql-action/init@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6",
19411
+ "github/codeql-action/autobuild" => "github/codeql-action/autobuild@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6",
19412
+ "github/codeql-action/analyze" => "github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6",
19204
19413
  "pozil/auto-assign-issue" => "pozil/auto-assign-issue@af6beea6bdf1e8eb373f061c5bc168681fc6d011 # v4.0.1",
19205
19414
  "apache/skywalking-eyes/dependency" => "apache/skywalking-eyes/dependency@61275cc80d0798a405cb070f7d3a8aaf7cf2c2c1 # v0.8.0",
19206
19415
  "sarisia/actions-status-discord" => "sarisia/actions-status-discord@eb045afee445dc055c18d3d90bd0f244fd062708 # v1.16.0"
data.tar.gz.sig CHANGED
Binary file