The @nx/owners
plugin extends the CODEOWNERS functionality to allow you to define code ownership based on projects in addition to the standard file-based definitions. It leverages the nx sync
command to compile owners
configuration settings from nx.json
and project configuration files into valid CODEOWNERS files for GitHub, Bitbucket or GitLab.
With this plugin, you can specify code ownership using the same project matcher syntax as nx run-many
. This allows you to easily define rules for multiple projects that may not be located in the same directory. Also, the CODEOWNERS rules will not need to be revisited if a project location is changed or a new project is added.
Set Up @nx/owners
Section titled “Set Up @nx/owners”Activate Powerpack if you haven't already
Install the package
nx add @nx/ownersConfigure Ownership
Configure the
@nx/owners
plugin in thenx.json
file or in individual project configuration files. Consult the Owners Configuration Reference section for more details.Configure the Sync Generator and CI
The nx add @nx/owners
command should have registered the @nx/owners:sync-codeowners-file
generator as a globalGenerator
in nx.json
. You can double check to make sure:
{ "sync": { "globalGenerators": ["@nx/owners:sync-codeowners-file"] }}
Add nx sync:check
to the beginning of the CI process.
- name: Ensure the workspace configuration is in sync run: npx nx sync:check
It is also often helpful to add nx sync
as a git push hook or git commit hook.
Owners Configuration Reference
Section titled “Owners Configuration Reference”{ // Can be set to true instead of an object to accept all defaults "owners": { // Options are `github`, `bitbucket` or `gitlab`. (Optional) Defaults to `github` "format": "github", // (Optional) Default changes based on format: `.github/CODEOWNERS`, `.bitbucket/CODEOWNERS`, `.gitlab/CODEOWNERS` "outputPath": "CODEOWNERS", // (Optional) "patterns": [ { "description": "A description of the rule", "owners": ["@joelovesrust"], // specify either projects or files, not both // Can be any project specifier that could be used in `nx run-many` // See https://nx.dev/reference/core-api/nx/documents/run-many "projects": ["my-rust-app", "rust-*", "tag:rust"], // File globs "files": [".github/workflows/**/*"] } ] }}
{ // Can be set to true instead of an object to accept all defaults "owners": { // Options are `github`, `bitbucket` or `gitlab`. (Optional) Defaults to `github` "format": "bitbucket", // (Optional) Default changes based on format: `.github/CODEOWNERS`, `.bitbucket/CODEOWNERS`, `.gitlab/CODEOWNERS` "outputPath": "CODEOWNERS", // (Optional) "patterns": [ { "description": "A description of the rule", "owners": ["@joelovesrust"], // specify either projects or files, not both // Can be any project specifier that could be used in `nx run-many` // See https://nx.dev/reference/core-api/nx/documents/run-many "projects": ["my-rust-app", "rust-*", "tag:rust"], // File globs "files": [".github/workflows/**/*"] } ] }}
If you are using GitLab, you can specify CODEOWNERS sections which give you a little more control over the PR process.
{ // Can be set to true instead of an object to accept all defaults "owners": { // Options are `github`, `bitbucket` or `gitlab`. (Optional) Defaults to `github` "format": "gitlab", // (Optional) Default changes based on format: `.github/CODEOWNERS`, `.bitbucket/CODEOWNERS`, `.gitlab/CODEOWNERS` "outputPath": "CODEOWNERS", // (Optional) "patterns": [ { "description": "A description of the rule", "owners": ["@joelovesrust"], // Specify either `projects` or `files`, not both // Can be any project specifier that could be used in `nx run-many` // See https://nx.dev/reference/core-api/nx/documents/run-many "projects": ["my-rust-app", "rust-*", "tag:rust"], // File globs "files": [".github/workflows/**/*"] } ], // (Optional) "sections": [ { // Labels the section "name": "My section", // (Optional) The owners to use if a pattern does not specify a set of owners "defaultOwners": ["@cheddar"], // Specify either `numberOfRequiredApprovals` or `optional`, not both // (Optional) Require more than one person to approve the PR "numberOfRequiredApprovals": 2, // (Optional) Do not require any approvals, just notify the owners "optional": true, // Same format as the root patterns "patterns": [] } ] }}
{ "owners": { // Keys are file globs relative to the root of the project // Owners can be listed as a string array "**/*": ["@ahmed", "@petra"], // Owners can be listed as an object with a description "README.md": { "description": "Jared is very particular about the README file", "owners": ["@jared"] } }};
Examples:
{ "owners": { // defaults to "github" "format": "github", // defaults to ".github/CODEOWNERS" "outputPath": "CODEOWNERS", "patterns": [ { "description": "Joe should double check all changes to rust code", "projects": ["tag:rust"], "owners": ["@joelovesrust"] }, { "description": "The Finance team owns these projects", "projects": ["finance-*"], "owners": ["@finance-team"] }, { "description": "Alice, Bob and Cecil work together on these projects", "projects": ["admin", "booking", "cart"], "owners": ["@alice", "@bob", "@cecil"] }, { "description": "CI Workflows", "files": [".github/workflows/**/*"], "owners": ["@devops"] } ] }}
{ "owners": { "**/*": ["@ahmed", "@petra"], "package.json": ["@ahmed"], "README.md": { "owners": ["@jared"], "description": "Jared is very particular about the README file" } },};
{ "owners": { "format": "bitbucket", // defaults to ".bitbucket/CODEOWNERS" "outputPath": "CODEOWNERS", "patterns": [ { "description": "Joe should double check all changes to rust code", "projects": ["tag:rust"], "owners": ["@joelovesrust"] }, { "description": "The Finance team owns these projects", "projects": ["finance-*"], "owners": ["@finance-team"] }, { "description": "Alice, Bob and Cecil work together on these projects", "projects": ["admin", "booking", "cart"], "owners": ["@alice", "@bob", "@cecil"] }, { "description": "CI Workflows", "files": [".github/workflows/**/*"], "owners": ["@devops"] } ] }}
{ "owners": { "**/*": ["@ahmed", "@petra"], "package.json": ["@ahmed"], "README.md": { "owners": ["@jared"], "description": "Jared is very particular about the README file" } },};
{ "owners": { "format": "gitlab", // defaults to ".gitlab/CODEOWNERS" "outputPath": "CODEOWNERS", "patterns": [ { "description": "Joe should double check all changes to rust code", "projects": ["tag:rust"], "owners": ["@joelovesrust"] }, { "description": "CI Workflows", "files": [".github/workflows/**/*"], "owners": ["@devops"] } ], "sections": [ { "name": "Finance", "defaultOwners": ["@finance-team"], "numberOfRequiredApprovals": 2, "patterns": [ { "description": "The Finance team owns these projects", "projects": ["finance-*"] }, { "description": "Alice, Bob and Cecil work together on these projects", "projects": ["admin", "booking", "cart"], "owners": ["@alice", "@bob", "@cecil"] } ] } ] }}
{ "owners": { "**/*": ["@ahmed", "@petra"], "package.json": ["@ahmed"], "README.md": { "owners": ["@jared"], "description": "Jared is very particular about the README file" } },};