Skip to content

Code Owners Automation for Automated Reviewers

Overview

The CODEOWNERS file is a technique used on github.com to allow for automated reviewers for code based on coding patterns. You can read about the github implementation of CODEOWNERS on github's documentation. The Energizers team has implemented a code owner's implementation for Azure DevOps using a clone of the public open source repository named azure-codeowners-fx. Our version of the source code is cloned and stored in the repository devops-codeowners-fx in the enablement project.

This CODEOWNERS automation is a powerful tool to implement required reviewers and "component ownership" among your source code assets.

Physical implementation

In the Azure Simplified DevOps Architecture subscription a resource group named rg-codeownersautomation exists that has among other things a serverless function named func-codeownersautomation. This is a production running instance of the code owners system that has an ability to implement the CODEOWNERS pattern on projects in MDTProductDevelopment and MDTCRHF organizations using the PAT of a service account.

Integration with Azure DevOps

To be able to use this capability an azure devops project needs to be integrated with the function. An Azure DevOps Project administrator need to add the service hook to enable the project to support this capability.

  1. Select the azure devops project you want to enable.
  2. Select the project settings gear in the lower left corner.
  3. Select service hooks.
  4. Select the (+) to add a service hook.
  5. Select web hooks, next, "Pull Request Created", next
  6. In the URL section paste the following syntax.
https://func-codeownersautomation.azurewebsites.net/api/AzureDevOpsCodeOwnerAnalysis?code=SECURITYTOKEN

Note to obtain the value of SECURITYTOKEN ask an Azure DevOps enablement project administrator and they can look up the value on their hook currently applied under their project settings. The value comes from the Azure Function Keys settings if lost.

  1. Press finish.
  2. Repeat the above process but this time create a web hook for "Pull Request Updated".

Once both web hooks are in place the capability has been enabled for the project. Although pull request creates and changes will call the web hook nothing will happen until a code owner file is added to the repository and included in a pull request.

At the time of writing only the enablement project in MDTProductDevelopment has been enabled. Over time this will change as project administrators enable this in other projects in the org.

Specify source branch of CODEOWNERS file

The CODEOWNERS file will be taken from the target branch of the Pull Request by default. When invoking the Azure Function from the service hook, the query parameter ?codeOwnerBranch=<Target|Source|RepoDefault> on the function's url can also be specified to control where the CODEOWNERS file is taken from.

The values for the codeOwnerBranch query parameter are:

  • Target: [Default] Taken from the Pull Request's target branch. This is the recommended behavior for most use cases.
  • Source: Taken from the Pull Request's source branch. This is the legacy behavior, but incorrectly allows for the Pull Request to bypass the CODEOWNERS by modifying the CODEOWNERS file as part of the Pull Request itself.
  • RepoDefault: Taken from the default branch of the Pull Request's repo. This allows for all Pull Request to use the same CODEOWNERS file regardless of source and target branches. It centralizes owner management, but also requires that said CODEOWNERS file has glob patterns that account for all branches within the repo. It works best for less granular CODEOWNER files or repos whose folders do not change too often.
https://func-codeownersautomation.azurewebsites.net/api/AzureDevOpsCodeOwnerAnalysis?codeOwnerBranch=<Target|Source|RepoDefault>&code=SECURITYTOKEN

Using the CODEOWNERS file

For a repository to use a code owners file for reviewer(s) allocation, the following must be true.

  1. A file named CODEOWNERS must exist at the root of the repository. The name must be in all capital letters.
  2. The integration with Azure DevOps on pull request web hooks must be completed.
  3. At least one code owner must be specified in the file with a pattern matching a changed file.

The lines of the code owners file have the following format:

GlobbingPattern emailAddress [emailAddress...]
[More patterns...]
owningTeam teamName
trustedTeams teamName [teamName...]

A globbing pattern indicates which files/directories should apply to the code owner. The globbing patterns supported by this implementation are documented on the open source library used by the function. Generally though the first line of the file should have the globbing pattern of * to indicate all files as a fall back.

E-mail addresses after the globbing pattern must be of valid users or DLs of the azure devops organization. They usually look like our Azure AD e-mail format (e.g. jsmith1@medtronic.com, dl.energizers@medtronic.com). Note that the entire e-mail address needs to be supplied. More than one owner can be specified on a line by spaces.

owningTeam contains the name of a SINGLE scrum team name that owns the repository and therefore is the primary contributor or point of contact for the repository.

trustedTeams contains multiple space separated scrum team names that are familiar with the contents of the repository and can therefore be contacted in case owningTeam is not available. This list does not include the owning scrum team.

NOTE: Both owningTeam and trustedTeams values are not considered by the codeowners function during reviewer addition to PR.

Example CODEOWNERS file:

# The CODEOWNERS file can contain comments like this

# The file should always start with a wildcard glob pattern to match anything that may not be defined otherwise
* jsmith1@medtronic.com

