Пример #1
0
        public static int Main(string[] args)
        {
            const int expectedArguments = 9;

            if (args.Length != expectedArguments)
            {
                Console.Error.WriteLine($"Expected {expectedArguments} arguments, found {args.Length}: {string.Join(';', args)}");
                return(1);
            }

            var    outputDir                   = args[0];
            var    packageName                 = args[1];
            string targetsFileDir              = args[2];
            string targetsFileName             = args[3];
            var    assemblyList                = args[4].Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).ToList();
            var    binDirectory                = args[5];
            var    configuration               = args[6];
            var    tfm                         = args[7];
            var    releaseTrackingOptOutString = args[8];

            if (!bool.TryParse(releaseTrackingOptOutString, out bool releaseTrackingOptOut))
            {
                releaseTrackingOptOut = false;
            }

            using var shippedFilesDataBuilder = ArrayBuilder <ReleaseTrackingData> .GetInstance();

            using var versionsBuilder = PooledHashSet <Version> .GetInstance();

            // Validate all assemblies exist on disk and can be loaded.
            foreach (string assembly in assemblyList)
            {
                var assemblyPath = GetAssemblyPath(assembly);
                if (!File.Exists(assemblyPath))
                {
                    Console.Error.WriteLine($"'{assemblyPath}' does not exist");
                    return(2);
                }

                try
                {
                    _ = Assembly.LoadFrom(assemblyPath);
                }
#pragma warning disable CA1031 // Do not catch general exception types
                catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
                {
                    Console.Error.WriteLine(ex.Message);
                    return(3);
                }
            }

            // Compute descriptors by rule ID and shipped analyzer release versions and shipped data.
            var allRulesById   = new SortedList <string, DiagnosticDescriptor>();
            var sawShippedFile = false;
            foreach (string assembly in assemblyList)
            {
                var assemblyPath          = GetAssemblyPath(assembly);
                var analyzerFileReference = new AnalyzerFileReference(assemblyPath, AnalyzerAssemblyLoader.Instance);
                analyzerFileReference.AnalyzerLoadFailed += AnalyzerFileReference_AnalyzerLoadFailed;
                var analyzers = analyzerFileReference.GetAnalyzersForAllLanguages();

                foreach (var analyzer in analyzers)
                {
                    foreach (var rule in analyzer.SupportedDiagnostics)
                    {
                        allRulesById[rule.Id] = rule;
                    }
                }

                var assemblyDir = Path.GetDirectoryName(assemblyPath);
                if (assemblyDir is null)
                {
                    continue;
                }
                var assemblyName = Path.GetFileNameWithoutExtension(assembly);
                var shippedFile  = Path.Combine(assemblyDir, "AnalyzerReleases", assemblyName, ReleaseTrackingHelper.ShippedFileName);
                if (File.Exists(shippedFile))
                {
                    sawShippedFile = true;

                    if (releaseTrackingOptOut)
                    {
                        Console.Error.WriteLine($"'{shippedFile}' exists but was not expected");
                        return(4);
                    }

                    try
                    {
                        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}'"),
                                                                                                isShippedFile: true);
                        shippedFilesDataBuilder.Add(releaseTrackingData);
                        versionsBuilder.AddRange(releaseTrackingData.Versions);
                    }
#pragma warning disable CA1031 // Do not catch general exception types
                    catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
                    {
                        Console.Error.WriteLine(ex.Message);
                        return(5);
                    }
                }
            }

            if (!releaseTrackingOptOut && !sawShippedFile)
            {
                Console.Error.WriteLine($"Could not find any 'AnalyzerReleases.Shipped.md' file");
                return(6);
            }

            if (versionsBuilder.Count > 0)
            {
                var shippedFilesData = shippedFilesDataBuilder.ToImmutable();

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

                    foreach (var analysisMode in Enum.GetValues(typeof(AnalysisMode)))
                    {
                        CreateEditorconfig(
                            outputDir,
                            $"AnalysisLevel_{analysisLevelVersionString}_{analysisMode}.editorconfig",
                            $"Rules from '{version}' release with '{analysisMode}' analysis mode",
                            $"Rules with enabled-by-default state from '{version}' release with '{analysisMode}' analysis mode. Rules that are first released in a version later than '{version}' are disabled.",
                            (AnalysisMode)analysisMode !,
                            allRulesById,
                            (shippedFilesData, version));
                    }
                }
            }

            CreateTargetsFile(targetsFileDir, targetsFileName, packageName);

            return(0);
