Skip to content

Commit c5aa7bf

Browse files
authored
Merge pull request #6258 from mavasani/FixTooling
Enhance GenerateDocumentationAndConfigFiles tool to generate vNext globalconfig files
2 parents ebaa318 + f88c0ae commit c5aa7bf

File tree

2 files changed

+72
-26
lines changed

2 files changed

+72
-26
lines changed

src/Directory.Build.targets

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@
2424
<!-- Unshipped release -->
2525
<ItemGroup Condition="'$(ReleaseTrackingOptOut)' != 'true' AND Exists('$(MSBuildProjectDirectory)\AnalyzerReleases.Unshipped.md')">
2626
<AdditionalFiles Include="$(MSBuildProjectDirectory)\AnalyzerReleases.Unshipped.md" />
27+
<!-- Copy the unshipped releases file to output directory so it can be used in 'GenerateGlobalAnalyzerConfigs' post-build target -->
28+
<!-- Include unshipped file also as 'None' - Workaround for 'CopyToOutputDirectory' not being respected for additional files -->
29+
<None Update="AnalyzerReleases.Unshipped.md">
30+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
31+
<Link>AnalyzerReleases\$(AssemblyName)\AnalyzerReleases.Unshipped.md</Link>
32+
</None>
2733
</ItemGroup>
2834
<!-- Shipped releases -->
2935
<ItemGroup Condition="'$(ReleaseTrackingOptOut)' != 'true' AND Exists('$(MSBuildProjectDirectory)\AnalyzerReleases.Shipped.md')">

src/Tools/GenerateDocumentationAndConfigFiles/Program.cs

Lines changed: 66 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -666,7 +666,7 @@ async Task<bool> checkHelpLinkAsync(string helpLink)
666666

