@@ -21,22 +21,21 @@ static void Main(string[] args)
2121 stopWatch . Start ( ) ;
2222
2323 // The storage URIs are in the azure-sdk-write-teams-container-blobs pipeline variable group.
24- // The URIs do not contain the SAS.
2524 var teamUserBlobStorageUriOption = new Option < string >
2625 ( name : "--teamUserBlobStorageURI" ,
27- description : "The team/user blob storage URI without the SAS ." ) ;
26+ description : "The team/user blob storage URI." ) ;
2827 teamUserBlobStorageUriOption . AddAlias ( "-tUri" ) ;
2928 teamUserBlobStorageUriOption . IsRequired = true ;
3029
3130 var userOrgVisibilityBlobStorageUriOption = new Option < string >
3231 ( name : "--userOrgVisibilityBlobStorageURI" ,
33- description : "The user/org blob storage URI without the SAS ." ) ;
32+ description : "The user/org blob storage URI." ) ;
3433 userOrgVisibilityBlobStorageUriOption . AddAlias ( "-uUri" ) ;
3534 userOrgVisibilityBlobStorageUriOption . IsRequired = true ;
3635
3736 var repoLabelBlobStorageUriOption = new Option < string >
3837 ( name : "--repoLabelBlobStorageURI" ,
39- description : "The repo/label blob storage URI without the SAS ." ) ;
38+ description : "The repo/label blob storage URI." ) ;
4039 repoLabelBlobStorageUriOption . AddAlias ( "-rUri" ) ;
4140 repoLabelBlobStorageUriOption . IsRequired = true ;
4241
@@ -68,6 +67,13 @@ static void Main(string[] args)
6867 description : "Generate the baseline error file." ) ;
6968 generateBaselineOption . AddAlias ( "-gbl" ) ;
7069
70+ var baseBranchBaselineFileOption = new Option < string >
71+ ( name : "--baseBranchBaselineFile" ,
72+ 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." ) ;
73+ baseBranchBaselineFileOption . AddAlias ( "-bbf" ) ;
74+ baseBranchBaselineFileOption . IsRequired = false ;
75+ baseBranchBaselineFileOption . SetDefaultValue ( null ) ;
76+
7177 var rootCommand = new RootCommand
7278 {
7379 teamUserBlobStorageUriOption ,
@@ -76,7 +82,8 @@ static void Main(string[] args)
7682 repoRootOption ,
7783 repoNameOption ,
7884 filterBaselineErrorsOption ,
79- generateBaselineOption
85+ generateBaselineOption ,
86+ baseBranchBaselineFileOption
8087 } ;
8188
8289 int returnCode = 1 ;
@@ -98,13 +105,15 @@ static void Main(string[] args)
98105 string repoName = context . ParseResult . GetValueForOption ( repoNameOption ) ;
99106 bool filterBaselineErrors = context . ParseResult . GetValueForOption ( filterBaselineErrorsOption ) ;
100107 bool generateBaseline = context . ParseResult . GetValueForOption ( generateBaselineOption ) ;
108+ string baseBranchBaselineFile = context . ParseResult . GetValueForOption ( baseBranchBaselineFileOption ) ;
101109 returnCode = LintCodeownersFile ( teamUserBlobStorageUri ,
102110 userOrgVisibilityBlobStorageUri ,
103111 repoLabelBlobStorageUri ,
104112 repoRoot ,
105113 repoName ,
106114 filterBaselineErrors ,
107- generateBaseline ) ;
115+ generateBaseline ,
116+ baseBranchBaselineFile ) ;
108117 } ) ;
109118
110119 rootCommand . Invoke ( args ) ;
@@ -124,6 +133,18 @@ static void Main(string[] args)
124133 /// Verify the arguments and call to process the CODEOWNERS file. If errors are being filtered with a
125134 /// baseline, or used to regenerate the baseline, that's done in here. Note that filtering errors and
126135 /// regenerating the baseline cannot both be done in the same run.
136+ ///
137+ /// The baseBranchBaselineFile
138+ /// This file will be primarily used in PR validation where two calls will be made. be made. The first
139+ /// call will use the -gbl option and generate the secondary file to a different location. It can't use
140+ /// the standard CODEOWNERS_baseline_error.txt file because it'll be being used in combination with this
141+ /// file. The second call, to verify CODEOWNERS changes in the PR, will verify against the default
142+ /// CODEOWNERS_baseline_error.txt and, if there are any remaining errors, check to see if those exist in the
143+ /// secondary baseline file. The reason for doing this is prevent PRs from being blocked if there are issues
144+ /// in the baseline branch. The typical scenario here will be people leaving the company, the base branch's
145+ /// CODEOWNERS hasn't yet been updated to reflect this and because of that any PRs with CODEOWNERS changes
146+ /// would get blocked. If the remaining errors in the PR validation exist in the base branch's errors then
147+ /// the linter will return a pass instead of a failure.
127148 /// </summary>
128149 /// <param name="teamUserBlobStorageUri">URI of the team/user data in blob storate</param>
129150 /// <param name="userOrgVisibilityBlobStorageUri">URI of the org visibility in blob storage</param>
@@ -132,6 +153,7 @@ static void Main(string[] args)
132153 /// <param name="repoName">The repository name, including org. Eg. Azure/azure-sdk</param>
133154 /// <param name="filterBaselineErrors">Boolean, if true then errors should be filtered using the repository's baseline.</param>
134155 /// <param name="generateBaseline">Boolean, if true then regenerate the baseline file from the error encountered during parsing.</param>
156+ /// <param name="baseBranchBaselineFile">The name of the base branch baseline file to generate or use.</param>
135157 /// <returns>integer, used to set the return code</returns>
136158 /// <exception cref="ArgumentException">Thrown if any arguments, or argument combinations, are invalid.</exception>
137159 static int LintCodeownersFile ( string teamUserBlobStorageUri ,
@@ -140,7 +162,8 @@ static int LintCodeownersFile(string teamUserBlobStorageUri,
140162 string repoRoot ,
141163 string repoName ,
142164 bool filterBaselineErrors ,
143- bool generateBaseline )
165+ bool generateBaseline ,
166+ string baseBranchBaselineFile )
144167 {
145168 // Don't allow someone to create and use a baseline in the same run
146169 if ( filterBaselineErrors && generateBaseline )
@@ -165,7 +188,20 @@ static int LintCodeownersFile(string teamUserBlobStorageUri,
165188 {
166189 throw new ArgumentException ( $ "The repository label data for { repoName } does not exist. Should this be running in this repository?") ;
167190 }
168-
191+
192+ bool useBaseBranchBaselineFile = false ;
193+ if ( ! string . IsNullOrEmpty ( baseBranchBaselineFile ) )
194+ {
195+ if ( ( filterBaselineErrors && File . Exists ( baseBranchBaselineFile ) ) || generateBaseline )
196+ {
197+ useBaseBranchBaselineFile = true ;
198+ }
199+ else
200+ {
201+ throw new ArgumentException ( $ "The base branch baseline file { baseBranchBaselineFile } does not exist.") ;
202+ }
203+ }
204+
169205 string codeownersBaselineFile = Path . Combine ( repoRoot , ".github" , BaselineConstants . BaselineErrorFile ) ;
170206 bool codeownersBaselineFileExists = false ;
171207 // If the baseline is to be used, verify that it exists.
@@ -192,7 +228,15 @@ static int LintCodeownersFile(string teamUserBlobStorageUri,
192228 // Regenerate the baseline file if that option was selected
193229 if ( generateBaseline )
194230 {
195- BaselineUtils baselineUtils = new BaselineUtils ( codeownersBaselineFile ) ;
231+ BaselineUtils baselineUtils = null ;
232+ if ( useBaseBranchBaselineFile )
233+ {
234+ baselineUtils = new BaselineUtils ( baseBranchBaselineFile ) ;
235+ }
236+ else
237+ {
238+ baselineUtils = new BaselineUtils ( codeownersBaselineFile ) ;
239+ }
196240 baselineUtils . GenerateBaseline ( errors ) ;
197241 }
198242
@@ -215,11 +259,20 @@ static int LintCodeownersFile(string teamUserBlobStorageUri,
215259 errors = baselineUtils . FilterErrorsUsingBaseline ( errors ) ;
216260 }
217261 }
262+
263+ // After the file has been filered with the standard CODEOWNERS baseline file, if there are
264+ // still remaining errors and there is a base branch baseline file, further filter with that
265+ // file.
266+ if ( useBaseBranchBaselineFile && errors . Count > 0 )
267+ {
268+ BaselineUtils baselineUtils = new BaselineUtils ( baseBranchBaselineFile ) ;
269+ errors = baselineUtils . FilterErrorsUsingBaseline ( errors ) ;
270+ }
218271 }
219272
220273 int returnCode = 0 ;
221- // If there are errors, ensure the returnCode is non-zero and output the errors.
222- if ( errors . Count > 0 )
274+ // If there are errors, and this isn't a baseline generation, ensure the returnCode is non-zero and output the errors.
275+ if ( ( errors . Count > 0 ) && ! generateBaseline )
223276 {
224277 returnCode = 1 ;
225278
0 commit comments