auto-approver
Advanced tools
Comparing version 1.13.4 to 1.13.5
@@ -1,10 +0,1 @@ | ||
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()); | ||
}); | ||
}; | ||
import axios from 'axios'; | ||
@@ -52,13 +43,11 @@ import logdown from 'logdown'; | ||
} | ||
approveByMatch(regex, repositories) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const allRepositories = repositories || (yield this.getRepositoriesWithOpenPullRequests()); | ||
const matchingRepositories = this.getMatchingRepositories(allRepositories, regex); | ||
const resultPromises = matchingRepositories.map((_a) => __awaiter(this, [_a], void 0, function* ({ pullRequests, repositorySlug }) { | ||
const actionPromises = pullRequests.map(pullRequest => this.approveByPullNumber(repositorySlug, pullRequest.number)); | ||
const actionResults = yield Promise.all(actionPromises); | ||
return { actionResults, repositorySlug }; | ||
})); | ||
return Promise.all(resultPromises); | ||
async approveByMatch(regex, repositories) { | ||
const allRepositories = repositories || (await this.getRepositoriesWithOpenPullRequests()); | ||
const matchingRepositories = this.getMatchingRepositories(allRepositories, regex); | ||
const resultPromises = matchingRepositories.map(async ({ pullRequests, repositorySlug }) => { | ||
const actionPromises = pullRequests.map(pullRequest => this.approveByPullNumber(repositorySlug, pullRequest.number)); | ||
const actionResults = await Promise.all(actionPromises); | ||
return { actionResults, repositorySlug }; | ||
}); | ||
return Promise.all(resultPromises); | ||
} | ||
@@ -76,93 +65,77 @@ getMatchingRepositories(repositories, regex) { | ||
} | ||
commentByMatch(regex, comment, repositories) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const allRepositories = repositories || (yield this.getRepositoriesWithOpenPullRequests()); | ||
const matchingRepositories = this.getMatchingRepositories(allRepositories, regex); | ||
const resultPromises = matchingRepositories.map((_a) => __awaiter(this, [_a], void 0, function* ({ pullRequests, repositorySlug }) { | ||
const actionPromises = pullRequests.map(pullRequest => this.commentOnPullRequest(repositorySlug, pullRequest.number, comment)); | ||
const actionResults = yield Promise.all(actionPromises); | ||
return { actionResults, repositorySlug }; | ||
})); | ||
return Promise.all(resultPromises); | ||
async commentByMatch(regex, comment, repositories) { | ||
const allRepositories = repositories || (await this.getRepositoriesWithOpenPullRequests()); | ||
const matchingRepositories = this.getMatchingRepositories(allRepositories, regex); | ||
const resultPromises = matchingRepositories.map(async ({ pullRequests, repositorySlug }) => { | ||
const actionPromises = pullRequests.map(pullRequest => this.commentOnPullRequest(repositorySlug, pullRequest.number, comment)); | ||
const actionResults = await Promise.all(actionPromises); | ||
return { actionResults, repositorySlug }; | ||
}); | ||
return Promise.all(resultPromises); | ||
} | ||
approveByPullNumber(repositorySlug, pullNumber) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const actionResult = { pullNumber, status: 'good' }; | ||
try { | ||
if (!this.config.dryRun) { | ||
yield this.postReview(repositorySlug, pullNumber); | ||
} | ||
async approveByPullNumber(repositorySlug, pullNumber) { | ||
const actionResult = { pullNumber, status: 'good' }; | ||
try { | ||
if (!this.config.dryRun) { | ||
await this.postReview(repositorySlug, pullNumber); | ||
} | ||
catch (error) { | ||
this.logger.error(`Could not approve request #${pullNumber} in "${repositorySlug}": ${error.message}`); | ||
actionResult.status = 'bad'; | ||
actionResult.error = error.toString(); | ||
} | ||
catch (error) { | ||
this.logger.error(`Could not approve request #${pullNumber} in "${repositorySlug}": ${error.message}`); | ||
actionResult.status = 'bad'; | ||
actionResult.error = error.toString(); | ||
} | ||
return actionResult; | ||
} | ||
async commentOnPullRequest(repositorySlug, pullNumber, comment) { | ||
const actionResult = { pullNumber, status: 'good' }; | ||
try { | ||
if (!this.config.dryRun) { | ||
await this.postComment(repositorySlug, pullNumber, comment); | ||
} | ||
return actionResult; | ||
}); | ||
} | ||
catch (error) { | ||
this.logger.error(`Could not comment on pull request #${pullNumber} in "${repositorySlug}": ${error.message}`); | ||
actionResult.status = 'bad'; | ||
actionResult.error = error.toString(); | ||
} | ||
return actionResult; | ||
} | ||
commentOnPullRequest(repositorySlug, pullNumber, comment) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const actionResult = { pullNumber, status: 'good' }; | ||
async getAllRepositories() { | ||
const repositorySlugs = this.config.projects.gitHub.filter(repositorySlug => this.checkRepositorySlug(repositorySlug)); | ||
const repositoriesPromises = repositorySlugs.map(async (repositorySlug) => { | ||
try { | ||
if (!this.config.dryRun) { | ||
yield this.postComment(repositorySlug, pullNumber, comment); | ||
} | ||
const pullRequests = await this.getPullRequestsBySlug(repositorySlug); | ||
return { pullRequests, repositorySlug }; | ||
} | ||
catch (error) { | ||
this.logger.error(`Could not comment on pull request #${pullNumber} in "${repositorySlug}": ${error.message}`); | ||
actionResult.status = 'bad'; | ||
actionResult.error = error.toString(); | ||
this.logger.error(`Could not get pull requests for "${repositorySlug}": ${error.message}`); | ||
return undefined; | ||
} | ||
return actionResult; | ||
}); | ||
return (await Promise.all(repositoriesPromises)).filter(Boolean); | ||
} | ||
getAllRepositories() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const repositorySlugs = this.config.projects.gitHub.filter(repositorySlug => this.checkRepositorySlug(repositorySlug)); | ||
const repositoriesPromises = repositorySlugs.map((repositorySlug) => __awaiter(this, void 0, void 0, function* () { | ||
try { | ||
const pullRequests = yield this.getPullRequestsBySlug(repositorySlug); | ||
return { pullRequests, repositorySlug }; | ||
} | ||
catch (error) { | ||
this.logger.error(`Could not get pull requests for "${repositorySlug}": ${error.message}`); | ||
return undefined; | ||
} | ||
})); | ||
return (yield Promise.all(repositoriesPromises)).filter(Boolean); | ||
}); | ||
async getRepositoriesWithOpenPullRequests() { | ||
const allRepositories = await this.getAllRepositories(); | ||
return allRepositories.filter(repository => !!repository.pullRequests.length); | ||
} | ||
getRepositoriesWithOpenPullRequests() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const allRepositories = yield this.getAllRepositories(); | ||
return allRepositories.filter(repository => !!repository.pullRequests.length); | ||
}); | ||
} | ||
/** @see https://docs.github.com/en/rest/reference/pulls#create-a-review-for-a-pull-request */ | ||
postReview(repositorySlug, pullNumber) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const resourceUrl = `/repos/${repositorySlug}/pulls/${pullNumber}/reviews`; | ||
yield this.apiClient.post(resourceUrl, { event: 'APPROVE' }); | ||
}); | ||
async postReview(repositorySlug, pullNumber) { | ||
const resourceUrl = `/repos/${repositorySlug}/pulls/${pullNumber}/reviews`; | ||
await this.apiClient.post(resourceUrl, { event: 'APPROVE' }); | ||
} | ||
/** @see https://docs.github.com/en/rest/reference/issues#create-an-issue-comment */ | ||
postComment(repositorySlug, pullNumber, comment) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const resourceUrl = `/repos/${repositorySlug}/issues/${pullNumber}/comments`; | ||
yield this.apiClient.post(resourceUrl, { body: comment }); | ||
}); | ||
async postComment(repositorySlug, pullNumber, comment) { | ||
const resourceUrl = `/repos/${repositorySlug}/issues/${pullNumber}/comments`; | ||
await this.apiClient.post(resourceUrl, { body: comment }); | ||
} | ||
getPullRequestsBySlug(repositorySlug) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const resourceUrl = `/repos/${repositorySlug}/pulls`; | ||
const params = { state: 'open' }; | ||
const response = yield this.apiClient.get(resourceUrl, { params }); | ||
if (!this.config.keepDrafts) { | ||
response.data = response.data.filter(pr => !pr.draft); | ||
} | ||
return response.data; | ||
}); | ||
async getPullRequestsBySlug(repositorySlug) { | ||
const resourceUrl = `/repos/${repositorySlug}/pulls`; | ||
const params = { state: 'open' }; | ||
const response = await this.apiClient.get(resourceUrl, { params }); | ||
if (!this.config.keepDrafts) { | ||
response.data = response.data.filter(pr => !pr.draft); | ||
} | ||
return response.data; | ||
} | ||
} |
@@ -1,10 +0,1 @@ | ||
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()); | ||
}); | ||
}; | ||
import { expect, describe, test, beforeEach, afterEach, vi } from 'vitest'; | ||
@@ -103,14 +94,14 @@ import nock from 'nock'; | ||
describe('commentByMatch', () => { | ||
test('comments on matching PRs', () => __awaiter(void 0, void 0, void 0, function* () { | ||
test('comments on matching PRs', async () => { | ||
vi.spyOn(autoApprover, 'postComment'); | ||
const comment = '@dependabot squash and merge'; | ||
yield autoApprover.commentByMatch(/eslint/gi, comment, repositories); | ||
await autoApprover.commentByMatch(/eslint/gi, comment, repositories); | ||
const expectedRepositoryESLint = repositories[0]; | ||
expect(autoApprover['postComment']).toHaveBeenCalledWith(expectedRepositoryESLint.repositorySlug, expectedRepositoryESLint.pullRequests[0].number, comment); | ||
yield autoApprover.commentByMatch(/typescript-4.0.3/gi, comment, repositories); | ||
await autoApprover.commentByMatch(/typescript-4.0.3/gi, comment, repositories); | ||
const expectedRepositoryTypescript = repositories[1]; | ||
expect(autoApprover['postComment']).toHaveBeenCalledWith(expectedRepositoryTypescript.repositorySlug, expectedRepositoryTypescript.pullRequests[0].number, comment); | ||
})); | ||
}); | ||
}); | ||
}); | ||
}); |
#!/usr/bin/env node | ||
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()); | ||
}); | ||
}; | ||
import { program as commander } from 'commander'; | ||
@@ -41,16 +32,18 @@ import { cosmiconfigSync } from 'cosmiconfig'; | ||
} | ||
const configFileData = Object.assign(Object.assign(Object.assign({}, configResult.config), (commanderOptions.message && { useComment: commanderOptions.message })), (commanderOptions.dryRun && { dryRun: commanderOptions.dryRun })); | ||
function runAction(autoApprover, repositories, pullRequestSlug) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const regex = new RegExp(pullRequestSlug, 'gi'); | ||
const action = configFileData.useComment ? 'Commented on' : 'Approved'; | ||
const actionResult = configFileData.useComment | ||
? yield autoApprover.commentByMatch(regex, configFileData.useComment, repositories) | ||
: yield autoApprover.approveByMatch(regex, repositories); | ||
const actedRepositories = actionResult.reduce((count, repository) => { | ||
return count + repository.actionResults.length; | ||
}, 0); | ||
const prPluralized = pluralize('PR', actedRepositories); | ||
logger.info(`${action} ${actedRepositories} ${prPluralized} matching "${regex}".`); | ||
}); | ||
const configFileData = { | ||
...configResult.config, | ||
...(commanderOptions.message && { useComment: commanderOptions.message }), | ||
...(commanderOptions.dryRun && { dryRun: commanderOptions.dryRun }), | ||
}; | ||
async function runAction(autoApprover, repositories, pullRequestSlug) { | ||
const regex = new RegExp(pullRequestSlug, 'gi'); | ||
const action = configFileData.useComment ? 'Commented on' : 'Approved'; | ||
const actionResult = configFileData.useComment | ||
? await autoApprover.commentByMatch(regex, configFileData.useComment, repositories) | ||
: await autoApprover.approveByMatch(regex, repositories); | ||
const actedRepositories = actionResult.reduce((count, repository) => { | ||
return count + repository.actionResults.length; | ||
}, 0); | ||
const prPluralized = pluralize('PR', actedRepositories); | ||
logger.info(`${action} ${actedRepositories} ${prPluralized} matching "${regex}".`); | ||
} | ||
@@ -62,14 +55,12 @@ function askQuestion(question) { | ||
} | ||
function askAction(autoApprover, repositories, doAction) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const answer = yield askQuestion(`ℹ️ auto-approver Which PR would you like to ${doAction} (enter a branch name)? `); | ||
yield runAction(autoApprover, repositories, answer); | ||
yield askAction(autoApprover, repositories, doAction); | ||
}); | ||
async function askAction(autoApprover, repositories, doAction) { | ||
const answer = await askQuestion(`ℹ️ auto-approver Which PR would you like to ${doAction} (enter a branch name)? `); | ||
await runAction(autoApprover, repositories, answer); | ||
await askAction(autoApprover, repositories, doAction); | ||
} | ||
void (() => __awaiter(void 0, void 0, void 0, function* () { | ||
void (async () => { | ||
try { | ||
const autoApprover = new AutoApprover(configFileData); | ||
logger.info('Loading all pull requests ...'); | ||
const allRepositories = yield autoApprover.getRepositoriesWithOpenPullRequests(); | ||
const allRepositories = await autoApprover.getRepositoriesWithOpenPullRequests(); | ||
if (allRepositories.length) { | ||
@@ -84,3 +75,3 @@ const repositories = allRepositories | ||
const doAction = configFileData.useComment ? 'comment on' : 'approve'; | ||
yield askAction(autoApprover, allRepositories, doAction); | ||
await askAction(autoApprover, allRepositories, doAction); | ||
} | ||
@@ -96,2 +87,2 @@ else { | ||
} | ||
}))(); | ||
})(); |
@@ -32,3 +32,7 @@ #!/usr/bin/env node | ||
} | ||
const configFileData = Object.assign(Object.assign(Object.assign({}, configResult.config), (commanderOptions.message && { useComment: commanderOptions.message })), (commanderOptions.dryRun && { dryRun: commanderOptions.dryRun })); | ||
const configFileData = { | ||
...configResult.config, | ||
...(commanderOptions.message && { useComment: commanderOptions.message }), | ||
...(commanderOptions.dryRun && { dryRun: commanderOptions.dryRun }), | ||
}; | ||
async function runAction(autoApprover, repositories, pullRequestSlug) { | ||
@@ -35,0 +39,0 @@ const regex = new RegExp(pullRequestSlug, 'gi'); |
@@ -15,3 +15,3 @@ { | ||
"rimraf": "5.0.7", | ||
"typescript": "5.4.5", | ||
"typescript": "5.5.2", | ||
"vitest": "1.6.0" | ||
@@ -51,4 +51,4 @@ }, | ||
"type": "module", | ||
"version": "1.13.4", | ||
"gitHead": "28c184f53a87d8eb082cc27c923ef7b352bbe875" | ||
"version": "1.13.5", | ||
"gitHead": "f7a6a79286e4eb85392b5f2d33942ab166142109" | ||
} |
75114
812