Repository navigation
ci: restore with NuGet lock files and cache the packages folder - #1293
Merged
github-actions[bot] merged 1 commit intoOct 15, 2026
Merged
github-actions[bot] merged 1 commit into
github-actions[bot] merged 1 commit into
Conversation
Turns RestorePackagesWithLockFile on at the root and commits a lock file for every project except the two MAUI heads, whose restore graph changes with the runtime identifier. The pull request dotnet job and the nightly run restore in locked mode, and setup-dotnet caches the NuGet folder keyed on the lock files. Guideline ADR 0002 records the heads exception; architecture tests pin the rules. Decision taken without asking: lock everything but the heads rather than normalising the heads' runtime identifiers; the alternative is named in the pull request and in ADR 0002. Refs #748 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 15, 2026
JSdotNet
marked this pull request as ready for review
October 15, 2026 18:08
JSdotNet
added a commit
that referenced
this pull request
Oct 15, 2026
…2026-10-15/753-credentials-at-rest Keeps both sides of the ADR list and related: conflicts (ADR 0030 beside main's ADR 0029/0031 and the Sync context's moved pairing anchors), and regenerates the packages.lock.json files main's #1293 committed, which the ProtectedData references this branch adds made stale. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #748
Summary
Finishes the last open part of item 4.
RestorePackagesWithLockFileis on in the rootDirectory.Build.props, and 85packages.lock.jsonfiles are committed — everyBacklog.slnproject except the two MAUI heads, which opt out in their own csproj. The pull requestdotnetjob andnightly-tests.ymlrestoreBacklog.WithoutAppHeads.slnfwith--locked-mode(NU1004 on drift), andsetup-dotnetin both workflows caches the NuGet folder keyed on**/packages.lock.json. The release and deploy workflows stay unlocked and uncached.BuildPolicyTestsandContinuousIntegrationWorkflowTestspin all of it, and guideline ADR 0002 records the heads exception and the alternative. Items 1–3 were already on main (#808, #936).Decision taken without asking (follow it, or ask for the alternative)
Question. How should NuGet lock files and the setup-dotnet cache handle the MAUI heads, whose restore graph depends on the runtime identifier, and which CI jobs should enforce and cache them?
Chosen. Lock files for every Backlog.sln project except the two MAUI heads. The root Directory.Build.props turns the property on, and each head csproj turns it off explicitly. Restore in locked mode only in the two jobs that restore Backlog.WithoutAppHeads.slnf on windows-latest: the PR
dotnetjob and nightly-tests.yml. Setcache: trueon setup-dotnet in pull-request.yml (both jobs) and nightly-tests.yml. Leave the release and deploy jobs uncached and unlocked.Alternative. Per-RID handling. Give the heads lock files too and normalise their restore inputs: declare a fixed RuntimeIdentifiers list in each head (win-x64 for Desktop, the Android RIDs for Mobile). Replace the app-heads job's
-r win-x64second restore with a single RuntimeIdentifierOverride restore. Run every head restore, the release workflows included, in locked mode, so all 87 projects are locked.Why the choice. The heads are where restore inputs vary today. The Desktop head is restored once with RuntimeIdentifierOverride=win-x64 and once with
-r win-x64(pull-request.yml app-heads job), and published with an override and MSIX properties in release-desktop.yml. The Android head pulls in the Android RuntimeIdentifiers and is restored on ubuntu in release-mobile.yml. Locking them means changing how the release pipelines restore, inside a change whose stated value is reproducible test restores and a faster PR run. The heads have no tests and sit outside the test suite's restore. The 85 non-head projects are what the PR and nightly suites restore, and they are what the cache speeds up. Locked mode belongs only where the restore inputs are fixed: Backlog.WithoutAppHeads.slnf on windows-latest x64. That runner matches the win-x64 host RID the AppHost's implicit Aspire.Dashboard.Sdk.* and Aspire.Hosting.Orchestration.* references record (Aspire.AppHost.Sdk 13.6.1 Sdk.targets lines 194-195). The app-heads job's global-r win-x64would flow into the referenced projects and fail their lock files, so that job stays unlocked. Release and deploy jobs stay uncached so a stale or poisoned cache cannot reach a shipped artifact.To follow the alternative instead. For the alternative, the PR would also need: a RestorePackagesWithLockFile opt-in and explicit RuntimeIdentifiers in both head csproj files instead of the opt-out; two committed head lock files; app-heads restores reduced to one RID-consistent restore per head with
--locked-mode; locked-mode restores, and probably caches, added to release-desktop.yml and release-mobile.yml; the ArchitectureTests changed from 'heads opt out' to 'every project has a lock file'; and ADR 0002's deviation entry for the heads removed.Acceptance criteria
dotnet restore Backlog.WithoutAppHeads.slnf --locked-modesucceeds with no NU1004, and a second plain restore leaves the lock files unchanged — not proved by a test: Verified by hand: locked-mode restore exit 0; the combined SHA1 of the 85 lock files stayed the same after a plain restore, a --force-evaluate restore and a full Backlog.sln restoredotnet test --solution Backlog.slnreported 16269 total but 5, then 2, Desktop.UI timing tests failed under load; that module passes alone (5134/5134).node .devbook/_tools/devbook-meta/build.mjs --checkandnode tools/devbook/check-metadata.mjsboth pass — not proved by a test: Both run in the worktree: exit 0, 0 blocking (advisory warnings were already there)Fixes #748— not proved by a test: Not done here: this worker must not commit or open a PR; left to the owning sessionTesting
cd "D:/iswp/748-nuget-lock-files-ci-cache" && dotnet build Backlog.sln -nologo -v:minimal && dotnet test Backlog.sln --no-builddotnet test tests/Backlog.Desktop.UI.UnitTestsre-run — 5134 passed, 0 failed (the three failures in the workflow's run were bUnit timing flakes in Devbook pane and search tests this change does not touch). Both devbook checks pass.Review
cache: truewith the same**/packages.lock.jsonkey as thedotnetjob, but the packages it restores are not in those lock files. Both jobs run on windows-latest, so they compute the same cache key and race to save it. Which one wins decides what the cache holds.- name:at six-space indent as a step start. The existing helper also accepts- uses:items at any indent.Assert.Equal(2, SetupDotnetSteps(Workflow(PullRequestWorkflow)).Count)fixes how many setup-dotnet steps pull-request.yml has, which is a detail of the current file and not the rule being tested. Suppose a later PR adds a third .NET job to pull-request.yml and gives its setup-dotnet stepcache: trueand the lock-file path correctly. The cache rule is still met, but this fact fails.What could not be proved
Backlog.Desktop.UI.UnitTestsbUnit timing/render-order failures (DevbookSearchViewMeaningTests.Only_the_latest_question_is_drawn, twoHomeDevbookPaneTests). The whole project passed on a re-run (5134/5134), and every test the change touches (BuildPolicyTests,ContinuousIntegrationWorkflowTests) passed in the original run.--locked-modeholds on the windows-latest runner can only be proved by this pull request's own CI. The lock files were written on one Windows x64 machine; the AppHost's lock file stays free of host runtime identifiers only whileAspireUseCliBundleis on. Watch thedotnetjob's restore for NU1004.package-updateschedule's pull requests do too, or their locked-mode restore fails.Merge Danger
Door. Two-way: a revert removes the lock files and the locked-mode flag. Nothing persisted outside the repository changes; a GitHub Actions cache entry simply goes unused.
Blast radius. repository — every pull request's
dotnetjob and the nightly run; a stale lock file now fails CI instead of building.Assumptions taken instead of asking
cache: truewith the defaultcache-dependency-path(**/packages.lock.json) and finds the lock files from the repository root. If the default differs, setcache-dependency-path: '**/packages.lock.json'explicitly. Check this against the action's README at the pinned SHA.dotnet restore Backlog.Desktop.csproj -r win-x64rewrites the lock files of the projects the head references, adding a net10.0/win-x64 section. That is why the app-heads job stays unlocked. On the runner the rewrite is harmless. A developer who runs that-r win-x64restore locally gets modified lock files, which a plaindotnet restore Backlog.WithoutAppHeads.slnfputs back exactly (verified by hash). The AppHost's AddProject for the desktop head passes no runtime identifier, soaspire startdoes not cause this.dotnetandapp-headsjobs both run on windows-latest and compute the same cache key. Whichever job saves first wins, so the other job may restore from a partial cache; NuGet just downloads what is missing. The heads' own packages (MAUI, Android) are not in any lock file, so a bump to a head-only package does not change the key. Both effects only cost speed.dotnet test --solution Backlog.slnfailures were Backlog.Desktop.UI.UnitTests timing tests, most marked 'canceled'; a different set failed on each of two runs. I treated them as known load-dependent flakes unrelated to this change: the module passes alone (5134/5134), and the CI-equivalent serial run passes 16256 tests with 0 failures. I did not run a baseline on main to confirm they also flake there.Fixes #748in the commit and PR) is left to the owning session, because this worker was told not to commit or create a PR.Opened as a draft by an attended run of
delivery-schedule:schedule-issue-sweep(2026-10-15), told by the owner to decide without asking and to name the choice and the alternative.🤖 Generated with Claude Code