googleapis / googleapis/release-please-action

Single-package node repo with include-component-in-tag:false deadlocks on tagging — empty component override ignored

Open
#1,205 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
2.5k
Forks
327
PR merge metrics
No merged PRs in 30d

Description

### TL;DR

For a single-package node repo with `include-component-in-tag: false`, release-please-action **never tags or releases the merged release PR**, even though the PR is correctly labeled `autorelease: pending`. The release-build phase logs:

```
⚠ PR component: undefined does not match configured component:
```

and then the pull-request-build phase logs:

```
⚠ There are untagged, merged release PRs outstanding - aborting
```

The deadlock is unrecoverable through config and recurs on every push. Setting `component: ""` on the package, removing `package-name`, and setting `pull-request-title-pattern` explicitly all fail to break it.

### Expected behaviour

When a release PR (labeled `autorelease: pending`) is merged to `main`, the next workflow run should:

1. Detect the merged-but-untagged PR
2. Create the git tag (`v`)
3. Create the GitHub Release
4. Update the label from `autorelease: pending` to `autorelease: tagged`

… for a single-package repo regardless of whether `package.json#name` matches an empty/unset component config.

### Observed behaviour

Action SHA: `googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7` (v5.0.0)
release-please version (logged by the action): `17.6.0`

Two consecutive release cycles (v1.1.0 and v1.1.1) on the same single-package repo each opened a release PR correctly, but on merge the action **refused to tag**:

```
✔ Building releases
✔ Building strategies by path
❯ .: node
❯ Found pull request #10: 'chore: release main'
✔ Building release for path: .
❯ type: node
⚠ pullRequestTitlePattern miss the part of '${scope}'
⚠ pullRequestTitlePattern miss the part of '${component}'
❯ targetBranch: main
❯ Fetching package.json from branch main
⚠ PR component: undefined does not match configured component: kujali-chatcare

✔ Collecting commits since all latest releases
❯ looking for tagName: v1.1.1

⚠ There are untagged, merged release PRs outstanding - aborting
```

Both releases had to be tagged manually (`gh release create vX.Y.Z --target …`) and then the label flipped to `autorelease: tagged` to break the loop.

### Reproduction

`release-please-config.json`:

```json
{
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
"include-component-in-tag": false,
"include-v-in-tag": true,
"pull-request-title-pattern": "chore: release ${version}",
"packages": {
".": {
"release-type": "node",
"changelog-path": "CHANGELOG.md",
"component": ""
}
}
}
```

`.release-please-manifest.json`:

```json
{ ".": "1.0.0" }
```

`package.json`:

```json
{ "name": "kujali-chatcare", "version": "1.0.0", … }
```

Workflow trigger: push to `main`, single job using the SHA above. Token is a classic PAT with `repo` + `workflow` scopes (the org has fine-grained PATs disabled).

Steps:

1. Push commits with `feat:` / `fix:` types to `main`.
2. release-please opens a release PR titled `chore: release main`, with label `autorelease: pending`.
3. Merge the PR (squash).
4. Next push triggers release-please again — but instead of tagging the merged PR, it logs the component-mismatch warning and aborts.

### What I tried

| Attempt | Result |
|---|---|
| Default config with `package-name: "kujali-chatcare"` | Component mismatch (`undefined ≠ kujali-chatcare`), abort |
| Removed `package-name` from the package config | Same — the node strategy still derives the component from `package.json#name` |
| Added `component: ""` to the package config | Same — empty string is silently ignored, derived component still used |
| Added `pull-request-title-pattern: "chore: release ${version}"` at top level | Pattern ignored; PR title remains `chore: release main`; same abort |

### Root cause hypothesis

The `node` release-type derives an implicit component from `package.json#name`. When `include-component-in-tag: false` is set, the resulting release PR title (`chore: release main` — no `${component}` segment) **does not encode** the component. But on subsequent runs the release-build phase still checks `PR.component (parsed from title → undefined)` against `package.component (derived → kujali-chatcare)`. The mismatch makes release-build skip the tagging path, the pull-request-build phase sees the merged-but-untagged PR, and the whole run aborts.

An explicit empty-string `component: ""` ought to override the derived value, but in `release-please@17.6.0` it appears to be discarded (either by the `??` fallback to the strategy's derived component or by JSON parsing).

### Workaround

Manual tag + release on each merge, then re-label:

```bash
gh release create v1.1.1 --target --title "v1.1.1" --notes-file
gh pr edit --remove-label "autorelease: pending" --add-label "autorelease: tagged"
```

This works because once the PR is labeled `autorelease: tagged`, release-please ignores it on the next run and stops the abort loop. But the manual step defeats the whole point of the action.

### Proposed fix

Either:

- **(a) Honour explicit empty-string `component`** on a package config, so single-package repos with `include-component-in-tag: false` can opt out of component matching entirely; OR
- **(b) Skip component matching when `include-component-in-tag: false`** — if the tag isn't going to encode the component, the PR title shouldn't need to either, so the comparison is moot; OR
- **(c) Detect single-package configs** (`packages` has exactly one entry at `.`) and apply (b) automatically.

Happy to PR (b) or (c) if either is the preferred direction.

### Environment

- Repo: single-package, single-path (`.`), `release-type: node`
- Org: fine-grained PAT requests disabled at org level → classic PAT used
- Action version: `release-please-action@45996ed…` (v5.0.0)
- release-please CLI version (per action log): `17.6.0`
- `package.json#name`: `kujali-chatcare`
- `include-component-in-tag`: `false`
- `include-v-in-tag`: `true`

Contributor guide

Open the contributing guide

Research direction

Start by tracing the release-build and pull-request-build phases for the node strategy, using the component handling shown in the issue. Compare how release-please-config.json, package.json, and the merged PR title are parsed when include-component-in-tag is false. Done means the reproduced single-package workflow tags the merged release PR, creates the GitHub Release, and updates the label without manual intervention.

Written by the indexing model from the issue text.

Assessment

Tech stack
github-actions, node.js, typescript
Domain
ci-cd, devops, release
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.