A couple of weeks or so back, I had an interesting work land into my sprint. The request was to protect the ‘master’ branch and enable PR build for a set of Azure repositories.
This involved -for each repository:
-Require a minimum number of reviewers
-Enable a certain set of policies
-Check for linked work items
-Check for comment resolution
-Check for build validation
-Add a conditional step in the associated build definition and update release definition accordingly
I won’t dig deeper into -why we protect the ‘master’ branch -in this note. Simply stated, the concept of branch protection is to prevent irrevocable changes from being committed. With more and more repos being hosted as public, there needs to be a standardized process in which the community benefits from the repository and at the same time is able to make meaningful contributions. And that is where branch protection is of value.
Generally speaking master branch is sacrosanct.
Different development teams treat the ‘master’ branch differently. Some consider that once a code repository goes through a certain maturity phase, where the ‘master’ branch becomes stable, any changes (commit) made to it should be on certain policies being met. These policies effectively work towards ensuring that the master branch is protected from changes that do not align. Or loosely stated, commit/s to the ‘master’ branch is not allowed unless a specific set of conditions/policies are not met.
How do we protect the ‘master’ branch (in Azure DevOps)?
Universal answer: By enabling Pull requests.
In Azure DevOps pull requests are enabled via the following steps.
For any repository, click on branches -> ellipsis (next to the branch that is being protected) -> branch policies
This navigates to the policies page for the branch. Here is an image of a few policies for this repository.
As can be seen, above are a few policies (and I have not enabled any policies) for this repository in this image.
Coming back to the request at hand… it was to protect the ‘master’ branch for a set of existing repositories (between 2-3 dozen) by enabling these policies.
Here is a little more information on the request. There were existing Azure DevOps build definitions (kept in a certain folder under All build pipelines). Each of these build definitions was associated with a repository in Azure DevOps. 1:1 mapping. The request was to protect the ‘master’ branch ONLY in these repositories. Another critical piece of information: a few of these repositories already had some of the policies applied.
I was not going to work through this manually.
Algorithm:
Step 1: Create a list of all build definitions under the ‘particular folder’
Step 2: for each build definition in the list, gather information about the repository that is tied to it
Step 3: here, I had a choice. For each repository
(a) either delete all existing policies and apply new ones. This was a lot easier since it would ensure that no checks (if policies exist) were need.
(b) or check if a certain policy existed and apply only if it did not and move to the next policy until all the policies were applied.
Both approaches have benefits and drawbacks: (i) delete all and recreate does not consider special conditions unless explicitly stated and (ii) creating only missing policies would allow for existing deviations to persist (for already created policies). And I wanted a solution where-in it was possible to use both options rather than have two separate scripts for that purpose.
My preferred scripting language is PowerShell and I was able to code the entire workflow with the help of some very good documentation from docs.microsoft.com
I have the code committed in my GitHub repository: ApplyPoliciesToAzureRepos and I have ensured that as much information is available in the ReadMe file about how to use it.
After I executed the PowerShell script with appropriate arguments, this is how the policies page looked.
There are a few more policies such as case-enforcement, file-size, merge-strategy, and required-reviewer which I did not enable since it was not required in the repositories I was working with.
More information related to these can be found at below links:
az repos policy case-enforcement
az repos policy file-size
az repos policy merge-strategy
az repos policy required-reviewer
The other part of the request was to add a conditional step in the associated build definition. I have that as a separate note here.