Skip to content

Commit

Permalink
Enhance GenerateDocumentationAndConfigFiles tool to generate vNext gl…
Browse files Browse the repository at this point in the history
…obalconfig files

Fixes dotnet#6247

Our generated globalconfig files that we ship in the analyzer NuGet packages and .NET SDK should likely include a vNext set of globalconfig files so that when the analysis level is set to latest or explicitly to vNext for upcoming .NET Release, we still find a proper mapped globalconfig file. This will avoid regressions such as dotnet#6245 in future.

Verified that locally built Microsoft.CodeAnalysis.NetAnalyzers package with this change includes globalconfig files specific to 8.0 release version.
  • Loading branch information
mavasani committed Nov 11, 2022
1 parent 31373ce commit 00c98ef
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 21 deletions.
6 changes: 6 additions & 0 deletions src/Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@
<!-- Unshipped release -->
<ItemGroup Condition="'$(ReleaseTrackingOptOut)' != 'true' AND Exists('$(MSBuildProjectDirectory)\AnalyzerReleases.Unshipped.md')">
<AdditionalFiles Include="$(MSBuildProjectDirectory)\AnalyzerReleases.Unshipped.md" />
<!-- Copy the unshipped releases file to output directory so it can be used in 'GenerateGlobalAnalyzerConfigs' post-build target -->
<!-- Include unshipped file also as 'None' - Workaround for 'CopyToOutputDirectory' not being respected for additional files -->
<None Update="AnalyzerReleases.Unshipped.md">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>AnalyzerReleases\$(AssemblyName)\AnalyzerReleases.Unshipped.md</Link>
</None>
</ItemGroup>
<!-- Shipped releases -->
<ItemGroup Condition="'$(ReleaseTrackingOptOut)' != 'true' AND Exists('$(MSBuildProjectDirectory)\AnalyzerReleases.Shipped.md')">
Expand Down
73 changes: 52 additions & 21 deletions src/Tools/GenerateDocumentationAndConfigFiles/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,7 @@ async Task<bool> checkHelpLinkAsync(string helpLink)
async Task<bool> createGlobalConfigFilesAsync()
{
using var shippedFilesDataBuilder = ArrayBuilder<ReleaseTrackingData>.GetInstance();
using var unshippedFilesDataBuilder = ArrayBuilder<ReleaseTrackingData>.GetInstance();
using var versionsBuilder = PooledHashSet<Version>.GetInstance();

// Validate all assemblies exist on disk and can be loaded.
Expand Down Expand Up @@ -705,7 +706,8 @@ async Task<bool> createGlobalConfigFilesAsync()

var assemblyName = Path.GetFileNameWithoutExtension(assembly);
var shippedFile = Path.Combine(assemblyDir, "AnalyzerReleases", assemblyName, ReleaseTrackingHelper.ShippedFileName);
if (File.Exists(shippedFile))
var unshippedFile = Path.Combine(assemblyDir, "AnalyzerReleases", assemblyName, ReleaseTrackingHelper.UnshippedFileName);
if (File.Exists(shippedFile) && File.Exists(unshippedFile))
{
sawShippedFile = true;

Expand All @@ -717,6 +719,7 @@ async Task<bool> createGlobalConfigFilesAsync()

try
{
// Read shipped file
using var fileStream = File.OpenRead(shippedFile);
var sourceText = SourceText.From(fileStream);
var releaseTrackingData = ReleaseTrackingHelper.ReadReleaseTrackingData(shippedFile, sourceText,
Expand All @@ -725,6 +728,15 @@ async Task<bool> createGlobalConfigFilesAsync()
isShippedFile: true);
shippedFilesDataBuilder.Add(releaseTrackingData);
versionsBuilder.AddRange(releaseTrackingData.Versions);

// Read unshipped file
using var fileStreamUnshipped = File.OpenRead(unshippedFile);
var sourceTextUnshipped = SourceText.From(fileStreamUnshipped);
var releaseTrackingDataUnshipped = ReleaseTrackingHelper.ReadReleaseTrackingData(unshippedFile, sourceTextUnshipped,
onDuplicateEntryInRelease: (_1, _2, _3, _4, line) => throw new Exception($"Duplicate entry in {unshippedFile} at {line.LineNumber}: '{line}'"),
onInvalidEntry: (line, _2, _3, _4) => throw new Exception($"Invalid entry in {unshippedFile} at {line.LineNumber}: '{line}'"),
isShippedFile: false);
unshippedFilesDataBuilder.Add(releaseTrackingDataUnshipped);
}
#pragma warning disable CA1031 // Do not catch general exception types
catch (Exception ex)
Expand All @@ -744,33 +756,50 @@ async Task<bool> createGlobalConfigFilesAsync()

if (versionsBuilder.Count > 0)
{
var shippedFilesData = shippedFilesDataBuilder.ToImmutable();
var releaseTrackingData = shippedFilesDataBuilder.Concat(unshippedFilesDataBuilder).ToImmutableArray();

// Generate global analyzer config files for each shipped version, if required.
// Generate global analyzer config files for each shipped version.
foreach (var version in versionsBuilder)
{
var analysisLevelVersionString = GetNormalizedVersionStringForEditorconfigFileNameSuffix(version);

foreach (var analysisMode in Enum.GetValues(typeof(AnalysisMode)))
{
CreateGlobalConfig(version, analysisLevelVersionString, (AnalysisMode)analysisMode!, shippedFilesData, category: null);
foreach (var category in categories)
{
CreateGlobalConfig(version, analysisLevelVersionString, (AnalysisMode)analysisMode!, shippedFilesData, category);
}
}
CreateGlobalConfigsForVersion(version, isShippedVersion: true, analysisLevelVersionString, releaseTrackingData);
}

// Generate global analyzer config files for unshipped version.
// See https://github.com/dotnet/roslyn-analyzers/issues/6247 for details.

// Use 'unshippedVersion = maxShippedVersion + 1' for unshipped data.
var maxShippedVersion = versionsBuilder.Max();
var unshippedVersion = new Version(maxShippedVersion!.Major + 1, maxShippedVersion.Minor);
var unshippedAnalysisLevelVersionString = GetNormalizedVersionStringForEditorconfigFileNameSuffix(unshippedVersion);
CreateGlobalConfigsForVersion(unshippedVersion, isShippedVersion: false, unshippedAnalysisLevelVersionString, releaseTrackingData);
}

return true;

// Local functions.
void CreateGlobalConfigsForVersion(
Version version,
bool isShippedVersion,
string analysisLevelVersionString,
ImmutableArray<ReleaseTrackingData> releaseTrackingData)
{
foreach (var analysisMode in Enum.GetValues(typeof(AnalysisMode)))
{
CreateGlobalConfig(version, isShippedVersion, analysisLevelVersionString, (AnalysisMode)analysisMode!, releaseTrackingData, category: null);
foreach (var category in categories!)
{
CreateGlobalConfig(version, isShippedVersion, analysisLevelVersionString, (AnalysisMode)analysisMode!, releaseTrackingData, category);
}
}
}

void CreateGlobalConfig(
Version version,
bool isShippedVersion,
string analysisLevelVersionString,
AnalysisMode analysisMode,
ImmutableArray<ReleaseTrackingData> shippedFilesData,
ImmutableArray<ReleaseTrackingData> releaseTrackingData,
string? category)
{
var analysisLevelPropName = "AnalysisLevel";
Expand All @@ -793,7 +822,7 @@ void CreateGlobalConfig(
analysisMode,
category,
allRulesById,
(shippedFilesData, version));
(releaseTrackingData, version, isShippedVersion));
}

static string GetNormalizedVersionStringForEditorconfigFileNameSuffix(Version version)
Expand Down Expand Up @@ -1125,7 +1154,7 @@ private static void CreateGlobalconfig(
AnalysisMode analysisMode,
string? category,
SortedList<string, DiagnosticDescriptor> sortedRulesById,
(ImmutableArray<ReleaseTrackingData> shippedFiles, Version version) shippedReleaseData)
(ImmutableArray<ReleaseTrackingData> releaseTrackingData, Version version, bool isShippedVersion) releaseTrackingDataAndVersion)
{
Debug.Assert(editorconfigFileName.EndsWith(".editorconfig", StringComparison.Ordinal));

Expand All @@ -1135,7 +1164,7 @@ private static void CreateGlobalconfig(
analysisMode,
category,
sortedRulesById,
shippedReleaseData);
releaseTrackingDataAndVersion);
var directory = Directory.CreateDirectory(folder);
var editorconfigFilePath = Path.Combine(directory.FullName, editorconfigFileName.ToLowerInvariant());
File.WriteAllText(editorconfigFilePath, text);
Expand All @@ -1148,7 +1177,7 @@ static string GetGlobalconfigText(
AnalysisMode analysisMode,
string? category,
SortedList<string, DiagnosticDescriptor> sortedRulesById,
(ImmutableArray<ReleaseTrackingData> shippedFiles, Version version)? shippedReleaseData)
(ImmutableArray<ReleaseTrackingData> releaseTrackingData, Version version, bool isShippedVersion)? releaseTrackingDataAndVersion)
{
var result = new StringBuilder();
StartGlobalconfig();
Expand Down Expand Up @@ -1257,14 +1286,16 @@ bool AddRule(DiagnosticDescriptor rule, string? category)
effectiveSeverity = DiagnosticSeverity.Warning;
}

if (shippedReleaseData != null)
if (releaseTrackingDataAndVersion != null)
{
isEnabledByDefault = isEnabledRuleForNonDefaultAnalysisMode;
var maxVersion = shippedReleaseData.Value.version;
var maxVersion = releaseTrackingDataAndVersion.Value.isShippedVersion ?
releaseTrackingDataAndVersion.Value.version :
ReleaseTrackingHelper.UnshippedVersion;
var foundReleaseTrackingEntry = false;
foreach (var shippedFile in shippedReleaseData.Value.shippedFiles)
foreach (var releaseTrackingData in releaseTrackingDataAndVersion.Value.releaseTrackingData)
{
if (shippedFile.TryGetLatestReleaseTrackingLine(rule.Id, maxVersion, out _, out var releaseTrackingLine))
if (releaseTrackingData.TryGetLatestReleaseTrackingLine(rule.Id, maxVersion, out _, out var releaseTrackingLine))
{
foundReleaseTrackingEntry = true;

Expand Down

0 comments on commit 00c98ef

Please sign in to comment.