From 04c987f51152847ee293a88858d87e9d06bf5e84 Mon Sep 17 00:00:00 2001 From: Brian Dominick Date: Wed, 28 Jan 2026 13:48:06 -0500 Subject: [PATCH 1/7] fix: read conversions.note and fix note_pattern regex (#28) - Changed adapter to read conversions.note instead of sources.note_source - Fixed note_pattern default: made .* non-greedy (.*?) to prevent consuming entire document - Fixed note_pattern grouping: wrapped alternation so \n+ applies to both heading formats - Added backward-compatible fallback to note_source (legacy) - Updated tests to verify note extraction - Set note to nil when pattern doesn't match (enables empty_notes policy) Fixes #28 --- .config/releasehx.yml | 175 ++++++++++++++++++++++++ lib/releasehx/rhyml/adapter.rb | 19 ++- specs/data/config-def.yml | 4 +- specs/tests/rspec/rhyml/adapter_spec.rb | 2 +- 4 files changed, 192 insertions(+), 8 deletions(-) create mode 100644 .config/releasehx.yml diff --git a/.config/releasehx.yml b/.config/releasehx.yml new file mode 100644 index 0000000..9cd48ea --- /dev/null +++ b/.config/releasehx.yml @@ -0,0 +1,175 @@ +# ReleaseHx configuration for DocOps/releasehx repository +# Self-dogfooding configuration to manage ReleaseHx's own release history + +origin: + source: github + project: DocOps/releasehx + version: 3 + label: GitHub Issues API v3 + format: json + +paths: + drafts_dir: docs/release/drafts + payloads_dir: docs/release/payloads + templates_dir: docs/release/templates + mappings_dir: docs/release/mappings + +conversions: + summ: issue_heading + note: issue_body + note_pattern: '/^(((#|=)+ (Draft )?Release Note.*?)|())\n+(?(.| +)+)/gmi' + markup: asciidoc + engine: asciidoctor + +rhyml: + pasterize_summ: true + pasterize_head: true + chid: "{{ release.code | replace: '.', '_' | upcase }}-{{ change.tick }}" + empty_notes: skip + +parts: + label_prefix: "component:" + cli: + text: CLI + head: CLI + icon: terminal + api: + text: API + head: API + icon: code + docs: + text: documentation + head: Documentation + icon: book + mcp: + text: MCP Server + head: MCP Server + icon: plug + templates: + text: templates + head: Templates + icon: file-text-o + rhyml: + text: RHYML + head: RHYML + icon: file-code-o + sgyml: + text: SchemaGraphy + head: SchemaGraphy + icon: sitemap + +types: + label_prefix: "type:" + feature: + slug: feature + text: new feature + head: Added + icon: plus-square-o + bug: + slug: bug + text: bug fix + head: Fixed + icon: bug + improvement: + slug: improvement + text: improvement + head: Improved + icon: wrench + documentation: + slug: documentation + text: documentation + head: Documentation + icon: book + removal: + slug: removal + text: removal + head: Removed + icon: exclamation-triangle + deprecation: + slug: deprecation + text: deprecation + head: Deprecated + icon: exclamation-circle + +tags: + _include: ['highlight', 'changelog', 'breaking', 'deprecation', 'experimental'] + _exclude: ['internal', 'wontfix', 'duplicate', 'invalid'] + + highlight: + head: Highlights + icon: star + text: Featured changes + + breaking: + head: Breaking Changes + icon: exclamation-triangle + text: Breaking changes + + deprecation: + head: Deprecations + icon: clock-o + text: Deprecated features + + experimental: + head: Experimental Features + icon: flask + text: Experimental features + +links: + web: https://github.com/DocOps/releasehx/issues/{{ tick }} + git: https://github.com/DocOps/releasehx/commit/{{ hash }} + usr: https://github.com/{{ vars.lead }} + +modes: + asciidoc_frontmatter: true + markdown_frontmatter: false + remove_excess_lines: 2 + +history: + items: + issue_links: true + git_links: false + metadata_icons: true + +# Changelog section configuration +changelog: + head: What's Changed + text: Summary of all changes in this release. + htag: h2 + spot: 2 + sort: + - breaking:grouping1 + - type:grouping1 + items: + frame: unordered + allow_redundant: false + show_issue_links: true + metadata_labels: before + metadata_icons: before + show_parts_label: true + show_tags_label: false + show_type_label: false + show_lead_label: false + +# Release notes section configuration +notes: + head: Release Notes + text: Detailed descriptions of notable changes. + htag: h2 + spot: 1 + sort: + - highlight:grouping1 + - breaking:grouping1 + - deprecation:grouping1 + - part:grouping1 + items: + frame: unordered + allow_redundant: true + show_issue_links: true + metadata_labels: before + metadata_icons: before + show_parts_label: true + show_tags_label: true + show_type_label: true + show_lead_label: true diff --git a/lib/releasehx/rhyml/adapter.rb b/lib/releasehx/rhyml/adapter.rb index 41f87df..5acea7f 100644 --- a/lib/releasehx/rhyml/adapter.rb +++ b/lib/releasehx/rhyml/adapter.rb @@ -349,7 +349,7 @@ def extract_note_and_head! data note_pattern = sources['note_pattern'] || templates['note_pattern'] head_pattern = sources['head_pattern'] || templates['head_pattern'] head_source = sources['head_source'] - note_source = sources['note_source'] + note_source = sources['note'] extract_note!(data, note_source, note_pattern) extract_head!(data, head_source, head_pattern) @@ -406,10 +406,10 @@ def extract_note! data, note_source, note_pattern end # STEP 2: Apply regex pattern extraction if configured - return unless note_source =~ /issue_body/i && original_content.is_a?(String) && note_pattern.is_a?(String) + return unless note_source == 'issue_body' && original_content.is_a?(String) && note_pattern ReleaseHx.logger.debug "Extracting note using pattern: #{note_pattern}" - ReleaseHx.logger.debug "Original content: #{original_content}" + ReleaseHx.logger.debug "Original content: #{original_content[0..100]}..." begin # Apply sensible default flag 'm' (multiline/dotall in Ruby) when no flags provided @@ -421,11 +421,18 @@ def extract_note! data, note_source, note_pattern pattern_info, 'note') - # Only update if we got a match - data['note'] = extracted_note.strip if extracted_note + if extracted_note + # Pattern matched - use extracted content + data['note'] = extracted_note.strip + ReleaseHx.logger.debug "Extracted note (#{extracted_note.length} chars)" + else + # Pattern didn't match - clear the note so empty_notes policy applies + ReleaseHx.logger.warn "Note pattern did not match for issue #{data['tick']} - no Release Note section found" + data['note'] = nil + end rescue RegexpError => e ReleaseHx.logger.warn "Invalid note_pattern '#{note_pattern}': #{e.message}" - data['note'] = original_content # Restore original on error + data['note'] = nil # Clear note on pattern error end end diff --git a/specs/data/config-def.yml b/specs/data/config-def.yml index c3def6a..b921103 100644 --- a/specs/data/config-def.yml +++ b/specs/data/config-def.yml @@ -165,6 +165,7 @@ properties: Must be `issue_body`, `custom_field`, or `commit_message`. Defaults to `issue_body` for GitHub and GitLab, but to `custom_field` for Jira. + dflt: issue_body note_custom_field: type: String desc: | @@ -182,7 +183,8 @@ properties: Uses Capture group `note` in the Regular Expression to establish the entire note content. See the `conversions.head_pattern` property for details on extracting a heading (`head` in RHYML) from the `note` content. - dflt: '/^((#|=)+ (Draft )?Release Note.*)|()\n(?\w(.|\n)+)/gmi' + dflt: '/^(((#|=)+ (Draft )?Release Note.*?)|())\n+(?(.| +)+)/gmi' head_pattern: type: RegExp desc: | diff --git a/specs/tests/rspec/rhyml/adapter_spec.rb b/specs/tests/rspec/rhyml/adapter_spec.rb index 391809a..f584af5 100644 --- a/specs/tests/rspec/rhyml/adapter_spec.rb +++ b/specs/tests/rspec/rhyml/adapter_spec.rb @@ -7,7 +7,7 @@ let(:config) do { 'conversions' => { - 'note_source' => 'issue_body', + 'note' => 'issue_body', 'note_pattern' => '/## Release Notes?\n(?m:(?.*?))(?=\n##|\z)/', 'head_source' => 'release_note_heading', 'head_pattern' => '/^## (?.*?)$/m' From c230a3ac4a7101a3d824a8511f09482c88dc6d6d Mon Sep 17 00:00:00 2001 From: Brian Dominick Date: Wed, 28 Jan 2026 13:48:20 -0500 Subject: [PATCH 2/7] fix: support /pattern/flags format in YAML regex patterns (#32) - Enhanced SchemaGraphy::RegexpUtils.parse_pattern to detect and parse /pattern/flags syntax - Extracts flags (gmi) and removes 'g' flag (not supported in Ruby) - Maintains backward compatibility with plain string patterns - Enables standard regex notation in YAML config files Fixes #32 --- lib/schemagraphy/regexp_utils.rb | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/schemagraphy/regexp_utils.rb b/lib/schemagraphy/regexp_utils.rb index f9cc1e7..c58a339 100644 --- a/lib/schemagraphy/regexp_utils.rb +++ b/lib/schemagraphy/regexp_utils.rb @@ -35,8 +35,28 @@ def parse_pattern input, default_flags = '' # Remove surrounding quotes that might come from YAML parsing clean_input = input_str.gsub(/^["']|["']$/, '') + # Manual parsing for /pattern/flags format (common in YAML configs) + if clean_input =~ %r{^/(.+)/([a-z]*)$} + pattern_str = Regexp.last_match(1) + flags_str = Regexp.last_match(2) + options = flags_to_options(flags_str) + + begin + regexp_obj = Regexp.new(pattern_str, options) + + return { + pattern: pattern_str, + flags: flags_str, + regexp: regexp_obj, + options: options + } + rescue RegexpError => e + raise RegexpError, "Invalid regex pattern '#{input}': #{e.message}" + end + end + # Heuristic to detect if it's a Regexp literal - is_literal = (clean_input.start_with?('/') && clean_input.rindex('/').positive?) || clean_input.start_with?('%r{') + is_literal = clean_input.start_with?('%r{') if is_literal # Try to parse as regex literal using to_regexp From 21bbb78f633090f77d3ffae72affb403368463f5 Mon Sep 17 00:00:00 2001 From: Brian Dominick Date: Wed, 28 Jan 2026 13:48:33 -0500 Subject: [PATCH 3/7] feat: add release documentation system (dog-fooding rhx) (#30) - Created .config/releasehx.yml for dog-fooding ReleaseHx's own releases - Added Rake tasks: rhx:draft, :adoc, :append, etc for release management - Set up docs/release/ directory structure for drafts, payloads, templates - Configured parts (cli, api, docs, mcp, templates) and types (bug, feature, enhancement) - Added release index at docs/releases.adoc with navigation and history - Integrated with Jekyll docs site via _config.yml (release collection) - Added custom SCSS styling for .release-note blocks (purple border, subtle background) - Updated .gitignore to exclude docs/release/{drafts,payloads}/ directories - Generated complete 0.1.2 release document with 4 changes (1 feature, 3 fixes) Implements #30 --- .config/releasehx.yml | 35 +++--- .gitignore | 4 + Gemfile.lock | 2 +- README.adoc | 2 +- Rakefile | 158 +++++++++++++++++++++++++++ docs/_config.yml | 12 ++ docs/jekyll/_sass/custom/custom.scss | 74 +++++++++++++ docs/release/0.1.2.adoc | 89 +++++++++++++++ docs/release/drafts/0.1.2.yml | 53 +++++++++ docs/releases.adoc | 28 +++++ 10 files changed, 441 insertions(+), 16 deletions(-) create mode 100644 docs/release/0.1.2.adoc create mode 100644 docs/release/drafts/0.1.2.yml create mode 100644 docs/releases.adoc diff --git a/.config/releasehx.yml b/.config/releasehx.yml index 9cd48ea..e1bdab3 100644 --- a/.config/releasehx.yml +++ b/.config/releasehx.yml @@ -17,10 +17,9 @@ paths: conversions: summ: issue_heading note: issue_body - note_pattern: '/^(((#|=)+ (Draft )?Release Note.*?)|())\n+(?(.| -)+)/gmi' - markup: asciidoc - engine: asciidoctor + note_pattern: | + /^(((#|=)+ (Draft )?Release Note.*?)|())\n+(?(.|)+)/gmi + markup: markdown rhyml: pasterize_summ: true @@ -54,10 +53,14 @@ parts: text: RHYML head: RHYML icon: file-code-o - sgyml: + schemagraphy: text: SchemaGraphy head: SchemaGraphy icon: sitemap + configuration: + text: configuration + head: Configuration + icon: cogs types: label_prefix: "type:" @@ -93,8 +96,9 @@ types: icon: exclamation-circle tags: - _include: ['highlight', 'changelog', 'breaking', 'deprecation', 'experimental'] - _exclude: ['internal', 'wontfix', 'duplicate', 'invalid'] + # Include all tags by default for 0.1.2 (no filtering) + # _include: ['highlight', 'changelog', 'breaking', 'deprecation', 'experimental'] + # _exclude: ['internal', 'wontfix', 'duplicate', 'invalid'] highlight: head: Highlights @@ -116,6 +120,12 @@ tags: icon: flask text: Experimental features + # Pass-through tags for labels not explicitly configured + documentation: + slug: documentation + changelog: + slug: changelog + links: web: https://github.com/DocOps/releasehx/issues/{{ tick }} git: https://github.com/DocOps/releasehx/commit/{{ hash }} @@ -137,7 +147,7 @@ changelog: head: What's Changed text: Summary of all changes in this release. htag: h2 - spot: 2 + spot: 1 sort: - breaking:grouping1 - type:grouping1 @@ -157,14 +167,11 @@ notes: head: Release Notes text: Detailed descriptions of notable changes. htag: h2 - spot: 1 + spot: 2 sort: - - highlight:grouping1 - - breaking:grouping1 - - deprecation:grouping1 - - part:grouping1 + - type:grouping1 items: - frame: unordered + frame: table-cols-1 allow_redundant: true show_issue_links: true metadata_labels: before diff --git a/.gitignore b/.gitignore index 8625b88..24c60d1 100644 --- a/.gitignore +++ b/.gitignore @@ -80,3 +80,7 @@ repomix-output.xml # Local development directories dev/ releasehx-demo/ + +# Release history working directories +docs/release/drafts/ +docs/release/payloads/ diff --git a/Gemfile.lock b/Gemfile.lock index f29368f..c1bc35e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - releasehx (0.1.0) + releasehx (0.1.2) asciidoctor-pdf (~> 2.3) commonmarker (~> 0.23) faraday (~> 2.9) diff --git a/README.adoc b/README.adoc index 150af28..7c41803 100644 --- a/README.adoc +++ b/README.adoc @@ -15,7 +15,7 @@ :this_prod_vrsn_major: 0 :this_prod_vrsn_minor: 1 :this_prod_vrsn_major-minor: {this_prod_vrsn_major}.{this_prod_vrsn_minor} -:this_prod_vrsn_patch: 1 +:this_prod_vrsn_patch: 2 :this_prod_vrsn: {this_prod_vrsn_major-minor}.{this_prod_vrsn_patch} :next_prod_vrsn: 0.2.0 :tagline: Generate formatted release histories from Jira, GitHub, GitLab, YAML, or JSON sources. diff --git a/Rakefile b/Rakefile index 4193efd..fa19df2 100644 --- a/Rakefile +++ b/Rakefile @@ -36,6 +36,7 @@ task :prebuild do require_relative 'lib/releasehx/mcp' ReleaseHx::MCP::AssetPackager.new.package! Sourcerer.generate_manpage('docs/manpage.adoc', 'build/docs/releasehx.1') + generate_release_index end desc 'Build and tag multi-arch Docker image for releasehx' @@ -192,6 +193,104 @@ task :serve do puts "Serving docs at http://localhost:#{port}" end +# ReleaseHx self-dogfooding tasks +namespace :rhx do + # Shared configuration for all rhx tasks + def self.rhx_config + require_relative 'lib/releasehx' + + config_path = '.config/releasehx.yml' + unless File.exist?(config_path) + warn "ERROR: Config file not found: #{config_path}" + exit 1 + end + + config = YAML.safe_load_file(config_path, aliases: true) + [config_path, config] + end + + def self.get_version(args) + args[:version] || extract_version + end + + desc 'Draft a YAML release-history document for the current version' + task :draft, [:version] do |_t, args| + config_path, _config = rhx_config + version = get_version(args) + + puts "Fetching issues for version #{version} from GitHub..." + + # Use ReleaseHx CLI via system call + cmd = "bundle exec bin/rhx #{version} --config #{config_path} --fetch --yaml" + puts "Running: #{cmd}" + success = system(cmd) + + exit 1 unless success + + puts "✓ Successfully fetched and generated draft for version #{version}" + end + + desc 'Append new issues to existing release draft' + task :append, [:version] do |_t, args| + config_path, _config = rhx_config + version = get_version(args) + + puts "Appending new issues for version #{version}..." + + # Use ReleaseHx CLI with --append flag + cmd = "bundle exec bin/rhx #{version} --config #{config_path} --fetch --append" + puts "Running: #{cmd}" + success = system(cmd) + + exit 1 unless success + + puts "✓ Successfully appended new issues to version #{version} draft" + end + + desc 'Publish release notes as AsciiDoc' + task :adoc, [:version] do |_t, args| + config_path, config = rhx_config + version = get_version(args) + + # Infer draft path from config or use default + drafts_dir = config.dig('paths', 'drafts_dir') || 'docs/release/drafts' + yaml_file = File.join(drafts_dir, "#{version}.yml") + + unless File.exist?(yaml_file) + warn "ERROR: Draft not found: #{yaml_file}" + warn "Run 'rake rhx:draft[#{version}]' first to create the draft." + exit 1 + end + + puts "Publishing release notes for version #{version}..." + + # Generate AsciiDoc output + output_file = "docs/release/#{version}.adoc" + cmd = "bundle exec bin/rhx #{yaml_file} --config #{config_path} --adoc #{output_file}" + puts "Running: #{cmd}" + success = system(cmd) + + exit 1 unless success + + puts "✓ Successfully published release notes to #{output_file}" + end + + desc 'Complete workflow: draft, then publish as AsciiDoc' + task :generate, [:version] do |_t, args| + version = get_version(args) + + puts "=== Generating complete release documentation for #{version} ===" + + # Run draft task + Rake::Task['rhx:draft'].invoke(version) + + # Run adoc task + Rake::Task['rhx:adoc'].invoke(version) + + puts "\n✓ Complete! Release documentation generated for version #{version}" + end +end + def extract_version attrs = readme_attrs return attrs['this_prod_vrsn'].strip if attrs['this_prod_vrsn'] @@ -212,3 +311,62 @@ def ensure_buildx_builder sh "docker buildx create --name #{BUILDER_NAME} --driver docker-container --use" sh "docker buildx inspect --builder #{BUILDER_NAME} --bootstrap" end + +def generate_release_index + require 'fileutils' + require 'yaml' + + release_dir = 'docs/release' + output_file = 'build/docs/_release_index.adoc' + + # Ensure output directory exists + FileUtils.mkdir_p(File.dirname(output_file)) + + # Find all release AsciiDoc files (not drafts, not test files) + release_files = Dir.glob("#{release_dir}/*.adoc") + .reject { |f| f.include?('-test') || f.include?('draft') } + .sort + .reverse + + return if release_files.empty? + + # Build the index content + content = [] + content << "== Available Releases" + content << "" + content << "Each release includes detailed notes about new features, improvements, bug fixes, and breaking changes." + content << "" + + # List releases + release_files.each do |file| + version = File.basename(file, '.adoc') + # Try to extract date from the file + date = extract_release_date(file) || 'TBD' + content << "* link:../release/#{version}.html[#{version}] - #{date}" + end + + content << "" + content << "== Latest Release" + content << "" + + # Include the latest release content + if release_files.any? + latest_file = release_files.first + latest_version = File.basename(latest_file, '.adoc') + content << "include::release/#{latest_version}.adoc[leveloffset=+1]" + end + + # Write the file + File.write(output_file, content.join("\n")) + puts "✓ Generated release index: #{output_file}" +end + +def extract_release_date(file) + # Read first 20 lines looking for :page-date: attribute + File.foreach(file).first(20).each do |line| + if line =~ /:page-date:\s+(.+)$/ + return $1.strip + end + end + nil +end diff --git a/docs/_config.yml b/docs/_config.yml index 8515039..74bd12b 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -5,15 +5,27 @@ baseurl: / plugins: - jekyll-asciidoc +collections: + releases: + output: true + permalink: /releases/:name/ + defaults: - scope: path: "api" values: render_with_liquid: false + - scope: + path: "" + type: "releases" + values: + layout: default + nav_exclude: true include: - index.adoc - config-reference.adoc + - releases.adoc exclude: - manpage.adoc diff --git a/docs/jekyll/_sass/custom/custom.scss b/docs/jekyll/_sass/custom/custom.scss index b8cdbd2..db0b6fd 100644 --- a/docs/jekyll/_sass/custom/custom.scss +++ b/docs/jekyll/_sass/custom/custom.scss @@ -53,4 +53,78 @@ h5 { .cl { color: #6367A9; } +} + +/* Release notes styling */ +.release-note { + margin-bottom: 1.5em; + padding: 1em 1.25em; + border-left: 3px solid #7253ed; + background-color: rgba(114, 83, 237, 0.04); + border-radius: 0 4px 4px 0; +} + +.release-note .paragraph:last-child p { + margin-bottom: 0; +} + +.release-note .listingblock { + margin-bottom: 0.5em; +} + +/* Component/part labels styled as badges */ +.rhx-component { + display: inline-block; + padding: 0.1em 0.4em; + margin: 0 0.2em; + font-size: 0.85em; + font-weight: 500; + border-radius: 3px; + background-color: rgba(100, 100, 255, 0.15); + border: 1px solid rgba(100, 100, 255, 0.3); +} + +/* Type labels styled as badges */ +.rhx-type { + display: inline-block; + padding: 0.1em 0.5em; + margin: 0 0.3em; + font-size: 0.85em; + font-weight: 600; + border-radius: 3px; +} + +.rhx-type-bug { + background-color: rgba(255, 100, 100, 0.15); + border: 1px solid rgba(255, 100, 100, 0.4); + color: #ff6b6b; +} + +.rhx-type-feature { + background-color: rgba(100, 200, 100, 0.15); + border: 1px solid rgba(100, 200, 100, 0.4); + color: #69db7c; +} + +.rhx-type-improvement { + background-color: rgba(100, 180, 255, 0.15); + border: 1px solid rgba(100, 180, 255, 0.4); + color: #74c0fc; +} + +.rhx-type-documentation { + background-color: rgba(200, 150, 255, 0.15); + border: 1px solid rgba(200, 150, 255, 0.4); + color: #da77f2; +} + +.rhx-type-deprecation { + background-color: rgba(255, 200, 100, 0.15); + border: 1px solid rgba(255, 200, 100, 0.4); + color: #ffc078; +} + +/* Icon spacing in metadata */ +.meta-icon { + margin-right: 0.2em; } \ No newline at end of file diff --git a/docs/release/0.1.2.adoc b/docs/release/0.1.2.adoc new file mode 100644 index 0000000..7b92403 --- /dev/null +++ b/docs/release/0.1.2.adoc @@ -0,0 +1,89 @@ +:icons: font + +:page-title: Release History for 0.1.2 +:page-version: 0.1.2 +:page-date: 2026-01-29 + += Release History -- 0.1.2 - 2026-01-29 + + +== What's Changed + + +Summary of all changes in this release. + + +=== Added + + +* Established an instance of ReleaseHx for managing the release history of... ReleaseHx + + +xref:note-0_1_2-30[NOTE] + + +=== Fixed + + +* The documented regexp format (/pattern/flags) is unsupported + + +xref:note-0_1_2-32[NOTE] + + +* Config property mismatch: code reads `note_source` but docs specify `note` + + +xref:note-0_1_2-28[NOTE] + + +* Formatting errors in AsciiDoc templates + + +xref:note-0_1_2-36[NOTE] + + +== Release Notes + + +Detailed descriptions of notable changes. + + +=== Added + +[.release-note] +-- +The ReleaseHx website now hosts a rich-text roster of change reports built with ReleaseHx itself at https://releasehx.docopslab.org/docs/releases/. +The output is configured in `.config/releasehx.yml`, and the process is documented in `README.adoc`. + +-- + + +=== Fixed + +[.release-note] +-- +Regular expressions in YAML files such as the releasehx application config now support being written as fully qualified strings with the pattern fenced in `/` markers. +Use `/pattern/flags` formats such as the following and expect proper parsing. + +[,yaml] +---- + note_pattern: /^((#+ Draft Release Note.*?)\n+(?(.|)+)/gmi +---- + +-- + + +[.release-note] +-- +Added support for a proper configuration property for release-note extraction, bringing the product into line with the documented config. +The effective property was never documented, so it has been removed, but no deprecation was deemed necessary. +Backward compatibility has been sacrificed in this rare case, since the functionality was obscured. + +-- + + +[.release-note] +-- +AsciiDoc templates have been cleaned up and streamlined significantly, mostly by removing the clumsy metadata that was hard to style in rich-text output. +We will improve on these templates later and welcome contributions cleaning them up. + +-- + + diff --git a/docs/release/drafts/0.1.2.yml b/docs/release/drafts/0.1.2.yml new file mode 100644 index 0000000..9a84a7d --- /dev/null +++ b/docs/release/drafts/0.1.2.yml @@ -0,0 +1,53 @@ +code: "0.1.2" +date: 2026-01-29 +memo: +changes: + + - chid: 0_1_2-30 + tick: 30 + type: feature + part: docs + summ: | + Established an instance of ReleaseHx for managing the release history of... ReleaseHx + note: | + The ReleaseHx website now hosts a rich-text roster of change reports built with ReleaseHx itself at https://releasehx.docopslab.org/docs/releases/. The output is configured in `.config/releasehx.yml`, and the process is documented in `README.adoc`. + tags: + - documentation + + - chid: 0_1_2-32 + tick: 32 + type: bug + parts: + - configuration + - schemagraphy + summ: | + The documented regexp format (/pattern/flags) is unsupported + note: | + Regular expressions in YAML files such as the releasehx application config now support being written as fully qualified strings with the pattern fenced in `/` markers. Use `/pattern/flags` formats such as the following and expect proper parsing. + + ```yaml + note_pattern: /^((#+ Draft Release Note.*?)\n+(?(.|)+)/gmi + ``` + + - chid: 0_1_2-28 + tick: 28 + type: bug + parts: + - configuration + - rhyml + summ: | + Config property mismatch: code reads `note_source` but docs specify `note` + note: | + Added support for a proper configuration property for release-note extraction, bringing the product into line with the documented config. + The effective property was never documented, so it has been removed, but no deprecation was deemed necessary. + Backward compatibility has been sacrificed in this rare case, since the functionality was obscured. + lead: briandominick + + - chid: 0_1_2-36 + tick: 36 + type: bug + part: templates + summ: | + Formatting errors in AsciiDoc templates + note: | + AsciiDoc templates have been cleaned up and streamlined significantly, mostly by removing the clumsy metadata that was hard to style in rich-text output. We will improve on these templates later and welcome contributions cleaning them up. diff --git a/docs/releases.adoc b/docs/releases.adoc new file mode 100644 index 0000000..bb408cd --- /dev/null +++ b/docs/releases.adoc @@ -0,0 +1,28 @@ +--- +layout: default +title: Releases +nav_order: 90 +permalink: /releases/ +--- += Release History +:page-layout: default +:page-title: Releases +:page-nav_order: 90 +:page-permalink: /releases/ + +Complete release history for ReleaseHx, generated using ReleaseHx itself. + +ifdef::env-site[] +// Generated during prebuild - includes release index and content +include::_release_index.adoc[] +endif::[] + +ifndef::env-site[] +== Development Mode + +Release history is generated during the prebuild process. Run `bundle exec rake prebuild` to generate the full release index. +endif::[] + +--- + +For more information about ReleaseHx, see the link:/[main documentation]. From 2755d66e888538a16902a9b473c09538ac82f2ad Mon Sep 17 00:00:00 2001 From: Brian Dominick Date: Thu, 29 Jan 2026 19:56:48 -0500 Subject: [PATCH 4/7] fix: prioritize file path argument over API fetch (#33) Fixes #33 --- lib/releasehx/cli.rb | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/lib/releasehx/cli.rb b/lib/releasehx/cli.rb index 09028ae..c790d6d 100644 --- a/lib/releasehx/cli.rb +++ b/lib/releasehx/cli.rb @@ -688,23 +688,32 @@ def enrich_direct_from_source source_path, version end def create_rhyml_from_source source_path, version - # Determine source type from configuration, not just file extension - configured_source_type = @settings.dig('origin', 'source') || 'json' - - # Handle different source types based on configuration - case configured_source_type - when 'rhyml' + # First check if source_path is actually a file (overrides config) + if version_or_file(source_path) == :file && File.exist?(source_path) # Load RHYML data directly from YAML file + ReleaseHx.logger.debug "Loading RHYML from file: #{source_path}" if options[:verbose] rhyml_data = SchemaGraphy::Loader.load_yaml_with_tags(source_path) release_data = rhyml_data['releases'] ? rhyml_data['releases'].first : rhyml_data # Convert hash keys to keyword arguments for Release constructor - ReleaseHx::RHYML::Release.new( + return ReleaseHx::RHYML::Release.new( code: release_data['code'] || version, date: release_data['date'], hash: release_data['hash'], memo: release_data['memo'], changes: release_data['changes'] || []) + end + + # Determine source type from configuration + configured_source_type = @settings.dig('origin', 'source') || 'json' + + # Handle different source types based on configuration + case configured_source_type + when 'rhyml' + # Config says rhyml but source_path is not a file - error + raise Thor::Error, + "ERROR: origin.source is 'rhyml' but no YAML file provided. " \ + 'Specify a YAML file path as the first argument.' when 'json' # For json type, only use local files (never API calls) if options[:api_data] From 6b9ebb202c463035fa348c4469291b983469493a Mon Sep 17 00:00:00 2001 From: Brian Dominick Date: Thu, 29 Jan 2026 19:58:40 -0500 Subject: [PATCH 5/7] fix: simplify AsciiDoc/Markdown templates (#36) - Simplified entry templates to show only summary + optional NOTE link - Simplified note templates to use single open block format with .release-note class - Removed complex metadata framing (open/sidebar/example blocks) - Fixed adapter to preserve original content on RegexpError (don't lose data due to bad config) - Updated adapter tests to properly test note extraction with Release Notes header - Corrected GitHub mapping: type.name instead of issue_type.name, added downcasing - Updated config default: "Component" instead of "Part" for better terminology Fixes #36 --- lib/releasehx/rhyml/adapter.rb | 2 +- lib/releasehx/rhyml/mappings/github.yaml | 4 +- .../rhyml/templates/entry.adoc.liquid | 10 +-- lib/releasehx/rhyml/templates/entry.md.liquid | 7 +- .../templates/metadata-entry.adoc.liquid | 83 ++++++++----------- .../rhyml/templates/metadata-note.adoc.liquid | 83 ++++++++----------- .../rhyml/templates/note.adoc.liquid | 42 +--------- lib/releasehx/rhyml/templates/note.md.liquid | 16 ++-- .../rhyml/templates/parts-listing.liquid | 12 +-- .../rhyml/templates/rhyml-change.yaml.liquid | 3 +- specs/data/config-def.yml | 2 +- specs/tests/rspec/rhyml/adapter_spec.rb | 4 +- 12 files changed, 102 insertions(+), 166 deletions(-) diff --git a/lib/releasehx/rhyml/adapter.rb b/lib/releasehx/rhyml/adapter.rb index 5acea7f..2c05fda 100644 --- a/lib/releasehx/rhyml/adapter.rb +++ b/lib/releasehx/rhyml/adapter.rb @@ -432,7 +432,7 @@ def extract_note! data, note_source, note_pattern end rescue RegexpError => e ReleaseHx.logger.warn "Invalid note_pattern '#{note_pattern}': #{e.message}" - data['note'] = nil # Clear note on pattern error + # Preserve original content on pattern error - don't lose data due to bad config end end diff --git a/lib/releasehx/rhyml/mappings/github.yaml b/lib/releasehx/rhyml/mappings/github.yaml index 537acc6..f5fe4d7 100644 --- a/lib/releasehx/rhyml/mappings/github.yaml +++ b/lib/releasehx/rhyml/mappings/github.yaml @@ -25,7 +25,9 @@ note: # Extract type from the native GitHub Issues type field (modern approach) type: - path: "issue_type.name" + path: "type.name" + ruby: | + path&.downcase # Derive `parts` from labels using direct key matching or slug override parts: diff --git a/lib/releasehx/rhyml/templates/entry.adoc.liquid b/lib/releasehx/rhyml/templates/entry.adoc.liquid index 93bb160..278a88e 100644 --- a/lib/releasehx/rhyml/templates/entry.adoc.liquid +++ b/lib/releasehx/rhyml/templates/entry.adoc.liquid @@ -1,4 +1,3 @@ -{%- embed metadata-entry.adoc.liquid -%} {%- assign frame = content_config.items.frame %} {%- assign summ = change.summ %} {%- case frame %} @@ -17,10 +16,7 @@ [start={{ item_count }}] {%- endif %} {{ bullet -}} -{{ change.summ | trim }} + -{%- if change_metadata != "" -%} -{{ change_metadata | trim }} -{%- endif %} -{%- if change.note %} -xref:note-{{ change.chid }}[icon:sticky-note[]NOTE] +{{ change.summ | trim }} +{%- if change.note %} + +xref:note-{{ change.chid }}[NOTE] {%- endif %} diff --git a/lib/releasehx/rhyml/templates/entry.md.liquid b/lib/releasehx/rhyml/templates/entry.md.liquid index e1849fd..f121f62 100644 --- a/lib/releasehx/rhyml/templates/entry.md.liquid +++ b/lib/releasehx/rhyml/templates/entry.md.liquid @@ -1,4 +1,3 @@ -{%- embed metadata-entry.md.liquid -%} {%- assign frame = content_config.items.frame | default: "unordered" %} {%- assign summ = change.summ %} {%- case frame %} @@ -14,12 +13,12 @@ {%- if frame == "basic" %} -{{ bullet }}{{ change.summ | trim }}{% if change_metadata != "" %} ({{ change_metadata | trim | replace: " | ", ", " }}){% endif %}{% if change.note and change.note != "" %} [NOTE](#note-{{ change.chid }}){% endif %} +{{ bullet }}{{ change.summ | trim }}{% if change.note and change.note != "" %} [NOTE](#note-{{ change.chid }}){% endif %} {%- elsif frame == "paragraph" %} -{{ change.summ | trim }}{% if change_metadata != "" %} ({{ change_metadata | trim }}){% endif %}{% if change.note and change.note != "" %} [NOTE](#note-{{ change.chid }}){% endif %} +{{ change.summ | trim }}{% if change.note and change.note != "" %} [NOTE](#note-{{ change.chid }}){% endif %} {%- else %} -{{ bullet }}{{ change.summ | trim }}{% if change_metadata != "" %} ({{ change_metadata | trim }}){% endif %}{% if change.note and change.note != "" %} [NOTE](#note-{{ change.chid }}){% endif %} +{{ bullet }}{{ change.summ | trim }}{% if change.note and change.note != "" %} [NOTE](#note-{{ change.chid }}){% endif %} {%- endif %} diff --git a/lib/releasehx/rhyml/templates/metadata-entry.adoc.liquid b/lib/releasehx/rhyml/templates/metadata-entry.adoc.liquid index a04b8cb..d6b2fe6 100644 --- a/lib/releasehx/rhyml/templates/metadata-entry.adoc.liquid +++ b/lib/releasehx/rhyml/templates/metadata-entry.adoc.liquid @@ -4,53 +4,42 @@ {%- assign format = "asciidoc" %} {%- embed tags-listing.liquid %} {%- embed parts-listing.liquid %} -{%- capture change_metadata %} -{%- if parts_listing != "" and entry_show_parts_label %} -{{- parts_listing | trim }} -{%- elsif change.parts and change.parts.size > 0 and entry_show_parts_label == false %} -{%- for part in change.parts %} -{%- unless part == "changelog" or part == "release_note_needed" %} -{{ config.parts[part]['text'] | default: part }} -{%- endunless %} -{%- endfor %} -{%- endif %} -{%- if change.type %} -{%- assign type_config = config.types[change.type] %} -{%- if entry_show_type_label %} -[.meta-label.type-label]*{{ labeling_type_label }}:* -{%- endif %} -{%- if type_config.icon and show_icons and show_icons == "before" %} -icon:{{ type_config.icon | default: 'tag' }}[role=meta-icon] -{%- endif %} -{{ type_config.text | default: change.type }} -{%- if type_config.icon and show_icons and show_icons == "after" %} -icon:{{ type_config.icon | default: 'tag' }}[role=meta-icon] -{%- endif %} -{%- endif %} -{%- if tags_listing != "" and entry_show_tags_label %} -{{- tags_listing | trim }} -{%- elsif change.tags and change.tags.size > 0 and entry_show_tags_label == false %} -{%- for tag in change.tags %} -{%- unless tag == "changelog" or tag == "release_note_needed" %} -{{ config.tags[tag]['text'] | default: tag }} -{%- endunless %} -{%- endfor %} -{%- endif %} -{%- if entry_show_lead and change.lead %} -{%- if entry_show_lead_label %} -[.meta-label.lead-label]*{{ labeling_lead_label }}:* -{%- endif %} -{%- if entry_user_link_template %} -link:{{ entry_user_link_template | render: change }}[icon:user[]{{ change.lead }}] -{%- else %} -icon:user[]{{ change.lead }} -{%- endif %} -{%- endif %} -{%- if config.links.web.href and config.links.web.href != "" %} -link:{{ config.links.web.href | render: change }}[icon:{{ config.links.web.icon }}[]{{ config.links.web.text | render: change }}] +{%- capture change_metadata -%} +{%- if parts_listing != "" and entry_show_parts_label -%} +{{ parts_listing | trim }} {% endif -%} +{%- if change.parts and change.parts.size > 0 and entry_show_parts_label == false -%} +{%- for part in change.parts -%} +{%- unless part == "changelog" or part == "release_note_needed" -%} +{{ config.parts[part]['text'] | default: part }} {% endunless -%} +{%- endfor -%} {%- endif -%} -{%- if entry_show_git_links and config.links.git.href and config.links.git.href != "" %} -link:{{ config.links.git.href | render: change }}[icon:{{ config.links.git.icon | default: 'code-fork' }}[]{{ change.hash | slice: 0, 7 }}] -{%- endif %} +{%- if change.type -%} +{%- assign type_config = config.types[change.type] -%} +{%- if entry_show_type_label -%} +**{{ labeling_type_label }}:** {% endif -%} +{%- if type_config.icon and show_icons and show_icons == "before" -%} +icon:{{ type_config.icon | default: 'tag' }}[role=meta-icon]{% endif -%} +{{ type_config.text | default: change.type }} {% if type_config.icon and show_icons and show_icons == "after" -%} +icon:{{ type_config.icon | default: 'tag' }}[role=meta-icon]{% endif -%} +{%- endif -%} +{%- if tags_listing != "" and entry_show_tags_label -%} +{{ tags_listing | trim }} {% endif -%} +{%- if change.tags and change.tags.size > 0 and entry_show_tags_label == false -%} +{%- for tag in change.tags -%} +{%- unless tag == "changelog" or tag == "release_note_needed" -%} +{{ config.tags[tag]['text'] | default: tag }} {% endunless -%} +{%- endfor -%} +{%- endif -%} +{%- if entry_show_lead and change.lead -%} +{%- if entry_show_lead_label -%} +**{{ labeling_lead_label }}:** {% endif -%} +{%- if entry_user_link_template -%} +link:{{ entry_user_link_template | render: change }}[icon:user[]{{ change.lead }}] {% else -%} +icon:user[]{{ change.lead }} {% endif -%} +{%- endif -%} +{%- if config.links.web.href and config.links.web.href != "" -%} +link:{{ config.links.web.href | render: change }}[icon:{{ config.links.web.icon }}[]{{ config.links.web.text | render: change }}] {% endif -%} +{%- if entry_show_git_links and config.links.git.href and config.links.git.href != "" -%} +link:{{ config.links.git.href | render: change }}[icon:{{ config.links.git.icon | default: 'code-fork' }}[]{{ change.hash | slice: 0, 7 }}] {% endif -%} {%- endcapture %} {%- assign catch_metadata_error = change_metadata %} diff --git a/lib/releasehx/rhyml/templates/metadata-note.adoc.liquid b/lib/releasehx/rhyml/templates/metadata-note.adoc.liquid index 0f0477c..b9b43cc 100644 --- a/lib/releasehx/rhyml/templates/metadata-note.adoc.liquid +++ b/lib/releasehx/rhyml/templates/metadata-note.adoc.liquid @@ -4,53 +4,42 @@ {%- assign format = "asciidoc" %} {%- embed tags-listing.liquid %} {%- embed parts-listing.liquid %} -{%- capture change_metadata %} -{%- if parts_listing != "" and note_show_parts_label %} -{{- parts_listing | trim }} -{%- elsif change.parts and change.parts.size > 0 and note_show_parts_label == false %} -{%- for part in change.parts %} -{%- unless part == "changelog" or part == "release_note_needed" %} -{{ config.parts[part]['text'] | default: part }} -{%- endunless %} -{%- endfor %} -{%- endif %} -{%- if change.type %} -{%- assign type_config = config.types[change.type] %} -{%- if note_show_type_label %} -[.meta-label.type-label]*{{ labeling_type_label }}:* -{%- endif %} -{%- if type_config.icon and show_icons and show_icons == "before" %} -icon:{{ type_config.icon | default: 'tag' }}[role=meta-icon] -{%- endif %} -{{ type_config.text | default: change.type }} -{%- if type_config.icon and show_icons and show_icons == "after" %} -icon:{{ type_config.icon | default: 'tag' }}[role=meta-icon] -{%- endif %} -{%- endif %} -{%- if tags_listing != "" and note_show_tags_label %} -{{- tags_listing | trim }} -{%- elsif change.tags and change.tags.size > 0 and note_show_tags_label == false %} -{%- for tag in change.tags %} -{%- unless tag == "changelog" or tag == "release_note_needed" %} -{{ config.tags[tag]['text'] | default: tag }} -{%- endunless %} -{%- endfor %} -{%- endif %} -{%- if note_show_lead and change.lead %} -{%- if note_show_lead_label %} -[.meta-label.lead-label]*{{ labeling_lead_label }}:* -{%- endif %} -{%- if note_user_link_template %} -link:{{ note_user_link_template | render: change }}[icon:user[]{{ change.lead }}] -{%- else %} -icon:user[]{{ change.lead }} -{%- endif %} -{%- endif %} -{%- if config.links.web.href and config.links.web.href != "" %} -link:{{ config.links.web.href | render: change }}[icon:{{ config.links.web.icon }}[]{{ config.links.web.text | render: change }}] +{%- capture change_metadata -%} +{%- if parts_listing != "" and note_show_parts_label -%} +{{ parts_listing | trim }} {% endif -%} +{%- if change.parts and change.parts.size > 0 and note_show_parts_label == false -%} +{%- for part in change.parts -%} +{%- unless part == "changelog" or part == "release_note_needed" -%} +{{ config.parts[part]['text'] | default: part }} {% endunless -%} +{%- endfor -%} {%- endif -%} -{%- if note_show_git_links and config.links.git.href and config.links.git.href != "" %} -link:{{ config.links.git.href | render: change }}[icon:{{ config.links.git.icon | default: 'code-fork' }}[]{{ change.hash | slice: 0, 7 }}] -{%- endif %} +{%- if change.type -%} +{%- assign type_config = config.types[change.type] -%} +{%- if note_show_type_label -%} +**{{ labeling_type_label }}:** {% endif -%} +{%- if type_config.icon and show_icons and show_icons == "before" -%} +icon:{{ type_config.icon | default: 'tag' }}[role=meta-icon]{% endif -%} +{{ type_config.text | default: change.type }} {% if type_config.icon and show_icons and show_icons == "after" -%} +icon:{{ type_config.icon | default: 'tag' }}[role=meta-icon]{% endif -%} +{%- endif -%} +{%- if tags_listing != "" and note_show_tags_label -%} +{{ tags_listing | trim }} {% endif -%} +{%- if change.tags and change.tags.size > 0 and note_show_tags_label == false -%} +{%- for tag in change.tags -%} +{%- unless tag == "changelog" or tag == "release_note_needed" -%} +{{ config.tags[tag]['text'] | default: tag }} {% endunless -%} +{%- endfor -%} +{%- endif -%} +{%- if note_show_lead and change.lead -%} +{%- if note_show_lead_label -%} +**{{ labeling_lead_label }}:** {% endif -%} +{%- if note_user_link_template -%} +link:{{ note_user_link_template | render: change }}[icon:user[]{{ change.lead }}] {% else -%} +icon:user[]{{ change.lead }} {% endif -%} +{%- endif -%} +{%- if config.links.web.href and config.links.web.href != "" -%} +link:{{ config.links.web.href | render: change }}[icon:{{ config.links.web.icon }}[]{{ config.links.web.text | render: change }}] {% endif -%} +{%- if note_show_git_links and config.links.git.href and config.links.git.href != "" -%} +link:{{ config.links.git.href | render: change }}[icon:{{ config.links.git.icon | default: 'code-fork' }}[]{{ change.hash | slice: 0, 7 }}] {% endif -%} {%- endcapture %} {%- assign catch_metadata_error = change_metadata %} diff --git a/lib/releasehx/rhyml/templates/note.adoc.liquid b/lib/releasehx/rhyml/templates/note.adoc.liquid index a1ef955..7554b4c 100644 --- a/lib/releasehx/rhyml/templates/note.adoc.liquid +++ b/lib/releasehx/rhyml/templates/note.adoc.liquid @@ -3,50 +3,12 @@ {%- else %} {%- assign change_note = change.note | default: "NO RELEASE NOTE PROVIDED" | trim %} {%- endif %} -{%- include metadata-note.adoc.liquid %} {%- unless changes_listed contains change.chid %} [[note-{{ change.chid }}]] {%- endunless %} [.release-note] -{%- if config.notes.items.frame == "table-cols-1" %} -|=== -a| {{ change_metadata }} + -{%- if change.head %} -*{{ change.head }}* + -{%- endif %} +-- {{ change_note }} -|=== -{%- elsif config.notes.items.frame == "table-cols-2" %} -[cols="5,2"] -|=== -{%- if change.head %} -2+a| *{{ change.head }}* -{%- endif %} -a| {{ change_note }} -a| {{ change_metadata }} -|=== -{%- elsif config.notes.items.frame == "desc-list" %} -{{ change.head }}:: -{{ change_note }} + -{{ change_metadata }} -{%- elsif config.notes.items.frame == "admonition" %} -{%- if change.type == "removal" or change.type == "deprecation" or change.type == "breaking" %} -{%- assign admonition_type = "WARNING" %} -{%- elsif change.type == "security" %} -{%- assign admonition_type = "IMPORTANT" %} -{%- elsif change.type == "experimental" %} -{%- assign admonition_type = "TIP" %} -{%- else %} -{%- assign admonition_type = "NOTE" %} -{%- endif %} -[{{ admonition_type }}] -{%- if change.head %} -.{{ change.head }} -{%- endif %} -==== -{{ change_note }} + -{{ change_metadata }} -==== -{%- endif %} +-- diff --git a/lib/releasehx/rhyml/templates/note.md.liquid b/lib/releasehx/rhyml/templates/note.md.liquid index 58b1c08..a71e5d0 100644 --- a/lib/releasehx/rhyml/templates/note.md.liquid +++ b/lib/releasehx/rhyml/templates/note.md.liquid @@ -3,17 +3,15 @@ {% else -%} {% assign change_note = change.note | default: "NO RELEASE NOTE PROVIDED" | adoc_to_md | trim -%} {% endif -%} -{% embed metadata-note.md.liquid -%} {%- if config.notes.items.frame == "table" %} -| Change | Details | -|--------|---------| -| {{ change_metadata }} | {% if change.head %}**{{ change.head }}**
{% endif %}{{ change_note }} | +| Details | +|---------| +| {% if change.head %}**{{ change.head }}**
{% endif %}{{ change_note }} | {%- elsif config.notes.items.frame == "desc-list" %} -**{{ change.head }}** -{{ change_note }} -*{{ change_metadata }}* +**{{ change.head | default: change.summ }}** +{{ change_note }} {% elsif config.notes.items.frame == "admonition" %} {% if change.type == "removal" or change.type == "deprecation" or change.type == "breaking" %} {% assign admonition_type = "Warning" %} @@ -25,13 +23,11 @@ {% assign admonition_type = "Note" %} {% endif %} -> **{{ admonition_type }}**: {% if change.head %}**{{ change.head }}** - {% endif %}{{ change_note }} -> {{ change_metadata }} +> **{{ admonition_type }}**: {% if change.head %}**{{ change.head }}** - {% endif %}{{ change_note }} {% else -%} {% if change.head -%} ### {{ change.head }} {% endif -%} {{ change_note }} -{{- change_metadata }} {% endif %} diff --git a/lib/releasehx/rhyml/templates/parts-listing.liquid b/lib/releasehx/rhyml/templates/parts-listing.liquid index 87024b1..c384c4d 100644 --- a/lib/releasehx/rhyml/templates/parts-listing.liquid +++ b/lib/releasehx/rhyml/templates/parts-listing.liquid @@ -19,10 +19,10 @@ {%- if show_labels -%} {%- if format == "asciidoc" -%} {%- if labeling_singularize_labels and parts_count == 1 -%} -[.meta-label.parts-label]*{{ labeling_part_label }}:*{%- else -%}[.meta-label.parts-label]*{{ labeling_parts_label }}:*{%- endif -%} +**{{ labeling_part_label }}:** {% else -%}**{{ labeling_parts_label }}:** {% endif -%} {%- elsif format == "markdown" -%} {%- if labeling_singularize_labels and parts_count == 1 -%} -{{ labeling_part_label }}: {%- else -%}{{ labeling_parts_label }}: {%- endif -%} +{{ labeling_part_label }}: {% else -%}{{ labeling_parts_label }}: {% endif -%} {%- endif -%} {%- endif -%} {%- assign part_texts = "" | split: "," -%} @@ -38,10 +38,10 @@ {%- unless skip_part -%} {%- capture part_text -%} {%- if config.parts[part].icon and show_icons and show_icons == "before" -%} -{%- if format == "asciidoc" -%}icon:{{ config.parts[part].icon }}[] {%- endif -%} +{%- if format == "asciidoc" -%}icon:{{ config.parts[part].icon }}[]{%- endif -%} {%- endif -%} {%- if format == "asciidoc" -%} -{{ config.parts[part]['text'] | default: part }}{%- elsif format == "markdown" -%}**{{ config.parts[part]['text'] | default: part }}**{%- endif -%} +{{ config.parts[part]['head'] | default: config.parts[part]['text'] | default: part }}{%- elsif format == "markdown" -%}**{{ config.parts[part]['head'] | default: config.parts[part]['text'] | default: part }}**{%- endif -%} {%- if config.parts[part].icon and show_icons and show_icons == "after" -%} {%- if format == "asciidoc" -%} icon:{{ config.parts[part].icon }}[]{%- endif -%} {%- endif -%} @@ -52,10 +52,10 @@ {%- if part_texts.size > 0 -%} {%- if format == "asciidoc" -%} {%- for part_text in part_texts -%} -{{ part_text }}{%- unless forloop.last %} {%- endunless -%} +{{ part_text }}{%- unless forloop.last %}, {% endunless -%} {%- endfor -%} {%- elsif format == "markdown" -%} -{{ part_texts | join: ", " }}{%- endif -%} +{{ part_texts | join: ", " }}{% endif -%} {%- endif -%} {%- endcapture -%} {%- endif -%} diff --git a/lib/releasehx/rhyml/templates/rhyml-change.yaml.liquid b/lib/releasehx/rhyml/templates/rhyml-change.yaml.liquid index 70232cf..feed26a 100644 --- a/lib/releasehx/rhyml/templates/rhyml-change.yaml.liquid +++ b/lib/releasehx/rhyml/templates/rhyml-change.yaml.liquid @@ -20,7 +20,8 @@ {%- if change.hash %} hash: {{ change.hash }} {%- endif %} - summ: {{ change.summ }} + summ: | + {{ change.summ }} {%- if change.head %} head: {{ change.head }} {%- endif %} diff --git a/specs/data/config-def.yml b/specs/data/config-def.yml index b921103..2e85683 100644 --- a/specs/data/config-def.yml +++ b/specs/data/config-def.yml @@ -1164,7 +1164,7 @@ properties: The label to use for the _singular_ part/component affected by the change, when only one part is permitted. This value will apply either when <> is set to `1` or when the change has only one part _and_ <> is `true`. - dflt: Part + dflt: Component parts_icon: type: String desc: | diff --git a/specs/tests/rspec/rhyml/adapter_spec.rb b/specs/tests/rspec/rhyml/adapter_spec.rb index f584af5..4563882 100644 --- a/specs/tests/rspec/rhyml/adapter_spec.rb +++ b/specs/tests/rspec/rhyml/adapter_spec.rb @@ -50,7 +50,9 @@ end it 'extracts head from note content' do - data['note'] = "## Important Change\nThis is the content" + # Note content must match the note_pattern first (contains "## Release Notes") + # Then head_pattern extracts the heading from the extracted content + data['note'] = "## Release Notes\n## Important Change\nThis is the content\n## Another Section" processed = adapter.send(:postprocess, data.dup) expect(processed['head']).to eq('Important Change') expect(processed['note']).to eq('This is the content') From cd83598a06cfe1fdeb637b00bf8a18b9f442597c Mon Sep 17 00:00:00 2001 From: Brian Dominick Date: Thu, 29 Jan 2026 22:21:02 -0500 Subject: [PATCH 6/7] fix: align all docs URLs under /docs/ path (#27) - Set baseurl to / and use explicit /docs/ prefixes in permalinks - Landing page at /, main docs at /docs/ - API docs at /docs/api/, releases at /docs/releases/ - Update YARD output to build/docs/docs/api/ - Fix YARD index files: rename _index.html to index.html - Add jekyll/, payloads/, release/, yard/ to exclude list - Add jekyll-redirect-from plugin for old URL redirects - Add config-reference.adoc front matter generation to build script - Remove unused docs/Gemfile.lock and FontAwesome includes - Add redirect_from to moved pages --- Gemfile | 1 + Gemfile.lock | 3 + README.adoc | 3 +- docs/Gemfile.lock | 95 ------------------- docs/_config.yml | 10 +- docs/landing.adoc | 10 ++ docs/releases.adoc | 6 +- docs/sample-config.adoc | 2 + .../cfgyml/config-reference.adoc.liquid | 4 - scripts/build_docs.rb | 39 +++++++- 10 files changed, 65 insertions(+), 108 deletions(-) delete mode 100644 docs/Gemfile.lock diff --git a/Gemfile b/Gemfile index ee60260..76f9318 100644 --- a/Gemfile +++ b/Gemfile @@ -19,4 +19,5 @@ group :documentation do gem 'jekyll-asciidoc' gem 'just-the-docs' gem 'yard' + gem 'jekyll-redirect-from' end diff --git a/Gemfile.lock b/Gemfile.lock index c1bc35e..f4a85b4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -188,6 +188,8 @@ GEM jekyll (>= 3.0.0) jekyll-include-cache (0.2.1) jekyll (>= 3.7, < 5.0) + jekyll-redirect-from (0.16.0) + jekyll (>= 3.3, < 5.0) jekyll-sass-converter (3.1.0) sass-embedded (~> 1.75) jekyll-seo-tag (2.8.0) @@ -370,6 +372,7 @@ DEPENDENCIES docopslab-dev jekyll jekyll-asciidoc + jekyll-redirect-from just-the-docs releasehx! rspec (~> 3.0) diff --git a/README.adoc b/README.adoc index 7c41803..39ec0a6 100644 --- a/README.adoc +++ b/README.adoc @@ -1,5 +1,6 @@ :page-layout: default -:page-permalink: /docs +:page-permalink: /docs/ +:page-title: ReleaseHx Docs :page-nav_order: 1 [[releasehx]] = ReleaseHx diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock deleted file mode 100644 index 692d94c..0000000 --- a/docs/Gemfile.lock +++ /dev/null @@ -1,95 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - addressable (2.8.7) - public_suffix (>= 2.0.2, < 7.0) - asciidoctor (2.0.23) - base64 (0.3.0) - bigdecimal (3.2.3) - colorator (1.1.0) - concurrent-ruby (1.3.5) - csv (3.3.5) - em-websocket (0.5.3) - eventmachine (>= 0.12.9) - http_parser.rb (~> 0) - eventmachine (1.2.7) - ffi (1.17.2-x86_64-linux-gnu) - forwardable-extended (2.6.0) - google-protobuf (4.32.1-x86_64-linux-gnu) - bigdecimal - rake (>= 13) - http_parser.rb (0.8.0) - i18n (1.14.7) - concurrent-ruby (~> 1.0) - jekyll (4.4.1) - addressable (~> 2.4) - base64 (~> 0.2) - colorator (~> 1.0) - csv (~> 3.0) - em-websocket (~> 0.5) - i18n (~> 1.0) - jekyll-sass-converter (>= 2.0, < 4.0) - jekyll-watch (~> 2.0) - json (~> 2.6) - kramdown (~> 2.3, >= 2.3.1) - kramdown-parser-gfm (~> 1.0) - liquid (~> 4.0) - mercenary (~> 0.3, >= 0.3.6) - pathutil (~> 0.9) - rouge (>= 3.0, < 5.0) - safe_yaml (~> 1.0) - terminal-table (>= 1.8, < 4.0) - webrick (~> 1.7) - jekyll-asciidoc (3.0.1) - asciidoctor (>= 1.5.0, < 3.0.0) - jekyll (>= 3.0.0) - jekyll-include-cache (0.2.1) - jekyll (>= 3.7, < 5.0) - jekyll-sass-converter (3.1.0) - sass-embedded (~> 1.75) - jekyll-seo-tag (2.8.0) - jekyll (>= 3.8, < 5.0) - jekyll-watch (2.2.1) - listen (~> 3.0) - json (2.15.0) - just-the-docs (0.10.1) - jekyll (>= 3.8.5) - jekyll-include-cache - jekyll-seo-tag (>= 2.0) - rake (>= 12.3.1) - kramdown (2.5.1) - rexml (>= 3.3.9) - kramdown-parser-gfm (1.1.0) - kramdown (~> 2.0) - liquid (4.0.4) - listen (3.9.0) - rb-fsevent (~> 0.10, >= 0.10.3) - rb-inotify (~> 0.9, >= 0.9.10) - mercenary (0.4.0) - pathutil (0.16.2) - forwardable-extended (~> 2.6) - public_suffix (6.0.2) - rake (13.3.0) - rb-fsevent (0.11.2) - rb-inotify (0.11.1) - ffi (~> 1.0) - rexml (3.4.4) - rouge (4.6.1) - safe_yaml (1.0.5) - sass-embedded (1.93.2-x86_64-linux-gnu) - google-protobuf (~> 4.31) - terminal-table (3.0.2) - unicode-display_width (>= 1.1.1, < 3) - unicode-display_width (2.6.0) - webrick (1.9.1) - -PLATFORMS - x86_64-linux - -DEPENDENCIES - jekyll - jekyll-asciidoc - just-the-docs - -BUNDLED WITH - 2.4.19 diff --git a/docs/_config.yml b/docs/_config.yml index 74bd12b..cfe449e 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -4,15 +4,16 @@ baseurl: / plugins: - jekyll-asciidoc + - jekyll-redirect-from collections: releases: output: true - permalink: /releases/:name/ + permalink: /docs/releases/:name/ defaults: - scope: - path: "api" + path: "docs/api" values: render_with_liquid: false - scope: @@ -25,10 +26,13 @@ defaults: include: - index.adoc - config-reference.adoc - - releases.adoc exclude: - manpage.adoc + - jekyll/ + - payloads/ + - release/ + - yard/ # Enable Rouge for syntax highlighting in AsciiDoc blocks asciidoctor: diff --git a/docs/landing.adoc b/docs/landing.adoc index bd309b4..fadd47a 100644 --- a/docs/landing.adoc +++ b/docs/landing.adoc @@ -1,6 +1,7 @@ :page-permalink: / :page-layout: minimal :page-liquid: true +:page-nav_exclude: true = ReleaseHx ++++ @@ -10,6 +11,15 @@

ReleaseHx

+ diff --git a/docs/releases.adoc b/docs/releases.adoc index bb408cd..559c36a 100644 --- a/docs/releases.adoc +++ b/docs/releases.adoc @@ -2,13 +2,13 @@ layout: default title: Releases nav_order: 90 -permalink: /releases/ +permalink: /docs/releases/ --- = Release History :page-layout: default :page-title: Releases :page-nav_order: 90 -:page-permalink: /releases/ +:page-permalink: /docs/releases/ Complete release history for ReleaseHx, generated using ReleaseHx itself. @@ -25,4 +25,4 @@ endif::[] --- -For more information about ReleaseHx, see the link:/[main documentation]. +For more information about ReleaseHx, see the link:/docs/[main documentation]. diff --git a/docs/sample-config.adoc b/docs/sample-config.adoc index 2c123df..b401c43 100644 --- a/docs/sample-config.adoc +++ b/docs/sample-config.adoc @@ -1,4 +1,6 @@ :page-nav_order: 3 +:page-permalink: /docs/sample-config/ +:page-redirect_from: /sample-config.html = Sample Configuration File This is a "`kitchen sink`" example of the ReleaseHx configuration settings. diff --git a/lib/schemagraphy/templates/cfgyml/config-reference.adoc.liquid b/lib/schemagraphy/templates/cfgyml/config-reference.adoc.liquid index 4588ddf..f60130a 100644 --- a/lib/schemagraphy/templates/cfgyml/config-reference.adoc.liquid +++ b/lib/schemagraphy/templates/cfgyml/config-reference.adoc.liquid @@ -1,7 +1,3 @@ -:page-layout: default -:page-permalink: /config-reference/ -:page-nav_order: 2 -:page-title: Configuration Reference {%- for property in config_def.properties -%} {%- assign ppty_key1 = property[0] -%} {%- assign ppty_path_t1 = ppty_key1 -%} diff --git a/scripts/build_docs.rb b/scripts/build_docs.rb index cff1303..ce6fcc8 100644 --- a/scripts/build_docs.rb +++ b/scripts/build_docs.rb @@ -32,6 +32,9 @@ def self.prepare_jekyll_source _version FileUtils.cp 'README.adoc', 'build/docs/index.adoc' FileUtils.cp_r 'docs/.', 'build/docs/' + # Add front matter to config-reference.adoc + add_config_reference_front_matter + # Update version in Jekyll config config_path = 'build/docs/_config.yml' raise "Jekyll config not found at #{config_path}" unless File.exist?(config_path) @@ -40,6 +43,26 @@ def self.prepare_jekyll_source _version File.write(config_path, config_content) end + def self.add_config_reference_front_matter + config_ref_path = 'build/docs/config-reference.adoc' + return unless File.exist?(config_ref_path) + + content = File.read(config_ref_path) + + # Add front matter if not already present + return if content.start_with?(':page-layout:') + + front_matter = <<~FRONT_MATTER + :page-layout: default + :page-permalink: /docs/config-reference/ + :page-nav_order: 2 + :page-redirect_from: ["/config-reference"] + :page-title: Configuration Reference + FRONT_MATTER + + File.write(config_ref_path, front_matter + content) + end + def self.generate_module_docs version puts 'Generating modular API docs with YARD...' @@ -65,7 +88,7 @@ def self.generate_module_docs version temp_readme_path = "build/docs/#{mod[:name].downcase}_readme.html" File.write(temp_readme_path, processed_readme_html) - output_dir = "build/docs/api/#{mod[:name].downcase}" + output_dir = "build/docs/docs/api/#{mod[:name].downcase}" FileUtils.mkdir_p output_dir file_list = mod[:files].join(' ') @@ -90,6 +113,18 @@ def self.generate_module_docs version Dir.glob("#{output_dir}/**/*.html").each do |html_file| add_custom_css_to_html(html_file, output_dir) end + + # Fix YARD index file naming: _index.html is the real API index, + # but index.html is generated from README. Rename them appropriately. + yard_index = File.join(output_dir, '_index.html') + readme_index = File.join(output_dir, 'index.html') + + if File.exist?(yard_index) + # Rename README-based index to readme.html + File.rename(readme_index, File.join(output_dir, 'readme.html')) if File.exist?(readme_index) + # Rename _index.html to index.html (this is the real API overview) + File.rename(yard_index, readme_index) + end end end @@ -169,7 +204,7 @@ def self.add_jekyll_front_matter end # Add front matter to YARD API documentation files - api_files = Dir.glob('build/docs/api/**/*.html') + api_files = Dir.glob('build/docs/docs/api/**/*.html') return if api_files.empty? api_files.each do |file| From 8278eb61de433c3bf24a61190eca79c9823bc453 Mon Sep 17 00:00:00 2001 From: Brian Dominick Date: Fri, 30 Jan 2026 00:59:30 -0500 Subject: [PATCH 7/7] Pre-release cleanup - Excuse some files from Vale linting - RuboCop autocorrection of Gemfile, *.rb files - Explicit ID for README.adoc section --- .config/docopslab-dev.yml | 4 + Gemfile | 2 +- README.adoc | 1 + Rakefile | 150 +++++++++----------- docs/release/drafts/0.1.2.yml | 53 ------- scripts/build_docs.rb | 16 +-- specs/tests/rspec/build_integration_spec.rb | 4 +- specs/tests/rspec/dependencies_spec.rb | 5 +- 8 files changed, 83 insertions(+), 152 deletions(-) delete mode 100644 docs/release/drafts/0.1.2.yml diff --git a/.config/docopslab-dev.yml b/.config/docopslab-dev.yml index c606bb8..8b2188c 100644 --- a/.config/docopslab-dev.yml +++ b/.config/docopslab-dev.yml @@ -47,6 +47,10 @@ tools: paths: skip: - build/* + - specs/* + - "**/config-reference.adoc" + - docs/releases.adoc + - docs/release/* - tool: htmlproofer enabled: true # Disabled by default, enable per project diff --git a/Gemfile b/Gemfile index 76f9318..7ef0445 100644 --- a/Gemfile +++ b/Gemfile @@ -17,7 +17,7 @@ end group :documentation do gem 'jekyll' gem 'jekyll-asciidoc' + gem 'jekyll-redirect-from' gem 'just-the-docs' gem 'yard' - gem 'jekyll-redirect-from' end diff --git a/README.adoc b/README.adoc index 39ec0a6..2afddc3 100644 --- a/README.adoc +++ b/README.adoc @@ -2476,6 +2476,7 @@ Use `PORT=NNNN` environment argument to specify a different port. [.prompt] PORT=4000 bundle exec rake serve +[[docopslab-devtool]] ==== DocOps Lab Devtool (`docopslab-dev`) Special dev Rake tasks and libraries are available via the `docopslab-dev` gem. diff --git a/Rakefile b/Rakefile index fa19df2..4892fce 100644 --- a/Rakefile +++ b/Rakefile @@ -194,99 +194,81 @@ task :serve do end # ReleaseHx self-dogfooding tasks +RHX_CONFIG_PATH = '.config/releasehx.yml' + namespace :rhx do - # Shared configuration for all rhx tasks def self.rhx_config - require_relative 'lib/releasehx' - - config_path = '.config/releasehx.yml' - unless File.exist?(config_path) - warn "ERROR: Config file not found: #{config_path}" + unless File.exist?(RHX_CONFIG_PATH) + warn "ERROR: Config file not found: #{RHX_CONFIG_PATH}" exit 1 end - - config = YAML.safe_load_file(config_path, aliases: true) - [config_path, config] + + config = YAML.safe_load_file(RHX_CONFIG_PATH, aliases: true) + [RHX_CONFIG_PATH, config] end - def self.get_version(args) + def self.get_version args args[:version] || extract_version end + def self.run_cmd cmd + puts "Running: #{cmd}" + exit 1 unless system(cmd) + end + + def self.with_rhx args + config_path, config = rhx_config + version = get_version(args) + yield(config_path, config, version) + end + desc 'Draft a YAML release-history document for the current version' task :draft, [:version] do |_t, args| - config_path, _config = rhx_config - version = get_version(args) - - puts "Fetching issues for version #{version} from GitHub..." - - # Use ReleaseHx CLI via system call - cmd = "bundle exec bin/rhx #{version} --config #{config_path} --fetch --yaml" - puts "Running: #{cmd}" - success = system(cmd) - - exit 1 unless success - - puts "✓ Successfully fetched and generated draft for version #{version}" + with_rhx(args) do |config_path, _config, version| + puts "Fetching issues for version #{version} from GitHub..." + cmd = "bundle exec bin/rhx #{version} --config #{config_path} --fetch --yaml" + run_cmd(cmd) + puts "✓ Successfully fetched and generated draft for version #{version}" + end end desc 'Append new issues to existing release draft' task :append, [:version] do |_t, args| - config_path, _config = rhx_config - version = get_version(args) - - puts "Appending new issues for version #{version}..." - - # Use ReleaseHx CLI with --append flag - cmd = "bundle exec bin/rhx #{version} --config #{config_path} --fetch --append" - puts "Running: #{cmd}" - success = system(cmd) - - exit 1 unless success - - puts "✓ Successfully appended new issues to version #{version} draft" + with_rhx(args) do |config_path, _config, version| + puts "Appending new issues for version #{version}..." + cmd = "bundle exec bin/rhx #{version} --config #{config_path} --fetch --append" + run_cmd(cmd) + puts "✓ Successfully appended new issues to version #{version} draft" + end end desc 'Publish release notes as AsciiDoc' task :adoc, [:version] do |_t, args| - config_path, config = rhx_config - version = get_version(args) - - # Infer draft path from config or use default - drafts_dir = config.dig('paths', 'drafts_dir') || 'docs/release/drafts' - yaml_file = File.join(drafts_dir, "#{version}.yml") - - unless File.exist?(yaml_file) - warn "ERROR: Draft not found: #{yaml_file}" - warn "Run 'rake rhx:draft[#{version}]' first to create the draft." - exit 1 + with_rhx(args) do |config_path, config, version| + drafts_dir = config.dig('paths', 'drafts_dir') || 'docs/release/drafts' + yaml_file = File.join(drafts_dir, "#{version}.yml") + + unless File.exist?(yaml_file) + warn "ERROR: Draft not found: #{yaml_file}" + warn "Run 'rake rhx:draft[#{version}]' first to create the draft." + exit 1 + end + + puts "Publishing release notes for version #{version}..." + output_file = "docs/release/#{version}.adoc" + cmd = "bundle exec bin/rhx #{yaml_file} --config #{config_path} --adoc #{output_file}" + run_cmd(cmd) + puts "✓ Successfully published release notes to #{output_file}" end - - puts "Publishing release notes for version #{version}..." - - # Generate AsciiDoc output - output_file = "docs/release/#{version}.adoc" - cmd = "bundle exec bin/rhx #{yaml_file} --config #{config_path} --adoc #{output_file}" - puts "Running: #{cmd}" - success = system(cmd) - - exit 1 unless success - - puts "✓ Successfully published release notes to #{output_file}" end desc 'Complete workflow: draft, then publish as AsciiDoc' task :generate, [:version] do |_t, args| version = get_version(args) - + puts "=== Generating complete release documentation for #{version} ===" - - # Run draft task Rake::Task['rhx:draft'].invoke(version) - - # Run adoc task Rake::Task['rhx:adoc'].invoke(version) - puts "\n✓ Complete! Release documentation generated for version #{version}" end end @@ -315,28 +297,28 @@ end def generate_release_index require 'fileutils' require 'yaml' - + release_dir = 'docs/release' output_file = 'build/docs/_release_index.adoc' - + # Ensure output directory exists FileUtils.mkdir_p(File.dirname(output_file)) - + # Find all release AsciiDoc files (not drafts, not test files) release_files = Dir.glob("#{release_dir}/*.adoc") .reject { |f| f.include?('-test') || f.include?('draft') } .sort .reverse - + return if release_files.empty? - + # Build the index content content = [] - content << "== Available Releases" - content << "" - content << "Each release includes detailed notes about new features, improvements, bug fixes, and breaking changes." - content << "" - + content << '== Available Releases' + content << '' + content << 'Each release includes detailed notes about new features, improvements, bug fixes, and breaking changes.' + content << '' + # List releases release_files.each do |file| version = File.basename(file, '.adoc') @@ -344,29 +326,27 @@ def generate_release_index date = extract_release_date(file) || 'TBD' content << "* link:../release/#{version}.html[#{version}] - #{date}" end - - content << "" - content << "== Latest Release" - content << "" - + + content << '' + content << '== Latest Release' + content << '' + # Include the latest release content if release_files.any? latest_file = release_files.first latest_version = File.basename(latest_file, '.adoc') content << "include::release/#{latest_version}.adoc[leveloffset=+1]" end - + # Write the file File.write(output_file, content.join("\n")) puts "✓ Generated release index: #{output_file}" end -def extract_release_date(file) +def extract_release_date file # Read first 20 lines looking for :page-date: attribute File.foreach(file).first(20).each do |line| - if line =~ /:page-date:\s+(.+)$/ - return $1.strip - end + return Regexp.last_match(1).strip if line =~ /:page-date:\s+(.+)$/ end nil end diff --git a/docs/release/drafts/0.1.2.yml b/docs/release/drafts/0.1.2.yml deleted file mode 100644 index 9a84a7d..0000000 --- a/docs/release/drafts/0.1.2.yml +++ /dev/null @@ -1,53 +0,0 @@ -code: "0.1.2" -date: 2026-01-29 -memo: -changes: - - - chid: 0_1_2-30 - tick: 30 - type: feature - part: docs - summ: | - Established an instance of ReleaseHx for managing the release history of... ReleaseHx - note: | - The ReleaseHx website now hosts a rich-text roster of change reports built with ReleaseHx itself at https://releasehx.docopslab.org/docs/releases/. The output is configured in `.config/releasehx.yml`, and the process is documented in `README.adoc`. - tags: - - documentation - - - chid: 0_1_2-32 - tick: 32 - type: bug - parts: - - configuration - - schemagraphy - summ: | - The documented regexp format (/pattern/flags) is unsupported - note: | - Regular expressions in YAML files such as the releasehx application config now support being written as fully qualified strings with the pattern fenced in `/` markers. Use `/pattern/flags` formats such as the following and expect proper parsing. - - ```yaml - note_pattern: /^((#+ Draft Release Note.*?)\n+(?(.|)+)/gmi - ``` - - - chid: 0_1_2-28 - tick: 28 - type: bug - parts: - - configuration - - rhyml - summ: | - Config property mismatch: code reads `note_source` but docs specify `note` - note: | - Added support for a proper configuration property for release-note extraction, bringing the product into line with the documented config. - The effective property was never documented, so it has been removed, but no deprecation was deemed necessary. - Backward compatibility has been sacrificed in this rare case, since the functionality was obscured. - lead: briandominick - - - chid: 0_1_2-36 - tick: 36 - type: bug - part: templates - summ: | - Formatting errors in AsciiDoc templates - note: | - AsciiDoc templates have been cleaned up and streamlined significantly, mostly by removing the clumsy metadata that was hard to style in rich-text output. We will improve on these templates later and welcome contributions cleaning them up. diff --git a/scripts/build_docs.rb b/scripts/build_docs.rb index ce6fcc8..92c3fa6 100644 --- a/scripts/build_docs.rb +++ b/scripts/build_docs.rb @@ -48,7 +48,7 @@ def self.add_config_reference_front_matter return unless File.exist?(config_ref_path) content = File.read(config_ref_path) - + # Add front matter if not already present return if content.start_with?(':page-layout:') @@ -118,13 +118,13 @@ def self.generate_module_docs version # but index.html is generated from README. Rename them appropriately. yard_index = File.join(output_dir, '_index.html') readme_index = File.join(output_dir, 'index.html') - - if File.exist?(yard_index) - # Rename README-based index to readme.html - File.rename(readme_index, File.join(output_dir, 'readme.html')) if File.exist?(readme_index) - # Rename _index.html to index.html (this is the real API overview) - File.rename(yard_index, readme_index) - end + + next unless File.exist?(yard_index) + + # Rename README-based index to readme.html + File.rename(readme_index, File.join(output_dir, 'readme.html')) if File.exist?(readme_index) + # Rename _index.html to index.html (this is the real API overview) + File.rename(yard_index, readme_index) end end diff --git a/specs/tests/rspec/build_integration_spec.rb b/specs/tests/rspec/build_integration_spec.rb index c99dcbb..c1bb72b 100644 --- a/specs/tests/rspec/build_integration_spec.rb +++ b/specs/tests/rspec/build_integration_spec.rb @@ -89,9 +89,7 @@ expect(stdout).to match(/prebuild artifacts missing/i) ensure # Restore generated.rb if we backed it up - if generated_backup - FileUtils.mv('lib/releasehx/generated.rb.bak', 'lib/releasehx/generated.rb') - end + FileUtils.mv('lib/releasehx/generated.rb.bak', 'lib/releasehx/generated.rb') if generated_backup end end end diff --git a/specs/tests/rspec/dependencies_spec.rb b/specs/tests/rspec/dependencies_spec.rb index ff7c87e..abb9803 100644 --- a/specs/tests/rspec/dependencies_spec.rb +++ b/specs/tests/rspec/dependencies_spec.rb @@ -65,8 +65,9 @@ temp_config.close begin - result = system("bundle exec bin/releasehx 1.0.0 --config #{temp_config.path} " \ - "--api-data #{temp_json} --md #{temp_output}/output.md --force") + result = system( + "bundle exec bin/releasehx 1.0.0 --config #{temp_config.path} " \ + "--api-data #{temp_json} --md #{temp_output}/output.md --force") expect(result).to be(true), 'Template processing failed with sample data' # Should have generated some output files