From 2217645bf05363fa52fc35bf91bdbebc84f8204c Mon Sep 17 00:00:00 2001 From: Simon Heather Date: Sun, 14 Jun 2020 12:39:25 +0100 Subject: [PATCH 1/4] New GitHubRpositoryBranchProtectionRule functions --- GitHubBranches.ps1 | 514 ++++++++++++++++++++++++++++++++- GitHubCore.ps1 | 2 + PowerShellForGitHub.psd1 | 4 + Tests/GitHubBranches.tests.ps1 | 170 +++++++++++ USAGE.md | 26 ++ 5 files changed, 715 insertions(+), 1 deletion(-) diff --git a/GitHubBranches.ps1 b/GitHubBranches.ps1 index 357d5792..0e4b981f 100644 --- a/GitHubBranches.ps1 +++ b/GitHubBranches.ps1 @@ -154,6 +154,518 @@ filter Get-GitHubRepositoryBranch return (Invoke-GHRestMethodMultipleResult @params | Add-GitHubBranchAdditionalProperties) } +function Get-GitHubRepositoryBranchProtectionRule +{ +<# + .SYNOPSIS + Retrieve branch protection rules for a given GitHub repository. + + .DESCRIPTION + Retrieve branch protection rules for a given GitHub repository. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER Name + Name of the specific branch to be retrieved. If not supplied, all branches will be retrieved. + + .PARAMETER Uri + Uri for the repository. + The OwnerName and RepositoryName will be extracted from here instead of needing to provide + them individually. + + .PARAMETER OwnerName + Owner of the repository. + If not supplied here, the DefaultOwnerName configuration property value will be used. + + .PARAMETER RepositoryName + Name of the repository. + If not supplied here, the DefaultRepositoryName configuration property value will be used. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .PARAMETER NoStatus + If this switch is specified, long-running commands will run on the main thread + with no commandline status update. When not specified, those commands run in + the background, enabling the command prompt to provide status information. + If not supplied here, the DefaultNoStatus configuration property value will be used. + + .INPUTS + None + + .OUTPUTS + PSCustomObject + + .EXAMPLE + Get-GitHubRepositoryBranchProtectionRule -Name master -OwnerName Microsoft -RepositoryName PowerShellForGitHub + + Retrieves branch protection rules for the master branch of the PowerShellForGithub repository. + + .EXAMPLE + Get-GitHubRepositoryBranchProtectionRule -Name master -Uri 'https://github.com/PowerShell/PowerShellForGitHub' + + Retrieves branch protection rules for the master branch of the PowerShellForGithub repository. +#> + [CmdletBinding( + PositionalBinding = $false, + DefaultParameterSetName='Elements')] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '', + Justification='One or more parameters (like NoStatus) are only referenced by helper methods which get access to it from the stack via Get-Variable -Scope 1.')] + param( + [Parameter( + Mandatory, + Position = 1)] + [string] $Name, + + [Parameter( + Mandatory, + Position = 2, + ParameterSetName='Uri')] + [string] $Uri, + + [Parameter(ParameterSetName='Elements')] + [string] $OwnerName, + + [Parameter(ParameterSetName='Elements')] + [string] $RepositoryName, + + [string] $AccessToken, + + [switch] $NoStatus + ) + + Write-InvocationLog + + $elements = Resolve-RepositoryElements + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties = @{ + 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) + 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) + } + + $params = @{ + UriFragment = "repos/$OwnerName/$RepositoryName/branches/$Name/protection" + Description = "Getting branch protection status for $RepositoryName" + Method = 'Get' + AcceptHeader = $script:lukeCageAcceptHeader + AccessToken = $AccessToken + TelemetryEventName = $MyInvocation.MyCommand.Name + TelemetryProperties = $telemetryProperties + NoStatus = (Resolve-ParameterWithDefaultConfigurationValue -Name NoStatus -ConfigValueName DefaultNoStatus) + } + + return Invoke-GHRestMethod @params +} + +function Set-GitHubRepositoryBranchProtectionRule +{ +<# + .SYNOPSIS + Set branch protection rules for a given GitHub repository. + + .DESCRIPTION + Set branch protection rules for a given GitHub repository. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER Name + Name of the specific branch to be retrieved. If not supplied, all branches will be retrieved. + + .PARAMETER Uri + Uri for the repository. + The OwnerName and RepositoryName will be extracted from here instead of needing to provide + them individually. + + .PARAMETER OwnerName + Owner of the repository. + If not supplied here, the DefaultOwnerName configuration property value will be used. + + .PARAMETER RepositoryName + Name of the repository. + If not supplied here, the DefaultRepositoryName configuration property value will be used. + + .PARAMETER StatusChecks + The list of status checks to require in order to merge into the branch. + + .PARAMETER RequireUpToDateBranches + Require branches to be up to date before merging. + + .PARAMETER EnforceAdmins + Enforce all configured restrictions for administrators. + + .PARAMETER DismissalUsers + Specify which users can dismiss pull request reviews. + + .PARAMETER DismissalTeams + Specify which teams can dismiss pull request reviews. + + .PARAMETER DismissStaleReviews + If specified, approving reviews when someone pushes a new commit are automatically + dismissed. + + .PARAMETER RequireCodeOwnerReviews + Blocks merging pull requests until code owners review them. + + .PARAMETER RequiredApprovingReviewCount + Specify the number of reviewers required to approve pull requests. Use a number between 1 + and 6. + + .PARAMETER RestrictPushUsers + Specify which users have push access. + + .PARAMETER RestrictPushTeams + Specify which teams have push access. + + .PARAMETER RestrictPushApps + Specify which apps have push access. + + .PARAMETER RequiredLinearHistory + Enforces a linear commit Git history, which prevents anyone from pushing merge commits to a + branch. + + .PARAMETER AllowForcePushes + Permits force pushes to the protected branch by anyone with write access to the repository. + + .PARAMETER AllowDeletions + Allows deletion of the protected branch by anyone with write access to the repository. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .PARAMETER NoStatus + If this switch is specified, long-running commands will run on the main thread + with no commandline status update. When not specified, those commands run in + the background, enabling the command prompt to provide status information. + If not supplied here, the DefaultNoStatus configuration property value will be used. + + .INPUTS + None + + .OUTPUTS + PSCustomObject + + .EXAMPLE + Set-GitHubRepositoryBranchProtectionRule -Name master -OwnerName Microsoft -RepositoryName PowerShellForGitHub -EnforceAdmins + + Sets a branch protection rule for the master branch of the PowerShellForGithub repository + enforcing all configuration restrictions for administrators. + + .EXAMPLE + Set-GitHubRepositoryBranchProtectionRule -Name master -Uri 'https://github.com/PowerShell/PowerShellForGitHub' -RequiredApprovingReviewCount 1 + + Sets a branch protection rule for the master branch of the PowerShellForGithub repository + requiring one approving review. +#> + [CmdletBinding( + PositionalBinding = $false, + SupportsShouldProcess, + DefaultParameterSetName='Elements')] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '', + Justification='One or more parameters (like NoStatus) are only referenced by helper methods which get access to it from the stack via Get-Variable -Scope 1.')] + param( + [Parameter( + Mandatory, + Position = 1)] + [string] $Name, + + [Parameter( + Mandatory, + Position = 2, + ParameterSetName='Uri')] + [string] $Uri, + + [Parameter(ParameterSetName='Elements')] + [string] $OwnerName, + + [Parameter(ParameterSetName='Elements')] + [string] $RepositoryName, + + [string[]] $StatusChecks, + + [switch] $RequireUpToDateBranches, + + [switch] $EnforceAdmins, + + [string[]] $DismissalUsers, + + [string[]] $DismissalTeams, + + [switch] $DismissStaleReviews, + + [switch] $RequireCodeOwnerReviews, + + [ValidateRange(1,6)] + [int] $RequiredApprovingReviewCount, + + [string[]] $RestrictPushUsers, + + [string[]] $RestrictPushTeams, + + [string[]] $RestrictPushApps, + + [switch]$RequiredLinearHistory, + + [switch] $AllowForcePushes, + + [switch] $AllowDeletions, + + [string] $AccessToken, + + [switch] $NoStatus + ) + + $elements = Resolve-RepositoryElements + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties = @{ + OwnerName = (Get-PiiSafeString -PlainText $OwnerName) + RepositoryName = (Get-PiiSafeString -PlainText $RepositoryName) + } + + if ($PSBoundParameters.ContainsKey('StatusChecks')) + { + $requiredStatusChecks = @{ + strict = $RequireUpToDateBranches.ToBool() + contexts = $StatusChecks + } + } + else + { + $requiredStatusChecks = $null + } + + $dismissalRestrictions = @{} + + if ($PSBoundParameters.ContainsKey('DismissalUsers')) { + $dismissalRestrictions['users'] = $DismissalUsers } + if ($PSBoundParameters.ContainsKey('DismissalTeams')) + { + $teams = Get-GitHubTeam -OwnerName $OwnerName -RepositoryName $RepositoryName | + Where-Object -FilterScript { $DismissalTeams -contains $_.name } + $dismissalRestrictions['teams'] = @($teams.slug) + } + + $requiredPullRequestReviews = @{} + + if ($PSBoundParameters.ContainsKey('DismissStaleReviews')) { + $requiredPullRequestReviews['dismiss_stale_reviews'] = $DismissStaleReviews.ToBool() } + if ($PSBoundParameters.ContainsKey('RequireCodeOwnerReviews')) { + $requiredPullRequestReviews['require_code_owner_reviews'] = $RequireCodeOwnerReviews.ToBool() } + if ($PSBoundParameters.ContainsKey('RequiredApprovingReviewCount')) { + $requiredPullRequestReviews['required_approving_review_count'] = $RequiredApprovingReviewCount } + + if ($dismissalRestrictions.count -gt 0) + { + $requiredPullRequestReviews['dismissal_restrictions'] = $dismissalRestrictions + } + + if ($requiredPullRequestReviews.count -eq 0) + { + $requiredPullRequestReviews = $null + } + + if ($PSBoundParameters.ContainsKey('RestrictPushUsers') -or + $PSBoundParameters.ContainsKey('RestrictPushTeams') -or + $PSBoundParameters.ContainsKey('RestrictPushApps')) + { + if ($null -eq $RestrictPushUsers) + { + $RestrictPushUsers = @() + } + + if ($null -eq $RestrictPushTeams) + { + $RestrictPushTeams = @() + } + + $restrictions = @{ + users = $RestrictPushUsers + teams = $RestrictPushTeams + } + + if ($PSBoundParameters.ContainsKey('RestrictPushApps')) { + $restrictions['apps'] = $RestrictPushApps } + } + else + { + $restrictions = $null + } + + $hashBody = @{ + name = $RepositoryName + required_status_checks = $requiredStatusChecks + enforce_admins = $EnforceAdmins.ToBool() + required_pull_request_reviews = $requiredPullRequestReviews + restrictions = $restrictions + } + + if ($PSBoundParameters.ContainsKey('RequiredLinearHistory')) { + $hashBody['required_linear_history'] = $RequiredLinearHistory.ToBool() } + if ($PSBoundParameters.ContainsKey('AllowForcePushes')) { + $hashBody['allow_force_pushes'] = $AllowForcePushes.ToBool() } + if ($PSBoundParameters.ContainsKey('AllowDeletions')) { + $hashBody['allow_deletions'] = $AllowDeletions.ToBool() } + + if ($PSCmdlet.ShouldProcess("'$Name' branch of repository '$RepositoryName'", + 'Set GitHub Repository Branch Protection')) + { + Write-InvocationLog + + $params = @{ + UriFragment = "repos/$OwnerName/$RepositoryName/branches/$Name/protection" + Body = (ConvertTo-Json -InputObject $hashBody -Depth 3) + Description = "Setting $Name branch protection status for $RepositoryName" + Method = 'Put' + AcceptHeader = $script:lukeCageAcceptHeader + AccessToken = $AccessToken + TelemetryEventName = $MyInvocation.MyCommand.Name + TelemetryProperties = $telemetryProperties + NoStatus = (Resolve-ParameterWithDefaultConfigurationValue -Name NoStatus ` + -ConfigValueName DefaultNoStatus) + } + + return Invoke-GHRestMethod @params + } +} + +function Remove-GitHubRepositoryBranchProtectionRule +{ +<# + .SYNOPSIS + Remove branch protection rules for a given GitHub repository. + + .DESCRIPTION + Remove branch protection rules for a given GitHub repository. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER Name + Name of the specific branch to be retrieved. If not supplied, all branches will be retrieved. + + .PARAMETER Uri + Uri for the repository. + The OwnerName and RepositoryName will be extracted from here instead of needing to provide + them individually. + + .PARAMETER OwnerName + Owner of the repository. + If not supplied here, the DefaultOwnerName configuration property value will be used. + + .PARAMETER RepositoryName + Name of the repository. + If not supplied here, the DefaultRepositoryName configuration property value will be used. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .PARAMETER NoStatus + If this switch is specified, long-running commands will run on the main thread + with no commandline status update. When not specified, those commands run in + the background, enabling the command prompt to provide status information. + If not supplied here, the DefaultNoStatus configuration property value will be used. + + .INPUTS + None + + .OUTPUTS + None + + .EXAMPLE + Remove-GitHubRepositoryBranchProtectionRule -Name master -OwnerName Microsoft -RepositoryName PowerShellForGitHub + + Removes branch protection rules from the master branch of the PowerShellForGithub repository. + + .EXAMPLE + Removes-GitHubRepositoryBranchProtection -Name master -Uri 'https://github.com/PowerShell/PowerShellForGitHub' + + Removes branch protection rules from the master branch of the PowerShellForGithub repository. + + .EXAMPLE + Removes-GitHubRepositoryBranchProtection -Name master -Uri 'https://github.com/PowerShell/PowerShellForGitHub' -Confirm:$false + + Removes branch protection rules from the master branch of the PowerShellForGithub repository + without prompting for confirmation. + + .EXAMPLE + Removes-GitHubRepositoryBranchProtection -Name master -Uri 'https://github.com/PowerShell/PowerShellForGitHub' -Force + + Removes branch protection rules from the master branch of the PowerShellForGithub repository + without prompting for confirmation. +#> + [CmdletBinding( + PositionalBinding = $false, + SupportsShouldProcess, + DefaultParameterSetName='Elements', + ConfirmImpact="High")] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '', + Justification='One or more parameters (like NoStatus) are only referenced by helper methods which get access to it from the stack via Get-Variable -Scope 1.')] + [Alias('Delete-GitHubRepositoryBranchProtectionRule')] + param( + [Parameter( + Mandatory, + Position = 1)] + [string] $Name, + + [Parameter( + Mandatory, + Position = 2, + ParameterSetName='Uri')] + [string] $Uri, + + [Parameter(ParameterSetName='Elements')] + [string] $OwnerName, + + [Parameter(ParameterSetName='Elements')] + [string] $RepositoryName, + + [switch] $Force, + + [string] $AccessToken, + + [switch] $NoStatus + ) + + $elements = Resolve-RepositoryElements + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties = @{ + 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) + 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) + } + + if ($Force -and (-not $Confirm)) + { + $ConfirmPreference = 'None' + } + + if ($PSCmdlet.ShouldProcess("'$Name' branch of repository '$RepositoryName'", + 'Remove GitHub Repository Branch Protection Rule')) + { + Write-InvocationLog + + $params = @{ + UriFragment = "repos/$OwnerName/$RepositoryName/branches/$Name/protection" + Description = "Removing $Name branch protection rule for $RepositoryName" + Method = 'Delete' + AcceptHeader = $script:lukeCageAcceptHeader + AccessToken = $AccessToken + TelemetryEventName = $MyInvocation.MyCommand.Name + TelemetryProperties = $telemetryProperties + NoStatus = (Resolve-ParameterWithDefaultConfigurationValue -Name NoStatus ` + -ConfigValueName DefaultNoStatus) + } + + return Invoke-GHRestMethod @params + } +} + filter Add-GitHubBranchAdditionalProperties { <# @@ -201,4 +713,4 @@ filter Add-GitHubBranchAdditionalProperties Write-Output $item } -} +} \ No newline at end of file diff --git a/GitHubCore.ps1 b/GitHubCore.ps1 index 09068429..767fbb12 100644 --- a/GitHubCore.ps1 +++ b/GitHubCore.ps1 @@ -19,6 +19,8 @@ squirrelGirlAcceptHeader = 'application/vnd.github.squirrel-girl-preview' starfoxAcceptHeader = 'application/vnd.github.starfox-preview+json' symmetraAcceptHeader = 'application/vnd.github.symmetra-preview+json' + lukeCageAcceptHeader = 'application/vnd.github.luke-cage-preview+json' + }.GetEnumerator() | ForEach-Object { Set-Variable -Scope Script -Option ReadOnly -Name $_.Key -Value $_.Value } diff --git a/PowerShellForGitHub.psd1 b/PowerShellForGitHub.psd1 index c7f51c82..07239de9 100644 --- a/PowerShellForGitHub.psd1 +++ b/PowerShellForGitHub.psd1 @@ -79,6 +79,7 @@ 'Get-GitHubRelease', 'Get-GitHubRepository', 'Get-GitHubRepositoryBranch', + 'Get-GitHubRepositoryBranchProtectionRule', 'Get-GitHubRepositoryCollaborator', 'Get-GitHubRepositoryContributor', 'Get-GitHubRepositoryFork', @@ -120,6 +121,7 @@ 'Remove-GitHubProjectCard', 'Remove-GitHubProjectColumn', 'Remove-GitHubRepository', + 'Remove-GitHubRepositoryBranchProtectionRule', 'Rename-GitHubRepository', 'Reset-GitHubConfiguration', 'Restore-GitHubConfiguration', @@ -132,6 +134,7 @@ 'Set-GitHubProject', 'Set-GitHubProjectCard', 'Set-GitHubProjectColumn', + 'Set-GitHubRepositoryBranchProtectionRule', 'Set-GitHubRepositoryTopic', 'Split-GitHubUri', 'Test-GitHubAssignee', @@ -153,6 +156,7 @@ 'Delete-GitHubProjectCard', 'Delete-GitHubProjectColumn' 'Delete-GitHubRepository', + 'Delete-GitHubRepositoryBranchProtectionRule', 'Get-GitHubBranch', 'Get-GitHubComment', 'New-GitHubComment', diff --git a/Tests/GitHubBranches.tests.ps1 b/Tests/GitHubBranches.tests.ps1 index f0df1ca9..3f803b1d 100644 --- a/Tests/GitHubBranches.tests.ps1 +++ b/Tests/GitHubBranches.tests.ps1 @@ -107,6 +107,176 @@ try } } } + + Describe 'GitHubBranches\Get-GitHubRepositoryBranchProtectionRule' { + Context 'When getting GitHub repository branch protection' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid + $branchName = 'master' + $repo = New-GitHubRepository -RepositoryName $repoName -AutoInit + Set-GitHubRepositoryBranchProtectionRule -Name $branchName -Uri $repo.svn_url | Out-Null + $protection = Get-GitHubRepositoryBranchProtectionRule -Name $branchName -uri $repo.svn_url + } + + It 'Should return an object of the correct type' { + $protection | Should -BeOfType PSCustomObject + } + + It 'Should return the correct properties' { + $protection.url | + Should -Be "https://api.github.com/repos/$script:ownerName/$repoName/branches/$branchName/protection" + } + + AfterAll -ScriptBlock { + if ($repo) + { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } + } + } + } + + Describe 'GitHubBranches\Set-GitHubRepositoryBranchProtectionRule' { + + Context 'When setting GitHub repository branch protection' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid + $branchName = 'master' + $protectionUrl = "https://api.github.com/repos/$script:organizationName/" + + "$repoName/branches/$branchName/protection" + $newGitHubRepositoryParms = @{ + OrganizationName = $script:organizationName + RepositoryName = $repoName + AutoInit = $true + } + $repo = New-GitHubRepository @newGitHubRepositoryParms + } + + Context 'When setting base protection options' { + BeforeAll { + $setGitHubRepositoryBranchProtectionParms = @{ + Name = $branchName + Uri = $repo.svn_url + EnforceAdmins = $true + RequiredLinearHistory = $true + AllowForcePushes = $true + AllowDeletions = $true + } + $protection = Set-GitHubRepositoryBranchProtectionRule @setGitHubRepositoryBranchProtectionParms + } + + It 'Should return an object of the correct type' { + $protection | Should -BeOfType PSCustomObject + } + + It 'Should return the correct properties' { + $protection.url | Should -Be $protectionUrl + $protection.enforce_admins.enabled | Should -BeTrue + $protection.required_linear_history.enabled | Should -BeTrue + $protection.allow_force_pushes | Should -BeTrue + $protection.allow_deletions | Should -BeTrue + } + } + + Context 'When setting required status checks' { + BeforeAll { + $statusChecks = 'test' + $setGitHubRepositoryBranchProtectionParms = @{ + Name = $branchName + Uri = $repo.svn_url + RequireUpToDateBranches = $true + StatusChecks = $statusChecks + } + $protection = Set-GitHubRepositoryBranchProtectionRule @setGitHubRepositoryBranchProtectionParms + } + + It 'Should return an object of the correct type' { + $protection | Should -BeOfType PSCustomObject + } + + It 'Should return the correct properties' { + $protection.url | Should -Be $protectionUrl + $protection.required_status_checks.strict | Should -BeTrue + $protection.required_status_checks.contexts | Should -Be $statusChecks + } + } + + Context 'When setting required pull request reviews' { + BeforeAll { + $setGitHubRepositoryBranchProtectionParms = @{ + Name = $branchName + Uri = $repo.svn_url + DismissalUsers = $script:OwnerName + DismissStaleReviews = $true + RequireCodeOwnerReviews = $true + RequiredApprovingReviewCount = 1 + } + $protection = Set-GitHubRepositoryBranchProtectionRule @setGitHubRepositoryBranchProtectionParms + } + + It 'Should return an object of the correct type' { + $protection | Should -BeOfType PSCustomObject + } + + It 'Should return the correct properties' { + $protection.url | Should -Be $protectionUrl + $protection.required_pull_request_reviews.dismissal_restrictions.users.login | + Should -Contain $script:OwnerName + } + } + + Context 'When setting push restrictions' { + BeforeAll { + $setGitHubRepositoryBranchProtectionParms = @{ + Name = $branchName + Uri = $repo.svn_url + RestrictPushUsers = $script:OwnerName + } + $protection = Set-GitHubRepositoryBranchProtectionRule @setGitHubRepositoryBranchProtectionParms + } + + It 'Should return an object of the correct type' { + $protection | Should -BeOfType PSCustomObject + } + + It 'Should return the correct properties' { + $protection.url | Should -Be $protectionUrl + $protection.restrictions.users.login | Should -Contain $script:OwnerName + } + } + + AfterAll -ScriptBlock { + if ($repo) + { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } + } + } + } + + Describe 'GitHubBranches\Remove-GitHubRepositoryBranchProtectionRule' { + Context 'When removing GitHub repository branch protection' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid + $branchName = 'master' + $repo = New-GitHubRepository -RepositoryName $repoName -AutoInit + Set-GitHubRepositoryBranchProtectionRule -Name $branchName -Uri $repo.svn_url | Out-Null + } + + It 'Should not throw' { + { Remove-GitHubRepositoryBranchProtectionRule -Name $branchName -Uri $repo.svn_url -Force } | + Should -Not -Throw + } + + AfterAll -ScriptBlock { + if ($repo) + { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } + } + } + } + } finally { diff --git a/USAGE.md b/USAGE.md index 59cc3954..75e69d4c 100644 --- a/USAGE.md +++ b/USAGE.md @@ -29,6 +29,10 @@ * [Updating the current authenticated user](#updating-the-current-authenticated-user) * [Getting any user](#getting-any-user) * [Getting all users](#getting-all-users) + * [Branches](#branches) + * [Getting a repository branch protection rule](#getting-a-repository-branch-protection-rule) + * [Setting a repository branch protection rule](#setting-a-repository-branch-protection-rule) + * [Removing a repository branch protection rule](#removing-a-repository-branch-protection-rule) * [Forks](#forks) * [Get all the forks for a repository](#get-all-the-forks-for-a-repository) * [Create a new fork](#create-a-new-fork) @@ -414,6 +418,28 @@ Get-GitHubUser ---------- +### Branches + +#### Getting a repository branch protection rule + +```powershell +Get-GitHubRepositoryBranchProtectionRule -Name master -OwnerName Microsoft -RepositoryName PowerShellForGitHub +``` + +#### Setting a repository branch protection rule + +```powershell +Set-GitHubRepositoryBranchProtectionRule -Name master -OwnerName Microsoft -RepositoryName PowerShellForGitHub -RequiredApprovingReviewCount 1 +``` + +#### Removing a repository branch protection rule + +```powershell +Remove-GitHubRepositoryBranchProtectionRule -Name master -OwnerName Microsoft -RepositoryName PowerShellForGitHub +``` + +---------- + ### Forks #### Get all the forks for a repository From 17413a04dee877f6a64473562898fca7f101daf8 Mon Sep 17 00:00:00 2001 From: Simon Heather Date: Sun, 21 Jun 2020 09:43:20 +0100 Subject: [PATCH 2/4] Add BranchProtectionRule pipeline support --- GitHubBranches.ps1 | 140 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 106 insertions(+), 34 deletions(-) diff --git a/GitHubBranches.ps1 b/GitHubBranches.ps1 index 0e4b981f..99c912c0 100644 --- a/GitHubBranches.ps1 +++ b/GitHubBranches.ps1 @@ -3,6 +3,7 @@ @{ GitHubBranchTypeName = 'GitHub.Branch' + GitHubBranchProtectionRuleName = 'GitHub.BranchProtectionRule' }.GetEnumerator() | ForEach-Object { Set-Variable -Scope Script -Option ReadOnly -Name $_.Key -Value $_.Value } @@ -154,7 +155,7 @@ filter Get-GitHubRepositoryBranch return (Invoke-GHRestMethodMultipleResult @params | Add-GitHubBranchAdditionalProperties) } -function Get-GitHubRepositoryBranchProtectionRule +filter Get-GitHubRepositoryBranchProtectionRule { <# .SYNOPSIS @@ -192,18 +193,19 @@ function Get-GitHubRepositoryBranchProtectionRule If not supplied here, the DefaultNoStatus configuration property value will be used. .INPUTS - None + GitHub.Repository + GitHub.Branch .OUTPUTS - PSCustomObject + GitHub.BranchProtectionRule .EXAMPLE - Get-GitHubRepositoryBranchProtectionRule -Name master -OwnerName Microsoft -RepositoryName PowerShellForGitHub + Get-GitHubRepositoryBranchProtectionRule -Name master -OwnerName microsoft -RepositoryName PowerShellForGitHub Retrieves branch protection rules for the master branch of the PowerShellForGithub repository. .EXAMPLE - Get-GitHubRepositoryBranchProtectionRule -Name master -Uri 'https://github.com/PowerShell/PowerShellForGitHub' + Get-GitHubRepositoryBranchProtectionRule -Name master -Uri 'https://github.com/microsoft/PowerShellForGitHub' Retrieves branch protection rules for the master branch of the PowerShellForGithub repository. #> @@ -215,12 +217,14 @@ function Get-GitHubRepositoryBranchProtectionRule param( [Parameter( Mandatory, + ValueFromPipelineByPropertyName, Position = 1)] - [string] $Name, + [string] $BranchName, [Parameter( Mandatory, Position = 2, + ValueFromPipelineByPropertyName, ParameterSetName='Uri')] [string] $Uri, @@ -247,7 +251,7 @@ function Get-GitHubRepositoryBranchProtectionRule } $params = @{ - UriFragment = "repos/$OwnerName/$RepositoryName/branches/$Name/protection" + UriFragment = "repos/$OwnerName/$RepositoryName/branches/$BranchName/protection" Description = "Getting branch protection status for $RepositoryName" Method = 'Get' AcceptHeader = $script:lukeCageAcceptHeader @@ -257,10 +261,10 @@ function Get-GitHubRepositoryBranchProtectionRule NoStatus = (Resolve-ParameterWithDefaultConfigurationValue -Name NoStatus -ConfigValueName DefaultNoStatus) } - return Invoke-GHRestMethod @params + return (Invoke-GHRestMethod @params | Add-GitHubBranchProtectionRuleAdditionalProperties) } -function Set-GitHubRepositoryBranchProtectionRule +filter Set-GitHubRepositoryBranchProtectionRule { <# .SYNOPSIS @@ -343,19 +347,21 @@ function Set-GitHubRepositoryBranchProtectionRule If not supplied here, the DefaultNoStatus configuration property value will be used. .INPUTS - None + GitHub.Repository + GitHub.Branch + GitHub.BranchRepositoryRule .OUTPUTS - PSCustomObject + GitHub.BranchRepositoryRule .EXAMPLE - Set-GitHubRepositoryBranchProtectionRule -Name master -OwnerName Microsoft -RepositoryName PowerShellForGitHub -EnforceAdmins + Set-GitHubRepositoryBranchProtectionRule -Name master -OwnerName microsoft -RepositoryName PowerShellForGitHub -EnforceAdmins Sets a branch protection rule for the master branch of the PowerShellForGithub repository enforcing all configuration restrictions for administrators. .EXAMPLE - Set-GitHubRepositoryBranchProtectionRule -Name master -Uri 'https://github.com/PowerShell/PowerShellForGitHub' -RequiredApprovingReviewCount 1 + Set-GitHubRepositoryBranchProtectionRule -Name master -Uri 'https://github.com/microsoft/PowerShellForGitHub' -RequiredApprovingReviewCount 1 Sets a branch protection rule for the master branch of the PowerShellForGithub repository requiring one approving review. @@ -369,11 +375,13 @@ function Set-GitHubRepositoryBranchProtectionRule param( [Parameter( Mandatory, + ValueFromPipelineByPropertyName, Position = 1)] - [string] $Name, + [string] $BranchName, [Parameter( Mandatory, + ValueFromPipelineByPropertyName, Position = 2, ParameterSetName='Uri')] [string] $Uri, @@ -511,15 +519,15 @@ function Set-GitHubRepositoryBranchProtectionRule if ($PSBoundParameters.ContainsKey('AllowDeletions')) { $hashBody['allow_deletions'] = $AllowDeletions.ToBool() } - if ($PSCmdlet.ShouldProcess("'$Name' branch of repository '$RepositoryName'", + if ($PSCmdlet.ShouldProcess("'$BranchName' branch of repository '$RepositoryName'", 'Set GitHub Repository Branch Protection')) { Write-InvocationLog $params = @{ - UriFragment = "repos/$OwnerName/$RepositoryName/branches/$Name/protection" + UriFragment = "repos/$OwnerName/$RepositoryName/branches/$BranchName/protection" Body = (ConvertTo-Json -InputObject $hashBody -Depth 3) - Description = "Setting $Name branch protection status for $RepositoryName" + Description = "Setting $BranchName branch protection status for $RepositoryName" Method = 'Put' AcceptHeader = $script:lukeCageAcceptHeader AccessToken = $AccessToken @@ -529,23 +537,23 @@ function Set-GitHubRepositoryBranchProtectionRule -ConfigValueName DefaultNoStatus) } - return Invoke-GHRestMethod @params + return (Invoke-GHRestMethod @params | Add-GitHubBranchProtectionRuleAdditionalProperties) } } -function Remove-GitHubRepositoryBranchProtectionRule +filter Remove-GitHubRepositoryBranchProtectionRule { <# .SYNOPSIS - Remove branch protection rules for a given GitHub repository. + Remove branch protection rules from a given GitHub repository. .DESCRIPTION - Remove branch protection rules for a given GitHub repository. + Remove branch protection rules from a given GitHub repository. The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub .PARAMETER Name - Name of the specific branch to be retrieved. If not supplied, all branches will be retrieved. + Name of the specific branch to be removed. .PARAMETER Uri Uri for the repository. @@ -571,29 +579,30 @@ function Remove-GitHubRepositoryBranchProtectionRule If not supplied here, the DefaultNoStatus configuration property value will be used. .INPUTS - None + GitHub.Repository + GitHub.Branch .OUTPUTS None .EXAMPLE - Remove-GitHubRepositoryBranchProtectionRule -Name master -OwnerName Microsoft -RepositoryName PowerShellForGitHub + Remove-GitHubRepositoryBranchProtectionRule -Name master -OwnerName microsoft -RepositoryName PowerShellForGitHub Removes branch protection rules from the master branch of the PowerShellForGithub repository. .EXAMPLE - Removes-GitHubRepositoryBranchProtection -Name master -Uri 'https://github.com/PowerShell/PowerShellForGitHub' + Removes-GitHubRepositoryBranchProtection -Name master -Uri 'https://github.com/microsoft/PowerShellForGitHub' Removes branch protection rules from the master branch of the PowerShellForGithub repository. .EXAMPLE - Removes-GitHubRepositoryBranchProtection -Name master -Uri 'https://github.com/PowerShell/PowerShellForGitHub' -Confirm:$false + Removes-GitHubRepositoryBranchProtection -Name master -Uri 'https://github.com/microsoft/PowerShellForGitHub' -Confirm:$false Removes branch protection rules from the master branch of the PowerShellForGithub repository without prompting for confirmation. .EXAMPLE - Removes-GitHubRepositoryBranchProtection -Name master -Uri 'https://github.com/PowerShell/PowerShellForGitHub' -Force + Removes-GitHubRepositoryBranchProtection -Name master -Uri 'https://github.com/master/PowerShellForGitHub' -Force Removes branch protection rules from the master branch of the PowerShellForGithub repository without prompting for confirmation. @@ -609,12 +618,14 @@ function Remove-GitHubRepositoryBranchProtectionRule param( [Parameter( Mandatory, + ValueFromPipelineByPropertyName, Position = 1)] - [string] $Name, + [string] $BranchName, [Parameter( Mandatory, Position = 2, + ValueFromPipelineByPropertyName, ParameterSetName='Uri')] [string] $Uri, @@ -645,14 +656,14 @@ function Remove-GitHubRepositoryBranchProtectionRule $ConfirmPreference = 'None' } - if ($PSCmdlet.ShouldProcess("'$Name' branch of repository '$RepositoryName'", + if ($PSCmdlet.ShouldProcess("'$BranchName' branch of repository '$RepositoryName'", 'Remove GitHub Repository Branch Protection Rule')) { Write-InvocationLog $params = @{ - UriFragment = "repos/$OwnerName/$RepositoryName/branches/$Name/protection" - Description = "Removing $Name branch protection rule for $RepositoryName" + UriFragment = "repos/$OwnerName/$RepositoryName/branches/$BranchName/protection" + Description = "Removing $BranchName branch protection rule for $RepositoryName" Method = 'Delete' AcceptHeader = $script:lukeCageAcceptHeader AccessToken = $AccessToken @@ -662,7 +673,7 @@ function Remove-GitHubRepositoryBranchProtectionRule -ConfigValueName DefaultNoStatus) } - return Invoke-GHRestMethod @params + return Invoke-GHRestMethod @params | Out-Null } } @@ -679,7 +690,7 @@ filter Add-GitHubBranchAdditionalProperties The type that should be assigned to the object. .INPUTS - [PSCustomObject] + PSCustomObject .OUTPUTS GitHub.Branch @@ -713,4 +724,65 @@ filter Add-GitHubBranchAdditionalProperties Write-Output $item } -} \ No newline at end of file +} + +filter Add-GitHubBranchProtectionRuleAdditionalProperties +{ +<# + .SYNOPSIS + Adds type name and additional properties to ease pipelining to GitHub Branch Protection Rule objects. + + .PARAMETER InputObject + The GitHub object to add additional properties to. + + .PARAMETER TypeName + The type that should be assigned to the object. + + .INPUTS + PSCustomObject + + .OUTPUTS + GitHub.Branch +#> + [CmdletBinding()] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '', + Justification='Internal helper that is definitely adding more than one property.')] + param( + [Parameter( + Mandatory, + ValueFromPipeline)] + [AllowNull()] + [AllowEmptyCollection()] + [PSCustomObject[]] $InputObject, + + [ValidateNotNullOrEmpty()] + [string] $TypeName = $script:GitHubBranchTypeName + ) + + foreach ($item in $InputObject) + { + $item.PSObject.TypeNames.Insert(0, $TypeName) + + if (-not (Get-GitHubConfiguration -Name DisablePipelineSupport)) + { + $elements = Split-GitHubUri -Uri $item.url - + $repositoryUrl = Join-GitHubUri @elements + Add-Member -InputObject $item -Name 'RepositoryUrl' -Value $repositoryUrl -MemberType NoteProperty -Force + + $hostName = $(Get-GitHubConfiguration -Name 'ApiHostName') + + if ($item.html_url -match "^https?://api.$hostName/repos/([^/]+)/?([^/]+)/?([^/]+)/?([^/]+)?(?:/.*)?$") + { + $branchName = $Matches[4] + } + else + { + $branchName = '' + } + + Add-Member -InputObject $item -Name 'BranchName' -Value $branchName -MemberType NoteProperty -Force + } + + Write-Output $item + } +} From af85fa225cbefdbae656d79393597ac3a1a86ea5 Mon Sep 17 00:00:00 2001 From: Simon Heather Date: Sun, 21 Jun 2020 11:36:58 +0100 Subject: [PATCH 3/4] Fix review comments --- GitHubBranches.ps1 | 129 +++++++++++++++++++-------------- Tests/GitHubBranches.tests.ps1 | 23 +++--- USAGE.md | 6 +- 3 files changed, 92 insertions(+), 66 deletions(-) diff --git a/GitHubBranches.ps1 b/GitHubBranches.ps1 index 99c912c0..34da85a9 100644 --- a/GitHubBranches.ps1 +++ b/GitHubBranches.ps1 @@ -200,12 +200,12 @@ filter Get-GitHubRepositoryBranchProtectionRule GitHub.BranchProtectionRule .EXAMPLE - Get-GitHubRepositoryBranchProtectionRule -Name master -OwnerName microsoft -RepositoryName PowerShellForGitHub + Get-GitHubRepositoryBranchProtectionRule -OwnerName microsoft -RepositoryName PowerShellForGitHub -BranchName master Retrieves branch protection rules for the master branch of the PowerShellForGithub repository. .EXAMPLE - Get-GitHubRepositoryBranchProtectionRule -Name master -Uri 'https://github.com/microsoft/PowerShellForGitHub' + Get-GitHubRepositoryBranchProtectionRule -Uri 'https://github.com/microsoft/PowerShellForGitHub' -BranchName master Retrieves branch protection rules for the master branch of the PowerShellForGithub repository. #> @@ -217,16 +217,16 @@ filter Get-GitHubRepositoryBranchProtectionRule param( [Parameter( Mandatory, + Position = 1, ValueFromPipelineByPropertyName, - Position = 1)] - [string] $BranchName, + ParameterSetName='Uri')] + [string] $Uri, [Parameter( Mandatory, - Position = 2, ValueFromPipelineByPropertyName, - ParameterSetName='Uri')] - [string] $Uri, + Position = 2)] + [string] $BranchName, [Parameter(ParameterSetName='Elements')] [string] $OwnerName, @@ -252,7 +252,7 @@ filter Get-GitHubRepositoryBranchProtectionRule $params = @{ UriFragment = "repos/$OwnerName/$RepositoryName/branches/$BranchName/protection" - Description = "Getting branch protection status for $RepositoryName" + Description = "Getting branch protection status for $RepositoryName" Method = 'Get' AcceptHeader = $script:lukeCageAcceptHeader AccessToken = $AccessToken @@ -295,13 +295,15 @@ filter Set-GitHubRepositoryBranchProtectionRule The list of status checks to require in order to merge into the branch. .PARAMETER RequireUpToDateBranches - Require branches to be up to date before merging. + Require branches to be up to date before merging. This setting will not take effect unless + at least one status check is defined. .PARAMETER EnforceAdmins Enforce all configured restrictions for administrators. .PARAMETER DismissalUsers - Specify which users can dismiss pull request reviews. + Specify the user names of users who can dismiss pull request reviews. This can only be + specified for organization-owned repositories. .PARAMETER DismissalTeams Specify which teams can dismiss pull request reviews. @@ -326,9 +328,10 @@ filter Set-GitHubRepositoryBranchProtectionRule .PARAMETER RestrictPushApps Specify which apps have push access. - .PARAMETER RequiredLinearHistory + .PARAMETER RequireLinearHistory Enforces a linear commit Git history, which prevents anyone from pushing merge commits to a - branch. + branch. Your repository must allow squash merging or rebase merging before you can enable a + linear commit history. .PARAMETER AllowForcePushes Permits force pushes to the protected branch by anyone with write access to the repository. @@ -354,14 +357,17 @@ filter Set-GitHubRepositoryBranchProtectionRule .OUTPUTS GitHub.BranchRepositoryRule + .NOTES + Protecting a branch requires admin or owner permissions to the repository. + .EXAMPLE - Set-GitHubRepositoryBranchProtectionRule -Name master -OwnerName microsoft -RepositoryName PowerShellForGitHub -EnforceAdmins + Set-GitHubRepositoryBranchProtectionRule -OwnerName microsoft -RepositoryName PowerShellForGitHub -BranchName master -EnforceAdmins Sets a branch protection rule for the master branch of the PowerShellForGithub repository enforcing all configuration restrictions for administrators. .EXAMPLE - Set-GitHubRepositoryBranchProtectionRule -Name master -Uri 'https://github.com/microsoft/PowerShellForGitHub' -RequiredApprovingReviewCount 1 + Set-GitHubRepositoryBranchProtectionRule -Uri 'https://github.com/microsoft/PowerShellForGitHub' -BranchName master -RequiredApprovingReviewCount 1 Sets a branch protection rule for the master branch of the PowerShellForGithub repository requiring one approving review. @@ -376,15 +382,15 @@ filter Set-GitHubRepositoryBranchProtectionRule [Parameter( Mandatory, ValueFromPipelineByPropertyName, - Position = 1)] - [string] $BranchName, + Position = 1, + ParameterSetName='Uri')] + [string] $Uri, [Parameter( Mandatory, ValueFromPipelineByPropertyName, - Position = 2, - ParameterSetName='Uri')] - [string] $Uri, + Position = 2)] + [string] $BranchName, [Parameter(ParameterSetName='Elements')] [string] $OwnerName, @@ -406,7 +412,7 @@ filter Set-GitHubRepositoryBranchProtectionRule [switch] $RequireCodeOwnerReviews, - [ValidateRange(1,6)] + [ValidateRange(1, 6)] [int] $RequiredApprovingReviewCount, [string[]] $RestrictPushUsers, @@ -415,7 +421,7 @@ filter Set-GitHubRepositoryBranchProtectionRule [string[]] $RestrictPushApps, - [switch]$RequiredLinearHistory, + [switch]$RequireLinearHistory, [switch] $AllowForcePushes, @@ -449,8 +455,10 @@ filter Set-GitHubRepositoryBranchProtectionRule $dismissalRestrictions = @{} - if ($PSBoundParameters.ContainsKey('DismissalUsers')) { - $dismissalRestrictions['users'] = $DismissalUsers } + if ($PSBoundParameters.ContainsKey('DismissalUsers')) + { + $dismissalRestrictions['users'] = $DismissalUsers + } if ($PSBoundParameters.ContainsKey('DismissalTeams')) { $teams = Get-GitHubTeam -OwnerName $OwnerName -RepositoryName $RepositoryName | @@ -460,12 +468,18 @@ filter Set-GitHubRepositoryBranchProtectionRule $requiredPullRequestReviews = @{} - if ($PSBoundParameters.ContainsKey('DismissStaleReviews')) { - $requiredPullRequestReviews['dismiss_stale_reviews'] = $DismissStaleReviews.ToBool() } - if ($PSBoundParameters.ContainsKey('RequireCodeOwnerReviews')) { - $requiredPullRequestReviews['require_code_owner_reviews'] = $RequireCodeOwnerReviews.ToBool() } - if ($PSBoundParameters.ContainsKey('RequiredApprovingReviewCount')) { - $requiredPullRequestReviews['required_approving_review_count'] = $RequiredApprovingReviewCount } + if ($PSBoundParameters.ContainsKey('DismissStaleReviews')) + { + $requiredPullRequestReviews['dismiss_stale_reviews'] = $DismissStaleReviews.ToBool() + } + if ($PSBoundParameters.ContainsKey('RequireCodeOwnerReviews')) + { + $requiredPullRequestReviews['require_code_owner_reviews'] = $RequireCodeOwnerReviews.ToBool() + } + if ($PSBoundParameters.ContainsKey('RequiredApprovingReviewCount')) + { + $requiredPullRequestReviews['required_approving_review_count'] = $RequiredApprovingReviewCount + } if ($dismissalRestrictions.count -gt 0) { @@ -488,12 +502,18 @@ filter Set-GitHubRepositoryBranchProtectionRule if ($null -eq $RestrictPushTeams) { - $RestrictPushTeams = @() + $restrictPushTeamSlugs = @() + } + else + { + $teams = Get-GitHubTeam -OwnerName $OwnerName -RepositoryName $RepositoryName | + Where-Object -FilterScript { $RestrictPushTeams -contains $_.name } + $restrictPushTeamSlugs['teams'] = @($teams.slug) } $restrictions = @{ users = $RestrictPushUsers - teams = $RestrictPushTeams + teams = $restrictPushTeamSlugs } if ($PSBoundParameters.ContainsKey('RestrictPushApps')) { @@ -505,28 +525,35 @@ filter Set-GitHubRepositoryBranchProtectionRule } $hashBody = @{ - name = $RepositoryName required_status_checks = $requiredStatusChecks enforce_admins = $EnforceAdmins.ToBool() required_pull_request_reviews = $requiredPullRequestReviews restrictions = $restrictions } - if ($PSBoundParameters.ContainsKey('RequiredLinearHistory')) { - $hashBody['required_linear_history'] = $RequiredLinearHistory.ToBool() } - if ($PSBoundParameters.ContainsKey('AllowForcePushes')) { - $hashBody['allow_force_pushes'] = $AllowForcePushes.ToBool() } - if ($PSBoundParameters.ContainsKey('AllowDeletions')) { - $hashBody['allow_deletions'] = $AllowDeletions.ToBool() } + if ($PSBoundParameters.ContainsKey('RequireLinearHistory')) + { + $hashBody['required_linear_history'] = $RequireLinearHistory.ToBool() + } + if ($PSBoundParameters.ContainsKey('AllowForcePushes')) + { + $hashBody['allow_force_pushes'] = $AllowForcePushes.ToBool() + } + if ($PSBoundParameters.ContainsKey('AllowDeletions')) + { + $hashBody['allow_deletions'] = $AllowDeletions.ToBool() + } if ($PSCmdlet.ShouldProcess("'$BranchName' branch of repository '$RepositoryName'", 'Set GitHub Repository Branch Protection')) { Write-InvocationLog + $jsonConversionDepth = 3 + $params = @{ UriFragment = "repos/$OwnerName/$RepositoryName/branches/$BranchName/protection" - Body = (ConvertTo-Json -InputObject $hashBody -Depth 3) + Body = (ConvertTo-Json -InputObject $hashBody -Depth $jsonConversionDepth) Description = "Setting $BranchName branch protection status for $RepositoryName" Method = 'Put' AcceptHeader = $script:lukeCageAcceptHeader @@ -586,23 +613,17 @@ filter Remove-GitHubRepositoryBranchProtectionRule None .EXAMPLE - Remove-GitHubRepositoryBranchProtectionRule -Name master -OwnerName microsoft -RepositoryName PowerShellForGitHub + Remove-GitHubRepositoryBranchProtectionRule -OwnerName microsoft -RepositoryName PowerShellForGitHub -BranchName master Removes branch protection rules from the master branch of the PowerShellForGithub repository. .EXAMPLE - Removes-GitHubRepositoryBranchProtection -Name master -Uri 'https://github.com/microsoft/PowerShellForGitHub' + Removes-GitHubRepositoryBranchProtection -Uri 'https://github.com/microsoft/PowerShellForGitHub' -BranchName master Removes branch protection rules from the master branch of the PowerShellForGithub repository. .EXAMPLE - Removes-GitHubRepositoryBranchProtection -Name master -Uri 'https://github.com/microsoft/PowerShellForGitHub' -Confirm:$false - - Removes branch protection rules from the master branch of the PowerShellForGithub repository - without prompting for confirmation. - - .EXAMPLE - Removes-GitHubRepositoryBranchProtection -Name master -Uri 'https://github.com/master/PowerShellForGitHub' -Force + Removes-GitHubRepositoryBranchProtection -Uri 'https://github.com/master/PowerShellForGitHub' -BranchName master -Force Removes branch protection rules from the master branch of the PowerShellForGithub repository without prompting for confirmation. @@ -618,16 +639,16 @@ filter Remove-GitHubRepositoryBranchProtectionRule param( [Parameter( Mandatory, + Position = 1, ValueFromPipelineByPropertyName, - Position = 1)] - [string] $BranchName, + ParameterSetName='Uri')] + [string] $Uri, [Parameter( Mandatory, - Position = 2, ValueFromPipelineByPropertyName, - ParameterSetName='Uri')] - [string] $Uri, + Position = 2)] + [string] $BranchName, [Parameter(ParameterSetName='Elements')] [string] $OwnerName, @@ -765,7 +786,7 @@ filter Add-GitHubBranchProtectionRuleAdditionalProperties if (-not (Get-GitHubConfiguration -Name DisablePipelineSupport)) { - $elements = Split-GitHubUri -Uri $item.url - + $elements = Split-GitHubUri -Uri $item.url $repositoryUrl = Join-GitHubUri @elements Add-Member -InputObject $item -Name 'RepositoryUrl' -Value $repositoryUrl -MemberType NoteProperty -Force diff --git a/Tests/GitHubBranches.tests.ps1 b/Tests/GitHubBranches.tests.ps1 index 3f803b1d..9968ccf3 100644 --- a/Tests/GitHubBranches.tests.ps1 +++ b/Tests/GitHubBranches.tests.ps1 @@ -114,8 +114,8 @@ try $repoName = [Guid]::NewGuid().Guid $branchName = 'master' $repo = New-GitHubRepository -RepositoryName $repoName -AutoInit - Set-GitHubRepositoryBranchProtectionRule -Name $branchName -Uri $repo.svn_url | Out-Null - $protection = Get-GitHubRepositoryBranchProtectionRule -Name $branchName -uri $repo.svn_url + Set-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName | Out-Null + $protection = Get-GitHubRepositoryBranchProtectionRule -uri $repo.svn_url -BranchName $branchName } It 'Should return an object of the correct type' { @@ -149,19 +149,21 @@ try RepositoryName = $repoName AutoInit = $true } + $repo = New-GitHubRepository @newGitHubRepositoryParms } Context 'When setting base protection options' { BeforeAll { $setGitHubRepositoryBranchProtectionParms = @{ - Name = $branchName Uri = $repo.svn_url + BranchName = $branchName EnforceAdmins = $true - RequiredLinearHistory = $true + RequireLinearHistory = $true AllowForcePushes = $true AllowDeletions = $true } + $protection = Set-GitHubRepositoryBranchProtectionRule @setGitHubRepositoryBranchProtectionParms } @@ -182,11 +184,12 @@ try BeforeAll { $statusChecks = 'test' $setGitHubRepositoryBranchProtectionParms = @{ - Name = $branchName Uri = $repo.svn_url + BranchName = $branchName RequireUpToDateBranches = $true StatusChecks = $statusChecks } + $protection = Set-GitHubRepositoryBranchProtectionRule @setGitHubRepositoryBranchProtectionParms } @@ -204,13 +207,14 @@ try Context 'When setting required pull request reviews' { BeforeAll { $setGitHubRepositoryBranchProtectionParms = @{ - Name = $branchName Uri = $repo.svn_url + BranchName = $branchName DismissalUsers = $script:OwnerName DismissStaleReviews = $true RequireCodeOwnerReviews = $true RequiredApprovingReviewCount = 1 } + $protection = Set-GitHubRepositoryBranchProtectionRule @setGitHubRepositoryBranchProtectionParms } @@ -228,10 +232,11 @@ try Context 'When setting push restrictions' { BeforeAll { $setGitHubRepositoryBranchProtectionParms = @{ - Name = $branchName Uri = $repo.svn_url + BranchName = $branchName RestrictPushUsers = $script:OwnerName } + $protection = Set-GitHubRepositoryBranchProtectionRule @setGitHubRepositoryBranchProtectionParms } @@ -260,11 +265,11 @@ try $repoName = [Guid]::NewGuid().Guid $branchName = 'master' $repo = New-GitHubRepository -RepositoryName $repoName -AutoInit - Set-GitHubRepositoryBranchProtectionRule -Name $branchName -Uri $repo.svn_url | Out-Null + Set-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName | Out-Null } It 'Should not throw' { - { Remove-GitHubRepositoryBranchProtectionRule -Name $branchName -Uri $repo.svn_url -Force } | + { Remove-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName -Force } | Should -Not -Throw } diff --git a/USAGE.md b/USAGE.md index 75e69d4c..a2e37188 100644 --- a/USAGE.md +++ b/USAGE.md @@ -423,19 +423,19 @@ Get-GitHubUser #### Getting a repository branch protection rule ```powershell -Get-GitHubRepositoryBranchProtectionRule -Name master -OwnerName Microsoft -RepositoryName PowerShellForGitHub +Get-GitHubRepositoryBranchProtectionRule -OwnerName microsoft -RepositoryName PowerShellForGitHub -BranchName master ``` #### Setting a repository branch protection rule ```powershell -Set-GitHubRepositoryBranchProtectionRule -Name master -OwnerName Microsoft -RepositoryName PowerShellForGitHub -RequiredApprovingReviewCount 1 +Set-GitHubRepositoryBranchProtectionRule -OwnerName microsoft -RepositoryName PowerShellForGitHub -BranchName master -RequiredApprovingReviewCount 1 ``` #### Removing a repository branch protection rule ```powershell -Remove-GitHubRepositoryBranchProtectionRule -Name master -OwnerName Microsoft -RepositoryName PowerShellForGitHub +Remove-GitHubRepositoryBranchProtectionRule -OwnerName microsoft -RepositoryName PowerShellForGitHub -BranchName master ``` ---------- From a8690922ea003d82ba7bedc2579ffcfa855bf155 Mon Sep 17 00:00:00 2001 From: Simon Heather Date: Sat, 27 Jun 2020 19:42:15 +0100 Subject: [PATCH 4/4] Fix review comments --- GitHubBranches.ps1 | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/GitHubBranches.ps1 b/GitHubBranches.ps1 index e4a660ca..d36f8205 100644 --- a/GitHubBranches.ps1 +++ b/GitHubBranches.ps1 @@ -421,7 +421,7 @@ filter Set-GitHubRepositoryBranchProtectionRule [string[]] $RestrictPushApps, - [switch]$RequireLinearHistory, + [switch] $RequireLinearHistory, [switch] $AllowForcePushes, @@ -544,7 +544,8 @@ filter Set-GitHubRepositoryBranchProtectionRule $hashBody['allow_deletions'] = $AllowDeletions.ToBool() } - if ($PSCmdlet.ShouldProcess("'$BranchName' branch of repository '$RepositoryName'", + if ($PSCmdlet.ShouldProcess( + "'$BranchName' branch of repository '$RepositoryName'", 'Set GitHub Repository Branch Protection')) { Write-InvocationLog @@ -777,7 +778,7 @@ filter Add-GitHubBranchProtectionRuleAdditionalProperties [PSCustomObject[]] $InputObject, [ValidateNotNullOrEmpty()] - [string] $TypeName = $script:GitHubBranchTypeName + [string] $TypeName = $script:GitHubBranchProtectionRuleName ) foreach ($item in $InputObject) @@ -792,9 +793,9 @@ filter Add-GitHubBranchProtectionRuleAdditionalProperties $hostName = $(Get-GitHubConfiguration -Name 'ApiHostName') - if ($item.html_url -match "^https?://api.$hostName/repos/([^/]+)/?([^/]+)/?([^/]+)/?([^/]+)?(?:/.*)?$") + if ($item.html_url -match "^https?://(?:www\.|api\.|)$hostName/repos/(?:[^/]+)/(?:[^/]+)/branches/([^/]+)/.*$") { - $branchName = $Matches[4] + $branchName = $Matches[1] } else {