Skip to content

Commit

Permalink
Merge pull request #6258 from mavasani/FixTooling
Browse files Browse the repository at this point in the history
Enhance GenerateDocumentationAndConfigFiles tool to generate vNext globalconfig files
  • Loading branch information
mavasani authored Nov 16, 2022
2 parents ebaa318 + f88c0ae commit c5aa7bf
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 26 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
92 changes: 66 additions & 26 deletions src/Tools/GenerateDocumentationAndConfigFiles/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -666,7 +666,7 @@ async Task<bool> checkHelpLinkAsync(string helpLink)

async Task<bool> createGlobalConfigFilesAsync()
{
using var shippedFilesDataBuilder = ArrayBuilder<ReleaseTrackingData>.GetInstance();
using var releaseTrackingFilesDataBuilder = 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 +705,19 @@ 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);
var shippedFileExists = File.Exists(shippedFile);
var unshippedFileExists = File.Exists(unshippedFile);

if (shippedFileExists ^ unshippedFileExists)
{
var existingFile = shippedFileExists ? shippedFile : unshippedFile;
var nonExistingFile = shippedFileExists ? unshippedFile : shippedFile;
await Console.Error.WriteLineAsync($"Expected both '{shippedFile}' and '{unshippedFile}' to exist or not exist, but '{existingFile}' exists and '{nonExistingFile}' does not exist.").ConfigureAwait(false);
return false;
}

if (shippedFileExists)
{
sawShippedFile = true;

Expand All @@ -717,14 +729,24 @@ 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,
onDuplicateEntryInRelease: (_1, _2, _3, _4, line) => throw new Exception($"Duplicate entry in {shippedFile} at {line.LineNumber}: '{line}'"),
onInvalidEntry: (line, _2, _3, _4) => throw new Exception($"Invalid entry in {shippedFile} at {line.LineNumber}: '{line}'"),
onDuplicateEntryInRelease: (_1, _2, _3, _4, line) => throw new InvalidOperationException($"Duplicate entry in {shippedFile} at {line.LineNumber}: '{line}'"),
onInvalidEntry: (line, _2, _3, _4) => throw new InvalidOperationException($"Invalid entry in {shippedFile} at {line.LineNumber}: '{line}'"),
isShippedFile: true);
shippedFilesDataBuilder.Add(releaseTrackingData);
releaseTrackingFilesDataBuilder.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 InvalidOperationException($"Duplicate entry in {unshippedFile} at {line.LineNumber}: '{line}'"),
onInvalidEntry: (line, _2, _3, _4) => throw new InvalidOperationException($"Invalid entry in {unshippedFile} at {line.LineNumber}: '{line}'"),
isShippedFile: false);
releaseTrackingFilesDataBuilder.Add(releaseTrackingDataUnshipped);
}
#pragma warning disable CA1031 // Do not catch general exception types
catch (Exception ex)
Expand All @@ -744,33 +766,49 @@ async Task<bool> createGlobalConfigFilesAsync()

if (versionsBuilder.Count > 0)
{
var shippedFilesData = shippedFilesDataBuilder.ToImmutable();
var releaseTrackingData = releaseTrackingFilesDataBuilder.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, 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);
CreateGlobalConfigsForVersion(unshippedVersion, isShippedVersion: false, releaseTrackingData);
}

return true;

// Local functions.
void CreateGlobalConfigsForVersion(
Version version,
bool isShippedVersion,
ImmutableArray<ReleaseTrackingData> releaseTrackingData)
{
var analysisLevelVersionString = GetNormalizedVersionStringForEditorconfigFileNameSuffix(version);

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 +831,7 @@ void CreateGlobalConfig(
analysisMode,
category,
allRulesById,
(shippedFilesData, version));
(releaseTrackingData, version, isShippedVersion));
}

static string GetNormalizedVersionStringForEditorconfigFileNameSuffix(Version version)
Expand Down Expand Up @@ -1125,7 +1163,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 +1173,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 +1186,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 +1295,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 c5aa7bf

Please sign in to comment.