Skip to content

Commit b1a2cf5

Browse files
ChrisAnnnickfloyd
andauthored
[FEAT] Add support for "Require approval of the most recent reviewable push" (#2839)
Add support for "Require approval of the most recent reviewable push" Co-authored-by: Nick Floyd <[email protected]>
1 parent 3e92a69 commit b1a2cf5

File tree

4 files changed

+45
-10
lines changed

4 files changed

+45
-10
lines changed

Octokit.Tests.Integration/Clients/RepositoryBranchesClientTests.cs

+18
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ public async Task GetsBranchProtection()
292292
Assert.Null(protection.RequiredPullRequestReviews.DismissalRestrictions);
293293
Assert.True(protection.RequiredPullRequestReviews.DismissStaleReviews);
294294
Assert.True(protection.RequiredPullRequestReviews.RequireCodeOwnerReviews);
295+
Assert.True(protection.RequiredPullRequestReviews.RequireLastPushApproval);
295296

296297
Assert.Null(protection.Restrictions);
297298

@@ -320,6 +321,7 @@ public async Task GetsBranchProtectionWithRepositoryId()
320321
Assert.Null(protection.RequiredPullRequestReviews.DismissalRestrictions);
321322
Assert.True(protection.RequiredPullRequestReviews.DismissStaleReviews);
322323
Assert.True(protection.RequiredPullRequestReviews.RequireCodeOwnerReviews);
324+
Assert.True(protection.RequiredPullRequestReviews.RequireLastPushApproval);
323325

324326
Assert.Null(protection.Restrictions);
325327

@@ -349,6 +351,7 @@ public async Task GetsBranchProtectionForOrgRepo()
349351
Assert.Equal(0, protection.RequiredPullRequestReviews.DismissalRestrictions.Users.Count);
350352
Assert.True(protection.RequiredPullRequestReviews.DismissStaleReviews);
351353
Assert.True(protection.RequiredPullRequestReviews.RequireCodeOwnerReviews);
354+
Assert.True(protection.RequiredPullRequestReviews.RequireLastPushApproval);
352355

353356
Assert.Equal(1, protection.Restrictions.Teams.Count);
354357
Assert.Equal(0, protection.Restrictions.Users.Count);
@@ -373,6 +376,7 @@ public async Task GetsBranchProtectionForOrgRepoWithRepositoryId()
373376
Assert.Equal(0, protection.RequiredPullRequestReviews.DismissalRestrictions.Users.Count);
374377
Assert.True(protection.RequiredPullRequestReviews.DismissStaleReviews);
375378
Assert.True(protection.RequiredPullRequestReviews.RequireCodeOwnerReviews);
379+
Assert.True(protection.RequiredPullRequestReviews.RequireLastPushApproval);
376380

377381
Assert.Equal(1, protection.Restrictions.Teams.Count);
378382
Assert.Equal(0, protection.Restrictions.Users.Count);
@@ -404,6 +408,7 @@ public async Task UpdatesBranchProtection()
404408
Assert.Null(protection.RequiredPullRequestReviews.DismissalRestrictions);
405409
Assert.False(protection.RequiredPullRequestReviews.DismissStaleReviews);
406410
Assert.True(protection.RequiredPullRequestReviews.RequireCodeOwnerReviews);
411+
Assert.True(protection.RequiredPullRequestReviews.RequireLastPushApproval);
407412
Assert.Equal(2, protection.RequiredPullRequestReviews.RequiredApprovingReviewCount);
408413

409414
Assert.Null(protection.Restrictions);
@@ -432,6 +437,7 @@ public async Task UpdatesBranchProtectionWithRepositoryId()
432437
Assert.Null(protection.RequiredPullRequestReviews.DismissalRestrictions);
433438
Assert.False(protection.RequiredPullRequestReviews.DismissStaleReviews);
434439
Assert.True(protection.RequiredPullRequestReviews.RequireCodeOwnerReviews);
440+
Assert.True(protection.RequiredPullRequestReviews.RequireLastPushApproval);
435441
Assert.Equal(2, protection.RequiredPullRequestReviews.RequiredApprovingReviewCount);
436442

437443
Assert.Null(protection.Restrictions);
@@ -461,6 +467,7 @@ public async Task UpdatesBranchProtectionForOrgRepo()
461467
Assert.Null(protection.RequiredPullRequestReviews.DismissalRestrictions);
462468
Assert.False(protection.RequiredPullRequestReviews.DismissStaleReviews);
463469
Assert.False(protection.RequiredPullRequestReviews.RequireCodeOwnerReviews);
470+
Assert.False(protection.RequiredPullRequestReviews.RequireLastPushApproval);
464471
Assert.Equal(2, protection.RequiredPullRequestReviews.RequiredApprovingReviewCount);
465472

466473
Assert.Empty(protection.Restrictions.Teams);
@@ -490,6 +497,7 @@ public async Task UpdatesBranchProtectionForOrgRepoWithRepositoryId()
490497
Assert.Null(protection.RequiredPullRequestReviews.DismissalRestrictions);
491498
Assert.False(protection.RequiredPullRequestReviews.DismissStaleReviews);
492499
Assert.False(protection.RequiredPullRequestReviews.RequireCodeOwnerReviews);
500+
Assert.False(protection.RequiredPullRequestReviews.RequireLastPushApproval);
493501
Assert.Equal(2, protection.RequiredPullRequestReviews.RequiredApprovingReviewCount);
494502

495503
Assert.Empty(protection.Restrictions.Teams);
@@ -798,6 +806,7 @@ public async Task GetsReviewEnforcement()
798806
Assert.Null(requiredReviews.DismissalRestrictions);
799807
Assert.True(requiredReviews.DismissStaleReviews);
800808
Assert.True(requiredReviews.RequireCodeOwnerReviews);
809+
Assert.True(requiredReviews.RequireLastPushApproval);
801810
}
802811
}
803812

