@@ -59,7 +59,7 @@ partial class Build
5959 [ Parameter ( "Only update package versions for packages with the following names" ) ]
6060 readonly string [ ] IncludePackages ;
6161
62- [ Parameter ( "Minimum age in days a NuGet package version must have been published before auto-including. Defaults to 2 days, or 0 when --IncludePackages is set " ) ]
62+ [ Parameter ( "Minimum age in days a NuGet package version must have been published before auto-including. Defaults to 2. Ignored for packages named in --IncludePackages, which always bypass the cooldown. " ) ]
6363 readonly int ? PackageVersionCooldownDays ;
6464
6565 [ LazyLocalExecutable ( @"C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\gacutil.exe" ) ]
@@ -235,53 +235,64 @@ partial class Build
235235 var definitionsFile = BuildDirectory / FileNames . DefinitionsJson ;
236236 var supportedVersionsPath = BuildDirectory / "supported_versions.json" ;
237237
238- // Build the shouldQueryNuGet predicate from include/exclude filters
239- Func < string , bool > shouldUpdatePackage = ( IncludePackages , ExcludePackages ) switch
238+ // Decides the cooldown treatment for each package by name. See CooldownMode for what each value does.
239+ var getCooldownMode = BuildCooldownModeSelector ( IncludePackages , ExcludePackages ) ;
240+
241+ // Dependabot re-uses the previous entry verbatim for Freeze; Skip and Normal both refresh.
242+ Func < string , bool > shouldUpdatePackage = name => getCooldownMode ( name ) is not CooldownMode . Freeze ;
243+
244+ static Func < string , CooldownMode > BuildCooldownModeSelector ( string [ ] includePackages , string [ ] excludePackages )
240245 {
241- ( { } include , _) => name => include . Contains ( name , StringComparer . OrdinalIgnoreCase ) ,
242- ( _, { } exclude ) => name => ! exclude . Contains ( name , StringComparer . OrdinalIgnoreCase ) ,
243- _ => _ => true
244- } ;
245-
246- // Load caches for both pipelines
247- var cacheFilePath = BuildDirectory / "nuget_version_cache.json" ;
248- var previousVersionCache = await NuGetVersionCache . Load ( cacheFilePath ) ;
249- Logger . Information ( "Loaded NuGet version cache with {Count} entries" , previousVersionCache . Count ) ;
246+ // No filter: every package goes through the normal cooldown filter.
247+ if ( includePackages is null && excludePackages is null )
248+ {
249+ return _ => CooldownMode . Normal ;
250+ }
251+
252+ // --IncludePackages Foo Bar: update only the listed packages (bypassing cooldown);
253+ // freeze every other package so it re-emits its previous output unchanged.
254+ if ( includePackages is not null )
255+ {
256+ var targeted = new HashSet < string > ( includePackages , StringComparer . OrdinalIgnoreCase ) ;
257+ return name => targeted . Contains ( name ) ? CooldownMode . BypassCooldown : CooldownMode . Freeze ;
258+ }
259+
260+ // --ExcludePackages Foo Bar: freeze the listed packages; everything else updates normally.
261+ var blocked = new HashSet < string > ( excludePackages , StringComparer . OrdinalIgnoreCase ) ;
262+ return name => blocked . Contains ( name ) ? CooldownMode . Freeze : CooldownMode . Normal ;
263+ }
264+
250265 var previousSupportedVersions = await GenerateSupportMatrix . LoadPreviousVersions ( supportedVersionsPath ) ;
251266 Logger . Information ( "Loaded previous supported versions with {Count} entries" , previousSupportedVersions . Count ) ;
252267
253- // Derive baseline from supported_versions.json: the max tested version per package
254- // acts as a floor to prevent cooldown filtering from downgrading previously accepted versions.
255- // We collect all max tested versions per package (not just the global max) so that
256- // split-range packages (e.g., GraphQL 4.x-6.x and 7.x-9.x) get a per-range baseline .
257- var baseline = previousSupportedVersions
268+ // Pull the max tested version per package from supported_versions.json. The cooldown
269+ // filter keeps anything at or below this value so we never downgrade a version we
270+ // already shipped against. Collected as a list per package (not a single global max)
271+ // so split-range packages (e.g. GraphQL 4.x-6.x and 7.x-9.x) get a per-range value .
272+ var previousMaxVersions = previousSupportedVersions
258273 . Where ( kvp => kvp . Value . MaxVersionTestedInclusive is not null )
259274 . GroupBy ( kvp => kvp . Key . PackageName )
260275 . ToDictionary (
261276 g => g . Key ,
262277 g => g . Select ( kvp => new Version ( kvp . Value . MaxVersionTestedInclusive ! ) ) . ToList ( ) ) ;
263- Logger . Information ( "Derived version baseline with {Count} entries from supported_versions.json" , baseline . Count ) ;
278+ Logger . Information ( "Loaded previous max tested versions for {Count} packages from supported_versions.json" , previousMaxVersions . Count ) ;
264279
265- // Resolve effective cooldown:
266- // - Explicit --PackageVersionCooldownDays wins
267- // - --IncludePackages without explicit cooldown defaults to 0
268- var effectiveCooldownDays = PackageVersionCooldownDays ?? ( IncludePackages is not null ? 0 : 2 ) ;
280+ var effectiveCooldownDays = PackageVersionCooldownDays ?? 2 ;
269281
270282 // Pipeline A: generate .g.props/.g.cs files
271283 Logger . Information ( "Using package version cooldown of {Days} days" , effectiveCooldownDays ) ;
272- var versionGenerator = new PackageVersionGenerator ( TracerDirectory , testDir , shouldUpdatePackage , previousVersionCache , effectiveCooldownDays , baseline ) ;
284+ var versionGenerator = new PackageVersionGenerator ( TracerDirectory , testDir , getCooldownMode , effectiveCooldownDays , previousMaxVersions ) ;
273285 var testedVersions = await versionGenerator . GenerateVersions ( Solution ) ;
274- await NuGetVersionCache . Save ( cacheFilePath , versionGenerator . VersionCache ) ;
275286
276287 // Log version changes: bumps, unchanged, and overridden
277- var versionCache = versionGenerator . VersionCache ;
288+ var queriedVersions = versionGenerator . QueriedVersions ;
278289 var bumped = 0 ;
279290 var unchanged = 0 ;
280291 foreach ( var tested in testedVersions )
281292 {
282293 var packageName = tested . NugetPackageSearchName ;
283- baseline . TryGetValue ( packageName , out var previousMaxVersions ) ;
284- var previousMax = previousMaxVersions ?
294+ previousMaxVersions . TryGetValue ( packageName , out var previousMaxCandidates ) ;
295+ var previousMax = previousMaxCandidates ?
285296 . Where ( v => v >= tested . MinVersion && v <= tested . MaxVersion )
286297 . OrderByDescending ( v => v )
287298 . FirstOrDefault ( ) ;
@@ -290,12 +301,12 @@ partial class Build
290301 {
291302 bumped ++ ;
292303 var publishedDate = "(unknown)" ;
293- if ( versionCache . TryGetValue ( packageName , out var cachedVersions ) )
304+ if ( queriedVersions . TryGetValue ( packageName , out var versionsForPackage ) )
294305 {
295- var match = cachedVersions . FirstOrDefault ( v => v . Version == tested . MaxVersion . ToString ( ) ) ;
306+ var match = versionsForPackage . FirstOrDefault ( v => v . Version == tested . MaxVersion . ToString ( ) ) ;
296307 if ( match ? . Published is not null )
297308 {
298- publishedDate = match . Published . Value . ToString ( "yyyy-MM-dd" ) ;
309+ publishedDate = match . Published . Value . UtcDateTime . ToString ( "yyyy-MM-dd" ) ;
299310 }
300311 }
301312
@@ -325,13 +336,11 @@ partial class Build
325336
326337 foreach ( var entry in versionGenerator . CooldownReport . Entries )
327338 {
328- var resolvedText = entry . ResolvedVersion is not null ? $ "using: { entry . ResolvedVersion } " : "skipped" ;
329339 Logger . Warning (
330- " {Package} {Version} overridden (published {Date}, {Resolved} )" ,
340+ " {Package} {Version} overridden (published {Date})" ,
331341 entry . PackageName ,
332342 entry . OverriddenVersion ,
333- entry . PublishedDate ? . ToString ( "yyyy-MM-dd" ) ?? "unknown" ,
334- resolvedText ) ;
343+ entry . PublishedDate ? . UtcDateTime . ToString ( "yyyy-MM-dd" ) ?? "unknown" ) ;
335344 }
336345
337346 var reportPath = TemporaryDirectory / "cooldown_report.md" ;
@@ -347,7 +356,7 @@ partial class Build
347356 var integrations = GenerateIntegrationDefinitions . GetAllIntegrations ( assemblies , definitionsFile ) ;
348357
349358 // Pipeline B: generate dependabot files + supported_versions.json
350- // TestedVersions are cooldown-filtered but the baseline prevents downgrades,
359+ // TestedVersions are cooldown-filtered but the previous max pins prevent downgrades,
351360 // so they accurately reflect what we're testing.
352361 var distinctIntegrations = await DependabotFileManager . BuildDistinctIntegrationMaps (
353362 integrations , testedVersions , shouldUpdatePackage , previousSupportedVersions ) ;
0 commit comments