Skip to content

Commit

Permalink
feat(stale): stale locally the issues older than 30 days
Browse files Browse the repository at this point in the history
  • Loading branch information
C0ZEN committed Nov 10, 2021
1 parent d849715 commit c5af87c
Show file tree
Hide file tree
Showing 6 changed files with 253 additions and 8 deletions.
27 changes: 27 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
"@octokit/webhooks-definitions": "3.67.3",
"ansi-styles": "6.1.0",
"lodash": "4.17.21",
"luxon": "2.1.1",
"terminal-link": "3.0.0",
"tslib": "2.3.1"
},
Expand All @@ -109,6 +110,7 @@
"@types/faker": "5.5.9",
"@types/jest": "27.0.2",
"@types/lodash": "4.14.176",
"@types/luxon": "2.0.7",
"@types/node": "14.17.33",
"@typescript-eslint/eslint-plugin": "4.33.0",
"@typescript-eslint/parser": "4.33.0",
Expand Down
120 changes: 114 additions & 6 deletions src/core/issues/issue-processor.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { IssueIgnoreProcessor } from '@core/issues/issue-ignore-processor';
import { IssueLogger } from '@core/issues/issue-logger';
import { IssueProcessor } from '@core/issues/issue-processor';
import { IssueStaleProcessor } from '@core/issues/issue-stale-processor';
import { IGithubApiIssue } from '@github/api/issues/github-api-issue.interface';
import * as CreateLinkModule from '@utils/links/create-link';
import { DateTime } from 'luxon';
import { createHydratedMock } from 'ts-auto-mock';
import { MockedObjectDeep } from 'ts-jest/dist/utils/testing';
import { mocked } from 'ts-jest/utils';
Expand All @@ -11,8 +13,9 @@ jest.mock(`@utils/loggers/logger.service`);
jest.mock(`@utils/loggers/logger-format.service`);
jest.mock(`@core/issues/issue-logger`);
jest.mock(`@core/issues/issue-ignore-processor`);
jest.mock(`@core/issues/issue-stale-processor`);

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

beforeEach((): void => {
Expand Down Expand Up @@ -58,13 +61,15 @@ describe(`IssueProcessor`, (): void => {
let loggerStartGroupSpy: jest.SpyInstance;
let stopProcessingSpy: jest.SpyInstance;
let shouldIgnoreSpy: jest.SpyInstance;
let processForStaleSpy: jest.SpyInstance;
let loggerInfoSpy: jest.SpyInstance;
let createLinkSpy: jest.SpyInstance;

beforeEach((): void => {
loggerStartGroupSpy = jest.spyOn(issueProcessor.logger, `startGroup`).mockImplementation();
stopProcessingSpy = jest.spyOn(issueProcessor, `stopProcessing$$`).mockImplementation();
shouldIgnoreSpy = jest.spyOn(issueProcessor, `shouldIgnore$$`).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 @@ -104,12 +109,13 @@ describe(`IssueProcessor`, (): void => {
});

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

await issueProcessor.process();

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

Expand All @@ -118,13 +124,51 @@ describe(`IssueProcessor`, (): void => {
shouldIgnoreSpy.mockReturnValue(false);
});

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

await issueProcessor.process();

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

describe(`getUpdatedAt()`, (): void => {
describe(`when the creation date of the issue is invalid`, (): void => {
beforeEach((): void => {
issueProcessor = new IssueProcessor(
createHydratedMock<IGithubApiIssue>({
updatedAt: `dummy-wrong-date`,
})
);
});

it(`should throw an error`, (): void => {
expect.assertions(1);

expect((): DateTime => issueProcessor.getUpdatedAt()).toThrow(new Error(`unparsable`));
});
});

describe(`when the creation date of the issue is valid`, (): void => {
beforeEach((): void => {
issueProcessor = new IssueProcessor(
createHydratedMock<IGithubApiIssue>({
updatedAt: DateTime.now().toISO(),
})
);
});

it(`should return the creation date as a date time class`, (): void => {
expect.assertions(2);

const result = issueProcessor.getUpdatedAt();

expect(result).toBeInstanceOf(DateTime);
expect(result.equals(DateTime.now())).toBeTrue();
});
});
});
Expand Down Expand Up @@ -165,6 +209,7 @@ describe(`IssueProcessor`, (): void => {

beforeEach((): void => {
mockIssueIgnoreProcessor.mockClear();

mockIssueIgnoreProcessor.prototype.shouldIgnore.mockImplementation().mockReturnValue(false);
});

Expand Down Expand Up @@ -207,5 +252,68 @@ describe(`IssueProcessor`, (): void => {
});
});
});

describe(`processForStale$$()`, (): void => {
const mockIssueStaleProcessor: MockedObjectDeep<typeof IssueStaleProcessor> = mocked(IssueStaleProcessor, true);

let stopProcessingSpy: jest.SpyInstance;

beforeEach((): void => {
mockIssueStaleProcessor.mockClear();

stopProcessingSpy = jest.spyOn(issueProcessor, `stopProcessing$$`).mockImplementation();
});

it(`should check if the issue should be stale`, async (): Promise<void> => {
expect.assertions(4);

await issueProcessor.processForStale$$();

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

describe(`when the issue should not be stale`, (): void => {
beforeEach((): void => {
mockIssueStaleProcessor.prototype.shouldBeStale.mockImplementation().mockReturnValue(false);
});

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

await issueProcessor.processForStale$$();

expect(mockIssueStaleProcessor.prototype.stale).not.toHaveBeenCalled();
expect(stopProcessingSpy).toHaveBeenCalledTimes(1);
expect(stopProcessingSpy).toHaveBeenCalledWith();
});
});

describe(`when the issue should be stale`, (): void => {
beforeEach((): void => {
mockIssueStaleProcessor.prototype.shouldBeStale.mockImplementation().mockReturnValue(true);
});

it(`should stale the issue`, async (): Promise<void> => {
expect.assertions(2);

await issueProcessor.processForStale$$();

expect(mockIssueStaleProcessor.prototype.stale.mock.calls).toHaveLength(1);
expect(mockIssueStaleProcessor.prototype.stale.mock.calls[0]).toHaveLength(0);
});

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

await issueProcessor.processForStale$$();

expect(stopProcessingSpy).toHaveBeenCalledTimes(1);
expect(stopProcessingSpy).toHaveBeenCalledWith();
});
});
});
});
});
37 changes: 35 additions & 2 deletions src/core/issues/issue-processor.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { IssueIgnoreProcessor } from '@core/issues/issue-ignore-processor';
import { IssueLogger } from '@core/issues/issue-logger';
import { IssueStaleProcessor } from '@core/issues/issue-stale-processor';
import { IGithubApiIssue } from '@github/api/issues/github-api-issue.interface';
import { createLink } from '@utils/links/create-link';
import { LoggerFormatService } from '@utils/loggers/logger-format.service';
import _ from 'lodash';
import { DateTime } from 'luxon';

