diff --git a/CODEOWNERS b/CODEOWNERS index 283b979289..0d5c319413 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -8,118 +8,118 @@ package.json @FrozenPandaz @vsavkin @AgentEnder @jaysoo @JamesHenry pnpm-lock.yaml @FrozenPandaz @vsavkin @AgentEnder @jaysoo @JamesHenry # Docs Site + Graph -/docs @bcabanes @isaacplmann @juristr -/docs/nx-cloud @StalkAltan @rarmatei @isaacplmann @juristr @bcabanes +/docs @nrwl/nx-docs-reviewers +/docs/nx-cloud @StalkAltan @rarmatei @nrwl/nx-docs-reviewers /graph/** @philipjfulcher @FrozenPandaz @bcabanes -/images @bcabanes @isaacplmann @juristr -/nx-dev/** @bcabanes @isaacplmann @juristr -/typedoc-theme @bcabanes @isaacplmann +/images @nrwl/nx-docs-reviewers +/nx-dev/** @nrwl/nx-docs-reviewers +/typedoc-theme @nrwl/nx-docs-reviewers # Plugin Verticals ## Angular -/docs/generated/packages/angular/** @Coly010 @leosvelperez -/docs/shared/packages/angular/** @Coly010 @leosvelperez @isaacplmann @juristr -/packages/angular/** @Coly010 @leosvelperez -/e2e/angular-core/** @Coly010 @leosvelperez -/e2e/angular-extensions/** @Coly010 @leosvelperez -/packages/angular/plugins/component-testing.ts @leosvelperez @Coly010 @barbados-clemens -/packages/angular/src/generators/cypress-component-configuration/** @leosvelperez @Coly010 @barbados-clemens -/packages/angular/src/generators/component-test/** @leosvelperez @Coly010 @barbados-clemens +/docs/generated/packages/angular/** @nrwl/nx-angular-reviewers @nrwl/nx-docs-reviewers +/docs/shared/packages/angular/** @nrwl/nx-angular-reviewers @nrwl/nx-docs-reviewers +/packages/angular/** @nrwl/nx-angular-reviewers +/e2e/angular-core/** @nrwl/nx-angular-reviewers +/e2e/angular-extensions/** @nrwl/nx-angular-reviewers +/packages/angular/plugins/component-testing.ts @nrwl/nx-angular-reviewers @nrwl/nx-testing-tools-reviewers +/packages/angular/src/generators/cypress-component-configuration/** @nrwl/nx-angular-reviewers @nrwl/nx-testing-tools-reviewers +/packages/angular/src/generators/component-test/** @nrwl/nx-angular-reviewers @nrwl/nx-testing-tools-reviewers ## React -/docs/generated/packages/react/** @jaysoo @ndcunningham @mandarini @xiongemi -/docs/generated/packages/next/** @jaysoo @ndcunningham @xiongemi -/docs/shared/packages/react/** @jaysoo @ndcunningham @mandarini @xiongemi -/docs/shared/packages/next/** @jaysoo @ndcunningham @xiongemi -/packages/react/** @jaysoo @ndcunningham @mandarini @xiongemi -/e2e/react-core/** @jaysoo @mandarini @xiongemi @ndcunningham -/e2e/react-extensions/** @jaysoo @mandarini @xiongemi @ndcunningham -/packages/next/** @ndcunningham @jaysoo @xiongemi -/e2e/next/** @ndcunningham @jaysoo @xiongemi -/packages/react/plugins/component-testing/** @jaysoo @ndcunningham @barbados-clemens -/packages/react/src/generators/cypress-component-configuration/** @jaysoo @ndcunningham @barbados-clemens -/packages/react/src/generators/component-test/** @jaysoo @ndcunningham @barbados-clemens +/docs/generated/packages/react/** @nrwl/nx-react-reviewers @nrwl/nx-docs-reviewers +/docs/generated/packages/next/** @nrwl/nx-react-reviewers @nrwl/nx-docs-reviewers +/docs/shared/packages/react/** @nrwl/nx-react-reviewers @nrwl/nx-docs-reviewers +/docs/shared/packages/next/** @nrwl/nx-react-reviewers @nrwl/nx-docs-reviewers +/packages/react/** @nrwl/nx-react-reviewers +/e2e/react-core/** @nrwl/nx-react-reviewers +/e2e/react-extensions/** @nrwl/nx-react-reviewers +/packages/next/** @nrwl/nx-react-reviewers +/e2e/next/** @nrwl/nx-react-reviewers +/packages/react/plugins/component-testing/** @nrwl/nx-react-reviewers @nrwl/nx-testing-tools-reviewers +/packages/react/src/generators/cypress-component-configuration/** @nrwl/nx-react-reviewers @nrwl/nx-testing-tools-reviewers +/packages/react/src/generators/component-test/** @nrwl/nx-react-reviewers @nrwl/nx-testing-tools-reviewers # React Native -/docs/generated/packages/detox/** @xiongemi @jaysoo @ndcunningham -/docs/generated/packages/expo/** @xiongemi @jaysoo @ndcunningham -/docs/generated/packages/react-native/** @xiongemi @jaysoo @ndcunningham -/docs/shared/packages/react-native/** @xiongemi @jaysoo @ndcunningham @FrozenPandaz @isaacplmann @juristr -/packages/detox/** @xiongemi @jaysoo @ndcunningham -/e2e/detox/** @xiongemi @jaysoo @ndcunningham -/packages/expo/** @xiongemi @jaysoo @ndcunningham -/e2e/expo/** @xiongemi @jaysoo @ndcunningham -/packages/react-native/** @xiongemi @jaysoo @ndcunningham -/e2e/react-native/** @xiongemi @jaysoo @ndcunningham +/docs/generated/packages/detox/** @nrwl/nx-react-reviewers @nrwl/nx-docs-reviewers +/docs/generated/packages/expo/** @nrwl/nx-react-reviewers @nrwl/nx-docs-reviewers +/docs/generated/packages/react-native/** @nrwl/nx-react-reviewers @nrwl/nx-docs-reviewers +/docs/shared/packages/react-native/** @nrwl/nx-react-reviewers @nrwl/nx-docs-reviewers +/packages/detox/** @nrwl/nx-react-reviewers +/e2e/detox/** @nrwl/nx-react-reviewers +/packages/expo/** @nrwl/nx-react-reviewers +/e2e/expo/** @nrwl/nx-react-reviewers +/packages/react-native/** @nrwl/nx-react-reviewers +/e2e/react-native/** @nrwl/nx-react-reviewers ## Node -/docs/generated/packages/node/** @nartc @ndcunningham @jaysoo -/docs/generated/packages/nest/** @nartc @ndcunningham @jaysoo -/docs/generated/packages/express/** @nartc @ndcunningham @jaysoo -/docs/shared/packages/node/** @nartc @FrozenPandaz @isaacplmann @juristr -/docs/shared/packages/express/** @ndcunningham @nartc @FrozenPandaz @isaacplmann @juristr -/docs/shared/packages/nest/** @ndcunningham @nartc @FrozenPandaz @isaacplmann @juristr -/packages/node/** @nartc @ndcunningham @jaysoo -/packages/express/** @nartc @ndcunningham @jaysoo -/packages/nest/** @nartc @ndcunningham @jaysoo -/e2e/node/** @nartc @ndcunningham @jaysoo +/docs/generated/packages/node/** @nrwl/nx-node-reviewers @nrwl/nx-docs-reviewers +/docs/generated/packages/nest/** @nrwl/nx-node-reviewers @nrwl/nx-docs-reviewers +/docs/generated/packages/express/** @nrwl/nx-node-reviewers @nrwl/nx-docs-reviewers +/docs/shared/packages/node/** @nrwl/nx-node-reviewers @nrwl/nx-docs-reviewers +/docs/shared/packages/express/** @nrwl/nx-node-reviewers @nrwl/nx-docs-reviewers +/docs/shared/packages/nest/** @nrwl/nx-node-reviewers @FrozenPandaz @nrwl/nx-docs-reviewers +/packages/node/** @nrwl/nx-node-reviewers +/packages/express/** @nrwl/nx-node-reviewers +/packages/nest/** @nrwl/nx-node-reviewers +/e2e/node/** @nrwl/nx-node-reviewers ## JS -/docs/generated/packages/js/** @nartc @jaysoo @ndcunningham -/docs/generated/packages/web/** @jaysoo @mandarini @ndcunningham -/docs/generated/packages/webpack/** @jaysoo @mandarini @ndcunningham -/docs/generated/packages/esbuild/** @nartc @jaysoo @ndcunningham -/docs/generated/packages/rollup/** @jaysoo @mandarini @ndcunningham -/docs/generated/packages/vite/** @jaysoo @mandarini @ndcunningham -/docs/shared/packages/js/** @nartc @jaysoo @ndcunningham -/docs/shared/packages/web/** @jaysoo @mandarini @ndcunningham -/docs/shared/packages/webpack/** @jaysoo @mandarini @ndcunningham -/docs/shared/packages/esbuild/** @nartc @jaysoo @ndcunningham -/docs/shared/packages/vite/** @jaysoo @mandarini @ndcunningham -/packages/js/** @nartc @jaysoo @ndcunningham -/e2e/js/** @nartc @jaysoo @ndcunningham -/packages/web/** @jaysoo @mandarini @ndcunningham -/e2e/web/** @jaysoo @mandarini @ndcunningham -/packages/webpack/** @jaysoo @mandarini @ndcunningham -/e2e/webpack/** @jaysoo @mandarini @ndcunningham -/packages/esbuild/** @jaysoo @nartc @ndcunningham -/e2e/esbuild/** @jaysoo @nartc @ndcunningham -/packages/rollup/** @jaysoo @mandarini @ndcunningham -/e2e/rollup/** @jaysoo @mandarini @ndcunningham -/packages/vite/** @jaysoo @mandarini @ndcunningham -/e2e/vite/** @jaysoo @mandarini @ndcunningham +/docs/generated/packages/js/** @nrwl/nx-js-reviewers @nrwl/nx-docs-reviewers +/docs/generated/packages/web/** @nrwl/nx-js-reviewers @nrwl/nx-docs-reviewers +/docs/generated/packages/webpack/** @nrwl/nx-js-reviewers @nrwl/nx-docs-reviewers +/docs/generated/packages/esbuild/** @nrwl/nx-js-reviewers @nrwl/nx-docs-reviewers +/docs/generated/packages/rollup/** @nrwl/nx-js-reviewers @nrwl/nx-docs-reviewers +/docs/generated/packages/vite/** @nrwl/nx-js-reviewers @nrwl/nx-docs-reviewers +/docs/shared/packages/js/** @nrwl/nx-js-reviewers @nrwl/nx-docs-reviewers +/docs/shared/packages/web/** @nrwl/nx-js-reviewers @nrwl/nx-docs-reviewers +/docs/shared/packages/webpack/** @nrwl/nx-js-reviewers @nrwl/nx-docs-reviewers +/docs/shared/packages/esbuild/** @nrwl/nx-js-reviewers @nrwl/nx-docs-reviewers +/docs/shared/packages/vite/** @nrwl/nx-js-reviewers @nrwl/nx-docs-reviewers +/packages/js/** @nrwl/nx-js-reviewers +/e2e/js/** @nrwl/nx-js-reviewers +/packages/web/** @nrwl/nx-js-reviewers +/e2e/web/** @nrwl/nx-js-reviewers +/packages/webpack/** @nrwl/nx-js-reviewers +/e2e/webpack/** @nrwl/nx-js-reviewers +/packages/esbuild/** @nrwl/nx-js-reviewers +/e2e/esbuild/** @nrwl/nx-js-reviewers +/packages/rollup/** @nrwl/nx-js-reviewers +/e2e/rollup/** @nrwl/nx-js-reviewers +/packages/vite/** @nrwl/nx-js-reviewers +/e2e/vite/** @nrwl/nx-js-reviewers ## Tools -/docs/generated/packages/cypress/** @barbados-clemens @FrozenPandaz -/docs/generated/packages/jest/** @barbados-clemens @FrozenPandaz -/docs/shared/packages/jest/** @barbados-clemens @FrozenPandaz @isaacplmann @juristr -/docs/shared/packages/cypress/** @barbados-clemens @FrozenPandaz @isaacplmann @juristr -/packages/cypress/** @barbados-clemens @FrozenPandaz -/e2e/cypress/** @barbados-clemens @FrozenPandaz -/packages/jest/** @barbados-clemens @FrozenPandaz -/e2e/jest/** @barbados-clemens @FrozenPandaz +/docs/generated/packages/cypress/** @nrwl/nx-testing-tools-reviewers @nrwl/nx-docs-reviewers +/docs/generated/packages/jest/** @nrwl/nx-testing-tools-reviewers @nrwl/nx-docs-reviewers +/docs/shared/packages/jest/** @nrwl/nx-testing-tools-reviewers @nrwl/nx-docs-reviewers +/docs/shared/packages/cypress/** @nrwl/nx-testing-tools-reviewers @nrwl/nx-docs-reviewers +/packages/cypress/** @nrwl/nx-testing-tools-reviewers +/e2e/cypress/** @nrwl/nx-testing-tools-reviewers +/packages/jest/** @nrwl/nx-testing-tools-reviewers +/e2e/jest/** @nrwl/nx-testing-tools-reviewers # Linter -/docs/generated/packages/eslint-plugin/** @meeroslav @FrozenPandaz @JamesHenry -/docs/generated/packages/linter/** @meeroslav @FrozenPandaz @JamesHenry -/docs/shared/packages/linter/** @meeroslav @FrozenPandaz @isaacplmann @juristr -/packages/eslint-plugin/** @meeroslav @FrozenPandaz @JamesHenry -/packages/linter/** @meeroslav @FrozenPandaz @JamesHenry -/e2e/linter/** @meeroslav @FrozenPandaz -.eslint* @meeroslav @FrozenPandaz @JamesHenry +/docs/generated/packages/eslint-plugin/** @nrwl/nx-linter-reviewers @nrwl/nx-docs-reviewers +/docs/generated/packages/linter/** @nrwl/nx-linter-reviewers @nrwl/nx-docs-reviewers +/docs/shared/packages/linter/** @nrwl/nx-linter-reviewers @nrwl/nx-docs-reviewers +/packages/eslint-plugin/** @nrwl/nx-linter-reviewers +/packages/linter/** @nrwl/nx-linter-reviewers +/e2e/linter/** @nrwl/nx-linter-reviewers +.eslint* @nrwl/nx-linter-reviewers # Storybook -/docs/generated/packages/storybook/** @mandarini @jaysoo @Coly010 -/docs/shared/packages/storybook/** @mandarini @jaysoo @Coly010 -/packages/storybook/** @mandarini @jaysoo @Coly010 -/e2e/storybook/** @mandarini @FrozenPandaz @Coly010 -/e2e/storybook-angular/** @mandarini @Coly010 +/docs/generated/packages/storybook/** @nrwl/nx-storybook-reviewers @nrwl/nx-docs-reviewers +/docs/shared/packages/storybook/** @nrwl/nx-storybook-reviewers @nrwl/nx-docs-reviewers +/packages/storybook/** @nrwl/nx-storybook-reviewers +/e2e/storybook/** @nrwl/nx-storybook-reviewers +/e2e/storybook-angular/** @nrwl/nx-storybook-reviewers ## Devkit -/docs/generated/devkit/** @FrozenPandaz @AgentEnder -/docs/generated/packages/devkit/** @FrozenPandaz @AgentEnder -/packages/devkit/** @FrozenPandaz @AgentEnder +/docs/generated/devkit/** @nrwl/nx-devkit-reviewers @nrwl/nx-docs-reviewers +/docs/generated/packages/devkit/** @nrwl/nx-devkit-reviewers @nrwl/nx-docs-reviewers +/packages/devkit/** @nrwl/nx-devkit-reviewers /packages/devkit/index.js @FrozenPandaz @vsavkin /packages/devkit/index.d.ts @FrozenPandaz @vsavkin /packages/devkit/public-api.ts @FrozenPandaz @vsavkin @@ -127,32 +127,32 @@ pnpm-lock.yaml @FrozenPandaz @vsavkin @AgentEnder @jaysoo @JamesHenry /packages/devkit/src/utils/module-federation @jaysoo @Coly010 # Nx-Plugin -/docs/generated/packages/plugin/** @AgentEnder @FrozenPandaz -/docs/shared/packages/plugin/** @AgentEnder @FrozenPandaz @isaacplmann @juristr -/packages/plugin/** @AgentEnder @FrozenPandaz -/e2e/plugin/** @AgentEnder @FrozenPandaz +/docs/generated/packages/plugin/** @nrwl/nx-devkit-reviewers @nrwl/nx-docs-reviewers +/docs/shared/packages/plugin/** @nrwl/nx-devkit-reviewers @nrwl/nx-docs-reviewers +/packages/plugin/** @nrwl/nx-devkit-reviewers +/e2e/plugin/** @nrwl/nx-devkit-reviewers ## Core -/docs/generated/cli/** @vsavkin @FrozenPandaz @AgentEnder -/docs/generated/packages/nx/** @vsavkin @FrozenPandaz @AgentEnder -/docs/generated/packages/workspace/** @vsavkin @FrozenPandaz @AgentEnder -/packages/nx/** @vsavkin @FrozenPandaz @AgentEnder -/packages/nx/src/adapter @AgentEnder @leosvelperez -/packages/nx/src/native @vsavkin @FrozenPandaz @Cammisuli -/packages/nx/src/plugins/js/lock-file @meeroslav @FrozenPandaz -/packages/nx/src/command-line/init/implementation/angular/** @Coly010 @leosvelperez @FrozenPandaz -/e2e/nx-init/src/nx-init-angular.test.ts @Coly010 @leosvelperez -/packages/nx/src/command-line/init/implementation/react/** @jaysoo @xiongemi @mandarini -/e2e/nx-init/src/nx-init-react.test.ts @jaysoo @xiongemi @mandarini @ndcunningham -/e2e/nx-init/src/files/cra/** @jaysoo @xiongemi @mandarini @ndcunningham -/e2e/nx*/** @FrozenPandaz @AgentEnder @vsavkin -/packages/workspace/** @FrozenPandaz @AgentEnder @vsavkin -/e2e/workspace-create/** @FrozenPandaz @AgentEnder @vsavkin -/e2e/workspace-create-npm/** @FrozenPandaz @vsavkin +/docs/generated/cli/** @nrwl/nx-core-reviewers @nrwl/nx-docs-reviewers +/docs/generated/packages/nx/** @nrwl/nx-core-reviewers @nrwl/nx-docs-reviewers +/docs/generated/packages/workspace/** @nrwl/nx-core-reviewers @nrwl/nx-docs-reviewers +/packages/nx/** @nrwl/nx-core-reviewers +/packages/nx/src/adapter @nrwl/nx-core-reviewers @leosvelperez +/packages/nx/src/native @nrwl/nx-core-reviewers @nrwl/nx-native-reviewers +/packages/nx/src/plugins/js/lock-file @nrwl/nx-core-reviewers @meeroslav +/packages/nx/src/command-line/init/implementation/angular/** @nrwl/nx-angular-reviewers @nrwl/nx-core-reviewers +/e2e/nx-init/src/nx-init-angular.test.ts @nrwl/nx-angular-reviewers +/packages/nx/src/command-line/init/implementation/react/** @nrwl/nx-react-reviewers +/e2e/nx-init/src/nx-init-react.test.ts @nrwl/nx-react-reviewers +/e2e/nx-init/src/files/cra/** @nrwl/nx-react-reviewers +/e2e/nx*/** @nrwl/nx-core-reviewers +/packages/workspace/** @nrwl/nx-core-reviewers +/e2e/workspace-create/** @nrwl/nx-core-reviewers +/e2e/workspace-create-npm/** @nrwl/nx-core-reviewers # Misc /e2e/lerna-smoke-tests/** @vsavkin @JamesHenry -/e2e/utils/** @meeroslav @barbados-clemens @vsavkin @mandarini +/e2e/utils/** @meeroslav @nrwl/nx-testing-tools-reviewers @vsavkin @mandarini /community @AgentEnder @FrozenPandaz /CONTRIBUTING.md @FrozenPandaz @isaacplmann /CODE_OF_CONDUCT.md @FrozenPandaz @isaacplmann @@ -160,9 +160,9 @@ pnpm-lock.yaml @FrozenPandaz @vsavkin @AgentEnder @jaysoo @JamesHenry # Scripts /scripts/depcheck @FrozenPandaz @vsavkin @jaysoo -/scripts/documentation @bcabanes @isaacplmann +/scripts/documentation @nrwl/nx-docs-reviewers /scripts/local-registry @FrozenPandaz @vsavkin -/scripts/angular-support-upgrades @Coly010 @leosvelperez +/scripts/angular-support-upgrades @nrwl/nx-angular-reviewers # CI /.circleci/** @meeroslav @vsavkin @FrozenPandaz @@ -172,9 +172,9 @@ pnpm-lock.yaml @FrozenPandaz @vsavkin @AgentEnder @jaysoo @JamesHenry # Global Files project.json @FrozenPandaz @vsavkin -jest.config.ts @barbados-clemens @FrozenPandaz -jest.preset.js @barbados-clemens @FrozenPandaz +jest.config.ts @nrwl/nx-testing-tools-reviewers @FrozenPandaz +jest.preset.js @nrwl/nx-testing-tools-reviewers @FrozenPandaz # Overrides - These are applied last, so override any matches above. -docs/generated/manifests/* @bcabanes @FrozenPandaz @jaysoo @AgentEnder @isaacplmann @juristr -docs/generated/packages-metadata.json @bcabanes @FrozenPandaz @jaysoo @AgentEnder @isaacplmann @juristr +docs/generated/manifests/* @FrozenPandaz @jaysoo @AgentEnder @nrwl/nx-docs-reviewers +docs/generated/packages-metadata.json @FrozenPandaz @jaysoo @AgentEnder @nrwl/nx-docs-reviewers diff --git a/scripts/check-codeowners.ts b/scripts/check-codeowners.ts index 73c16d6549..023b9829aa 100644 --- a/scripts/check-codeowners.ts +++ b/scripts/check-codeowners.ts @@ -1,7 +1,9 @@ import * as fg from 'fast-glob'; import * as path from 'path'; import * as fs from 'fs'; +import * as octokit from 'octokit'; import { output } from '@nx/devkit'; +import { Octokit } from 'octokit'; async function main() { const codeowners = fs.readFileSync( @@ -12,13 +14,19 @@ async function main() { .split('\n') .filter((line) => line.trim().length > 0 && !line.startsWith('#')); - const errors: string[] = []; + const mismatchedPatterns: string[] = []; + const mismatchedOwners: string[] = []; + + const gh = new octokit.Octokit({ + auth: process.env.GITHUB_TOKEN, + }).rest; + const cache: Map = new Map(); for (const line of codeownersLines) { // This is perhaps a bit naive, but it should // work for all paths and patterns that do not // contain spaces. - const specifiedPattern = line.split(' ')[0]; + const [specifiedPattern, ...owners] = line.split(' '); let foundMatchingFiles = false; const patternsToCheck = specifiedPattern.startsWith('/') @@ -34,16 +42,85 @@ async function main() { }).length > 0; } if (!foundMatchingFiles) { - errors.push(specifiedPattern); + mismatchedPatterns.push(specifiedPattern); + } + + if (process.env.GITHUB_TOKEN) { + for (let owner of owners) { + owner = owner.substring(1); // Remove the @ + if (owner.includes('/')) { + // Its a team. + const [org, team] = owner.split('/'); + let res = cache.get(owner); + if (res === undefined) { + res = await validateTeam(gh, org, team); + cache.set(owner, res); + } + if (res === false) { + mismatchedOwners.push(`${specifiedPattern}: ${owner}`); + } + } else { + let res = cache.get(owner); + if (res === undefined) { + res = await validateUser(gh, owner); + cache.set(owner, res); + } + if (res === false) { + mismatchedOwners.push(`${specifiedPattern}: ${owner}`); + } + } + } + } else { + output.warn({ + title: `Skipping owner validation because GITHUB_TOKEN is not set.`, + }); } } - if (errors.length > 0) { + if (mismatchedPatterns.length > 0) { output.error({ title: `The following patterns in CODEOWNERS do not match any files:`, - bodyLines: errors.map((e) => `- ${e}`), + bodyLines: mismatchedPatterns.map((e) => `- ${e}`), }); - process.exit(1); } + + if (mismatchedOwners.length > 0) { + output.error({ + title: `The following owners in CODEOWNERS do not exist:`, + bodyLines: mismatchedOwners.map((e) => `- ${e}`), + }); + } + + process.exit(mismatchedPatterns.length + mismatchedOwners.length > 0 ? 1 : 0); } main(); + +async function validateTeam( + gh: Octokit['rest'], + org: string, + team: string +): Promise { + try { + await gh.teams.getByName({ + org, + team_slug: team, + }); + return true; + } catch { + return false; + } +} + +async function validateUser( + gh: Octokit['rest'], + username: string +): Promise { + try { + await gh.users.getByUsername({ + username, + }); + return true; + } catch { + return false; + } +}