使用 CODEOWNERS 管理提取要求核准

本指南說明 CODEOWNERS 功能的結構、語法和實作方式,方便您彈性控管 Pull Request (PR) 的核准規定。

簡介

Secure Source Manager CODEOWNERS 功能會使用程式碼基底中的檔案,設定檔案層級的核准者。相較於其他分支規則,這項功能可提供更精細的控制權,因為您可以為特定檔案指派特定擁有者,並定義獨立的核准者組合。

CODEOWNERS 功能提供下列功能:

  • 定義可核准檔案、目錄和分支機構提取要求的使用者。
  • 設定不同的程式碼擁有者組合,保護不同分支。
  • 確保指定擁有者會審查檔案變更。

啟用程式碼擁有者審查

如要啟用及強制執行 CODEOWNERS 規則,分支保護管理員必須在存放區設定中更新分支規則,將「Require Code Owner Review on Pull Requests」(要求對提取要求進行程式碼擁有者審查) 設為啟用。在分支規則設定中選取這個選項。如果這項設定為「關閉」,系統會忽略 CODEOWNERS 檔案,以便合併至目標分支。如果選取這個選項,系統會封鎖推送和合併至分支版本機構的作業,直到程式碼擁有者審查並核准提取要求為止。

CODEOWNERS 檔案位置和優先順序

Secure Source Manager 支援兩種定義 CODEOWNERS 檔案的選項:

  1. 巢狀檔案:任何目錄中的 CODEOWNERS 檔案, .securesourcemanager 目錄除外。巢狀 CODEOWNERS 檔案只會影響自己的目錄 (包括子目錄),且其中的檔案路徑必須相對於 CODEOWNERS 檔案所在的目錄指定。建議您在多數情況下採用這種做法。

  2. 單一專屬檔案:如需區分 Secure Source Manager 的 CODEOWNERS 檔案與其他工具使用的 CODEOWNERS 檔案 (例如 .gitlab/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-*-glob 會比對 my-feat-glob 等分支版本。
  • PATH_GLOB:必要全域模式,指定規則適用的檔案路徑。Secure Source Manager 的語法以gitignore 模式為基礎。

    • 如果模式不含 /,或只含 / 做為尾隨字元,則為在任何目錄中相符的 glob。
      • *.js 會比對任何位置的 JavaScript 檔案。
      • build/ 會比對任何位置名為 build 的目錄。
    • 如果模式在結尾以外的位置包含 /,系統會將其視為 CODEOWNERS 檔案位置的相對路徑。
      • docs/* 會比對 docs/ 底下的檔案,與 CODEOWNERS 檔案相對。
      • /*.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] 將規則分組,各自需要獨立核准。這項功能可讓您要求不同團隊 (例如安全性或 QA) 進行審查。

  • 區段定義:使用 [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 檔案。

處理語法錯誤

只有在啟用「Require Code Owner Review on Pull Requests」(要求對提取要求進行程式碼擁有者審查) 的分支上,才會執行預先提交檢查。如果語法無效的 CODEOWNERS 檔案已提交至分支版本,且稍後為該分支版本啟用程式碼擁有者審查,系統會妥善處理錯誤:

  • 如果系統無法將某幾行剖析為區段定義、規則行或註解格式,就會忽略這些行。
  • 如果核准次數為負數,系統會視為 0。
  • 系統會繼續照常剖析及套用所有有效行。

後續步驟