使用 CODEOWNERS 管理拉取请求审批

本指南介绍了 CODEOWNERS 功能的结构、语法和实现,该功能可让您灵活控制拉取请求 (PR) 审批要求。

简介

Secure Source Manager CODEOWNERS 功能使用代码库中的文件来设置文件级审批者。与其他分支规则相比,这种规则可提供更精细的控制,因为您可以为特定文件分配特定所有者,并定义独立的审批者集。

CODEOWNERS 功能提供以下功能:

  • 定义可以批准文件、目录和分支的拉取请求的用户。
  • 配置不同的代码所有者组,以保护不同的分支。
  • 确保指定的所有者会审核文件更改。

启用代码所有者审核

如需启用并强制执行 CODEOWNERS 规则,分支保护管理员必须将代码库设置中的分支规则更新为要求对拉取请求进行代码所有者审核。在分支规则设置中选择此选项。 如果此设置处于 关闭状态,系统会在合并到目标分支时忽略 CODEOWNERS 文件。如果您选择此选项,系统会阻止向分支推送和合并,直到代码所有者审核并批准拉取请求为止。

CODEOWNERS 文件位置和优先级

Secure Source Manager 支持以下两种用于定义 CODEOWNERS 文件的选项:

  1. 嵌套文件:任何目录(除了 .securesourcemanager 目录)中的 CODEOWNERS 文件。嵌套的 CODEOWNERS 文件仅影响其自身目录(包括子目录),其中的文件路径必须相对于 CODEOWNERS 文件所在的目录指定。这是推荐的大多数用例方法。

  2. 单个专用文件:如果您需要区分 Secure Source Manager 的 CODEOWNERS 文件与其他工具(例如 .gitlab/CODEOWNERS)使用的其他 CODEOWNERS 文件,可以使用位于代码库根目录中的 .securesourcemanager/CODEOWNERS 中的单个文件。如果此文件存在,Secure Source Manager 会忽略同一分支中的所有其他 CODEOWNERS 文件,包括嵌套的文件。.securesourcemanager 目录仅在代码库根目录中识别。

与拉取请求和审批互动

创建拉取请求或使用新提交更新其源分支时,系统仅使用目标分支(您要合并到的分支)中的 CODEOWNERS 文件来确定审批要求。系统会忽略推送代码中对 CODEOWNERS 文件所做的更改,以进行相应验证。

CODEOWNERS 语法和结构

CODEOWNERS 文件由注释、规则行和部分标记组成。 注释以 # 开头,会被系统忽略。

标尺线格式

规则行的标准格式为:

[BRANCH_GLOB] PATH_GLOB [OWNERS...]

其中:

  • BRANCH_GLOB:一个可选的 glob 模式,用于指定规则适用的分支。如果您未指定分支 glob,则该规则适用于签入 CODEOWNERS 文件的任何分支(如果该分支的分支规则中已启用 CODEOWNERS)。例如:

    • main 仅与 main 分支匹配。
    • dev-* 匹配以 dev- 开头的分支。
    • *-glob 匹配以 -glob 结尾的分支。
    • my-*-globmy-feat-glob 等分支匹配。
  • PATH_GLOB:必需的 glob 模式,用于指定相应规则适用于哪些文件路径。Secure Source Manager 的语法基于 gitignore 模式

    • 如果模式不包含 /,或者仅包含 / 作为尾随字符,则它是与任何目录匹配的 glob。
      • *.js 匹配任何位置的 JavaScript 文件。
      • build/ 匹配名为 build 的目录(无论位于何处)。
    • 如果某个模式在末尾以外的任何位置包含 /,则会被视为相对于 CODEOWNERS 文件位置的路径。
      • docs/* 匹配 CODEOWNERS 文件下相对于 docs/ 的文件。
      • /*.js 会匹配与 CODEOWNERS 文件位于同一目录中的 JavaScript 文件,但不会匹配嵌套的 JavaScript 文件。
    • / 结尾的模式仅匹配目录及其内容(以递归方式)。例如,build-*/ 可匹配任何位置的 build-app/build-tool/ 等目录。
    • 如果使用 .securesourcemanager/CODEOWNERS,路径相对于代码库根目录。
  • OWNERS:以空格分隔的所有者电子邮件地址的可选列表。如果省略,此规则将充当路径排除规则。

分支机构专属的所有权

规则行开头的可选 BRANCH_GLOB 字段可让您实现特定分支的代码所有者控制。

  • 如果您未在规则开头指定 BRANCH_GLOB,则该规则适用于所有分支。
  • 系统会忽略任何分支 glob 与当前分支不匹配的行。

