Skip to content

Commit

Permalink
feat(issue): stop processing an issue already stale
Browse files Browse the repository at this point in the history
  • Loading branch information
C0ZEN committed Nov 14, 2021
1 parent b6390da commit 3dbd799
Show file tree
Hide file tree
Showing 4 changed files with 296 additions and 6 deletions.
132 changes: 132 additions & 0 deletions src/core/issues/issue-is-stale-processor.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { IInputs } from '@core/inputs/inputs.interface';
import { InputsService } from '@core/inputs/inputs.service';
import { IssueIsStaleProcessor } from '@core/issues/issue-is-stale-processor';
import { IssueProcessor } from '@core/issues/issue-processor';
import { IGithubApiLabel } from '@github/api/labels/interfaces/github-api-label.interface';
import { createHydratedMock } from 'ts-auto-mock';

jest.mock(`@utils/loggers/logger.service`);
jest.mock(`@utils/loggers/logger-format.service`);

describe(`IssueIsStaleProcessor`, (): void => {
let issueProcessor: IssueProcessor;

beforeEach((): void => {
issueProcessor = createHydratedMock<IssueProcessor>();
});

describe(`constructor()`, (): void => {
it(`should save the given issue processor`, (): void => {
expect.assertions(1);

const result = new IssueIsStaleProcessor(issueProcessor);

expect(result.issueProcessor).toStrictEqual(issueProcessor);
});
});

describe(`after creation`, (): void => {
let issueIsStaleProcessor: IssueIsStaleProcessor;

beforeEach((): void => {
issueProcessor = createHydratedMock<IssueProcessor>({});
});

describe(`isStale()`, (): void => {
let issueProcessorLoggerInfoSpy: jest.SpyInstance;
let inputsServiceGetInputsSpy: jest.SpyInstance;

beforeEach((): void => {
issueIsStaleProcessor = new IssueIsStaleProcessor(issueProcessor);

issueProcessorLoggerInfoSpy = jest
.spyOn(issueIsStaleProcessor.issueProcessor.logger, `info`)
.mockImplementation();
inputsServiceGetInputsSpy = jest.spyOn(InputsService, `getInputs`).mockReturnValue(
createHydratedMock<IInputs>({
issueStaleLabel: `stale`,
})
);
});

it(`should check if the stale label is already added to this issue`, (): void => {
expect.assertions(4);

issueIsStaleProcessor.isStale();

expect(issueProcessorLoggerInfoSpy).toHaveBeenCalledTimes(2);
expect(issueProcessorLoggerInfoSpy).toHaveBeenNthCalledWith(1, `Checking if the issue is already stale...`);
expect(inputsServiceGetInputsSpy).toHaveBeenCalledTimes(1);
expect(inputsServiceGetInputsSpy).toHaveBeenCalledWith();
});

describe(`when the issue has already the stale label`, (): void => {
beforeEach((): void => {
issueProcessor = createHydratedMock<IssueProcessor>({
githubIssue: {
labels: {
nodes: [
createHydratedMock<IGithubApiLabel>({
name: `stale`,
}),
],
},
},
});
issueIsStaleProcessor = new IssueIsStaleProcessor(issueProcessor);

issueProcessorLoggerInfoSpy = jest
.spyOn(issueIsStaleProcessor.issueProcessor.logger, `info`)
.mockImplementation();
});

it(`should return true`, (): void => {
expect.assertions(3);

const result = issueIsStaleProcessor.isStale();

expect(issueProcessorLoggerInfoSpy).toHaveBeenCalledTimes(2);
expect(issueProcessorLoggerInfoSpy).toHaveBeenNthCalledWith(
2,
`The stale label is already added on this issue`
);
expect(result).toBeTrue();
});
});

describe(`when the issue does not have the stale label`, (): void => {
beforeEach((): void => {
issueProcessor = createHydratedMock<IssueProcessor>({
githubIssue: {
labels: {
nodes: [
createHydratedMock<IGithubApiLabel>({
name: `marco`,
}),
createHydratedMock<IGithubApiLabel>({
name: `polo`,
}),
],
},
},
});
issueIsStaleProcessor = new IssueIsStaleProcessor(issueProcessor);

issueProcessorLoggerInfoSpy = jest
.spyOn(issueIsStaleProcessor.issueProcessor.logger, `info`)
.mockImplementation();
});

it(`should return false`, (): void => {
expect.assertions(3);

const result = issueIsStaleProcessor.isStale();

expect(issueProcessorLoggerInfoSpy).toHaveBeenCalledTimes(2);
expect(issueProcessorLoggerInfoSpy).toHaveBeenNthCalledWith(2, `The stale label is not yet on this issue`);
expect(result).toBeFalse();
});
});
});
});
});
39 changes: 39 additions & 0 deletions src/core/issues/issue-is-stale-processor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { InputsService } from '@core/inputs/inputs.service';
import { IssueProcessor } from '@core/issues/issue-processor';
import { IGithubApiLabel } from '@github/api/labels/interfaces/github-api-label.interface';

/**
* @description
* The processor to check if an issue is stale
*/
export class IssueIsStaleProcessor {
public readonly issueProcessor: IssueProcessor;

public constructor(issueProcessor: Readonly<IssueProcessor>) {
this.issueProcessor = issueProcessor;
}

public isStale(): boolean {
this.issueProcessor.logger.info(`Checking if the issue is already stale...`);

const staleLabel: IGithubApiLabel | undefined = this._getStaleLabel();

if (staleLabel) {
this.issueProcessor.logger.info(`The stale label is already added on this issue`);

return true;
}

this.issueProcessor.logger.info(`The stale label is not yet on this issue`);

return false;
}

private _getStaleLabel(): IGithubApiLabel | undefined {
const { issueStaleLabel } = InputsService.getInputs();

return this.issueProcessor.githubIssue.labels.nodes.find(
(label: Readonly<IGithubApiLabel>): boolean => label.name === issueStaleLabel
);
}
}
105 changes: 99 additions & 6 deletions src/core/issues/issue-processor.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { IssueIgnoreProcessor } from '@core/issues/issue-ignore-processor';
import { IssueIsStaleProcessor } from '@core/issues/issue-is-stale-processor';
import { IssueLogger } from '@core/issues/issue-logger';
import { IssueProcessor } from '@core/issues/issue-processor';
import { IssueStaleProcessor } from '@core/issues/issue-stale-processor';
Expand Down Expand Up @@ -61,6 +62,8 @@ describe(`IssueProcessor`, (): void => {
let loggerStartGroupSpy: jest.SpyInstance;
let stopProcessingSpy: jest.SpyInstance;
let shouldIgnoreSpy: jest.SpyInstance;
let isAlreadyStaleSpy: jest.SpyInstance;
let processToRemoveStaleSpy: jest.SpyInstance;
let processForStaleSpy: jest.SpyInstance;
let loggerInfoSpy: jest.SpyInstance;
let createLinkSpy: jest.SpyInstance;
Expand All @@ -69,6 +72,8 @@ describe(`IssueProcessor`, (): void => {
loggerStartGroupSpy = jest.spyOn(issueProcessor.logger, `startGroup`).mockImplementation();
stopProcessingSpy = jest.spyOn(issueProcessor, `stopProcessing$$`).mockImplementation();
shouldIgnoreSpy = jest.spyOn(issueProcessor, `shouldIgnore$$`).mockImplementation();
isAlreadyStaleSpy = jest.spyOn(issueProcessor, `isAlreadyStale$$`).mockImplementation();
processToRemoveStaleSpy = jest.spyOn(issueProcessor, `processToRemoveStale$$`).mockImplementation();
processForStaleSpy = jest.spyOn(issueProcessor, `processForStale$$`).mockImplementation();
loggerInfoSpy = jest.spyOn(issueProcessor.logger, `info`).mockImplementation();
createLinkSpy = jest.spyOn(CreateLinkModule, `createLink`).mockReturnValue(`dummy-link`);
Expand Down Expand Up @@ -109,12 +114,14 @@ describe(`IssueProcessor`, (): void => {
});

it(`should stop to process this issue`, async (): Promise<void> => {
expect.assertions(3);
expect.assertions(5);

await issueProcessor.process();

expect(stopProcessingSpy).toHaveBeenCalledTimes(1);
expect(stopProcessingSpy).toHaveBeenCalledWith();
expect(isAlreadyStaleSpy).not.toHaveBeenCalled();
expect(processToRemoveStaleSpy).not.toHaveBeenCalled();
expect(processForStaleSpy).not.toHaveBeenCalled();
});
});
Expand All @@ -124,14 +131,50 @@ describe(`IssueProcessor`, (): void => {
shouldIgnoreSpy.mockReturnValue(false);
});

it(`should really process the issue for the stale checks`, async (): Promise<void> => {
expect.assertions(3);
it(`should check if the issue is already stale`, async (): Promise<void> => {
expect.assertions(2);

await issueProcessor.process();

expect(processForStaleSpy).toHaveBeenCalledTimes(1);
expect(processForStaleSpy).toHaveBeenCalledWith();
expect(stopProcessingSpy).not.toHaveBeenCalled();
expect(isAlreadyStaleSpy).toHaveBeenCalledTimes(1);
expect(isAlreadyStaleSpy).toHaveBeenCalledWith();
});

describe(`when the issue is already stale`, (): void => {
beforeEach((): void => {
isAlreadyStaleSpy.mockReturnValue(true);
});

it(`should try to remove the stale state (if conditions are met)`, async (): Promise<void> => {
expect.assertions(7);

await issueProcessor.process();

expect(processToRemoveStaleSpy).toHaveBeenCalledTimes(1);
expect(processToRemoveStaleSpy).toHaveBeenCalledWith();
expect(processForStaleSpy).toHaveBeenCalledTimes(1);
expect(processForStaleSpy).toHaveBeenCalledWith();
expect(loggerInfoSpy).toHaveBeenCalledTimes(1);
expect(loggerInfoSpy).toHaveBeenCalledWith(`Already stale`);
expect(processForStaleSpy).not.toHaveBeenCalled();
});
});

describe(`when the issue is not stale yet`, (): void => {
beforeEach((): void => {
isAlreadyStaleSpy.mockReturnValue(false);
});

it(`should really process the issue for the stale checks`, async (): Promise<void> => {
expect.assertions(4);

await issueProcessor.process();

expect(processForStaleSpy).toHaveBeenCalledTimes(1);
expect(processForStaleSpy).toHaveBeenCalledWith();
expect(processToRemoveStaleSpy).not.toHaveBeenCalled();
expect(stopProcessingSpy).not.toHaveBeenCalled();
});
});
});
});
Expand Down Expand Up @@ -315,5 +358,55 @@ describe(`IssueProcessor`, (): void => {
});
});
});

