Skip to content

Commit

Permalink
feat(draft-pr): add new option to not process PRs which are in draft (#…
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
C0ZEN authored Sep 20, 2021
1 parent 303465a commit 9912fa7
Show file tree
Hide file tree
Showing 13 changed files with 367 additions and 72 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ Every argument is optional.
| [exempt-all-assignees](#exempt-all-assignees) | Exempt all issues/PRs with assignees from stale | `false` |
| [exempt-all-issue-assignees](#exempt-all-issue-assignees) | Override [exempt-all-assignees](#exempt-all-assignees) for issues only | |
| [exempt-all-pr-assignees](#exempt-all-pr-assignees) | Override [exempt-all-assignees](#exempt-all-assignees) for PRs only | |
| [exempt-draft-pr](#exempt-draft-pr) | Skip the stale action for draft PRs | `false` |
| [enable-statistics](#enable-statistics) | Display statistics in the logs | `true` |
| [ignore-updates](#ignore-updates) | Any update (update/comment) can reset the stale idle time on the issues/PRs | `false` |
| [ignore-issue-updates](#ignore-issue-updates) | Override [ignore-updates](#ignore-updates) for issues only | |
Expand Down Expand Up @@ -472,6 +473,14 @@ Override [exempt-all-assignees](#exempt-all-assignees) but only to exempt the pu

Default value: unset

#### exempt-draft-pr

If set to `true`, the pull requests currently in draft will not be marked as stale automatically.
⚠️ This option consume one operation per pull request to process because we need to fetch the pull request with the GitHub API to know if it's a draft one or not.

Default value: `false`
Required Permission: `pull-requests: read`

#### enable-statistics

Collects and display statistics at the end of the stale workflow logs to get a summary of what happened during the run.
Expand Down
8 changes: 7 additions & 1 deletion __tests__/classes/issues-processor-mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {Issue} from '../../src/classes/issue';
import {IssuesProcessor} from '../../src/classes/issues-processor';
import {IComment} from '../../src/interfaces/comment';
import {IIssuesProcessorOptions} from '../../src/interfaces/issues-processor-options';
import {IPullRequest} from '../../src/interfaces/pull-request';

export class IssuesProcessorMock extends IssuesProcessor {
constructor(
Expand All @@ -14,7 +15,8 @@ export class IssuesProcessorMock extends IssuesProcessor {
getLabelCreationDate?: (
issue: Issue,
label: string
) => Promise<string | undefined>
) => Promise<string | undefined>,
getPullRequest?: (issue: Issue) => Promise<IPullRequest | undefined | void>
) {
super(options);

Expand All @@ -29,5 +31,9 @@ export class IssuesProcessorMock extends IssuesProcessor {
if (getLabelCreationDate) {
this.getLabelCreationDate = getLabelCreationDate;
}

if (getPullRequest) {
this.getPullRequest = getPullRequest;
}
}
}
3 changes: 2 additions & 1 deletion __tests__/constants/default-processor-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,6 @@ export const DefaultProcessorOptions: IIssuesProcessorOptions = Object.freeze({
labelsToAddWhenUnstale: '',
ignoreUpdates: false,
ignoreIssueUpdates: undefined,
ignorePrUpdates: undefined
ignorePrUpdates: undefined,
exemptDraftPr: false
});
139 changes: 139 additions & 0 deletions __tests__/exempt-draft-pr.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import {Issue} from '../src/classes/issue';
import {IIssue} from '../src/interfaces/issue';
import {IIssuesProcessorOptions} from '../src/interfaces/issues-processor-options';
import {IPullRequest} from '../src/interfaces/pull-request';
import {IssuesProcessorMock} from './classes/issues-processor-mock';
import {DefaultProcessorOptions} from './constants/default-processor-options';
import {generateIssue} from './functions/generate-issue';

let issuesProcessorBuilder: IssuesProcessorBuilder;
let issuesProcessor: IssuesProcessorMock;

describe('exempt-draft-pr option', (): void => {
beforeEach((): void => {
issuesProcessorBuilder = new IssuesProcessorBuilder();
});

describe('when the option "exempt-draft-pr" is disabled', (): void => {
beforeEach((): void => {
issuesProcessorBuilder.processDraftPr();
});

test('should stale the pull request', async (): Promise<void> => {
expect.assertions(1);
issuesProcessor = issuesProcessorBuilder
.toStalePrs([
{
number: 10
}
])
.build();

await issuesProcessor.processIssues();

expect(issuesProcessor.staleIssues).toHaveLength(1);
});
});

describe('when the option "exempt-draft-pr" is enabled', (): void => {
beforeEach((): void => {
issuesProcessorBuilder.exemptDraftPr();
});

test('should not stale the pull request', async (): Promise<void> => {
expect.assertions(1);
issuesProcessor = issuesProcessorBuilder
.toStalePrs([
{
number: 20
}
])
.build();

await issuesProcessor.processIssues();

expect(issuesProcessor.staleIssues).toHaveLength(0);
});
});
});

class IssuesProcessorBuilder {
private _options: IIssuesProcessorOptions = {
...DefaultProcessorOptions
};
private _issues: Issue[] = [];

processDraftPr(): IssuesProcessorBuilder {
this._options.exemptDraftPr = false;

return this;
}

exemptDraftPr(): IssuesProcessorBuilder {
this._options.exemptDraftPr = true;

return this;
}

issuesOrPrs(issues: Partial<IIssue>[]): IssuesProcessorBuilder {
this._issues = issues.map(
(issue: Readonly<Partial<IIssue>>, index: Readonly<number>): Issue =>
generateIssue(
this._options,
issue.number ?? index,
issue.title ?? 'dummy-title',
issue.updated_at ?? new Date().toDateString(),
issue.created_at ?? new Date().toDateString(),
!!issue.pull_request,
issue.labels ? issue.labels.map(label => label.name) : []
)
);

return this;
}

prs(issues: Partial<IIssue>[]): IssuesProcessorBuilder {
this.issuesOrPrs(
issues.map((issue: Readonly<Partial<IIssue>>): Partial<IIssue> => {
return {
...issue,
pull_request: {key: 'value'}
};
})
);

return this;
}

toStalePrs(issues: Partial<IIssue>[]): IssuesProcessorBuilder {
this.prs(
issues.map((issue: Readonly<Partial<IIssue>>): Partial<IIssue> => {
return {
...issue,
updated_at: '2020-01-01T17:00:00Z',
created_at: '2020-01-01T17:00:00Z'
};
})
);

return this;
}

build(): IssuesProcessorMock {
return new IssuesProcessorMock(
this._options,
async p => (p === 1 ? this._issues : []),
async () => [],
async () => new Date().toDateString(),
async (): Promise<IPullRequest> => {
return Promise.resolve({
number: 0,
draft: true,
head: {
ref: 'ref'
}
});
}
);
}
}
4 changes: 4 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ inputs:
description: 'Exempt all pull requests with assignees from being marked as stale. Override "exempt-all-assignees" option regarding only the pull requests.'
default: ''
required: false
exempt-draft-pr:
description: 'Exempt draft pull requests from being marked as stale. Default to false.'
default: 'false'
required: false
enable-statistics:
description: 'Display some statistics at the end regarding the stale workflow (only when the logs are enabled).'
default: 'true'
Expand Down
Loading

0 comments on commit 9912fa7

Please sign in to comment.