From 614fe3ca560d0f0909299b0fa43d728e65f2af2e Mon Sep 17 00:00:00 2001 From: Dan Adajian Date: Mon, 31 Jul 2023 13:29:29 -0500 Subject: [PATCH] fix(approvals-satisfied): add logging (#400) --- dist/499.index.js | 14 ++++++++++---- dist/499.index.js.map | 2 +- src/helpers/approvals-satisfied.ts | 5 +++++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/dist/499.index.js b/dist/499.index.js index 5869d76b4..871920339 100644 --- a/dist/499.index.js +++ b/dist/499.index.js @@ -11,14 +11,16 @@ __webpack_require__.r(__webpack_exports__); /* harmony export */ "ApprovalsSatisfied": () => (/* binding */ ApprovalsSatisfied), /* harmony export */ "approvalsSatisfied": () => (/* binding */ approvalsSatisfied) /* harmony export */ }); -/* harmony import */ var _types_generated__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(3476); +/* harmony import */ var _types_generated__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(3476); /* harmony import */ var _actions_github__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5438); /* harmony import */ var _actions_github__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_actions_github__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _octokit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6161); /* harmony import */ var _utils_get_core_member_logins__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(7290); /* harmony import */ var bluebird__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(8710); /* harmony import */ var bluebird__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(bluebird__WEBPACK_IMPORTED_MODULE_3__); -/* harmony import */ var _utils_convert_to_team_slug__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(489); +/* harmony import */ var _utils_convert_to_team_slug__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(489); +/* harmony import */ var _actions_core__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(2186); +/* harmony import */ var _actions_core__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_actions_core__WEBPACK_IMPORTED_MODULE_4__); /* Copyright 2021 Expedia, Inc. Licensed under the Apache License, Version 2.0 (the "License"); @@ -46,7 +48,8 @@ var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _argume -class ApprovalsSatisfied extends _types_generated__WEBPACK_IMPORTED_MODULE_4__/* .HelperInputs */ .s { + +class ApprovalsSatisfied extends _types_generated__WEBPACK_IMPORTED_MODULE_5__/* .HelperInputs */ .s { } const approvalsSatisfied = ({ teams, number_of_reviewers = '1', pull_number } = {}) => __awaiter(void 0, void 0, void 0, function* () { const prNumber = pull_number ? Number(pull_number) : _actions_github__WEBPACK_IMPORTED_MODULE_0__.context.issue.number; @@ -61,7 +64,7 @@ const approvalsSatisfied = ({ teams, number_of_reviewers = '1', pull_number } = const teamsAndLoginsLists = yield (0,bluebird__WEBPACK_IMPORTED_MODULE_3__.map)(entry.owners, (team) => __awaiter(void 0, void 0, void 0, function* () { const { data } = yield _octokit__WEBPACK_IMPORTED_MODULE_1__/* .octokit.teams.listMembersInOrg */ .K.teams.listMembersInOrg({ org: _actions_github__WEBPACK_IMPORTED_MODULE_0__.context.repo.owner, - team_slug: (0,_utils_convert_to_team_slug__WEBPACK_IMPORTED_MODULE_5__/* .convertToTeamSlug */ .$)(team), + team_slug: (0,_utils_convert_to_team_slug__WEBPACK_IMPORTED_MODULE_6__/* .convertToTeamSlug */ .$)(team), per_page: 100 }); return data.map(({ login }) => ({ team, login })); @@ -70,6 +73,9 @@ const approvalsSatisfied = ({ teams, number_of_reviewers = '1', pull_number } = const numberOfCollectiveApprovalsAcrossTeams = approverLogins.filter(login => codeOwnerLogins.includes(login)).length; const numberOfApprovalsForSingleTeam = codeOwnerLogins.filter(login => approverLogins.includes(login)).length; const numberOfApprovals = entry.owners.length > 1 ? numberOfCollectiveApprovalsAcrossTeams : numberOfApprovalsForSingleTeam; + _actions_core__WEBPACK_IMPORTED_MODULE_4__.info(`Required code owners: ${requiredCodeOwnersEntries.map(({ owners }) => owners).toString()}`); + _actions_core__WEBPACK_IMPORTED_MODULE_4__.info(`PR already approved by: ${approverLogins.toString()}`); + _actions_core__WEBPACK_IMPORTED_MODULE_4__.info(`Current number of approvals: ${numberOfApprovals}`); return numberOfApprovals >= Number(number_of_reviewers); }); const booleans = yield Promise.all(requiredCodeOwnersEntries.map(codeOwnersEntrySatisfiesApprovals)); diff --git a/dist/499.index.js.map b/dist/499.index.js.map index 093786b8d..6a2db7830 100644 --- a/dist/499.index.js.map +++ b/dist/499.index.js.map @@ -1 +1 @@ -{"version":3,"file":"499.index.js","mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;AAWA;;;;;;;;;;AAEA;AACA;AACA;AACA;AACA;AACA;AAGA;AAIA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;AC3DA;;;;;;;;;;;AAWA;AAEA;AACA;AACA;AAEA;AACA;;;;;;;;;;;AClBA;;;;;;;;;;;AAWA;AAEA;AA0CA;;;;;;;;;;;ACvDA;;;;;;;;;;;AAWA;AAEA;;;;;;;;;;;;;;ACbA;;;;;;;;;;;AAWA;;;;;;;;;;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAMA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;AClCA;;;;;;;;;;;AAWA;;;;;;;;;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA","sources":["webpack://github-helpers/./src/helpers/approvals-satisfied.ts","webpack://github-helpers/./src/octokit.ts","webpack://github-helpers/./src/types/generated.ts","webpack://github-helpers/./src/utils/convert-to-team-slug.ts","webpack://github-helpers/./src/utils/get-changed-filepaths.ts","webpack://github-helpers/./src/utils/get-core-member-logins.ts"],"sourcesContent":["/*\nCopyright 2021 Expedia, Inc.\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n https://www.apache.org/licenses/LICENSE-2.0\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport { HelperInputs } from '../types/generated';\nimport { context } from '@actions/github';\nimport { octokit } from '../octokit';\nimport { getRequiredCodeOwnersEntries } from '../utils/get-core-member-logins';\nimport { map } from 'bluebird';\nimport { convertToTeamSlug } from '../utils/convert-to-team-slug';\nimport { CodeOwnersEntry } from 'codeowners-utils';\n\nexport class ApprovalsSatisfied extends HelperInputs {\n teams?: string;\n number_of_reviewers?: string;\n pull_number?: string;\n}\n\nexport const approvalsSatisfied = async ({ teams, number_of_reviewers = '1', pull_number }: ApprovalsSatisfied = {}) => {\n const prNumber = pull_number ? Number(pull_number) : context.issue.number;\n const { data: reviews } = await octokit.pulls.listReviews({ pull_number: prNumber, ...context.repo });\n const approverLogins = reviews\n .filter(({ state }) => state === 'APPROVED')\n .map(({ user }) => user?.login)\n .filter(Boolean);\n const teamsList = teams?.split('\\n');\n const requiredCodeOwnersEntries = teamsList ? createArtificialCodeOwnersEntry(teamsList) : await getRequiredCodeOwnersEntries(prNumber);\n\n const codeOwnersEntrySatisfiesApprovals = async (entry: Pick) => {\n const teamsAndLoginsLists = await map(entry.owners, async team => {\n const { data } = await octokit.teams.listMembersInOrg({\n org: context.repo.owner,\n team_slug: convertToTeamSlug(team),\n per_page: 100\n });\n return data.map(({ login }) => ({ team, login }));\n });\n const codeOwnerLogins = teamsAndLoginsLists.flat().map(({ login }) => login);\n\n const numberOfCollectiveApprovalsAcrossTeams = approverLogins.filter(login => codeOwnerLogins.includes(login)).length;\n const numberOfApprovalsForSingleTeam = codeOwnerLogins.filter(login => approverLogins.includes(login)).length;\n const numberOfApprovals = entry.owners.length > 1 ? numberOfCollectiveApprovalsAcrossTeams : numberOfApprovalsForSingleTeam;\n\n return numberOfApprovals >= Number(number_of_reviewers);\n };\n\n const booleans = await Promise.all(requiredCodeOwnersEntries.map(codeOwnersEntrySatisfiesApprovals));\n return booleans.every(Boolean);\n};\n\nconst createArtificialCodeOwnersEntry = (teams: string[]) => teams.map(team => ({ owners: [team] }));\n","/*\nCopyright 2021 Expedia, Inc.\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n https://www.apache.org/licenses/LICENSE-2.0\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport * as core from '@actions/core';\nimport * as fetch from '@adobe/node-fetch-retry';\nimport { getOctokit } from '@actions/github';\n\nconst githubToken = core.getInput('github_token', { required: true });\nexport const { rest: octokit, graphql: octokitGraphql } = getOctokit(githubToken, { request: { fetch } });\n","/*\nCopyright 2021 Expedia, Inc.\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n https://www.apache.org/licenses/LICENSE-2.0\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nexport class HelperInputs {\n helper?: string;\n github_token?: string;\n body?: string;\n project_name?: string;\n project_destination_column_name?: string;\n note?: string;\n project_origin_column_name?: string;\n sha?: string;\n context?: string;\n state?: string;\n description?: string;\n target_url?: string;\n environment?: string;\n environment_url?: string;\n label?: string;\n labels?: string;\n paths?: string;\n ignore_globs?: string;\n extensions?: string;\n override_filter_paths?: string;\n batches?: string;\n pattern?: string;\n teams?: string;\n login?: string;\n paths_no_filter?: string;\n slack_webhook_url?: string;\n number_of_assignees?: string;\n number_of_reviewers?: string;\n globs?: string;\n override_filter_globs?: string;\n title?: string;\n seconds?: string;\n pull_number?: string;\n base?: string;\n head?: string;\n days?: string;\n no_evict_upon_conflict?: string;\n skip_if_already_set?: string;\n delimiter?: string;\n team?: string;\n ignore_deleted?: string;\n}\n","/*\nCopyright 2021 Expedia, Inc.\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n https://www.apache.org/licenses/LICENSE-2.0\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nexport const convertToTeamSlug = (codeOwner: string) => codeOwner.substring(codeOwner.indexOf('/') + 1);\n","/*\nCopyright 2021 Expedia, Inc.\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n https://www.apache.org/licenses/LICENSE-2.0\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport { ChangedFilesList } from '../types/github';\nimport { context } from '@actions/github';\nimport { octokit } from '../octokit';\n\nexport const getChangedFilepaths = async (pull_number: number, ignore_deleted?: boolean) => {\n const changedFiles = await paginateAllChangedFilepaths(pull_number);\n const filesToMap = ignore_deleted ? changedFiles.filter(file => file.status !== 'removed') : changedFiles;\n return filesToMap.map(file => file.filename);\n};\n\nconst paginateAllChangedFilepaths = async (pull_number: number, page = 1): Promise => {\n const response = await octokit.pulls.listFiles({\n pull_number,\n per_page: 100,\n page,\n ...context.repo\n });\n if (!response.data.length) {\n return [];\n }\n return response.data.concat(await paginateAllChangedFilepaths(pull_number, page + 1));\n};\n","/*\nCopyright 2021 Expedia, Inc.\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n https://www.apache.org/licenses/LICENSE-2.0\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport * as core from '@actions/core';\nimport { CodeOwnersEntry, loadOwners, matchFile } from 'codeowners-utils';\nimport { uniq, union } from 'lodash';\nimport { context } from '@actions/github';\nimport { getChangedFilepaths } from './get-changed-filepaths';\nimport { map } from 'bluebird';\nimport { octokit } from '../octokit';\nimport { convertToTeamSlug } from './convert-to-team-slug';\n\nexport const getCoreMemberLogins = async (pull_number: number, teams?: string[]) => {\n const codeOwners = teams ?? getCodeOwnersFromEntries(await getRequiredCodeOwnersEntries(pull_number));\n const teamsAndLogins = await getCoreTeamsAndLogins(codeOwners);\n return uniq(teamsAndLogins.map(({ login }) => login));\n};\n\nexport const getRequiredCodeOwnersEntries = async (pull_number: number): Promise => {\n const codeOwners = (await loadOwners(process.cwd())) ?? [];\n const changedFilePaths = await getChangedFilepaths(pull_number);\n return changedFilePaths.map(filePath => matchFile(filePath, codeOwners)).filter(Boolean);\n};\n\nconst getCoreTeamsAndLogins = async (codeOwners?: string[]) => {\n if (!codeOwners?.length) {\n core.setFailed('No code owners found. Please provide a \"teams\" input or set up a CODEOWNERS file in your repo.');\n throw new Error();\n }\n\n const teamsAndLogins = await map(codeOwners, async team =>\n octokit.teams\n .listMembersInOrg({\n org: context.repo.owner,\n team_slug: team,\n per_page: 100\n })\n .then(listMembersResponse => listMembersResponse.data.map(({ login }) => ({ team, login })))\n );\n return union(...teamsAndLogins);\n};\n\nconst getCodeOwnersFromEntries = (codeOwnersEntries: CodeOwnersEntry[]) => {\n return uniq(\n codeOwnersEntries\n .map(entry => entry.owners)\n .flat()\n .filter(Boolean)\n .map(codeOwner => convertToTeamSlug(codeOwner))\n );\n};\n"],"names":[],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"499.index.js","mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;AAWA;;;;;;;;;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAIA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;AChEA;;;;;;;;;;;AAWA;AAEA;AACA;AACA;AAEA;AACA;;;;;;;;;;;AClBA;;;;;;;;;;;AAWA;AAEA;AA0CA;;;;;;;;;;;ACvDA;;;;;;;;;;;AAWA;AAEA;;;;;;;;;;;;;;ACbA;;;;;;;;;;;AAWA;;;;;;;;;;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAMA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;AClCA;;;;;;;;;;;AAWA;;;;;;;;;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA","sources":["webpack://github-helpers/./src/helpers/approvals-satisfied.ts","webpack://github-helpers/./src/octokit.ts","webpack://github-helpers/./src/types/generated.ts","webpack://github-helpers/./src/utils/convert-to-team-slug.ts","webpack://github-helpers/./src/utils/get-changed-filepaths.ts","webpack://github-helpers/./src/utils/get-core-member-logins.ts"],"sourcesContent":["/*\nCopyright 2021 Expedia, Inc.\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n https://www.apache.org/licenses/LICENSE-2.0\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport { HelperInputs } from '../types/generated';\nimport { context } from '@actions/github';\nimport { octokit } from '../octokit';\nimport { getRequiredCodeOwnersEntries } from '../utils/get-core-member-logins';\nimport { map } from 'bluebird';\nimport { convertToTeamSlug } from '../utils/convert-to-team-slug';\nimport { CodeOwnersEntry } from 'codeowners-utils';\nimport * as core from '@actions/core';\n\nexport class ApprovalsSatisfied extends HelperInputs {\n teams?: string;\n number_of_reviewers?: string;\n pull_number?: string;\n}\n\nexport const approvalsSatisfied = async ({ teams, number_of_reviewers = '1', pull_number }: ApprovalsSatisfied = {}) => {\n const prNumber = pull_number ? Number(pull_number) : context.issue.number;\n const { data: reviews } = await octokit.pulls.listReviews({ pull_number: prNumber, ...context.repo });\n const approverLogins = reviews\n .filter(({ state }) => state === 'APPROVED')\n .map(({ user }) => user?.login)\n .filter(Boolean);\n const teamsList = teams?.split('\\n');\n const requiredCodeOwnersEntries = teamsList ? createArtificialCodeOwnersEntry(teamsList) : await getRequiredCodeOwnersEntries(prNumber);\n\n const codeOwnersEntrySatisfiesApprovals = async (entry: Pick) => {\n const teamsAndLoginsLists = await map(entry.owners, async team => {\n const { data } = await octokit.teams.listMembersInOrg({\n org: context.repo.owner,\n team_slug: convertToTeamSlug(team),\n per_page: 100\n });\n return data.map(({ login }) => ({ team, login }));\n });\n const codeOwnerLogins = teamsAndLoginsLists.flat().map(({ login }) => login);\n\n const numberOfCollectiveApprovalsAcrossTeams = approverLogins.filter(login => codeOwnerLogins.includes(login)).length;\n const numberOfApprovalsForSingleTeam = codeOwnerLogins.filter(login => approverLogins.includes(login)).length;\n const numberOfApprovals = entry.owners.length > 1 ? numberOfCollectiveApprovalsAcrossTeams : numberOfApprovalsForSingleTeam;\n\n core.info(`Required code owners: ${requiredCodeOwnersEntries.map(({ owners }) => owners).toString()}`);\n core.info(`PR already approved by: ${approverLogins.toString()}`);\n core.info(`Current number of approvals: ${numberOfApprovals}`);\n\n return numberOfApprovals >= Number(number_of_reviewers);\n };\n\n const booleans = await Promise.all(requiredCodeOwnersEntries.map(codeOwnersEntrySatisfiesApprovals));\n return booleans.every(Boolean);\n};\n\nconst createArtificialCodeOwnersEntry = (teams: string[]) => teams.map(team => ({ owners: [team] }));\n","/*\nCopyright 2021 Expedia, Inc.\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n https://www.apache.org/licenses/LICENSE-2.0\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport * as core from '@actions/core';\nimport * as fetch from '@adobe/node-fetch-retry';\nimport { getOctokit } from '@actions/github';\n\nconst githubToken = core.getInput('github_token', { required: true });\nexport const { rest: octokit, graphql: octokitGraphql } = getOctokit(githubToken, { request: { fetch } });\n","/*\nCopyright 2021 Expedia, Inc.\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n https://www.apache.org/licenses/LICENSE-2.0\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nexport class HelperInputs {\n helper?: string;\n github_token?: string;\n body?: string;\n project_name?: string;\n project_destination_column_name?: string;\n note?: string;\n project_origin_column_name?: string;\n sha?: string;\n context?: string;\n state?: string;\n description?: string;\n target_url?: string;\n environment?: string;\n environment_url?: string;\n label?: string;\n labels?: string;\n paths?: string;\n ignore_globs?: string;\n extensions?: string;\n override_filter_paths?: string;\n batches?: string;\n pattern?: string;\n teams?: string;\n login?: string;\n paths_no_filter?: string;\n slack_webhook_url?: string;\n number_of_assignees?: string;\n number_of_reviewers?: string;\n globs?: string;\n override_filter_globs?: string;\n title?: string;\n seconds?: string;\n pull_number?: string;\n base?: string;\n head?: string;\n days?: string;\n no_evict_upon_conflict?: string;\n skip_if_already_set?: string;\n delimiter?: string;\n team?: string;\n ignore_deleted?: string;\n}\n","/*\nCopyright 2021 Expedia, Inc.\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n https://www.apache.org/licenses/LICENSE-2.0\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nexport const convertToTeamSlug = (codeOwner: string) => codeOwner.substring(codeOwner.indexOf('/') + 1);\n","/*\nCopyright 2021 Expedia, Inc.\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n https://www.apache.org/licenses/LICENSE-2.0\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport { ChangedFilesList } from '../types/github';\nimport { context } from '@actions/github';\nimport { octokit } from '../octokit';\n\nexport const getChangedFilepaths = async (pull_number: number, ignore_deleted?: boolean) => {\n const changedFiles = await paginateAllChangedFilepaths(pull_number);\n const filesToMap = ignore_deleted ? changedFiles.filter(file => file.status !== 'removed') : changedFiles;\n return filesToMap.map(file => file.filename);\n};\n\nconst paginateAllChangedFilepaths = async (pull_number: number, page = 1): Promise => {\n const response = await octokit.pulls.listFiles({\n pull_number,\n per_page: 100,\n page,\n ...context.repo\n });\n if (!response.data.length) {\n return [];\n }\n return response.data.concat(await paginateAllChangedFilepaths(pull_number, page + 1));\n};\n","/*\nCopyright 2021 Expedia, Inc.\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n https://www.apache.org/licenses/LICENSE-2.0\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport * as core from '@actions/core';\nimport { CodeOwnersEntry, loadOwners, matchFile } from 'codeowners-utils';\nimport { uniq, union } from 'lodash';\nimport { context } from '@actions/github';\nimport { getChangedFilepaths } from './get-changed-filepaths';\nimport { map } from 'bluebird';\nimport { octokit } from '../octokit';\nimport { convertToTeamSlug } from './convert-to-team-slug';\n\nexport const getCoreMemberLogins = async (pull_number: number, teams?: string[]) => {\n const codeOwners = teams ?? getCodeOwnersFromEntries(await getRequiredCodeOwnersEntries(pull_number));\n const teamsAndLogins = await getCoreTeamsAndLogins(codeOwners);\n return uniq(teamsAndLogins.map(({ login }) => login));\n};\n\nexport const getRequiredCodeOwnersEntries = async (pull_number: number): Promise => {\n const codeOwners = (await loadOwners(process.cwd())) ?? [];\n const changedFilePaths = await getChangedFilepaths(pull_number);\n return changedFilePaths.map(filePath => matchFile(filePath, codeOwners)).filter(Boolean);\n};\n\nconst getCoreTeamsAndLogins = async (codeOwners?: string[]) => {\n if (!codeOwners?.length) {\n core.setFailed('No code owners found. Please provide a \"teams\" input or set up a CODEOWNERS file in your repo.');\n throw new Error();\n }\n\n const teamsAndLogins = await map(codeOwners, async team =>\n octokit.teams\n .listMembersInOrg({\n org: context.repo.owner,\n team_slug: team,\n per_page: 100\n })\n .then(listMembersResponse => listMembersResponse.data.map(({ login }) => ({ team, login })))\n );\n return union(...teamsAndLogins);\n};\n\nconst getCodeOwnersFromEntries = (codeOwnersEntries: CodeOwnersEntry[]) => {\n return uniq(\n codeOwnersEntries\n .map(entry => entry.owners)\n .flat()\n .filter(Boolean)\n .map(codeOwner => convertToTeamSlug(codeOwner))\n );\n};\n"],"names":[],"sourceRoot":""} \ No newline at end of file diff --git a/src/helpers/approvals-satisfied.ts b/src/helpers/approvals-satisfied.ts index c6ef6d6af..d1382d7ef 100644 --- a/src/helpers/approvals-satisfied.ts +++ b/src/helpers/approvals-satisfied.ts @@ -18,6 +18,7 @@ import { getRequiredCodeOwnersEntries } from '../utils/get-core-member-logins'; import { map } from 'bluebird'; import { convertToTeamSlug } from '../utils/convert-to-team-slug'; import { CodeOwnersEntry } from 'codeowners-utils'; +import * as core from '@actions/core'; export class ApprovalsSatisfied extends HelperInputs { teams?: string; @@ -50,6 +51,10 @@ export const approvalsSatisfied = async ({ teams, number_of_reviewers = '1', pul const numberOfApprovalsForSingleTeam = codeOwnerLogins.filter(login => approverLogins.includes(login)).length; const numberOfApprovals = entry.owners.length > 1 ? numberOfCollectiveApprovalsAcrossTeams : numberOfApprovalsForSingleTeam; + core.info(`Required code owners: ${requiredCodeOwnersEntries.map(({ owners }) => owners).toString()}`); + core.info(`PR already approved by: ${approverLogins.toString()}`); + core.info(`Current number of approvals: ${numberOfApprovals}`); + return numberOfApprovals >= Number(number_of_reviewers); };