Skip to content

feat(scripts): detect modified-but-unreleased dependencies during release#436

Open
sandersaares wants to merge 106 commits into
mainfrom
feat/release-deps-upstream-scan
Open

feat(scripts): detect modified-but-unreleased dependencies during release#436
sandersaares wants to merge 106 commits into
mainfrom
feat/release-deps-upstream-scan

Conversation

@sandersaares
Copy link
Copy Markdown
Member

@sandersaares sandersaares commented May 20, 2026

Problem

When releasing a workspace package, an author may have also modified one of its workspace dependencies but forgotten to release that dependency. Locally everything builds via path-references, but once published the released package resolves against the last released version of each dependency on crates.io — missing the new changes. The dependency-side modification may even have landed in a previous PR that merged to main without a version increment, so a plain "diff vs PR base" check is not enough to catch it.

What changes for the user

Dependency review during release

release-packages.ps1 now scans the dependency graph of every package in the release plan and surfaces every workspace dependency with unreleased modifications — evaluated per package against that dependency's own last version = / publish = commit, not against the PR base. For each finding the user can view the diff, skip the package, or release it alongside the original target.

Multi-package releases are now atomic

Previously the script handled one package per invocation, with cascade decisions surfaced incrementally across re-runs. The new driver takes the entire release plan up-front:

./scripts/release-packages.ps1 -Packages 'bytesbuf@breaking','bytesbuf_io@nonbreaking'

After plan review, all writes — Cargo.toml version increments, CHANGELOG.md entries, README.md regeneration, workspace [workspace.dependencies] updates — happen in one shot, followed by a workspace cargo check. Two guided alternatives are available when you don't have the full list ready up-front: -Changed (walk every package with unreleased modifications) and -All (walk every publishable package, modified or not).

Semantic change type instead of numeric version components

The previous -Bump major|minor|patch CLI conflated numeric version-string components with semantic intent — and they are not interchangeable: a breaking change on a 0.x package moves the minor component, on a >=1.x package the major component. The new change-spec is a semantic label per package: breaking, nonbreaking, or patch. Users who want to pin an exact target can do so explicitly — foo@1.0.0, bar@1.0.0-rc.1 — with full SemVer 2.0 (three numeric components plus optional pre-release / build metadata) accepted.

If the cascade computes a stronger change type than the user requested (e.g. the user said patch but the dependent exposes a breaking-changed dependency in its public API), the change type is auto-upgraded and the upgrade is shown in the plan display. Explicit version pins are not silently overridden — by default the plan is rejected; the new -Force switch overrides this when the pin really is intentional.

Breaking changes for tooling muscle memory

  • scripts/release-crate.ps1 is removed; use scripts/release-packages.ps1.
  • -Bump major|minor|patch is gone; supply -Packages '<name>@<change-spec>', ... instead.
  • A Crate*Package* symbol rename swept the release tooling (release-record property, function names, log strings). Cargo's own terminology (crates/, crates.io, Cargo.toml, cargo metadata) is preserved verbatim.

Documentation and tests

Release vocabulary, workflow, and invariants now live in docs/releasing.md; AGENTS.md shrinks to a list of pointers. A Pester suite under scripts/tests/Pester/ covers pure helpers, BFS / aggregation analyses on synthetic workspaces, and agent-driven end-to-end interactive scenarios. Runs locally via just test-scripts and on Windows + Linux in the script-tests CI job.

sandersaares and others added 2 commits May 20, 2026 14:44
…lease

When releasing a crate, an author may have also modified one of its upstream
workspace dependencies but forgotten to release the dependency too. Locally
everything builds via path-references, but once published the released crate
resolves to the last released version on crates.io, missing the new changes.

This adds two layers of automation:

1. Interactive layer (release-crate.ps1):
   After the existing downstream cascade finishes, scan the release set for
   transitive workspace dependencies that have file changes vs the PR base ref
   but are not themselves being released. Prompt the author (y/N + bump kind)
   for each finding so material changes get an extra release queued, while
   immaterial changes (formatting, doc tweaks) can be declined.

2. CI layer (scripts/check-unreleased-dependencies.ps1 +
   .github/workflows/main.yml release-deps job):
   Runs the same analysis non-interactively and posts a sticky PR comment
   listing any findings so reviewers can sanity-check materiality decisions.

