When I wrote this project originally, I worked for a company that has a staff with an attention to well-formatted, pretty files. If a change is made to a CODEOWNERS file that would require the file to be re-columned, then the PR would show all lines changed. This would prompt a PR reviewer to have to either click "approve" without considering the content of the file, or actually read the entire CODEOWNERS file again. So, I wrote codeowner-gen with this problem in mind.
codeowner-gen takes a well-formatted yaml file, and does a few things:
- You specify a bunch of paths and one or more owners per path, and it will ensure that all records are spaced so that output is columnar,
- You specify one or more
owner_groupswhich is a group of people or teams, and they can then be assigned to paths, - the output will be alphabetized,
- unless you specify one or more of the objects as "grouped", in which case it will alphabetize and then group the records together,
- it processes the Owners you've listed and I might eventually enable the app to validate that the user/team you've specified actually exists,
- You can specify a comment, per path entry, and it will render it out for you.
The output is then rendered to the CODEOWNERS file for you, alphabetized and/or grouped by your grouping specification, and properly columned so that the text columns align.
With this workflow, a reviewer can see that the first line of the CODEOWNERS file is a codeowner-gen rendered file and ignore it, in favor of reviewing the changes in the codeowners.yaml file instead. That file, being yaml, will show changes in a more sane and easy-to-digest format for a PR reviewer.
The latest release version is available in the Releases area of GitHub, with Linux and Windows binaries pre-created. Download from there.
cargo install --git https://github.com/PeterGrace/codeowner-gen.git
codeowner-gen in a directory with a well-formatted codeowners.yaml will output a CODEOWNERS file. If you want to specify an alternate yaml, use -i option.
The traditional format uses an entries array where each entry specifies a path and its owners:
---
entries:
- path: "alpha"
comment: "Alphabetically speaking, this probably is coming early on"
group: "phonetic"
owners:
- "@petergrace"
- path: "zebra"
comment: "This is likely the last entry"
group: "phonetic"
owners:
- "@petergrace"
- path: "*"
group: "main"
owners:
- "@petergrace"
- path: "target/debug/deps/itoa-*"
owners:
- "pete.grace@gmail.com"
- "@petergrace"
- "@petergrace/teamname"Alternatively, you can use the teams format which maps owners to a list of paths they own. This is useful when you want to manage ownership by team rather than by path:
---
teams:
"@petergrace":
- "alpha"
- "zebra"
"@myorg/platform-team":
- "src/"
- "lib/"
"pete.grace@gmail.com":
- "docs/"Paths in the teams format can also include a group field. Use an object with path and group instead of a simple string:
---
teams:
"@petergrace":
- path: "src/"
group: "core"
- "lib/"
"@myorg/platform-team":
- path: "infra/"
group: "infrastructure"Owner groups let you define reusable collections of owners that can be referenced by name. This is useful when the same set of owners appears in multiple places:
---
owner_groups:
- name: platform_team
owners:
- "@alice"
- "@bob"
- "@myorg/platform"
- name: security_team
owners:
- "@security-lead"
- "@myorg/security"Once defined, owner groups can be referenced by their name (without @) in both entries and teams:
---
owner_groups:
- name: platform_team
owners:
- "@alice"
- "@bob"
entries:
- path: "src/"
owners:
- "platform_team"
- "@extra-reviewer"
teams:
platform_team:
- "lib/"
- "infra/"In this example:
src/will have owners@alice @bob @extra-reviewerlib/andinfra/will each have owners@alice @bob
Note: Owner groups cannot reference other owner groups (no nesting). The owners within an owner group must be valid GitHub usernames (@user), teams (@org/team), or email addresses.
You can combine both formats. When the same path appears in both teams and entries, owners are merged and the entry's metadata (comment/group) is preserved:
---
teams:
"@myorg/team":
- "src/"
entries:
- path: "src/"
comment: "Core source code"
owners:
- "@admin"This results in src/ having owners @myorg/team @admin with the comment "Core source code".
Note: If the same path has a group defined in both entries and teams, the entry's group takes precedence. The team's group is only applied if the entry doesn't already have a group.
Given a yaml file like below:
---
entries:
- path: "alpha"
comment: "Alphabetically speaking, this probably is coming early on"
group: "phonetic"
owners:
- "@petergrace"
- path: "zebra"
comment: "This is likely the last entry"
group: "phonetic"
owners:
- "@petergrace"
- path: "*"
group: "main"
owners:
- "@petergrace"
- path: "target/debug/deps/itoa-*"
owners:
- "pete.grace@gmail.com"
- "@petergrace"
- "@petergrace/teamname"The codeowners-gen program will output:
# Generated by codeowner-gen v0.1.0/2db3d0dbd7ece3182de63b440b07379cb19b49cd
#
####### BEGIN UNGROUPED
target/debug/deps/itoa-* pete.grace@gmail.com @petergrace @petergrace/teamname
####### BEGIN GROUP MAIN
* @petergrace
### END GROUP MAIN
####### BEGIN GROUP PHONETIC
# Alphabetically speaking, this probably is coming early on
alpha @petergrace
# This is likely the last entry
zebra @petergrace