Post

Delete GitHub Branch Protection Rules Programmatically

Delete GitHub Branch Protection Rules from a PowerShell script

Overview

After a migration, or maybe when doing cleanup, you may want to delete branch protection rules in bulk. Instead of having to click through each branch protection rule individually, I wrote a PowerShell script that leverages the GraphQL endpoint. At the time I wrote this a few years ago, there wasn’t an API for deleting branch protection rules, only GraphQL. However, there is now an API endpoint for managing branch protection rules, so if I were to re-write this, that’s likely what I would use.

But this script works just fine as is to delete branch protection rules programmatically, and I thought it was time to share it!

Script

The script is also located here.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
##############################################################
# Delete branch protection rules
##############################################################

[CmdletBinding()]
param (
    [parameter (Mandatory = $true)][string]$PersonalAccessToken,
    [parameter (Mandatory = $true)][string]$GitHubOrg,
    [parameter (Mandatory = $true)][string]$GitHubRepo,
    [parameter (Mandatory = $true)][string]$PatternToDelete 
      # If you want to delete branch protection rules that start with "feature", pass in "feature*"
      # If you want to delete ALL branch protection rules, pass in "*"
)

# Example that deletes ALL branch protection rules:
# ./github-delete-branch-protection.ps1 -PersonalAccessToken "xxx" -GitHubOrg "myorg" -GitHubRepo "myrepo" -PatternToDelete "*"

# Example that deletes branch protection rules that start with feature:
# ./github-delete-branch-protection.ps1 -PersonalAccessToken "xxx" -GitHubOrg "myorg" -GitHubRepo "myrepo" -PatternToDelete "feature*"

# Set up API Header
$AuthenticationHeader = @{Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($PersonalAccessToken)")) }

####### Script #######

### GRAPHQL
# Get body
$body = @{
    query = "query BranchProtectionRule {
        repository(owner:`"$GitHubOrg`", name:`"$GitHubRepo`") { 
          branchProtectionRules(first: 100) { 
              nodes { 
                  pattern,
                  id
                      matchingRefs(first: 100) {
                          nodes {
                              name
                          }
                      }
                  }
              }
          }
      }"
}

write-host "Getting policies for repo: $GitHubRepo ..."
$graphql = Invoke-RestMethod -Uri "https://api.github.com/graphql" -Method POST -Headers $AuthenticationHeader -ContentType 'application/json' -Body ($body | ConvertTo-Json) # | ConvertTo-Json -Depth 10
write-host ""

foreach($policy in $graphql.data.repository.branchProtectionRules.nodes) {
    if($policy.pattern -like $PatternToDelete) {
        write-host "Deleting branch policy: $($policy.pattern) ..."
        $bodyDelete = @{
            query = "mutation {
                deleteBranchProtectionRule(input:{branchProtectionRuleId: `"$($policy.id)`"}) {
                clientMutationId
                }
            }"
        }
        $toDelete = Invoke-RestMethod -Uri "https://api.github.com/graphql" -Method POST -Headers $AuthenticationHeader -ContentType 'application/json' -Body ($bodyDelete | ConvertTo-Json)
        
        if($toDelete -like "*errors*") {
            write-host "Error deleting policy: $($policy.pattern)" -f red
        }
        else {
            write-host "Policy deleted: $($policy.pattern)"
        }
    }
}

Usage

As an example, if I wanted to clean up all of the branch protection rules on my feature branches, the script can be called like:

1
./github-delete-branch-protection.ps1 -PatternToDelete "feature*" -PersonalAccessToken "xxx" -GitHubOrg "myorg" -GitHubRepo "myrepo"

Alternatively, if I wanted to delete ALL branch protection rules, I can use a "*" wildcard to delete them all:

1
./github-delete-branch-protection.ps1 -PatternToDelete "*" -PersonalAccessToken "xxx" -GitHubOrg "myorg" -GitHubRepo "myrepo"

Output

Here’s an example of an output / logs from the script:

1
2
3
4
5
6
Getting policies for repo: gh-cli-get-branches-example ...

Deleting branch policy: test1 ...
Policy deleted: test1
Deleting branch policy: test2 ...
Policy deleted: test2

Notes

If you have more than 100 branch protection rules that you are cleaning, update the branchProtectionRules(first: 100) and matchingRefs(first: 100)

This post is licensed under CC BY 4.0 by the author.