googleapis / googleapis/release-please
Regression: `<...>` inside inline code spans in commit subjects still break PR-body parsing, silently skipping a component release (manifest mode)
- Dominant language
- TypeScript
- Stars
- 7.5k
- Forks
- 588
- Avg merge
- 12h 16m
- Merged PRs (30d)
- 7
Description
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 ` `` keeps a **raw ``** 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 `` is treated as an unclosed HTML tag and the following `` block(s) get nested inside it and dropped from `root.getElementsByTagName('details')` — the exact mechanism described in #1659.
- `src/strategies/base.ts` then logs `Pull request contains releases, but not for component: ` 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 ` flag`` (affecting multiple packages so it appears in multiple `` 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
```js
// npm i release-please@17.6.0
const { PullRequestBody } = require('release-please/build/src/util/pull-request-body.js');
const body = [
':robot: release', '---', '',
'pkg-a: 1.0.0\n\n### Features\n\n* add `--report ` flag\n',
'pkg-b: 2.0.0\n\n### Features\n\n* add `--report ` flag\n',
'---', '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>')).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 `` block contained the 2nd `` 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 `` blocks robustly so an unclosed tag in note text cannot corrupt the DOM and drop sibling blocks.
Contributor guide
Assessment
This issue has not been assessed yet.