# Followed by more specific glob patterns
*.md mdoe4@medtronic.com ajohns2@medtronic.com
tests/*.cs mdoe4@medtronic.com

# Scrum team that is owner of the repository should be stated next
# Lastly, scrum teams, other than the owningTeam, that are familiar with the repository should be stated. Team names which have spaces must be enclosed in double quotes
owningTeam Energizers
trustedTeams "Buid and Deploy" Spartans

# Using a DL has the benefit that the owners that are a part of the DL can be managed without updating the CODEOWNERS file
# As well as having the benefit that only one owner on the list is required to sign instead of all owners if listed individually
# DLs should use the DL's name, which will usually have spaces so must be enclosed in double quotes, or email addresss
/**/*.xml "DL Xml Experts" dl.schemareviewers@medtronic.com

# Glob ptterns can specify exact or relative paths to sub files and folders
/**/*.cpp dl.cplusplusexpert@medtronic.com
/**/*.png dl.graphicartist@medtronic.com

# Multiple owners can be defined in a space, tab, comma, or semicolon delimited list
# All owners on the list are added as required
/**/*.js dl.webdesigner@medtronic.com dl.nodeuser@medtronic.com

# Glob patterns can also have spaces if enclosed in double quotes
# But it's best practice to avoid spaces in file and folder names
"Design Documents/**/*.pdf" dl.manager@medtronic.com

The code owners file is processed from bottom to top and once a changed file has a found codeowner the processing stops for that change. So in the above example if the file tests/helloworld.cs was changed in a PR only mdoe4@medtronic.com would be added as a required reviewer and not jsmith1@medtronic.com. But if the PR contained the files changed of hello.md and README.txt then all three users would be added a required reviewers.

The impact of the CODEOWNERS file

Once the code owners system is setup any creation or update of a pull request will cause the function to analyze the changes and attempt to apply reviewers if they are not currently present. While at this time you can move a required reviewer to optional you cannot remove them without the function adding them back. To remove a required reviewer at this time you would need to remove them from the branch that the CODEOWNERS file is taken from (either the PR's target, source or the repo's default branch).

Azure DevOps Personal Access Token Used by the Production Function

The Azure AD service account SVC-azure-devops-api was used to generate the PAT for this service. The PAT is needed to be able to read and alter pull requests and look at the changes in them. This PAT will need to be updated on a yearly basis. To update the PAT an Azure DevOps org administrator should use the following credentials.

In Azure Key Vault (AKV) uscp-azdo-private-kv, of Simplified DevOps Architecture subscription

  • Login: Secret stored as azdo-devops-svc-account-name
  • Password: Secret stored as azdo-devops-svc-account-password
  • PAT Needs: Full Access to MDTProductDevelopment and MDTCRHF, expiration 1 year (or at minimum Code: Read & Write, Entitlements: Read, Graph: Read, Member Entitlement Management: Read).

When a new PAT is obtained it should be stored in AKV kv-codeownersautomation of Simplified DevOps Architecture subscription as a new version of the following secret. The function will automatically use the new version on next execution.

  • PAT: Secret stored as AzDoCodeOwnersFunctionPATProd

Note: The staging function use a different secret named AzDoCodeOwnersFunctionPATStage which only provides access to the org DevOpsSimpPlayground at this time.

Staging Function

A second deployment of the Azure function for testing upgrades to this function is available in the same resource group. It currently is using a PAT with only access to the DevOpsSimpTesting Azure DevOps organization. You can see this in the project named pr-testing in that organization. The function it calls is the staging version at

https://func-codeownersautomationsandbox.azurewebsites.net/api/AzureDevOpsCodeOwnerAnalysis?code=SECURITYTOKEN

The PAT is stored in the same AKV in a key named AzDoCodeOwnersFunctionPATStage that gives the sandbox version access to the testing playground org. Any deployments of changes to the function should first be testing with this version before breaking the production version.

Question and Answers

Q. What happens if a person goes on vacation and I need a review done?
A. Add someone else as a required reviewer and set them to optional in the pull request or use DLs with multiple reviewers to minimize the impact in such situations.

Q. How long does it take to update my pull request?
A. Usually 10-15 seconds or less depending on load and how recently it was just run.

Q. How do I record why I added a person as a code owner?
A. The CODEOWNERS file supports # as a comment symbol for the line.

Q. I think the function isn't working how do I troubleshoot it?
A. Go to the service hooks and look at the history of the hook. If detailed logging is on any errors will be reported here.

Q. How do I suggest a change or improvement to the function?
A. Submit a PR to the devops-codeowners-fx repository and the energizers team will review it and may implement the change or discuss possible alternative changes.

Q. Should I start the lines with a / or not?
A. If the line doesn't start with a / the function will prepend one.

Q. How do I determine the e-mail address for a user to use?
A. Navigate to the organization level of Azure DevOps, select Organization Settings in the lower left, Select Users. In the filter enter the user's name and you will see under the match their Azure DevOps e-mail address.