diff --git a/dist/index.js b/dist/index.js index 192a953..74065fe 100644 --- a/dist/index.js +++ b/dist/index.js @@ -10031,149 +10031,152 @@ function wrappy (fn, cb) { /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; - -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.approve = void 0; -const core = __importStar(__nccwpck_require__(2186)); -const github = __importStar(__nccwpck_require__(5438)); -const request_error_1 = __nccwpck_require__(537); -function approve(token, context, prNumber, reviewMessage) { - var _a, _b; - return __awaiter(this, void 0, void 0, function* () { - if (!prNumber) { - prNumber = (_a = context.payload.pull_request) === null || _a === void 0 ? void 0 : _a.number; - } - if (!prNumber) { - core.setFailed("Event payload missing `pull_request` key, and no `pull-request-number` provided as input." + - "Make sure you're triggering this action on the `pull_request` or `pull_request_target` events."); - return; - } - const client = github.getOctokit(token); - try { - core.info(`Getting current user info`); - const login = yield getLoginForToken(client); - core.info(`Current user is ${login}`); - core.info(`Getting pull request #${prNumber} info`); - const pull_request = yield client.rest.pulls.get({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: prNumber, - }); - const commit = pull_request.data.head.sha; - core.info(`Commit SHA is ${commit}`); - core.info(`Getting reviews for pull request #${prNumber} and commit ${commit}`); - const reviews = yield client.rest.pulls.listReviews({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: prNumber, - }); - for (const review of reviews.data) { - if (((_b = review.user) === null || _b === void 0 ? void 0 : _b.login) == login && - review.commit_id == commit && - review.state == "APPROVED") { - core.info(`Current user already approved pull request #${prNumber}, nothing to do`); - return; - } - } - core.info(`Pull request #${prNumber} has not been approved yet, creating approving review`); - yield client.rest.pulls.createReview({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: prNumber, - body: reviewMessage, - event: "APPROVE", - }); - core.info(`Approved pull request #${prNumber}`); - } - catch (error) { - if (error instanceof request_error_1.RequestError) { - switch (error.status) { - case 401: - core.setFailed(`${error.message}. Please check that the \`github-token\` input ` + - "parameter is set correctly."); - break; - case 403: - core.setFailed(`${error.message}. In some cases, the GitHub token used for actions triggered ` + - "from `pull_request` events are read-only, which can cause this problem. " + - "Switching to the `pull_request_target` event typically resolves this issue."); - break; - case 404: - core.setFailed(`${error.message}. This typically means the token you're using doesn't have ` + - "access to this repository. Use the built-in `${{ secrets.GITHUB_TOKEN }}` token " + - "or review the scopes assigned to your personal access token."); - break; - case 422: - core.setFailed(`${error.message}. This typically happens when you try to approve the pull ` + - "request with the same user account that created the pull request. Try using " + - "the built-in `${{ secrets.GITHUB_TOKEN }}` token, or if you're using a personal " + - "access token, use one that belongs to a dedicated bot account."); - break; - default: - core.setFailed(`Error (code ${error.status}): ${error.message}`); - } - return; - } - if (error instanceof Error) { - core.setFailed(error); - } - else { - core.setFailed("Unknown error"); - } - return; - } - }); -} -exports.approve = approve; -function getLoginForToken(client) { - return __awaiter(this, void 0, void 0, function* () { - try { - const { data: user } = yield client.rest.users.getAuthenticated(); - return user.login; - } - catch (error) { - if (error instanceof request_error_1.RequestError) { - // If you use the GITHUB_TOKEN provided by GitHub Actions to fetch the current user - // you get a 403. For now we'll assume any 403 means this is an Actions token. - if (error.status === 403) { - return "github-actions[bot]"; - } - } - throw error; - } - }); -} + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.approve = void 0; +const core = __importStar(__nccwpck_require__(2186)); +const github = __importStar(__nccwpck_require__(5438)); +const request_error_1 = __nccwpck_require__(537); +function approve(token, context, prNumber, reviewMessage) { + var _a, _b; + return __awaiter(this, void 0, void 0, function* () { + if (!prNumber) { + prNumber = (_a = context.payload.pull_request) === null || _a === void 0 ? void 0 : _a.number; + } + if (!prNumber) { + core.setFailed("Event payload missing `pull_request` key, and no `pull-request-number` provided as input." + + "Make sure you're triggering this action on the `pull_request` or `pull_request_target` events."); + return; + } + const client = github.getOctokit(token); + try { + core.info(`Getting current user info`); + const login = yield getLoginForToken(client); + core.info(`Current user is ${login}`); + core.info(`Getting pull request #${prNumber} info`); + const pull_request = yield client.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: prNumber, + }); + const commit = pull_request.data.head.sha; + core.info(`Commit SHA is ${commit}`); + core.info(`Getting reviews for pull request #${prNumber} and commit ${commit}`); + const reviews = yield client.rest.pulls.listReviews({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: prNumber, + }); + for (const review of reviews.data) { + if (((_b = review.user) === null || _b === void 0 ? void 0 : _b.login) == login && + review.commit_id == commit && + review.state == "APPROVED" && + ((pull_request.data.requested_reviewers != undefined && + pull_request.data.requested_reviewers.filter(reviewer => reviewer.login == login).length == 0) || + pull_request.data.requested_reviewers == undefined)) { + core.info(`Current user already approved pull request #${prNumber}, nothing to do`); + return; + } + } + core.info(`Pull request #${prNumber} has not been approved yet, creating approving review`); + yield client.rest.pulls.createReview({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: prNumber, + body: reviewMessage, + event: "APPROVE", + }); + core.info(`Approved pull request #${prNumber}`); + } + catch (error) { + if (error instanceof request_error_1.RequestError) { + switch (error.status) { + case 401: + core.setFailed(`${error.message}. Please check that the \`github-token\` input ` + + "parameter is set correctly."); + break; + case 403: + core.setFailed(`${error.message}. In some cases, the GitHub token used for actions triggered ` + + "from `pull_request` events are read-only, which can cause this problem. " + + "Switching to the `pull_request_target` event typically resolves this issue."); + break; + case 404: + core.setFailed(`${error.message}. This typically means the token you're using doesn't have ` + + "access to this repository. Use the built-in `${{ secrets.GITHUB_TOKEN }}` token " + + "or review the scopes assigned to your personal access token."); + break; + case 422: + core.setFailed(`${error.message}. This typically happens when you try to approve the pull ` + + "request with the same user account that created the pull request. Try using " + + "the built-in `${{ secrets.GITHUB_TOKEN }}` token, or if you're using a personal " + + "access token, use one that belongs to a dedicated bot account."); + break; + default: + core.setFailed(`Error (code ${error.status}): ${error.message}`); + } + return; + } + if (error instanceof Error) { + core.setFailed(error); + } + else { + core.setFailed("Unknown error"); + } + return; + } + }); +} +exports.approve = approve; +function getLoginForToken(client) { + return __awaiter(this, void 0, void 0, function* () { + try { + const { data: user } = yield client.rest.users.getAuthenticated(); + return user.login; + } + catch (error) { + if (error instanceof request_error_1.RequestError) { + // If you use the GITHUB_TOKEN provided by GitHub Actions to fetch the current user + // you get a 403. For now we'll assume any 403 means this is an Actions token. + if (error.status === 403) { + return "github-actions[bot]"; + } + } + throw error; + } + }); +} /***/ }), @@ -10182,79 +10185,79 @@ function getLoginForToken(client) { /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; - -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.run = void 0; -const core = __importStar(__nccwpck_require__(2186)); -const github = __importStar(__nccwpck_require__(5438)); -const approve_1 = __nccwpck_require__(6609); -function run() { - return __awaiter(this, void 0, void 0, function* () { - try { - const token = core.getInput("github-token"); - const reviewMessage = core.getInput("review-message"); - yield (0, approve_1.approve)(token, github.context, prNumber(), reviewMessage || undefined); - } - catch (error) { - if (error instanceof Error) { - core.setFailed(error.message); - } - else { - core.setFailed("Unknown error"); - } - } - }); -} -exports.run = run; -function prNumber() { - if (core.getInput("pull-request-number") !== "") { - const prNumber = parseInt(core.getInput("pull-request-number"), 10); - if (Number.isNaN(prNumber)) { - throw new Error("Invalid `pull-request-number` value"); - } - return prNumber; - } - if (!github.context.payload.pull_request) { - throw new Error("This action must be run using a `pull_request` event or " + - "have an explicit `pull-request-number` provided"); - } - return github.context.payload.pull_request.number; -} -if (require.main === require.cache[eval('__filename')]) { - run(); -} + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.run = void 0; +const core = __importStar(__nccwpck_require__(2186)); +const github = __importStar(__nccwpck_require__(5438)); +const approve_1 = __nccwpck_require__(6609); +function run() { + return __awaiter(this, void 0, void 0, function* () { + try { + const token = core.getInput("github-token"); + const reviewMessage = core.getInput("review-message"); + yield (0, approve_1.approve)(token, github.context, prNumber(), reviewMessage || undefined); + } + catch (error) { + if (error instanceof Error) { + core.setFailed(error.message); + } + else { + core.setFailed("Unknown error"); + } + } + }); +} +exports.run = run; +function prNumber() { + if (core.getInput("pull-request-number") !== "") { + const prNumber = parseInt(core.getInput("pull-request-number"), 10); + if (Number.isNaN(prNumber)) { + throw new Error("Invalid `pull-request-number` value"); + } + return prNumber; + } + if (!github.context.payload.pull_request) { + throw new Error("This action must be run using a `pull_request` event or " + + "have an explicit `pull-request-number` provided"); + } + return github.context.payload.pull_request.number; +} +if (require.main === require.cache[eval('__filename')]) { + run(); +} /***/ }), diff --git a/src/approve.test.ts b/src/approve.test.ts index d32c589..e1cf319 100644 --- a/src/approve.test.ts +++ b/src/approve.test.ts @@ -24,8 +24,8 @@ afterEach(() => { const apiNock = nock("https://api.github.com"); const apiMocks = { getUser: () => apiNock.get("/user").reply(200, { login: "hmarr" }), - getPull: () => - apiNock.get("/repos/hmarr/test/pulls/101").reply(200, { + getPull: (pullRequest?: object) => + apiNock.get("/repos/hmarr/test/pulls/101").reply(200, pullRequest ?? { head: { sha: "24c5451bbf1fb09caa3ac8024df4788aff4d4974" }, }), getReviews: (reviews?: object[]) => @@ -226,6 +226,29 @@ test("when a review has already been approved by unknown user", async () => { expect(createReview.isDone()).toBe(true); }); +test("when a review has been previously approved by user and but requests a re-review", async () => { + apiMocks.getUser(); + apiMocks.getPull({ + head: { sha: "24c5451bbf1fb09caa3ac8024df4788aff4d4974" }, + requested_reviewers: [ + { login: "hmarr" } + ] + }); + apiMocks.getReviews([ + { + user: { login: "some" }, + commit_id: "24c5451bbf1fb09caa3ac8024df4788aff4d4974", + state: "APPROVED", + }, + ]); + + const createReview = apiMocks.createReview(); + + await approve("gh-tok", new Context(), 101); + + expect(createReview.isDone()).toBe(true); +}); + test("without a pull request", async () => { const createReview = apiMocks.createReview(); await approve("gh-tok", new Context()); diff --git a/src/approve.ts b/src/approve.ts index 8e4f20d..dc798fe 100644 --- a/src/approve.ts +++ b/src/approve.ts @@ -52,7 +52,13 @@ export async function approve( if ( review.user?.login == login && review.commit_id == commit && - review.state == "APPROVED" + review.state == "APPROVED" && + (( + pull_request.data.requested_reviewers != undefined && + pull_request.data.requested_reviewers.filter(reviewer => reviewer.login == login).length == 0 + ) || + pull_request.data.requested_reviewers == undefined + ) ) { core.info( `Current user already approved pull request #${prNumber}, nothing to do`