mirror of
https://github.com/actions/stale.git
synced 2026-02-11 08:38:17 +00:00
feat: enhance IssuesProcessor to return label creation date and events, add stale label event checks
This commit is contained in:
@@ -4,6 +4,7 @@ import {IComment} from '../../src/interfaces/comment';
|
||||
import {IIssuesProcessorOptions} from '../../src/interfaces/issues-processor-options';
|
||||
import {IPullRequest} from '../../src/interfaces/pull-request';
|
||||
import {IState} from '../../src/interfaces/state/state';
|
||||
import {IIssueEvent} from '../../src/interfaces/issue-event';
|
||||
|
||||
export class IssuesProcessorMock extends IssuesProcessor {
|
||||
constructor(
|
||||
@@ -17,7 +18,15 @@ export class IssuesProcessorMock extends IssuesProcessor {
|
||||
getLabelCreationDate?: (
|
||||
issue: Issue,
|
||||
label: string
|
||||
) => Promise<string | undefined>,
|
||||
) =>
|
||||
| Promise<string | undefined>
|
||||
| Promise<{creationDate?: string; events: IIssueEvent[]}>,
|
||||
hasOnlyStaleLabelingEventsSince?: (
|
||||
issue: Issue,
|
||||
sinceDate: string,
|
||||
staleLabel: string,
|
||||
events: IIssueEvent[]
|
||||
) => Promise<boolean>,
|
||||
getPullRequest?: (issue: Issue) => Promise<IPullRequest | undefined | void>
|
||||
) {
|
||||
super(options, state);
|
||||
@@ -31,7 +40,21 @@ export class IssuesProcessorMock extends IssuesProcessor {
|
||||
}
|
||||
|
||||
if (getLabelCreationDate) {
|
||||
this.getLabelCreationDate = getLabelCreationDate;
|
||||
this.getLabelCreationDate = async (
|
||||
issue: Issue,
|
||||
label: string
|
||||
): Promise<{creationDate?: string; events: IIssueEvent[]}> => {
|
||||
const result = await getLabelCreationDate(issue, label);
|
||||
if (typeof result === 'string' || typeof result === 'undefined') {
|
||||
return {creationDate: result, events: []};
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
if (hasOnlyStaleLabelingEventsSince) {
|
||||
this.hasOnlyStaleLabelingEventsSince = hasOnlyStaleLabelingEventsSince;
|
||||
}
|
||||
|
||||
if (getPullRequest) {
|
||||
|
||||
@@ -129,6 +129,7 @@ class IssuesProcessorBuilder {
|
||||
async p => (p === 1 ? this._issues : []),
|
||||
async () => [],
|
||||
async () => new Date().toDateString(),
|
||||
undefined,
|
||||
async (): Promise<IPullRequest> => {
|
||||
return Promise.resolve({
|
||||
number: 0,
|
||||
|
||||
288
__tests__/remove-stale-when-updated-label-events.spec.ts
Normal file
288
__tests__/remove-stale-when-updated-label-events.spec.ts
Normal file
@@ -0,0 +1,288 @@
|
||||
import {Issue} from '../src/classes/issue';
|
||||
import {IIssuesProcessorOptions} from '../src/interfaces/issues-processor-options';
|
||||
import {IssuesProcessorMock} from './classes/issues-processor-mock';
|
||||
import {DefaultProcessorOptions} from './constants/default-processor-options';
|
||||
import {generateIssue} from './functions/generate-issue';
|
||||
import {alwaysFalseStateMock} from './classes/state-mock';
|
||||
import {IState} from '../src/interfaces/state/state';
|
||||
import {IIssueEvent} from '../src/interfaces/issue-event';
|
||||
import {IssuesProcessor} from '../src/classes/issues-processor';
|
||||
|
||||
describe('remove-stale-when-updated with stale label events', (): void => {
|
||||
const markedStaleOn = '2025-01-01T00:00:00Z';
|
||||
const updatedAt = '2025-01-01T00:01:00Z';
|
||||
|
||||
let options: IIssuesProcessorOptions;
|
||||
|
||||
beforeEach((): void => {
|
||||
options = {
|
||||
...DefaultProcessorOptions,
|
||||
removeStaleWhenUpdated: true
|
||||
};
|
||||
});
|
||||
|
||||
const buildIssue = (): Issue =>
|
||||
generateIssue(
|
||||
options,
|
||||
1,
|
||||
'dummy-title',
|
||||
updatedAt,
|
||||
markedStaleOn,
|
||||
false,
|
||||
false,
|
||||
['Stale']
|
||||
);
|
||||
|
||||
const buildEvents = (): IIssueEvent[] => [
|
||||
{
|
||||
event: 'labeled',
|
||||
created_at: markedStaleOn,
|
||||
label: {name: 'Stale'}
|
||||
}
|
||||
];
|
||||
|
||||
test('does not remove stale label when only stale label events occurred', async (): Promise<void> => {
|
||||
expect.assertions(1);
|
||||
const issue = buildIssue();
|
||||
|
||||
const processor = new IssuesProcessorMock(
|
||||
options,
|
||||
alwaysFalseStateMock,
|
||||
async p => (p === 1 ? [issue] : []),
|
||||
async () => [],
|
||||
async () => ({creationDate: markedStaleOn, events: buildEvents()}),
|
||||
async () => true
|
||||
);
|
||||
|
||||
await processor.processIssues();
|
||||
|
||||
expect(processor.removedLabelIssues).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('removes stale label when updates are not just stale label events', async (): Promise<void> => {
|
||||
expect.assertions(1);
|
||||
const issue = buildIssue();
|
||||
|
||||
const processor = new IssuesProcessorMock(
|
||||
options,
|
||||
alwaysFalseStateMock,
|
||||
async p => (p === 1 ? [issue] : []),
|
||||
async () => [],
|
||||
async () => ({creationDate: markedStaleOn, events: buildEvents()}),
|
||||
async () => false
|
||||
);
|
||||
|
||||
await processor.processIssues();
|
||||
|
||||
expect(processor.removedLabelIssues).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
class TestIssuesProcessor extends IssuesProcessor {
|
||||
constructor(
|
||||
options: IIssuesProcessorOptions,
|
||||
state: IState,
|
||||
events: IIssueEvent[]
|
||||
) {
|
||||
super(options, state);
|
||||
const client = {
|
||||
rest: {
|
||||
issues: {
|
||||
listEvents: {
|
||||
endpoint: {
|
||||
merge: () => ({})
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
paginate: {
|
||||
iterator: async function* () {
|
||||
yield {data: events};
|
||||
}
|
||||
}
|
||||
};
|
||||
(this as any).client = client;
|
||||
}
|
||||
|
||||
async callhasOnlyStaleLabelingEventsSince(
|
||||
issue: Issue,
|
||||
sinceDate: string,
|
||||
staleLabel: string,
|
||||
events: IIssueEvent[]
|
||||
): Promise<boolean> {
|
||||
return this.hasOnlyStaleLabelingEventsSince(
|
||||
issue,
|
||||
sinceDate,
|
||||
staleLabel,
|
||||
events
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
describe('hasOnlyStaleLabelingEventsSince', (): void => {
|
||||
const staleLabel = 'Stale';
|
||||
const sinceDate = '2025-01-01T00:00:00Z';
|
||||
const originalRepo = process.env.GITHUB_REPOSITORY;
|
||||
|
||||
let options: IIssuesProcessorOptions;
|
||||
|
||||
beforeEach((): void => {
|
||||
process.env.GITHUB_REPOSITORY = 'owner/repo';
|
||||
options = {
|
||||
...DefaultProcessorOptions,
|
||||
staleIssueLabel: staleLabel,
|
||||
removeStaleWhenUpdated: true
|
||||
};
|
||||
});
|
||||
|
||||
afterEach((): void => {
|
||||
if (originalRepo === undefined) {
|
||||
delete process.env.GITHUB_REPOSITORY;
|
||||
} else {
|
||||
process.env.GITHUB_REPOSITORY = originalRepo;
|
||||
}
|
||||
});
|
||||
|
||||
const buildIssue = (): Issue =>
|
||||
generateIssue(
|
||||
options,
|
||||
1,
|
||||
'dummy-title',
|
||||
'2025-01-01T00:02:00Z',
|
||||
sinceDate,
|
||||
false,
|
||||
false,
|
||||
[staleLabel]
|
||||
);
|
||||
|
||||
test('returns true when only stale label events exist after the since date', async (): Promise<void> => {
|
||||
expect.assertions(1);
|
||||
const issue = buildIssue();
|
||||
const events: IIssueEvent[] = [
|
||||
// Event before the sinceDate should be ignored.
|
||||
{
|
||||
event: 'labeled',
|
||||
created_at: '2024-12-31T23:59:00Z',
|
||||
label: {name: staleLabel}
|
||||
},
|
||||
{
|
||||
event: 'labeled',
|
||||
created_at: '2025-01-01T00:00:10Z',
|
||||
label: {name: staleLabel}
|
||||
}
|
||||
];
|
||||
const processor = new TestIssuesProcessor(
|
||||
options,
|
||||
alwaysFalseStateMock,
|
||||
events
|
||||
);
|
||||
const result = await processor.callhasOnlyStaleLabelingEventsSince(
|
||||
issue,
|
||||
sinceDate,
|
||||
staleLabel,
|
||||
events
|
||||
);
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
test('returns false when a non-stale label event exists after the since date', async (): Promise<void> => {
|
||||
expect.assertions(1);
|
||||
const issue = buildIssue();
|
||||
const events: IIssueEvent[] = [
|
||||
{
|
||||
event: 'labeled',
|
||||
created_at: '2025-01-01T00:00:10Z',
|
||||
label: {name: 'other-label'}
|
||||
}
|
||||
];
|
||||
const processor = new TestIssuesProcessor(
|
||||
options,
|
||||
alwaysFalseStateMock,
|
||||
events
|
||||
);
|
||||
const result = await processor.callhasOnlyStaleLabelingEventsSince(
|
||||
issue,
|
||||
sinceDate,
|
||||
staleLabel,
|
||||
events
|
||||
);
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
test('returns false when stale label is removed after the since date', async (): Promise<void> => {
|
||||
expect.assertions(1);
|
||||
const issue = buildIssue();
|
||||
const events: IIssueEvent[] = [
|
||||
{
|
||||
event: 'unlabeled',
|
||||
created_at: '2025-01-01T00:00:10Z',
|
||||
label: {name: staleLabel}
|
||||
}
|
||||
];
|
||||
const processor = new TestIssuesProcessor(
|
||||
options,
|
||||
alwaysFalseStateMock,
|
||||
events
|
||||
);
|
||||
const result = await processor.callhasOnlyStaleLabelingEventsSince(
|
||||
issue,
|
||||
sinceDate,
|
||||
staleLabel,
|
||||
events
|
||||
);
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
test('returns false when a non-label event exists after the since date', async (): Promise<void> => {
|
||||
expect.assertions(1);
|
||||
const issue = buildIssue();
|
||||
const events: IIssueEvent[] = [
|
||||
{
|
||||
event: 'commented',
|
||||
created_at: '2025-01-01T00:00:10Z',
|
||||
label: {name: staleLabel}
|
||||
}
|
||||
];
|
||||
const processor = new TestIssuesProcessor(
|
||||
options,
|
||||
alwaysFalseStateMock,
|
||||
events
|
||||
);
|
||||
const result = await processor.callhasOnlyStaleLabelingEventsSince(
|
||||
issue,
|
||||
sinceDate,
|
||||
staleLabel,
|
||||
events
|
||||
);
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
test('includes events that occur exactly at the since date boundary', async (): Promise<void> => {
|
||||
expect.assertions(1);
|
||||
const issue = buildIssue();
|
||||
const events: IIssueEvent[] = [
|
||||
{
|
||||
event: 'labeled',
|
||||
created_at: sinceDate,
|
||||
label: {name: staleLabel}
|
||||
}
|
||||
];
|
||||
const processor = new TestIssuesProcessor(
|
||||
options,
|
||||
alwaysFalseStateMock,
|
||||
events
|
||||
);
|
||||
const result = await processor.callhasOnlyStaleLabelingEventsSince(
|
||||
issue,
|
||||
sinceDate,
|
||||
staleLabel,
|
||||
events
|
||||
);
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user