ObjectSharp
Published in

ObjectSharp

Adding Branch Protection to your Repo with the GitHub Rest API and PowerShell

In the last two articles we created a repo then added a CODEOWNERS file to the repo so the Developers team would be the Code Owners and responsible for approving PR’s.

Now lets add Branch Protection to our repo. For my example I’ll create a PowerShell script called addBranchProtection.ps1 with:

  • One mandatory parameter: The name of the repo
  • A variable with the GitHub organization name. This could also be a parameter obviously.
  • A variable with the Personal Access Token we will get from an environment variable, converted to base64.
param (
[Parameter(Mandatory=$true)] $repoName
)
$orgName = "myOrg"
$pat = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($env:GH_PAT)"))

For the body of the API call lets create a JSON file with the options defined already. I like this approach, because I can have multiple files for different scenarios of branch protection.

You can get the structure of the JSON by calling the API to GET the branch protection of an existing Repo using this API call repos/<Owner>/<Repo>/branches/<branch>/protection

I’ll save you the trouble. Here is an example:

{
"required_pull_request_reviews": {
"dismiss_stale_reviews": true,
"require_code_owner_reviews": true,
"required_approving_review_count": 1
},
"required_status_checks": {
"strict": false,
"contexts": []
},
"restrictions": null,
"required_signatures": false,
"enforce_admins": true,
"required_linear_history": false,
"allow_force_pushes": false,
"allow_deletions": false,
"required_conversation_resolution": true
}

Just to be clear here is what each section of the JSON represents in GitHub Branch Protection.

Checkout the documentation for all the possible scenarios.

Back to the script. We need to read in our JSON file and use it to create the body of our API call.

$body = Get-Content -path ".\branchProtection.json" -Raw

Now it’s simply a matter of calling the API to update branch policies for a particular branch.

$branchName = "main"
$params = @{'Uri' =
('https://api.github.com/repos/{0}/{1}/branches/{2}/protection'
-f $orgName,$repoName,$branchName)
'Headers' = @{'Authorization' = 'Basic ' + $pat}
'Method' = 'Put'
'ContentType' = 'application/json'
'Body' = ($body)}
$result = Invoke-RestMethod @params

Now just call the script to add Branch Protection to the main branch of a repo.

./addBranchProtection.ps1 -repoName "MyRepo"

As an addition you may want to update more than one branch at a time. Or if I have a mix of master and main across different repos, and I don’t want to have to check first which it is.

I’ll get a list of all the branches for the repo.

$allBranches = @()
$page=0
$branchList = @()
do {
$page += 1
$params = @{'Uri' =
('https://api.github.com/repos/{0}/{1}/branches?page=
{2}&per_page=100' -f $orgName, $gh_repo, $page)
'Headers' = @{'Authorization' = 'Basic ' + $pat}
'Method' = 'Get'
'ContentType' = 'application/json'}
$branches=Invoke-RestMethod @params
$allBranches += $branches
$branchCount = $branches.Count
} while($branchCount -gt 0)
foreach ($branch in $allBranches) {
$branchList += $branch.name
}

This is the same pattern I used in this article to get all the Repos. I am just applying it to get all the branches here.

Now I can create a list of branches where I want to add branch protection. My script will check if they exist for the current repo I am updating, and update accordingly.

$branches = 'master','develop','main'
foreach($branch in $branches)
{
# Check the branch Exists
if ($branchList.Contains($branch)) {
Write-host "Add Branch Protection to $branch Branch"
$params = @{'Uri' =
('https://api.github.com/repos/{0}/{1}/branches/{2}/protection'
-f $orgName,$gh_repo,$branch)
'Headers' = @{'Authorization' = 'Basic ' + $pat}
'Method' = 'Put'
'ContentType' = 'application/json'
'Body' = ($body)}
$result = Invoke-RestMethod @params
}
else {
Write-host "This Repo does not have a $branch Branch"
continue
}
}

Output might look something like this:

./addBranchProtection.ps1 -repoName "MyRepo"
This Repo does not have a master Branch
This Repo does not have a develop Branch
Add Branch Protection to main Branch

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Dave Lloyd

Dave Lloyd

I have been writing software and teaching/coaching developers for over 35 years. My current passion is Azure DevOps and all the things it can do for a team.