Функция CODEOWNERS позволяет определить ответственных за отдельные части репозитория. Ответственными могут быть пользователи и группы. Изменения, затрагивающие файлы, указанные в CODEOWNERS, должны получить апрув от владельцев кода.

Использование CODEOWNERS помогает:

  • требовать апрувы от доменных экспертов для важных директорий;
  • упростить процесс поиска «ответственных» за конкретный участок кода.

CODEOWNERS дополняет механизм правил апрува, но не заменяет их. В отличие от правил апрува, которые задаются вручную в UI, CODEOWNERS работает через файл CODEOWNERS в репозитории.

Как работает CODEOWNERS

CODEOWNERS — текстовый файл в репозитории. Deckhouse Code использует его для определения владельцев файлов, участвующих в запросе на слияние.

Ищется в трёх местах (по приоритету):

  1. ./CODEOWNERS.
  2. ./docs/CODEOWNERS.
  3. ./.gitlab/CODEOWNERS.

Используется только первый найденный файл.

Если в проекте существует несколько файлов и вы сейчас просматриваете неприоритетный, то увидите соответствующее сообщение.

неприоритетный файл

Валидация файла CODEOWNERS

Валидация помогает увидеть ошибки в файле на этапе редактирования.

Если файл валиден, отображается соответствующее сообщение:

Валидный файл

Если файл невалиден, будут отображены проблемные строки и тип ошибки:

Невалидный файл

Существует 4 вида ошибок валидации:

  • У владельцев нет доступа в этот проект или их уровень доступа недостаточен — как минимум один из владельцев не имеет достаточных прав в проекте.
  • Пробелы в пути — если путь содержит пробелы, нужно их экранировать символом \.
  • Нет владельцев — не указано ни одного владельца.
  • Незакрытый раздел — не хватает символа закрытия раздела ].

Где применяется CODEOWNERS

Если MR, изменяющий файл, попадает под правила CODEOWNERS, то необходимо получить апрувы от владельцев.

Формат CODEOWNERS

Строка правила:

<путь или паттерн> <список владельцев>

Владельцы:

  • @user;
  • @group;
  • @group/subgroup;
  • роли: @@developer, @@maintainer, @@owner.

Примеры

# Владелец всех файлов
* @default-team

# README.md только в корне
/README.md @docs-team

# Все Ruby-файлы
*.rb @backend-team

# Вся директория config
/config/ @devops

# README.md в любом месте
README.md @docs

Паттерны путей

Deckhouse Code использует подстановочные символы:

  • * — любые символы кроме /.
  • ** — матч нескольких уровней директорий.
  • /dir/ — только указанная директория.
  • *.md — все Markdown-файлы.
  • /config/**/*.rb — все Ruby-файлы внутри config/* на всех уровнях.

Примеры паттернов

/docs/*       @docs-one      # один уровень
/docs/**      @docs-two      # рекурсивно
/app/**/*.rb  @ruby-team

Секции CODEOWNERS

В файле CODEOWNERS секции — это именованные области, которые анализируются отдельно и всегда применяются. Пока вы не определите ни одной секции, Deckhouse Code рассматривает весь файл CODEOWNERS как одну единственную секцию.

Особенности использования CODEOWNERS:

  • Deckhouse Code рассматривает записи без секций, включая правила, определённые до первой секции, как отдельную, безымянную секцию.
  • Каждая секция обрабатывает свои правила отдельно.
  • Если путь к файлу соответствует нескольким записям внутри одной секции, используется только последняя подходящая запись в этой секции.
  • Если путь к файлу соответствует записям в нескольких секциях, используется последняя подходящая запись в каждой секции.

Например, в файле CODEOWNERS со следующими секциями, определяющими владельцев для README:

* @root

[README Owners]
README.md @user1 @user2
internal/README.md @user4

[README other owners]
README.md @user3

Владельцы для README.md в корневой директории:

  • @root — из безымянной секции.
  • @user1 и @user2 — из секции [README Owners].
  • @user3 — из секции [README other owners].

Владельцы для internal/README.md:

  • @root — из безымянной секции.
  • @user4 — из секции [README Owners]. (И README.md, и internal/README.md подходят под правила секции, но используется только последняя подходящая запись в этой секции).
  • @user3 — из секции [README other owners].

В виджете запроса на слияние каждый владелец кода отображается под своим ярлыком.

Пример codeowners

Детальный пример: сложная комбинация секций

Ниже — пример реального промышленного файла, показывающий:

  • секции с разным количеством апрувов;
  • переопределение владельцев;
  • опциональные секции;
  • исключения;
  • наследование секций с одинаковыми именами.
# Глобальные настройки
* @fallback-team
!*.lock                    # lock-файлы не требуют апрувов
!**/generated/**           # автоматическая генерация

[Backend][2] @backend-core
# Требуются 2 апрува от backend-core для любого Ruby-кода
app/**/*.rb

# Но для критических моделей определяем другой порядок
app/models/**/*.rb @backend-core @security-team

# А вот эта модель — исключение, владелец другой
app/models/legacy/**/*.rb @migration-team

[Backend]
# Дополнение секции: теперь Backend включает также SQL
db/**/*.sql @db-team

[Ruby Optional]
# Дополнительная подсветка владельцев, апрувы НЕ обязательны
^[Ruby Optional]
*.rb @ruby-advisors

[Frontend][3]
# Для UI требуется 3 апрува
*.vue @frontend-team
*.js  @frontend-team

# переопределение: конкретный файл → конкретный человек
frontend/critical_entry.vue @frontend-lead

[Docs]
*.md @technical-writers

[Docs]
# переопределение: README всегда принадлежит docs-lead
README.md @docs-lead

Особенности примера:

  • секция [Backend] объявлена дважды → Deckhouse Code объединит её;
  • [Backend][2] @backend-core задаёт обязательные 2 апрува;
  • [Frontend][3] требует 3 апрува от фронтенда;
  • [Ruby Optional] отмечена как опциональная — владельцы видны, но их апрув не обязателен;
  • исключения !*.lock и !**/generated/** означают, что эти файлы вообще не требуют апрувов.

Исключения (!)

Используются для исключения файлов внутри секции:

* @default
!package-lock.json
!**/generated/**

После исключения файл не может быть снова включён в ту же секцию.

Порядок обработки правил

Правила обрабатываются в соответствии со следующим порядком:

  • Deckhouse Code читает файл сверху вниз.
  • В пределах одной секции правила с одинаковым путём переопределяют предыдущие.
  • Если файл подходит под несколько секций — владельцы из всех этих секций добавляются.
  • Секции не переопределяют друг друга — они независимы.

Кто может быть владельцем (eligible owners)

1. Пользователи (через @username)

Пользователь считается валидным владельцем, если:

  • Имеет прямое членство в проекте (Developer, Maintainer или Owner).
  • Имеет членство в группе проекта (включая наследуемое: группа проекта, родительские группы, предки родительских групп).
  • Является прямым или унаследованным участником группы, которая напрямую приглашена в проект.
  • Является прямым но не унаследованным участником группы которая приглашена в группу проекта.
  • Является прямым но не унаследованным участником группы которая приглашена в предка группы проекта.

Если подытожить, то подходят все пользователи которые отображаются на странице участников проекта с ролью developer или выше.

Не считается владельцем, если:

  • заблокирован,
  • доступ отозван,
  • роль ниже Developer.

2. Группы (через @group или @group/subgroup)

Группа может быть владельцем только если:

  • Она напрямую приглашена в проект с ролью Developer+ (через “Пригласить группу”).
  • Владельцами считаются только прямые участники этой группы.

Наследуемые участники родительских групп владельцами не считаются.

3. Роли (через @@role)

Формат:

@@developer
@@maintainer
@@owner

Особенности:

  • учитываются только прямые участники проекта;
  • члены групп в расчёт не входят;
  • роли не наследуют друг друга (@@developer НЕ включает maintainer’ов).

Можно указывать несколько ролей в одной строке:

file.md @@developer @@maintainer

Взаимодействие с правилами апрува

CODEOWNERS и правила апрувов работают независимо, но их требования суммируются.

Пример:

  • правило Security требует 1 апрув;
  • секция [Backend][2] требует 2 апрува;
  • MR меняет backend-файл.

Итог: необходимо 3 апрува.

Рекомендации по оформлению

При оформлении файла CODEOWNERS следуйте рекомендациям:

  • Сначала задавайте широкие правила (* @team). Далее уточняющие (app/**/*.rb @backend-team).
  • Используйте секции для лучшей структуры и наглядности.
  • Избегайте дубликатов — последнее правило в секции имеет приоритет.
  • Опциональные секции полезны для подсветки экспертов без обязательных апрувов.

Пример финального файла

# Глобальные владельцы
* @default-team

# Исключения
!yarn.lock
!**/generated/**

[Backend][2]
app/**/*.rb @backend-core

[Frontend][3]
*.vue @frontend-team
*.js @frontend-team

^[Docs]
*.md @docs-team

[Critical Overrides]
/config/production.yml @ops-lead