Skip to content

Regression: <...> inside inline code spans in commit subjects still break PR-body parsing, silently skipping a component release (manifest mode) #2801

Description

@eungkyu

This is a regression / incomplete fix of #1659 (fixed by #1661). HTML tags inside inline code spans in commit subjects are intentionally left unescaped by htmlEscape, but they still break the PR-body re-parsing step, causing a component's release to be silently skipped.

Environment

  • release-please 17.6.0 (googleapis/release-please-action@v5)
  • Manifest mode, multi-package monorepo, include-component-in-tag: true

Root cause

  • src/changelog-notes/default.ts htmlEscape() escapes bare </>, but via the regex /[^`].*[^`]|`[^`]*`|<|>/g with match.length > 1 ? match : ... it leaves </> inside inline code spans untouched. So a subject like add `check --report <path>` keeps a raw <path> in the generated release-PR body.
  • On release creation, src/util/pull-request-body.ts extractMultipleReleases() re-parses the PR body with node-html-parser. It does not understand markdown backticks, so <path> is treated as an unclosed HTML tag and the following <details> block(s) get nested inside it and dropped from root.getElementsByTagName('details') — the exact mechanism described in HTML tags in commit messages can break PR message parsing, causing missing package releases #1659.
  • src/strategies/base.ts then logs Pull request contains releases, but not for component: <X> and skips that component: no git tag, no GitHub release, no publish — while the workflow still reports success.
  • The next release-please run can no longer find that component's release boundary (tag missing) and re-walks its entire history, producing a bogus major bump in the next release PR.

Steps to reproduce

  1. In a manifest repo with ≥2 packages, land a commit whose subject contains an inline code span with an HTML-tag-looking token, e.g. feat: add `--report <path>` flag (affecting multiple packages so it appears in multiple <details> blocks).
  2. Merge the release PR.
  3. Observe that the component carrying the 2nd occurrence is not released (no tag/release/publish), though the run succeeds.

Minimal reproduction

// npm i release-please@17.6.0
const { PullRequestBody } = require('release-please/build/src/util/pull-request-body.js');
const body = [
  ':robot: release', '---', '',
  '<details><summary>pkg-a: 1.0.0</summary>\n\n### Features\n\n* add `--report <path>` flag\n</details>',
  '<details><summary>pkg-b: 2.0.0</summary>\n\n### Features\n\n* add `--report <path>` flag\n</details>',
  '---', 'footer',
].join('\n');

console.log(PullRequestBody.parse(body).releaseData.map(d => d.component));
// => [ 'pkg-a' ]            <-- pkg-b silently dropped

console.log(PullRequestBody.parse(body.replaceAll('<path>', '&lt;path&gt;')).releaseData.map(d => d.component));
// => [ 'pkg-a', 'pkg-b' ]   <-- escaping the angle brackets fixes it

Real-world case: an 11-package release PR dropped exactly the package whose <details> block contained the 2nd <path> occurrence.

Suggested fix

Since the PR body is later HTML-parsed (not rendered as markdown), </> should be escaped even when inside code spans when generating the body. Alternatively, make extractMultipleReleases extract <details> blocks robustly so an unclosed tag in note text cannot corrupt the DOM and drop sibling blocks.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

priority: p3Desirable enhancement or fix. May not be included in next release.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions