371 lines
10 KiB
Markdown
371 lines
10 KiB
Markdown
---
|
|
stage: Create
|
|
group: Source Code
|
|
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
|
---
|
|
|
|
# Code Owners syntax and error handling **(PREMIUM)**
|
|
|
|
This page describes the syntax and error handling used in Code Owners files,
|
|
and provides an example file.
|
|
|
|
## Code Owners syntax
|
|
|
|
### Comments
|
|
|
|
Lines beginning with `#` are ignored:
|
|
|
|
```plaintext
|
|
# This is a comment
|
|
```
|
|
|
|
### Sections
|
|
|
|
Sections are groups of entries. A section begins with a section heading in square brackets, followed by the entries.
|
|
|
|
```plaintext
|
|
[Section name]
|
|
/path/of/protected/file.rb @username
|
|
/path/of/protected/dir/ @group
|
|
```
|
|
|
|
#### Section headings
|
|
|
|
Section headings must always have a name. They can also be made optional, or
|
|
require a number of approvals. A list of default owners can be added to the section heading line.
|
|
|
|
```plaintext
|
|
# Required section
|
|
[Section name]
|
|
|
|
# Optional section
|
|
^[Section name]
|
|
|
|
# Section requiring 5 approvals
|
|
[Section name][5]
|
|
|
|
# Section with @username as default owner
|
|
[Section name] @username
|
|
|
|
# Section with @group and @subgroup as default owners and requiring 2 approvals
|
|
[Section name][2] @group @subgroup
|
|
```
|
|
|
|
#### Section names
|
|
|
|
Sections names are defined between square brackets. Section names are not case-sensitive.
|
|
[Sections with duplicate names](index.md#sections-with-duplicate-names) are combined.
|
|
|
|
```plaintext
|
|
[Section name]
|
|
```
|
|
|
|
#### Required sections
|
|
|
|
Required sections do not include `^` before the [section name](#section-names).
|
|
|
|
```plaintext
|
|
[Required section]
|
|
```
|
|
|
|
#### Optional sections
|
|
|
|
Optional sections include a `^` before the [section name](#section-names).
|
|
|
|
```plaintext
|
|
^[Optional section]
|
|
```
|
|
|
|
#### Sections requiring multiple approvals
|
|
|
|
Sections requiring multiple approvals include the number of approvals in square brackets after the [section name](#section-names).
|
|
|
|
```plaintext
|
|
[Section requiring 5 approvals][5]
|
|
```
|
|
|
|
NOTE:
|
|
Optional sections ignore the number of approvals required.
|
|
|
|
#### Sections with default owners
|
|
|
|
You can define a default owner for the entries in a section by appending the owners to the [section heading](#section-headings).
|
|
|
|
```plaintext
|
|
# Section with @username as default owner
|
|
[Section name] @username
|
|
|
|
# Section with @group and @subgroup as default owners and requiring 2 approvals
|
|
[Section name][2] @group @subgroup
|
|
```
|
|
|
|
### Code Owner entries
|
|
|
|
Each Code Owner entry includes a path followed by one or more owners.
|
|
|
|
```plaintext
|
|
README.md @username1
|
|
```
|
|
|
|
NOTE:
|
|
If an entry is duplicated in a section, [the last entry is used from each section.](index.md#define-more-specific-owners-for-more-specifically-defined-files-or-directories)
|
|
|
|
### Relative paths
|
|
|
|
If a path does not start with a `/`, the path is treated as if it starts with
|
|
a [globstar](#globstar-paths). `README.md` is treated the same way as `/**/README.md`:
|
|
|
|
```plaintext
|
|
# This will match /README.md, /internal/README.md, /app/lib/README.md
|
|
README.md @username
|
|
|
|
# This will match /internal/README.md, /docs/internal/README.md, /docs/api/internal/README.md
|
|
internal/README.md
|
|
```
|
|
|
|
### Absolute paths
|
|
|
|
If a path starts with a `/` it matches the root of the repository.
|
|
|
|
```plaintext
|
|
# Matches only the file named `README.md` in the root of the repository.
|
|
/README.md
|
|
|
|
# Matches only the file named `README.md` inside the `/docs` directory.
|
|
/docs/README.md
|
|
```
|
|
|
|
### Directory paths
|
|
|
|
If a path ends with `/`, the path matches any file in the directory.
|
|
|
|
```plaintext
|
|
# This is the same as `/docs/**/*`
|
|
/docs/
|
|
```
|
|
|
|
### Wildcard paths
|
|
|
|
Wildcards can be used to match one of more characters of a path.
|
|
|
|
```plaintext
|
|
# Any markdown files in the docs directory
|
|
/docs/*.md @username
|
|
|
|
# /docs/index file of any filetype
|
|
# For example: /docs/index.md, /docs/index.html, /docs/index.xml
|
|
/docs/index.* @username
|
|
|
|
# Any file in the docs directory with 'spec' in the name.
|
|
# For example: /docs/qa_specs.rb, /docs/spec_helpers.rb, /docs/runtime.spec
|
|
/docs/*spec* @username
|
|
|
|
# README.md files one level deep within the docs directory
|
|
# For example: /docs/api/README.md
|
|
/docs/*/README.md @username
|
|
```
|
|
|
|
### Globstar paths
|
|
|
|
Globstars (`**`) can be used to match zero or more directories and subdirectories.
|
|
|
|
```plaintext
|
|
# This will match /docs/index.md, /docs/api/index.md, /docs/api/graphql/index.md
|
|
/docs/**/index.md
|
|
```
|
|
|
|
### Entry owners
|
|
|
|
Entries must be followed by one or more owner. These can be groups, subgroups,
|
|
and users. Order of owners is not important.
|
|
|
|
```plaintext
|
|
/path/to/entry.rb @group
|
|
/path/to/entry.rb @group/subgroup
|
|
/path/to/entry.rb @user
|
|
/path/to/entry.rb @group @group/subgroup @user
|
|
```
|
|
|
|
#### Groups as entry owners
|
|
|
|
Groups and subgroups can be owners of an entry.
|
|
Each entry can be owned by [one or more owners](#entry-owners).
|
|
For more details see the [Add a group as a Code Owner](index.md#add-a-group-as-a-code-owner).
|
|
|
|
```plaintext
|
|
/path/to/entry.rb @group
|
|
/path/to/entry.rb @group/subgroup
|
|
/path/to/entry.rb @group @group/subgroup
|
|
```
|
|
|
|
### Users as entry owners
|
|
|
|
Users can be owners of an entry. Each entry can be owned by
|
|
[one or more owners](#entry-owners).
|
|
|
|
```plaintext
|
|
/path/to/entry.rb @username1
|
|
/path/to/entry.rb @username1 @username2
|
|
```
|
|
|
|
## Error handling in Code Owners
|
|
|
|
### Entries with spaces
|
|
|
|
Paths containing whitespace must be escaped with backslashes: `path\ with\ spaces/*.md`.
|
|
Without the backslashes, the path after the first whitespace is parsed as an owner.
|
|
GitLab the parses `folder with spaces/*.md @group` into
|
|
`path: "folder", owners: " with spaces/*.md @group"`.
|
|
|
|
### Unparsable sections
|
|
|
|
If a section heading cannot be parsed, the section is:
|
|
|
|
1. Parsed as an entry.
|
|
1. Added to the previous section.
|
|
1. If no previous section exists, the section is added to the default section.
|
|
|
|
For example, this file is missing a square closing bracket:
|
|
|
|
```plaintext
|
|
* @group
|
|
|
|
[Section name
|
|
docs/ @docs_group
|
|
```
|
|
|
|
GitLab recognizes the heading `[Section name` as an entry. The default section includes 3 rules:
|
|
|
|
- Default section
|
|
- `*` owned by `@group`
|
|
- `[Section` owned by `name`
|
|
- `docs/` owned by `@docs_group`
|
|
|
|
This file contains an unescaped space between the words `Section` and `name`.
|
|
GitLab recognizes the intended heading as an entry:
|
|
|
|
```plaintext
|
|
[Docs]
|
|
docs/**/* @group
|
|
|
|
[Section name]{2} @group
|
|
docs/ @docs_group
|
|
```
|
|
|
|
The `[Docs]` section then includes 3 rules:
|
|
|
|
- `docs/**/*` owned by `@group`
|
|
- `[Section` owned by `name]{2} @group`
|
|
- `docs/` owned by `@docs_group`
|
|
|
|
### Malformed owners
|
|
|
|
Each entry must contain 1 or more owners to be valid, malformed owners are ignored.
|
|
For example `/path/* @group user_without_at_symbol @user_with_at_symbol`
|
|
is owned by `@group` and `@user_with_at_symbol`.
|
|
|
|
### Inaccessible or incorrect owners
|
|
|
|
Inaccessible or incorrect owners are ignored. For example, if `@group`, `@username`,
|
|
and `example@gitlab.com` are accessible on the project and we create an entry:
|
|
|
|
```plaintext
|
|
* @group @grou @username @i_left @i_dont_exist example@gitlab.com invalid@gitlab.com
|
|
```
|
|
|
|
GitLab ignores `@grou`, `@i_left`, `@i_dont_exist`, and `invalid@gitlab.com`.
|
|
|
|
For more information on who is accessible, see [Add a group as a Code Owner](index.md#add-a-group-as-a-code-owner).
|
|
|
|
### Zero owners
|
|
|
|
If an entry includes no owners, or zero [accessible owners](#inaccessible-or-incorrect-owners)
|
|
exist, the entry is invalid. Because this rule can never be satisfied, GitLab
|
|
auto-approves it in merge requests.
|
|
|
|
NOTE:
|
|
When a protected branch has `Require code owner approval` enabled, rules with
|
|
zero owners are still honored.
|
|
|
|
### Less than 1 required approval
|
|
|
|
When [defining the number of approvals](index.md#require-multiple-approvals-from-code-owners) for a section,
|
|
the minimum number of approvals is `1`. Setting the number of approvals to
|
|
`0` results in GitLab requiring one approval.
|
|
|
|
## Example `CODEOWNERS` file
|
|
|
|
```plaintext
|
|
# This is an example of a CODEOWNERS file.
|
|
# Lines that start with `#` are ignored.
|
|
|
|
# app/ @commented-rule
|
|
|
|
# Specify a default Code Owner by using a wildcard:
|
|
* @default-codeowner
|
|
|
|
# Specify multiple Code Owners by using a tab or space:
|
|
* @multiple @code @owners
|
|
|
|
# Rules defined later in the file take precedence over the rules
|
|
# defined before.
|
|
# For example, for all files with a filename ending in `.rb`:
|
|
*.rb @ruby-owner
|
|
|
|
# Files with a `#` can still be accessed by escaping the pound sign:
|
|
\#file_with_pound.rb @owner-file-with-pound
|
|
|
|
# Specify multiple Code Owners separated by spaces or tabs.
|
|
# In the following case the CODEOWNERS file from the root of the repo
|
|
# has 3 Code Owners (@multiple @code @owners):
|
|
CODEOWNERS @multiple @code @owners
|
|
|
|
# You can use both usernames or email addresses to match
|
|
# users. Everything else is ignored. For example, this code
|
|
# specifies the `@legal` and a user with email `janedoe@gitlab.com` as the
|
|
# owner for the LICENSE file:
|
|
LICENSE @legal this_does_not_match janedoe@gitlab.com
|
|
|
|
# Use group names to match groups, and nested groups to specify
|
|
# them as owners for a file:
|
|
README @group @group/with-nested/subgroup
|
|
|
|
# End a path in a `/` to specify the Code Owners for every file
|
|
# nested in that directory, on any level:
|
|
/docs/ @all-docs
|
|
|
|
# End a path in `/*` to specify Code Owners for every file in
|
|
# a directory, but not nested deeper. This code matches
|
|
# `docs/index.md` but not `docs/projects/index.md`:
|
|
/docs/* @root-docs
|
|
|
|
# Include `/**` to specify Code Owners for all subdirectories
|
|
# in a directory. This rule matches `docs/projects/index.md` or
|
|
# `docs/development/index.md`
|
|
/docs/**/*.md @root-docs
|
|
|
|
# This code makes matches a `lib` directory nested anywhere in the repository:
|
|
lib/ @lib-owner
|
|
|
|
# This code match only a `config` directory in the root of the repository:
|
|
/config/ @config-owner
|
|
|
|
# If the path contains spaces, escape them like this:
|
|
path\ with\ spaces/ @space-owner
|
|
|
|
# Code Owners section:
|
|
[Documentation]
|
|
ee/docs @docs
|
|
docs @docs
|
|
|
|
# Use of default owners for a section. In this case, all files (*) are owned by
|
|
the dev team except the README.md and data-models which are owned by other teams.
|
|
[Development] @dev-team
|
|
*
|
|
README.md @docs-team
|
|
data-models/ @data-science-team
|
|
|
|
# This section is combined with the previously defined [Documentation] section:
|
|
[DOCUMENTATION]
|
|
README.md @docs
|
|
```
|