667667
async Task<bool> createGlobalConfigFilesAsync()
668668
{
669-
using var shippedFilesDataBuilder = ArrayBuilder<ReleaseTrackingData>.GetInstance();
669+
using var releaseTrackingFilesDataBuilder = ArrayBuilder<ReleaseTrackingData>.GetInstance();
670670
using var versionsBuilder = PooledHashSet<Version>.GetInstance();
671671

672672
// Validate all assemblies exist on disk and can be loaded.
@@ -705,7 +705,19 @@ async Task<bool> createGlobalConfigFilesAsync()
705705

706706
var assemblyName = Path.GetFileNameWithoutExtension(assembly);
707707
var shippedFile = Path.Combine(assemblyDir, "AnalyzerReleases", assemblyName, ReleaseTrackingHelper.ShippedFileName);
708-
if (File.Exists(shippedFile))
708+
var unshippedFile = Path.Combine(assemblyDir, "AnalyzerReleases", assemblyName, ReleaseTrackingHelper.UnshippedFileName);
709+
var shippedFileExists = File.Exists(shippedFile);
710+
var unshippedFileExists = File.Exists(unshippedFile);
711+
712+
if (shippedFileExists ^ unshippedFileExists)
713+
{
714+
var existingFile = shippedFileExists ? shippedFile : unshippedFile;
715+
var nonExistingFile = shippedFileExists ? unshippedFile : shippedFile;
716+
await Console.Error.WriteLineAsync($"Expected both '{shippedFile}' and '{unshippedFile}' to exist or not exist, but '{existingFile}' exists and '{nonExistingFile}' does not exist.").ConfigureAwait(false);
717+
return false;
718+
}
719+
720+
if (shippedFileExists)
709721
{
710722
sawShippedFile = true;
711723

@@ -717,14 +729,24 @@ async Task<bool> createGlobalConfigFilesAsync()
717729

718730
try
719731
{
732+
// Read shipped file
720733
using var fileStream = File.OpenRead(shippedFile);
721734
var sourceText = SourceText.From(fileStream);
722735
var releaseTrackingData = ReleaseTrackingHelper.ReadReleaseTrackingData(shippedFile, sourceText,
723-
onDuplicateEntryInRelease: (_1, _2, _3, _4, line) => throw new Exception($"Duplicate entry in {shippedFile} at {line.LineNumber}: '{line}'"),
724-
onInvalidEntry: (line, _2, _3, _4) => throw new Exception($"Invalid entry in {shippedFile} at {line.LineNumber}: '{line}'"),
736+
onDuplicateEntryInRelease: (_1, _2, _3, _4, line) => throw new InvalidOperationException($"Duplicate entry in {shippedFile} at {line.LineNumber}: '{line}'"),
737+
onInvalidEntry: (line, _2, _3, _4) => throw new InvalidOperationException($"Invalid entry in {shippedFile} at {line.LineNumber}: '{line}'"),
725738
isShippedFile: true);
726-
shippedFilesDataBuilder.Add(releaseTrackingData);
739+
releaseTrackingFilesDataBuilder.Add(releaseTrackingData);
727740
versionsBuilder.AddRange(releaseTrackingData.Versions);
741+
742+
// Read unshipped file
743+
using var fileStreamUnshipped = File.OpenRead(unshippedFile);
744+
var sourceTextUnshipped = SourceText.From(fileStreamUnshipped);
745+
var releaseTrackingDataUnshipped = ReleaseTrackingHelper.ReadReleaseTrackingData(unshippedFile, sourceTextUnshipped,
746+
onDuplicateEntryInRelease: (_1, _2, _3, _4, line) => throw new InvalidOperationException($"Duplicate entry in {unshippedFile} at {line.LineNumber}: '{line}'"),
747+
onInvalidEntry: (line, _2, _3, _4) => throw new InvalidOperationException($"Invalid entry in {unshippedFile} at {line.LineNumber}: '{line}'"),
748+
isShippedFile: false);
749+
releaseTrackingFilesDataBuilder.Add(releaseTrackingDataUnshipped);
728750
}
729751
#pragma warning disable CA1031 // Do not catch general exception types
730752
catch (Exception ex)
@@ -744,33 +766,49 @@ async Task<bool> createGlobalConfigFilesAsync()
744766

745767
if (versionsBuilder.Count > 0)
746768
{
747-
var shippedFilesData = shippedFilesDataBuilder.ToImmutable();
769+
var releaseTrackingData = releaseTrackingFilesDataBuilder.ToImmutableArray();
748770

749-
// Generate global analyzer config files for each shipped version, if required.
771+
// Generate global analyzer config files for each shipped version.
750772
foreach (var version in versionsBuilder)
751773
{
752-
var analysisLevelVersionString = GetNormalizedVersionStringForEditorconfigFileNameSuffix(version);
753-
754-
foreach (var analysisMode in Enum.GetValues(typeof(AnalysisMode)))
755-
{
756-
CreateGlobalConfig(version, analysisLevelVersionString, (AnalysisMode)analysisMode!, shippedFilesData, category: null);
757-
foreach (var category in categories)
758-
{
759-
CreateGlobalConfig(version, analysisLevelVersionString, (AnalysisMode)analysisMode!, shippedFilesData, category);
760-
}
761-
}
774+
CreateGlobalConfigsForVersion(version, isShippedVersion: true, releaseTrackingData);
762775
}
776+
777+
// Generate global analyzer config files for unshipped version.
778+
// See https://github.com/dotnet/roslyn-analyzers/issues/6247 for details.
779+
780+
// Use 'unshippedVersion = maxShippedVersion + 1' for unshipped data.
781+
var maxShippedVersion = versionsBuilder.Max();
782+
var unshippedVersion = new Version(maxShippedVersion!.Major + 1, maxShippedVersion.Minor);
783+
CreateGlobalConfigsForVersion(unshippedVersion, isShippedVersion: false, releaseTrackingData);
763784
}
764785

765786
return true;
766787

767788
// Local functions.
789+
void CreateGlobalConfigsForVersion(
790+
Version version,
791+
bool isShippedVersion,
792+
ImmutableArray<ReleaseTrackingData> releaseTrackingData)
793+
{
794+
var analysisLevelVersionString = GetNormalizedVersionStringForEditorconfigFileNameSuffix(version);
795+
796+
foreach (var analysisMode in Enum.GetValues(typeof(AnalysisMode)))
797+
{
798+
CreateGlobalConfig(version, isShippedVersion, analysisLevelVersionString, (AnalysisMode)analysisMode!, releaseTrackingData, category: null);
799+
foreach (var category in categories!)
800+
{
801+
CreateGlobalConfig(version, isShippedVersion, analysisLevelVersionString, (AnalysisMode)analysisMode!, releaseTrackingData, category);
802+
}
803+
}
804+
}
768805

769806
void CreateGlobalConfig(
770807
Version version,
808+
bool isShippedVersion,
771809
string analysisLevelVersionString,
772810
AnalysisMode analysisMode,
773-
ImmutableArray<ReleaseTrackingData> shippedFilesData,
811+
ImmutableArray<ReleaseTrackingData> releaseTrackingData,
774812
string? category)
775813
{
776814
var analysisLevelPropName = "AnalysisLevel";
@@ -793,7 +831,7 @@ void CreateGlobalConfig(
793831
analysisMode,
794832
category,
795833
allRulesById,
796-
(shippedFilesData, version));
834+
(releaseTrackingData, version, isShippedVersion));
797835
}
798836

799837
static string GetNormalizedVersionStringForEditorconfigFileNameSuffix(Version version)
@@ -1125,7 +1163,7 @@ private static void CreateGlobalconfig(
11251163
AnalysisMode analysisMode,
11261164
string? category,
11271165
SortedList<string, DiagnosticDescriptor> sortedRulesById,
1128-
(ImmutableArray<ReleaseTrackingData> shippedFiles, Version version) shippedReleaseData)
1166+
(ImmutableArray<ReleaseTrackingData> releaseTrackingData, Version version, bool isShippedVersion) releaseTrackingDataAndVersion)
11291167
{
11301168
Debug.Assert(editorconfigFileName.EndsWith(".editorconfig", StringComparison.Ordinal));
11311169

@@ -1135,7 +1173,7 @@ private static void CreateGlobalconfig(
11351173
analysisMode,
11361174
category,
11371175
sortedRulesById,
1138-
shippedReleaseData);
1176+
releaseTrackingDataAndVersion);
11391177
var directory = Directory.CreateDirectory(folder);
11401178
var editorconfigFilePath = Path.Combine(directory.FullName, editorconfigFileName.ToLowerInvariant());
11411179
File.WriteAllText(editorconfigFilePath, text);
@@ -1148,7 +1186,7 @@ static string GetGlobalconfigText(
11481186
AnalysisMode analysisMode,
11491187
string? category,
11501188
SortedList<string, DiagnosticDescriptor> sortedRulesById,
1151-
(ImmutableArray<ReleaseTrackingData> shippedFiles, Version version)? shippedReleaseData)
1189+
(ImmutableArray<ReleaseTrackingData> releaseTrackingData, Version version, bool isShippedVersion)? releaseTrackingDataAndVersion)
11521190
{
11531191
var result = new StringBuilder();
11541192
StartGlobalconfig();
@@ -1257,14 +1295,16 @@ bool AddRule(DiagnosticDescriptor rule, string? category)
12571295
effectiveSeverity = DiagnosticSeverity.Warning;
12581296
}
12591297

1260-
if (shippedReleaseData != null)
1298+
if (releaseTrackingDataAndVersion != null)
12611299
{
12621300
isEnabledByDefault = isEnabledRuleForNonDefaultAnalysisMode;
1263-
var maxVersion = shippedReleaseData.Value.version;
1301+
var maxVersion = releaseTrackingDataAndVersion.Value.isShippedVersion ?
1302+
releaseTrackingDataAndVersion.Value.version :
1303+
ReleaseTrackingHelper.UnshippedVersion;
12641304
var foundReleaseTrackingEntry = false;
1265-
foreach (var shippedFile in shippedReleaseData.Value.shippedFiles)
1305+
foreach (var releaseTrackingData in releaseTrackingDataAndVersion.Value.releaseTrackingData)
12661306
{
1267-
if (shippedFile.TryGetLatestReleaseTrackingLine(rule.Id, maxVersion, out _, out var releaseTrackingLine))
1307+
if (releaseTrackingData.TryGetLatestReleaseTrackingLine(rule.Id, maxVersion, out _, out var releaseTrackingLine))
12681308
{
12691309
foundReleaseTrackingEntry = true;
12701310

0 commit comments

Comments
 (0)