Skip to content

fix(convert): fail --strict on Asciidoctor errors - #1045

Merged
amondnet merged 3 commits into
mainfrom
amondnet/strict-asciidoctor-errors
Sep 30, 2026
Merged

amondnet merged 3 commits into
mainfrom
amondnet/strict-asciidoctor-errors

Conversation

@amondnet

@amondnet amondnet commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Closes #1044

Summary

convert.ts --strict now fails when Antora or Asciidoctor logs an ERROR. Until now it gated on the converter's own warnings only, so data-relational-3.2.9 published a page with a literal "Unresolved include directive" and exit 0.

The generated playbook already declared runtime.log.failure_level: error. Nothing applied it: this pipeline drives Antora as a library (ADR-0002), and it is the site generator that configures @antora/logger. Every conversion log started with logger not configured; creating logger with default settings, whose default failure level is silent.

What changes

  • Logger setup: convert.ts configures @antora/logger from the built playbook's runtime.log before aggregating content, so the YAML is the single source of truth. format: pretty is pinned, because Antora's auto format switches to JSON whenever stdout is not a TTY.
  • Failure decision: the verdict comes from our own count of ERROR messages, not from Antora's failOnExit. Two kinds of ERROR are exempt from that count. They are still printed, and summarised at the end.
    • Xrefs into the project's externalComponents. For Boot these are api, gradle-plugin and maven-plugin. The converter already rewrites these links to docs.spring.io, so no content is lost; Boot 4.1.1 alone logs 805 of them. A versioned id (4.1.1@maven-plugin:…) is not exempt, because the converter doesn't rewrite it.
    • The losses a synthesized era declares. ADR-0004 and ADR-0006 accept that Boot 3.3.0–4.0.7 cannot reconstruct the generated appendix: the configuration-property tables, starters, dependency versions and so on. That decision is now data. SynthesisSources.acceptedMissing lists the exact include targets and the two appendix: xrefs, taken from the release logs. An undeclared sibling of a declared file still fails.
  • Without --strict: the run still exits 0 and prints the count.
  • Dependency: @antora/logger 3.2.0 was a transitive dependency. It is now a direct one, at the same version as the other @antora/* packages.

Scan of the 899 catalogued versions

Every version's release.yml log was scanned for ERROR lines. All 899 logs were still available.

Before the exemptions ERROR lines Versions
xref into an external component 27,822 all 55 boot, exempt
include or xref the Boot synthesized eras declare as lost 2,030 53 boot (3.3.0–4.0.7), exempt
everything else 29 15, listed below

These 15 versions would fail if their tags were re-run. Each is a real upstream defect, and their published archives don't change:

Version ERROR Content lost?
data-relational 3.2.9 target of include not found: 3.2.9@data-commons::page$value-expressions.adoc Yes, one page
data-redis 3.2.0–3.2.8, 3.3.0–3.3.2 dropping cells from incomplete row in cluster.adoc No, the table renders
security 7.0.7+rebuild.1, 7.1.1+rebuild.1 target of xref not found: attachment$api/java/index.html A dead Javadoc link

Verification

  • Boot rebuilds: 4.1.1, 4.0.7 and 3.5.16, fetched and converted under --strict, exit 0. Their output is byte-identical to markdown/boot/<version>/, apart from LICENSE/NOTICE, which package-release.ts adds.
  • Known failures: data-relational 3.2.9 and data-redis 3.2.0 exit 1 locally, with the ERROR counts the scan predicted.
  • Unchanged output: data-jpa 4.1.1 exits 0, byte-identical to markdown/data-jpa/4.1.1/.
  • Logger warning: logger not configured no longer appears.

Tests

  • tests/integration/pipeline.test.ts:
    • a missing include fails --strict and exits 0 without it;
    • an external xref passes --strict and is rewritten to docs.spring.io;
    • a non-external missing xref fails.
  • tests/unit/convert.test.ts: externalXrefComponent covers id forms, versioned ids and non-external components. isAcceptedLoss covers directory prefixes, exact files, siblings, lookalike prefixes and message kinds.
  • tests/unit/upstream-sources.test.ts: both Boot synthesized eras declare their losses; archive, overlay and template eras declare none.

tsc and lint pass. The full suite passes 531/531.


Summary by cubic

convert.ts --strict now fails when Antora or Asciidoctor logs an ERROR. Previously the playbook's runtime.log.failure_level: error never took effect because the pipeline drives Antora as a library and never configured @antora/logger, so a page with an unresolved include was published with exit 0 (#1044).

Details

  • convert.ts configures @antora/logger from the built playbook and counts ERROR messages directly instead of relying on Antora's failOnExit.
  • The logger is finalized on both the success and failure paths, so the pretty-format stream does not drop the ERROR lines that explain a failure.
  • All counts are printed before any --strict throws, so a failing run still reports both warning and ERROR totals.
  • Without --strict the run still exits 0 and prints the count.
  • @antora/logger is now a direct dependency at the same 3.2.0 version as the other @antora/* packages.

Exemptions

  • Unresolved xrefs into external components (e.g. api, gradle-plugin, maven-plugin) are exempt only when the converter actually rewrote that reference to docs.spring.io; a versioned id (4.1.1@maven-plugin:...) or a reference emitted verbatim (e.g. inside a [literal] block) still fails.
  • Unresolved targets a synthesized Boot era declares as accepted losses (ADR-0004, ADR-0006) are declared as data in AcceptedMissing; any undeclared missing target still fails.

Written for commit a34867c. Summary will update on new commits.

The playbook's runtime.log.failure_level never took effect: the pipeline
drives Antora as a library and never configured @antora/logger, so an
unresolved include was published with exit 0. convert.ts now configures
the logger from the playbook and fails --strict on any ERROR except xrefs
into the external components the converter rewrites, and the generated
appendix the Boot synthesized eras declare as lost (ADR-0004, ADR-0006).

Closes #1044
@codecov

codecov Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 42.93785% with 101 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
scripts/convert.ts 23.48% 101 Missing ⚠️

📢 Thoughts on this report? Let us know!

@greptile-apps

greptile-apps Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[High risk] Build pipeline now fails on Asciidoctor errors in strict mode.

The PR appears safe to merge based on the changes since the previous review.

Summary

The PR makes --strict fail on Antora and Asciidoctor ERROR logs while exempting declared synthesized-era losses and external xrefs the converter rewrites.

  • The changes since the previous review record rewritten xref IDs and use them to distinguish rewritten references from unrewritten ones.
  • The version check now tests only the portion of an ID before its first colon.

Reviews (3) · Last reviewed commit: "fix(convert): exempt only external xrefs..."

Comment thread scripts/convert.ts Outdated
Comment thread scripts/convert.ts Outdated
@greptile-apps

This comment has been minimized.

@sonarqubecloud

Copy link
Copy Markdown

@amondnet
amondnet merged commit 8c52beb into main Sep 30, 2026
7 of 8 checks passed
@amondnet
amondnet deleted the amondnet/strict-asciidoctor-errors branch September 30, 2026 02:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

convert --strict ignores Asciidoctor errors: the playbook's failure_level never takes effect

1 participant