From 5cf604b0a4bb0fa1d1150cea21936f1e699498a5 Mon Sep 17 00:00:00 2001 From: Chris Simpson Date: Fri, 15 Jul 2022 20:46:56 +0100 Subject: [PATCH] feat: Adds missing properties to the branch protection response object (#2485) --- .../Clients/RepositoryBranchesClientTests.cs | 47 ++++++++--- .../OrganizationRepositoryWithTeamContext.cs | 7 +- ...ObservableRepositoryBranchesClientTests.cs | 61 +++++++++++--- .../Models/Request/BranchProtectionUpdate.cs | 64 +++++++++++++- Octokit/Models/Response/BranchProtection.cs | 83 +++++++++++++++++-- 5 files changed, 227 insertions(+), 35 deletions(-) diff --git a/Octokit.Tests.Integration/Clients/RepositoryBranchesClientTests.cs b/Octokit.Tests.Integration/Clients/RepositoryBranchesClientTests.cs index b4bb1481..6e2b747b 100644 --- a/Octokit.Tests.Integration/Clients/RepositoryBranchesClientTests.cs +++ b/Octokit.Tests.Integration/Clients/RepositoryBranchesClientTests.cs @@ -197,7 +197,6 @@ public class RepositoryBranchesClientTests { IRepositoryBranchesClient _client; RepositoryContext _userRepoContext; - OrganizationRepositoryWithTeamContext _orgRepoContext; public TheGetBranchProtectionMethod() { @@ -205,7 +204,6 @@ public class RepositoryBranchesClientTests _client = github.Repository.Branch; _userRepoContext = github.CreateRepositoryWithProtectedBranch().Result; - _orgRepoContext = github.CreateOrganizationRepositoryWithProtectedBranch().Result; } [IntegrationTest] @@ -213,7 +211,7 @@ public class RepositoryBranchesClientTests { var repoOwner = _userRepoContext.RepositoryOwner; var repoName = _userRepoContext.RepositoryName; - var protection = await _client.GetBranchProtection(repoOwner, repoName, "master"); + var protection = await _client.GetBranchProtection(repoOwner, repoName, "main"); Assert.True(protection.RequiredStatusChecks.Strict); Assert.Equal(2, protection.RequiredStatusChecks.Contexts.Count); @@ -225,13 +223,18 @@ public class RepositoryBranchesClientTests Assert.Null(protection.Restrictions); Assert.True(protection.EnforceAdmins.Enabled); + Assert.True(protection.RequiredLinearHistory.Enabled); + Assert.True(protection.AllowForcePushes.Enabled); + Assert.True(protection.AllowDeletions.Enabled); + Assert.False(protection.BlockCreations.Enabled); + Assert.True(protection.RequiredConversationResolution.Enabled); } [IntegrationTest] public async Task GetsBranchProtectionWithRepositoryId() { var repoId = _userRepoContext.RepositoryId; - var protection = await _client.GetBranchProtection(repoId, "master"); + var protection = await _client.GetBranchProtection(repoId, "main"); Assert.True(protection.RequiredStatusChecks.Strict); Assert.Equal(2, protection.RequiredStatusChecks.Contexts.Count); @@ -243,14 +246,39 @@ public class RepositoryBranchesClientTests Assert.Null(protection.Restrictions); Assert.True(protection.EnforceAdmins.Enabled); + Assert.True(protection.RequiredLinearHistory.Enabled); + Assert.True(protection.AllowForcePushes.Enabled); + Assert.True(protection.AllowDeletions.Enabled); + Assert.False(protection.BlockCreations.Enabled); + Assert.True(protection.RequiredConversationResolution.Enabled); } - [IntegrationTest] + public void Dispose() + { + if (_userRepoContext != null) + _userRepoContext.Dispose(); + } + } + + public class TheGetBranchOrgProtectionMethod : IDisposable + { + IRepositoryBranchesClient _client; + OrganizationRepositoryWithTeamContext _orgRepoContext; + + public TheGetBranchOrgProtectionMethod() + { + var github = Helper.GetAuthenticatedClient(); + _client = github.Repository.Branch; + + _orgRepoContext = github.CreateOrganizationRepositoryWithProtectedBranch().Result; + } + + [OrganizationTest] public async Task GetsBranchProtectionForOrgRepo() { var repoOwner = _orgRepoContext.RepositoryContext.RepositoryOwner; var repoName = _orgRepoContext.RepositoryContext.RepositoryName; - var protection = await _client.GetBranchProtection(repoOwner, repoName, "master"); + var protection = await _client.GetBranchProtection(repoOwner, repoName, "main"); Assert.True(protection.RequiredStatusChecks.Strict); Assert.Equal(2, protection.RequiredStatusChecks.Contexts.Count); @@ -266,11 +294,11 @@ public class RepositoryBranchesClientTests Assert.True(protection.EnforceAdmins.Enabled); } - [IntegrationTest] + [OrganizationTest] public async Task GetsBranchProtectionForOrgRepoWithRepositoryId() { var repoId = _orgRepoContext.RepositoryContext.RepositoryId; - var protection = await _client.GetBranchProtection(repoId, "master"); + var protection = await _client.GetBranchProtection(repoId, "main"); Assert.True(protection.RequiredStatusChecks.Strict); Assert.Equal(2, protection.RequiredStatusChecks.Contexts.Count); @@ -288,9 +316,6 @@ public class RepositoryBranchesClientTests public void Dispose() { - if (_userRepoContext != null) - _userRepoContext.Dispose(); - if (_orgRepoContext != null) _orgRepoContext.Dispose(); } diff --git a/Octokit.Tests.Integration/Helpers/OrganizationRepositoryWithTeamContext.cs b/Octokit.Tests.Integration/Helpers/OrganizationRepositoryWithTeamContext.cs index 8c36d503..c0e89ba7 100644 --- a/Octokit.Tests.Integration/Helpers/OrganizationRepositoryWithTeamContext.cs +++ b/Octokit.Tests.Integration/Helpers/OrganizationRepositoryWithTeamContext.cs @@ -34,9 +34,14 @@ namespace Octokit.Tests.Integration.Helpers new BranchProtectionRequiredStatusChecksUpdate(true, new[] { "build", "test" }), new BranchProtectionRequiredReviewsUpdate(true, true, 3), null, + true, + true, + true, + true, + false, true); - await client.Repository.Branch.UpdateBranchProtection(contextUserRepo.RepositoryOwner, contextUserRepo.RepositoryName, "master", update); + await client.Repository.Branch.UpdateBranchProtection(contextUserRepo.RepositoryOwner, contextUserRepo.RepositoryName, "main", update); return contextUserRepo; } diff --git a/Octokit.Tests.Integration/Reactive/ObservableRepositoryBranchesClientTests.cs b/Octokit.Tests.Integration/Reactive/ObservableRepositoryBranchesClientTests.cs index 8cbac07c..2e49b7e3 100644 --- a/Octokit.Tests.Integration/Reactive/ObservableRepositoryBranchesClientTests.cs +++ b/Octokit.Tests.Integration/Reactive/ObservableRepositoryBranchesClientTests.cs @@ -121,7 +121,6 @@ namespace Octokit.Tests.Integration { IObservableRepositoryBranchesClient _client; RepositoryContext _userRepoContext; - OrganizationRepositoryWithTeamContext _orgRepoContext; public TheUpdateBranchProtectionMethod() { @@ -129,7 +128,6 @@ namespace Octokit.Tests.Integration _client = new ObservableRepositoryBranchesClient(github); _userRepoContext = github.CreateRepositoryWithProtectedBranch().Result; - _orgRepoContext = github.CreateOrganizationRepositoryWithProtectedBranch().Result; } [IntegrationTest] @@ -142,7 +140,7 @@ namespace Octokit.Tests.Integration new BranchProtectionRequiredReviewsUpdate(false, true, 2), false); - var protection = await _client.UpdateBranchProtection(repoOwner, repoName, "master", update); + var protection = await _client.UpdateBranchProtection(repoOwner, repoName, "main", update); Assert.False(protection.RequiredStatusChecks.Strict); Assert.Equal(1, protection.RequiredStatusChecks.Contexts.Count); @@ -166,7 +164,7 @@ namespace Octokit.Tests.Integration new BranchProtectionRequiredReviewsUpdate(false, true, 2), false); - var protection = await _client.UpdateBranchProtection(repoId, "master", update); + var protection = await _client.UpdateBranchProtection(repoId, "main", update); Assert.False(protection.RequiredStatusChecks.Strict); Assert.Equal(1, protection.RequiredStatusChecks.Contexts.Count); @@ -181,7 +179,27 @@ namespace Octokit.Tests.Integration Assert.False(protection.EnforceAdmins.Enabled); } - [IntegrationTest] + public void Dispose() + { + if (_userRepoContext != null) + _userRepoContext.Dispose(); + } + } + + public class TheUpdateOrgBranchProtectionMethod : IDisposable + { + IObservableRepositoryBranchesClient _client; + OrganizationRepositoryWithTeamContext _orgRepoContext; + + public TheUpdateOrgBranchProtectionMethod() + { + var github = Helper.GetAuthenticatedClient(); + _client = new ObservableRepositoryBranchesClient(github); + + _orgRepoContext = github.CreateOrganizationRepositoryWithProtectedBranch().Result; + } + + [OrganizationTest] public async Task UpdatesBranchProtectionForOrgRepo() { var repoOwner = _orgRepoContext.RepositoryContext.RepositoryOwner; @@ -190,9 +208,14 @@ namespace Octokit.Tests.Integration new BranchProtectionRequiredStatusChecksUpdate(false, new[] { "new" }), new BranchProtectionRequiredReviewsUpdate(new BranchProtectionRequiredReviewsDismissalRestrictionsUpdate(false), false, false, 2), new BranchProtectionPushRestrictionsUpdate(), - false); + false, + true, + true, + true, + true, + true); - var protection = await _client.UpdateBranchProtection(repoOwner, repoName, "master", update); + var protection = await _client.UpdateBranchProtection(repoOwner, repoName, "main", update); Assert.False(protection.RequiredStatusChecks.Strict); Assert.Equal(1, protection.RequiredStatusChecks.Contexts.Count); @@ -206,9 +229,14 @@ namespace Octokit.Tests.Integration Assert.Empty(protection.Restrictions.Users); Assert.False(protection.EnforceAdmins.Enabled); + Assert.True(protection.RequiredLinearHistory.Enabled); + Assert.True(protection.AllowForcePushes.Enabled); + Assert.True(protection.AllowDeletions.Enabled); + Assert.True(protection.BlockCreations.Enabled); + Assert.True(protection.RequiredConversationResolution.Enabled); } - [IntegrationTest] + [OrganizationTest] public async Task UpdatesBranchProtectionForOrgRepoWithRepositoryId() { var repoId = _orgRepoContext.RepositoryContext.RepositoryId; @@ -216,9 +244,14 @@ namespace Octokit.Tests.Integration new BranchProtectionRequiredStatusChecksUpdate(false, new[] { "new" }), new BranchProtectionRequiredReviewsUpdate(new BranchProtectionRequiredReviewsDismissalRestrictionsUpdate(false), false, false, 2), new BranchProtectionPushRestrictionsUpdate(), - false); + false, + true, + true, + true, + true, + true); - var protection = await _client.UpdateBranchProtection(repoId, "master", update); + var protection = await _client.UpdateBranchProtection(repoId, "main", update); Assert.False(protection.RequiredStatusChecks.Strict); Assert.Equal(1, protection.RequiredStatusChecks.Contexts.Count); @@ -232,13 +265,15 @@ namespace Octokit.Tests.Integration Assert.Empty(protection.Restrictions.Users); Assert.False(protection.EnforceAdmins.Enabled); + Assert.True(protection.RequiredLinearHistory.Enabled); + Assert.True(protection.AllowForcePushes.Enabled); + Assert.True(protection.AllowDeletions.Enabled); + Assert.True(protection.BlockCreations.Enabled); + Assert.True(protection.RequiredConversationResolution.Enabled); } public void Dispose() { - if (_userRepoContext != null) - _userRepoContext.Dispose(); - if (_orgRepoContext != null) _orgRepoContext.Dispose(); } diff --git a/Octokit/Models/Request/BranchProtectionUpdate.cs b/Octokit/Models/Request/BranchProtectionUpdate.cs index 227730c3..1c2424cd 100644 --- a/Octokit/Models/Request/BranchProtectionUpdate.cs +++ b/Octokit/Models/Request/BranchProtectionUpdate.cs @@ -85,7 +85,10 @@ namespace Octokit /// Specifies if reviews are required to merge the pull request. Pass null to disable required reviews /// Specifies the requested push access restrictions (applies only to Organization owned repositories). Pass null to disable push access restrictions /// Specifies whether the protections applied to this branch also apply to repository admins - public BranchProtectionSettingsUpdate(BranchProtectionRequiredStatusChecksUpdate requiredStatusChecks, BranchProtectionRequiredReviewsUpdate requiredPullRequestReviews, BranchProtectionPushRestrictionsUpdate restrictions, bool enforceAdmins) + public BranchProtectionSettingsUpdate(BranchProtectionRequiredStatusChecksUpdate requiredStatusChecks, + BranchProtectionRequiredReviewsUpdate requiredPullRequestReviews, + BranchProtectionPushRestrictionsUpdate restrictions, + bool enforceAdmins) { RequiredStatusChecks = requiredStatusChecks; RequiredPullRequestReviews = requiredPullRequestReviews; @@ -93,6 +96,39 @@ namespace Octokit EnforceAdmins = enforceAdmins; } + /// + /// Create a BranchProtection update request + /// + /// Specifies the requested status check settings. Pass null to disable status checks + /// Specifies if reviews are required to merge the pull request. Pass null to disable required reviews + /// Specifies the requested push access restrictions (applies only to Organization owned repositories). Pass null to disable push access restrictions + /// Specifies whether the protections applied to this branch also apply to repository admins + /// Enforces a linear commit Git history + /// Permits force pushes to the protected branch + /// Allows deletion of the protected branch + /// The restrictions branch protection settings will also block pushes which create new branches + /// Requires all conversations on code to be resolved before a pull request can be merged + public BranchProtectionSettingsUpdate(BranchProtectionRequiredStatusChecksUpdate requiredStatusChecks, + BranchProtectionRequiredReviewsUpdate requiredPullRequestReviews, + BranchProtectionPushRestrictionsUpdate restrictions, + bool enforceAdmins, + bool requiredLinearHistory, + bool? allowForcePushes, + bool allowDeletions, + bool blockCreations, + bool requiredConversationResolution) + { + RequiredStatusChecks = requiredStatusChecks; + RequiredPullRequestReviews = requiredPullRequestReviews; + Restrictions = restrictions; + EnforceAdmins = enforceAdmins; + RequiredLinearHistory = requiredLinearHistory; + AllowForcePushes = allowForcePushes; + AllowDeletions = allowDeletions; + BlockCreations = blockCreations; + RequiredConversationResolution = requiredConversationResolution; + } + /// /// Status check settings for the protected branch /// @@ -116,6 +152,32 @@ namespace Octokit /// public bool EnforceAdmins { get; set; } + /// + /// Enforces a linear commit Git history. Default is false. + /// + public bool RequiredLinearHistory { get; set; } + + /// + /// Permits force pushes to the protected branch by anyone with write access to the repository. Default is false. + /// + public bool? AllowForcePushes { get; set; } + + /// + /// Allows deletion of the protected branch by anyone with write access to the repository. Default is false. + /// + public bool AllowDeletions { get; set; } + + /// + /// If set to true, the restrictions branch protection settings which limits who can push will also block pushes which create new branches, unless the push is initiated by a user, team, or app which has the ability to push. Default is false. + /// + public bool BlockCreations { get; set; } + + /// + /// Requires all conversations on code to be resolved before a pull request can be merged. Default is false. + /// + public bool RequiredConversationResolution { get; set; } + + internal string DebuggerDisplay { get diff --git a/Octokit/Models/Response/BranchProtection.cs b/Octokit/Models/Response/BranchProtection.cs index e73e8645..2c1703d1 100644 --- a/Octokit/Models/Response/BranchProtection.cs +++ b/Octokit/Models/Response/BranchProtection.cs @@ -9,41 +9,85 @@ namespace Octokit /// /// Protection details for a . /// - /// - /// Note: this is a PREVIEW api: https://developer.github.com/changes/2016-06-27-protected-branches-api-update/ - /// [DebuggerDisplay("{DebuggerDisplay,nq}")] public class BranchProtectionSettings { public BranchProtectionSettings() { } - public BranchProtectionSettings(BranchProtectionRequiredStatusChecks requiredStatusChecks, BranchProtectionPushRestrictions restrictions, BranchProtectionRequiredReviews requiredPullRequestReviews, EnforceAdmins enforceAdmins) + public BranchProtectionSettings(BranchProtectionRequiredStatusChecks requiredStatusChecks, + BranchProtectionRequiredReviews requiredPullRequestReviews, + BranchProtectionPushRestrictions restrictions, + EnforceAdmins enforceAdmins, + BranchProtectionEnabledCommon requiredLinearHistory, + BranchProtectionEnabledCommon allowForcePushes, + BranchProtectionEnabledCommon allowDeletions, + BranchProtectionEnabledCommon blockCreations, + BranchProtectionEnabledCommon requiredConversationResolution, + BranchProtectionEnabledCommon requiredSignatures) { RequiredStatusChecks = requiredStatusChecks; - Restrictions = restrictions; RequiredPullRequestReviews = requiredPullRequestReviews; + Restrictions = restrictions; EnforceAdmins = enforceAdmins; + RequiredLinearHistory = requiredLinearHistory; + AllowForcePushes = allowForcePushes; + AllowDeletions = allowDeletions; + BlockCreations = blockCreations; + RequiredConversationResolution = requiredConversationResolution; + RequiredSignatures = requiredSignatures; } + + /// /// Status check settings for the protected branch /// - public BranchProtectionRequiredStatusChecks RequiredStatusChecks { get; protected set; } + public BranchProtectionRequiredStatusChecks RequiredStatusChecks { get; private set; } /// /// Required review settings for the protected branch /// - public BranchProtectionRequiredReviews RequiredPullRequestReviews { get; protected set; } + public BranchProtectionRequiredReviews RequiredPullRequestReviews { get; private set; } /// /// Push access restrictions for the protected branch /// - public BranchProtectionPushRestrictions Restrictions { get; protected set; } + public BranchProtectionPushRestrictions Restrictions { get; private set; } /// /// Specifies whether the protections applied to this branch also apply to repository admins /// - public EnforceAdmins EnforceAdmins { get; protected set; } + public EnforceAdmins EnforceAdmins { get; private set; } + + /// + /// Specifies whether a linear history is required + /// + public BranchProtectionEnabledCommon RequiredLinearHistory { get; private set; } + + /// + /// Specifies whether force pushes are allowed + /// + public BranchProtectionEnabledCommon AllowForcePushes { get; private set; } + + /// + /// Specifies whether deletions are allowed + /// + public BranchProtectionEnabledCommon AllowDeletions { get; private set; } + + /// + /// Specifies whether creations can be blocked + /// + public BranchProtectionEnabledCommon BlockCreations { get; private set; } + + /// + /// Specifies whether conversation resolution iss required + /// + public BranchProtectionEnabledCommon RequiredConversationResolution { get; private set; } + + /// + /// Specifies whether signatures are required + /// + public BranchProtectionEnabledCommon RequiredSignatures { get; private set; } internal string DebuggerDisplay { @@ -239,4 +283,25 @@ namespace Octokit } } } + + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class BranchProtectionEnabledCommon + { + public BranchProtectionEnabledCommon() { } + + public BranchProtectionEnabledCommon(bool enabled) + { + Enabled = enabled; + } + + public bool Enabled { get; protected set; } + + internal string DebuggerDisplay + { + get + { + return string.Format(CultureInfo.InvariantCulture, "Enabled: {0}", Enabled); + } + } + } }