export class IssueProcessor {
public readonly githubIssue: IGithubApiIssue;
Expand All @@ -14,6 +16,11 @@ export class IssueProcessor {
this.logger = new IssueLogger(this.githubIssue.number);
}

/**
* @description
* First step to process an issue
* @returns {Promise<void>}
*/
public async process(): Promise<void> {
this.logger.startGroup(
`Processing the issue`,
Expand All @@ -29,9 +36,17 @@ export class IssueProcessor {
return;
}

this.stopProcessing$$();
return this.processForStale$$();
}

return Promise.resolve();
public getUpdatedAt(): DateTime {
const dateTime: DateTime = DateTime.fromISO(this.githubIssue.updatedAt);

if (_.isString(dateTime.invalidReason)) {
throw new Error(dateTime.invalidReason);
}

return dateTime;
}

public stopProcessing$$(): void {
Expand All @@ -42,4 +57,22 @@ export class IssueProcessor {
public shouldIgnore$$(): boolean {
return new IssueIgnoreProcessor(this).shouldIgnore();
}

/**
* @description
* Second step to process an issue
* At this point, the issue can really be processed (not ignored)
* @returns {Promise<void>}
*/
public processForStale$$(): Promise<void> {
const issueStaleProcessor: IssueStaleProcessor = new IssueStaleProcessor(this);

if (issueStaleProcessor.shouldBeStale()) {
issueStaleProcessor.stale();
}

this.stopProcessing$$();

return Promise.resolve();
}
}
44 changes: 44 additions & 0 deletions src/core/issues/issue-stale-processor.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { IssueProcessor } from '@core/issues/issue-processor';
import { IssueStaleProcessor } from '@core/issues/issue-stale-processor';
import { createHydratedMock } from 'ts-auto-mock';

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

describe(`issueStaleProcessor`, (): 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 IssueStaleProcessor(issueProcessor);

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

describe(`after creation`, (): void => {
let issueStaleProcessor: IssueStaleProcessor;

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

describe(`shouldBeStale()`, (): void => {
beforeEach((): void => {});

it.todo(``);
});

describe(`isStaleByUpdateDate$$()`, (): void => {
beforeEach((): void => {});

it.todo(``);
});
});
});

0 comments on commit c5af87c

Please sign in to comment.