Loading workspace insights... Statistics interval
7 days30 daysLatest CI Pipeline Executions
d3bf9115 fix(release): scope ambiguous-scope check to active release group's projects (#35745)
## Current Behavior
`nx release --group=<group>` walks the full commit range since the last
matching tag and resolves each commit's conventional-commit scope
against the **entire** project graph (`findMatchingProjects` over
`projectGraph.nodes`). If a scope is ambiguous against *any* projects in
the workspace, Nx throws unconditionally — even when those projects
aren't in the release group currently being processed.
In workspaces with slash-style subpath project names (e.g. a meta
package `@scope/cui` plus subpath packages `@scope/cui/forms`,
`@scope/cui/select`, …), a single commit with a short-form scope like
`fix(cui): …` permanently blocks every release group whose tag-range
includes it — including unrelated groups that don't contain any of the
matching projects.
Closes #35744.
## Expected Behavior
The ambiguity check should be scoped to the active release group's
projects. A scope that only collides with projects *outside* the group
should fall through to the file-affectedness path that's already used
when a commit has no scope at all.
## Fix
In `getCommitsRelevantToProjects`, `projects: string[]` (already in the
function signature as the active release group's projects, materialized
as `projectSet` at the top) is now applied to the per-pattern ambiguity
check and to the `scopedProjects` set:
1. **Per-pattern check filters to the group.** `inGroupMatches =
perPatternMatches.filter(p => projectSet.has(p))`. Throw only when
`inGroupMatches.length > 1` — ambiguity *within* the group is still a
real error.
2. **`scopedProjects` is intersected with the group.** Cross-group
matches no longer bleed into `isProjectScopedCommit` downstream.
When the filtered set is empty or singleton, the commit is treated
identically to a commit with no scope for this group's processing —
`isProjectScopedCommit` falls back to `false` for projects whose
`affectedGraph` includes them via files, matching the existing
scope-less behavior.
## Tests
`packages/nx/src/command-line/release/utils/shared.spec.ts`:
- **Existing test for in-group ambiguity** (`should throw when commit
scope matches multiple projects (ambiguous scope)`) — converted from a
`try { … } catch (err) { expect(…) }` pattern (which silently passed if
no throw happened) to `await expect(…).rejects.toThrow(…)`. Existing
behavior preserved: throws when `@foo/graph` + `@bar/graph` are both in
the active group with scope `graph`.
- **New test for cross-group ambiguity** — active group `['lib-a']`,
scope `graph` matches `@foo/graph` + `@bar/graph` (both outside the
group). No throw. Commit is included via file-affectedness,
`isProjectScopedCommit: false`.
- **New test for partial cross-group ambiguity** — active group
`['@foo/graph']`, scope `graph` matches `@foo/graph` (in group) +
`@bar/graph` (out). Filtered to one match. No throw, treated as scoped
to `@foo/graph` (`isProjectScopedCommit: true`).
Also extended `createMockCommit` to accept an explicit `scope` argument
so tests actually exercise the scope-parsing path. The existing
ambiguity test relied on `feat(graph): …` in the commit *message*, but
`commit.scope` itself was hardcoded to `''`, so `scopePatterns` was
always empty and the throw never fired in the test — the assertion lived
in a catch block that was never reached. The conversion to
`rejects.toThrow` plus the explicit `scope` argument makes the original
test actually verify what its name says.
## Verification
```
pnpm exec nx test nx --testPathPatterns=shared.spec
# Tests: 38 passed, 38 total
pnpm exec nx test nx --testPathPatterns="release"
# Tests: 1 skipped, 503 passed, 504 total
pnpm exec nx lint nx
# 0 errors (2 pre-existing warnings, unrelated)
```
Minimal real-world repro repo:
https://github.com/jmclellan-crexi/nx-release-scope-ambiguity-repro
## PR Checklist
- [x] Bug-fix only — no API surface changes
- [x] Tests added for new behavior + existing test converted to assert
what it claims
- [x] Backwards compatible — in-group ambiguity still throws; scope-less
commits unchanged; unambiguous scopes unchanged
- [x] No documentation changes needed (behavior is now closer to what
the existing docs imply)
---------
Co-authored-by: Justin McLellan <jmclellan@beast>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>