Пример #2
0
        public static int Main(string[] args)
        {
            const int expectedArguments = 9;

            if (args.Length != expectedArguments)
            {
                Console.Error.WriteLine($"Expected {expectedArguments} arguments, found {args.Length}: {string.Join(';', args)}");
                return(1);
            }

            var    outputDir                   = args[0];
            var    packageName                 = args[1];
            string targetsFileDir              = args[2];
            string targetsFileName             = args[3];
            var    assemblyList                = args[4].Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).ToList();
            var    binDirectory                = args[5];
            var    configuration               = args[6];
            var    tfm                         = args[7];
            var    releaseTrackingOptOutString = args[8];

            if (!bool.TryParse(releaseTrackingOptOutString, out bool releaseTrackingOptOut))
            {
                releaseTrackingOptOut = false;
            }

            using var shippedFilesDataBuilder = ArrayBuilder <ReleaseTrackingData> .GetInstance();

            using var versionsBuilder = PooledHashSet <Version> .GetInstance();

            // Validate all assemblies exist on disk and can be loaded.
            foreach (string assembly in assemblyList)
            {
                var assemblyPath = GetAssemblyPath(assembly);
                if (!File.Exists(assemblyPath))
                {
                    Console.Error.WriteLine($"'{assemblyPath}' does not exist");
                    return(2);
                }

                try
                {
                    _ = Assembly.LoadFrom(assemblyPath);
                }
#pragma warning disable CA1031 // Do not catch general exception types
                catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
                {
                    Console.Error.WriteLine(ex.Message);
                    return(3);
                }
            }

            // Compute descriptors by rule ID and shipped analyzer release versions and shipped data.
            var allRulesById = new SortedList <string, DiagnosticDescriptor>();
            var hasInfoOrHiddenDiagnostic = false;
            var sawShippedFile            = false;
            foreach (string assembly in assemblyList)
            {
                var assemblyPath          = GetAssemblyPath(assembly);
                var analyzerFileReference = new AnalyzerFileReference(assemblyPath, AnalyzerAssemblyLoader.Instance);
                analyzerFileReference.AnalyzerLoadFailed += AnalyzerFileReference_AnalyzerLoadFailed;
                var analyzers = analyzerFileReference.GetAnalyzersForAllLanguages();

                foreach (var analyzer in analyzers)
                {
                    foreach (var rule in analyzer.SupportedDiagnostics)
                    {
                        allRulesById[rule.Id]     = rule;
                        hasInfoOrHiddenDiagnostic = hasInfoOrHiddenDiagnostic ||
                                                    rule.IsEnabledByDefault && (rule.DefaultSeverity == DiagnosticSeverity.Info || rule.DefaultSeverity == DiagnosticSeverity.Hidden);
                    }
                }

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

                    if (releaseTrackingOptOut)
                    {
                        Console.Error.WriteLine($"'{shippedFile}' exists but was not expected");
                        return(4);
                    }

                    try
                    {
                        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}'"),
                                                                                                isShippedFile: true);
                        shippedFilesDataBuilder.Add(releaseTrackingData);
                        versionsBuilder.AddRange(releaseTrackingData.Versions);
                    }
#pragma warning disable CA1031 // Do not catch general exception types
                    catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
                    {
                        Console.Error.WriteLine(ex.Message);
                        return(5);
                    }
                }
            }

            if (!releaseTrackingOptOut && !sawShippedFile)
            {
                Console.Error.WriteLine($"Could not find any 'AnalyzerReleases.Shipped.md' file");
                return(6);
            }

            // Bail out if following conditions hold for the analyzer package:
            //  1. No Info/Hidden diagnostic in the package: No need for have different global analyzer config for build and live analysis.
            //  2. No shipped releases: User cannot choose a version specific global analyzer config.
            if (!hasInfoOrHiddenDiagnostic && versionsBuilder.Count == 0)
            {
                return(0);
            }

            var shippedFilesData = shippedFilesDataBuilder.ToImmutable();

            // Generate build and live analysis global analyzer config files for latest/unshipped version.
            CreateGlobalAnalyzerConfig(
                "BuildRules",
                "All build rules with default severity",
                "All build rules (warnings/errors) with default severity. Rules with IsEnabledByDefault = false or default severity Suggestion/Hidden are disabled.",
                EditorConfigKind.CommandLine);

            CreateGlobalAnalyzerConfig(
                "LiveAnalysisRules",
                "All rules with default severity",
                "All rules are enabled with default severity. Rules with IsEnabledByDefault = false are disabled.",
                EditorConfigKind.LiveAnalysis);

            // Generate build and live analysis global analyzer config files for each shipped version.
            foreach (var version in versionsBuilder)
            {
                var versionString = version.ToString().Replace(".", "_", StringComparison.Ordinal);
                CreateGlobalAnalyzerConfig(
                    $"BuildRulesVersion{versionString}",
                    $"All '{version}' build rules with default severity",
                    $"All '{version}' build rules (warnings/errors) with default severity. Rules with IsEnabledByDefault = false or first released in a version later then {version} or default severity Suggestion/Hidden are disabled.",
                    EditorConfigKind.CommandLine,
                    (shippedFilesData, version));

                CreateGlobalAnalyzerConfig(
                    $"LiveAnalysisRules{versionString}",
                    $"All '{version}' rules with default severity",
                    $"All '{version}' rules are enabled with default severity. Rules with IsEnabledByDefault = false or first released in a version later then {version} are disabled.",
                    EditorConfigKind.LiveAnalysis,
                    (shippedFilesData, version));
            }

            CreateTargetsFile(targetsFileDir, targetsFileName, packageName);

            return(0);