From 48b1b68a702fa3b86582e70b9aec2cbf62880096 Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Tue, 18 Feb 2025 12:46:34 -0330 Subject: [PATCH] ci: Add CODEOWNER constraints (#5352) ## Explanation Add Yarn constraints to ensure each package has a designated owner, and that any non-wallet-frameowrk packages have the wallet framework team set as co-owners of release related files. ## References N/A ## Changelog N/A ## Checklist - [x] I've updated the test suite for new or updated code as appropriate - [x] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate - [x] I've highlighted breaking changes using the "BREAKING" category above as appropriate - [x] I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes --- yarn.config.cjs | 61 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/yarn.config.cjs b/yarn.config.cjs index 9d6fe4526f7..946a5ce0a3c 100644 --- a/yarn.config.cjs +++ b/yarn.config.cjs @@ -247,6 +247,8 @@ module.exports = defineConfig({ if (isChildWorkspace) { // All non-root packages must have a valid README.md file. await expectReadme(workspace, workspaceBasename); + + await expectCodeowner(workspace, workspaceBasename); } } @@ -835,3 +837,62 @@ async function expectReadme(workspace, workspaceBasename) { ); } } + +// A promise resolving to the codeowners file contents +let cachedCodeownersFile; + +/** + * Expect that the workspace has a codeowner set, and that the CHANGELOG.md and + * package.json files are co-owned with the wallet framework team. + * + * @param {Workspace} workspace - The workspace to check. + * @param {string} workspaceBasename - The name of the workspace. + * @returns {Promise} + */ +async function expectCodeowner(workspace, workspaceBasename) { + if (!cachedCodeownersFile) { + cachedCodeownersFile = readFile( + resolve(__dirname, '.github', 'CODEOWNERS'), + 'utf8', + ); + } + const codeownersFile = await cachedCodeownersFile; + const codeownerRules = codeownersFile.split('\n'); + + const packageCodeownerRule = codeownerRules.find((rule) => + // Matcher includes intentional trailing space to ensure there is a package-wide rule, not + // just a rule for specific files/directories in the package. + rule.startsWith(`/packages/${workspaceBasename} `), + ); + + if (!packageCodeownerRule) { + workspace.error('Missing CODEOWNER rule for package'); + return; + } + + if (!packageCodeownerRule.includes('@MetaMask/wallet-framework-engineers')) { + if ( + !codeownerRules.some( + (rule) => + rule.startsWith(`/packages/${workspaceBasename}/CHANGELOG.md`) && + rule.includes('@MetaMask/wallet-framework-engineers'), + ) + ) { + workspace.error( + 'Missing CODEOWNER rule for CHANGELOG.md co-ownership with wallet framework team', + ); + } + + if ( + !codeownerRules.some( + (rule) => + rule.startsWith(`/packages/${workspaceBasename}/package.json`) && + rule.includes('@MetaMask/wallet-framework-engineers'), + ) + ) { + workspace.error( + 'Missing CODEOWNER rule for package.json co-ownership with wallet framework team', + ); + } + } +}