From 1f507bdb42723c5179df6804bed61b1ffc48c4ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Gorzeli=C5=84ski?= Date: Mon, 19 Jun 2023 14:22:05 +0200 Subject: [PATCH] Add updates on reactions --- dist/index.js | 63 ++++++++++++++++++++++++++- src/classes/issues-processor.ts | 76 ++++++++++++++++++++++++++++++++- src/classes/statistics.ts | 14 ++++++ src/interfaces/issue.ts | 2 + src/interfaces/reaction.ts | 4 ++ 5 files changed, 155 insertions(+), 4 deletions(-) create mode 100644 src/interfaces/reaction.ts diff --git a/dist/index.js b/dist/index.js index 6937fa60..14247d77 100644 --- a/dist/index.js +++ b/dist/index.js @@ -654,6 +654,38 @@ class IssuesProcessor { } }); } + // Grab reactions for an issue since a given date + listIssueReactions(issue, sinceDate) { + var _a; + return __awaiter(this, void 0, void 0, function* () { + try { + this._consumeIssueOperation(issue); + (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementFetchedItemsReactionsCount(); + let reactions = []; + let currentReactions = []; + let iterator = 1; + const daysSinceLastUpdated = (new Date().getTime() - new Date(sinceDate).getTime()) / + (1000 * 60 * 60 * 24); + do { + const response = yield this.client.rest.reactions.listForIssue({ + owner: github_1.context.repo.owner, + repo: github_1.context.repo.repo, + issue_number: issue.number, + per_page: 100, + page: iterator + }); + currentReactions = response.data; + reactions = [...reactions, ...currentReactions]; + iterator++; + } while (currentReactions.length !== 0); + return reactions.filter(reaction => IssuesProcessor._updatedSince(reaction.created_at, daysSinceLastUpdated)); + } + catch (error) { + this._logger.error(`List issue reactions error: ${error.message}`); + return Promise.resolve([]); + } + }); + } // grab issues from github in batches of 100 getIssues(page) { var _a; @@ -729,6 +761,8 @@ class IssuesProcessor { issueLogger.info(`$$type marked stale on: ${logger_service_1.LoggerService.cyan(markedStaleOn)}`); const issueHasCommentsSinceStale = yield this._hasCommentsSince(issue, markedStaleOn, staleMessage); issueLogger.info(`$$type has been commented on: ${logger_service_1.LoggerService.cyan(issueHasCommentsSinceStale)}`); + const issueHasReactionsSinceStale = yield this._hasReactionsSince(issue, markedStaleOn); + issueLogger.info(`$$type had a reaction: ${logger_service_1.LoggerService.cyan(issueHasReactionsSinceStale)}`); const daysBeforeClose = issue.isPullRequest ? this._getDaysBeforePrClose() : this._getDaysBeforeIssueClose(); @@ -751,7 +785,9 @@ class IssuesProcessor { issueLogger.info(`$$type has been updated since it was marked stale: ${logger_service_1.LoggerService.cyan(issueHasUpdateSinceStale)}`); // Should we un-stale this issue? if (shouldRemoveStaleWhenUpdated && - (issueHasUpdateSinceStale || issueHasCommentsSinceStale) && + (issueHasUpdateSinceStale || + issueHasCommentsSinceStale || + issueHasReactionsSinceStale) && !issue.markedStaleThisRun) { issueLogger.info(`Remove the stale label since the $$type has been updated and the workflow should remove the stale label when updated`); yield this._removeStaleLabel(issue, staleLabel); @@ -767,7 +803,9 @@ class IssuesProcessor { } const issueHasUpdateInCloseWindow = IssuesProcessor._updatedSince(issue.updated_at, daysBeforeClose); issueLogger.info(`$$type has been updated in the last ${daysBeforeClose} days: ${logger_service_1.LoggerService.cyan(issueHasUpdateInCloseWindow)}`); - if (!issueHasCommentsSinceStale && !issueHasUpdateInCloseWindow) { + if (!issueHasCommentsSinceStale && + !issueHasUpdateInCloseWindow && + !issueHasReactionsSinceStale) { issueLogger.info(`Closing $$type because it was last updated on: ${logger_service_1.LoggerService.cyan(issue.updated_at)}`); yield this._closeIssue(issue, closeMessage, closeLabel); if (this.options.deleteBranch && issue.pull_request) { @@ -801,6 +839,18 @@ class IssuesProcessor { return filteredComments.length > 0; }); } + // find any reactions since the date + _hasReactionsSince(issue, sinceDate) { + return __awaiter(this, void 0, void 0, function* () { + const issueLogger = new issue_logger_1.IssueLogger(issue); + issueLogger.info(`Checking for reactions on $$type since: ${logger_service_1.LoggerService.cyan(sinceDate)}`); + if (!sinceDate) { + return true; + } + const reactions = yield this.listIssueReactions(issue, sinceDate); + return reactions.length > 0; + }); + } // Mark an issue as stale with a comment and a label _markStale(issue, staleMessage, staleLabel, skipMessage) { var _a, _b, _c; @@ -1529,6 +1579,7 @@ class Statistics { this.fetchedItemsCount = 0; this.fetchedItemsEventsCount = 0; this.fetchedItemsCommentsCount = 0; + this.fetchedItemsReactionsCount = 0; this.fetchedPullRequestsCount = 0; } incrementProcessedItemsCount(issue, increment = 1) { @@ -1599,6 +1650,10 @@ class Statistics { this.fetchedItemsCommentsCount += increment; return this; } + incrementFetchedItemsReactionsCount(increment = 1) { + this.fetchedItemsReactionsCount += increment; + return this; + } incrementFetchedPullRequestsCount(increment = 1) { this.fetchedPullRequestsCount += increment; return this; @@ -1617,6 +1672,7 @@ class Statistics { this._logFetchedItemsCount(); this._logFetchedItemsEventsCount(); this._logFetchedItemsCommentsCount(); + this._logFetchedItemsReactionsCount(); this._logFetchedPullRequestsCount(); this._logOperationsCount(); return this; @@ -1793,6 +1849,9 @@ class Statistics { _logFetchedItemsCommentsCount() { this._logCount('Fetched items comments', this.fetchedItemsCommentsCount); } + _logFetchedItemsReactionsCount() { + this._logCount('Fetched items reactions', this.fetchedItemsReactionsCount); + } _logFetchedPullRequestsCount() { this._logCount('Fetched pull requests', this.fetchedPullRequestsCount); } diff --git a/src/classes/issues-processor.ts b/src/classes/issues-processor.ts index 9c4a633d..d4977913 100644 --- a/src/classes/issues-processor.ts +++ b/src/classes/issues-processor.ts @@ -14,6 +14,7 @@ import {IComment} from '../interfaces/comment'; import {IIssueEvent} from '../interfaces/issue-event'; import {IIssuesProcessorOptions} from '../interfaces/issues-processor-options'; import {IPullRequest} from '../interfaces/pull-request'; +import {IReaction} from '../interfaces/reaction'; import {Assignees} from './assignees'; import {IgnoreUpdates} from './ignore-updates'; import {ExemptDraftPullRequest} from './exempt-draft-pull-request'; @@ -546,6 +547,41 @@ export class IssuesProcessor { } } + // Grab reactions for an issue since a given date + async listIssueReactions( + issue: Readonly, + sinceDate: Readonly + ): Promise { + try { + this._consumeIssueOperation(issue); + this.statistics?.incrementFetchedItemsReactionsCount(); + let reactions: IReaction[] = []; + let currentReactions: IReaction[] = []; + let iterator = 1; + const daysSinceLastUpdated = + (new Date().getTime() - new Date(sinceDate).getTime()) / + (1000 * 60 * 60 * 24); + do { + const response = await this.client.rest.reactions.listForIssue({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + per_page: 100, + page: iterator + }); + currentReactions = response.data; + reactions = [...reactions, ...currentReactions]; + iterator++; + } while (currentReactions.length !== 0); + return reactions.filter(reaction => + IssuesProcessor._updatedSince(reaction.created_at, daysSinceLastUpdated) + ); + } catch (error) { + this._logger.error(`List issue reactions error: ${error.message}`); + return Promise.resolve([]); + } + } + // grab issues from github in batches of 100 async getIssues(page: number): Promise { try { @@ -652,6 +688,16 @@ export class IssuesProcessor { )}` ); + const issueHasReactionsSinceStale: boolean = await this._hasReactionsSince( + issue, + markedStaleOn + ); + issueLogger.info( + `$$type had a reaction: ${LoggerService.cyan( + issueHasReactionsSinceStale + )}` + ); + const daysBeforeClose: number = issue.isPullRequest ? this._getDaysBeforePrClose() : this._getDaysBeforeIssueClose(); @@ -703,7 +749,9 @@ export class IssuesProcessor { // Should we un-stale this issue? if ( shouldRemoveStaleWhenUpdated && - (issueHasUpdateSinceStale || issueHasCommentsSinceStale) && + (issueHasUpdateSinceStale || + issueHasCommentsSinceStale || + issueHasReactionsSinceStale) && !issue.markedStaleThisRun ) { issueLogger.info( @@ -739,7 +787,11 @@ export class IssuesProcessor { )}` ); - if (!issueHasCommentsSinceStale && !issueHasUpdateInCloseWindow) { + if ( + !issueHasCommentsSinceStale && + !issueHasUpdateInCloseWindow && + !issueHasReactionsSinceStale + ) { issueLogger.info( `Closing $$type because it was last updated on: ${LoggerService.cyan( issue.updated_at @@ -798,6 +850,26 @@ export class IssuesProcessor { return filteredComments.length > 0; } + // find any reactions since the date + private async _hasReactionsSince( + issue: Issue, + sinceDate: string + ): Promise { + const issueLogger: IssueLogger = new IssueLogger(issue); + + issueLogger.info( + `Checking for reactions on $$type since: ${LoggerService.cyan(sinceDate)}` + ); + + if (!sinceDate) { + return true; + } + + const reactions = await this.listIssueReactions(issue, sinceDate); + + return reactions.length > 0; + } + // Mark an issue as stale with a comment and a label private async _markStale( issue: Issue, diff --git a/src/classes/statistics.ts b/src/classes/statistics.ts index 321ea70d..dcf06e45 100644 --- a/src/classes/statistics.ts +++ b/src/classes/statistics.ts @@ -30,6 +30,7 @@ export class Statistics { fetchedItemsCount = 0; fetchedItemsEventsCount = 0; fetchedItemsCommentsCount = 0; + fetchedItemsReactionsCount = 0; fetchedPullRequestsCount = 0; incrementProcessedItemsCount( @@ -154,6 +155,14 @@ export class Statistics { return this; } + incrementFetchedItemsReactionsCount( + increment: Readonly = 1 + ): Statistics { + this.fetchedItemsReactionsCount += increment; + + return this; + } + incrementFetchedPullRequestsCount( increment: Readonly = 1 ): Statistics { @@ -176,6 +185,7 @@ export class Statistics { this._logFetchedItemsCount(); this._logFetchedItemsEventsCount(); this._logFetchedItemsCommentsCount(); + this._logFetchedItemsReactionsCount(); this._logFetchedPullRequestsCount(); this._logOperationsCount(); @@ -430,6 +440,10 @@ export class Statistics { this._logCount('Fetched items comments', this.fetchedItemsCommentsCount); } + private _logFetchedItemsReactionsCount(): void { + this._logCount('Fetched items reactions', this.fetchedItemsReactionsCount); + } + private _logFetchedPullRequestsCount(): void { this._logCount('Fetched pull requests', this.fetchedPullRequestsCount); } diff --git a/src/interfaces/issue.ts b/src/interfaces/issue.ts index 2110e2fc..f4df8eee 100644 --- a/src/interfaces/issue.ts +++ b/src/interfaces/issue.ts @@ -2,6 +2,7 @@ import {IsoDateString} from '../types/iso-date-string'; import {Assignee} from './assignee'; import {ILabel} from './label'; import {IMilestone} from './milestone'; +import {IReaction} from './reaction'; import {components} from '@octokit/openapi-types'; export interface IIssue { title: string; @@ -14,6 +15,7 @@ export interface IIssue { locked: boolean; milestone?: IMilestone | null; assignees?: Assignee[] | null; + reactions?: IReaction[] | null; } export type OctokitIssue = components['schemas']['issue']; diff --git a/src/interfaces/reaction.ts b/src/interfaces/reaction.ts new file mode 100644 index 00000000..13af88fd --- /dev/null +++ b/src/interfaces/reaction.ts @@ -0,0 +1,4 @@ +export interface IReaction { + content: string; + created_at: string; +}