Shared logic lives in the new scripts/lib/releasing.ps1 library, dot-sourced
by both entry-point scripts. Workspace dependency types kind=normal and
kind=build are tracked; kind=dev is excluded (cannot affect downstream
consumers via crates.io). Cascade re-bump is idempotent: re-cascading into a
crate already at a sufficient version appends a maintenance bullet to its
existing changelog section instead of double-bumping.

The .delta.toml Cargo.toml trip-wire is documented as a dependency of the
release-deps CI gate so any version bump touches Cargo.toml -> skip=false.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Migrate the three remaining Invoke-GitCommand callsites in release-crate.ps1
(tag --list, git log, remote get-url) to the array-argument Invoke-Git wrapper
in releasing.ps1, then delete the legacy wrapper. Removes the last use of
Invoke-Expression-based git invocation in the release tooling.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented May 20, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.0%. Comparing base (bf1ba72) to head (d1b2184).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #436   +/-   ##
=======================================
  Coverage   100.0%   100.0%           
=======================================
  Files         335      335           
  Lines       25586    25586           
=======================================
  Hits        25586    25586           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ralfbiedert
Copy link
Copy Markdown
Collaborator

Whops, I missed the draft on this

sandersaares and others added 2 commits May 21, 2026 13:53
The release-deps job previously depended on the delta job and used
`delta.outputs.skip != 'true'` as a compute optimization to skip the
analysis when no crate was affected. The optimization was structurally
fragile - it relied on the implicit invariant that Cargo.toml and
scripts/* remain in .delta.toml's trip_wire_patterns - and only saved a
few seconds when there are no findings.

Drop both the needs: [delta] dependency and the delta.skip gate. The
check-unreleased-dependencies.ps1 script already exits fast (no
findings -> no markdown, no comment) when there is nothing to report,
so always running it is safe and simple.

Also remove the corresponding NOTE in .delta.toml since that
dependency no longer exists.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@sandersaares sandersaares marked this pull request as ready for review May 21, 2026 11:06
Copilot AI review requested due to automatic review settings May 21, 2026 11:06
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR strengthens the workspace crate release tooling by detecting “modified-but-unreleased” upstream workspace dependencies that could be missed when publishing to crates.io, and surfaces the same signal in CI via a new informational job.

Changes:

  • Extracts shared release/dependency-graph and git helper logic into a dot-sourced PowerShell library (scripts/lib/releasing.ps1).
  • Extends scripts/release-crate.ps1 to (optionally) scan for modified-but-unreleased upstream workspace deps after the existing downstream cascade, with interactive prompting to release them.
  • Adds a CI-only analyzer script and a new workflow job that posts/removes a sticky PR comment when such unreleased upstream dependency changes are detected.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
scripts/release-crate.ps1 Adds base-ref/non-interactive options, refactors cascade flow, and performs a post-release upstream dependency scan.
scripts/lib/releasing.ps1 New shared library providing safe git invocation, SemVer helpers, workspace metadata, and unreleased-dependency analysis.
scripts/check-unreleased-dependencies.ps1 New CI companion script that emits a markdown report + step output for unreleased upstream dependency changes.
.github/workflows/main.yml Adds release-deps job to run the CI analyzer and post/remove a sticky PR comment.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread scripts/release-crate.ps1 Outdated
Comment thread scripts/check-unreleased-dependencies.ps1 Outdated
- release-crate.ps1: drop -AllowFailure on the fetch in the base-ref resolver
  so the surrounding try/catch can actually trigger and emit a warning on fetch
  failure (previously the catch was unreachable because -AllowFailure returns
  $null instead of throwing).

- check-unreleased-dependencies.ps1: route Get-RepoRoot through Invoke-Git
  instead of shelling out directly, matching the design described in the PR.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 21, 2026 12:14
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

Comment thread scripts/release-crate.ps1 Outdated
sandersaares and others added 2 commits May 21, 2026 15:33
…rades them

When the post-release dep scan runs a nested `Invoke-ReleaseFlow` for an
upstream crate the user opts to release, the resulting cascade may upgrade a
crate that was already in the release set (e.g., the initial release patch-bumped
`foo` and the nested major release of an upstream dep now requires a major on
`foo`). Previously the merge skipped duplicates outright, so `Show-ReleaseSummary`
and the final `feat(crate): release v<version>` message reported a stale
version that did not match what was actually written to `Cargo.toml`.

Replace the skip-on-duplicate logic with an in-place update: keep the original
`OldVersion` (the pre-PR baseline) and adopt the latest `NewVersion` from the
nested cascade. New crates are still appended as before.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The previous logic compared the working tree against the PR base ref to
decide which workspace crates had unreleased modifications. That missed a
real scenario: an earlier PR merges a source change to `bytesbuf` without
bumping its version, and a later PR bumps `bytesbuf_io` (which depends on
`bytesbuf`). On crates.io the published `bytesbuf_io` resolves to the last
released `bytesbuf`, which does *not* include the unreleased modification.
Because the modification predates the PR's base ref, the old `BaseRef`-
relative scan saw nothing to flag.

Switch each crate's "modification baseline" to its own most-recent commit
that touched `version =` or `publish =` in its `Cargo.toml`, derived via
`git log -1 -G '^(version|publish)\s*='`. Any change under `crates/<folder>/`
newer than that commit (committed, working-tree, or untracked) is treated
as unreleased.

`Get-CratesWithVersionBumps` (release-set detection) intentionally still
diffs against the PR base ref — that's the correct anchor for "what is this
PR releasing".

Replaces `Get-GitFileChangeSet` / `Get-CratesWithFileChanges` with the new
`Get-CrateLastReleaseBaseline` + `Get-CratesWithUnreleasedChanges` helpers
and rewrites `Get-UnreleasedModifiedDependencies` to consume the per-crate
modification map.

Also persists the manual test plan as `scripts/RELEASE-DEPS-TEST-CASES.md`
so future agents can re-run T1-T16 (original PR-vs-base coverage) and
N1-N10 (multi-PR baseline coverage) when the logic changes. All N1-N9
scenarios were verified in a scratch worktree before this commit; N10
(brand-new crate) is structurally covered by the new-crate branch in
`Get-CratesWithVersionBumps`.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 21, 2026 14:54
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Comment thread scripts/check-unreleased-dependencies.ps1 Outdated
Comment thread scripts/release-crate.ps1 Outdated
sandersaares and others added 2 commits May 21, 2026 18:32
Two real defects flagged on the latest review pass:

1. `check-unreleased-dependencies.ps1` was supposed to alphabetically sort
   the release-set listing in the sticky PR comment, but the chain
   `@(Get-CratesWithVersionBumps ...) | Sort-Object` silently broke. The
   helper returns its HashSet via `Write-Output -NoEnumerate` so callers
   can use `.Contains()`. That wrapping makes `Sort-Object` receive a
   single object (the HashSet itself), so the sort is a no-op and the
   foreach below iterates the HashSet in insertion order. Fixed by
   unwrapping with `... | ForEach-Object { $_ }` before sorting.

2. `Add-CascadeBulletToVersionSection`'s `if ($subStart -ge 0)` branch
   built the new file content with
   `@($lines[0..($insertAt - 1)]) + @($bullet) + @($lines[$insertAt..($lines.Count - 1)])`.
   When `$insertAt` equals `$lines.Count` (target sub-header is the last
   content in the file, no bullets yet, no trailing blank lines), the
   right-hand slice becomes `$lines[N..N-1]` which is a reverse-range that
   silently aliases to the last element — so the last line was duplicated.
   Reproduced on a synthesised changelog before fixing. Mirrored the EOF
   guard that the `else` branch already has.

Verified by direct PowerShell repros for both: sort now yields
alphabetical order, EOF insertion no longer duplicates the sub-header
line, and the non-EOF + idempotency paths are unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Anticipates a future home for other script-related test material. The doc
is unchanged; only its location moves. References inside the doc point at
other scripts (`scripts/lib/releasing.ps1`, `scripts/release-crate.ps1`,
`scripts/check-unreleased-dependencies.ps1`) from the repo root and remain
valid after the move.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 22, 2026 04:56
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Comment thread scripts/check-unreleased-dependencies.ps1 Outdated
Comment thread .github/workflows/main.yml Outdated
Comment thread scripts/release-crate.ps1 Outdated
Comment thread scripts/tests/RELEASE-DEPS-TEST-CASES.md Outdated
sandersaares and others added 2 commits May 22, 2026 08:13
…e set

Documentation drift after the per-crate baseline refactor (cedd750). Four
Copilot review comments on PR #436 flagged that synopses, parameter docs,
and the user-facing PR-comment / interactive-warning text still said
"modified vs the PR base ref" — but only the release-set anchor uses
BaseRef; modifications are evaluated per crate against each crate's own
last `version =` / `publish =` commit.

Updated:
- `scripts/check-unreleased-dependencies.ps1` — synopsis, description,
  BaseRef parameter docs, and the markdown body line ("unreleased
  modifications — changes newer than their last `version =` or `publish =`
  bump").
- `scripts/release-crate.ps1` — BaseRef parameter comment, the
  `Invoke-PostReleaseDepScan` function docstring, and the interactive
  warning text. (Switched the warning from a `"..."` to a `'...'` literal
  so the inline `` `version =` `` / `` `publish =` `` backticks aren't
  interpreted as PowerShell escape sequences — `` `v `` is vertical tab.)
- `.github/workflows/main.yml` — `release-deps` job comment.

Self-reviewed the rest of the PR diff for similar drift; the remaining
"vs base" mentions (release-set BFS docstring, "Fetch base ref" workflow
step name, "What this means" sticky-comment block) are legitimate and
unchanged. Re-ran N1-N9 against the updated scripts in a scratch worktree:
9/9 pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Capture the non-obvious lessons learned while building the N-series
and T-series test harnesses, so future maintainers/agents who need to
rebuild a harness from scratch don't have to relearn them.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 55 out of 55 changed files in this pull request and generated no new comments.

The change detection that powers -Changed (and the snapshot used for
elevation review under -Packages) is scoped to files under
`crates/<package>/`. Modifications elsewhere in the repository — the
workspace-level Cargo.toml, .cargo/, deny.toml, shared CI workflows,
top-level scripts — are invisible to the scan even when they affect
how a package builds or behaves.

Document this in three places so the limitation cannot be missed:

* `scripts/release-packages.ps1` — Description block for -Changed mode
  and the `.PARAMETER Changed` help entry.
* `docs/releasing.md` — both the top-of-document `-Changed` bullet and
  the dedicated "Guided modes" section.

Each note cross-references `-All` (which surfaces every publishable
package regardless of detected changes) and `-Packages` (which lets the
user list affected packages explicitly) as the two correct mitigations
for cross-cutting changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@sandersaares sandersaares marked this pull request as ready for review June 5, 2026 06:42
Copilot AI review requested due to automatic review settings June 5, 2026 06:42
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 55 out of 55 changed files in this pull request and generated 1 comment.

Comment thread scripts/lib/check-unreleased-deps.ps1 Outdated
sandersaares and others added 2 commits June 5, 2026 11:52
We do not need to support Windows PowerShell 5.1. Declare a hard
floor of PowerShell 7.0 on every release-tooling script introduced
by this PR so the version expectation is explicit and machine-
checked at parse time.

Files updated with `#Requires -Version 7.0` immediately after the
copyright header (before any comment-based help):

* `scripts/release-packages.ps1`
* `scripts/check-unreleased-dependencies.ps1`
* `scripts/tests/Pester/Run-Tests.ps1`
* `scripts/lib/releasing.ps1`
* `scripts/lib/release-flow.ps1`
* `scripts/lib/check-unreleased-deps.ps1`

`#Requires` is honored both in scripts that are invoked directly
and in scripts that are dot-sourced; dot-sourcing a library that
declares a minimum version into an interpreter that does not meet
it fails fast with a clear diagnostic, which is what we want.

Drop the `-Encoding utf8` arguments from the two `Add-Content` /
`Set-Content` calls in `scripts/lib/check-unreleased-deps.ps1`
that wrote to `$env:GITHUB_OUTPUT` and `$OutputFile`. PowerShell 7
defaults `*-Content` cmdlet encoding to `utf8NoBOM`, which is
exactly the format GitHub Actions wants; the explicit argument
was redundant. Also rewrite the now-misleading comment block at
the top of `Set-StepOutput` that justified the explicit encoding
with a claim about Windows PowerShell 5.1 BOM defaults — the
`-LiteralPath` rationale is preserved and the encoding rationale
is recast as "PS 7 already defaults to utf8NoBOM".

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 5, 2026 09:36
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 55 out of 55 changed files in this pull request and generated no new comments.

sandersaares and others added 2 commits June 5, 2026 12:55
The skipped placeholder asserted that Invoke-PlanReview throws a
"no progress" diagnostic when an iteration body completes without
mutating any of {userTokens, declined, reviewedCascadeAsIs}. After
auditing the current control flow, that branch is genuinely
unreachable from any well-formed caller:

* an empty findings queue early-returns before the next iteration's
  signature check runs;
* `Get-PackageReleaseDecision` only returns 'ignore' or one of
  {'breaking', 'non-breaking', 'patch'};
* ignore always adds to `declined` or `reviewedCascadeAsIs`;
* accept always appends a token to `userTokens`;
* the switch's `default` arm throws "Internal error" on any other
  action — never falling through to the loop body's tail.

A unit test would therefore have to inject a buggy state via mocks
that no real caller can produce — a tautology that adds no signal.
Drop the placeholder so the suite reports zero skipped tests instead
of carrying a permanent "(1 skipped)" footnote that hides any
genuinely-skipped regression in the future.

The signature-progress check itself is retained in production code
as defense-in-depth: a future change that introduces a
state-leak path (e.g. a new `continue`-without-mutate branch) will
abort with a clear diagnostic instead of silently spinning to the
runaway cap. The inline comment on the check is rewritten to
acknowledge the unreachable-but-defensive nature; a sibling comment
in PromptFlow.Tests.ps1 documents why the test was removed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…eview

Add the two specific tests the test-suite review identified as the
highest-priority gaps. Both pin contracts that unit-level coverage of
the individual helpers cannot demonstrate — they require driving the
production entry points end-to-end.

C1 — atomic multi-package on-disk product (integration test)

Releasing-Integration.Tests.ps1 gets a new Describe block that calls
Invoke-ResolvedRelease directly with a hand-built two-package plan
(upstream user-source non-breaking → 0.2.1, downstream cascade-source
→ 0.1.1) and asserts every per-folder side effect:

 * package Cargo.toml × 2 — new [package] version line written, old
   line gone, other fields preserved
 * workspace root Cargo.toml — both [workspace.dependencies] inline
   versions updated, neither old version remains
 * CHANGELOG × 2 — new ## [version] - <date> section prepended, top-
   level # Changelog preserved, manually-curated ## [Unreleased] body
   folded into the new section, conventional-commit bullets present
 * downstream CHANGELOG — cascade-from-dependency bullet emitted
   (🔧 Maintenance / Now requires `0.2.1` of `upstream`)
 * Update-Readme — mocked and asserted invoked once per release-set
   member with the right -packageName argument

Closes the "wrote Cargo.toml but skipped CHANGELOG/README" regression
mode the review highlighted: previously, that regression would only
have been observable through the returned Releases array, which lies
about disk state.

C2 — -Force end-to-end via the scenario harness

Invoke-Scenario.ps1 grows Run.Force support in the targeted branch
(splatted through to Invoke-ReleasePackagesMain). The changed/all
branches throw if Force is set, mirroring the production parameter-
validation rule that -Force is only valid with -Packages.

S24-pin-with-cascade-conflict-force.scenario.psd1 mirrors S14 (same
two-package workspace, same pin that conflicts with cascade) but sets
Run.Force = $true. Where S14 asserts the resolver throws, S24 asserts
the run completes with the explicit pin honoured verbatim (target
2.0.0, dependent 1.0.1 — below cascade's >=2.0.0 requirement). Closes
the gap that -Force had only unit coverage (of Resolve-ReleaseSet);
no test previously proved the CLI switch was plumbed all the way from
Invoke-ReleasePackagesMain through Invoke-PlanReview into the
resolver.

Pester: 390 / 0 / 0 (was 388 / 0 / 0).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 5, 2026 10:39
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 56 out of 56 changed files in this pull request and generated 1 comment.

Comment thread scripts/tests/Pester/scenarios/S00-smoke-fresh-release.scenario.psd1 Outdated
sandersaares and others added 2 commits June 5, 2026 14:06
Reviewer noted S00 was the only scenario whose internal `Name` field
diverged from its file base name. Pester's per-scenario It display
name is derived from the file base name (Scenarios.Tests.ps1) while
workspace paths and error messages use the scenario `Name` field
(Invoke-Scenario.ps1); the mismatch made failure messages slightly
harder to correlate.

Surveyed the full `scenarios/` directory; S00 was the only mismatch.
Rename the internal field to `S00-smoke-fresh-release` and fold the
descriptive `-no-cascade` qualifier into the Description so the
extra detail isn't lost.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 5, 2026 11:37
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 56 out of 56 changed files in this pull request and generated 1 comment.

Comment thread scripts/release-packages.ps1 Outdated
sandersaares and others added 3 commits June 5, 2026 17:09
…-root filter

The unreleased-deps check was intended to run both interactively (during
`release-packages.ps1`) and at CI time as an informational PR comment.
Surface-level the two flows look symmetric, but they make different
"what counts as a release-set member" assumptions: the interactive flow
knows when a release-set entry is cascade-source-with-no-mods (and can
correctly skip it as a BFS root, since such a member cannot have started
consuming any new dep features), while the CI-time approximation derived
the release set purely by diffing version bumps against the PR base ref
and had no way to distinguish cascade vs user-source entries — leading
to systematic false positives on every cascade-bumped package whose
dependencies happened to have unrelated edits in the same PR.

Rather than ship a check whose precision we cannot match between the
two flows, the CI scope is deferred until we have a more foolproof
architecture (one that does not depend on diffing package directories
against `main`). The interactive scan remains the source of truth.

Concrete changes:

* `.github/workflows/main.yml`: remove the `release-deps` job and its
  reference in any documentation that listed it.
* `scripts/check-unreleased-dependencies.ps1`,
  `scripts/lib/check-unreleased-deps.ps1`,
  `scripts/tests/Pester/unit/check-unreleased-deps/`: deleted.
* `scripts/lib/releasing.ps1` — `Get-UnreleasedModifiedDependencies`:
  apply the LIVE-flow filter as a default precondition on BFS root
  selection. A release-set member only counts as a BFS root when it
  also has source modifications past its per-package baseline.
  Pure-cascade members (version bump only, no source changes of their
  own) are categorically incapable of producing real findings via BFS,
  only false positives, so they are skipped.
* `scripts/lib/releasing.ps1` — Phase B sweep: generalise from
  `-IncludeAllModifiedAsRoots`-gated (iterating `modifiedMap.Keys`) to
  always run over `$rootFolders`. This is the only way to preserve
  Invariant B (release-set elevation review) for leaf-position release-set
  members once the LIVE filter is applied — without it, a release-set
  leaf with own mods could no longer surface for elevation because no
  other release-set member would BFS to it.
* Doc comments (`releasing.ps1`, `release-flow.ps1`, `AGENTS.md`,
  `docs/releasing.md`): strip references to the CI check.
* Existing tests updated for the LIVE filter precondition: the
  release-set member used as a BFS root now needs its own
  `ModifySource('<member>')` to qualify. Topology-Presets contexts and
  Releasing-Integration tests (N1, N2, N4, N5, N6, N8, N9, N10, T16-style,
  "tags non-release-set findings", "uses caller-provided snapshot",
  "returns no findings when snapshot is empty", "behaves identically with
  or without switch", and the WorkspaceDependencyChains tests) updated
  accordingly. Scenarios S02, S03, S05, S07, S08, S09, S10, S11 each gain
  a `ModifySource('<release-target>')` History op so the post-release
  scan still has a BFS root.
* New Describe block in Releasing-Integration.Tests.ps1
  ("Get-UnreleasedModifiedDependencies: LIVE-flow BFS-root filter"):
  four It blocks pinning the filter's contract for cascade- and
  user-source release-set members, with and without own modifications.

Result: 367 Pester tests pass; `just spellcheck` clean.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 5, 2026 14:30
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 53 out of 53 changed files in this pull request and generated no new comments.

sandersaares and others added 2 commits June 5, 2026 18:02
…ges.ps1

Examples used .\release-packages.ps1, which only works after cd'ing into scripts/. Use ./scripts/release-packages.ps1 (cross-platform in pwsh) so the examples are runnable from the repo root, matching the rest of the documentation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

5 participants