From 1c70cae24ac8e75ca19d2845a40226d82801ad00 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 19:36:02 +0000 Subject: [PATCH 1/4] Initial plan From d65d0e312cf3d14fbe460bae37dde8c9933e05c0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 19:50:23 +0000 Subject: [PATCH 2/4] Fix sdk check command to handle missing releases.json gracefully Co-authored-by: marcpopMSFT <12663534+marcpopMSFT@users.noreply.github.com> --- .../Sdk/Check/ProductCollectionProvider.cs | 5 ++-- .../Commands/Sdk/Check/SdkOutputWriter.cs | 27 ++++++++++++++++--- .../Sdk/Check/GivenDotnetSdkCheck.cs | 26 ++++++++++++++++++ 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/Cli/dotnet/Commands/Sdk/Check/ProductCollectionProvider.cs b/src/Cli/dotnet/Commands/Sdk/Check/ProductCollectionProvider.cs index 780427aa026f..13e991d99c01 100644 --- a/src/Cli/dotnet/Commands/Sdk/Check/ProductCollectionProvider.cs +++ b/src/Cli/dotnet/Commands/Sdk/Check/ProductCollectionProvider.cs @@ -30,9 +30,10 @@ public IEnumerable GetProductReleases(Deployment.DotNet.Releases { return product.GetReleasesAsync().Result; } - catch (Exception e) + catch (Exception) { - throw new GracefulException(string.Format(CliCommandStrings.ReleasesLibraryFailed, e.Message)); + // Return empty collection if releases are not available (e.g., unreleased preview versions) + return Enumerable.Empty(); } } } diff --git a/src/Cli/dotnet/Commands/Sdk/Check/SdkOutputWriter.cs b/src/Cli/dotnet/Commands/Sdk/Check/SdkOutputWriter.cs index ce7d7c9df8eb..0ee9e8b5d225 100644 --- a/src/Cli/dotnet/Commands/Sdk/Check/SdkOutputWriter.cs +++ b/src/Cli/dotnet/Commands/Sdk/Check/SdkOutputWriter.cs @@ -68,7 +68,13 @@ private bool NewerSdkPatchExists(NetSdkInfo bundle) private ReleaseVersion? NewestSdkPatchVersion(NetSdkInfo bundle) { - var product = _productCollection.First(product => product.ProductVersion.Equals($"{bundle.Version.Major}.{bundle.Version.Minor}")); + var product = _productCollection.FirstOrDefault(product => product.ProductVersion.Equals($"{bundle.Version.Major}.{bundle.Version.Minor}")); + if (product == null) + { + // No release information available for this SDK version + return null; + } + if (product.LatestSdkVersion.SdkFeatureBand == bundle.Version.SdkFeatureBand) { // This is the latest feature band @@ -88,11 +94,24 @@ private bool NewerSdkPatchExists(NetSdkInfo bundle) private bool NewFeatureBandAvailable() { - return NewestFeatureBandAvailable() > _sdkInfo.Select(sdk => sdk.Version).Max(); + if (!_sdkInfo.Any()) + { + return false; + } + + var newestAvailable = NewestFeatureBandAvailable(); + return newestAvailable != null && newestAvailable > _sdkInfo.Select(sdk => sdk.Version).Max(); } - private ReleaseVersion NewestFeatureBandAvailable() + private ReleaseVersion? NewestFeatureBandAvailable() { - return _productCollection.OrderByDescending(product => product.ProductVersion).First().LatestSdkVersion; + var newestProduct = _productCollection.OrderByDescending(product => product.ProductVersion).FirstOrDefault(); + if (newestProduct != null) + { + return newestProduct.LatestSdkVersion; + } + + // Fallback to the newest installed SDK if no product collection is available + return _sdkInfo.Any() ? _sdkInfo.Select(sdk => sdk.Version).Max() : null; } } diff --git a/test/dotnet.Tests/CommandTests/Sdk/Check/GivenDotnetSdkCheck.cs b/test/dotnet.Tests/CommandTests/Sdk/Check/GivenDotnetSdkCheck.cs index 5782aa2b9022..37d552f3ae14 100644 --- a/test/dotnet.Tests/CommandTests/Sdk/Check/GivenDotnetSdkCheck.cs +++ b/test/dotnet.Tests/CommandTests/Sdk/Check/GivenDotnetSdkCheck.cs @@ -207,6 +207,32 @@ public void ItUsesConfigFile() _reporter.Lines.Should().Contain(replacementString); } + [Fact] + public void WhenSdkHasNoReleasesJsonItShowsVersionCheckFailure() + { + var parseResult = Parser.Parse(new string[] { "dotnet", "sdk", "check" }); + // Install SDK 11.0.100 which doesn't have releases.json in the test assets + var bundles = GetFakeEnvironmentInfo(new[] { "3.1.100", "5.0.100", "11.0.100" }, new[] { "3.1.0", "5.0.0" }); + + // This should not throw even though 11.0 doesn't have releases.json + new SdkCheckCommand(parseResult, new MockNETBundleProvider(bundles), new MockProductCollectionProvider(fakeReleasesPath), _reporter).Execute(); + + // Verify all SDKs are shown + foreach (var version in bundles.SdkInfo.Select(b => b.Version.ToString())) + { + string.Join(' ', _reporter.Lines) + .Should() + .Contain(version); + } + + // The SDK without releases should show version check failure + string.Join(' ', _reporter.Lines) + .Should() + .Contain("11.0.100") + .And + .Contain(CliCommandStrings.VersionCheckFailure); + } + private NetEnvironmentInfo GetFakeEnvironmentInfo(IEnumerable sdkVersions, IEnumerable runtimeVersions) { var sdks = sdkVersions.Select(version => new NetSdkInfo(version, string.Empty)); From a511ec6e396364fba6ebff7a298c9a77e1bc97bd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 19:55:10 +0000 Subject: [PATCH 3/4] Address code review feedback: improve exception handling and test naming Co-authored-by: marcpopMSFT <12663534+marcpopMSFT@users.noreply.github.com> --- .../dotnet/Commands/Sdk/Check/ProductCollectionProvider.cs | 7 ++++++- .../CommandTests/Sdk/Check/GivenDotnetSdkCheck.cs | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Cli/dotnet/Commands/Sdk/Check/ProductCollectionProvider.cs b/src/Cli/dotnet/Commands/Sdk/Check/ProductCollectionProvider.cs index 13e991d99c01..0c3ff39c8940 100644 --- a/src/Cli/dotnet/Commands/Sdk/Check/ProductCollectionProvider.cs +++ b/src/Cli/dotnet/Commands/Sdk/Check/ProductCollectionProvider.cs @@ -30,9 +30,14 @@ public IEnumerable GetProductReleases(Deployment.DotNet.Releases { return product.GetReleasesAsync().Result; } - catch (Exception) + catch (Exception ex) when (ex is HttpRequestException || + ex is FileNotFoundException || + ex is AggregateException aggregateEx && + (aggregateEx.InnerException is HttpRequestException || + aggregateEx.InnerException is FileNotFoundException)) { // Return empty collection if releases are not available (e.g., unreleased preview versions) + // This handles cases where the releases.json file doesn't exist yet for a version return Enumerable.Empty(); } } diff --git a/test/dotnet.Tests/CommandTests/Sdk/Check/GivenDotnetSdkCheck.cs b/test/dotnet.Tests/CommandTests/Sdk/Check/GivenDotnetSdkCheck.cs index 37d552f3ae14..4283fd069cd8 100644 --- a/test/dotnet.Tests/CommandTests/Sdk/Check/GivenDotnetSdkCheck.cs +++ b/test/dotnet.Tests/CommandTests/Sdk/Check/GivenDotnetSdkCheck.cs @@ -208,7 +208,7 @@ public void ItUsesConfigFile() } [Fact] - public void WhenSdkHasNoReleasesJsonItShowsVersionCheckFailure() + public void WhenSdkHasNoReleasesJsonItShowsVersionCheckUnavailable() { var parseResult = Parser.Parse(new string[] { "dotnet", "sdk", "check" }); // Install SDK 11.0.100 which doesn't have releases.json in the test assets From a6728f9ce2ee98e71f5b16864dd82c3eeff32a29 Mon Sep 17 00:00:00 2001 From: Marc Paine Date: Fri, 6 Feb 2026 13:23:29 -0800 Subject: [PATCH 4/4] Update test to use SDK version 99.0.100 We'll have to update this in 80 years or so but that's not my problem. --- .../CommandTests/Sdk/Check/GivenDotnetSdkCheck.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/dotnet.Tests/CommandTests/Sdk/Check/GivenDotnetSdkCheck.cs b/test/dotnet.Tests/CommandTests/Sdk/Check/GivenDotnetSdkCheck.cs index 4283fd069cd8..7fcc0264722d 100644 --- a/test/dotnet.Tests/CommandTests/Sdk/Check/GivenDotnetSdkCheck.cs +++ b/test/dotnet.Tests/CommandTests/Sdk/Check/GivenDotnetSdkCheck.cs @@ -211,10 +211,10 @@ public void ItUsesConfigFile() public void WhenSdkHasNoReleasesJsonItShowsVersionCheckUnavailable() { var parseResult = Parser.Parse(new string[] { "dotnet", "sdk", "check" }); - // Install SDK 11.0.100 which doesn't have releases.json in the test assets - var bundles = GetFakeEnvironmentInfo(new[] { "3.1.100", "5.0.100", "11.0.100" }, new[] { "3.1.0", "5.0.0" }); + // Install SDK 99.0.100 which doesn't have releases.json in the test assets + var bundles = GetFakeEnvironmentInfo(new[] { "3.1.100", "5.0.100", "99.0.100" }, new[] { "3.1.0", "5.0.0" }); - // This should not throw even though 11.0 doesn't have releases.json + // This should not throw even though 99.0 doesn't have releases.json new SdkCheckCommand(parseResult, new MockNETBundleProvider(bundles), new MockProductCollectionProvider(fakeReleasesPath), _reporter).Execute(); // Verify all SDKs are shown @@ -228,7 +228,7 @@ public void WhenSdkHasNoReleasesJsonItShowsVersionCheckUnavailable() // The SDK without releases should show version check failure string.Join(' ', _reporter.Lines) .Should() - .Contain("11.0.100") + .Contain("99.0.100") .And .Contain(CliCommandStrings.VersionCheckFailure); }