From a39b25c4174e4ff7405a610bf01d08a72ee99944 Mon Sep 17 00:00:00 2001 From: fpellet Date: Sun, 8 Nov 2026 19:35:06 +0100 Subject: [PATCH 1/2] fix: leave the load scripts to the restore after paket update --no-install With generate_load_scripts: true, paket update --no-install generated the load scripts from the packages folder, which --no-install doesn't download. It failed with "Folder ... doesn't exist. Did you restore group Main?" when a package of the new paket.lock wasn't there, as on a fresh checkout or for a package that the update adds, and wrote the scripts from the packages of the old lock when versions changed. As --no-install doesn't write the restore cache, the next restore sees the new lock, downloads the packages and generates the scripts. Fixes #2785 --- RELEASE_NOTES.md | 1 + .../LoadingScriptGenerationTests.fs | 16 ++++++++++++++++ src/Paket.Core/Installation/UpdateProcess.fs | 4 +++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index b37598483f..61e8a55393 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,6 +1,7 @@ #### Unreleased * `paket pack --symbols` no longer fails on a project with Compile entries without an `Include` or `Update` attribute, such as `` or a Compile item definition in an `ItemDefinitionGroup`, and leaves out of the symbols package the files that a Remove names without wildcards - https://github.com/fsprojects/Paket/issues/4222 +* `paket update --no-install` no longer fails when a group has `generate_load_scripts: true` and the packages of the new paket.lock aren't all restored, as on a fresh checkout or for a package that the update adds: it leaves the load scripts to the next restore, which downloads the packages that they load - https://github.com/fsprojects/Paket/issues/2785 #### 12.0.0-alpha005 - 2026-11-07 diff --git a/integrationtests/Paket.IntegrationTests/LoadingScriptGenerationTests.fs b/integrationtests/Paket.IntegrationTests/LoadingScriptGenerationTests.fs index 455ca3fc61..8dd28cf452 100644 --- a/integrationtests/Paket.IntegrationTests/LoadingScriptGenerationTests.fs +++ b/integrationtests/Paket.IntegrationTests/LoadingScriptGenerationTests.fs @@ -268,6 +268,22 @@ let ``#3238 restore regenerates load scripts when .paket/load folder is missing` nHibernate35Expectations |> assertExpectations scenario ExpectationType.ShouldContain +[] +let ``#2785 update --no-install leaves the load scripts to the restore`` () = + // generate_load_scripts: true, and nothing restored yet + let scenario = "issue-2939" + use __ = paket "update --no-install" scenario |> fst + + let tempPath = scenarioTempPath scenario + Assert.IsTrue(File.Exists(Path.Combine(tempPath, "paket.lock")), "update should write paket.lock") + Assert.IsFalse(Directory.Exists(Path.Combine(tempPath, "packages", "Newtonsoft.Json")), "--no-install should not download the packages") + Assert.IsFalse((scriptRoot scenario).Exists, "--no-install should not generate the load scripts") + + directPaket "restore" scenario |> ignore + + let newtonsoftScript = Path.Combine((scriptRoot scenario).FullName, "Newtonsoft.Json.fsx") + Assert.IsTrue(File.Exists newtonsoftScript, "restore should generate the load scripts") + [] let ``issue 2156 netstandard`` () = let scenario = "issue-2156" diff --git a/src/Paket.Core/Installation/UpdateProcess.fs b/src/Paket.Core/Installation/UpdateProcess.fs index 0ca4518e1f..a80c403e39 100644 --- a/src/Paket.Core/Installation/UpdateProcess.fs +++ b/src/Paket.Core/Installation/UpdateProcess.fs @@ -297,7 +297,9 @@ let SmartInstall(dependenciesFile:DependenciesFile, updateMode, options : Update |> Seq.tryHead |> Option.isSome - if shouldGenerateScripts then + // --no-install doesn't download the packages that the scripts load. When the lock file changes, + // the restore cache no longer matches it, so the next restore downloads them and generates the scripts (#2785) + if shouldGenerateScripts && not options.NoInstall then let groupsToGenerate = if options.Common.GenerateLoadScripts then [] else dependenciesFile.Groups From ff11a6fdbce60293f34b40c7b7c54c2b85b33f3e Mon Sep 17 00:00:00 2001 From: fpellet Date: Sun, 8 Nov 2026 19:35:24 +0100 Subject: [PATCH 2/2] fix: tell after update --no-install that the next restore generates the load scripts The hint is printed when update --no-install changes paket.lock, the case where the next restore downloads the packages and generates the scripts. It names paket restore rather than the --no-install flag, which API callers don't pass. --- .../Paket.IntegrationTests/LoadingScriptGenerationTests.fs | 4 +++- src/Paket.Core/Installation/UpdateProcess.fs | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/integrationtests/Paket.IntegrationTests/LoadingScriptGenerationTests.fs b/integrationtests/Paket.IntegrationTests/LoadingScriptGenerationTests.fs index 8dd28cf452..29eb2fe250 100644 --- a/integrationtests/Paket.IntegrationTests/LoadingScriptGenerationTests.fs +++ b/integrationtests/Paket.IntegrationTests/LoadingScriptGenerationTests.fs @@ -272,7 +272,9 @@ let ``#3238 restore regenerates load scripts when .paket/load folder is missing` let ``#2785 update --no-install leaves the load scripts to the restore`` () = // generate_load_scripts: true, and nothing restored yet let scenario = "issue-2939" - use __ = paket "update --no-install" scenario |> fst + let cleanup, output = paket "update --no-install" scenario + use __ = cleanup + StringAssert.Contains("The load scripts will be generated by the next paket restore", output) let tempPath = scenarioTempPath scenario Assert.IsTrue(File.Exists(Path.Combine(tempPath, "paket.lock")), "update should write paket.lock") diff --git a/src/Paket.Core/Installation/UpdateProcess.fs b/src/Paket.Core/Installation/UpdateProcess.fs index a80c403e39..3d63f8df3d 100644 --- a/src/Paket.Core/Installation/UpdateProcess.fs +++ b/src/Paket.Core/Installation/UpdateProcess.fs @@ -299,7 +299,10 @@ let SmartInstall(dependenciesFile:DependenciesFile, updateMode, options : Update // --no-install doesn't download the packages that the scripts load. When the lock file changes, // the restore cache no longer matches it, so the next restore downloads them and generates the scripts (#2785) - if shouldGenerateScripts && not options.NoInstall then + if shouldGenerateScripts && options.NoInstall then + if hasChanged then + tracefn "The load scripts will be generated by the next paket restore, which downloads the packages." + elif shouldGenerateScripts then let groupsToGenerate = if options.Common.GenerateLoadScripts then [] else dependenciesFile.Groups