Allow the processing of locked issues and pull requests
This commit is contained in:
parent
3f3b0175e8
commit
7e06b131d5
11
README.md
11
README.md
|
@ -97,6 +97,7 @@ Every argument is optional.
|
|||
| [ignore-issue-updates](#ignore-issue-updates) | Override [ignore-updates](#ignore-updates) for issues only | |
|
||||
| [ignore-pr-updates](#ignore-pr-updates) | Override [ignore-updates](#ignore-updates) for PRs only | |
|
||||
| [include-only-assigned](#include-only-assigned) | Process only assigned issues | `false` |
|
||||
| [exempt-locked](#exempt-locked) | Issues and pull requests that are locked will not be marked as stale. | `true` |
|
||||
|
||||
### List of output options
|
||||
|
||||
|
@ -547,6 +548,16 @@ If set to `true`, only the issues or the pull requests with an assignee will be
|
|||
|
||||
Default value: `false`
|
||||
|
||||
#### exempt-locked
|
||||
|
||||
If set to `false` issues or pull requests that are locked will be marked as
|
||||
stale automatically. If you process locked issues and pull requests and want to
|
||||
add a closing message the default repo-token will not be sufficient. For that
|
||||
you will have to use a PAT which has write access, is repository owner or
|
||||
collaborator.
|
||||
|
||||
Default value: `true`
|
||||
|
||||
### Usage
|
||||
|
||||
See also [action.yml](./action.yml) for a comprehensive list of all the options.
|
||||
|
|
|
@ -55,5 +55,6 @@ export const DefaultProcessorOptions: IIssuesProcessorOptions = Object.freeze({
|
|||
ignorePrUpdates: undefined,
|
||||
exemptDraftPr: false,
|
||||
closeIssueReason: 'not_planned',
|
||||
includeOnlyAssigned: false
|
||||
includeOnlyAssigned: false,
|
||||
exemptLocked: true
|
||||
});
|
||||
|
|
|
@ -930,6 +930,38 @@ test('locked issues will not be marked stale', async () => {
|
|||
expect(processor.closedIssues).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('locked issues are marked stale', async () => {
|
||||
const opts: IIssuesProcessorOptions = {...DefaultProcessorOptions};
|
||||
opts.exemptLocked = false;
|
||||
const TestIssueList: Issue[] = [
|
||||
generateIssue(
|
||||
opts,
|
||||
1,
|
||||
'A locked issue that will be stale',
|
||||
'2020-01-01T17:00:00Z',
|
||||
'2020-01-01T17:00:00Z',
|
||||
false,
|
||||
false,
|
||||
[],
|
||||
false,
|
||||
true
|
||||
)
|
||||
];
|
||||
const processor = new IssuesProcessorMock(
|
||||
opts,
|
||||
alwaysFalseStateMock,
|
||||
async p => (p === 1 ? TestIssueList : []),
|
||||
async () => [],
|
||||
async () => new Date().toDateString()
|
||||
);
|
||||
|
||||
// process our fake issue list
|
||||
await processor.processIssues(1);
|
||||
|
||||
expect(processor.staleIssues).toHaveLength(1);
|
||||
expect(processor.closedIssues).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('stale locked issues will not be closed', async () => {
|
||||
const TestIssueList: Issue[] = [
|
||||
generateIssue(
|
||||
|
@ -960,6 +992,38 @@ test('stale locked issues will not be closed', async () => {
|
|||
expect(processor.closedIssues).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('stale locked issues will be closed', async () => {
|
||||
const opts: IIssuesProcessorOptions = {...DefaultProcessorOptions};
|
||||
opts.exemptLocked = false;
|
||||
const TestIssueList: Issue[] = [
|
||||
generateIssue(
|
||||
opts,
|
||||
1,
|
||||
'A stale locked issue that will not be closed',
|
||||
'2020-01-01T17:00:00Z',
|
||||
'2020-01-01T17:00:00Z',
|
||||
false,
|
||||
false,
|
||||
['Stale'],
|
||||
false,
|
||||
true
|
||||
)
|
||||
];
|
||||
const processor = new IssuesProcessorMock(
|
||||
opts,
|
||||
alwaysFalseStateMock,
|
||||
async p => (p === 1 ? TestIssueList : []),
|
||||
async () => [],
|
||||
async () => new Date().toDateString()
|
||||
);
|
||||
|
||||
// process our fake issue list
|
||||
await processor.processIssues(1);
|
||||
|
||||
expect(processor.staleIssues).toHaveLength(0);
|
||||
expect(processor.closedIssues).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('locked prs will not be marked stale', async () => {
|
||||
const TestIssueList: Issue[] = [
|
||||
generateIssue(
|
||||
|
@ -988,6 +1052,38 @@ test('locked prs will not be marked stale', async () => {
|
|||
expect(processor.closedIssues).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('locked prs will be marked stale', async () => {
|
||||
const opts: IIssuesProcessorOptions = {...DefaultProcessorOptions};
|
||||
opts.exemptLocked = false;
|
||||
const TestIssueList: Issue[] = [
|
||||
generateIssue(
|
||||
opts,
|
||||
1,
|
||||
'A locked PR that will not be marked stale',
|
||||
'2020-01-01T17:00:00Z',
|
||||
'2020-01-01T17:00:00Z',
|
||||
false,
|
||||
true,
|
||||
[],
|
||||
false,
|
||||
true
|
||||
)
|
||||
];
|
||||
const processor = new IssuesProcessorMock(
|
||||
opts,
|
||||
alwaysFalseStateMock,
|
||||
async p => (p === 1 ? TestIssueList : []),
|
||||
async () => [],
|
||||
async () => new Date().toDateString()
|
||||
);
|
||||
|
||||
// process our fake issue list
|
||||
await processor.processIssues(1);
|
||||
|
||||
expect(processor.staleIssues).toHaveLength(1);
|
||||
expect(processor.closedIssues).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('stale locked prs will not be closed', async () => {
|
||||
const TestIssueList: Issue[] = [
|
||||
generateIssue(
|
||||
|
@ -1018,6 +1114,38 @@ test('stale locked prs will not be closed', async () => {
|
|||
expect(processor.closedIssues).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('stale locked prs will be closed', async () => {
|
||||
const opts: IIssuesProcessorOptions = {...DefaultProcessorOptions};
|
||||
opts.exemptLocked = false;
|
||||
const TestIssueList: Issue[] = [
|
||||
generateIssue(
|
||||
opts,
|
||||
1,
|
||||
'A stale locked PR that will not be closed',
|
||||
'2020-01-01T17:00:00Z',
|
||||
'2020-01-01T17:00:00Z',
|
||||
false,
|
||||
true,
|
||||
['Stale'],
|
||||
false,
|
||||
true
|
||||
)
|
||||
];
|
||||
const processor = new IssuesProcessorMock(
|
||||
opts,
|
||||
alwaysFalseStateMock,
|
||||
async p => (p === 1 ? TestIssueList : []),
|
||||
async () => [],
|
||||
async () => new Date().toDateString()
|
||||
);
|
||||
|
||||
// process our fake issue list
|
||||
await processor.processIssues(1);
|
||||
|
||||
expect(processor.staleIssues).toHaveLength(0);
|
||||
expect(processor.closedIssues).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('exempt issue labels will not be marked stale', async () => {
|
||||
expect.assertions(3);
|
||||
const opts = {...DefaultProcessorOptions};
|
||||
|
@ -2516,6 +2644,44 @@ test('processing a locked issue with a close label will not remove the close lab
|
|||
expect(processor.removedLabelIssues).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('processing a locked issue with a close label will remove the close label', async () => {
|
||||
expect.assertions(1);
|
||||
const opts: IIssuesProcessorOptions = {
|
||||
...DefaultProcessorOptions,
|
||||
closeIssueLabel: 'close',
|
||||
staleIssueLabel: 'stale',
|
||||
exemptLocked: false
|
||||
};
|
||||
const now: Date = new Date();
|
||||
const oneWeekAgo: Date = new Date(now.setDate(now.getDate() - 7));
|
||||
const TestIssueList: Issue[] = [
|
||||
generateIssue(
|
||||
opts,
|
||||
1,
|
||||
'A closed issue with a close label',
|
||||
oneWeekAgo.toDateString(),
|
||||
now.toDateString(),
|
||||
false,
|
||||
false,
|
||||
['close'],
|
||||
false,
|
||||
true
|
||||
)
|
||||
];
|
||||
const processor = new IssuesProcessorMock(
|
||||
opts,
|
||||
alwaysFalseStateMock,
|
||||
async p => (p === 1 ? TestIssueList : []),
|
||||
async () => [],
|
||||
async () => new Date().toDateString()
|
||||
);
|
||||
|
||||
// process our fake issue list
|
||||
await processor.processIssues(1);
|
||||
|
||||
expect(processor.removedLabelIssues).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('processing an issue stale since less than the daysBeforeStale with a stale label created after daysBeforeClose should close the issue', async () => {
|
||||
expect.assertions(3);
|
||||
const opts: IIssuesProcessorOptions = {
|
||||
|
|
|
@ -204,6 +204,10 @@ inputs:
|
|||
description: 'Only the issues or the pull requests with an assignee will be marked as stale automatically.'
|
||||
default: 'false'
|
||||
required: false
|
||||
exempt-locked:
|
||||
description: 'Issues and pull requests that are locked will not be marked as stale.'
|
||||
default: 'true'
|
||||
required: false
|
||||
outputs:
|
||||
closed-issues-prs:
|
||||
description: 'List of all closed issues and pull requests.'
|
||||
|
|
|
@ -495,7 +495,7 @@ class IssuesProcessor {
|
|||
IssuesProcessor._endIssueProcessing(issue);
|
||||
return; // Don't process closed issues
|
||||
}
|
||||
if (issue.locked) {
|
||||
if (issue.locked && this.options.exemptLocked) {
|
||||
issueLogger.info(`Skipping this $$type because it is locked`);
|
||||
IssuesProcessor._endIssueProcessing(issue);
|
||||
return; // Don't process locked issues
|
||||
|
@ -2567,7 +2567,8 @@ function _getAndValidateArgs() {
|
|||
ignorePrUpdates: _toOptionalBoolean('ignore-pr-updates'),
|
||||
exemptDraftPr: core.getInput('exempt-draft-pr') === 'true',
|
||||
closeIssueReason: core.getInput('close-issue-reason'),
|
||||
includeOnlyAssigned: core.getInput('include-only-assigned') === 'true'
|
||||
includeOnlyAssigned: core.getInput('include-only-assigned') === 'true',
|
||||
exemptLocked: core.getInput('exempt-locked') === 'true'
|
||||
};
|
||||
for (const numberInput of ['days-before-stale']) {
|
||||
if (isNaN(parseFloat(core.getInput(numberInput)))) {
|
||||
|
|
|
@ -64,7 +64,8 @@ describe('Issue', (): void => {
|
|||
ignorePrUpdates: undefined,
|
||||
exemptDraftPr: false,
|
||||
closeIssueReason: '',
|
||||
includeOnlyAssigned: false
|
||||
includeOnlyAssigned: false,
|
||||
exemptLocked: true
|
||||
};
|
||||
issueInterface = {
|
||||
title: 'dummy-title',
|
||||
|
|
|
@ -237,7 +237,7 @@ export class IssuesProcessor {
|
|||
return; // Don't process closed issues
|
||||
}
|
||||
|
||||
if (issue.locked) {
|
||||
if (issue.locked && this.options.exemptLocked) {
|
||||
issueLogger.info(`Skipping this $$type because it is locked`);
|
||||
IssuesProcessor._endIssueProcessing(issue);
|
||||
return; // Don't process locked issues
|
||||
|
@ -1196,7 +1196,9 @@ export class IssuesProcessor {
|
|||
const issueLogger: IssueLogger = new IssueLogger(issue);
|
||||
|
||||
issueLogger.info(
|
||||
`The $$type is not closed nor locked. Trying to remove the close label...`
|
||||
`The $$type is not closed${
|
||||
this.options.exemptLocked ? ' nor locked' : ''
|
||||
}. Trying to remove the close label...`
|
||||
);
|
||||
|
||||
if (!closeLabel) {
|
||||
|
|
|
@ -54,4 +54,5 @@ export interface IIssuesProcessorOptions {
|
|||
exemptDraftPr: boolean;
|
||||
closeIssueReason: string;
|
||||
includeOnlyAssigned: boolean;
|
||||
exemptLocked: boolean;
|
||||
}
|
||||
|
|
|
@ -123,7 +123,8 @@ function _getAndValidateArgs(): IIssuesProcessorOptions {
|
|||
ignorePrUpdates: _toOptionalBoolean('ignore-pr-updates'),
|
||||
exemptDraftPr: core.getInput('exempt-draft-pr') === 'true',
|
||||
closeIssueReason: core.getInput('close-issue-reason'),
|
||||
includeOnlyAssigned: core.getInput('include-only-assigned') === 'true'
|
||||
includeOnlyAssigned: core.getInput('include-only-assigned') === 'true',
|
||||
exemptLocked: core.getInput('exempt-locked') === 'true'
|
||||
};
|
||||
|
||||
for (const numberInput of ['days-before-stale']) {
|
||||
|
|
Loading…
Reference in New Issue