@@ -813,6 +822,7 @@ public async Task GetsReviewEnforcementWithRepositoryId()
813822
Assert.Null(requiredReviews.DismissalRestrictions);
814823
Assert.True(requiredReviews.DismissStaleReviews);
815824
Assert.True(requiredReviews.RequireCodeOwnerReviews);
825+
Assert.True(requiredReviews.RequireLastPushApproval);
816826
}
817827
}
818828

@@ -829,6 +839,7 @@ public async Task GetsReviewEnforcementForOrgRepo()
829839
Assert.Equal(0, requiredReviews.DismissalRestrictions.Users.Count);
830840
Assert.True(requiredReviews.DismissStaleReviews);
831841
Assert.True(requiredReviews.RequireCodeOwnerReviews);
842+
Assert.True(requiredReviews.RequireLastPushApproval);
832843
}
833844
}
834845

@@ -845,6 +856,7 @@ public async Task GetsReviewEnforcementForOrgRepoWithRepositoryId()
845856
Assert.Equal(0, requiredReviews.DismissalRestrictions.Users.Count);
846857
Assert.True(requiredReviews.DismissStaleReviews);
847858
Assert.True(requiredReviews.RequireCodeOwnerReviews);
859+
Assert.True(requiredReviews.RequireLastPushApproval);
848860
}
849861
}
850862
}
@@ -865,6 +877,7 @@ public async Task UpdatesReviewEnforcement()
865877
Assert.Null(requiredReviews.DismissalRestrictions);
866878
Assert.False(requiredReviews.DismissStaleReviews);
867879
Assert.True(requiredReviews.RequireCodeOwnerReviews);
880+
Assert.True(requiredReviews.RequireLastPushApproval);
868881
Assert.Equal(2, requiredReviews.RequiredApprovingReviewCount);
869882
}
870883
}
@@ -883,6 +896,7 @@ public async Task UpdatesReviewEnforcementWithRepositoryId()
883896
Assert.Null(requiredReviews.DismissalRestrictions);
884897
Assert.False(requiredReviews.DismissStaleReviews);
885898
Assert.True(requiredReviews.RequireCodeOwnerReviews);
899+
Assert.True(requiredReviews.RequireLastPushApproval);
886900
Assert.Equal(2, requiredReviews.RequiredApprovingReviewCount);
887901
}
888902
}
@@ -905,6 +919,7 @@ public async Task UpdatesReviewEnforcementForOrgRepo()
905919
Assert.Null(requiredReviews.DismissalRestrictions);
906920
Assert.False(requiredReviews.DismissStaleReviews);
907921
Assert.False(requiredReviews.RequireCodeOwnerReviews);
922+
Assert.False(requiredReviews.RequireLastPushApproval);
908923
Assert.Equal(2, requiredReviews.RequiredApprovingReviewCount);
909924
}
910925
}
@@ -927,6 +942,7 @@ public async Task UpdatesReviewEnforcementForOrgRepoWithRepositoryId()
927942
Assert.Null(requiredReviews.DismissalRestrictions);
928943
Assert.False(requiredReviews.DismissStaleReviews);
929944
Assert.False(requiredReviews.RequireCodeOwnerReviews);
945+
Assert.False(requiredReviews.RequireLastPushApproval);
930946
Assert.Equal(2, requiredReviews.RequiredApprovingReviewCount);
931947
}
932948
}
@@ -950,6 +966,7 @@ public async Task UpdatesReviewEnforcementForOrgRepoWithAdminOnly()
950966
Assert.Empty(requiredReviews.DismissalRestrictions.Users);
951967
Assert.False(requiredReviews.DismissStaleReviews);
952968
Assert.False(requiredReviews.RequireCodeOwnerReviews);
969+
Assert.False(requiredReviews.RequireLastPushApproval);
953970
Assert.Equal(2, requiredReviews.RequiredApprovingReviewCount);
954971
}
955972
}
@@ -973,6 +990,7 @@ public async Task UpdatesReviewEnforcementForOrgRepoWithAdminOnlyWithRepositoryI
973990
Assert.Empty(requiredReviews.DismissalRestrictions.Users);
974991
Assert.False(requiredReviews.DismissStaleReviews);
975992
Assert.False(requiredReviews.RequireCodeOwnerReviews);
993+
Assert.False(requiredReviews.RequireLastPushApproval);
976994
Assert.Equal(2, requiredReviews.RequiredApprovingReviewCount);
977995
}
978996
}

