diff --git a/src/dotnet/APIView/APIViewWeb/Helpers/CodeFileHelpers.cs b/src/dotnet/APIView/APIViewWeb/Helpers/CodeFileHelpers.cs index d3d304331cb..3c90c2bdabc 100644 --- a/src/dotnet/APIView/APIViewWeb/Helpers/CodeFileHelpers.cs +++ b/src/dotnet/APIView/APIViewWeb/Helpers/CodeFileHelpers.cs @@ -333,6 +333,9 @@ private static void InsertCodePanelRowData(CodePanelData codePanelData, CodePane private static void AddDiagnosticRow(CodePanelData codePanelData, CodeFile codeFile, string nodeId, string nodeIdHashed) { + if (codeFile.Diagnostics == null || codeFile.Diagnostics.Length == 0) + return; + var diagnostics = codeFile.Diagnostics.Where(d => d.TargetId == nodeId); foreach (var diagnostic in diagnostics) { diff --git a/src/dotnet/APIView/APIViewWeb/Managers/APIRevisionsManager.cs b/src/dotnet/APIView/APIViewWeb/Managers/APIRevisionsManager.cs index 01a18b265cc..694a9ba1450 100644 --- a/src/dotnet/APIView/APIViewWeb/Managers/APIRevisionsManager.cs +++ b/src/dotnet/APIView/APIViewWeb/Managers/APIRevisionsManager.cs @@ -725,12 +725,12 @@ public async Task UpdateAPIRevisionAsync(APIRevisionListItemModel revision, Lang try { var fileOriginal = await _originalsRepository.GetOriginalAsync(file.FileId); - // file.Name property has been repurposed to store package name and version string - // This is causing issue when updating review using latest parser since it expects Name field as file name - // We have added a new property FileName which is only set for new reviews - // All older reviews needs to be handled by checking review name field - var fileName = file.FileName ?? file.FileId; - var codeFile = await languageService.GetCodeFileAsync(fileName, fileOriginal, false); + if (string.IsNullOrEmpty(file.FileName)) + { + _telemetryClient.TrackTrace($"Revision does not have original file name to update API revision. Revision Id: {revision.Id}"); + continue; + } + var codeFile = await languageService.GetCodeFileAsync(file.FileName, fileOriginal, false); if (!verifyUpgradabilityOnly) { await _codeFileRepository.UpsertCodeFileAsync(revision.Id, file.FileId, codeFile); diff --git a/src/dotnet/APIView/apiview.yml b/src/dotnet/APIView/apiview.yml index dea1efe525b..0e457e11c7b 100644 --- a/src/dotnet/APIView/apiview.yml +++ b/src/dotnet/APIView/apiview.yml @@ -4,7 +4,7 @@ parameters: default: 'https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-net/nuget/v3/index.json' - name: CSharpAPIParserVersion type: string - default: '1.0.0-dev.20240723.1' + default: '1.0.0-dev.20240826.7' trigger: branches: diff --git a/tools/apiview/parsers/csharp-api-parser/CSharpAPIParser/TreeToken/CodeFileBuilder.cs b/tools/apiview/parsers/csharp-api-parser/CSharpAPIParser/TreeToken/CodeFileBuilder.cs index 6c9a6d4c58c..15577766c82 100644 --- a/tools/apiview/parsers/csharp-api-parser/CSharpAPIParser/TreeToken/CodeFileBuilder.cs +++ b/tools/apiview/parsers/csharp-api-parser/CSharpAPIParser/TreeToken/CodeFileBuilder.cs @@ -119,13 +119,14 @@ public static void BuildInternalsVisibleToAttributes(List reviewLine !a.ConstructorArguments[0].Value?.ToString()?.Contains("DynamicProxyGenAssembly2") == true); if (assemblyAttributes != null && assemblyAttributes.Any()) { - reviewLines.Add(new ReviewLine() + var internalVisibleLine = new ReviewLine() { LineId = "InternalsVisibleTo", Tokens = [ ReviewToken.CreateStringLiteralToken("Exposes internals to:") ] - }); + }; + reviewLines.Add(internalVisibleLine); foreach (AttributeData attribute in assemblyAttributes) { @@ -146,6 +147,8 @@ public static void BuildInternalsVisibleToAttributes(List reviewLine } } } + // Add an empty line after internals visible to section + reviewLines.Add(new ReviewLine() { RelatedToLine = internalVisibleLine.LineId }); } } diff --git a/tools/apiview/parsers/csharp-api-parser/CSharpAPIParserTests/CSharpAPIParserTests.csproj b/tools/apiview/parsers/csharp-api-parser/CSharpAPIParserTests/CSharpAPIParserTests.csproj index e5b5ccebbd5..466c9d34132 100644 --- a/tools/apiview/parsers/csharp-api-parser/CSharpAPIParserTests/CSharpAPIParserTests.csproj +++ b/tools/apiview/parsers/csharp-api-parser/CSharpAPIParserTests/CSharpAPIParserTests.csproj @@ -11,6 +11,7 @@ + diff --git a/tools/apiview/parsers/csharp-api-parser/CSharpAPIParserTests/CodeFileTests.cs b/tools/apiview/parsers/csharp-api-parser/CSharpAPIParserTests/CodeFileTests.cs index 1d1b59641e4..672a506a914 100644 --- a/tools/apiview/parsers/csharp-api-parser/CSharpAPIParserTests/CodeFileTests.cs +++ b/tools/apiview/parsers/csharp-api-parser/CSharpAPIParserTests/CodeFileTests.cs @@ -43,9 +43,9 @@ static CodeFileTests() public static IEnumerable CodeFiles => new List { - new object[] { templateCodeFile, "Azure.Template" , "1.0.3.0", 8}, - new object[] { storageCodeFile , "Azure.Storage.Blobs", "12.21.2.0", 14}, - new object[] { coreCodeFile, "Azure.Core", "1.42.0.0", 26}, + new object[] { templateCodeFile, "Azure.Template" , "1.0.3.0", 9}, + new object[] { storageCodeFile , "Azure.Storage.Blobs", "12.21.2.0", 15}, + new object[] { coreCodeFile, "Azure.Core", "1.42.0.0", 27}, }; [Theory] @@ -103,6 +103,7 @@ public void TestApiReviewLine() var classLine = namespaceLine.Children.Where(lines => lines.LineId == "Azure.Storage.Blobs.BlobServiceClient").FirstOrDefault(); Assert.NotNull(classLine); var methodLine = classLine.Children.Where(lines => lines.LineId == "Azure.Storage.Blobs.BlobServiceClient.BlobServiceClient(System.String)").FirstOrDefault(); + Assert.NotNull(methodLine); Assert.Equal(7, methodLine.Tokens.Count()); Assert.Equal("public BlobServiceClient(string connectionString);", methodLine.ToString().Trim()); } @@ -224,7 +225,7 @@ public static class TemplateClientBuilderExtensions { public void TestCodeFileJsonSchema(CodeFile codeFile) { //Verify JSON file generated for Azure.Template - var isValid = validateSchema(templateCodeFile); + var isValid = validateSchema(codeFile); Assert.True(isValid); } @@ -261,6 +262,7 @@ public void TestNavigationNodeHasRenderingClass() { var jsonString = JsonSerializer.Serialize(templateCodeFile); var parsedCodeFile = JsonSerializer.Deserialize(jsonString); + Assert.NotNull(parsedCodeFile); Assert.Equal(8, CountNavigationNodes(parsedCodeFile.ReviewLines)); } @@ -317,5 +319,31 @@ private int CountHiddenApiInBlobDownloadInfo(List lines) } return count; } + + [Fact] + public void VerifyObsoleteMemberIsHidden() + { + var attestationAssembly = Assembly.Load("Azure.Security.Attestation"); + var dllStream = attestationAssembly.GetFile("Azure.Security.Attestation.dll"); + var assemblySymbol = CompilationFactory.GetCompilation(dllStream, null); + var codeFile = new CSharpAPIParser.TreeToken.CodeFileBuilder().Build(assemblySymbol, true, null); + + var lines = codeFile.ReviewLines; + var namespaceLine = lines.Where(lines => lines.LineId == "Azure.Security.Attestation").FirstOrDefault(); + Assert.NotNull(namespaceLine); + var classLine = namespaceLine.Children.Where(lines => lines.LineId == "Azure.Security.Attestation.AttestationResult").FirstOrDefault(); + Assert.NotNull(classLine); + + var obsoleteMethods = classLine.Children.Where(line => line.ToString().StartsWith("[Obsolete(")); + Assert.NotEmpty(obsoleteMethods); + //Make sure member lines are marked as hidden if it has obsolete attribute + foreach (var method in obsoleteMethods) + { + Assert.True(method.IsHidden); + Assert.NotNull(method.RelatedToLine); + var relatedLine = classLine.Children.Where(line => line.LineId == method.RelatedToLine).FirstOrDefault(); + Assert.True(relatedLine?.IsHidden); + } + } } }