语法基础知识

  • 字段解释:字段以空格分隔。
    • 包含 @ 的字段会被识别为所有者电子邮件地址。
    • 如果某个不含 @ 的字段位于所有者电子邮件地址之前,则该字段会被视为 PATH_GLOB。例如,在 *.js user@example.com 中,*.jsPATH_GLOB
    • 如果所有者电子邮件地址前面有两个不含 @ 的字段,则第一个字段为 BRANCH_GLOB,第二个字段为 PATH_GLOB。例如,在 main *.js user@example.com 中,mainBRANCH_GLOB*.jsPATH_GLOB
    • 如果未指定任何所有者,则应用相同的逻辑:一个字段为 PATH_GLOB,两个字段为 BRANCH_GLOB PATH_GLOB
  • Glob 样式语法:Secure Source Manager 使用标准的 glob 样式(.gitignore 样式)路径表达式语法。
  • 通配符详细信息
    • ** 可匹配任何字符序列,包括 /
    • * 匹配任何字符序列,但 / 除外。
    • ? 匹配除 / 以外的任何单个字符。
  • 区分大小写CODEOWNERS 文件区分大小写。
  • 所有者身份识别:系统通过电子邮件地址识别所有者。@ 字符用于区分所有者字段。
  • 在所有者电子邮件地址中,只需要转义 spacebackslash
  • 保留字符:系统保留了以下字符。您必须在分支和路径表达式中对它们进行反斜杠转义 (\):[] @*?\{}!
  • 如果 ** 与非斜杠字符混用,系统会将其视为常规通配符。例如,/**/*.py 会匹配任意深度的 Python 文件,而 /**.py 会被视为 /*.py,并且仅匹配根目录中的文件。

多个审批组的版块

使用 [Section] 将规则分组为独立的必需审批。这对于要求不同团队(例如安全团队或质量检查团队)进行审核非常有用。

  • 部分定义:使用 [Section Name] 格式的行(使用任何自然语言名称)。
  • 审批数量:部分可以包含可选的后缀 [<approverCount>],以指定除 1 以外的审批数量。数量为 0 表示可选所有者。例如,您可以使用此功能显示特定文件的专家,以供参考,而无需专家审核。
  • 部分终止:一个部分适用于其后的所有规则,直到下一个部分开始。
  • 未分段的规则:系统会将出现在任何 [Section] 定义之前的规则视为一个统一的段落,默认情况下需要一次审批。
  • 合并:系统会将具有相同名称(不区分大小写)的各个部分(即使分布在多个嵌套的 CODEOWNERS 文件中)视为一个统一的部分,并遵循标准的优先级规则

路径排除

如需从之前的更广泛子句中排除特定路径,请为该路径设置零个所有者。如果您定义的规则不包含任何所有者,系统会移除之前规则为相应路径设置的所有者,并且该路径不需要所有者批准。

只有当目录匹配项以 / 结尾或最后一部分不包含任何通配符时,目录匹配项才有效。

例如,*.py 不会匹配隐藏目录 .py/,但 *.py/ 会匹配。

冲突解决和优先顺序

如果存在 .securesourcemanager/CODEOWNERS 文件,则所有其他 CODEOWNERS 文件都会被忽略。如果某个路径与同一部分中的两行不同代码匹配,则仅应用最后一行。如果这些行位于不同的部分,则两者都会应用。

系统针对嵌套文件使用基于位置的优先规则:

  • 深层嵌套(更本地化)的 CODEOWNERS 文件中的规则会替换较浅层级文件中的匹配规则。
  • 根目录 CODEOWNERS 文件的优先级始终最低。

CODEOWNERS 文件示例

以下是一个 CODEOWNERS 文件示例,展示了 CODEOWNERS 语法:

# Un-sectioned rules; 1 approve required from any of owners of last matching line.
# Format: [BRANCH_GLOB] PATH_GLOB [OWNERS...]

# Make repo-admin the owner of all files of the current branch.
*   repo-admin@example.com      # No slash prefix; matches in sub-dirs too.
/**/* repo-admin@example.com      # Slash-prefix equivalent of prior line.

# Match all py files (including sub-dirs). Note repo-admin must be re-added.
*.py  repo-admin@example.com python-owner@example.com

# With repo-admin not included here, repo-admin no longer owns README.
/README.md readme-owner@example.com

/scratchpad.txt             # Can also override a path to have zero owners (path exclusion).

# Branch-specific syntax.
# Note that since un-sectioned rules are independent of sectioned rules,
# the above [Section] rules will still apply to this branch if they
# aren't modified to add e.g. `main ` as a prefix.
dev-* *             # Remove all owners reqs on dev branches.
dev-* /experimental/ exp-owner@example.com   # dev-specific owners.

# Make repo admin own all CODEOWNERS files, regardless of any prior rules.
CODEOWNERS repo-admin@example.com

# Section; 1 approval required *in addition* to owners outside this section.
[Security Team]
/secure-directory/ security-expert@example.com security-reviewer@example.com
/**/*secure\ me* security-expert@example.com security-reviewer@example.com

# Section w/ req approval count of 2 instead of 1.
[Doc Team][2]
/docs doc-expert@example.com doc-reviewer@example.com
*.md doc-expert@example.com doc-reviewer@example.com

与其他源代码管理器的兼容性

Secure Source Manager 提供了一种与其他源代码管理器兼容的熟悉且可移植的语法。Secure Source Manager CODEOWNERS 语法与 GitHub CODEOWNERS 语法兼容,并与 GitLab CODEOWNERS 语法部分兼容,包括 [Section Name][2] 等分段审批计数。

Secure Source Manager 的 CODEOWNERS 实现不支持 GitLab !path 路径否定语法。如需了解 Secure Source Manager 中的路径否定,请参阅路径排除。Secure Source Manager 也不支持在部分标题中使用默认所有者,例如 [Section Name] @owner1 @owner2

验证和错误处理

查看 CODEOWNERS 文件时,界面会显示其状态以及行级警告或信息(例如,与此分支不匹配的行)。您可以将鼠标悬停在突出显示的行号或行上,以查看更多详细信息。

强制执行

预提交防护措施会在您启用代码所有者分支规则的任何分支上强制执行语法错误检查。这样可以防止您意外提交损坏的 CODEOWNERS 文件。

语法错误处理

预提交检查仅在启用了需要代码所有者审核拉取请求的分支上运行。如果将语法无效的 CODEOWNERS 文件提交到分支,并且稍后为该分支启用了代码所有者审核,系统会妥善处理错误:

  • 系统会忽略无法解析为部分定义、规则行或注释格式的行。
  • 如果审批次数为负数,系统会将其视为 0。
  • 系统会继续像往常一样解析并应用所有有效行。

后续步骤