Remove labels on stale (#959)

This commit is contained in:
Milos Pantic 2023-03-21 13:11:19 +00:00 committed by GitHub
parent 01aa53266c
commit 75d4d955ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1398 additions and 1315 deletions

View File

@ -63,6 +63,7 @@ Every argument is optional.
| [remove-issue-stale-when-updated](#remove-issue-stale-when-updated) | Remove stale label from issues on updates/comments | |
| [remove-pr-stale-when-updated](#remove-pr-stale-when-updated) | Remove stale label from PRs on updates/comments | |
| [labels-to-add-when-unstale](#labels-to-add-when-unstale) | Add specified labels from issues/PRs when they become unstale | |
| [labels-to-remove-when-stale](#labels-to-remove-when-stale) | Remove specified labels from issues/PRs when they become stale | |
| [labels-to-remove-when-unstale](#labels-to-remove-when-unstale) | Remove specified labels from issues/PRs when they become unstale | |
| [debug-only](#debug-only) | Dry-run | `false` |
| [ascending](#ascending) | Order to get issues/PRs | `false` |
@ -358,6 +359,15 @@ A comma delimited list of labels to add when a stale issue or pull request recei
Default value: unset
#### labels-to-remove-when-stale
A comma delimited list of labels to remove when an issue or pull request becomes stale and has the [stale-issue-label](#stale-issue-label) or [stale-pr-label](#stale-pr-label) added to it.
Warning: each label results in a unique API call which can drastically consume the limit of [operations-per-run](#operations-per-run).
Default value: unset
Required Permission: `pull-requests: write`
#### labels-to-remove-when-unstale
A comma delimited list of labels to remove when a stale issue or pull request receives activity and has the [stale-issue-label](#stale-issue-label) or [stale-pr-label](#stale-pr-label) removed from it.

View File

@ -47,6 +47,7 @@ export const DefaultProcessorOptions: IIssuesProcessorOptions = Object.freeze({
exemptAllIssueAssignees: undefined,
exemptAllPrAssignees: undefined,
enableStatistics: true,
labelsToRemoveWhenStale: '',
labelsToRemoveWhenUnstale: '',
labelsToAddWhenUnstale: '',
ignoreUpdates: false,

View File

@ -1220,6 +1220,48 @@ test('when the option "labelsToAddWhenUnstale" is set, the labels should be adde
expect(processor.addedLabelIssues).toHaveLength(1);
});
test('when the option "labelsToRemoveWhenStale" is set, the labels should be removed when stale', async () => {
expect.assertions(3);
const opts = {
...DefaultProcessorOptions,
removeStaleWhenUpdated: true,
labelsToRemoveWhenStale: 'test'
};
const TestIssueList: Issue[] = [
generateIssue(
opts,
1,
'An issue that should have labels removed to it when stale',
'2020-01-01T17:00:00Z',
'2020-01-01T17:00:00Z',
false,
['Stale', 'test']
)
];
const processor = new IssuesProcessorMock(
opts,
async p => (p === 1 ? TestIssueList : []),
async () => [
{
user: {
login: 'notme',
type: 'User'
},
body: 'Body'
}
], // return a fake comment to indicate there was an update
async () => new Date().toDateString()
);
// process our fake issue list
await processor.processIssues(1);
expect(processor.closedIssues).toHaveLength(0);
expect(processor.staleIssues).toHaveLength(0);
// test label should have been removed
expect(processor.removedLabelIssues).toHaveLength(1);
});
test('stale label should not be removed if a comment was added by the bot (and the issue should be closed)', async () => {
const opts = {...DefaultProcessorOptions, removeStaleWhenUpdated: true};
github.context.actor = 'abot';

View File

@ -177,11 +177,15 @@ inputs:
default: 'true'
required: false
labels-to-add-when-unstale:
description: 'A comma delimited list of labels to add when a stale issue or pull request receives activity and has the stale-issue-label or stale-pr-label removed from it.'
description: 'A comma delimited list of labels to add when an issue or pull request becomes unstale.'
default: ''
required: false
labels-to-remove-when-stale:
description: 'A comma delimited list of labels to remove when an issue or pull request becomes stale.'
default: ''
required: false
labels-to-remove-when-unstale:
description: 'A comma delimited list of labels to remove when a stale issue or pull request receives activity and has the stale-issue-label or stale-pr-label removed from it.'
description: 'A comma delimited list of labels to remove when an issue or pull request becomes unstale.'
default: ''
required: false
ignore-updates:

2612
dist/index.js vendored

File diff suppressed because it is too large Load Diff

6
package-lock.json generated
View File

@ -1988,9 +1988,9 @@
}
},
"@types/jest": {
"version": "29.4.0",
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.4.0.tgz",
"integrity": "sha512-VaywcGQ9tPorCX/Jkkni7RWGFfI11whqzs8dvxF41P17Z+z872thvEvlIbznjPJ02kl1HMX3LmLOonsj2n7HeQ==",
"version": "29.4.4",
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.4.4.tgz",
"integrity": "sha512-qezb65VIH7X1wobSnd6Lvdve7PXSyQRa3dljTkhTtDhi603RvHQCshSlJcuyMLHJpeHgY3NKwvDJWxMOOHxGDQ==",
"dev": true,
"requires": {
"expect": "^29.0.0",

View File

@ -56,6 +56,7 @@ describe('Issue', (): void => {
exemptAllIssueAssignees: undefined,
exemptAllPrAssignees: undefined,
enableStatistics: false,
labelsToRemoveWhenStale: '',
labelsToRemoveWhenUnstale: '',
labelsToAddWhenUnstale: '',
ignoreUpdates: false,

View File

@ -123,6 +123,10 @@ export class IssuesProcessor {
);
}
const labelsToRemoveWhenStale: string[] = wordsToList(
this.options.labelsToRemoveWhenStale
);
const labelsToAddWhenUnstale: string[] = wordsToList(
this.options.labelsToAddWhenUnstale
);
@ -141,7 +145,8 @@ export class IssuesProcessor {
await this.processIssue(
issue,
labelsToAddWhenUnstale,
labelsToRemoveWhenUnstale
labelsToRemoveWhenUnstale,
labelsToRemoveWhenStale
);
});
}
@ -179,7 +184,8 @@ export class IssuesProcessor {
async processIssue(
issue: Issue,
labelsToAddWhenUnstale: Readonly<string>[],
labelsToRemoveWhenUnstale: Readonly<string>[]
labelsToRemoveWhenUnstale: Readonly<string>[],
labelsToRemoveWhenStale: Readonly<string>[]
): Promise<void> {
this.statistics?.incrementProcessedItemsCount(issue);
@ -509,6 +515,7 @@ export class IssuesProcessor {
staleMessage,
labelsToAddWhenUnstale,
labelsToRemoveWhenUnstale,
labelsToRemoveWhenStale,
closeMessage,
closeLabel
);
@ -623,6 +630,7 @@ export class IssuesProcessor {
staleMessage: string,
labelsToAddWhenUnstale: Readonly<string>[],
labelsToRemoveWhenUnstale: Readonly<string>[],
labelsToRemoveWhenStale: Readonly<string>[],
closeMessage?: string,
closeLabel?: string
) {
@ -671,6 +679,11 @@ export class IssuesProcessor {
if (issue.markedStaleThisRun) {
issueLogger.info(`marked stale this run, so don't check for updates`);
await this._removeLabelsOnStatusTransition(
issue,
labelsToRemoveWhenStale,
Option.LabelsToRemoveWhenStale
);
}
// The issue.updated_at and markedStaleOn are not always exactly in sync (they can be off by a second or 2)
@ -699,7 +712,11 @@ export class IssuesProcessor {
await this._removeStaleLabel(issue, staleLabel);
// Are there labels to remove or add when an issue is no longer stale?
await this._removeLabelsWhenUnstale(issue, labelsToRemoveWhenUnstale);
await this._removeLabelsOnStatusTransition(
issue,
labelsToRemoveWhenUnstale,
Option.LabelsToRemoveWhenUnstale
);
await this._addLabelsWhenUnstale(issue, labelsToAddWhenUnstale);
issueLogger.info(`Skipping the process since the $$type is now un-stale`);
@ -1074,9 +1091,10 @@ export class IssuesProcessor {
return this.options.removeStaleWhenUpdated;
}
private async _removeLabelsWhenUnstale(
private async _removeLabelsOnStatusTransition(
issue: Issue,
removeLabels: Readonly<string>[]
removeLabels: Readonly<string>[],
staleStatus: Option
): Promise<void> {
if (!removeLabels.length) {
return;
@ -1086,7 +1104,7 @@ export class IssuesProcessor {
issueLogger.info(
`Removing all the labels specified via the ${this._logger.createOptionLink(
Option.LabelsToRemoveWhenUnstale
staleStatus
)} option.`
);

View File

@ -41,6 +41,7 @@ export enum Option {
ExemptAllIssueAssignees = 'exempt-all-issue-assignees',
ExemptAllPrAssignees = 'exempt-all-pr-assignees',
EnableStatistics = 'enable-statistics',
LabelsToRemoveWhenStale = 'labels-to-remove-when-stale',
LabelsToRemoveWhenUnstale = 'labels-to-remove-when-unstale',
LabelsToAddWhenUnstale = 'labels-to-add-when-unstale',
IgnoreUpdates = 'ignore-updates',

View File

@ -45,6 +45,7 @@ export interface IIssuesProcessorOptions {
exemptAllIssueAssignees: boolean | undefined;
exemptAllPrAssignees: boolean | undefined;
enableStatistics: boolean;
labelsToRemoveWhenStale: string;
labelsToRemoveWhenUnstale: string;
labelsToAddWhenUnstale: string;
ignoreUpdates: boolean;

View File

@ -82,6 +82,7 @@ function _getAndValidateArgs(): IIssuesProcessorOptions {
exemptAllIssueAssignees: _toOptionalBoolean('exempt-all-issue-assignees'),
exemptAllPrAssignees: _toOptionalBoolean('exempt-all-pr-assignees'),
enableStatistics: core.getInput('enable-statistics') === 'true',
labelsToRemoveWhenStale: core.getInput('labels-to-remove-when-stale'),
labelsToRemoveWhenUnstale: core.getInput('labels-to-remove-when-unstale'),
labelsToAddWhenUnstale: core.getInput('labels-to-add-when-unstale'),
ignoreUpdates: core.getInput('ignore-updates') === 'true',