1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
|
---
stage: Create
group: Source Code
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
# Code Owners syntax and error handling
DETAILS:
**Tier:** Premium, Ultimate
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
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 specific 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
> - Error validation [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216066) in GitLab 16.3.
### 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.
#### After the default section
```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`
#### After a named section
```plaintext
[Docs]
docs/**/* @group
[Section name
docs/ @docs_group
```
GitLab recognizes the heading `[Section name` as an entry. The `[Docs]` section includes 3 rules:
- `docs/**/*` owned by `@group`
- `[Section` owned by `name`
- `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
```
|