diff --git a/Aspire.slnx b/Aspire.slnx index 03ee4cce7bd..a3e9e9ad130 100644 --- a/Aspire.slnx +++ b/Aspire.slnx @@ -48,6 +48,7 @@ + diff --git a/src/Aspire.Hosting.Analyzers/AnalyzerReleases.Unshipped.md b/src/Aspire.Hosting.Analyzers/AnalyzerReleases.Unshipped.md index ab70a35f04b..62bfdc2112c 100644 --- a/src/Aspire.Hosting.Analyzers/AnalyzerReleases.Unshipped.md +++ b/src/Aspire.Hosting.Analyzers/AnalyzerReleases.Unshipped.md @@ -1,17 +1,2 @@ ; Unshipped analyzer release ; https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md - -### New Rules - -Rule ID | Category | Severity | Notes ---------|----------|----------|------- -ASPIREEXPORT001 | Design | Error | AspireExportAnalyzer, [Documentation](https://aka.ms/aspire/diagnostics/ASPIREEXPORT001) -ASPIREEXPORT002 | Design | Error | AspireExportAnalyzer, [Documentation](https://aka.ms/aspire/diagnostics/ASPIREEXPORT002) -ASPIREEXPORT003 | Design | Error | AspireExportAnalyzer, [Documentation](https://aka.ms/aspire/diagnostics/ASPIREEXPORT003) -ASPIREEXPORT004 | Design | Error | AspireExportAnalyzer, [Documentation](https://aka.ms/aspire/diagnostics/ASPIREEXPORT004) -ASPIREEXPORT005 | Design | Warning | AspireExportAnalyzer, [Documentation](https://aka.ms/aspire/diagnostics/ASPIREEXPORT005) -ASPIREEXPORT006 | Design | Warning | AspireExportAnalyzer, [Documentation](https://aka.ms/aspire/diagnostics/ASPIREEXPORT006) -ASPIREEXPORT007 | Design | Warning | AspireExportAnalyzer, [Documentation](https://aka.ms/aspire/diagnostics/ASPIREEXPORT007) -ASPIREEXPORT008 | Design | Warning | AspireExportAnalyzer, [Documentation](https://aka.ms/aspire/diagnostics/ASPIREEXPORT008) -ASPIREEXPORT009 | Design | Warning | AspireExportAnalyzer, [Documentation](https://aka.ms/aspire/diagnostics/ASPIREEXPORT009) -ASPIREEXPORT010 | Design | Warning | AspireExportAnalyzer, [Documentation](https://aka.ms/aspire/diagnostics/ASPIREEXPORT010) diff --git a/src/Aspire.Hosting.Integration.Analyzers/AnalyzerReleases.Shipped.md b/src/Aspire.Hosting.Integration.Analyzers/AnalyzerReleases.Shipped.md new file mode 100644 index 00000000000..d027c512cb9 --- /dev/null +++ b/src/Aspire.Hosting.Integration.Analyzers/AnalyzerReleases.Shipped.md @@ -0,0 +1,3 @@ +; Shipped analyzer releases +; https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md + diff --git a/src/Aspire.Hosting.Integration.Analyzers/AnalyzerReleases.Unshipped.md b/src/Aspire.Hosting.Integration.Analyzers/AnalyzerReleases.Unshipped.md new file mode 100644 index 00000000000..ab70a35f04b --- /dev/null +++ b/src/Aspire.Hosting.Integration.Analyzers/AnalyzerReleases.Unshipped.md @@ -0,0 +1,17 @@ +; Unshipped analyzer release +; https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md + +### New Rules + +Rule ID | Category | Severity | Notes +--------|----------|----------|------- +ASPIREEXPORT001 | Design | Error | AspireExportAnalyzer, [Documentation](https://aka.ms/aspire/diagnostics/ASPIREEXPORT001) +ASPIREEXPORT002 | Design | Error | AspireExportAnalyzer, [Documentation](https://aka.ms/aspire/diagnostics/ASPIREEXPORT002) +ASPIREEXPORT003 | Design | Error | AspireExportAnalyzer, [Documentation](https://aka.ms/aspire/diagnostics/ASPIREEXPORT003) +ASPIREEXPORT004 | Design | Error | AspireExportAnalyzer, [Documentation](https://aka.ms/aspire/diagnostics/ASPIREEXPORT004) +ASPIREEXPORT005 | Design | Warning | AspireExportAnalyzer, [Documentation](https://aka.ms/aspire/diagnostics/ASPIREEXPORT005) +ASPIREEXPORT006 | Design | Warning | AspireExportAnalyzer, [Documentation](https://aka.ms/aspire/diagnostics/ASPIREEXPORT006) +ASPIREEXPORT007 | Design | Warning | AspireExportAnalyzer, [Documentation](https://aka.ms/aspire/diagnostics/ASPIREEXPORT007) +ASPIREEXPORT008 | Design | Warning | AspireExportAnalyzer, [Documentation](https://aka.ms/aspire/diagnostics/ASPIREEXPORT008) +ASPIREEXPORT009 | Design | Warning | AspireExportAnalyzer, [Documentation](https://aka.ms/aspire/diagnostics/ASPIREEXPORT009) +ASPIREEXPORT010 | Design | Warning | AspireExportAnalyzer, [Documentation](https://aka.ms/aspire/diagnostics/ASPIREEXPORT010) diff --git a/src/Aspire.Hosting.Integration.Analyzers/Aspire.Hosting.Integration.Analyzers.csproj b/src/Aspire.Hosting.Integration.Analyzers/Aspire.Hosting.Integration.Analyzers.csproj new file mode 100644 index 00000000000..430dfb5802d --- /dev/null +++ b/src/Aspire.Hosting.Integration.Analyzers/Aspire.Hosting.Integration.Analyzers.csproj @@ -0,0 +1,44 @@ + + + + netstandard2.0 + true + true + false + false + false + 12.0 + + $(NoWarn),1573,1591,1712 + + false + + + + + + + + + + + + + + + + + + + + diff --git a/src/Aspire.Hosting.Analyzers/AspireExportAnalyzer.Diagnostics.cs b/src/Aspire.Hosting.Integration.Analyzers/AspireExportAnalyzer.Diagnostics.cs similarity index 100% rename from src/Aspire.Hosting.Analyzers/AspireExportAnalyzer.Diagnostics.cs rename to src/Aspire.Hosting.Integration.Analyzers/AspireExportAnalyzer.Diagnostics.cs diff --git a/src/Aspire.Hosting.Analyzers/AspireExportAnalyzer.cs b/src/Aspire.Hosting.Integration.Analyzers/AspireExportAnalyzer.cs similarity index 100% rename from src/Aspire.Hosting.Analyzers/AspireExportAnalyzer.cs rename to src/Aspire.Hosting.Integration.Analyzers/AspireExportAnalyzer.cs diff --git a/src/Aspire.Hosting/Aspire.Hosting.csproj b/src/Aspire.Hosting/Aspire.Hosting.csproj index bbfb120f7fc..cc7c588988c 100644 --- a/src/Aspire.Hosting/Aspire.Hosting.csproj +++ b/src/Aspire.Hosting/Aspire.Hosting.csproj @@ -10,6 +10,10 @@ Core abstractions for the Aspire application model. + + + + @@ -138,4 +142,26 @@ + + + $(BeforePack);IncludeIntegrationAnalyzerInPackage + + + + + + + + + + + + + + + diff --git a/src/Aspire.Hosting/buildTransitive/Aspire.Hosting.targets b/src/Aspire.Hosting/buildTransitive/Aspire.Hosting.targets new file mode 100644 index 00000000000..39a2d820fb0 --- /dev/null +++ b/src/Aspire.Hosting/buildTransitive/Aspire.Hosting.targets @@ -0,0 +1,12 @@ + + + + false + <_AspireIntegrationAnalyzerAssembly Condition="'$(_AspireIntegrationAnalyzerAssembly)' == ''">$(MSBuildThisFileDirectory)Aspire.Hosting.Integration.Analyzers.dll + + + + + + + diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index 828c0f7d33d..d1bbc9062e9 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -18,8 +18,12 @@ - + + diff --git a/tests/Aspire.Hosting.Tests/MSBuildTests.cs b/tests/Aspire.Hosting.Tests/MSBuildTests.cs index 7100f876562..8ccefd334d4 100644 --- a/tests/Aspire.Hosting.Tests/MSBuildTests.cs +++ b/tests/Aspire.Hosting.Tests/MSBuildTests.cs @@ -372,6 +372,133 @@ the Aspire.AppHost.SDK targets that will automatically add these references to p Assert.Contains("warning ASPIRE004", output); } + [Fact] + public void AspireExportAnalyzersAreDisabledByDefault() + { + var repoRoot = MSBuildUtils.GetRepoRoot(); + using var tempDirectory = new TestTempDirectory(); + + var projectDirectory = Path.Combine(tempDirectory.Path, "MyHostingExtension"); + Directory.CreateDirectory(projectDirectory); + + File.WriteAllText(Path.Combine(projectDirectory, "MyHostingExtension.csproj"), + $""" + + + + net8.0 + enable + enable + + + + + + + + """); + + File.WriteAllText(Path.Combine(projectDirectory, "Extensions.cs"), + """ + using Aspire.Hosting; + using Aspire.Hosting.ApplicationModel; + + namespace MyHostingExtension; + + public static class CustomResourceExtensions + { + public static IResourceBuilder AddCustomContainer(this IDistributedApplicationBuilder builder) + { + return builder.AddContainer("custom", "custom-image"); + } + } + """); + + CreateExportAnalyzerDirectoryBuildFiles(projectDirectory, repoRoot); + + var output = BuildProject(projectDirectory); + + Assert.DoesNotContain("warning ASPIREEXPORT008", output); + } + + [Fact] + public void AspireExportAnalyzersCanBeEnabledWithMsBuildProperty() + { + var repoRoot = MSBuildUtils.GetRepoRoot(); + using var tempDirectory = new TestTempDirectory(); + + var projectDirectory = Path.Combine(tempDirectory.Path, "MyHostingExtension"); + Directory.CreateDirectory(projectDirectory); + + File.WriteAllText(Path.Combine(projectDirectory, "MyHostingExtension.csproj"), + $""" + + + + net8.0 + enable + enable + + + + + + + + """); + + File.WriteAllText(Path.Combine(projectDirectory, "Extensions.cs"), + """ + using Aspire.Hosting; + using Aspire.Hosting.ApplicationModel; + + namespace MyHostingExtension; + + public static class CustomResourceExtensions + { + public static IResourceBuilder AddCustomContainer(this IDistributedApplicationBuilder builder) + { + return builder.AddContainer("custom", "custom-image"); + } + } + """); + + CreateExportAnalyzerDirectoryBuildFiles(projectDirectory, repoRoot, enableAspireIntegrationAnalyzers: true); + + var output = BuildProject(projectDirectory); + + Assert.Contains("warning ASPIREEXPORT008", output); + } + + private static void CreateExportAnalyzerDirectoryBuildFiles( + string basePath, + string repoRoot, + bool enableAspireIntegrationAnalyzers = false) + { + File.WriteAllText(Path.Combine(basePath, "Directory.Build.props"), + $""" + + + {enableAspireIntegrationAnalyzers.ToString().ToLowerInvariant()} + + + """); + File.WriteAllText(Path.Combine(basePath, "Directory.Build.targets"), + $""" + + + + + + + + """); + } + /// /// Tests that when GenerateAssemblyInfo is set to false, a build error is emitted. ///