releasehx 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.adoc +366 -331
- data/build/docs/_config.yml +18 -1
- data/build/docs/_release_index.adoc +10 -0
- data/build/docs/config-reference.adoc +203 -16
- data/build/docs/config-reference.json +60 -10
- data/build/docs/index.adoc +316 -59
- data/build/docs/landing.adoc +11 -4
- data/build/docs/manpage.adoc +2 -2
- data/build/docs/release-procedure.adoc +365 -0
- data/build/docs/release-procedure.html +87 -0
- data/build/docs/releasehx.1 +17 -5
- data/build/docs/releases.adoc +28 -0
- data/build/docs/sample-config.adoc +2 -0
- data/build/docs/sample-config.yml +16 -9
- data/lib/releasehx/cli.rb +21 -9
- data/lib/releasehx/configuration.rb +0 -1
- data/lib/releasehx/generated.rb +1 -1
- data/lib/releasehx/mcp/assets/agent-config-guide.md +1 -1
- data/lib/releasehx/mcp/assets/config-def.yml +126 -8
- data/lib/releasehx/mcp/assets/config-reference.adoc +203 -16
- data/lib/releasehx/mcp/assets/config-reference.json +60 -10
- data/lib/releasehx/mcp/assets/sample-config.yml +16 -9
- data/lib/releasehx/mcp/server.rb +0 -1
- data/lib/releasehx/ops/enrich_ops.rb +161 -55
- data/lib/releasehx/ops/template_ops.rb +1 -1
- data/lib/releasehx/rhyml/adapter.rb +13 -9
- data/lib/releasehx/rhyml/mappings/github.yaml +3 -1
- data/lib/releasehx/rhyml/templates/bootstrap-overrides.css +15 -0
- data/lib/releasehx/rhyml/templates/changelog.adoc.liquid +2 -0
- data/lib/releasehx/rhyml/templates/changelog.html.liquid +6 -4
- data/lib/releasehx/rhyml/templates/changelog.md.liquid +1 -0
- data/lib/releasehx/rhyml/templates/embedded.css.liquid +263 -0
- data/lib/releasehx/rhyml/templates/entry.adoc.liquid +4 -7
- data/lib/releasehx/rhyml/templates/entry.html.liquid +21 -20
- data/lib/releasehx/rhyml/templates/entry.md.liquid +14 -21
- data/lib/releasehx/rhyml/templates/head-parser.liquid +6 -2
- data/lib/releasehx/rhyml/templates/header.liquid +13 -4
- data/lib/releasehx/rhyml/templates/history.html.liquid +152 -33
- data/lib/releasehx/rhyml/templates/metadata-entry.adoc.liquid +83 -49
- data/lib/releasehx/rhyml/templates/metadata-entry.html.liquid +60 -1
- data/lib/releasehx/rhyml/templates/metadata-entry.md.liquid +65 -113
- data/lib/releasehx/rhyml/templates/metadata-note.adoc.liquid +83 -49
- data/lib/releasehx/rhyml/templates/metadata-note.html.liquid +59 -22
- data/lib/releasehx/rhyml/templates/metadata-note.md.liquid +68 -23
- data/lib/releasehx/rhyml/templates/note.adoc.liquid +2 -40
- data/lib/releasehx/rhyml/templates/note.html.liquid +25 -19
- data/lib/releasehx/rhyml/templates/note.md.liquid +43 -29
- data/lib/releasehx/rhyml/templates/parts-listing.liquid +6 -6
- data/lib/releasehx/rhyml/templates/release-notes.adoc.liquid +2 -0
- data/lib/releasehx/rhyml/templates/release-notes.html.liquid +6 -4
- data/lib/releasehx/rhyml/templates/release-notes.md.liquid +1 -0
- data/lib/releasehx/rhyml/templates/release.adoc.liquid +2 -0
- data/lib/releasehx/rhyml/templates/release.md.liquid +8 -7
- data/lib/releasehx/rhyml/templates/rhyml-change.yaml.liquid +36 -35
- data/lib/releasehx/rhyml/templates/wrapper.html.liquid +103 -0
- data/lib/releasehx/sgyml/helpers.rb +0 -2
- data/lib/releasehx/transforms/adf_to_markdown.rb +1 -1
- data/lib/releasehx/version.rb +0 -2
- data/lib/releasehx.rb +2 -2
- data/specs/data/config-def.yml +126 -8
- metadata +50 -26
- data/build/docs/Gemfile.lock +0 -95
- data/build/docs/schemagraphy_readme.html +0 -0
- data/build/docs/sourcerer_readme.html +0 -46
- data/lib/schemagraphy/attribute_resolver.rb +0 -48
- data/lib/schemagraphy/cfgyml/definition.rb +0 -90
- data/lib/schemagraphy/cfgyml/doc_builder.rb +0 -52
- data/lib/schemagraphy/cfgyml/path_reference.rb +0 -24
- data/lib/schemagraphy/data_query/json_pointer.rb +0 -42
- data/lib/schemagraphy/loader.rb +0 -59
- data/lib/schemagraphy/regexp_utils.rb +0 -215
- data/lib/schemagraphy/safe_expression.rb +0 -189
- data/lib/schemagraphy/schema_utils.rb +0 -124
- data/lib/schemagraphy/tag_utils.rb +0 -32
- data/lib/schemagraphy/templating.rb +0 -104
- data/lib/schemagraphy.rb +0 -17
- data/lib/sourcerer/builder.rb +0 -120
- data/lib/sourcerer/jekyll/bootstrapper.rb +0 -78
- data/lib/sourcerer/jekyll/liquid/file_system.rb +0 -74
- data/lib/sourcerer/jekyll/liquid/filters.rb +0 -215
- data/lib/sourcerer/jekyll/liquid/tags.rb +0 -44
- data/lib/sourcerer/jekyll/monkeypatches.rb +0 -73
- data/lib/sourcerer/jekyll.rb +0 -26
- data/lib/sourcerer/plaintext_converter.rb +0 -75
- data/lib/sourcerer/templating.rb +0 -190
- data/lib/sourcerer.rb +0 -322
|
@@ -129,7 +129,8 @@
|
|
|
129
129
|
"note": {
|
|
130
130
|
"path": "conversions.note",
|
|
131
131
|
"desc": "The source of the release notes content.\nMust be `issue_body`, `custom_field`, or `commit_message`.\n\nDefaults to `issue_body` for GitHub and GitLab, but to `custom_field` for Jira.\n",
|
|
132
|
-
"type": "String"
|
|
132
|
+
"type": "String",
|
|
133
|
+
"default": "issue_body"
|
|
133
134
|
},
|
|
134
135
|
"note_custom_field": {
|
|
135
136
|
"path": "conversions.note_custom_field",
|
|
@@ -140,7 +141,7 @@
|
|
|
140
141
|
"path": "conversions.note_pattern",
|
|
141
142
|
"desc": "The Regular Expressions pattern to match in the body of an issue or commit message, after which all content is considered the release `note` matter.\n\nDefaults to a Markdown or AsciiDoc header or HTML comment with the case-insensitive string `release note` in it.\n\nUses Capture group `note` in the Regular Expression to establish the entire note content.\n\nSee the `conversions.head_pattern` property for details on extracting a heading (`head` in RHYML) from the `note` content.\n",
|
|
142
143
|
"type": "RegExp",
|
|
143
|
-
"default": "/^((#|=)+ (Draft )?Release Note
|
|
144
|
+
"default": "/^(((#|=)+ (Draft )?Release Note.*?)|(<!-- (draft )?release note -->))\\n+(?<note>(.| )+)/gmi"
|
|
144
145
|
},
|
|
145
146
|
"head_pattern": {
|
|
146
147
|
"path": "conversions.head_pattern",
|
|
@@ -154,10 +155,23 @@
|
|
|
154
155
|
"type": "String",
|
|
155
156
|
"default": "markdown"
|
|
156
157
|
},
|
|
157
|
-
"
|
|
158
|
-
"path": "conversions.
|
|
159
|
-
"desc": "
|
|
160
|
-
"
|
|
158
|
+
"engines": {
|
|
159
|
+
"path": "conversions.engines",
|
|
160
|
+
"desc": "Specifies the conversion engines to use when enriching to various output formats.\n\nThese settings determine which tool processes the conversion from draft formats to rich output.\nIntelligent defaults are applied based on source format when engines are not explicitly configured.\n",
|
|
161
|
+
"properties": {
|
|
162
|
+
"html": {
|
|
163
|
+
"path": "conversions.engines.html",
|
|
164
|
+
"desc": "Engine for converting to HTML format.\n\nValid engines:\n\n[horizontal]\n`asciidoctor-html5`:: Standard Asciidoctor HTML5 backend (nested div structure)\n`asciidoctor-html5s`:: Semantic HTML5 backend (cleaner section-based markup)\n`kramdown`:: Kramdown Markdown converter (for Markdown sources)\n`pandoc`:: Universal document converter (if available)\n\nWhen not specified, intelligent defaults apply:\n\n- AsciiDoc → HTML: `asciidoctor-html5s` (semantic HTML5)\n- Markdown → HTML: `kramdown`\n- RHYML → HTML: Liquid templates (no engine needed)\n",
|
|
165
|
+
"docs": "The html5s backend produces cleaner, more semantic HTML with `<section>` elements\ninstead of nested `<div class=\"sect1\"><div class=\"sectionbody\">` structures.\n\nThis is particularly useful when you want to apply custom CSS or when generating\nHTML that will be further processed or embedded in other systems.\n\nFor backwards compatibility or when you need the traditional Asciidoctor structure,\nuse `asciidoctor-html5`.\n",
|
|
166
|
+
"type": "String"
|
|
167
|
+
},
|
|
168
|
+
"pdf": {
|
|
169
|
+
"path": "conversions.engines.pdf",
|
|
170
|
+
"desc": "Engine for converting to PDF format.\n\nValid engines:\n\n[horizontal]\n`asciidoctor-pdf`:: Asciidoctor PDF converter (default for AsciiDoc)\n`asciidoctor-web-pdf`:: Web-based PDF converter using headless Chrome\n`pandoc`:: Universal document converter (if available)\n\nWhen not specified, intelligent defaults apply:\n\n- AsciiDoc → PDF: `asciidoctor-pdf`\n- Markdown → PDF: `pandoc` (if available)\n",
|
|
171
|
+
"docs": "The default `asciidoctor-pdf` engine provides excellent typography and layout\nfor technical documentation with support for themes, fonts, and advanced formatting.\n",
|
|
172
|
+
"type": "String"
|
|
173
|
+
}
|
|
174
|
+
}
|
|
161
175
|
}
|
|
162
176
|
}
|
|
163
177
|
},
|
|
@@ -995,8 +1009,8 @@
|
|
|
995
1009
|
"path": "modes",
|
|
996
1010
|
"desc": "Default settings for `rhx` command executions.\n",
|
|
997
1011
|
"properties": {
|
|
998
|
-
"
|
|
999
|
-
"path": "modes.
|
|
1012
|
+
"html_wrap": {
|
|
1013
|
+
"path": "modes.html_wrap",
|
|
1000
1014
|
"desc": "Include (or exclude) head, header, and footer elements when enriching to HTML.\n",
|
|
1001
1015
|
"type": "Boolean",
|
|
1002
1016
|
"default": false
|
|
@@ -1016,7 +1030,8 @@
|
|
|
1016
1030
|
"asciidoc_frontmatter": {
|
|
1017
1031
|
"path": "modes.asciidoc_frontmatter",
|
|
1018
1032
|
"desc": "Include frontmatter in AsciiDoc drafts.\n\nUses the `templates.asciidoc_frontmatter` template.\n",
|
|
1019
|
-
"type": "Boolean"
|
|
1033
|
+
"type": "Boolean",
|
|
1034
|
+
"default": false
|
|
1020
1035
|
},
|
|
1021
1036
|
"fetch": {
|
|
1022
1037
|
"path": "modes.fetch",
|
|
@@ -1125,6 +1140,41 @@
|
|
|
1125
1140
|
"type": "Liquid",
|
|
1126
1141
|
"default": "---\ntitle: Release History for {{ release.code }}\nversion: {{ release.code }}\ndate: {{ release.date }}\n---\n"
|
|
1127
1142
|
},
|
|
1143
|
+
"html_framework": {
|
|
1144
|
+
"path": "history.html_framework",
|
|
1145
|
+
"desc": "The HTML framework to use when enriching to HTML.\n\nValid entries:\n\n[horizontal]\n`bare`:: minimal HTML structure\n`bootstrap4`:: Bootstrap 4 framework\n`bootstrap5`:: Bootstrap 5 framework\n",
|
|
1146
|
+
"type": "String",
|
|
1147
|
+
"default": "bare"
|
|
1148
|
+
},
|
|
1149
|
+
"styling": {
|
|
1150
|
+
"path": "history.styling",
|
|
1151
|
+
"desc": "Configuration options for HTML styling and CSS framework integration.\n",
|
|
1152
|
+
"properties": {
|
|
1153
|
+
"mode": {
|
|
1154
|
+
"path": "history.styling.mode",
|
|
1155
|
+
"desc": "The HTML styling approach to use when generating wrapped HTML output.\n\nValid options:\n\n* `minimal` -- Basic semantic HTML with minimal inline styles\n* `embedded` -- Include comprehensive CSS in `<style>` block \n* `external` -- Reference external stylesheet via `<link>` tag\n* `framework` -- Use configured CSS framework only (Bootstrap, etc.)\n\nWhen `mode: framework`, styling relies entirely on the configured CSS framework.\nWhen `mode: embedded`, CSS is included inline for standalone HTML files.\nWhen `mode: external`, a custom CSS file must be provided via `css_url`.\n",
|
|
1156
|
+
"type": "String",
|
|
1157
|
+
"default": "framework"
|
|
1158
|
+
},
|
|
1159
|
+
"theme": {
|
|
1160
|
+
"path": "history.styling.theme",
|
|
1161
|
+
"desc": "The visual theme variant to apply to HTML output.\n\nBuilt-in themes:\n\n* `default` -- Standard professional appearance\n* `compact` -- Reduced spacing and condensed layout\n* `detailed` -- Enhanced metadata display with expanded information\n\nTheme selection affects spacing, typography, and metadata prominence.\n",
|
|
1162
|
+
"type": "String",
|
|
1163
|
+
"default": "default"
|
|
1164
|
+
},
|
|
1165
|
+
"embed_css": {
|
|
1166
|
+
"path": "history.styling.embed_css",
|
|
1167
|
+
"desc": "Include comprehensive CSS directly in the HTML `<style>` block.\n\nWhen enabled, generates standalone HTML files that display correctly\nwithout external dependencies. CSS includes framework customizations,\nresponsive design rules, and print optimizations.\n\nAutomatically enabled when `mode: embedded`.\n",
|
|
1168
|
+
"type": "Boolean",
|
|
1169
|
+
"default": false
|
|
1170
|
+
},
|
|
1171
|
+
"css_url": {
|
|
1172
|
+
"path": "history.styling.css_url",
|
|
1173
|
+
"desc": "URL or path to external CSS stylesheet for custom styling.\n\nWhen `mode: external`, this stylesheet is linked via `<link rel=\"stylesheet\">`.\nCan be a relative path, absolute URL, or CDN link.\n\nExample: `assets/custom-releasehx.css` or `https://example.com/styles.css`\n\nWhen provided, framework CSS and embedded CSS are disabled.\n",
|
|
1174
|
+
"type": "String"
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
},
|
|
1128
1178
|
"items": {
|
|
1129
1179
|
"path": "history.items",
|
|
1130
1180
|
"desc": "Settings pertaining to displayed items across Changelog and Release Notes sections.\n\nMost of these settings can be defined separately for each section under <<conf_ppty_changelog_items>> and <<conf_ppty_notes_items>>.\nIf an identically named setting exists, it will override the primary designator defined in this `config.history.items` block.\n",
|
|
@@ -1228,7 +1278,7 @@
|
|
|
1228
1278
|
"path": "history.labeling.part_label",
|
|
1229
1279
|
"desc": "The label to use for the _singular_ part/component affected by the change, when only one part is permitted.\n\nThis value will apply either when <<conf_ppty_rhyml_max_parts>> is set to `1` or when the change has only one part _and_ <<conf_ppty_history_labeling_singularize_labels>> is `true`.\n",
|
|
1230
1280
|
"type": "String",
|
|
1231
|
-
"default": "
|
|
1281
|
+
"default": "Component"
|
|
1232
1282
|
},
|
|
1233
1283
|
"parts_icon": {
|
|
1234
1284
|
"path": "history.labeling.parts_icon",
|
|
@@ -22,10 +22,12 @@ origin: # The API or file source for the issues.
|
|
|
22
22
|
conversions: # Details about content origination, as well as markup sources and conversion.
|
|
23
23
|
summ: issue # The source of the summary (Changelog) content.
|
|
24
24
|
# head: # The source of release-note headlines, when it is not the same as the summary.
|
|
25
|
-
|
|
25
|
+
note: issue_body # The source of the release notes content.
|
|
26
26
|
# note_custom_field: # The name of the custom field to use for the release notes content.Liquid error: wrong number of arguments (given 3, expected 1..2)Liquid error: wrong number of arguments (given 3, expected 1..2)
|
|
27
27
|
markup: markdown # The origin markup format for notes.
|
|
28
|
-
|
|
28
|
+
engines: # Specifies the conversion engines to use when enriching to various output formats.
|
|
29
|
+
# html: # Engine for converting to HTML format.
|
|
30
|
+
# pdf: # Engine for converting to PDF format.
|
|
29
31
|
extensions: # Default file extensions.
|
|
30
32
|
markdown: md # File extension for Markdown drafts.
|
|
31
33
|
asciidoc: adoc # File extension for AsciiDoc drafts.
|
|
@@ -72,7 +74,7 @@ tags: # Handling for tags, labels, or toggles associated with source Issues.
|
|
|
72
74
|
- breaking
|
|
73
75
|
- experimental
|
|
74
76
|
- changelog
|
|
75
|
-
_exclude: # The list of tags that cause a change/issue to be excluded from the release history.
|
|
77
|
+
_exclude: [] # The list of tags that cause a change/issue to be excluded from the release history.
|
|
76
78
|
highlight: # The tag, label, or toggle that indicates an issue is to be highlighted or prioritized in sorts.
|
|
77
79
|
head: Highlights # How this tag will display as a grouping title.
|
|
78
80
|
text: highlight # How this tag will display as a label.
|
|
@@ -163,10 +165,10 @@ paths: # The configuration for the paths to include in the release history listi
|
|
|
163
165
|
mappings_dir: _mappings # The path to the directory containing user-defined API mappings.
|
|
164
166
|
api_clients_dir: _apis # The path to the directory containing user-defined API client definitions.
|
|
165
167
|
modes: # Default settings for rhx command executions.
|
|
166
|
-
|
|
168
|
+
html_wrap: false # Include (or exclude) head, header, and footer elements when enriching to HTML.
|
|
167
169
|
html_frontmatter: true # Include frontmatter in the rendered HTML.
|
|
168
170
|
markdown_frontmatter: false # Include frontmatter in Markdown drafts.
|
|
169
|
-
|
|
171
|
+
asciidoc_frontmatter: false # Include frontmatter in AsciiDoc drafts.
|
|
170
172
|
fetch: notes-only # What to fetch when gathering issues from API.
|
|
171
173
|
remove_excess_lines: 1 # Reduces N+ consecutive blank lines to N lines.
|
|
172
174
|
rhyml: # Settings related to RHYML data objects and documents.
|
|
@@ -178,6 +180,12 @@ rhyml: # Settings related to RHYML data objects and documents.
|
|
|
178
180
|
pasterize_head: false # Whether to convert verbs in the head property to past tense when drafting.
|
|
179
181
|
history: # Configurations for the overall document, when applicable.Liquid error: wrong number of arguments (given 3, expected 1..2)
|
|
180
182
|
htag: h1 # The heading level (H1, H2, etc) for the release history header.Liquid error: wrong number of arguments (given 3, expected 1..2)Liquid error: wrong number of arguments (given 3, expected 1..2)Liquid error: wrong number of arguments (given 3, expected 1..2)
|
|
183
|
+
html_framework: bare # The HTML framework to use when enriching to HTML.
|
|
184
|
+
styling: # Configuration options for HTML styling and CSS framework integration.
|
|
185
|
+
mode: framework # The HTML styling approach to use when generating wrapped HTML output.
|
|
186
|
+
theme: default # The visual theme variant to apply to HTML output.
|
|
187
|
+
embed_css: false # Include comprehensive CSS directly in the HTML <style> block.
|
|
188
|
+
# css_url: # URL or path to external CSS stylesheet for custom styling.
|
|
181
189
|
items: # Settings pertaining to displayed items across Changelog and Release Notes sections.
|
|
182
190
|
allow_redundant: false # Whether to allow duplicate entries in a given section, for instance across groups for part:group sorts where a change affects...
|
|
183
191
|
show_issue_links: false # Whether to include web links in item metadata.
|
|
@@ -195,7 +203,7 @@ history: # Configurations for the overall document, when applicable.Liquid error
|
|
|
195
203
|
type_label: type # The label to use for the type of change.
|
|
196
204
|
# type_icon: # The icon to use for the type of change.
|
|
197
205
|
parts_label: Components # The label to use for the part/component affected by the change.
|
|
198
|
-
part_label:
|
|
206
|
+
part_label: Component # The label to use for the singular part/component affected by the change, when only one part is permitted.
|
|
199
207
|
parts_icon: puzzle-piece # The icon to use for the part/component affected by the change.
|
|
200
208
|
tags_label: # The tags associated with the change, if any.
|
|
201
209
|
- Tags
|
|
@@ -210,8 +218,7 @@ changelog: # The configuration for the changelog output.
|
|
|
210
218
|
head: Changelog # The header for the changelog output.Liquid error: wrong number of arguments (given 3, expected 1..2)
|
|
211
219
|
htag: h2 # The heading level (H1, H2, etc) for the changelog section header.
|
|
212
220
|
spot: 2 # Where in the document to place the changelog (1 = top, 2 = bottom).
|
|
213
|
-
sort: # The sort order for the changelog output.
|
|
214
|
-
- part:grouping1
|
|
221
|
+
sort: [part:grouping1] # The sort order for the changelog output.
|
|
215
222
|
items: # Settings that affect the frame/shape and arrangement of individual changelog entries.
|
|
216
223
|
frame: unordered # The layout for the changelog entry display.
|
|
217
224
|
allow_redundant: false # Whether to allow duplicate entries in a given section, for instance across groups for part:group sorts where a change affects...
|
|
@@ -248,4 +255,4 @@ notes: # The configuration for the Release Notes listing section.
|
|
|
248
255
|
show_parts_label: false # Whether to show the parts label in the item metadata output.
|
|
249
256
|
show_tags_label: false # Whether to show the tags label in the item metadata output.
|
|
250
257
|
show_lead_label: false # Whether to show the lead label in the item metadata output.
|
|
251
|
-
show_auths_label: false # Whether to show the authors label in the item metadata output.
|
|
258
|
+
show_auths_label: false # Whether to show the authors label in the item metadata output.
|
data/lib/releasehx/mcp/server.rb
CHANGED
|
@@ -34,7 +34,16 @@ module ReleaseHx
|
|
|
34
34
|
when :html
|
|
35
35
|
# Direct Liquid template rendering to HTML
|
|
36
36
|
html_content = DraftOps.process_template_content(release: release, config: config, format: :html)
|
|
37
|
-
|
|
37
|
+
|
|
38
|
+
# Wrap HTML with Bootstrap styling if enabled
|
|
39
|
+
enriched = if config && config.dig('modes', 'html_wrap') != false
|
|
40
|
+
ReleaseHx.logger.debug('Applying HTML wrapper')
|
|
41
|
+
wrap_html(html_content, config)
|
|
42
|
+
else
|
|
43
|
+
html_content
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
WriteOps.safe_write(outpath, enriched)
|
|
38
47
|
when :pdf
|
|
39
48
|
# Two-stage process: RHYML → AsciiDoc → PDF
|
|
40
49
|
asciidoc_content = DraftOps.process_template_content(release: release, config: config, format: :adoc)
|
|
@@ -49,7 +58,7 @@ module ReleaseHx
|
|
|
49
58
|
# Generates rich-text output from source draft files of various formats.
|
|
50
59
|
#
|
|
51
60
|
# Automatically detects the input file type and applies the appropriate conversion
|
|
52
|
-
# strategy, supporting YAML (via RHYML)
|
|
61
|
+
# strategy, supporting YAML (via RHYML) and AsciiDoc source formats.
|
|
53
62
|
#
|
|
54
63
|
# @param file_path [String] The path to the source draft file.
|
|
55
64
|
# @param format [Symbol] The target output format (:html or :pdf).
|
|
@@ -75,9 +84,6 @@ module ReleaseHx
|
|
|
75
84
|
# RHYML/YAML files: load as Release object and use Liquid templates
|
|
76
85
|
release = load_rhyml_from_yaml(file_path, config: config)
|
|
77
86
|
enrich_from_rhyml(release: release, config: config, format: format, outpath: outpath, force: true)
|
|
78
|
-
when '.md'
|
|
79
|
-
# Markdown files: use native converter
|
|
80
|
-
convert_markdown(file_path, format: format, config: config, outpath: outpath, force: true)
|
|
81
87
|
when '.adoc'
|
|
82
88
|
# AsciiDoc files: use native converter
|
|
83
89
|
convert_asciidoc(file_path, format: format, config: config, outpath: outpath, force: true)
|
|
@@ -86,70 +92,41 @@ module ReleaseHx
|
|
|
86
92
|
end
|
|
87
93
|
end
|
|
88
94
|
|
|
89
|
-
# Converts
|
|
95
|
+
# Converts AsciiDoc content or files to rich-text formats using configured engines.
|
|
90
96
|
#
|
|
91
|
-
#
|
|
92
|
-
#
|
|
93
|
-
#
|
|
94
|
-
#
|
|
95
|
-
# @param format [Symbol] The target output format (:html or :pdf).
|
|
96
|
-
# @param config [ReleaseHx::Configuration] Reserved for future use.
|
|
97
|
-
# @param outpath [String] The target output file path.
|
|
98
|
-
# @param force [Boolean] Reserved for future use.
|
|
99
|
-
# @return [String] The path to the generated output file.
|
|
100
|
-
# rubocop:disable Lint/UnusedMethodArgument
|
|
101
|
-
def self.convert_markdown file_path, format:, config:, outpath:, force:
|
|
102
|
-
# NOTE: config and force parameters are currently unused but kept for API consistency
|
|
103
|
-
content = File.read(file_path)
|
|
104
|
-
|
|
105
|
-
case format.to_sym
|
|
106
|
-
when :html
|
|
107
|
-
require 'kramdown'
|
|
108
|
-
enriched = Kramdown::Document.new(content).to_html
|
|
109
|
-
WriteOps.safe_write(outpath, enriched)
|
|
110
|
-
when :pdf
|
|
111
|
-
# Use Tilt with Pandoc for direct Markdown to PDF conversion
|
|
112
|
-
require 'tilt'
|
|
113
|
-
require 'tilt/pandoc'
|
|
114
|
-
|
|
115
|
-
template = Tilt::PandocTemplate.new(file_path)
|
|
116
|
-
enriched = template.render(nil, to: 'pdf')
|
|
117
|
-
WriteOps.safe_write(outpath, enriched)
|
|
118
|
-
ReleaseHx.logger.info("PDF generated via Tilt/Pandoc: #{outpath}")
|
|
119
|
-
else
|
|
120
|
-
raise "Unsupported format for Markdown: #{format}"
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
outpath
|
|
124
|
-
end
|
|
125
|
-
# rubocop:enable Lint/UnusedMethodArgument
|
|
126
|
-
|
|
127
|
-
# Converts AsciiDoc content or files to rich-text formats using Asciidoctor.
|
|
97
|
+
# Accepts either file paths or raw content strings as input. Selects appropriate
|
|
98
|
+
# converter engine based on config.conversions.engines.html/pdf settings with intelligent defaults:
|
|
99
|
+
# - AsciiDoc → HTML: asciidoctor-html5s (default)
|
|
100
|
+
# - AsciiDoc → PDF: asciidoctor-pdf (default)
|
|
128
101
|
#
|
|
129
|
-
#
|
|
130
|
-
# for HTML generation and Asciidoctor-PDF for direct PDF output.
|
|
102
|
+
# HTML output can be wrapped with Bootstrap CSS when config.modes.html_wrap is enabled.
|
|
131
103
|
#
|
|
132
104
|
# @param file_path_or_content [String] File path or raw AsciiDoc content.
|
|
133
105
|
# @param format [Symbol] The target output format (:html or :pdf).
|
|
134
106
|
# @param outpath [String] The target output file path.
|
|
135
|
-
# @param config [ReleaseHx::Configuration]
|
|
136
|
-
# @param force [Boolean]
|
|
107
|
+
# @param config [ReleaseHx::Configuration] Configuration for engines and wrapping options.
|
|
108
|
+
# @param force [Boolean] Whether to overwrite existing files.
|
|
137
109
|
# @return [String] The path to the generated output file.
|
|
138
|
-
# rubocop:disable Lint/UnusedMethodArgument
|
|
139
110
|
def self.convert_asciidoc file_path_or_content, format:, outpath:, config: nil, force: nil
|
|
140
|
-
# NOTE: config and force parameters are currently unused but kept for API consistency
|
|
141
111
|
# Determine if input is file path or raw content
|
|
142
112
|
is_file = file_path_or_content.is_a?(String) && File.exist?(file_path_or_content)
|
|
143
113
|
content = is_file ? File.read(file_path_or_content) : file_path_or_content
|
|
144
114
|
|
|
145
115
|
case format.to_sym
|
|
146
116
|
when :html
|
|
147
|
-
|
|
148
|
-
|
|
117
|
+
engine = resolve_engine(format: :html, source_format: :asciidoc, config: config)
|
|
118
|
+
html_fragment = convert_with_engine(content, engine: engine, format: :html)
|
|
119
|
+
|
|
120
|
+
# Wrap HTML with Bootstrap styling if enabled
|
|
121
|
+
enriched = if config && config.dig('modes', 'html_wrap') != false
|
|
122
|
+
ReleaseHx.logger.debug('Applying wrapper to AsciiDoc-derived HTML')
|
|
123
|
+
wrap_html(html_fragment, config)
|
|
124
|
+
else
|
|
125
|
+
html_fragment
|
|
126
|
+
end
|
|
149
127
|
when :pdf
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
Asciidoctor.convert(content, to_file: outpath, safe: :safe, backend: 'pdf')
|
|
128
|
+
engine = resolve_engine(format: :pdf, source_format: :asciidoc, config: config)
|
|
129
|
+
convert_with_engine(content, engine: engine, format: :pdf, outpath: outpath)
|
|
153
130
|
return outpath
|
|
154
131
|
else
|
|
155
132
|
raise "Unsupported format for AsciiDoc: #{format}"
|
|
@@ -163,7 +140,6 @@ module ReleaseHx
|
|
|
163
140
|
WriteOps.safe_write(outpath, enriched)
|
|
164
141
|
outpath
|
|
165
142
|
end
|
|
166
|
-
# rubocop:enable Lint/UnusedMethodArgument
|
|
167
143
|
|
|
168
144
|
# Loads RHYML data from a YAML file and creates a Release object.
|
|
169
145
|
#
|
|
@@ -217,5 +193,135 @@ module ReleaseHx
|
|
|
217
193
|
filename = SchemaGraphy::Templating.render_field_if_template(filename_template, context)
|
|
218
194
|
File.join(output_dir, enrich_dir, filename.strip)
|
|
219
195
|
end
|
|
196
|
+
|
|
197
|
+
# Wraps an HTML fragment with Bootstrap CSS and semantic HTML structure.
|
|
198
|
+
#
|
|
199
|
+
# Takes a raw HTML fragment and wraps it with proper DOCTYPE, head section with Bootstrap CDN link, and body tag.
|
|
200
|
+
# Uses the wrapper.html.liquid template for markup generation.
|
|
201
|
+
#
|
|
202
|
+
# @param html_fragment [String] The raw HTML content to wrap.
|
|
203
|
+
# @param config [ReleaseHx::Configuration] Configuration object for title and settings.
|
|
204
|
+
# @return [String] Complete HTML document with Bootstrap styling.
|
|
205
|
+
def self.wrap_html html_fragment, config
|
|
206
|
+
# Extract and parse framework setting
|
|
207
|
+
framework_spec = config.dig('history', 'html_framework') || 'bare'
|
|
208
|
+
framework_name, framework_version = parse_framework_spec(framework_spec)
|
|
209
|
+
|
|
210
|
+
template_path = WriteOps.resolve_template_path('wrapper.html.liquid', config)
|
|
211
|
+
|
|
212
|
+
template_vars = {
|
|
213
|
+
'config' => config,
|
|
214
|
+
'content' => html_fragment,
|
|
215
|
+
'framework' => framework_name,
|
|
216
|
+
'framework_version' => framework_version
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
WriteOps.process_template(template_path, template_vars, config)
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# Parses framework specification string into name and version.
|
|
223
|
+
#
|
|
224
|
+
# @param spec [String] Framework specification like 'bootstrap5' or 'bootstrap:5.3.0'
|
|
225
|
+
# @return [Array<String, String>] Tuple of [framework_name, framework_version]
|
|
226
|
+
def self.parse_framework_spec spec
|
|
227
|
+
case spec.to_s
|
|
228
|
+
when /^(.+):(.+)$/
|
|
229
|
+
# Format: "bootstrap:5.3.0"
|
|
230
|
+
[::Regexp.last_match(1), ::Regexp.last_match(2)]
|
|
231
|
+
when 'bootstrap5'
|
|
232
|
+
['bootstrap', '5.3.0']
|
|
233
|
+
when 'bootstrap4'
|
|
234
|
+
['bootstrap', '4.6.2']
|
|
235
|
+
else
|
|
236
|
+
['bare', nil]
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# Resolves the appropriate conversion engine based on format and source.
|
|
241
|
+
#
|
|
242
|
+
# Applies intelligent defaults based on source format:
|
|
243
|
+
# - AsciiDoc → HTML: asciidoctor-html5s
|
|
244
|
+
# - AsciiDoc → PDF: asciidoctor-pdf
|
|
245
|
+
# - Markdown → HTML: kramdown
|
|
246
|
+
# - Markdown → PDF: pandoc
|
|
247
|
+
#
|
|
248
|
+
# @param format [Symbol] Output format (:html or :pdf)
|
|
249
|
+
# @param source_format [Symbol] Source format (:asciidoc or :markdown)
|
|
250
|
+
# @param config [Hash] Configuration hash
|
|
251
|
+
# @return [String] Engine name
|
|
252
|
+
def self.resolve_engine format:, source_format:, config: nil
|
|
253
|
+
# Check for explicit engine configuration
|
|
254
|
+
explicit_engine = config&.dig('conversions', 'engines', format.to_s)
|
|
255
|
+
return explicit_engine if explicit_engine
|
|
256
|
+
|
|
257
|
+
# Apply intelligent defaults based on source format
|
|
258
|
+
case [source_format, format]
|
|
259
|
+
when %i[asciidoc html]
|
|
260
|
+
'asciidoctor-html5s'
|
|
261
|
+
when %i[asciidoc pdf]
|
|
262
|
+
'asciidoctor-pdf'
|
|
263
|
+
when %i[markdown html]
|
|
264
|
+
'kramdown'
|
|
265
|
+
when %i[markdown pdf]
|
|
266
|
+
'pandoc'
|
|
267
|
+
else
|
|
268
|
+
raise "Unsupported conversion: #{source_format} → #{format}"
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# Converts content using the specified engine.
|
|
273
|
+
#
|
|
274
|
+
# @param content [String] Source content to convert
|
|
275
|
+
# @param engine [String] Engine name (e.g., 'asciidoctor-html5s', 'asciidoctor-pdf')
|
|
276
|
+
# @param format [Symbol] Output format (:html or :pdf)
|
|
277
|
+
# @param outpath [String, nil] Output file path (required for PDF)
|
|
278
|
+
# @return [String] Converted content (for HTML) or output path (for PDF)
|
|
279
|
+
# rubocop:disable Lint/UnusedMethodArgument
|
|
280
|
+
def self.convert_with_engine content, engine:, format:, outpath: nil
|
|
281
|
+
case engine
|
|
282
|
+
when 'asciidoctor-html5', 'asciidoctor-html5s'
|
|
283
|
+
require 'asciidoctor'
|
|
284
|
+
backend = engine.split('-').last # 'html5' or 'html5s'
|
|
285
|
+
|
|
286
|
+
if backend == 'html5s'
|
|
287
|
+
begin
|
|
288
|
+
require 'asciidoctor-html5s'
|
|
289
|
+
ReleaseHx.logger.debug('Using asciidoctor-html5s backend for semantic HTML5')
|
|
290
|
+
rescue LoadError
|
|
291
|
+
ReleaseHx.logger.warn('asciidoctor-html5s not available, falling back to html5')
|
|
292
|
+
backend = 'html5'
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
Asciidoctor.convert(content, safe: :safe, backend: backend)
|
|
297
|
+
|
|
298
|
+
when 'asciidoctor-pdf'
|
|
299
|
+
require 'asciidoctor'
|
|
300
|
+
require 'asciidoctor-pdf'
|
|
301
|
+
ReleaseHx.logger.debug('Using asciidoctor-pdf for PDF generation')
|
|
302
|
+
Asciidoctor.convert(content, to_file: outpath, safe: :safe, backend: 'pdf')
|
|
303
|
+
outpath
|
|
304
|
+
|
|
305
|
+
when 'asciidoctor-web-pdf'
|
|
306
|
+
require 'asciidoctor'
|
|
307
|
+
require 'asciidoctor-web-pdf'
|
|
308
|
+
ReleaseHx.logger.debug('Using asciidoctor-web-pdf for PDF generation')
|
|
309
|
+
Asciidoctor.convert(content, to_file: outpath, safe: :safe, backend: 'web-pdf')
|
|
310
|
+
outpath
|
|
311
|
+
|
|
312
|
+
when 'kramdown'
|
|
313
|
+
require 'kramdown'
|
|
314
|
+
ReleaseHx.logger.debug('Using Kramdown for HTML conversion')
|
|
315
|
+
Kramdown::Document.new(content).to_html
|
|
316
|
+
|
|
317
|
+
when 'pandoc'
|
|
318
|
+
# Future implementation - would shell out to pandoc
|
|
319
|
+
raise 'Pandoc engine not yet implemented'
|
|
320
|
+
|
|
321
|
+
else
|
|
322
|
+
raise "Unsupported engine: #{engine}"
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
# rubocop:enable Lint/UnusedMethodArgument
|
|
220
326
|
end
|
|
221
327
|
end
|
|
@@ -6,9 +6,6 @@ require 'liquid'
|
|
|
6
6
|
require 'erb'
|
|
7
7
|
require 'yaml'
|
|
8
8
|
require 'json'
|
|
9
|
-
require_relative '../../schemagraphy'
|
|
10
|
-
require_relative '../../schemagraphy/safe_expression'
|
|
11
|
-
require_relative '../../sourcerer/jekyll'
|
|
12
9
|
|
|
13
10
|
module ReleaseHx
|
|
14
11
|
module RHYML
|
|
@@ -349,7 +346,7 @@ module ReleaseHx
|
|
|
349
346
|
note_pattern = sources['note_pattern'] || templates['note_pattern']
|
|
350
347
|
head_pattern = sources['head_pattern'] || templates['head_pattern']
|
|
351
348
|
head_source = sources['head_source']
|
|
352
|
-
note_source = sources['
|
|
349
|
+
note_source = sources['note']
|
|
353
350
|
|
|
354
351
|
extract_note!(data, note_source, note_pattern)
|
|
355
352
|
extract_head!(data, head_source, head_pattern)
|
|
@@ -406,10 +403,10 @@ module ReleaseHx
|
|
|
406
403
|
end
|
|
407
404
|
|
|
408
405
|
# STEP 2: Apply regex pattern extraction if configured
|
|
409
|
-
return unless note_source
|
|
406
|
+
return unless note_source == 'issue_body' && original_content.is_a?(String) && note_pattern
|
|
410
407
|
|
|
411
408
|
ReleaseHx.logger.debug "Extracting note using pattern: #{note_pattern}"
|
|
412
|
-
ReleaseHx.logger.debug "Original content: #{original_content}"
|
|
409
|
+
ReleaseHx.logger.debug "Original content: #{original_content[0..100]}..."
|
|
413
410
|
|
|
414
411
|
begin
|
|
415
412
|
# Apply sensible default flag 'm' (multiline/dotall in Ruby) when no flags provided
|
|
@@ -421,11 +418,18 @@ module ReleaseHx
|
|
|
421
418
|
pattern_info,
|
|
422
419
|
'note')
|
|
423
420
|
|
|
424
|
-
|
|
425
|
-
|
|
421
|
+
if extracted_note
|
|
422
|
+
# Pattern matched - use extracted content
|
|
423
|
+
data['note'] = extracted_note.strip
|
|
424
|
+
ReleaseHx.logger.debug "Extracted note (#{extracted_note.length} chars)"
|
|
425
|
+
else
|
|
426
|
+
# Pattern didn't match - clear the note so empty_notes policy applies
|
|
427
|
+
ReleaseHx.logger.warn "Note pattern did not match for issue #{data['tick']} - no Release Note section found"
|
|
428
|
+
data['note'] = nil
|
|
429
|
+
end
|
|
426
430
|
rescue RegexpError => e
|
|
427
431
|
ReleaseHx.logger.warn "Invalid note_pattern '#{note_pattern}': #{e.message}"
|
|
428
|
-
|
|
432
|
+
# Preserve original content on pattern error - don't lose data due to bad config
|
|
429
433
|
end
|
|
430
434
|
end
|
|
431
435
|
|
|
@@ -25,7 +25,9 @@ note:
|
|
|
25
25
|
|
|
26
26
|
# Extract type from the native GitHub Issues type field (modern approach)
|
|
27
27
|
type:
|
|
28
|
-
path: "
|
|
28
|
+
path: "type.name"
|
|
29
|
+
ruby: |
|
|
30
|
+
path&.downcase
|
|
29
31
|
|
|
30
32
|
# Derive `parts` from labels using direct key matching or slug override
|
|
31
33
|
parts:
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/* Bootstrap Overrides for ReleaseHx */
|
|
2
|
+
/* Users can override this file by placing bootstrap-overrides.css in their _templates directory */
|
|
3
|
+
|
|
4
|
+
/* Dark Mode Fixes */
|
|
5
|
+
@media (prefers-color-scheme: dark) {
|
|
6
|
+
/* Fix .bg-light in card headers - use semantic card background instead */
|
|
7
|
+
.card-header.bg-light {
|
|
8
|
+
background-color: var(--bs-card-cap-bg) !important;
|
|
9
|
+
border-bottom: var(--bs-card-border-width) solid var(--bs-card-border-color);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.container-lg {
|
|
14
|
+
max-width: 900px;
|
|
15
|
+
}
|
|
@@ -4,11 +4,13 @@
|
|
|
4
4
|
{%- assign dflt_next_header_level = level | plus: 1 -%}
|
|
5
5
|
{%- assign item_count = 0 %}
|
|
6
6
|
|
|
7
|
-
<
|
|
8
|
-
|
|
7
|
+
<section class="changelog-section py-4 px-3 mb-4 rounded">
|
|
8
|
+
{%- include header.liquid format=format level=level text=content_config.head %}
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
{%- embed section-text.liquid %}
|
|
11
11
|
|
|
12
|
+
<div class="changelog-content mt-4">
|
|
12
13
|
{%- embed groupings.liquid %}
|
|
13
|
-
</div>
|
|
14
|
+
</div>
|
|
15
|
+
</section>
|
|
14
16
|
|