Skip to content

feat!: always emit dev dependencies with scope=excluded; deprecate --exclude-dev#1044

Open
mtsfoni wants to merge 1 commit intomasterfrom
feat/dev-deps-to-formulation
Open

feat!: always emit dev dependencies with scope=excluded; deprecate --exclude-dev#1044
mtsfoni wants to merge 1 commit intomasterfrom
feat/dev-deps-to-formulation

Conversation

@mtsfoni
Copy link
Copy Markdown
Member

@mtsfoni mtsfoni commented Mar 1, 2026

Summary

Dev dependencies are now always included in the BOM with scope="excluded" rather
than being silently dropped when --exclude-dev is passed. This aligns with the
CycloneDX spec, which expects excluded components to be present but marked as such.

Changes

  • --exclude-dev deprecated — the flag is retained for backward compatibility
    but is now a no-op. Passing it emits a deprecation warning. Planned for removal
    in a future major release.
  • BFS-based scope resolution — replaces the old eager flag-and-filter approach.
    After all packages are loaded, a BFS from direct runtime references determines
    reachability. Packages never reached via a runtime path receive scope=excluded.
    This correctly handles the shared-transitive case: a package reachable from both
    a dev dep and a runtime dep is kept in scope.
  • ProjectAssetsFileService — dev dependency scope is no longer set eagerly;
    test-project exclusions are unaffected.

Breaking Change

Previously, --exclude-dev omitted dev dependency entries from the BOM entirely.
They are now always present with scope="excluded". Consumers that relied on the
flag to suppress those entries from output will see additional components.

Testing

  • Two new functional tests: transitive-only-via-dev and shared-transitive scenarios.
  • Existing dev dependency tests updated to reflect the new always-included behavior.
  • New docs/dev-and-test-dependencies.md documents the behavior and rationale.

…via BFS

Dev dependencies (PrivateAssets=all / developmentDependency=true) are now
always included in the BOM with scope="excluded" — no flag is needed and
--exclude-dev is deprecated (retained as a no-op for backward compat).

The scope is no longer set eagerly at load time for IsDevDependency.
Instead, Runner performs a BFS from direct runtime references after all
packages are loaded:

  - Seeds: direct references that are not dev deps and not already excluded
    by the test-project pass (scope=Excluded set in ProjectAssetsFileService).
  - BFS follows DotnetDependency.Dependencies. Any package reached via a
    runtime path is marked runtime-reachable and its children are queued.
  - Packages never reached by the BFS receive scope=Excluded.

This correctly handles the shared-transitive case: a package reachable
from both a dev dep and a runtime dep stays scope=required because the
runtime BFS path reaches it first.

Adds two functional tests covering the transitive-only and shared-transitive
scenarios, and a new docs/dev-and-test-dependencies.md documenting the
behaviour and the rationale for using scope=excluded.
@mtsfoni mtsfoni force-pushed the feat/dev-deps-to-formulation branch from 2fcd984 to 2ec29ee Compare March 3, 2026 23:14
@mtsfoni mtsfoni changed the title feat: move --exclude-dev packages into formulation instead of droppin… planned breaking feat: move --exclude-dev packages into formulation instead of droppin… Mar 3, 2026
@mtsfoni mtsfoni changed the title planned breaking feat: move --exclude-dev packages into formulation instead of droppin… feat!: always emit dev dependencies with scope=excluded; deprecate --exclude-dev Mar 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant