mirror of
https://github.com/actions/stale.git
synced 2025-12-11 04:32:53 +00:00
feat(logs): add a new log when an issue consumed at least one operation (#386)
* docs(only-labels): enhance the docs and fix duplicate (#341) * docs(only-labels): remove duplicated option and improve descriptions a bad rebase happend * docs(readme): use a multi-line array and remove the optional column the option column was not helpful since each value is optional the multi-line array will allow to have a better UI in small devices and basically in GitHub too due to the max-width * style(readme): break line for the statistics * docs(readme): add a better description for the ascending option * docs(action): add missing punctuation * build(deps-dev): bump @typescript-eslint/eslint-plugin (#342) Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 4.15.2 to 4.16.1. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v4.16.1/packages/eslint-plugin) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @octokit/rest from 18.3.0 to 18.3.2 (#350) Bumps [@octokit/rest](https://github.com/octokit/rest.js) from 18.3.0 to 18.3.2. - [Release notes](https://github.com/octokit/rest.js/releases) - [Commits](https://github.com/octokit/rest.js/compare/v18.3.0...v18.3.2) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * test: add more coverage for the stale label behaviour (#352) (#15) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * test: add more coverage for the stale label behaviour (#352) (#17) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * test: add more coverage for the stale label behaviour (#352) (#18) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * docs(operations-per-run): improve the doc for this option * feat(logs): add a new log when an issue consumed at least one operation the log will be visible as the last row of the processing of the given issue closes #348 * chore(readme): improve the operations per run Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> * chore(readme): improve the operations per run Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> * chore(readme): improve the operations per run Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> * chore(readme): improve the operations per run Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> * chore(readme): improve the operations per run Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> * chore(readme): improve the operations per run Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> * Typo in how to perform check for specific labels (#357) Not tests but feels like a typo. Or if we keep the title it `exempt` feels more approriate: exempt-issue-labels: 'roadmap' exempt-pr-labels: 'roadmap' * feat(any-of-labels): add 2 new options to customize for issues/PRs (#380) * docs(only-labels): enhance the docs and fix duplicate (#341) * docs(only-labels): remove duplicated option and improve descriptions a bad rebase happend * docs(readme): use a multi-line array and remove the optional column the option column was not helpful since each value is optional the multi-line array will allow to have a better UI in small devices and basically in GitHub too due to the max-width * style(readme): break line for the statistics * docs(readme): add a better description for the ascending option * docs(action): add missing punctuation * build(deps-dev): bump @typescript-eslint/eslint-plugin (#342) Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 4.15.2 to 4.16.1. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v4.16.1/packages/eslint-plugin) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @octokit/rest from 18.3.0 to 18.3.2 (#350) Bumps [@octokit/rest](https://github.com/octokit/rest.js) from 18.3.0 to 18.3.2. - [Release notes](https://github.com/octokit/rest.js/releases) - [Commits](https://github.com/octokit/rest.js/compare/v18.3.0...v18.3.2) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * test: add more coverage for the stale label behaviour (#352) (#15) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * test: add more coverage for the stale label behaviour (#352) (#17) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * test: add more coverage for the stale label behaviour (#352) (#18) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * feat(any-of-labels): add 2 new options to customize for issues/PRs closes #371 change this option and only-labels to have tree-logs * chore(index): update it Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * feat(logs): enhance the logs for assignees and milestones (#382) * docs(only-labels): enhance the docs and fix duplicate (#341) * docs(only-labels): remove duplicated option and improve descriptions a bad rebase happend * docs(readme): use a multi-line array and remove the optional column the option column was not helpful since each value is optional the multi-line array will allow to have a better UI in small devices and basically in GitHub too due to the max-width * style(readme): break line for the statistics * docs(readme): add a better description for the ascending option * docs(action): add missing punctuation * build(deps-dev): bump @typescript-eslint/eslint-plugin (#342) Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 4.15.2 to 4.16.1. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v4.16.1/packages/eslint-plugin) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @octokit/rest from 18.3.0 to 18.3.2 (#350) Bumps [@octokit/rest](https://github.com/octokit/rest.js) from 18.3.0 to 18.3.2. - [Release notes](https://github.com/octokit/rest.js/releases) - [Commits](https://github.com/octokit/rest.js/compare/v18.3.0...v18.3.2) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * test: add more coverage for the stale label behaviour (#352) (#15) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * test: add more coverage for the stale label behaviour (#352) (#17) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * test: add more coverage for the stale label behaviour (#352) (#18) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * feat(logs): enhance the logs for assignees and milestones closes #381 Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * style(typo): fix typo plural issue * style(naming): rename two methods * chore(error): remove a potential useless throw of error * style(naming): rename one method * refactor(issue): change the way to count the operations * refactor(operations): create a method to reduce code duplication Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> Co-authored-by: Romain Rigaux <romain.rigaux@gmail.com>
This commit is contained in:
committed by
GitHub
parent
440fb174b5
commit
c11507e9b7
@@ -6,6 +6,7 @@ import {IIssuesProcessorOptions} from '../interfaces/issues-processor-options';
|
||||
import {ILabel} from '../interfaces/label';
|
||||
import {IMilestone} from '../interfaces/milestone';
|
||||
import {IsoDateString} from '../types/iso-date-string';
|
||||
import {Operations} from './operations';
|
||||
|
||||
export class Issue implements IIssue {
|
||||
private readonly _options: IIssuesProcessorOptions;
|
||||
@@ -20,6 +21,19 @@ export class Issue implements IIssue {
|
||||
readonly milestone: IMilestone | undefined;
|
||||
readonly assignees: IAssignee[];
|
||||
isStale: boolean;
|
||||
operations = new Operations();
|
||||
|
||||
get isPullRequest(): boolean {
|
||||
return isPullRequest(this);
|
||||
}
|
||||
|
||||
get staleLabel(): string {
|
||||
return this._getStaleLabel();
|
||||
}
|
||||
|
||||
get hasAssignees(): boolean {
|
||||
return this.assignees.length > 0;
|
||||
}
|
||||
|
||||
constructor(
|
||||
options: Readonly<IIssuesProcessorOptions>,
|
||||
@@ -40,18 +54,6 @@ export class Issue implements IIssue {
|
||||
this.isStale = isLabeled(this, this.staleLabel);
|
||||
}
|
||||
|
||||
get isPullRequest(): boolean {
|
||||
return isPullRequest(this);
|
||||
}
|
||||
|
||||
get staleLabel(): string {
|
||||
return this._getStaleLabel();
|
||||
}
|
||||
|
||||
get hasAssignees(): boolean {
|
||||
return this.assignees.length > 0;
|
||||
}
|
||||
|
||||
private _getStaleLabel(): string {
|
||||
return this.isPullRequest
|
||||
? this._options.stalePrLabel
|
||||
|
||||
@@ -21,7 +21,7 @@ import {Issue} from './issue';
|
||||
import {IssueLogger} from './loggers/issue-logger';
|
||||
import {Logger} from './loggers/logger';
|
||||
import {Milestones} from './milestones';
|
||||
import {Operations} from './operations';
|
||||
import {StaleOperations} from './stale-operations';
|
||||
import {Statistics} from './statistics';
|
||||
|
||||
/***
|
||||
@@ -36,8 +36,23 @@ export class IssuesProcessor {
|
||||
return millisSinceLastUpdated <= daysInMillis;
|
||||
}
|
||||
|
||||
private static _endIssueProcessing(issue: Issue): void {
|
||||
const consumedOperationsCount: number = issue.operations.getConsumedOperationsCount();
|
||||
|
||||
if (consumedOperationsCount > 0) {
|
||||
const issueLogger: IssueLogger = new IssueLogger(issue);
|
||||
|
||||
issueLogger.info(
|
||||
chalk.cyan(consumedOperationsCount),
|
||||
`operation${
|
||||
consumedOperationsCount > 1 ? 's' : ''
|
||||
} consumed for this $$type`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private readonly _logger: Logger = new Logger();
|
||||
private readonly _operations: Operations;
|
||||
private readonly _operations: StaleOperations;
|
||||
private readonly _statistics: Statistics | undefined;
|
||||
readonly client: InstanceType<typeof GitHub>;
|
||||
readonly options: IIssuesProcessorOptions;
|
||||
@@ -49,7 +64,7 @@ export class IssuesProcessor {
|
||||
constructor(options: IIssuesProcessorOptions) {
|
||||
this.options = options;
|
||||
this.client = getOctokit(this.options.repoToken);
|
||||
this._operations = new Operations(this.options);
|
||||
this._operations = new StaleOperations(this.options);
|
||||
|
||||
this._logger.info(chalk.yellow('Starting the stale action process...'));
|
||||
|
||||
@@ -77,10 +92,10 @@ export class IssuesProcessor {
|
||||
chalk.green('No more issues found to process. Exiting...')
|
||||
);
|
||||
this._statistics
|
||||
?.setOperationsLeft(this._operations.getUnconsumedOperationsCount())
|
||||
?.setRemainingOperations(this._operations.getRemainingOperationsCount())
|
||||
.logStats();
|
||||
|
||||
return this._operations.getOperationsLeftCount();
|
||||
return this._operations.getRemainingOperationsCount();
|
||||
} else {
|
||||
this._logger.info(
|
||||
chalk.yellow(
|
||||
@@ -136,6 +151,8 @@ export class IssuesProcessor {
|
||||
chalk.white('└──'),
|
||||
`Skipping this $$type because it doesn't have all the required labels`
|
||||
);
|
||||
|
||||
IssuesProcessor._endIssueProcessing(issue);
|
||||
continue; // Don't process issues without all of the required labels
|
||||
} else {
|
||||
issueLogger.info(
|
||||
@@ -161,17 +178,20 @@ export class IssuesProcessor {
|
||||
|
||||
if (!staleMessage && shouldMarkAsStale) {
|
||||
issueLogger.info(`Skipping $$type due to empty stale message`);
|
||||
IssuesProcessor._endIssueProcessing(issue);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (issue.state === 'closed') {
|
||||
issueLogger.info(`Skipping $$type because it is closed`);
|
||||
continue; // don't process closed issues
|
||||
IssuesProcessor._endIssueProcessing(issue);
|
||||
continue; // Don't process closed issues
|
||||
}
|
||||
|
||||
if (issue.locked) {
|
||||
issueLogger.info(`Skipping $$type because it is locked`);
|
||||
continue; // don't process locked issues
|
||||
IssuesProcessor._endIssueProcessing(issue);
|
||||
continue; // Don't process locked issues
|
||||
}
|
||||
|
||||
// Try to remove the close label when not close/locked issue or PR
|
||||
@@ -190,6 +210,7 @@ export class IssuesProcessor {
|
||||
// Expecting that GitHub will always set a creation date on the issues and PRs
|
||||
// But you never know!
|
||||
if (!isValidDate(createdAt)) {
|
||||
IssuesProcessor._endIssueProcessing(issue);
|
||||
core.setFailed(
|
||||
new Error(
|
||||
`Invalid issue field: "created_at". Expected a valid date`
|
||||
@@ -208,7 +229,8 @@ export class IssuesProcessor {
|
||||
`Skipping $$type because it was created before the specified start date`
|
||||
);
|
||||
|
||||
continue; // don't process issues which were created before the start date
|
||||
IssuesProcessor._endIssueProcessing(issue);
|
||||
continue; // Don't process issues which were created before the start date
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,7 +257,8 @@ export class IssuesProcessor {
|
||||
}
|
||||
|
||||
issueLogger.info(`Skipping $$type because it has an exempt label`);
|
||||
continue; // don't process exempt issues
|
||||
IssuesProcessor._endIssueProcessing(issue);
|
||||
continue; // Don't process exempt issues
|
||||
}
|
||||
|
||||
const anyOfLabels: string[] = wordsToList(this._getAnyOfLabels(issue));
|
||||
@@ -256,6 +279,7 @@ export class IssuesProcessor {
|
||||
chalk.white('└──'),
|
||||
`Skipping this $$type because it doesn't have one of the required labels`
|
||||
);
|
||||
IssuesProcessor._endIssueProcessing(issue);
|
||||
continue; // Don't process issues without any of the required labels
|
||||
} else {
|
||||
issueLogger.info(
|
||||
@@ -278,35 +302,37 @@ export class IssuesProcessor {
|
||||
const milestones: Milestones = new Milestones(this.options, issue);
|
||||
|
||||
if (milestones.shouldExemptMilestones()) {
|
||||
continue; // don't process exempt milestones
|
||||
IssuesProcessor._endIssueProcessing(issue);
|
||||
continue; // Don't process exempt milestones
|
||||
}
|
||||
|
||||
const assignees: Assignees = new Assignees(this.options, issue);
|
||||
|
||||
if (assignees.shouldExemptAssignees()) {
|
||||
continue; // don't process exempt assignees
|
||||
IssuesProcessor._endIssueProcessing(issue);
|
||||
continue; // Don't process exempt assignees
|
||||
}
|
||||
|
||||
// should this issue be marked stale?
|
||||
// Should this issue be marked stale?
|
||||
const shouldBeStale = !IssuesProcessor._updatedSince(
|
||||
issue.updated_at,
|
||||
daysBeforeStale
|
||||
);
|
||||
|
||||
// determine if this issue needs to be marked stale first
|
||||
// Determine if this issue needs to be marked stale first
|
||||
if (!issue.isStale && shouldBeStale && shouldMarkAsStale) {
|
||||
issueLogger.info(
|
||||
`Marking $$type stale because it was last updated on ${issue.updated_at} and it does not have a stale label`
|
||||
);
|
||||
await this._markStale(issue, staleMessage, staleLabel, skipMessage);
|
||||
issue.isStale = true; // this issue is now considered stale
|
||||
issue.isStale = true; // This issue is now considered stale
|
||||
} else if (!issue.isStale) {
|
||||
issueLogger.info(
|
||||
`Not marking as stale: shouldBeStale=${shouldBeStale}, shouldMarkAsStale=${shouldMarkAsStale}`
|
||||
);
|
||||
}
|
||||
|
||||
// process the issue if it was marked stale
|
||||
// Process the issue if it was marked stale
|
||||
if (issue.isStale) {
|
||||
issueLogger.info(`Found a stale $$type`);
|
||||
await this._processStaleIssue(
|
||||
@@ -317,9 +343,11 @@ export class IssuesProcessor {
|
||||
closeLabel
|
||||
);
|
||||
}
|
||||
|
||||
IssuesProcessor._endIssueProcessing(issue);
|
||||
}
|
||||
|
||||
if (this._operations.hasOperationsLeft()) {
|
||||
if (!this._operations.hasRemainingOperations()) {
|
||||
this._logger.warning(
|
||||
chalk.yellowBright('No more operations left! Exiting...')
|
||||
);
|
||||
@@ -340,16 +368,16 @@ export class IssuesProcessor {
|
||||
chalk.green(`Batch ${chalk.cyan(`#${page}`)} processed.`)
|
||||
);
|
||||
|
||||
// do the next batch
|
||||
// Do the next batch
|
||||
return this.processIssues(page + 1);
|
||||
}
|
||||
|
||||
// grab comments for an issue since a given date
|
||||
// Grab comments for an issue since a given date
|
||||
async listIssueComments(
|
||||
issueNumber: number,
|
||||
sinceDate: string
|
||||
issueNumber: Readonly<number>,
|
||||
sinceDate: Readonly<string>
|
||||
): Promise<IComment[]> {
|
||||
// find any comments since date on the given issue
|
||||
// Find any comments since date on the given issue
|
||||
try {
|
||||
this._operations.consumeOperation();
|
||||
this._statistics?.incrementFetchedItemsCommentsCount();
|
||||
@@ -419,7 +447,7 @@ export class IssuesProcessor {
|
||||
|
||||
issueLogger.info(`Checking for label on $$type`);
|
||||
|
||||
this._operations.consumeOperation();
|
||||
this._consumeIssueOperation(issue);
|
||||
this._statistics?.incrementFetchedItemsEventsCount();
|
||||
const options = this.client.issues.listEvents.endpoint.merge({
|
||||
owner: context.repo.owner,
|
||||
@@ -563,7 +591,7 @@ export class IssuesProcessor {
|
||||
|
||||
if (!skipMessage) {
|
||||
try {
|
||||
this._operations.consumeOperation();
|
||||
this._consumeIssueOperation(issue);
|
||||
this._statistics?.incrementAddedItemsComment(issue);
|
||||
await this.client.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
@@ -577,7 +605,7 @@ export class IssuesProcessor {
|
||||
}
|
||||
|
||||
try {
|
||||
this._operations.consumeOperation();
|
||||
this._consumeIssueOperation(issue);
|
||||
this._statistics?.incrementAddedItemsLabel(issue);
|
||||
this._statistics?.incrementStaleItemsCount(issue);
|
||||
await this.client.issues.addLabels({
|
||||
@@ -608,7 +636,7 @@ export class IssuesProcessor {
|
||||
|
||||
if (closeMessage) {
|
||||
try {
|
||||
this._operations.consumeOperation();
|
||||
this._consumeIssueOperation(issue);
|
||||
this._statistics?.incrementAddedItemsComment(issue);
|
||||
await this.client.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
@@ -623,7 +651,7 @@ export class IssuesProcessor {
|
||||
|
||||
if (closeLabel) {
|
||||
try {
|
||||
this._operations.consumeOperation();
|
||||
this._consumeIssueOperation(issue);
|
||||
this._statistics?.incrementAddedItemsLabel(issue);
|
||||
await this.client.issues.addLabels({
|
||||
owner: context.repo.owner,
|
||||
@@ -637,7 +665,7 @@ export class IssuesProcessor {
|
||||
}
|
||||
|
||||
try {
|
||||
this._operations.consumeOperation();
|
||||
this._consumeIssueOperation(issue);
|
||||
this._statistics?.incrementClosedItemsCount(issue);
|
||||
await this.client.issues.update({
|
||||
owner: context.repo.owner,
|
||||
@@ -660,7 +688,7 @@ export class IssuesProcessor {
|
||||
}
|
||||
|
||||
try {
|
||||
this._operations.consumeOperation();
|
||||
this._consumeIssueOperation(issue);
|
||||
this._statistics?.incrementFetchedPullRequestsCount();
|
||||
const pullRequest = await this.client.pulls.get({
|
||||
owner: context.repo.owner,
|
||||
@@ -699,7 +727,7 @@ export class IssuesProcessor {
|
||||
);
|
||||
|
||||
try {
|
||||
this._operations.consumeOperation();
|
||||
this._consumeIssueOperation(issue);
|
||||
this._statistics?.incrementDeletedBranchesCount();
|
||||
await this.client.git.deleteRef({
|
||||
owner: context.repo.owner,
|
||||
@@ -729,7 +757,7 @@ export class IssuesProcessor {
|
||||
}
|
||||
|
||||
try {
|
||||
this._operations.consumeOperation();
|
||||
this._consumeIssueOperation(issue);
|
||||
this._statistics?.incrementDeletedItemsLabelsCount(issue);
|
||||
await this.client.issues.removeLabel({
|
||||
owner: context.repo.owner,
|
||||
@@ -854,4 +882,9 @@ export class IssuesProcessor {
|
||||
this._statistics?.incrementDeletedCloseItemsLabelsCount(issue);
|
||||
}
|
||||
}
|
||||
|
||||
private _consumeIssueOperation(issue: Readonly<Issue>): void {
|
||||
this._operations.consumeOperation();
|
||||
issue.operations.consumeOperation();
|
||||
}
|
||||
}
|
||||
|
||||
49
src/classes/operations.spec.ts
Normal file
49
src/classes/operations.spec.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import {Operations} from './operations';
|
||||
|
||||
describe('Operations', (): void => {
|
||||
let operations: Operations;
|
||||
|
||||
describe('consumeOperation()', (): void => {
|
||||
beforeEach((): void => {
|
||||
operations = new Operations();
|
||||
});
|
||||
|
||||
it('should increase the count of operation consume by 1', (): void => {
|
||||
expect.assertions(1);
|
||||
operations.consumeOperation();
|
||||
|
||||
const result = operations.getConsumedOperationsCount();
|
||||
|
||||
expect(result).toStrictEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('consumeOperations()', (): void => {
|
||||
beforeEach((): void => {
|
||||
operations = new Operations();
|
||||
});
|
||||
|
||||
it('should increase the count of operation consume by the provided quantity', (): void => {
|
||||
expect.assertions(1);
|
||||
operations.consumeOperations(8);
|
||||
|
||||
const result = operations.getConsumedOperationsCount();
|
||||
|
||||
expect(result).toStrictEqual(8);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getConsumedOperationsCount()', (): void => {
|
||||
beforeEach((): void => {
|
||||
operations = new Operations();
|
||||
});
|
||||
|
||||
it('should return 0 by default', (): void => {
|
||||
expect.assertions(1);
|
||||
|
||||
const result = operations.getConsumedOperationsCount();
|
||||
|
||||
expect(result).toStrictEqual(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,33 +1,17 @@
|
||||
import {IIssuesProcessorOptions} from '../interfaces/issues-processor-options';
|
||||
|
||||
export class Operations {
|
||||
private readonly _options: IIssuesProcessorOptions;
|
||||
private _operationsLeft;
|
||||
|
||||
constructor(options: Readonly<IIssuesProcessorOptions>) {
|
||||
this._options = options;
|
||||
this._operationsLeft = this._options.operationsPerRun;
|
||||
}
|
||||
protected _operationsConsumed = 0;
|
||||
|
||||
consumeOperation(): Operations {
|
||||
return this.consumeOperations(1);
|
||||
}
|
||||
|
||||
consumeOperations(quantity: Readonly<number>): Operations {
|
||||
this._operationsLeft -= quantity;
|
||||
this._operationsConsumed += quantity;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
getUnconsumedOperationsCount(): number {
|
||||
return this._options.operationsPerRun - this._operationsLeft;
|
||||
}
|
||||
|
||||
hasOperationsLeft(): boolean {
|
||||
return this._operationsLeft <= 0;
|
||||
}
|
||||
|
||||
getOperationsLeftCount(): number {
|
||||
return this._operationsLeft;
|
||||
getConsumedOperationsCount(): number {
|
||||
return this._operationsConsumed;
|
||||
}
|
||||
}
|
||||
|
||||
134
src/classes/stale-operations.spec.ts
Normal file
134
src/classes/stale-operations.spec.ts
Normal file
@@ -0,0 +1,134 @@
|
||||
import {DefaultProcessorOptions} from '../../__tests__/constants/default-processor-options';
|
||||
import {IIssuesProcessorOptions} from '../interfaces/issues-processor-options';
|
||||
import {StaleOperations} from './stale-operations';
|
||||
|
||||
interface IHasRemainingOperationsMatrix {
|
||||
operationsPerRun: number;
|
||||
consumeOperations: number;
|
||||
hasRemainingOperations: number;
|
||||
}
|
||||
|
||||
interface IGetRemainingOperationsCountMatrix {
|
||||
operationsPerRun: number;
|
||||
consumeOperations: number;
|
||||
getRemainingOperationsCount: number;
|
||||
}
|
||||
|
||||
describe('StaleOperations', (): void => {
|
||||
let operations: StaleOperations;
|
||||
let options: IIssuesProcessorOptions;
|
||||
|
||||
beforeEach((): void => {
|
||||
options = {...DefaultProcessorOptions};
|
||||
});
|
||||
|
||||
describe('consumeOperation()', (): void => {
|
||||
beforeEach((): void => {
|
||||
operations = new StaleOperations(options);
|
||||
});
|
||||
|
||||
it('should increase the count of operation consume by 1', (): void => {
|
||||
expect.assertions(1);
|
||||
operations.consumeOperation();
|
||||
|
||||
const result = operations.getConsumedOperationsCount();
|
||||
|
||||
expect(result).toStrictEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('consumeOperations()', (): void => {
|
||||
beforeEach((): void => {
|
||||
operations = new StaleOperations(options);
|
||||
});
|
||||
|
||||
it('should increase the count of operation consume by the provided quantity', (): void => {
|
||||
expect.assertions(1);
|
||||
operations.consumeOperations(8);
|
||||
|
||||
const result = operations.getConsumedOperationsCount();
|
||||
|
||||
expect(result).toStrictEqual(8);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getConsumedOperationsCount()', (): void => {
|
||||
beforeEach((): void => {
|
||||
operations = new StaleOperations(options);
|
||||
});
|
||||
|
||||
it('should return 0 by default', (): void => {
|
||||
expect.assertions(1);
|
||||
|
||||
const result = operations.getConsumedOperationsCount();
|
||||
|
||||
expect(result).toStrictEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasRemainingOperations()', (): void => {
|
||||
beforeEach((): void => {
|
||||
operations = new StaleOperations(options);
|
||||
});
|
||||
|
||||
describe.each`
|
||||
operationsPerRun | consumeOperations | hasRemainingOperations
|
||||
${1} | ${1} | ${false}
|
||||
${2} | ${1} | ${true}
|
||||
`(
|
||||
'when the operations per run is $operationsPerRun and $consumeOperations operations were consumed',
|
||||
({
|
||||
operationsPerRun,
|
||||
consumeOperations,
|
||||
hasRemainingOperations
|
||||
}: IHasRemainingOperationsMatrix): void => {
|
||||
beforeEach((): void => {
|
||||
options.operationsPerRun = operationsPerRun;
|
||||
operations = new StaleOperations(options);
|
||||
});
|
||||
|
||||
it(`should return ${hasRemainingOperations}`, (): void => {
|
||||
expect.assertions(1);
|
||||
operations.consumeOperations(consumeOperations);
|
||||
|
||||
const result = operations.hasRemainingOperations();
|
||||
|
||||
expect(result).toStrictEqual(hasRemainingOperations);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('getRemainingOperationsCount()', (): void => {
|
||||
beforeEach((): void => {
|
||||
operations = new StaleOperations(options);
|
||||
});
|
||||
|
||||
describe.each`
|
||||
operationsPerRun | consumeOperations | getRemainingOperationsCount
|
||||
${1} | ${1} | ${0}
|
||||
${2} | ${1} | ${1}
|
||||
`(
|
||||
'when the operations per run is $operationsPerRun and $consumeOperations operations were consumed',
|
||||
({
|
||||
operationsPerRun,
|
||||
consumeOperations,
|
||||
getRemainingOperationsCount
|
||||
}: IGetRemainingOperationsCountMatrix): void => {
|
||||
beforeEach((): void => {
|
||||
options.operationsPerRun = operationsPerRun;
|
||||
operations = new StaleOperations(options);
|
||||
});
|
||||
|
||||
it(`should return ${getRemainingOperationsCount}`, (): void => {
|
||||
expect.assertions(1);
|
||||
operations.consumeOperations(consumeOperations);
|
||||
|
||||
const result = operations.getRemainingOperationsCount();
|
||||
|
||||
expect(result).toStrictEqual(getRemainingOperationsCount);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
19
src/classes/stale-operations.ts
Normal file
19
src/classes/stale-operations.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import {IIssuesProcessorOptions} from '../interfaces/issues-processor-options';
|
||||
import {Operations} from './operations';
|
||||
|
||||
export class StaleOperations extends Operations {
|
||||
private readonly _options: IIssuesProcessorOptions;
|
||||
|
||||
constructor(options: Readonly<IIssuesProcessorOptions>) {
|
||||
super();
|
||||
this._options = options;
|
||||
}
|
||||
|
||||
hasRemainingOperations(): boolean {
|
||||
return this._operationsConsumed < this._options.operationsPerRun;
|
||||
}
|
||||
|
||||
getRemainingOperationsCount(): number {
|
||||
return this._options.operationsPerRun - this._operationsConsumed;
|
||||
}
|
||||
}
|
||||
@@ -65,8 +65,8 @@ export class Statistics {
|
||||
return this._incrementUndoStaleIssuesCount(increment);
|
||||
}
|
||||
|
||||
setOperationsLeft(operationsLeft: Readonly<number>): Statistics {
|
||||
this._operationsCount = operationsLeft;
|
||||
setRemainingOperations(remainingOperations: Readonly<number>): Statistics {
|
||||
this._operationsCount = remainingOperations;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
16
src/main.ts
16
src/main.ts
@@ -1,6 +1,6 @@
|
||||
import * as core from '@actions/core';
|
||||
import {isValidDate} from './functions/dates/is-valid-date';
|
||||
import {IssuesProcessor} from './classes/issues-processor';
|
||||
import {isValidDate} from './functions/dates/is-valid-date';
|
||||
import {IIssuesProcessorOptions} from './interfaces/issues-processor-options';
|
||||
|
||||
async function _run(): Promise<void> {
|
||||
@@ -85,9 +85,9 @@ function _getAndValidateArgs(): IIssuesProcessorOptions {
|
||||
'operations-per-run'
|
||||
]) {
|
||||
if (isNaN(parseInt(core.getInput(numberInput)))) {
|
||||
core.setFailed(
|
||||
new Error(`Option "${numberInput}" did not parse to a valid integer`)
|
||||
);
|
||||
const errorMessage = `Option "${numberInput}" did not parse to a valid integer`;
|
||||
core.setFailed(errorMessage);
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,11 +95,9 @@ function _getAndValidateArgs(): IIssuesProcessorOptions {
|
||||
// Ignore empty dates because it is considered as the right type for a default value (so a valid one)
|
||||
if (core.getInput(optionalDateInput) !== '') {
|
||||
if (!isValidDate(new Date(core.getInput(optionalDateInput)))) {
|
||||
core.setFailed(
|
||||
new Error(
|
||||
`Option "${optionalDateInput}" did not parse to a valid date`
|
||||
)
|
||||
);
|
||||
const errorMessage = `Option "${optionalDateInput}" did not parse to a valid date`;
|
||||
core.setFailed(errorMessage);
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user