From 022edf9e6e0ffd68e979c77bff8958dfbd7cf81e Mon Sep 17 00:00:00 2001 From: Geoffrey Testelin Date: Sat, 14 Aug 2021 14:56:22 +0200 Subject: [PATCH 01/12] chore(assignees): add logs --- dist/index.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/dist/index.js b/dist/index.js index 15c68c6e6..00a165f33 100644 --- a/dist/index.js +++ b/dist/index.js @@ -263,6 +263,7 @@ exports.Issue = void 0; const is_labeled_1 = __nccwpck_require__(6792); const is_pull_request_1 = __nccwpck_require__(5400); const operations_1 = __nccwpck_require__(7957); +const logger_1 = __nccwpck_require__(6212); class Issue { constructor(options, issue) { this.operations = new operations_1.Operations(); @@ -277,6 +278,10 @@ class Issue { this.locked = issue.locked; this.milestone = issue.milestone; this.assignees = issue.assignees; + // @todo remove this log + const logger = new logger_1.Logger(); + logger.info('Assignees:'); + logger.info(...this.assignees.map((assignee) => JSON.stringify(assignee))); this.isStale = is_labeled_1.isLabeled(this, this.staleLabel); } get isPullRequest() { @@ -9153,12 +9158,12 @@ module.exports = require("zlib");; /******/ /* webpack/runtime/compat */ /******/ /******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = __dirname + "/";/************************************************************************/ -/******/ +/******/ /******/ // startup /******/ // Load entry module and return exports /******/ // This entry module is referenced by other modules so it can't be inlined /******/ var __webpack_exports__ = __nccwpck_require__(3109); /******/ module.exports = __webpack_exports__; -/******/ +/******/ /******/ })() -; \ No newline at end of file +; From d7540962deb3fe9d6aaecda5be96f59f163f6214 Mon Sep 17 00:00:00 2001 From: TESTELIN Geoffrey Date: Tue, 8 Jun 2021 22:50:39 +0200 Subject: [PATCH 02/12] refactor(option): rename operations-per-run to query-operations-per-run --- README.md | 30 +++-- .../constants/default-processor-options.ts | 3 +- __tests__/operations-per-run.spec.ts | 44 +++---- action.yml | 8 +- src/classes/issue.spec.ts | 3 +- src/classes/issues-processor.ts | 118 +++++++++++++----- src/classes/operations.spec.ts | 10 +- src/classes/operations.ts | 29 +++-- src/classes/stale-operations.spec.ts | 22 ++-- src/classes/stale-operations.ts | 20 ++- src/classes/statistics.ts | 24 +++- src/enums/option.ts | 3 +- src/interfaces/issues-processor-options.ts | 3 +- src/main.ts | 10 +- 14 files changed, 221 insertions(+), 106 deletions(-) diff --git a/README.md b/README.md index 7578edd20..7fb21a903 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,8 @@ Every argument is optional. | [any-of-labels](#any-of-labels) | Only issues/PRs with ANY of these labels are checked | | | [any-of-issue-labels](#any-of-issue-labels) | Override [any-of-labels](#any-of-labels) for issues only | | | [any-of-pr-labels](#any-of-pr-labels) | Override [any-of-labels](#any-of-labels) for PRs only | | -| [operations-per-run](#operations-per-run) | Max number of operations per run | `30` | +| [query-operations-per-run](#query-operations-per-run) | Max number of query operations per run (GitHub read) | `30` | +| [mutation-operations-per-run](#mutation-operations-per-run) | Max number of mutation operations per run (GitHub write) | `200` | | [remove-stale-when-updated](#remove-stale-when-updated) | Remove stale label from issues/PRs on updates | `true` | | [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 | | @@ -299,7 +300,7 @@ Override [any-of-labels](#any-of-labels) but only to process the pull requests t Default value: unset -#### operations-per-run +#### query-operations-per-run _Context:_ This action performs some API calls to GitHub to fetch or close issues and pull requests, set or update labels, add comments, delete branches, etc. @@ -308,18 +309,23 @@ GitHub has a [rate limit](https://docs.github.com/en/rest/overview/resources-in- This option helps you to stay within the GitHub rate limits, as you can use this option to limit the number of operations for a single run. _Purpose:_ -This option aims to limit the number of operations made with the GitHub API to avoid reaching the [rate limit](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting). +This option limit the amount of API calls made to GitHub in order to fetch the issues and pull requests as well as comments. Based on your project, your GitHub business plan and the date of the cron job you set for this action, you can increase this limit to a higher number. If you are not sure which is the right value for you or if the default value is good enough, you could enable the logs and look at the end of the stale action. If you reached the limit, you will see a warning message in the logs, telling you that you should increase the number of operations. If you choose not to increase the limit, you might end up with unprocessed issues or pull requests after a stale action run. -When [debugging](#Debugging), you can set it to a much higher number like `1000` since there will be fewer operations made with the GitHub API. -Only the [actor](#repo-token) and the batch of issues (100 per batch) will consume the operations. - Default value: `30` +#### mutation-operations-per-run + +Same as [query-operations-per-run](#query-operations-per-run) except that the purpose of this option is to limit the API calls to GitHub to add or remove labels, add comments, delete branches, etc. + +When [debugging](#Debugging), you can set it to a much higher number like `5000` since the operations count will still works but no mutations will happen. + +Default value: `200` + #### remove-stale-when-updated Automatically remove the stale label when the issues or the pull requests are updated (based on [GitHub issue](https://docs.github.com/en/rest/reference/issues) field `updated_at`) or commented. @@ -350,7 +356,7 @@ Default value: unset 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. -Warning: each label results in a unique API call which can drastically consume the limit of [operations-per-run](#operations-per-run). +Warning: each label results in a unique API call which can drastically consume the limit of [mutation-operations-per-run](#mutation-operations-per-run). Default value: unset Required Permission: `pull-requests: write` @@ -370,7 +376,7 @@ Change the order used to fetch the issues and pull requests from GitHub: - `true` is for ascending. - `false` is for descending. -It can be useful if your repository is processing so many issues and pull requests that you reach the [operations-per-run](#operations-per-run) limit. +It can be useful if your repository is processing so many issues and pull requests that you reach the [query-operations-per-run](#query-operations-per-run) limit. Based on the order, you could prefer to focus on the new content or on the old content of your repository. Default value: `false` @@ -734,14 +740,14 @@ There are many logs, so this can be very helpful! **Statistics:** If the logs are enabled, you can also enable the statistics log which will be visible at the end of the logs once all issues were processed. This is very helpful to have a quick understanding of the whole stale workflow. -Set `enable-statistics` to `true` in your workflow configuration file. +Set [enable-statistics](#enable-statistics) to `true` in your workflow configuration file. **Dry-run:** -You can run this action in debug only mode (no actions will be taken on your issues and pull requests) by passing `debug-only` to `true` as an argument to the action. +You can run this action in debug only mode (no actions will be taken on your issues and pull requests) by passing [debug-only](#debug-only) to `true` as an argument to the action. **More operations:** -You can increase the maximum number of operations per run by passing `operations-per-run` to `1000` for example which will help you to handle more operations in a single stale workflow run. -If the `debug-only` option is enabled, this is very helpful because the workflow will (almost) never reach the GitHub API rate, and you will be able to deep-dive into the logs. +You can increase the maximum number of operations per run by passing [query-operations-per-run](#query-operations-per-run) and [mutation-operations-per-run](#mutation-operations-per-run) to `1000` for example which will help you to handle more operations in a single stale workflow run. +If the [debug-only](#debug-only) option is enabled, this is very helpful because the workflow will still count and limit the number of operations per run to avoid to reach the GitHub API rate, but will not perform the calls. **Job frequency:** You could change the cron job frequency in the stale workflow to run the stale workflow more often. diff --git a/__tests__/constants/default-processor-options.ts b/__tests__/constants/default-processor-options.ts index b526d12aa..cc3a2ffc6 100644 --- a/__tests__/constants/default-processor-options.ts +++ b/__tests__/constants/default-processor-options.ts @@ -24,7 +24,8 @@ export const DefaultProcessorOptions: IIssuesProcessorOptions = Object.freeze({ anyOfLabels: '', anyOfIssueLabels: '', anyOfPrLabels: '', - operationsPerRun: 100, + queryOperationsPerRun: 100, + mutationOperationsPerRun: 100, debugOnly: true, removeStaleWhenUpdated: false, removeIssueStaleWhenUpdated: undefined, diff --git a/__tests__/operations-per-run.spec.ts b/__tests__/operations-per-run.spec.ts index f42397c93..34bee125e 100644 --- a/__tests__/operations-per-run.spec.ts +++ b/__tests__/operations-per-run.spec.ts @@ -17,9 +17,9 @@ describe('operations-per-run option', (): void => { sut.staleIn(10).newIssue().updated(20); }); - describe('when the operations per run option is set to 1', (): void => { + describe('when the mutation operations per run option is set to 1', (): void => { beforeEach((): void => { - sut.operationsPerRun(1); + sut.mutationOperationsPerRun(1); }); it('should consume 1 operation (stale label)', async () => { @@ -29,7 +29,7 @@ describe('operations-per-run option', (): void => { expect(sut.processor.staleIssues).toHaveLength(1); expect( - sut.processor.operations.getConsumedOperationsCount() + sut.processor.operations.getConsumedMutationOperationsCount() ).toStrictEqual(1); }); }); @@ -40,9 +40,9 @@ describe('operations-per-run option', (): void => { sut.staleIn(10).commentOnStale().newIssue().updated(20); }); - describe('when the operations per run option is set to 2', (): void => { + describe('when the mutation operations per run option is set to 2', (): void => { beforeEach((): void => { - sut.operationsPerRun(2); + sut.mutationOperationsPerRun(2); }); it('should consume 2 operations (stale label, comment)', async () => { @@ -52,15 +52,15 @@ describe('operations-per-run option', (): void => { expect(sut.processor.staleIssues).toHaveLength(1); expect( - sut.processor.operations.getConsumedOperationsCount() + sut.processor.operations.getConsumedMutationOperationsCount() ).toStrictEqual(2); }); }); // Special case were we continue the issue processing even if the operations per run is reached - describe('when the operations per run option is set to 1', (): void => { + describe('when the mutation operations per run option is set to 1', (): void => { beforeEach((): void => { - sut.operationsPerRun(1); + sut.mutationOperationsPerRun(1); }); it('should consume 2 operations (stale label, comment)', async () => { @@ -70,7 +70,7 @@ describe('operations-per-run option', (): void => { expect(sut.processor.staleIssues).toHaveLength(1); expect( - sut.processor.operations.getConsumedOperationsCount() + sut.processor.operations.getConsumedMutationOperationsCount() ).toStrictEqual(2); }); }); @@ -83,9 +83,9 @@ describe('operations-per-run option', (): void => { sut.newIssue().updated(20); }); - describe('when the operations per run option is set to 3', (): void => { + describe('when the mutation perations per run option is set to 3', (): void => { beforeEach((): void => { - sut.operationsPerRun(3); + sut.mutationOperationsPerRun(3); }); it('should consume 4 operations (stale label, comment)', async () => { @@ -95,14 +95,14 @@ describe('operations-per-run option', (): void => { expect(sut.processor.staleIssues).toHaveLength(2); expect( - sut.processor.operations.getConsumedOperationsCount() + sut.processor.operations.getConsumedMutationOperationsCount() ).toStrictEqual(4); }); }); - describe('when the operations per run option is set to 2', (): void => { + describe('when the mutation operations per run option is set to 2', (): void => { beforeEach((): void => { - sut.operationsPerRun(2); + sut.mutationOperationsPerRun(2); }); it('should consume 2 operations (stale label, comment) and stop', async () => { @@ -112,15 +112,15 @@ describe('operations-per-run option', (): void => { expect(sut.processor.staleIssues).toHaveLength(1); expect( - sut.processor.operations.getConsumedOperationsCount() + sut.processor.operations.getConsumedMutationOperationsCount() ).toStrictEqual(2); }); }); // Special case were we continue the issue processing even if the operations per run is reached - describe('when the operations per run option is set to 1', (): void => { + describe('when the mutation operations per run option is set to 1', (): void => { beforeEach((): void => { - sut.operationsPerRun(1); + sut.mutationOperationsPerRun(1); }); it('should consume 2 operations (stale label, comment) and stop', async () => { @@ -130,7 +130,7 @@ describe('operations-per-run option', (): void => { expect(sut.processor.staleIssues).toHaveLength(1); expect( - sut.processor.operations.getConsumedOperationsCount() + sut.processor.operations.getConsumedMutationOperationsCount() ).toStrictEqual(2); }); }); @@ -169,15 +169,15 @@ class SUT { return this; } - operationsPerRun(count: number): SUT { + mutationOperationsPerRun(count: number): SUT { this._updateOptions({ - operationsPerRun: count + mutationOperationsPerRun: count }); return this; } - async test(): Promise { + async test(): Promise { return this._setTestIssueList()._setProcessor(); } @@ -202,7 +202,7 @@ class SUT { return this; } - private async _setProcessor(): Promise { + private async _setProcessor(): Promise { this.processor = new IssuesProcessorMock( this._opts, async p => (p === 1 ? this._testIssueList : []), diff --git a/action.yml b/action.yml index 5cf52fc17..96ebf3144 100644 --- a/action.yml +++ b/action.yml @@ -108,10 +108,14 @@ inputs: description: 'Only pull requests with all of these labels are checked if stale. Defaults to `[]` (disabled) and can be a comma-separated list of labels. Override "only-labels" option regarding only the pull requests.' default: '' required: false - operations-per-run: - description: 'The maximum number of operations per run, used to control rate limiting (GitHub API CRUD related).' + query-operations-per-run: + description: 'The maximum number of query operations per run, used to control rate limiting (GitHub API CRUD related).' default: '30' required: false + mutation-operations-per-run: + description: 'The maximum number of mutation operations per run, used to control rate limiting (GitHub API CRUD related).' + default: '200' + required: false remove-stale-when-updated: description: 'Remove stale labels from issues and pull requests when they are updated or commented on.' default: 'true' diff --git a/src/classes/issue.spec.ts b/src/classes/issue.spec.ts index ccd32d51a..2dc35b3d9 100644 --- a/src/classes/issue.spec.ts +++ b/src/classes/issue.spec.ts @@ -33,7 +33,8 @@ describe('Issue', (): void => { anyOfLabels: '', anyOfIssueLabels: '', anyOfPrLabels: '', - operationsPerRun: 0, + queryOperationsPerRun: 0, + mutationOperationsPerRun: 0, removeStaleWhenUpdated: false, removeIssueStaleWhenUpdated: undefined, removePrStaleWhenUpdated: undefined, diff --git a/src/classes/issues-processor.ts b/src/classes/issues-processor.ts index 708bafa4a..2047657fd 100644 --- a/src/classes/issues-processor.ts +++ b/src/classes/issues-processor.ts @@ -40,16 +40,16 @@ export class IssuesProcessor { } private static _endIssueProcessing(issue: Issue): void { - const consumedOperationsCount: number = - issue.operations.getConsumedOperationsCount(); + const consumedQueryOperationsCount: number = + issue.operations.getConsumedQueryOperationsCount(); - if (consumedOperationsCount > 0) { + if (consumedQueryOperationsCount > 0) { const issueLogger: IssueLogger = new IssueLogger(issue); issueLogger.info( - LoggerService.cyan(consumedOperationsCount), - `operation${ - consumedOperationsCount > 1 ? 's' : '' + LoggerService.cyan(consumedQueryOperationsCount), + `query operation${ + consumedQueryOperationsCount > 1 ? 's' : '' } consumed for this $$type` ); } @@ -98,7 +98,7 @@ export class IssuesProcessor { } } - async processIssues(page: Readonly = 1): Promise { + async processIssues(page: Readonly = 1): Promise { // get the next batch of issues const issues: Issue[] = await this.getIssues(page); @@ -107,10 +107,15 @@ export class IssuesProcessor { LoggerService.green(`No more issues found to process. Exiting...`) ); this.statistics - ?.setOperationsCount(this.operations.getConsumedOperationsCount()) + ?.setQueryOperationsCount( + this.operations.getConsumedQueryOperationsCount() + ) + ?.setMutationOperationsCount( + this.operations.getConsumedMutationOperationsCount() + ) .logStats(); - return this.operations.getRemainingOperationsCount(); + return; } else { this._logger.info( `${LoggerService.yellow( @@ -131,8 +136,9 @@ export class IssuesProcessor { ); for (const issue of issues.values()) { - // Stop the processing if no more operations remains - if (!this.operations.hasRemainingOperations()) { + // @todo change? + // Skip the processing if no more operations remains + if (!this.operations.hasRemainingQueryOperations()) { break; } @@ -146,24 +152,30 @@ export class IssuesProcessor { }); } - if (!this.operations.hasRemainingOperations()) { + // @todo change? + if (!this.operations.hasRemainingQueryOperations()) { this._logger.warning( - LoggerService.yellowBright(`No more operations left! Exiting...`) + LoggerService.yellowBright(`No more query operations left! Exiting...`) ); this._logger.warning( `${LoggerService.yellowBright( 'If you think that not enough issues were processed you could try to increase the quantity related to the' )} ${this._logger.createOptionLink( - Option.OperationsPerRun + Option.QueryOperationsPerRun )} ${LoggerService.yellowBright( 'option which is currently set to' - )} ${LoggerService.cyan(this.options.operationsPerRun)}` + )} ${LoggerService.cyan(this.options.queryOperationsPerRun)}` ); this.statistics - ?.setOperationsCount(this.operations.getConsumedOperationsCount()) + ?.setQueryOperationsCount( + this.operations.getConsumedQueryOperationsCount() + ) + ?.setMutationOperationsCount( + this.operations.getConsumedMutationOperationsCount() + ) .logStats(); - return 0; + return; } this._logger.info( @@ -515,7 +527,7 @@ export class IssuesProcessor { ): Promise { // Find any comments since date on the given issue try { - this.operations.consumeOperation(); + this.operations.consumeQueryOperation(); this.statistics?.incrementFetchedItemsCommentsCount(); const comments = await this.client.issues.listComments({ owner: context.repo.owner, @@ -537,7 +549,7 @@ export class IssuesProcessor { type OctoKitIssueList = GetResponseTypeFromEndpointMethod; try { - this.operations.consumeOperation(); + this.operations.consumeQueryOperation(); const issueResult: OctoKitIssueList = await this.client.issues.listForRepo({ owner: context.repo.owner, @@ -568,7 +580,7 @@ export class IssuesProcessor { issueLogger.info(`Checking for label on this $$type`); - this._consumeIssueOperation(issue); + this._consumeIssueQueryOperation(issue); this.statistics?.incrementFetchedItemsEventsCount(); const options = this.client.issues.listEvents.endpoint.merge({ owner: context.repo.owner, @@ -598,7 +610,7 @@ export class IssuesProcessor { const issueLogger: IssueLogger = new IssueLogger(issue); try { - this._consumeIssueOperation(issue); + this._consumeIssueQueryOperation(issue); this.statistics?.incrementFetchedPullRequestsCount(); const pullRequest = await this.client.pulls.get({ @@ -771,7 +783,7 @@ export class IssuesProcessor { if (!skipMessage) { try { - this._consumeIssueOperation(issue); + this._consumeIssueMutationOperation(issue); this.statistics?.incrementAddedItemsComment(issue); if (!this.options.debugOnly) { @@ -788,7 +800,7 @@ export class IssuesProcessor { } try { - this._consumeIssueOperation(issue); + this._consumeIssueMutationOperation(issue); this.statistics?.incrementAddedItemsLabel(issue); this.statistics?.incrementStaleItemsCount(issue); @@ -818,7 +830,7 @@ export class IssuesProcessor { if (closeMessage) { try { - this._consumeIssueOperation(issue); + this._consumeIssueMutationOperation(issue); this.statistics?.incrementAddedItemsComment(issue); this.addedCloseCommentIssues.push(issue); @@ -837,7 +849,7 @@ export class IssuesProcessor { if (closeLabel) { try { - this._consumeIssueOperation(issue); + this._consumeIssueMutationOperation(issue); this.statistics?.incrementAddedItemsLabel(issue); if (!this.options.debugOnly) { @@ -854,7 +866,7 @@ export class IssuesProcessor { } try { - this._consumeIssueOperation(issue); + this._consumeIssueMutationOperation(issue); this.statistics?.incrementClosedItemsCount(issue); if (!this.options.debugOnly) { @@ -870,6 +882,27 @@ export class IssuesProcessor { } } + private async _getPullRequest( + issue: Issue + ): Promise { + const issueLogger: IssueLogger = new IssueLogger(issue); + + try { + this._consumeIssueQueryOperation(issue); + this._statistics?.incrementFetchedPullRequestsCount(); + + const pullRequest = await this.client.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: issue.number + }); + + return pullRequest.data; + } catch (error) { + issueLogger.error(`Error when getting this $$type: ${error.message}`); + } + } + // Delete the branch on closed pull request private async _deleteBranch(issue: Issue): Promise { const issueLogger: IssueLogger = new IssueLogger(issue); @@ -896,7 +929,7 @@ export class IssuesProcessor { ); try { - this._consumeIssueOperation(issue); + this._consumeIssueMutationOperation(issue); this.statistics?.incrementDeletedBranchesCount(); if (!this.options.debugOnly) { @@ -931,7 +964,7 @@ export class IssuesProcessor { this.removedLabelIssues.push(issue); try { - this._consumeIssueOperation(issue); + this._consumeIssueMutationOperation(issue); this.statistics?.incrementDeletedItemsLabelsCount(issue); if (!this.options.debugOnly) { @@ -1065,7 +1098,7 @@ export class IssuesProcessor { this.addedLabelIssues.push(issue); try { - this.operations.consumeOperation(); + this.operations.consumeMutationOperation(); this.statistics?.incrementAddedItemsLabel(issue); if (!this.options.debugOnly) { await this.client.issues.addLabels({ @@ -1141,9 +1174,30 @@ export class IssuesProcessor { } } - private _consumeIssueOperation(issue: Readonly): void { - this.operations.consumeOperation(); - issue.operations.consumeOperation(); + /** + * @private + * + * @description + * Increase the counter of consumed operation related to queries (GitHub read) + * + * @param {Readonly} issue The processed issue + */ + private _consumeIssueQueryOperation(issue: Readonly): void { + this.operations.consumeQueryOperation(); + issue.operations.consumeQueryOperation(); + } + + /** + * @private + * + * @description + * Increase the counter of consumed operation related to mutations (GitHub write) + * + * @param {Readonly} issue The processed issue + */ + private _consumeIssueMutationOperation(issue: Readonly): void { + this.operations.consumeMutationOperation(); + issue.operations.consumeMutationOperation(); } private _getDaysBeforeStaleUsedOptionName( diff --git a/src/classes/operations.spec.ts b/src/classes/operations.spec.ts index c52e6c17c..664384668 100644 --- a/src/classes/operations.spec.ts +++ b/src/classes/operations.spec.ts @@ -10,9 +10,9 @@ describe('Operations', (): void => { it('should increase the count of operation consume by 1', (): void => { expect.assertions(1); - operations.consumeOperation(); + operations.consumeQueryOperation(); - const result = operations.getConsumedOperationsCount(); + const result = operations.getConsumedQueryOperationsCount(); expect(result).toStrictEqual(1); }); @@ -25,9 +25,9 @@ describe('Operations', (): void => { it('should increase the count of operation consume by the provided quantity', (): void => { expect.assertions(1); - operations.consumeOperations(8); + operations.consumeQueryOperations(8); - const result = operations.getConsumedOperationsCount(); + const result = operations.getConsumedQueryOperationsCount(); expect(result).toStrictEqual(8); }); @@ -41,7 +41,7 @@ describe('Operations', (): void => { it('should return 0 by default', (): void => { expect.assertions(1); - const result = operations.getConsumedOperationsCount(); + const result = operations.getConsumedQueryOperationsCount(); expect(result).toStrictEqual(0); }); diff --git a/src/classes/operations.ts b/src/classes/operations.ts index 3fc4bfad9..783bddad8 100644 --- a/src/classes/operations.ts +++ b/src/classes/operations.ts @@ -1,17 +1,32 @@ export class Operations { - protected _operationsConsumed = 0; + protected _queryOperationsConsumed = 0; + protected _mutationOperationsConsumed = 0; - consumeOperation(): Operations { - return this.consumeOperations(1); + consumeQueryOperation(): Operations { + return this.consumeQueryOperations(1); } - consumeOperations(quantity: Readonly): Operations { - this._operationsConsumed += quantity; + consumeMutationOperation(): Operations { + return this.consumeMutationOperations(1); + } + + consumeQueryOperations(quantity: Readonly): Operations { + this._queryOperationsConsumed += quantity; + + return this; + } + + consumeMutationOperations(quantity: Readonly): Operations { + this._mutationOperationsConsumed += quantity; return this; } - getConsumedOperationsCount(): number { - return this._operationsConsumed; + getConsumedQueryOperationsCount(): number { + return this._queryOperationsConsumed; + } + + getConsumedMutationOperationsCount(): number { + return this._mutationOperationsConsumed; } } diff --git a/src/classes/stale-operations.spec.ts b/src/classes/stale-operations.spec.ts index a44fd7f84..b2afff3c4 100644 --- a/src/classes/stale-operations.spec.ts +++ b/src/classes/stale-operations.spec.ts @@ -29,9 +29,9 @@ describe('StaleOperations', (): void => { it('should increase the count of operation consume by 1', (): void => { expect.assertions(1); - operations.consumeOperation(); + operations.consumeQueryOperation(); - const result = operations.getConsumedOperationsCount(); + const result = operations.getConsumedQueryOperationsCount(); expect(result).toStrictEqual(1); }); @@ -44,9 +44,9 @@ describe('StaleOperations', (): void => { it('should increase the count of operation consume by the provided quantity', (): void => { expect.assertions(1); - operations.consumeOperations(8); + operations.consumeQueryOperations(8); - const result = operations.getConsumedOperationsCount(); + const result = operations.getConsumedQueryOperationsCount(); expect(result).toStrictEqual(8); }); @@ -60,7 +60,7 @@ describe('StaleOperations', (): void => { it('should return 0 by default', (): void => { expect.assertions(1); - const result = operations.getConsumedOperationsCount(); + const result = operations.getConsumedQueryOperationsCount(); expect(result).toStrictEqual(0); }); @@ -83,15 +83,15 @@ describe('StaleOperations', (): void => { hasRemainingOperations }: IHasRemainingOperationsMatrix): void => { beforeEach((): void => { - options.operationsPerRun = operationsPerRun; + options.queryOperationsPerRun = operationsPerRun; operations = new StaleOperations(options); }); it(`should return ${hasRemainingOperations}`, (): void => { expect.assertions(1); - operations.consumeOperations(consumeOperations); + operations.consumeQueryOperations(consumeOperations); - const result = operations.hasRemainingOperations(); + const result = operations.hasRemainingQueryOperations(); expect(result).toStrictEqual(hasRemainingOperations); }); @@ -116,15 +116,15 @@ describe('StaleOperations', (): void => { getRemainingOperationsCount }: IGetRemainingOperationsCountMatrix): void => { beforeEach((): void => { - options.operationsPerRun = operationsPerRun; + options.queryOperationsPerRun = operationsPerRun; operations = new StaleOperations(options); }); it(`should return ${getRemainingOperationsCount}`, (): void => { expect.assertions(1); - operations.consumeOperations(consumeOperations); + operations.consumeQueryOperations(consumeOperations); - const result = operations.getRemainingOperationsCount(); + const result = operations.getRemainingQueryOperationsCount(); expect(result).toStrictEqual(getRemainingOperationsCount); }); diff --git a/src/classes/stale-operations.ts b/src/classes/stale-operations.ts index 79c097710..9b17b5864 100644 --- a/src/classes/stale-operations.ts +++ b/src/classes/stale-operations.ts @@ -9,11 +9,23 @@ export class StaleOperations extends Operations { this._options = options; } - hasRemainingOperations(): boolean { - return this._operationsConsumed < this._options.operationsPerRun; + hasRemainingQueryOperations(): boolean { + return this._queryOperationsConsumed < this._options.queryOperationsPerRun; } - getRemainingOperationsCount(): number { - return this._options.operationsPerRun - this._operationsConsumed; + hasRemainingMutationOperations(): boolean { + return ( + this._mutationOperationsConsumed < this._options.mutationOperationsPerRun + ); + } + + getRemainingQueryOperationsCount(): number { + return this._options.queryOperationsPerRun - this._queryOperationsConsumed; + } + + getRemainingMutationOperationsCount(): number { + return ( + this._options.mutationOperationsPerRun - this._mutationOperationsConsumed + ); } } diff --git a/src/classes/statistics.ts b/src/classes/statistics.ts index 321ea70d9..da4a7dc94 100644 --- a/src/classes/statistics.ts +++ b/src/classes/statistics.ts @@ -15,7 +15,8 @@ export class Statistics { stalePullRequestsCount = 0; undoStaleIssuesCount = 0; undoStalePullRequestsCount = 0; - operationsCount = 0; + queryOperationsCount = 0; + mutationOperationsCount = 0; closedIssuesCount = 0; closedPullRequestsCount = 0; deletedIssuesLabelsCount = 0; @@ -65,8 +66,14 @@ export class Statistics { return this._incrementUndoStaleIssuesCount(increment); } - setOperationsCount(operationsCount: Readonly): Statistics { - this.operationsCount = operationsCount; + setQueryOperationsCount(count: Readonly): Statistics { + this.queryOperationsCount = count; + + return this; + } + + setMutationOperationsCount(count: Readonly): Statistics { + this.mutationOperationsCount = count; return this; } @@ -435,7 +442,16 @@ export class Statistics { } private _logOperationsCount(): void { - this._logCount('Operations performed', this.operationsCount); + this._logGroup('Operations performed', [ + { + name: 'Query operations performed', + count: this.queryOperationsCount + }, + { + name: 'Mutation operations performed', + count: this.mutationOperationsCount + } + ]); } private _logCount(name: Readonly, count: Readonly): void { diff --git a/src/enums/option.ts b/src/enums/option.ts index f7167c725..1580ba4d1 100644 --- a/src/enums/option.ts +++ b/src/enums/option.ts @@ -20,7 +20,8 @@ export enum Option { OnlyIssueLabels = 'only-issue-labels', OnlyPrLabels = 'only-pr-labels', AnyOfLabels = 'any-of-labels', - OperationsPerRun = 'operations-per-run', + QueryOperationsPerRun = 'query-operations-per-run', + MutationOperationsPerRun = 'mutation-operations-per-run', RemoveStaleWhenUpdated = 'remove-stale-when-updated', RemoveIssueStaleWhenUpdated = 'remove-issue-stale-when-updated', RemovePrStaleWhenUpdated = 'remove-pr-stale-when-updated', diff --git a/src/interfaces/issues-processor-options.ts b/src/interfaces/issues-processor-options.ts index 8adbfb4a5..fbbaf4293 100644 --- a/src/interfaces/issues-processor-options.ts +++ b/src/interfaces/issues-processor-options.ts @@ -24,7 +24,8 @@ export interface IIssuesProcessorOptions { anyOfLabels: string; anyOfIssueLabels: string; anyOfPrLabels: string; - operationsPerRun: number; + queryOperationsPerRun: number; + mutationOperationsPerRun: number; removeStaleWhenUpdated: boolean; removeIssueStaleWhenUpdated: boolean | undefined; removePrStaleWhenUpdated: boolean | undefined; diff --git a/src/main.ts b/src/main.ts index af96654c5..db9b49962 100644 --- a/src/main.ts +++ b/src/main.ts @@ -50,8 +50,11 @@ function _getAndValidateArgs(): IIssuesProcessorOptions { anyOfLabels: core.getInput('any-of-labels'), anyOfIssueLabels: core.getInput('any-of-issue-labels'), anyOfPrLabels: core.getInput('any-of-pr-labels'), - operationsPerRun: parseInt( - core.getInput('operations-per-run', {required: true}) + queryOperationsPerRun: parseInt( + core.getInput('query-operations-per-run', {required: true}) + ), + mutationOperationsPerRun: parseInt( + core.getInput('mutation-operations-per-run', {required: true}) ), removeStaleWhenUpdated: !( core.getInput('remove-stale-when-updated') === 'false' @@ -93,7 +96,8 @@ function _getAndValidateArgs(): IIssuesProcessorOptions { for (const numberInput of [ 'days-before-stale', 'days-before-close', - 'operations-per-run' + 'query-operations-per-run', + 'mutation-operations-per-run' ]) { if (isNaN(parseInt(core.getInput(numberInput)))) { const errorMessage = `Option "${numberInput}" did not parse to a valid integer`; From 9da1ddd9b56c836670711f85ad5fa3d06333f508 Mon Sep 17 00:00:00 2001 From: TESTELIN Geoffrey Date: Wed, 9 Jun 2021 22:21:55 +0200 Subject: [PATCH 03/12] feat(operations): split the operations between queries and mutations Make sure to log the warning about the overflow of operations when the process fail fast due to a lack of operations as well as when it's finished as expected BREAKING CHANGE: the operations per run option no longer exists and was replaced by the query and mutation ones --- README.md | 2 +- src/classes/issues-processor.ts | 123 ++++++++++++++++++++++++-------- 2 files changed, 94 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 7fb21a903..289563bc7 100644 --- a/README.md +++ b/README.md @@ -751,7 +751,7 @@ If the [debug-only](#debug-only) option is enabled, this is very helpful because **Job frequency:** You could change the cron job frequency in the stale workflow to run the stale workflow more often. -Usually, this is not very helpful though. +Usually, we recommended running the workflow once per day nonetheless you could use a more frequent job and use a higher [query-operations-per-run](#query-operations-per-run) count to process all the issues in your repository and a lower [mutation-operations-per-run](#mutation-operations-per-run) count to only perform a few operations which reduce the risk in case of bad configuration. ### Contributing diff --git a/src/classes/issues-processor.ts b/src/classes/issues-processor.ts index 2047657fd..4ac401473 100644 --- a/src/classes/issues-processor.ts +++ b/src/classes/issues-processor.ts @@ -106,14 +106,8 @@ export class IssuesProcessor { this._logger.info( LoggerService.green(`No more issues found to process. Exiting...`) ); - this.statistics - ?.setQueryOperationsCount( - this.operations.getConsumedQueryOperationsCount() - ) - ?.setMutationOperationsCount( - this.operations.getConsumedMutationOperationsCount() - ) - .logStats(); + + this._onProcessingCompletion(); return; } else { @@ -136,9 +130,8 @@ export class IssuesProcessor { ); for (const issue of issues.values()) { - // @todo change? // Skip the processing if no more operations remains - if (!this.operations.hasRemainingQueryOperations()) { + if (!this._hasRemainingOperations()) { break; } @@ -152,28 +145,12 @@ export class IssuesProcessor { }); } - // @todo change? - if (!this.operations.hasRemainingQueryOperations()) { + if (!this._hasRemainingOperations()) { this._logger.warning( - LoggerService.yellowBright(`No more query operations left! Exiting...`) + LoggerService.yellowBright(`No more operations left! Exiting...`) ); - this._logger.warning( - `${LoggerService.yellowBright( - 'If you think that not enough issues were processed you could try to increase the quantity related to the' - )} ${this._logger.createOptionLink( - Option.QueryOperationsPerRun - )} ${LoggerService.yellowBright( - 'option which is currently set to' - )} ${LoggerService.cyan(this.options.queryOperationsPerRun)}` - ); - this.statistics - ?.setQueryOperationsCount( - this.operations.getConsumedQueryOperationsCount() - ) - ?.setMutationOperationsCount( - this.operations.getConsumedMutationOperationsCount() - ) - .logStats(); + + this._onProcessingCompletion(); return; } @@ -1247,4 +1224,90 @@ export class IssuesProcessor { return Option.RemoveStaleWhenUpdated; } + + /** + * @private + * + * @description + * Check if there is remaining operations + * Useful to stop the processing since it's pointless if there is no more operations available + * + * @returns {boolean} Return true if there is some remaining operations + */ + private _hasRemainingOperations(): boolean { + return ( + this.operations.hasRemainingQueryOperations() && + this.operations.hasRemainingMutationOperations() + ); + } + + /** + * @private + * + * @description + * Update the statistics about the operations and log the stats + */ + private _logStats(): void { + this.statistics + ?.setQueryOperationsCount( + this.operations.getConsumedQueryOperationsCount() + ) + ?.setMutationOperationsCount( + this.operations.getConsumedMutationOperationsCount() + ) + .logStats(); + } + + /** + * @private + * + * @description + * Log if there is no more operations + */ + private _logOperationsOverflow() { + if (!this.operations.hasRemainingQueryOperations()) { + this._logger.warning( + LoggerService.yellowBright( + `No more query operations left! The action was not able to process all the issues from your repository` + ) + ); + this._logger.warning( + `${LoggerService.yellowBright( + 'If you think that not enough issues were processed you could try to increase the quantity related to the' + )} ${this._logger.createOptionLink( + Option.QueryOperationsPerRun + )} ${LoggerService.yellowBright( + 'option which is currently set to' + )} ${LoggerService.cyan(this.options.queryOperationsPerRun)}` + ); + } + + if (!this.operations.hasRemainingMutationOperations()) { + this._logger.warning( + LoggerService.yellowBright( + `No more mutation operations left! The action was not able to add/remove/close all the labels/comments/issues` + ) + ); + this._logger.warning( + `${LoggerService.yellowBright( + 'If you think that not enough actions were taken to process the issues you could try to increase the quantity related to the' + )} ${this._logger.createOptionLink( + Option.MutationOperationsPerRun + )} ${LoggerService.yellowBright( + 'option which is currently set to' + )} ${LoggerService.cyan(this.options.mutationOperationsPerRun)}` + ); + } + } + + /** + * @private + * + * @description + * Start the logic when the issue processor can no longer process or when it's done processing + */ + private _onProcessingCompletion(): void { + this._logOperationsOverflow(); + this._logStats(); + } } From 393d62fbd36e90ec9421a95aaa31430e6ed6ed5e Mon Sep 17 00:00:00 2001 From: TESTELIN Geoffrey Date: Wed, 9 Jun 2021 22:29:31 +0200 Subject: [PATCH 04/12] docs(operations): enhance the wording of a comment --- src/classes/issues-processor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/classes/issues-processor.ts b/src/classes/issues-processor.ts index 4ac401473..94e996688 100644 --- a/src/classes/issues-processor.ts +++ b/src/classes/issues-processor.ts @@ -130,7 +130,7 @@ export class IssuesProcessor { ); for (const issue of issues.values()) { - // Skip the processing if no more operations remains + // Stop the processing if no more operations remains if (!this._hasRemainingOperations()) { break; } From 65c064b77e90d16efcfe585fd516846887b3756d Mon Sep 17 00:00:00 2001 From: TESTELIN Geoffrey Date: Mon, 14 Jun 2021 22:24:25 +0200 Subject: [PATCH 05/12] chore: apply changes due to rebase --- dist/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dist/index.js b/dist/index.js index 00a165f33..d31444e9d 100644 --- a/dist/index.js +++ b/dist/index.js @@ -9166,4 +9166,4 @@ module.exports = require("zlib");; /******/ module.exports = __webpack_exports__; /******/ /******/ })() -; +; \ No newline at end of file From 5b6cdf943d4d7f04d12954e9e5867eed68550d00 Mon Sep 17 00:00:00 2001 From: TESTELIN Geoffrey Date: Sun, 19 Sep 2021 20:26:04 +0200 Subject: [PATCH 06/12] style(log): change a log to be in a single row --- README.md | 4 ++-- dist/index.js | 13 ++----------- src/classes/issues-processor.ts | 6 +----- 3 files changed, 5 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 289563bc7..256d914f3 100644 --- a/README.md +++ b/README.md @@ -53,8 +53,8 @@ Every argument is optional. | [any-of-labels](#any-of-labels) | Only issues/PRs with ANY of these labels are checked | | | [any-of-issue-labels](#any-of-issue-labels) | Override [any-of-labels](#any-of-labels) for issues only | | | [any-of-pr-labels](#any-of-pr-labels) | Override [any-of-labels](#any-of-labels) for PRs only | | -| [query-operations-per-run](#query-operations-per-run) | Max number of query operations per run (GitHub read) | `30` | -| [mutation-operations-per-run](#mutation-operations-per-run) | Max number of mutation operations per run (GitHub write) | `200` | +| [query-operations-per-run](#query-operations-per-run) | Max number of query operations per run (GitHub read) | `30` | +| [mutation-operations-per-run](#mutation-operations-per-run) | Max number of mutation operations per run (GitHub write) | `200` | | [remove-stale-when-updated](#remove-stale-when-updated) | Remove stale label from issues/PRs on updates | `true` | | [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 | | diff --git a/dist/index.js b/dist/index.js index d31444e9d..7de237ab7 100644 --- a/dist/index.js +++ b/dist/index.js @@ -263,7 +263,6 @@ exports.Issue = void 0; const is_labeled_1 = __nccwpck_require__(6792); const is_pull_request_1 = __nccwpck_require__(5400); const operations_1 = __nccwpck_require__(7957); -const logger_1 = __nccwpck_require__(6212); class Issue { constructor(options, issue) { this.operations = new operations_1.Operations(); @@ -278,10 +277,6 @@ class Issue { this.locked = issue.locked; this.milestone = issue.milestone; this.assignees = issue.assignees; - // @todo remove this log - const logger = new logger_1.Logger(); - logger.info('Assignees:'); - logger.info(...this.assignees.map((assignee) => JSON.stringify(assignee))); this.isStale = is_labeled_1.isLabeled(this, this.staleLabel); } get isPullRequest() { @@ -886,11 +881,7 @@ class IssuesProcessor { var _a; return __awaiter(this, void 0, void 0, function* () { const issueLogger = new issue_logger_1.IssueLogger(issue); - issueLogger.info(`Delete - branch from closed $ - $type - - - ${issue.title}`); + issueLogger.info(`Delete branch from closed $$type - ${issue.title}`); const pullRequest = yield this.getPullRequest(issue); if (!pullRequest) { issueLogger.info(`Not deleting this branch as no pull request was found for this $$type`); @@ -9166,4 +9157,4 @@ module.exports = require("zlib");; /******/ module.exports = __webpack_exports__; /******/ /******/ })() -; \ No newline at end of file +; diff --git a/src/classes/issues-processor.ts b/src/classes/issues-processor.ts index 94e996688..999461d7b 100644 --- a/src/classes/issues-processor.ts +++ b/src/classes/issues-processor.ts @@ -884,11 +884,7 @@ export class IssuesProcessor { private async _deleteBranch(issue: Issue): Promise { const issueLogger: IssueLogger = new IssueLogger(issue); - issueLogger.info(`Delete - branch from closed $ - $type - - - ${issue.title}`); + issueLogger.info(`Delete branch from closed $$type - ${issue.title}`); const pullRequest: IPullRequest | undefined | void = await this.getPullRequest(issue); From 7e16ba536d23b53511ca1eb996425c37b3e8443e Mon Sep 17 00:00:00 2001 From: TESTELIN Geoffrey Date: Sun, 19 Sep 2021 20:40:49 +0200 Subject: [PATCH 07/12] build(steps): split the steps --- .github/workflows/test.yml | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6abb97840..4f2195cc0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,14 +7,35 @@ on: # rebuild any PRs and main branch changes - 'releases/*' jobs: - build: # make sure build/ci work properly + build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - run: | npm ci - npm run all:ci - test: # make sure the action works on a clean machine without building + npm run build + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: | + npm ci + npm run lint:all + pack: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: | + npm ci + npm run pack + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: | + npm ci + npm run test:only-errors" + e2e: # make sure the action works on a clean machine without building runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 From baab22449366a147ae02e02b719a01f7c92cc867 Mon Sep 17 00:00:00 2001 From: TESTELIN Geoffrey Date: Sun, 19 Sep 2021 20:45:29 +0200 Subject: [PATCH 08/12] test: fix failing test due to wrong return type --- __tests__/updates-reset-stale.spec.ts | 4 ++-- package.json | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/__tests__/updates-reset-stale.spec.ts b/__tests__/updates-reset-stale.spec.ts index 11865ecf1..4d02da603 100644 --- a/__tests__/updates-reset-stale.spec.ts +++ b/__tests__/updates-reset-stale.spec.ts @@ -658,7 +658,7 @@ class SUT { return this; } - async test(): Promise { + async test(): Promise { return this._setTestIssueList()._setProcessor(); } @@ -683,7 +683,7 @@ class SUT { return this; } - private async _setProcessor(): Promise { + private async _setProcessor(): Promise { this.processor = new IssuesProcessorMock( this._opts, async p => (p === 1 ? this._testIssueList : []), diff --git a/package.json b/package.json index e28be1ba1..bf8654a0e 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,6 @@ "test:only-errors": "jest --reporters jest-silent-reporter --silent", "test:watch": "jest --watch --notify --expand", "all": "npm run build && npm run format && npm run lint && npm run pack && npm test", - "all:ci": "npm run build && npm run lint:all && npm run pack && npm run test:only-errors", "prerelease": "npm run build && npm run pack", "release": "standard-version", "release:dry-run": "standard-version --dry-run" From 33e5dfd8d4bbc14797766ba3f759be0cf0df6344 Mon Sep 17 00:00:00 2001 From: TESTELIN Geoffrey Date: Sun, 19 Sep 2021 20:47:03 +0200 Subject: [PATCH 09/12] build: pack after build --- .github/workflows/test.yml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4f2195cc0..51833baa6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v2 - run: | npm ci - npm run build + npm run build && npm run pack lint: runs-on: ubuntu-latest steps: @@ -21,13 +21,6 @@ jobs: - run: | npm ci npm run lint:all - pack: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - run: | - npm ci - npm run pack test: runs-on: ubuntu-latest steps: From aa6139fc31b5f6cac6f7d71d17d1dd1b5c27531f Mon Sep 17 00:00:00 2001 From: TESTELIN Geoffrey Date: Sun, 19 Sep 2021 20:55:40 +0200 Subject: [PATCH 10/12] build: fix typo --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 51833baa6..7eccf7434 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,7 +27,7 @@ jobs: - uses: actions/checkout@v2 - run: | npm ci - npm run test:only-errors" + npm run test:only-errors e2e: # make sure the action works on a clean machine without building runs-on: ubuntu-latest steps: From 5f41ed03f4cd42b5c527f41604ed0df1b2023c01 Mon Sep 17 00:00:00 2001 From: Geoffrey Testelin Date: Tue, 21 Sep 2021 13:57:02 +0200 Subject: [PATCH 11/12] refactor(pr): remove useless code --- src/classes/issues-processor.ts | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/classes/issues-processor.ts b/src/classes/issues-processor.ts index 999461d7b..6eb7fd34d 100644 --- a/src/classes/issues-processor.ts +++ b/src/classes/issues-processor.ts @@ -859,27 +859,6 @@ export class IssuesProcessor { } } - private async _getPullRequest( - issue: Issue - ): Promise { - const issueLogger: IssueLogger = new IssueLogger(issue); - - try { - this._consumeIssueQueryOperation(issue); - this._statistics?.incrementFetchedPullRequestsCount(); - - const pullRequest = await this.client.pulls.get({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: issue.number - }); - - return pullRequest.data; - } catch (error) { - issueLogger.error(`Error when getting this $$type: ${error.message}`); - } - } - // Delete the branch on closed pull request private async _deleteBranch(issue: Issue): Promise { const issueLogger: IssueLogger = new IssueLogger(issue); From 72c9c800759dc16bc989fb854dd6b66f231483df Mon Sep 17 00:00:00 2001 From: Geoffrey Testelin Date: Wed, 22 Sep 2021 19:14:51 +0200 Subject: [PATCH 12/12] chore(index): update index file --- dist/index.js | 195 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 148 insertions(+), 47 deletions(-) diff --git a/dist/index.js b/dist/index.js index 7de237ab7..df2fc229a 100644 --- a/dist/index.js +++ b/dist/index.js @@ -385,24 +385,23 @@ class IssuesProcessor { return millisSinceLastUpdated <= daysInMillis; } static _endIssueProcessing(issue) { - const consumedOperationsCount = issue.operations.getConsumedOperationsCount(); - if (consumedOperationsCount > 0) { + const consumedQueryOperationsCount = issue.operations.getConsumedQueryOperationsCount(); + if (consumedQueryOperationsCount > 0) { const issueLogger = new issue_logger_1.IssueLogger(issue); - issueLogger.info(logger_service_1.LoggerService.cyan(consumedOperationsCount), `operation${consumedOperationsCount > 1 ? 's' : ''} consumed for this $$type`); + issueLogger.info(logger_service_1.LoggerService.cyan(consumedQueryOperationsCount), `query operation${consumedQueryOperationsCount > 1 ? 's' : ''} consumed for this $$type`); } } static _getCloseLabelUsedOptionName(issue) { return issue.isPullRequest ? option_1.Option.ClosePrLabel : option_1.Option.CloseIssueLabel; } processIssues(page = 1) { - var _a, _b; return __awaiter(this, void 0, void 0, function* () { // get the next batch of issues const issues = yield this.getIssues(page); if (issues.length <= 0) { this._logger.info(logger_service_1.LoggerService.green(`No more issues found to process. Exiting...`)); - (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.setOperationsCount(this.operations.getConsumedOperationsCount()).logStats(); - return this.operations.getRemainingOperationsCount(); + this._onProcessingCompletion(); + return; } else { this._logger.info(`${logger_service_1.LoggerService.yellow('Processing the batch of issues')} ${logger_service_1.LoggerService.cyan(`#${page}`)} ${logger_service_1.LoggerService.yellow('containing')} ${logger_service_1.LoggerService.cyan(issues.length)} ${logger_service_1.LoggerService.yellow(`issue${issues.length > 1 ? 's' : ''}...`)}`); @@ -411,7 +410,7 @@ class IssuesProcessor { const labelsToRemoveWhenUnstale = words_to_list_1.wordsToList(this.options.labelsToRemoveWhenUnstale); for (const issue of issues.values()) { // Stop the processing if no more operations remains - if (!this.operations.hasRemainingOperations()) { + if (!this._hasRemainingOperations()) { break; } const issueLogger = new issue_logger_1.IssueLogger(issue); @@ -419,11 +418,10 @@ class IssuesProcessor { yield this.processIssue(issue, labelsToAddWhenUnstale, labelsToRemoveWhenUnstale); })); } - if (!this.operations.hasRemainingOperations()) { + if (!this._hasRemainingOperations()) { this._logger.warning(logger_service_1.LoggerService.yellowBright(`No more operations left! Exiting...`)); - this._logger.warning(`${logger_service_1.LoggerService.yellowBright('If you think that not enough issues were processed you could try to increase the quantity related to the')} ${this._logger.createOptionLink(option_1.Option.OperationsPerRun)} ${logger_service_1.LoggerService.yellowBright('option which is currently set to')} ${logger_service_1.LoggerService.cyan(this.options.operationsPerRun)}`); - (_b = this.statistics) === null || _b === void 0 ? void 0 : _b.setOperationsCount(this.operations.getConsumedOperationsCount()).logStats(); - return 0; + this._onProcessingCompletion(); + return; } this._logger.info(`${logger_service_1.LoggerService.green('Batch')} ${logger_service_1.LoggerService.cyan(`#${page}`)} ${logger_service_1.LoggerService.green('processed.')}`); // Do the next batch @@ -618,7 +616,7 @@ class IssuesProcessor { return __awaiter(this, void 0, void 0, function* () { // Find any comments since date on the given issue try { - this.operations.consumeOperation(); + this.operations.consumeQueryOperation(); (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementFetchedItemsCommentsCount(); const comments = yield this.client.issues.listComments({ owner: github_1.context.repo.owner, @@ -641,7 +639,7 @@ class IssuesProcessor { // generate type for response const endpoint = this.client.issues.listForRepo; try { - this.operations.consumeOperation(); + this.operations.consumeQueryOperation(); const issueResult = yield this.client.issues.listForRepo({ owner: github_1.context.repo.owner, repo: github_1.context.repo.repo, @@ -666,7 +664,7 @@ class IssuesProcessor { return __awaiter(this, void 0, void 0, function* () { const issueLogger = new issue_logger_1.IssueLogger(issue); issueLogger.info(`Checking for label on this $$type`); - this._consumeIssueOperation(issue); + this._consumeIssueQueryOperation(issue); (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementFetchedItemsEventsCount(); const options = this.client.issues.listEvents.endpoint.merge({ owner: github_1.context.repo.owner, @@ -690,7 +688,7 @@ class IssuesProcessor { return __awaiter(this, void 0, void 0, function* () { const issueLogger = new issue_logger_1.IssueLogger(issue); try { - this._consumeIssueOperation(issue); + this._consumeIssueQueryOperation(issue); (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementFetchedPullRequestsCount(); const pullRequest = yield this.client.pulls.get({ owner: github_1.context.repo.owner, @@ -784,7 +782,7 @@ class IssuesProcessor { issue.updated_at = newUpdatedAtDate.toString(); if (!skipMessage) { try { - this._consumeIssueOperation(issue); + this._consumeIssueMutationOperation(issue); (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementAddedItemsComment(issue); if (!this.options.debugOnly) { yield this.client.issues.createComment({ @@ -800,7 +798,7 @@ class IssuesProcessor { } } try { - this._consumeIssueOperation(issue); + this._consumeIssueMutationOperation(issue); (_b = this.statistics) === null || _b === void 0 ? void 0 : _b.incrementAddedItemsLabel(issue); (_c = this.statistics) === null || _c === void 0 ? void 0 : _c.incrementStaleItemsCount(issue); if (!this.options.debugOnly) { @@ -826,7 +824,7 @@ class IssuesProcessor { this.closedIssues.push(issue); if (closeMessage) { try { - this._consumeIssueOperation(issue); + this._consumeIssueMutationOperation(issue); (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementAddedItemsComment(issue); this.addedCloseCommentIssues.push(issue); if (!this.options.debugOnly) { @@ -844,7 +842,7 @@ class IssuesProcessor { } if (closeLabel) { try { - this._consumeIssueOperation(issue); + this._consumeIssueMutationOperation(issue); (_b = this.statistics) === null || _b === void 0 ? void 0 : _b.incrementAddedItemsLabel(issue); if (!this.options.debugOnly) { yield this.client.issues.addLabels({ @@ -860,7 +858,7 @@ class IssuesProcessor { } } try { - this._consumeIssueOperation(issue); + this._consumeIssueMutationOperation(issue); (_c = this.statistics) === null || _c === void 0 ? void 0 : _c.incrementClosedItemsCount(issue); if (!this.options.debugOnly) { yield this.client.issues.update({ @@ -890,7 +888,7 @@ class IssuesProcessor { const branch = pullRequest.head.ref; issueLogger.info(`Deleting the branch "${logger_service_1.LoggerService.cyan(branch)}" from closed $$type`); try { - this._consumeIssueOperation(issue); + this._consumeIssueMutationOperation(issue); (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementDeletedBranchesCount(); if (!this.options.debugOnly) { yield this.client.git.deleteRef({ @@ -913,7 +911,7 @@ class IssuesProcessor { issueLogger.info(`${isSubStep ? logger_service_1.LoggerService.white('├── ') : ''}Removing the label "${logger_service_1.LoggerService.cyan(label)}" from this $$type...`); this.removedLabelIssues.push(issue); try { - this._consumeIssueOperation(issue); + this._consumeIssueMutationOperation(issue); (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementDeletedItemsLabelsCount(issue); if (!this.options.debugOnly) { yield this.client.issues.removeLabel({ @@ -1010,7 +1008,7 @@ class IssuesProcessor { issueLogger.info(`Adding all the labels specified via the ${this._logger.createOptionLink(option_1.Option.LabelsToAddWhenUnstale)} option.`); this.addedLabelIssues.push(issue); try { - this.operations.consumeOperation(); + this.operations.consumeMutationOperation(); (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementAddedItemsLabel(issue); if (!this.options.debugOnly) { yield this.client.issues.addLabels({ @@ -1056,9 +1054,29 @@ class IssuesProcessor { } }); } - _consumeIssueOperation(issue) { - this.operations.consumeOperation(); - issue.operations.consumeOperation(); + /** + * @private + * + * @description + * Increase the counter of consumed operation related to queries (GitHub read) + * + * @param {Readonly} issue The processed issue + */ + _consumeIssueQueryOperation(issue) { + this.operations.consumeQueryOperation(); + issue.operations.consumeQueryOperation(); + } + /** + * @private + * + * @description + * Increase the counter of consumed operation related to mutations (GitHub write) + * + * @param {Readonly} issue The processed issue + */ + _consumeIssueMutationOperation(issue) { + this.operations.consumeMutationOperation(); + issue.operations.consumeMutationOperation(); } _getDaysBeforeStaleUsedOptionName(issue) { return issue.isPullRequest @@ -1087,6 +1105,55 @@ class IssuesProcessor { } return option_1.Option.RemoveStaleWhenUpdated; } + /** + * @private + * + * @description + * Check if there is remaining operations + * Useful to stop the processing since it's pointless if there is no more operations available + * + * @returns {boolean} Return true if there is some remaining operations + */ + _hasRemainingOperations() { + return (this.operations.hasRemainingQueryOperations() && + this.operations.hasRemainingMutationOperations()); + } + /** + * @private + * + * @description + * Update the statistics about the operations and log the stats + */ + _logStats() { + var _a, _b; + (_b = (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.setQueryOperationsCount(this.operations.getConsumedQueryOperationsCount())) === null || _b === void 0 ? void 0 : _b.setMutationOperationsCount(this.operations.getConsumedMutationOperationsCount()).logStats(); + } + /** + * @private + * + * @description + * Log if there is no more operations + */ + _logOperationsOverflow() { + if (!this.operations.hasRemainingQueryOperations()) { + this._logger.warning(logger_service_1.LoggerService.yellowBright(`No more query operations left! The action was not able to process all the issues from your repository`)); + this._logger.warning(`${logger_service_1.LoggerService.yellowBright('If you think that not enough issues were processed you could try to increase the quantity related to the')} ${this._logger.createOptionLink(option_1.Option.QueryOperationsPerRun)} ${logger_service_1.LoggerService.yellowBright('option which is currently set to')} ${logger_service_1.LoggerService.cyan(this.options.queryOperationsPerRun)}`); + } + if (!this.operations.hasRemainingMutationOperations()) { + this._logger.warning(logger_service_1.LoggerService.yellowBright(`No more mutation operations left! The action was not able to add/remove/close all the labels/comments/issues`)); + this._logger.warning(`${logger_service_1.LoggerService.yellowBright('If you think that not enough actions were taken to process the issues you could try to increase the quantity related to the')} ${this._logger.createOptionLink(option_1.Option.MutationOperationsPerRun)} ${logger_service_1.LoggerService.yellowBright('option which is currently set to')} ${logger_service_1.LoggerService.cyan(this.options.mutationOperationsPerRun)}`); + } + } + /** + * @private + * + * @description + * Start the logic when the issue processor can no longer process or when it's done processing + */ + _onProcessingCompletion() { + this._logOperationsOverflow(); + this._logStats(); + } } exports.IssuesProcessor = IssuesProcessor; @@ -1404,17 +1471,28 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.Operations = void 0; class Operations { constructor() { - this._operationsConsumed = 0; + this._queryOperationsConsumed = 0; + this._mutationOperationsConsumed = 0; + } + consumeQueryOperation() { + return this.consumeQueryOperations(1); } - consumeOperation() { - return this.consumeOperations(1); + consumeMutationOperation() { + return this.consumeMutationOperations(1); } - consumeOperations(quantity) { - this._operationsConsumed += quantity; + consumeQueryOperations(quantity) { + this._queryOperationsConsumed += quantity; return this; } - getConsumedOperationsCount() { - return this._operationsConsumed; + consumeMutationOperations(quantity) { + this._mutationOperationsConsumed += quantity; + return this; + } + getConsumedQueryOperationsCount() { + return this._queryOperationsConsumed; + } + getConsumedMutationOperationsCount() { + return this._mutationOperationsConsumed; } } exports.Operations = Operations; @@ -1435,11 +1513,17 @@ class StaleOperations extends operations_1.Operations { super(); this._options = options; } - hasRemainingOperations() { - return this._operationsConsumed < this._options.operationsPerRun; + hasRemainingQueryOperations() { + return this._queryOperationsConsumed < this._options.queryOperationsPerRun; + } + hasRemainingMutationOperations() { + return (this._mutationOperationsConsumed < this._options.mutationOperationsPerRun); } - getRemainingOperationsCount() { - return this._options.operationsPerRun - this._operationsConsumed; + getRemainingQueryOperationsCount() { + return this._options.queryOperationsPerRun - this._queryOperationsConsumed; + } + getRemainingMutationOperationsCount() { + return (this._options.mutationOperationsPerRun - this._mutationOperationsConsumed); } } exports.StaleOperations = StaleOperations; @@ -1465,7 +1549,8 @@ class Statistics { this.stalePullRequestsCount = 0; this.undoStaleIssuesCount = 0; this.undoStalePullRequestsCount = 0; - this.operationsCount = 0; + this.queryOperationsCount = 0; + this.mutationOperationsCount = 0; this.closedIssuesCount = 0; this.closedPullRequestsCount = 0; this.deletedIssuesLabelsCount = 0; @@ -1500,8 +1585,12 @@ class Statistics { } return this._incrementUndoStaleIssuesCount(increment); } - setOperationsCount(operationsCount) { - this.operationsCount = operationsCount; + setQueryOperationsCount(count) { + this.queryOperationsCount = count; + return this; + } + setMutationOperationsCount(count) { + this.mutationOperationsCount = count; return this; } incrementClosedItemsCount(issue, increment = 1) { @@ -1748,7 +1837,16 @@ class Statistics { this._logCount('Fetched pull requests', this.fetchedPullRequestsCount); } _logOperationsCount() { - this._logCount('Operations performed', this.operationsCount); + this._logGroup('Operations performed', [ + { + name: 'Query operations performed', + count: this.queryOperationsCount + }, + { + name: 'Mutation operations performed', + count: this.mutationOperationsCount + } + ]); } _logCount(name, count) { if (count > 0) { @@ -1843,7 +1941,8 @@ var Option; Option["OnlyIssueLabels"] = "only-issue-labels"; Option["OnlyPrLabels"] = "only-pr-labels"; Option["AnyOfLabels"] = "any-of-labels"; - Option["OperationsPerRun"] = "operations-per-run"; + Option["QueryOperationsPerRun"] = "query-operations-per-run"; + Option["MutationOperationsPerRun"] = "mutation-operations-per-run"; Option["RemoveStaleWhenUpdated"] = "remove-stale-when-updated"; Option["RemoveIssueStaleWhenUpdated"] = "remove-issue-stale-when-updated"; Option["RemovePrStaleWhenUpdated"] = "remove-pr-stale-when-updated"; @@ -2152,7 +2251,8 @@ function _getAndValidateArgs() { anyOfLabels: core.getInput('any-of-labels'), anyOfIssueLabels: core.getInput('any-of-issue-labels'), anyOfPrLabels: core.getInput('any-of-pr-labels'), - operationsPerRun: parseInt(core.getInput('operations-per-run', { required: true })), + queryOperationsPerRun: parseInt(core.getInput('query-operations-per-run', { required: true })), + mutationOperationsPerRun: parseInt(core.getInput('mutation-operations-per-run', { required: true })), removeStaleWhenUpdated: !(core.getInput('remove-stale-when-updated') === 'false'), removeIssueStaleWhenUpdated: _toOptionalBoolean('remove-issue-stale-when-updated'), removePrStaleWhenUpdated: _toOptionalBoolean('remove-pr-stale-when-updated'), @@ -2185,7 +2285,8 @@ function _getAndValidateArgs() { for (const numberInput of [ 'days-before-stale', 'days-before-close', - 'operations-per-run' + 'query-operations-per-run', + 'mutation-operations-per-run' ]) { if (isNaN(parseInt(core.getInput(numberInput)))) { const errorMessage = `Option "${numberInput}" did not parse to a valid integer`; @@ -9149,12 +9250,12 @@ module.exports = require("zlib");; /******/ /* webpack/runtime/compat */ /******/ /******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = __dirname + "/";/************************************************************************/ -/******/ +/******/ /******/ // startup /******/ // Load entry module and return exports /******/ // This entry module is referenced by other modules so it can't be inlined /******/ var __webpack_exports__ = __nccwpck_require__(3109); /******/ module.exports = __webpack_exports__; -/******/ +/******/ /******/ })() -; +; \ No newline at end of file