Skip to content

Commit

Permalink
Add base branch baseline file for additional PR filtering (#8264)
Browse files Browse the repository at this point in the history
  • Loading branch information
JimSuplizio authored May 14, 2024
1 parent 620272b commit 0d4a130
Showing 1 changed file with 64 additions and 11 deletions.
75 changes: 64 additions & 11 deletions tools/codeowners-utils/Azure.Sdk.Tools.CodeownersLinter/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,21 @@ static void Main(string[] args)
stopWatch.Start();

// The storage URIs are in the azure-sdk-write-teams-container-blobs pipeline variable group.
// The URIs do not contain the SAS.
var teamUserBlobStorageUriOption = new Option<string>
(name: "--teamUserBlobStorageURI",
description: "The team/user blob storage URI without the SAS.");
description: "The team/user blob storage URI.");
teamUserBlobStorageUriOption.AddAlias("-tUri");
teamUserBlobStorageUriOption.IsRequired = true;

var userOrgVisibilityBlobStorageUriOption = new Option<string>
(name: "--userOrgVisibilityBlobStorageURI",
description: "The user/org blob storage URI without the SAS.");
description: "The user/org blob storage URI.");
userOrgVisibilityBlobStorageUriOption.AddAlias("-uUri");
userOrgVisibilityBlobStorageUriOption.IsRequired = true;

var repoLabelBlobStorageUriOption = new Option<string>
(name: "--repoLabelBlobStorageURI",
description: "The repo/label blob storage URI without the SAS.");
description: "The repo/label blob storage URI.");
repoLabelBlobStorageUriOption.AddAlias("-rUri");
repoLabelBlobStorageUriOption.IsRequired = true;

Expand Down Expand Up @@ -68,6 +67,13 @@ static void Main(string[] args)
description: "Generate the baseline error file.");
generateBaselineOption.AddAlias("-gbl");

var baseBranchBaselineFileOption = new Option<string>
(name: "--baseBranchBaselineFile",
description: "The full path to base branch baseline file to be generated or used. The file will be generated if -gbl is set and used to further filter errors if -fbl is set.");
baseBranchBaselineFileOption.AddAlias("-bbf");
baseBranchBaselineFileOption.IsRequired = false;
baseBranchBaselineFileOption.SetDefaultValue(null);

var rootCommand = new RootCommand
{
teamUserBlobStorageUriOption,
Expand All @@ -76,7 +82,8 @@ static void Main(string[] args)
repoRootOption,
repoNameOption,
filterBaselineErrorsOption,
generateBaselineOption
generateBaselineOption,
baseBranchBaselineFileOption
};

int returnCode = 1;
Expand All @@ -98,13 +105,15 @@ static void Main(string[] args)
string repoName = context.ParseResult.GetValueForOption(repoNameOption);
bool filterBaselineErrors = context.ParseResult.GetValueForOption(filterBaselineErrorsOption);
bool generateBaseline = context.ParseResult.GetValueForOption(generateBaselineOption);
string baseBranchBaselineFile = context.ParseResult.GetValueForOption(baseBranchBaselineFileOption);
returnCode = LintCodeownersFile(teamUserBlobStorageUri,
userOrgVisibilityBlobStorageUri,
repoLabelBlobStorageUri,
repoRoot,
repoName,
filterBaselineErrors,
generateBaseline);
generateBaseline,
baseBranchBaselineFile);
});