Octokit.Tests.Integration/Helpers/OrganizationRepositoryWithTeamContext.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ internal async static Task ProtectDefaultBranch(this IGitHubClient client, Repos
2828
// Protect default branch
2929
var update = new BranchProtectionSettingsUpdate(
3030
new BranchProtectionRequiredStatusChecksUpdate(true, new[] { "build", "test" }),
31-
new BranchProtectionRequiredReviewsUpdate(true, true, 3),
31+
new BranchProtectionRequiredReviewsUpdate(true, true, 3, true),
3232
null,
3333
true,
3434
true,
@@ -78,7 +78,7 @@ await client.Organization.Team.AddRepository(
7878
// Protect default branch
7979
var protection = new BranchProtectionSettingsUpdate(
8080
new BranchProtectionRequiredStatusChecksUpdate(true, new[] { "build", "test" }),
81-
new BranchProtectionRequiredReviewsUpdate(new BranchProtectionRequiredReviewsDismissalRestrictionsUpdate(new BranchProtectionTeamCollection { team.TeamName }), true, true, 3),
81+
new BranchProtectionRequiredReviewsUpdate(new BranchProtectionRequiredReviewsDismissalRestrictionsUpdate(new BranchProtectionTeamCollection { team.TeamName }), true, true, 3, true),
8282
new BranchProtectionPushRestrictionsUpdate(new BranchProtectionTeamCollection { team.TeamName }),
8383
true);
8484
await client.Repository.Branch.UpdateBranchProtection(repoContext.RepositoryOwner, repoContext.RepositoryName, repoContext.RepositoryDefaultBranch, protection);
@@ -105,7 +105,7 @@ await client.Organization.Team.AddRepository(
105105
// Protect default branch
106106
var protection = new BranchProtectionSettingsUpdate(
107107
new BranchProtectionRequiredStatusChecksUpdate(true, new[] { "build", "test" }),
108-
new BranchProtectionRequiredReviewsUpdate(new BranchProtectionRequiredReviewsDismissalRestrictionsUpdate(new BranchProtectionTeamCollection { contextOrgTeam.TeamName }), true, true, 3),
108+
new BranchProtectionRequiredReviewsUpdate(new BranchProtectionRequiredReviewsDismissalRestrictionsUpdate(new BranchProtectionTeamCollection { contextOrgTeam.TeamName }), true, true, 3, true),
109109
new BranchProtectionPushRestrictionsUpdate(new BranchProtectionTeamCollection { contextOrgTeam.TeamName }),
110110
true);
111111
await client.Repository.Branch.UpdateBranchProtection(contextOrgRepo.RepositoryOwner, contextOrgRepo.RepositoryName, "main", protection);

Octokit/Models/Request/BranchProtectionUpdate.cs

+14-4
Original file line numberDiff line numberDiff line change
@@ -370,11 +370,13 @@ public class BranchProtectionRequiredReviewsUpdate
370370
/// <param name="dismissStaleReviews">Dismiss approved reviews automatically when a new commit is pushed.</param>
371371
/// <param name="requireCodeOwnerReviews">Blocks merge until code owners have reviewed.</param>
372372
/// <param name="requiredApprovingReviewCount">Specify the number of reviewers required to approve pull requests. Use a number between 1 and 6.</param>
373-
public BranchProtectionRequiredReviewsUpdate(bool dismissStaleReviews, bool requireCodeOwnerReviews, int requiredApprovingReviewCount)
373+
/// <param name="requireLastPushApproval">Whether the most recent push must be approved by someone other than the person who pushed it. Default: false.</param>
374+
public BranchProtectionRequiredReviewsUpdate(bool dismissStaleReviews, bool requireCodeOwnerReviews, int requiredApprovingReviewCount, bool requireLastPushApproval = false)
374375
{
375376
DismissStaleReviews = dismissStaleReviews;
376377
RequireCodeOwnerReviews = requireCodeOwnerReviews;
377378
RequiredApprovingReviewCount = requiredApprovingReviewCount;
379+
RequireLastPushApproval = requireLastPushApproval;
378380
}
379381

380382
/// <summary>
@@ -384,14 +386,16 @@ public BranchProtectionRequiredReviewsUpdate(bool dismissStaleReviews, bool requ
384386
/// <param name="dismissStaleReviews">Dismiss approved reviews automatically when a new commit is pushed.</param>
385387
/// <param name="requireCodeOwnerReviews">Blocks merge until code owners have reviewed.</param>
386388
/// <param name="requiredApprovingReviewCount">Specify the number of reviewers required to approve pull requests. Use a number between 1 and 6.</param>
387-
public BranchProtectionRequiredReviewsUpdate(BranchProtectionRequiredReviewsDismissalRestrictionsUpdate dismissalRestrictions, bool dismissStaleReviews, bool requireCodeOwnerReviews, int requiredApprovingReviewCount)
389+
/// <param name="requireLastPushApproval">Whether the most recent push must be approved by someone other than the person who pushed it. Default: false.</param>
390+
public BranchProtectionRequiredReviewsUpdate(BranchProtectionRequiredReviewsDismissalRestrictionsUpdate dismissalRestrictions, bool dismissStaleReviews, bool requireCodeOwnerReviews, int requiredApprovingReviewCount, bool requireLastPushApproval = false)
388391
{
389392
Ensure.ArgumentNotNull(dismissalRestrictions, nameof(dismissalRestrictions));
390393

391394
DismissalRestrictions = dismissalRestrictions;
392395
DismissStaleReviews = dismissStaleReviews;
393396
RequireCodeOwnerReviews = requireCodeOwnerReviews;
394397
RequiredApprovingReviewCount = requiredApprovingReviewCount;
398+
RequireLastPushApproval = requireLastPushApproval;
395399
}
396400

397401
/// <summary>
@@ -413,16 +417,22 @@ public BranchProtectionRequiredReviewsUpdate(BranchProtectionRequiredReviewsDism
413417
/// Specify the number of reviewers required to approve pull requests. Use a number between 1 and 6.
414418
/// </summary>
415419
public int RequiredApprovingReviewCount { get; protected set; }
420+
421+
/// <summary>
422+
/// Whether the most recent push must be approved by someone other than the person who pushed it. Default: false
423+
/// </summary>
424+
public bool RequireLastPushApproval { get; protected set; }
416425

417426
internal string DebuggerDisplay
418427
{
419428
get
420429
{
421-
return string.Format(CultureInfo.InvariantCulture, "DismissalRestrictions: {0} DismissStaleReviews: {1} RequireCodeOwnerReviews: {2} RequiredApprovingReviewCount: {3}",
430+
return string.Format(CultureInfo.InvariantCulture, "DismissalRestrictions: {0} DismissStaleReviews: {1} RequireCodeOwnerReviews: {2} RequiredApprovingReviewCount: {3} RequireLastPushApproval: {4}",
422431
DismissalRestrictions?.DebuggerDisplay ?? "disabled",
423432
DismissStaleReviews,
424433
RequireCodeOwnerReviews,
425-
RequiredApprovingReviewCount);
434+
RequiredApprovingReviewCount,
435+
RequireLastPushApproval);
426436
}
427437
}
428438
}

Octokit/Models/Response/BranchProtection.cs

+10-3
Original file line numberDiff line numberDiff line change
@@ -236,12 +236,13 @@ public class BranchProtectionRequiredReviews
236236
{
237237
public BranchProtectionRequiredReviews() { }
238238

239-
public BranchProtectionRequiredReviews(BranchProtectionRequiredReviewsDismissalRestrictions dismissalRestrictions, bool dismissStaleReviews, bool requireCodeOwnerReviews, int requiredApprovingReviewCount)
239+
public BranchProtectionRequiredReviews(BranchProtectionRequiredReviewsDismissalRestrictions dismissalRestrictions, bool dismissStaleReviews, bool requireCodeOwnerReviews, int requiredApprovingReviewCount, bool requireLastPushApproval)
240240
{
241241
DismissalRestrictions = dismissalRestrictions;
242242
DismissStaleReviews = dismissStaleReviews;
243243
RequireCodeOwnerReviews = requireCodeOwnerReviews;
244244
RequiredApprovingReviewCount = requiredApprovingReviewCount;
245+
RequireLastPushApproval = requireLastPushApproval;
245246
}
246247

247248
/// <summary>
@@ -263,16 +264,22 @@ public BranchProtectionRequiredReviews(BranchProtectionRequiredReviewsDismissalR
263264
/// Specify the number of reviewers required to approve pull requests. Use a number between 1 and 6.
264265
/// </summary>
265266
public int RequiredApprovingReviewCount { get; private set; }
267+
268+
/// <summary>
269+
/// Whether the most recent push must be approved by someone other than the person who pushed it. Default: false
270+
/// </summary>
271+
public bool RequireLastPushApproval { get; protected set; }
266272

267273
internal string DebuggerDisplay
268274
{
269275
get
270276
{
271-
return string.Format(CultureInfo.InvariantCulture, "DismissalRestrictions: {0} DismissStaleReviews: {1} RequireCodeOwnerReviews: {2} RequiredApprovingReviewCount: {3}",
277+
return string.Format(CultureInfo.InvariantCulture, "DismissalRestrictions: {0} DismissStaleReviews: {1} RequireCodeOwnerReviews: {2} RequiredApprovingReviewCount: {3} RequireLastPushApproval: {4}",
272278
DismissalRestrictions?.DebuggerDisplay ?? "disabled",
273279
DismissStaleReviews,
274280
RequireCodeOwnerReviews,
275-
RequiredApprovingReviewCount);
281+
RequiredApprovingReviewCount,
282+
RequireLastPushApproval);
276283
}
277284
}
278285
}

0 commit comments

Comments
 (0)