Skip to content

Add CI validation of Semantic Search API lists #77535

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ stages:
- powershell: eng/build.ps1 -configuration Release -prepareMachine -ci -restore -binaryLogName Restore.binlog
displayName: Restore

- powershell: eng/build.ps1 -configuration Release -prepareMachine -ci -build -pack -publish -sign -binaryLogName Build.binlog /p:DotnetPublishUsingPipelines=true
- powershell: eng/build.ps1 -configuration Release -prepareMachine -ci -build -pack -publish -sign -binaryLogName Build.binlog /p:DotnetPublishUsingPipelines=true /p:ContinuousIntegrationBuildCorrectness=true
displayName: Build

# While this task is not executed in the official build, this serves as a PR check for whether symbol exclusions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ public sealed class GenerateFilteredReferenceAssembliesTask : Task
[Required]
public string ApisDir { get; private set; } = null!;

/// <summary>
/// True to report an error if any changes in Semantic Search APIs are detected.
/// </summary>
public bool RequireNoApiChanges { get; private set; } = false;

public override bool Execute()
{
try
Expand Down Expand Up @@ -123,12 +128,14 @@ internal void ExecuteImpl(IEnumerable<(string apiSpecPath, IReadOnlyList<string>
return;
}

WriteApis(Path.Combine(ApisDir, assemblyName + ".txt"), peImageBuffer);
WriteApis(assemblyName, peImageBuffer);
}
}

internal void WriteApis(string outputFilePath, byte[] peImage)
internal void WriteApis(string assemblyName, byte[] peImage)
{
string outputFilePath = Path.Combine(ApisDir, assemblyName + ".txt");

using var readableStream = new MemoryStream(peImage, writable: false);
var metadataRef = MetadataReference.CreateFromStream(readableStream);
var compilation = CSharpCompilation.Create("Metadata", references: [metadataRef]);
Expand All @@ -149,9 +156,39 @@ internal void WriteApis(string outputFilePath, byte[] peImage)
var newContent = $"# Generated, do not update manually{Environment.NewLine}" +
string.Join(Environment.NewLine, apis);

if (RequireNoApiChanges)
{
var oldContent = "";

if (File.Exists(outputFilePath))
{
try
{
oldContent = File.ReadAllText(outputFilePath, Encoding.UTF8);
}
catch (FileNotFoundException)
{
}
catch (Exception e)
{
Log.LogError($"Unable to read '{outputFilePath}': {e.Message}");
return;
}
}

if (oldContent != newContent)
{
Log.LogError(
$"APIs listed in file '{outputFilePath}' do not match the public APIs exposed by '{assemblyName}'. " +
$"Build SemanticSearch.ReferenceAssemblies project locally to update the file and review the changes.");

return;
}
}

try
{
File.WriteAllText(outputFilePath, newContent);
File.WriteAllText(outputFilePath, newContent, Encoding.UTF8);
Log.LogMessage($"Baseline updated: '{outputFilePath}'");
}
catch (Exception e)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
'%(ReferencePath.FileName)' == 'Microsoft.CodeAnalysis.CSharp'" />

<ApiSet Include="@(None)" Condition="'%(None.IsApiSet)' == 'true'" />
<Apis Include="@(ApiSet->'$(_ApisDir)%(FileName)%(Extension)')" />
<Apis Include="@(ApiSet->'$(_ApisDir)%(FileName)%(Extension)')" />

<_InputFile Include="@(ApiSet)" />
<_InputFile Include="@(_InputReference)" />
Expand All @@ -58,15 +58,21 @@
<Target Name="GenerateFilteredReferenceAssemblies" Condition="Exists('$(_BuildTaskAssemblyFile)')" BeforeTargets="AfterBuild" DependsOnTargets="_CalculateFilteredReferenceAssembliesInputsAndOutputs" Inputs="@(_InputFile)" Outputs="@(_OutputFile)">

<MakeDir Directories="$(_OutputDir)" />
<Microsoft.CodeAnalysis.Tools.GenerateFilteredReferenceAssembliesTask References="@(_InputReference)" ApiSets="@(ApiSet)" OutputDir="$(_OutputDir)" ApisDir="$(_ApisDir)" />

<PropertyGroup>
<_RequireNoApiChanges>false</_RequireNoApiChanges>
<_RequireNoApiChanges Condition="'$(ContinuousIntegrationBuildCorrectness)' == 'true'">true</_RequireNoApiChanges>
</PropertyGroup>

<Microsoft.CodeAnalysis.Tools.GenerateFilteredReferenceAssembliesTask References="@(_InputReference)" ApiSets="@(ApiSet)" OutputDir="$(_OutputDir)" ApisDir="$(_ApisDir)" RequireNoApiChanges="$(_RequireNoApiChanges)" />

<ItemGroup>
<FileWrites Include="@(_OutputFile)" />
</ItemGroup>
</Target>

<!-- Used from Setup and test projects to fetch the list of generated ref assemblies -->
<Target Name="PublishedProjectOutputGroup" DependsOnTargets="_CalculateFilteredReferenceAssembliesInputsAndOutputs" Returns="@(_OutputFile)" />
<Target Name="PublishedProjectOutputGroup" DependsOnTargets="_CalculateFilteredReferenceAssembliesInputsAndOutputs" Returns="@(_OutputFile)" />

<!-- Generates ref assemblies -->
<Target Name="PublishVsixItems" DependsOnTargets="PublishedProjectOutputGroup;GenerateFilteredReferenceAssemblies" Returns="@(_OutputFile)" />
Expand Down
Loading