feat(draft-pr): add new option to not process PRs which are in draft (#539)

* chore(assignees): add logs

* feat(draft-pr): add new option to not process PRs which are in draft

* refactor(draft-pr): create a dedicated class to handle the logic

* chore(index): update index file
This commit is contained in:
Geoffrey Testelin
2021-09-20 15:37:32 +02:00
committed by GitHub
parent 303465a5d2
commit 9912fa74d1
13 changed files with 367 additions and 72 deletions

View File

@@ -0,0 +1,51 @@
import {Option} from '../enums/option';
import {IIssuesProcessorOptions} from '../interfaces/issues-processor-options';
import {IPullRequest} from '../interfaces/pull-request';
import {LoggerService} from '../services/logger.service';
import {Issue} from './issue';
import {IssueLogger} from './loggers/issue-logger';
export class ExemptDraftPullRequest {
private readonly _options: IIssuesProcessorOptions;
private readonly _issue: Issue;
private readonly _issueLogger: IssueLogger;
constructor(options: Readonly<IIssuesProcessorOptions>, issue: Issue) {
this._options = options;
this._issue = issue;
this._issueLogger = new IssueLogger(issue);
}
async shouldExemptDraftPullRequest(
pullRequestCallback: () => Promise<IPullRequest | undefined | void>
): Promise<boolean> {
if (this._issue.isPullRequest) {
if (this._options.exemptDraftPr) {
this._issueLogger.info(
`The option ${this._issueLogger.createOptionLink(
Option.ExemptDraftPr
)} is enabled`
);
const pullRequest: IPullRequest | undefined | void =
await pullRequestCallback();
if (pullRequest?.draft === true) {
this._issueLogger.info(
LoggerService.white('└──'),
`Skip the $$type draft checks`
);
return true;
} else {
this._issueLogger.info(
LoggerService.white('└──'),
`Continuing the process for this $$type because it is not a draft`
);
}
}
}
return false;
}
}

View File

@@ -60,7 +60,8 @@ describe('Issue', (): void => {
labelsToAddWhenUnstale: '',
ignoreUpdates: false,
ignoreIssueUpdates: undefined,
ignorePrUpdates: undefined
ignorePrUpdates: undefined,
exemptDraftPr: false
};
issueInterface = {
title: 'dummy-title',

View File

@@ -17,6 +17,7 @@ import {IIssuesProcessorOptions} from '../interfaces/issues-processor-options';
import {IPullRequest} from '../interfaces/pull-request';
import {Assignees} from './assignees';
import {IgnoreUpdates} from './ignore-updates';
import {ExemptDraftPullRequest} from './exempt-draft-pull-request';
import {Issue} from './issue';
import {IssueLogger} from './loggers/issue-logger';
import {Logger} from './loggers/logger';
@@ -207,6 +208,19 @@ export class IssuesProcessor {
const daysBeforeStale: number = issue.isPullRequest
? this._getDaysBeforePrStale()
: this._getDaysBeforeIssueStale();
if (issue.state === 'closed') {
issueLogger.info(`Skipping this $$type because it is closed`);
IssuesProcessor._endIssueProcessing(issue);
return; // Don't process closed issues
}
if (issue.locked) {
issueLogger.info(`Skipping this $$type because it is locked`);
IssuesProcessor._endIssueProcessing(issue);
return; // Don't process locked issues
}
const onlyLabels: string[] = wordsToList(this._getOnlyLabels(issue));
if (onlyLabels.length > 0) {
@@ -260,18 +274,6 @@ export class IssuesProcessor {
const shouldMarkAsStale: boolean = shouldMarkWhenStale(daysBeforeStale);
if (issue.state === 'closed') {
issueLogger.info(`Skipping this $$type because it is closed`);
IssuesProcessor._endIssueProcessing(issue);
return; // Don't process closed issues
}
if (issue.locked) {
issueLogger.info(`Skipping this $$type because it is locked`);
IssuesProcessor._endIssueProcessing(issue);
return; // Don't process locked issues
}
// Try to remove the close label when not close/locked issue or PR
await this._removeCloseLabel(issue, closeLabel);
@@ -397,6 +399,23 @@ export class IssuesProcessor {
return; // Don't process exempt assignees
}
// Ignore draft PR
// Note that this check is so far below because it cost one read operation
// So it's simply better to do all the stale checks which don't cost more operation before this one
const exemptDraftPullRequest: ExemptDraftPullRequest =
new ExemptDraftPullRequest(this.options, issue);
if (
await exemptDraftPullRequest.shouldExemptDraftPullRequest(
async (): Promise<IPullRequest | undefined | void> => {
return this.getPullRequest(issue);
}
)
) {
IssuesProcessor._endIssueProcessing(issue);
return; // Don't process draft PR
}
// Determine if this issue needs to be marked stale first
if (!issue.isStale) {
issueLogger.info(`This $$type is not stale`);
@@ -574,6 +593,25 @@ export class IssuesProcessor {
return staleLabeledEvent.created_at;
}
async getPullRequest(issue: Issue): Promise<IPullRequest | undefined | void> {
const issueLogger: IssueLogger = new IssueLogger(issue);
try {
this._consumeIssueOperation(issue);
this._statistics?.incrementFetchedPullRequestsCount();
const pullRequest = await this.client.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: issue.number
});
return pullRequest.data;
} catch (error) {
issueLogger.error(`Error when getting this $$type: ${error.message}`);
}
}
// handle all of the stale issue logic when we find a stale issue
private async _processStaleIssue(
issue: Issue,
@@ -666,7 +704,7 @@ export class IssuesProcessor {
issueLogger.info(
`Deleting the branch since the option ${issueLogger.createOptionLink(
Option.DeleteBranch
)} was specified`
)} is enabled`
);
await this._deleteBranch(issue);
this.deletedBranchIssues.push(issue);
@@ -830,34 +868,14 @@ export class IssuesProcessor {
}
}
private async _getPullRequest(
issue: Issue
): Promise<IPullRequest | undefined | void> {
const issueLogger: IssueLogger = new IssueLogger(issue);
try {
this._consumeIssueOperation(issue);
this._statistics?.incrementFetchedPullRequestsCount();
const pullRequest = await this.client.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: issue.number
});
return pullRequest.data;
} catch (error) {
issueLogger.error(`Error when getting this $$type: ${error.message}`);
}
}
// Delete the branch on closed pull request
private async _deleteBranch(issue: Issue): Promise<void> {
const issueLogger: IssueLogger = new IssueLogger(issue);
issueLogger.info(`Delete branch from closed $$type - ${issue.title}`);
const pullRequest = await this._getPullRequest(issue);
const pullRequest: IPullRequest | undefined | void =
await this.getPullRequest(issue);
if (!pullRequest) {
issueLogger.info(