diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0001Tests.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0001Tests.cs index ad7b1e26c12..5296fd1e7e6 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0001Tests.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0001Tests.cs @@ -9,6 +9,13 @@ namespace Azure.ClientSdk.Analyzers.Tests { public class AZC0001Tests { + private readonly string message = "Namespace '{0}' shouldn't contain public types." + + " Use one of the following pre-approved namespace groups (https://azure.github.io/azure-sdk/registered_namespaces.html):" + + " Azure.AI, Azure.Analytics, Azure.Communication, Azure.Compute, Azure.Containers, Azure.Core.Expressions, Azure.Data, Azure.Developer," + + " Azure.DigitalTwins, Azure.Health, Azure.Identity, Azure.IoT, Azure.Maps, Azure.Media, Azure.Messaging, Azure.MixedReality," + + " Azure.Monitor, Azure.ResourceManager, Azure.Search, Azure.Security, Azure.Storage, Azure.Verticals," + + " Microsoft.Extensions.Azure"; + [Fact] public async Task AZC0001ProducedForInvalidNamespaces() { @@ -19,13 +26,28 @@ public class Program { } }"; var diagnostic = Verifier.Diagnostic("AZC0001") - .WithMessage("Namespace 'RandomNamespace' shouldn't contain public types. Use one of the following pre-approved namespace groups (https://azure.github.io/azure-sdk/registered_namespaces.html):" + - " Azure.AI, Azure.Analytics, Azure.Communication, Azure.Compute, Azure.Containers, Azure.Core.Expressions, Azure.Data, Azure.Developer, Azure.DigitalTwins, Azure.Identity, Azure.IoT, Azure.Learn, Azure.Management, Azure.Media, Azure.Messaging, Azure.MixedReality, Azure.Monitor, Azure.ResourceManager, Azure.Search, Azure.Security, Azure.Storage, Azure.Template, Microsoft.Extensions.Azure") + .WithMessage(string.Format(this.message, "RandomNamespace")) .WithSpan(2, 11, 2, 26); await Verifier.VerifyAnalyzerAsync(code, diagnostic); } + [Fact] + public async Task AZC0001ProducedForSubNamespacesOfAzureTemplate() + { + const string code = @" +namespace Azure.Template.RandomNamespace +{ + public class Program { } +}"; + + var diagnostic = Verifier.Diagnostic("AZC0001") + .WithMessage(string.Format(this.message, "Azure.Template.RandomNamespace")) + .WithSpan(2, 26, 2, 41); + + await Verifier.VerifyAnalyzerAsync(code, diagnostic); + } + [Fact] public async Task AZC0001ProducedOneErrorPerNamespaceDefinition() { @@ -65,10 +87,22 @@ public class Program { } } [Fact] - public async Task AZC0001AllowAzureCoreExpressions() + public async Task AZC0001NotProducedForAzureCoreExpressions() { const string code = @" namespace Azure.Core.Expressions.Foobar +{ + public class Program { } +}"; + + await Verifier.VerifyAnalyzerAsync(code); + } + + [Fact] + public async Task AZC0001NotProducedForAzureTemplate() + { + const string code = @" +namespace Azure.Template { public class Program { } }"; diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/ClientAssemblyNamespaceAnalyzer.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/ClientAssemblyNamespaceAnalyzer.cs index c1d932e26f1..355be34f7ba 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/ClientAssemblyNamespaceAnalyzer.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/ClientAssemblyNamespaceAnalyzer.cs @@ -21,10 +21,10 @@ public class ClientAssemblyNamespaceAnalyzer : SymbolAnalyzerBase "Azure.Data", "Azure.Developer", "Azure.DigitalTwins", + "Azure.Health", "Azure.Identity", "Azure.IoT", - "Azure.Learn", - "Azure.Management", + "Azure.Maps", "Azure.Media", "Azure.Messaging", "Azure.MixedReality", @@ -33,7 +33,7 @@ public class ClientAssemblyNamespaceAnalyzer : SymbolAnalyzerBase "Azure.Search", "Azure.Security", "Azure.Storage", - "Azure.Template", + "Azure.Verticals", "Microsoft.Extensions.Azure" }; @@ -74,6 +74,14 @@ public override void Analyze(ISymbolAnalysisContext context) { return; } + + // "Azure.Template" is not an approved namespace prefix, but we have a project template by that name + // to help customers get started. We do not want our template to include a suppression for this + // descriptor out of the box, so we need to treat it as a special case. + if (displayString == "Azure.Template") + { + return; + } } foreach (var namespaceSymbolLocation in namespaceSymbol.Locations)