public static void VerifyBlock()

in tools/codeowners-utils/Azure.Sdk.Tools.CodeownersUtils/Verification/CodeownersLinter.cs [102:265]


        public static void VerifyBlock(DirectoryUtils directoryUtils,
                                       OwnerDataUtils ownerData,
                                       RepoLabelDataUtils repoLabelData,
                                       List<BaseError> errors,
                                       int startBlockLineNumber, 
                                       int endBlockLineNumber, 
                                       List<string> codeownersFile,
                                       bool singleLineVerification = true)
        {
            List<string> blockErrorStrings = new List<string>();
            // The codeownersFile as a list<string> is 0 based, for reporting purposes it needs
            // to be 1 based to match the exact line in the CODEOWNERS file.
            int startLineNumberForReporting = startBlockLineNumber + 1;
            int endLineNumberForReporting = endBlockLineNumber + 1;
            bool endsWithSourceOwnerLine = ParsingUtils.IsSourcePathOwnerLine(codeownersFile[endBlockLineNumber]);
            // Booleans for every moniker, will be set to true when found, are used to verify the block
            // contains what it needs to contain for the monikers found within it.
            bool blockHasAzureSdkOwners = false;
            bool blockHasMissingFolder = false;
            bool blockHasPRLabel = false;
            bool blockHasServiceLabel = false;
            bool blockHasServiceOwners = false;

            for (int blockLine = startBlockLineNumber; blockLine <= endBlockLineNumber; blockLine++)
            {
                string line = codeownersFile[blockLine];
                int lineNumberForReporting = blockLine + 1;
                bool isSourcePathOwnerLine = ParsingUtils.IsSourcePathOwnerLine(line);
                if (isSourcePathOwnerLine)
                {
                    if (singleLineVerification)
                    {
                        VerifySingleLine(directoryUtils,
                                         ownerData,
                                         repoLabelData,
                                         errors,
                                         lineNumberForReporting,
                                         line,
                                         isSourcePathOwnerLine,
                                         !endsWithSourceOwnerLine);
                    }
                }
                else
                {
                    string moniker = MonikerUtils.ParseMonikerFromLine(line);
                    // This can happen if there's a comment line in the block, skip the line
                    if (null == moniker)
                    {
                        continue;
                    }
                    switch (moniker)
                    {
                        case MonikerConstants.AzureSdkOwners:
                            if (blockHasAzureSdkOwners)
                            {
                                blockErrorStrings.Add($"{MonikerConstants.AzureSdkOwners}{ErrorMessageConstants.DuplicateMonikerInBlockPartial}");
                            }
                            blockHasAzureSdkOwners = true;
                            break;
                        case MonikerConstants.PRLabel:
                            if (blockHasPRLabel)
                            {
                                blockErrorStrings.Add($"{MonikerConstants.PRLabel}{ErrorMessageConstants.DuplicateMonikerInBlockPartial}");
                            }
                            blockHasPRLabel = true;
                            break;
                        case MonikerConstants.MissingFolder:
                            if (blockHasMissingFolder)
                            {
                                blockErrorStrings.Add($"{MonikerConstants.MissingFolder}{ErrorMessageConstants.DuplicateMonikerInBlockPartial}");
                            }
                            blockHasMissingFolder = true;
                            break;
                        case MonikerConstants.ServiceLabel:
                            if (blockHasServiceLabel)
                            {
                                blockErrorStrings.Add($"{MonikerConstants.ServiceLabel}{ErrorMessageConstants.DuplicateMonikerInBlockPartial}");
                            }
                            blockHasServiceLabel = true;
                            break;
                        case MonikerConstants.ServiceOwners:
                            if (blockHasServiceOwners)
                            {
                                blockErrorStrings.Add($"{MonikerConstants.ServiceOwners}{ErrorMessageConstants.DuplicateMonikerInBlockPartial}");
                            }
                            blockHasServiceOwners = true;
                            break;
                        default:
                            // This shouldn't get here unless someone adds a new moniker and forgets to add it to the switch statement
                            throw new ArgumentException($"Unexpected moniker '{moniker}' found  on line {lineNumberForReporting}\nLine={line}");
                    }

                    if (singleLineVerification)
                    {
                        VerifySingleLine(directoryUtils,
                                         ownerData,
                                         repoLabelData,
                                         errors,
                                         lineNumberForReporting,
                                         line,
                                         isSourcePathOwnerLine,
                                         !endsWithSourceOwnerLine, // If the block ends in a source path/owner line then we don't expect owners on moniker lines
                                         moniker);
                    }
                }
            }

            // After the block has been processed, ensure that any monikers are paired correctly with other
            // monikers or source path/owners

            // If the block is a single source path/owners line then there's nothing else to be done since there
            // can't be any block errors.
            if (startBlockLineNumber == endBlockLineNumber && endsWithSourceOwnerLine)
            {
                return;
            }

            // AzureSdkOwners must be part of a block of that a ServiceLabel entry as the AzureSdkOwners are associated with
            // that ServiceLabel
            if (blockHasAzureSdkOwners && !blockHasServiceLabel)
            {
                blockErrorStrings.Add(ErrorMessageConstants.AzureSdkOwnersMustBeWithServiceLabel);
            }

            if (blockHasServiceOwners && !blockHasServiceLabel)
            {
                blockErrorStrings.Add(ErrorMessageConstants.ServiceOwnersMustBeWithServiceLabel);
            }

            // PRLabel moniker must be in a block that ends with a source path/owner line
            if (blockHasPRLabel && !endsWithSourceOwnerLine)
            {
                blockErrorStrings.Add($"{MonikerConstants.PRLabel}{ErrorMessageConstants.NeedsToEndWithSourceOwnerPartial}");
            }

            // ServiceLabel needs to be part of a block that has AzureSdkOwners or one of; ServiceOwners or #/<NotInRepo>/
            // (MonikerConstants.MissingFolder), or ends in a source path/owner line both not both.
            if (blockHasServiceLabel)
            {
                if (!endsWithSourceOwnerLine && !blockHasServiceOwners && !blockHasMissingFolder && !blockHasAzureSdkOwners)
                {
                    blockErrorStrings.Add(ErrorMessageConstants.ServiceLabelNeedsOwners);
                }
                else if (endsWithSourceOwnerLine && (blockHasServiceOwners || blockHasMissingFolder))
                {
                    blockErrorStrings.Add(ErrorMessageConstants.ServiceLabelHasTooManyOwners);
                }
                else if (blockHasServiceOwners && blockHasMissingFolder)
                {
                    blockErrorStrings.Add(ErrorMessageConstants.ServiceLabelHasTooManyOwnerMonikers);
                }
            }

            if (blockErrorStrings.Count > 0)
            {
                List<string> blockLines = new List<string>();
                blockLines.AddRange(codeownersFile.GetRange(startBlockLineNumber, (endBlockLineNumber - startBlockLineNumber) + 1));
                errors.Add(new BlockFormattingError(startLineNumberForReporting,
                                                    endLineNumberForReporting,
                                                    blockLines,
                                                    blockErrorStrings));

            }
        }