auto-approver
Advanced tools
Comparing version 1.4.1 to 1.5.0
@@ -25,9 +25,9 @@ interface GitHubPullRequest { | ||
} | ||
export interface Project { | ||
projectSlug: string; | ||
export interface Repository { | ||
pullRequests: GitHubPullRequest[]; | ||
repositorySlug: string; | ||
} | ||
export interface ProjectResult { | ||
export interface RepositoryResult { | ||
actionResults: ActionResult[]; | ||
projectSlug: string; | ||
repositorySlug: string; | ||
} | ||
@@ -40,8 +40,10 @@ export declare class AutoApprover { | ||
private checkConfig; | ||
private checkProject; | ||
approveAllByMatch(regex: RegExp): Promise<ProjectResult[]>; | ||
private getMatchingProjects; | ||
commentByMatch(regex: RegExp, comment: string): Promise<ProjectResult[]>; | ||
approveByPullNumber(projectSlug: string, pullNumber: number): Promise<ActionResult>; | ||
commentOnPullRequest(projectSlug: string, pullNumber: number, comment: string): Promise<ActionResult>; | ||
private checkRepository; | ||
approveByMatch(regex: RegExp, repositories?: Repository[]): Promise<RepositoryResult[]>; | ||
private getMatchingRepositories; | ||
commentByMatch(regex: RegExp, comment: string, repositories?: Repository[]): Promise<RepositoryResult[]>; | ||
approveByPullNumber(repositorySlug: string, pullNumber: number): Promise<ActionResult>; | ||
commentOnPullRequest(repositorySlug: string, pullNumber: number, comment: string): Promise<ActionResult>; | ||
getAllRepositories(): Promise<Repository[]>; | ||
getRepositoriesWithOpenPullRequests(): Promise<Repository[]>; | ||
/** @see https://docs.github.com/en/rest/reference/pulls#create-a-review-for-a-pull-request */ | ||
@@ -48,0 +50,0 @@ private postReview; |
@@ -17,3 +17,2 @@ "use strict"; | ||
const path = require("path"); | ||
const util_1 = require("./util"); | ||
const defaultPackageJsonPath = path.join(__dirname, 'package.json'); | ||
@@ -51,19 +50,20 @@ const packageJsonPath = fs.existsSync(defaultPackageJsonPath) | ||
} | ||
checkProject(projectSlug) { | ||
checkRepository(repositorySlug) { | ||
const gitHubUsernameRegex = /^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i; | ||
const gitHubProjectRegex = /^[\w-.]{0,100}$/i; | ||
const [userName, project] = projectSlug.trim().replace(/^\//, '').replace(/\/$/, '').split('/'); | ||
if (!gitHubUsernameRegex.test(userName) || !gitHubProjectRegex.test(project)) { | ||
this.logger.warn(`Invalid GitHub project slug "${projectSlug}". Skipping.`); | ||
const gitHubRepositoryRegex = /^[\w-.]{0,100}$/i; | ||
const [userName, repositoryName] = repositorySlug.trim().replace(/^\//, '').replace(/\/$/, '').split('/'); | ||
if (!gitHubUsernameRegex.test(userName) || !gitHubRepositoryRegex.test(repositoryName)) { | ||
this.logger.warn(`Invalid GitHub repository slug "${repositorySlug}". Skipping.`); | ||
return false; | ||
} | ||
return projectSlug; | ||
return repositorySlug; | ||
} | ||
approveAllByMatch(regex) { | ||
approveByMatch(regex, repositories) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const matchingProjects = yield this.getMatchingProjects(regex); | ||
const resultPromises = matchingProjects.map(({ pullRequests, projectSlug }) => __awaiter(this, void 0, void 0, function* () { | ||
const actionPromises = pullRequests.map(pullRequest => this.approveByPullNumber(projectSlug, pullRequest.number)); | ||
const allRepositories = repositories || (yield this.getRepositoriesWithOpenPullRequests()); | ||
const matchingRepositories = this.getMatchingRepositories(allRepositories, regex); | ||
const resultPromises = matchingRepositories.map(({ pullRequests, repositorySlug }) => __awaiter(this, void 0, void 0, function* () { | ||
const actionPromises = pullRequests.map(pullRequest => this.approveByPullNumber(repositorySlug, pullRequest.number)); | ||
const actionResults = yield Promise.all(actionPromises); | ||
return { actionResults, projectSlug }; | ||
return { actionResults, repositorySlug }; | ||
})); | ||
@@ -73,24 +73,16 @@ return Promise.all(resultPromises); | ||
} | ||
getMatchingProjects(regex) { | ||
const projectSlugs = this.config.projects.gitHub | ||
.map(projectSlug => this.checkProject(projectSlug)) | ||
.filter(Boolean); | ||
const projectsPromises = projectSlugs.map((projectSlug) => __awaiter(this, void 0, void 0, function* () { | ||
const pullRequests = yield this.getPullRequestsBySlug(projectSlug); | ||
const matchedPulls = pullRequests.filter(pullRequest => !!pullRequest.head.ref.match(regex)); | ||
if (matchedPulls.length) { | ||
const pluralSingular = util_1.getPlural('request', matchedPulls.length); | ||
this.logger.info(`Found ${matchedPulls.length} matching pull ${pluralSingular} for "${projectSlug}":`, matchedPulls.map(pull => pull.title)); | ||
} | ||
return { projectSlug, pullRequests: matchedPulls }; | ||
})); | ||
return Promise.all(projectsPromises); | ||
getMatchingRepositories(repositories, regex) { | ||
return repositories.filter(repository => { | ||
const matchingRepositories = repository.pullRequests.filter(pullRequest => !!pullRequest.head.ref.match(regex)); | ||
return !!matchingRepositories.length; | ||
}); | ||
} | ||
commentByMatch(regex, comment) { | ||
commentByMatch(regex, comment, repositories) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const matchingProjects = yield this.getMatchingProjects(regex); | ||
const resultPromises = matchingProjects.map(({ pullRequests, projectSlug }) => __awaiter(this, void 0, void 0, function* () { | ||
const actionPromises = pullRequests.map(pullRequest => this.commentOnPullRequest(projectSlug, pullRequest.number, comment)); | ||
const allRepositories = repositories || (yield this.getRepositoriesWithOpenPullRequests()); | ||
const matchingRepositories = this.getMatchingRepositories(allRepositories, regex); | ||
const resultPromises = matchingRepositories.map(({ pullRequests, repositorySlug }) => __awaiter(this, void 0, void 0, function* () { | ||
const actionPromises = pullRequests.map(pullRequest => this.commentOnPullRequest(repositorySlug, pullRequest.number, comment)); | ||
const actionResults = yield Promise.all(actionPromises); | ||
return { actionResults, projectSlug }; | ||
return { actionResults, repositorySlug }; | ||
})); | ||
@@ -100,7 +92,7 @@ return Promise.all(resultPromises); | ||
} | ||
approveByPullNumber(projectSlug, pullNumber) { | ||
approveByPullNumber(repositorySlug, pullNumber) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const actionResult = { pullNumber, status: 'ok' }; | ||
try { | ||
yield this.postReview(projectSlug, pullNumber); | ||
yield this.postReview(repositorySlug, pullNumber); | ||
} | ||
@@ -115,7 +107,7 @@ catch (error) { | ||
} | ||
commentOnPullRequest(projectSlug, pullNumber, comment) { | ||
commentOnPullRequest(repositorySlug, pullNumber, comment) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const actionResult = { pullNumber, status: 'ok' }; | ||
try { | ||
yield this.postComment(projectSlug, pullNumber, comment); | ||
yield this.postComment(repositorySlug, pullNumber, comment); | ||
} | ||
@@ -130,6 +122,24 @@ catch (error) { | ||
} | ||
getAllRepositories() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const repositorySlugs = this.config.projects.gitHub | ||
.map(repositorySlug => this.checkRepository(repositorySlug)) | ||
.filter(Boolean); | ||
const repositoriesPromises = repositorySlugs.map((repositorySlug) => __awaiter(this, void 0, void 0, function* () { | ||
const pullRequests = yield this.getPullRequestsBySlug(repositorySlug); | ||
return { pullRequests, repositorySlug }; | ||
})); | ||
return Promise.all(repositoriesPromises); | ||
}); | ||
} | ||
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(projectSlug, pullNumber) { | ||
postReview(repositorySlug, pullNumber) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const resourceUrl = `/repos/${projectSlug}/pulls/${pullNumber}/reviews`; | ||
const resourceUrl = `/repos/${repositorySlug}/pulls/${pullNumber}/reviews`; | ||
yield this.apiClient.post(resourceUrl, { event: 'APPROVE' }); | ||
@@ -139,11 +149,11 @@ }); | ||
/** @see https://docs.github.com/en/rest/reference/issues#create-an-issue-comment */ | ||
postComment(projectSlug, pullNumber, comment) { | ||
postComment(repositorySlug, pullNumber, comment) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const resourceUrl = `/repos/${projectSlug}/issues/${pullNumber}/comments`; | ||
const resourceUrl = `/repos/${repositorySlug}/issues/${pullNumber}/comments`; | ||
yield this.apiClient.post(resourceUrl, { body: comment }); | ||
}); | ||
} | ||
getPullRequestsBySlug(projectSlug) { | ||
getPullRequestsBySlug(repositorySlug) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const resourceUrl = `/repos/${projectSlug}/pulls`; | ||
const resourceUrl = `/repos/${repositorySlug}/pulls`; | ||
const params = { state: 'open' }; | ||
@@ -150,0 +160,0 @@ const response = yield this.apiClient.get(resourceUrl, { params }); |
@@ -0,1 +1,8 @@ | ||
## [1.4.1](https://github.com/ffflorian/auto-approver/compare/v1.4.0...v1.4.1) (2020-09-14) | ||
### Bug Fixes | ||
* Count PRs and not projects in CLI ([7def03f](https://github.com/ffflorian/auto-approver/commit/7def03f36f09133022c13381b75f594bdfed7ca6)) | ||
# [1.4.0](https://github.com/ffflorian/auto-approver/compare/v1.3.2...v1.4.0) (2020-09-11) | ||
@@ -2,0 +9,0 @@ |
67
cli.js
@@ -45,22 +45,55 @@ #!/usr/bin/env node | ||
} | ||
const configFileData = configResult.config; | ||
if (configFileData.useComment) { | ||
commander.message = configFileData.useComment; | ||
const configFileData = Object.assign(Object.assign({}, configResult.config), (commander.message && { useComment: commander.message })); | ||
function runAction(autoApprover, repositories, pullRequestSlug) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (configFileData.useComment) { | ||
const commentResult = yield autoApprover.commentByMatch(new RegExp(pullRequestSlug), configFileData.useComment, repositories); | ||
const commentedRepositories = commentResult.reduce((count, repository) => count + repository.actionResults.length, 0); | ||
const pluralSingular = util_1.getPlural('request', commentedRepositories); | ||
logger.info(`Commented "${configFileData.useComment}" on ${commentedRepositories} pull ${pluralSingular}.`); | ||
} | ||
else { | ||
const approveResult = yield autoApprover.approveByMatch(new RegExp(pullRequestSlug), repositories); | ||
const approvedRepositories = approveResult.reduce((count, repository) => count + repository.actionResults.length, 0); | ||
const pluralSingular = util_1.getPlural('request', approvedRepositories); | ||
logger.info(`Approved ${approvedRepositories} pull ${pluralSingular}.`); | ||
} | ||
}); | ||
} | ||
logger.info('Found the following repositories to check:', configFileData.projects.gitHub); | ||
const action = commander.message ? 'comment on' : 'approve'; | ||
input.question(`ℹ️ auto-approver Which PR would you like to ${action} (enter a branch name)? `, (answer) => __awaiter(void 0, void 0, void 0, function* () { | ||
const autoApprover = new AutoApprover_1.AutoApprover(configFileData); | ||
function askQuestion(question) { | ||
return new Promise(resolve => { | ||
input.question(question, answer => resolve(answer)); | ||
}); | ||
} | ||
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 actionLoop(autoApprover, repositories, doAction); | ||
}); | ||
} | ||
function actionLoop(autoApprover, repositories, doAction) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const answer = yield askQuestion(`ℹ️ auto-approver Would you like to ${doAction} another PR (Y/n)? `); | ||
if (!/n(o)?$/i.test(answer)) { | ||
yield askAction(autoApprover, repositories, doAction); | ||
} | ||
}); | ||
} | ||
void (() => __awaiter(void 0, void 0, void 0, function* () { | ||
try { | ||
if (commander.message) { | ||
const commentResult = yield autoApprover.commentByMatch(new RegExp(answer), commander.message); | ||
const commentedProjects = commentResult.reduce((count, project) => count + project.actionResults.length, 0); | ||
const pluralSingular = util_1.getPlural('request', commentedProjects); | ||
logger.info(`Commented "${commander.message}" on ${commentedProjects} pull ${pluralSingular}.`); | ||
const autoApprover = new AutoApprover_1.AutoApprover(configFileData); | ||
logger.info('Loading all pull requests ...'); | ||
const allRepositories = yield autoApprover.getRepositoriesWithOpenPullRequests(); | ||
if (!!allRepositories.length) { | ||
const repositories = allRepositories.map(repository => { | ||
const prText = util_1.getPlural('PR', repository.pullRequests.length); | ||
return `${repository.repositorySlug} (${repository.pullRequests.length} open ${prText})`; | ||
}); | ||
logger.info('Found the following repositories to check:', repositories); | ||
const doAction = configFileData.useComment ? 'comment on' : 'approve'; | ||
yield askAction(autoApprover, allRepositories, doAction); | ||
} | ||
else { | ||
const approveResult = yield autoApprover.approveAllByMatch(new RegExp(answer)); | ||
const approvedProjects = approveResult.reduce((count, project) => count + project.actionResults.length, 0); | ||
const pluralSingular = util_1.getPlural('request', approvedProjects); | ||
logger.info(`Approved ${approvedProjects} pull ${pluralSingular}.`); | ||
logger.info('Could not find any repositories with open pull requests.'); | ||
} | ||
@@ -73,3 +106,3 @@ process.exit(); | ||
} | ||
})); | ||
}))(); | ||
//# sourceMappingURL=cli.js.map |
@@ -28,3 +28,3 @@ { | ||
"eslint-plugin-jasmine": "4.1.1", | ||
"eslint-plugin-jsdoc": "30.4.2", | ||
"eslint-plugin-jsdoc": "30.5.1", | ||
"eslint-plugin-no-unsanitized": "3.1.2", | ||
@@ -38,3 +38,3 @@ "eslint-plugin-prettier": "3.1.4", | ||
"lint-staged": "10.3.0", | ||
"prettier": "2.1.1", | ||
"prettier": "2.1.2", | ||
"publish-flat": "1.4.1", | ||
@@ -109,3 +109,3 @@ "rimraf": "3.0.2", | ||
}, | ||
"version": "1.4.1" | ||
"version": "1.5.0" | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
67526
340