rootCommand.Invoke(args);
Expand All @@ -124,6 +133,18 @@ static void Main(string[] args)
/// Verify the arguments and call to process the CODEOWNERS file. If errors are being filtered with a
/// baseline, or used to regenerate the baseline, that's done in here. Note that filtering errors and
/// regenerating the baseline cannot both be done in the same run.
///
/// The baseBranchBaselineFile
/// This file will be primarily used in PR validation where two calls will be made. be made. The first
/// call will use the -gbl option and generate the secondary file to a different location. It can't use
/// the standard CODEOWNERS_baseline_error.txt file because it'll be being used in combination with this
/// file. The second call, to verify CODEOWNERS changes in the PR, will verify against the default
/// CODEOWNERS_baseline_error.txt and, if there are any remaining errors, check to see if those exist in the
/// secondary baseline file. The reason for doing this is prevent PRs from being blocked if there are issues
/// in the baseline branch. The typical scenario here will be people leaving the company, the base branch's
/// CODEOWNERS hasn't yet been updated to reflect this and because of that any PRs with CODEOWNERS changes
/// would get blocked. If the remaining errors in the PR validation exist in the base branch's errors then
/// the linter will return a pass instead of a failure.
/// </summary>
/// <param name="teamUserBlobStorageUri">URI of the team/user data in blob storate</param>
/// <param name="userOrgVisibilityBlobStorageUri">URI of the org visibility in blob storage</param>
Expand All @@ -132,6 +153,7 @@ static void Main(string[] args)
/// <param name="repoName">The repository name, including org. Eg. Azure/azure-sdk</param>
/// <param name="filterBaselineErrors">Boolean, if true then errors should be filtered using the repository's baseline.</param>
/// <param name="generateBaseline">Boolean, if true then regenerate the baseline file from the error encountered during parsing.</param>
/// <param name="baseBranchBaselineFile">The name of the base branch baseline file to generate or use.</param>
/// <returns>integer, used to set the return code</returns>
/// <exception cref="ArgumentException">Thrown if any arguments, or argument combinations, are invalid.</exception>
static int LintCodeownersFile(string teamUserBlobStorageUri,
Expand All @@ -140,7 +162,8 @@ static int LintCodeownersFile(string teamUserBlobStorageUri,
string repoRoot,
string repoName,
bool filterBaselineErrors,
bool generateBaseline)
bool generateBaseline,
string baseBranchBaselineFile)
{
// Don't allow someone to create and use a baseline in the same run
if (filterBaselineErrors && generateBaseline)
Expand All @@ -165,7 +188,20 @@ static int LintCodeownersFile(string teamUserBlobStorageUri,
{
throw new ArgumentException($"The repository label data for {repoName} does not exist. Should this be running in this repository?");
}


bool useBaseBranchBaselineFile = false;
if (!string.IsNullOrEmpty(baseBranchBaselineFile))
{
if ((filterBaselineErrors && File.Exists(baseBranchBaselineFile)) || generateBaseline)
{
useBaseBranchBaselineFile = true;
}
else
{
throw new ArgumentException($"The base branch baseline file {baseBranchBaselineFile} does not exist.");
}
}

string codeownersBaselineFile = Path.Combine(repoRoot, ".github", BaselineConstants.BaselineErrorFile);
bool codeownersBaselineFileExists = false;
// If the baseline is to be used, verify that it exists.
Expand All @@ -192,7 +228,15 @@ static int LintCodeownersFile(string teamUserBlobStorageUri,
// Regenerate the baseline file if that option was selected
if (generateBaseline)
{
BaselineUtils baselineUtils = new BaselineUtils(codeownersBaselineFile);
BaselineUtils baselineUtils = null;
if (useBaseBranchBaselineFile)
{
baselineUtils = new BaselineUtils(baseBranchBaselineFile);
}
else
{
baselineUtils = new BaselineUtils(codeownersBaselineFile);
}
baselineUtils.GenerateBaseline(errors);
}

Expand All @@ -215,11 +259,20 @@ static int LintCodeownersFile(string teamUserBlobStorageUri,
errors = baselineUtils.FilterErrorsUsingBaseline(errors);
}
}

// After the file has been filered with the standard CODEOWNERS baseline file, if there are
// still remaining errors and there is a base branch baseline file, further filter with that
// file.
if (useBaseBranchBaselineFile && errors.Count > 0)
{
BaselineUtils baselineUtils = new BaselineUtils(baseBranchBaselineFile);
errors = baselineUtils.FilterErrorsUsingBaseline(errors);
}
}

int returnCode = 0;
// If there are errors, ensure the returnCode is non-zero and output the errors.
if (errors.Count > 0)
// If there are errors, and this isn't a baseline generation, ensure the returnCode is non-zero and output the errors.
if ((errors.Count > 0) && !generateBaseline)
{
returnCode = 1;

Expand Down

0 comments on commit 0d4a130

Please sign in to comment.