describe(`isAlreadyStale$$()`, (): void => {
const mockIssueIsStaleProcessor: MockedObjectDeep<typeof IssueIsStaleProcessor> = mocked(
IssueIsStaleProcessor,
true
);

beforeEach((): void => {
mockIssueIsStaleProcessor.mockClear();
});

it(`should check if the issue is already stale`, (): void => {
expect.assertions(4);

issueProcessor.isAlreadyStale$$();

expect(mockIssueIsStaleProcessor).toHaveBeenCalledTimes(1);
expect(mockIssueIsStaleProcessor).toHaveBeenCalledWith(issueProcessor);
expect(mockIssueIsStaleProcessor.prototype.isStale.mock.calls).toHaveLength(1);
expect(mockIssueIsStaleProcessor.prototype.isStale.mock.calls[0]).toHaveLength(0);
});

describe(`when the issue is not stale`, (): void => {
beforeEach((): void => {
mockIssueIsStaleProcessor.prototype.isStale.mockImplementation().mockResolvedValue(false);
});

it(`should return false`, (): void => {
expect.assertions(1);

const result = issueProcessor.isAlreadyStale$$();

expect(result).toBeFalse();
});
});

describe(`when the issue is already stale`, (): void => {
beforeEach((): void => {
mockIssueIsStaleProcessor.prototype.isStale.mockImplementation().mockResolvedValue(true);
});

it(`should return true`, (): void => {
expect.assertions(1);

const result = issueProcessor.isAlreadyStale$$();

expect(result).toBeTrue();
});
});
});
});
});
26 changes: 26 additions & 0 deletions src/core/issues/issue-processor.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { IssueIgnoreProcessor } from '@core/issues/issue-ignore-processor';
import { IssueIsStaleProcessor } from '@core/issues/issue-is-stale-processor';
import { IssueLogger } from '@core/issues/issue-logger';
import { IssueStaleProcessor } from '@core/issues/issue-stale-processor';
import { IGithubApiIssue } from '@github/api/issues/interfaces/github-api-issue.interface';
Expand All @@ -7,6 +8,10 @@ import { LoggerFormatService } from '@utils/loggers/logger-format.service';
import _ from 'lodash';
import { DateTime } from 'luxon';

/**
* @description
* The main processor to process an issue
*/
export class IssueProcessor {
public readonly githubIssue: IGithubApiIssue;
public readonly logger: IssueLogger;
Expand Down Expand Up @@ -36,6 +41,17 @@ export class IssueProcessor {
return;
}

if (this.isAlreadyStale$$()) {
this.logger.info(`Already stale`);

this.processToRemoveStale$$();

// @todo add the closing logic here
this.stopProcessing$$();

return;
}

return this.processForStale$$();
}

Expand Down Expand Up @@ -73,4 +89,14 @@ export class IssueProcessor {

this.stopProcessing$$();
}

public isAlreadyStale$$(): boolean {
const issueIsStaleProcessor: IssueIsStaleProcessor = new IssueIsStaleProcessor(this);

return issueIsStaleProcessor.isStale();
}

public processToRemoveStale$$(): boolean {
return false;
}
}

0 comments on commit 3dbd799

Please sign in to comment.