From 64dc4df353de62f0c96dae96897e283e66d5be37 Mon Sep 17 00:00:00 2001 From: Christopher Dignam Date: Mon, 6 Mar 2023 16:46:48 -0500 Subject: [PATCH] wip --- src/lib/ownership/OwnershipEngine.ts | 22 +++++--- src/lib/ownership/exampleCodeownersFile.txt | 59 +++++++++++++++++++++ src/lib/ownership/github-example.test.ts | 10 ++++ 3 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 src/lib/ownership/exampleCodeownersFile.txt create mode 100644 src/lib/ownership/github-example.test.ts diff --git a/src/lib/ownership/OwnershipEngine.ts b/src/lib/ownership/OwnershipEngine.ts index ec8ada4..2f488fa 100644 --- a/src/lib/ownership/OwnershipEngine.ts +++ b/src/lib/ownership/OwnershipEngine.ts @@ -54,8 +54,10 @@ export class OwnershipEngine { if (!line || line.startsWith("#")) { continue; } - - owned.push(createMatcherCodeownersRule(line, idx)); + const matcher = createMatcherCodeownersRule(line, idx); + if (matcher != null) { + owned.push(matcher); + } } return new OwnershipEngine(owned); @@ -67,11 +69,15 @@ export class OwnershipEngine { } const createMatcherCodeownersRule = ( - rule: string, + rawRuleString: string, lineno: number -): FileOwnershipMatcher => { +): FileOwnershipMatcher | null => { + const ruleWithoutComments = rawRuleString.split("#")[0].trim(); + if (!ruleWithoutComments) { + return null; + } // Split apart on spaces - const parts = rule.split(/\s+/); + const parts = ruleWithoutComments.split(/\s+/); // The first part is expected to be the path const path = parts[0]; @@ -83,7 +89,9 @@ const createMatcherCodeownersRule = ( teamNames = parts.slice(1, parts.length); for (const name of teamNames) { if (!codeOwnerRegex.test(name)) { - throw new Error(`${name} is not a valid owner name in rule ${rule}`); + throw new Error( + `${name} is not a valid owner name in rule ${ruleWithoutComments}` + ); } } } @@ -105,7 +113,7 @@ const createMatcherCodeownersRule = ( // Return our complete matcher return { - rule, + rule: ruleWithoutComments, path, owners: teamNames, lineno, diff --git a/src/lib/ownership/exampleCodeownersFile.txt b/src/lib/ownership/exampleCodeownersFile.txt new file mode 100644 index 0000000..82bac45 --- /dev/null +++ b/src/lib/ownership/exampleCodeownersFile.txt @@ -0,0 +1,59 @@ +# This is a comment. +# Each line is a file pattern followed by one or more owners. + +# These owners will be the default owners for everything in +# the repo. Unless a later match takes precedence, +# @global-owner1 and @global-owner2 will be requested for +# review when someone opens a pull request. +* @global-owner1 @global-owner2 + +# Order is important; the last matching pattern takes the most +# precedence. When someone opens a pull request that only +# modifies JS files, only @js-owner and not the global +# owner(s) will be requested for a review. +*.js @js-owner #This is an inline comment. + +# You can also use email addresses if you prefer. They'll be +# used to look up users just like we do for commit author +# emails. +*.go docs@example.com + +# Teams can be specified as code owners as well. Teams should +# be identified in the format @org/team-name. Teams must have +# explicit write access to the repository. In this example, +# the octocats team in the octo-org organization owns all .txt files. +*.txt @octo-org/octocats + +# In this example, @doctocat owns any files in the build/logs +# directory at the root of the repository and any of its +# subdirectories. +/build/logs/ @doctocat + +# The `docs/*` pattern will match files like +# `docs/getting-started.md` but not further nested files like +# `docs/build-app/troubleshooting.md`. +docs/* docs@example.com + +# In this example, @octocat owns any file in an apps directory +# anywhere in your repository. +apps/ @octocat + +# In this example, @doctocat owns any file in the `/docs` +# directory in the root of your repository and any of its +# subdirectories. +/docs/ @doctocat + +# In this example, any change inside the `/scripts` directory +# will require approval from @doctocat or @octocat. +/scripts/ @doctocat @octocat + +# In this example, @octocat owns any file in a `/logs` directory such as +# `/build/logs`, `/scripts/logs`, and `/deeply/nested/logs`. Any changes +# in a `/logs` directory will require approval from @octocat. +**/logs @octocat + +# In this example, @octocat owns any file in the `/apps` +# directory in the root of your repository except for the `/apps/github` +# subdirectory, as its owners are left empty. +/apps/ @octocat +/apps/github diff --git a/src/lib/ownership/github-example.test.ts b/src/lib/ownership/github-example.test.ts new file mode 100644 index 0000000..5de6bda --- /dev/null +++ b/src/lib/ownership/github-example.test.ts @@ -0,0 +1,10 @@ +import path from "path"; +import { OwnershipEngine } from "./OwnershipEngine"; + +test("github example CODEOWNERS file", () => { + expect( + OwnershipEngine.FromCodeownersFile( + path.join(__dirname, "exampleCodeownersFile.txt") + ).calcFileOwnership("example.go")?.owners ?? [] + ).toContain("docs@example.com"); +});