Skip to content

node-workspace with merge: false: manifest updates go to the first candidate only, and plugin-created PRs are missing the autorelease label #2853

Description

@siamak-tendium

Environment

  • release-please 17.3.0 (bundled in release-please-action v4.4.1), manifest mode
  • Behavior confirmed unchanged by reading the source at v17.10.3
  • Monorepo: pnpm workspace, one shared library plus two services that depend on it via workspace:*
  • Config (trimmed):
{
  "separate-pull-requests": true,
  "plugins": [{ "type": "node-workspace", "merge": false }],
  "packages": {
    "packages/shared": { "release-type": "node", "component": "shared" },
    "services/a": { "release-type": "node", "component": "a" },
    "services/b": { "release-type": "node", "component": "b" }
  }
}

Steps to reproduce

  1. Land releasable commits that touch only packages/shared (the two services have no releasable commits of their own).
  2. Let release-please run. It computes a release for shared, and the node-workspace plugin creates dependency-bump candidates for both services.
  3. Inspect the three resulting pull requests.

Bug 1: all dependency-bump manifest entries are attached to the first candidate only

WorkspacePlugin.run pushes the whole updatedPathVersions map onto newCandidates[0] unconditionally, after the if (this.merge) block:

https://github.com/googleapis/release-please/blob/v17.10.3/src/plugins/workspace.ts#L179-L187

With merge: true this is correct (there is only one merged candidate). With merge: false there are multiple candidates, and newCandidates[0] is simply the first package in the post-order graph walk (in practice the alphabetically first dependent). Result, observed in real runs:

  • Service A's release PR contains the .release-please-manifest.json bump for service A and service B.
  • Service B's release PR contains no manifest update at all (plugin-created candidates only get package.json, package-lock.json and CHANGELOG updates; the per-candidate manifest update from buildPullRequests is only attached to strategy candidates).
  • The library's own PR is fine (strategy candidate).

Consequences depend on merge order and are all bad:

  • Merge A's PR while B's PR is closed or abandoned: the manifest now claims a version of B that was never released (a phantom version). On the next run release-please looks up the tag for that phantom version, cannot find it, and generates a release PR with an unbounded commit range.
  • Merge B's PR: the manifest is not updated, so release-please immediately re-proposes the same version for B in a new PR.

Bug 2: plugin-created candidates get labels: [], so the PRs never receive autorelease: pending

NodeWorkspace.newCandidate builds the pull request with an empty labels array:

https://github.com/googleapis/release-please/blob/v17.10.3/src/plugins/node-workspace.ts#L342

Strategy-built candidates get the configured labels, but dependency-bump-only PRs are created without autorelease: pending. In a run that created three PRs (library plus two dependents), the action log contains exactly one labeling call, for the strategy candidate only:

✔ Successfully added labels autorelease: pending to issue: <n>

Consequences:

  • buildReleases / createReleases filter merged PRs by that label (see findMergedReleasePullRequests), so merging an unlabeled dependency-bump PR silently creates no tag and no GitHub release, and the same version is re-proposed on the next run.
  • findOpenReleasePullRequests also filters by the label, so the open PR is invisible to the bot: it is never force-push refreshed after other merges and stays permanently conflicted.

Expected behavior

With merge: false:

  1. Each candidate PR should carry the manifest entry for its own path (and only that entry).
  2. Plugin-created candidates should receive the same labels as strategy candidates, so tagging and PR maintenance work.

Workaround

We removed the node-workspace plugin and replaced the cascade with a small workflow: when the library publishes a release, the workflow pushes one fix(deps): bump <library> to X.Y.Z commit that touches a marker file inside each consuming service's directory. Path attribution then produces normal strategy-built per-service release PRs with correct labels and manifest lines.

Metadata

Metadata

Assignees

No one assigned

    Labels

    priority: p3Desirable enhancement or fix. May not be included in next release.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions