From 40fcb33c7dd1cfb00fe62013cb1c509be026a707 Mon Sep 17 00:00:00 2001 From: Aleksei Simatov Date: Fri, 14 Nov 2025 20:19:11 +0700 Subject: [PATCH 1/3] Feature: Added support for teams --- build/index.js | 74 ++++++++++--------- package-lock.json | 4 +- package.json | 2 +- src/converters/collectData.ts | 8 +- .../utils/calculations/checkUserInclusive.ts | 16 +++- .../utils/calculations/getApproveTime.ts | 5 +- .../utils/calculations/getResponses.ts | 11 ++- src/converters/utils/prepareActionsTime.ts | 9 ++- .../utils/prepareConductedReviews.ts | 2 +- src/converters/utils/prepareDiscussions.ts | 14 ++-- .../utils/preparePullRequestTimeline.ts | 10 ++- .../utils/prepareRequestedReviews.ts | 4 +- src/converters/utils/prepareResponseTime.ts | 6 +- src/converters/utils/prepareReviews.ts | 6 +- 14 files changed, 96 insertions(+), 75 deletions(-) diff --git a/build/index.js b/build/index.js index ea8fee7..eca62c4 100644 --- a/build/index.js +++ b/build/index.js @@ -420,7 +420,7 @@ const collectData = (data, teams) => { const reviews = data.events[index]?.filter((el) => el.event === constants_1.reviewedTimelineEvent); const reviewRequests = data.events[index]?.filter((el) => el.event === constants_1.reviewRequestedTimelineEvent); const statuses = data.events[index]?.filter((el) => [constants_1.readyForReviewTimelineEvent, constants_1.convertToDraftTimelineEvent].includes(el.event)); - (0, utils_1.prepareActionsTime)(pullRequest, data.events[index]?.filter((el) => el), collection); + (0, utils_1.prepareActionsTime)(pullRequest, data.events[index]?.filter((el) => el), collection, teams); const closedDate = pullRequest.closed_at ? (0, date_fns_1.parseISO)(pullRequest.closed_at) : null; @@ -431,10 +431,10 @@ const collectData = (data, teams) => { (0, utils_1.prepareRequestedReviews)(reviewRequests, collection, dateKey, teams); ["total", userKey, ...(teams[userKey] || [])].forEach((key) => { ["total", dateKey].forEach((innerKey) => { - if ((0, calculations_1.checkUserInclusive)(userKey)) { + if ((0, calculations_1.checkUserInclusive)(userKey, teams)) { (0, set_1.default)(collection, [key, innerKey], (0, utils_1.preparePullRequestInfo)(pullRequest, (0, get_1.default)(collection, [key, innerKey], {}))); } - (0, set_1.default)(collection, [key, innerKey], (0, utils_1.preparePullRequestTimeline)(pullRequest, reviews, reviewRequests?.[0], statuses, (0, get_1.default)(collection, [key, innerKey], {}))); + (0, set_1.default)(collection, [key, innerKey], (0, utils_1.preparePullRequestTimeline)(pullRequest, reviews, reviewRequests?.[0], statuses, (0, get_1.default)(collection, [key, innerKey], {}), teams)); }); }); (0, utils_1.prepareReviews)(reviews, collection, dateKey, userKey, (0, calculations_1.getPullRequestSize)(pullRequest?.additions, pullRequest?.deletions), teams); @@ -765,17 +765,19 @@ exports.calcWeekendMinutes = calcWeekendMinutes; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.checkUserInclusive = void 0; const utils_1 = __nccwpck_require__(41002); -const checkUserInclusive = (name) => { +const checkUserInclusive = (name, teams) => { if ((0, utils_1.getMultipleValuesInput)("EXCLUDE_USERS").length === 0 && (0, utils_1.getMultipleValuesInput)("INCLUDE_USERS").length === 0) { return true; } if ((0, utils_1.getMultipleValuesInput)("EXCLUDE_USERS").length > 0 && - (0, utils_1.getMultipleValuesInput)("EXCLUDE_USERS").includes(name)) { + ((0, utils_1.getMultipleValuesInput)("EXCLUDE_USERS").includes(name) || + teams[name]?.some((team) => (0, utils_1.getMultipleValuesInput)("EXCLUDE_USERS").includes(team)))) { return false; } return (0, utils_1.getMultipleValuesInput)("INCLUDE_USERS").length > 0 - ? (0, utils_1.getMultipleValuesInput)("INCLUDE_USERS").includes(name) + ? (0, utils_1.getMultipleValuesInput)("INCLUDE_USERS").includes(name) || + teams[name]?.some((team) => (0, utils_1.getMultipleValuesInput)("INCLUDE_USERS").includes(team)) : true; }; exports.checkUserInclusive = checkUserInclusive; @@ -824,10 +826,10 @@ exports.getApproveTime = void 0; const date_fns_1 = __nccwpck_require__(73314); const constants_1 = __nccwpck_require__(95354); const checkUserInclusive_1 = __nccwpck_require__(50477); -const getApproveTime = (reviews, requiredApprovals) => { +const getApproveTime = (reviews, requiredApprovals, teams) => { const statuses = Object.values(reviews?.reduce((acc, review) => { const user = review.user?.login || constants_1.invalidUserLogin; - if (!(0, checkUserInclusive_1.checkUserInclusive)(user)) { + if (!(0, checkUserInclusive_1.checkUserInclusive)(user, teams)) { return acc; } const statusesEntries = Object.keys(acc); @@ -899,11 +901,11 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.getResponses = void 0; const constants_1 = __nccwpck_require__(95354); const checkUserInclusive_1 = __nccwpck_require__(50477); -const getResponses = (events = []) => { +const getResponses = (events = [], teams) => { return events?.reduce((acc, event) => { if (event.event === constants_1.reviewRequestedTimelineEvent) { const user = event.requested_reviewer?.login || constants_1.invalidUserLogin; - if (!(0, checkUserInclusive_1.checkUserInclusive)(user)) { + if (!(0, checkUserInclusive_1.checkUserInclusive)(user, teams)) { return acc; } return { @@ -913,7 +915,7 @@ const getResponses = (events = []) => { } if (event.event === constants_1.reviewedTimelineEvent) { const user = event.user?.login || constants_1.invalidUserLogin; - if (!(0, checkUserInclusive_1.checkUserInclusive)(user)) { + if (!(0, checkUserInclusive_1.checkUserInclusive)(user, teams)) { return acc; } return { @@ -925,7 +927,7 @@ const getResponses = (events = []) => { } if (event.event === constants_1.reviewRequestRemoved) { const user = event.requested_reviewer?.login || constants_1.invalidUserLogin; - if (!(0, checkUserInclusive_1.checkUserInclusive)(user)) { + if (!(0, checkUserInclusive_1.checkUserInclusive)(user, teams)) { return acc; } return { @@ -1102,7 +1104,7 @@ const date_fns_1 = __nccwpck_require__(73314); const lodash_1 = __nccwpck_require__(90250); const constants_1 = __nccwpck_require__(95354); const calculations_1 = __nccwpck_require__(16576); -const prepareActionsTime = (pullRequest, events = [], collection) => { +const prepareActionsTime = (pullRequest, events = [], collection, teams) => { const openingHour = pullRequest?.created_at ? (0, date_fns_1.getHours)((0, date_fns_1.parseISO)(pullRequest?.created_at)) : -1; @@ -1116,7 +1118,7 @@ const prepareActionsTime = (pullRequest, events = [], collection) => { ? (0, date_fns_1.getHours)((0, date_fns_1.parseISO)(el?.submitted_at)) : -1; const user = el?.user?.login || constants_1.invalidUserLogin; - if (submitHour !== -1 && (0, calculations_1.checkUserInclusive)(user)) { + if (submitHour !== -1 && (0, calculations_1.checkUserInclusive)(user, teams)) { const keys = ["total", "total", "actionsTime", submitHour, el.state]; (0, lodash_1.set)(collection, keys, (0, lodash_1.get)(collection, keys, 0) + 1); const userKeys = [user, "total", "actionsTime", submitHour, el.state]; @@ -1124,13 +1126,13 @@ const prepareActionsTime = (pullRequest, events = [], collection) => { } }); const prAuthor = pullRequest?.user?.login || constants_1.invalidUserLogin; - if (openingHour !== -1 && (0, calculations_1.checkUserInclusive)(prAuthor)) { + if (openingHour !== -1 && (0, calculations_1.checkUserInclusive)(prAuthor, teams)) { const keys = ["total", "total", "actionsTime", openingHour, "opened"]; (0, lodash_1.set)(collection, keys, (0, lodash_1.get)(collection, keys, 0) + 1); const userKeys = [prAuthor, "total", "actionsTime", openingHour, "opened"]; (0, lodash_1.set)(collection, userKeys, (0, lodash_1.get)(collection, userKeys, 0) + 1); } - if (mergingHour !== -1 && (0, calculations_1.checkUserInclusive)(prAuthor)) { + if (mergingHour !== -1 && (0, calculations_1.checkUserInclusive)(prAuthor, teams)) { const keys = ["total", "total", "actionsTime", mergingHour, "merged"]; (0, lodash_1.set)(collection, keys, (0, lodash_1.get)(collection, keys, 0) + 1); const userKeys = [prAuthor, "total", "actionsTime", mergingHour, "merged"]; @@ -1158,7 +1160,7 @@ const prepareConductedReviews = (pullRequestLogin, pullRequestReviews = [], coll return { ...acc, [review.state]: 1, total: 1 }; }, {}) || {}); [pullRequestLogin, "total", ...(teams[pullRequestLogin] || [])].forEach((key) => { - if (!(0, calculations_1.checkUserInclusive)(key)) + if (!(0, calculations_1.checkUserInclusive)(key, teams)) return; const statusesReviewsStats = statuses.reduce((acc, status) => { return { @@ -1202,19 +1204,19 @@ const getDiscussionType_1 = __nccwpck_require__(49575); const calculations_1 = __nccwpck_require__(16576); const prepareDiscussions = (comments, collection, index, dateKey, pullRequestLogin, teams) => { const reviewComments = comments[index]?.filter((comment) => pullRequestLogin !== (comment.user?.login || constants_1.invalidUserLogin) && - (0, calculations_1.checkUserInclusive)(comment.user?.login || constants_1.invalidUserLogin)); + (0, calculations_1.checkUserInclusive)(comment.user?.login || constants_1.invalidUserLogin, teams)); const discussions = comments[index]?.filter((comment) => { const userLogin = comment.user?.login || constants_1.invalidUserLogin; return (!comment.in_reply_to_id && pullRequestLogin !== userLogin && - (0, calculations_1.checkUserInclusive)(userLogin)); + (0, calculations_1.checkUserInclusive)(userLogin, teams)); }); ["total", dateKey].forEach((key) => { discussions?.forEach((discussion) => { const userLogin = discussion.user?.login || constants_1.invalidUserLogin; (0, getDiscussionType_1.getDiscussionType)(discussion.body).forEach((type) => { [userLogin, ...(teams[userLogin] || []), "total"].forEach((userKey) => { - if ((0, calculations_1.checkUserInclusive)(userLogin)) { + if ((0, calculations_1.checkUserInclusive)(userLogin, teams)) { (0, set_1.default)(collection, [userKey, key, "discussionsTypes", type], { ...(0, get_1.default)(collection, [userKey, key, "discussionsTypes", type], {}), conducted: { @@ -1247,7 +1249,7 @@ const prepareDiscussions = (comments, collection, index, dateKey, pullRequestLog } }); [pullRequestLogin, ...(teams[pullRequestLogin] || []), "total"].forEach((userKey) => { - if ((0, calculations_1.checkUserInclusive)(userLogin)) { + if ((0, calculations_1.checkUserInclusive)(userLogin, teams)) { (0, set_1.default)(collection, [userKey, key, "discussionsTypes", type], { ...(0, get_1.default)(collection, [userKey, key, "discussionsTypes", type], {}), received: { @@ -1282,7 +1284,7 @@ const prepareDiscussions = (comments, collection, index, dateKey, pullRequestLog }); }); comments[index] - ?.filter((comment) => (0, calculations_1.checkUserInclusive)(comment.user?.login || constants_1.invalidUserLogin)) + ?.filter((comment) => (0, calculations_1.checkUserInclusive)(comment.user?.login || constants_1.invalidUserLogin, teams)) .forEach((comment) => { const userLogin = comment.user?.login || constants_1.invalidUserLogin; if (pullRequestLogin !== userLogin) { @@ -1291,7 +1293,7 @@ const prepareDiscussions = (comments, collection, index, dateKey, pullRequestLog }); } }); - if (pullRequestLogin && (0, calculations_1.checkUserInclusive)(pullRequestLogin)) { + if (pullRequestLogin && (0, calculations_1.checkUserInclusive)(pullRequestLogin, teams)) { [pullRequestLogin, "total", ...(teams[pullRequestLogin] || [])].forEach((userKey) => { (0, set_1.default)(collection, [userKey, key, "reviewComments"], (reviewComments?.length || 0) + (0, get_1.default)(collection, [userKey, key, "reviewComments"], 0)); @@ -1314,7 +1316,7 @@ const prepareDiscussions = (comments, collection, index, dateKey, pullRequestLog const agreedDiscussions = discussions?.filter((discussion) => discussion.reactions?.["+1"]); const disagreedDiscussions = discussions?.filter((discussion) => discussion.reactions?.["-1"]); [pullRequestLogin, "total", ...(teams[pullRequestLogin] || [])].forEach((userKey) => { - if ((0, calculations_1.checkUserInclusive)(pullRequestLogin)) { + if ((0, calculations_1.checkUserInclusive)(pullRequestLogin, teams)) { (0, set_1.default)(collection, [userKey, key, "discussions"], { ...(0, get_1.default)(collection, [userKey, key, "discussions"], {}), received: { @@ -1468,13 +1470,13 @@ const constants_1 = __nccwpck_require__(95354); const calculations_1 = __nccwpck_require__(16576); const calcDifferenceInMinutes_1 = __nccwpck_require__(72317); const calcPRsize_1 = __nccwpck_require__(8722); -const preparePullRequestTimeline = (pullRequestInfo, pullRequestReviews = [], reviewRequest, statuses = [], collection) => { - if (!(0, calculations_1.checkUserInclusive)(pullRequestInfo?.user?.login || constants_1.invalidUserLogin)) { +const preparePullRequestTimeline = (pullRequestInfo, pullRequestReviews = [], reviewRequest, statuses = [], collection, teams) => { + if (!(0, calculations_1.checkUserInclusive)(pullRequestInfo?.user?.login || constants_1.invalidUserLogin, teams)) { return collection; } const firstReview = pullRequestReviews?.find((review) => review.user?.login !== pullRequestInfo?.user?.login && - (0, calculations_1.checkUserInclusive)(review.user?.login || constants_1.invalidUserLogin)); - const approveTime = (0, calculations_1.getApproveTime)(pullRequestReviews, parseInt((0, utils_1.getValueAsIs)("REQUIRED_APPROVALS"))); + (0, calculations_1.checkUserInclusive)(review.user?.login || constants_1.invalidUserLogin, teams)); + const approveTime = (0, calculations_1.getApproveTime)(pullRequestReviews, parseInt((0, utils_1.getValueAsIs)("REQUIRED_APPROVALS")), teams); const timeToReviewRequest = (0, calcDifferenceInMinutes_1.calcDifferenceInMinutes)(pullRequestInfo?.created_at, reviewRequest?.created_at, { endOfWorkingTime: (0, utils_1.getValueAsIs)("CORE_HOURS_END"), startOfWorkingTime: (0, utils_1.getValueAsIs)("CORE_HOURS_START"), @@ -1586,7 +1588,7 @@ const prepareRequestedReviews = (requests = [], collection, dateKey, teams) => { const user = request.requested_reviewer ? request.requested_reviewer?.login || constants_1.invalidUserLogin : request.requested_team?.name || "Invalid Team"; - if (!(0, calculations_1.checkUserInclusive)(user)) + if (!(0, calculations_1.checkUserInclusive)(user, teams)) return acc; return { ...acc, [user]: 1 }; }, {}); @@ -1598,7 +1600,7 @@ const prepareRequestedReviews = (requests = [], collection, dateKey, teams) => { }); [dateKey, "total"].forEach((date) => { Object.entries({ ...requestedReviewers }).forEach(([user, value]) => { - if ((0, calculations_1.checkUserInclusive)(user)) { + if ((0, calculations_1.checkUserInclusive)(user, teams)) { (0, set_1.default)(collection, [user, date, "reviewRequestsConducted"], (0, get_1.default)(collection, [user, date, "reviewRequestsConducted"], 0) + value); } @@ -1628,7 +1630,7 @@ const constants_1 = __nccwpck_require__(95354); const prepareResponseTime = (events = [], pullRequest, collection, dateKey, teams) => { if (!events) return; - const responses = (0, calculations_1.getResponses)(events); + const responses = (0, calculations_1.getResponses)(events, teams); const user = pullRequest?.user.login || constants_1.invalidUserLogin; ["total", user, ...(teams[user] || [])].forEach((userKey) => { [dateKey, "total"].forEach((key) => { @@ -1642,7 +1644,7 @@ const prepareResponseTime = (events = [], pullRequest, collection, dateKey, team startOfWorkingTime: (0, utils_1.getValueAsIs)("CORE_HOURS_START"), }, (0, utils_1.getMultipleValuesInput)("HOLIDAYS"))) .filter((el) => typeof el === "number"); - if ((0, calculations_1.checkUserInclusive)(userKey)) { + if ((0, calculations_1.checkUserInclusive)(userKey, teams)) { (0, set_1.default)(collection, [userKey, key, "timeWaitingForRepeatedReview"], [ ...(0, get_1.default)(collection, [userKey, key, "timeWaitingForRepeatedReview"], []), ...awaitingResponse, @@ -1667,7 +1669,7 @@ const prepareResponseTime = (events = [], pullRequest, collection, dateKey, team startOfWorkingTime: (0, utils_1.getValueAsIs)("CORE_HOURS_START"), }, (0, utils_1.getMultipleValuesInput)("HOLIDAYS"))); ["total", user, ...(teams[user] || [])].forEach((userKey) => { - if ((0, calculations_1.checkUserInclusive)(userKey)) { + if ((0, calculations_1.checkUserInclusive)(userKey, teams)) { (0, set_1.default)(collection, [userKey, key], { ...(0, get_1.default)(collection, [userKey, key], {}), timeFromInitialRequestToResponse: typeof timeFromInitialRequestToResponse === "number" @@ -1716,7 +1718,7 @@ const prepareReviews = (reviews = [], collection, dateKey, pullRequestLogin, pul let teamNames = []; const users = Object.keys(reviews?.reduce((acc, review) => { const userLogin = review.user?.login || constants_1.invalidUserLogin; - if (userLogin !== pullRequestLogin && (0, calculations_1.checkUserInclusive)(userLogin)) { + if (userLogin !== pullRequestLogin && (0, calculations_1.checkUserInclusive)(userLogin, teams)) { const teamsNames = (teams[userLogin] || []).reduce((acc, team) => ({ ...acc, [team]: 1 }), {}); teamNames = Object.keys(teamsNames); return { ...acc, [userLogin]: 1, ...teamsNames, total: 1 }; @@ -1727,11 +1729,11 @@ const prepareReviews = (reviews = [], collection, dateKey, pullRequestLogin, pul const userReviews = Array.isArray(reviews) && user !== "total" && !teamNames.includes(user) ? reviews?.filter((review) => { const userLogin = review.user?.login || constants_1.invalidUserLogin; - return userLogin === user && (0, calculations_1.checkUserInclusive)(userLogin); + return userLogin === user && (0, calculations_1.checkUserInclusive)(userLogin, teams); }) : reviews?.filter((review) => { const userLogin = review.user?.login || constants_1.invalidUserLogin; - return (0, calculations_1.checkUserInclusive)(userLogin); + return (0, calculations_1.checkUserInclusive)(userLogin, teams); }); [dateKey, "total"].forEach((key) => { (0, set_1.default)(collection, [user, key], (0, prepareConductedReviews_1.prepareConductedReviews)(pullRequestLogin, userReviews, (0, get_1.default)(collection, [user, key], {}), pullRequestSize, teams)); diff --git a/package-lock.json b/package-lock.json index 9b658df..364e986 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pull-request-analytics-action", - "version": "3.1.1", + "version": "4.8.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pull-request-analytics-action", - "version": "3.1.1", + "version": "4.8.1", "license": "MIT", "dependencies": { "@actions/core": "^1.10.1", diff --git a/package.json b/package.json index 408bf60..8b33c50 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pull-request-analytics-action", - "version": "4.8.0", + "version": "4.8.1", "description": "Generates detailed PR analytics reports within GitHub, focusing on review efficiency and team performance.", "main": "build/index.js", "scripts": { diff --git a/src/converters/collectData.ts b/src/converters/collectData.ts index d04fcaa..ce6e24e 100644 --- a/src/converters/collectData.ts +++ b/src/converters/collectData.ts @@ -51,7 +51,8 @@ export const collectData = ( prepareActionsTime( pullRequest, data.events[index]?.filter((el) => el), - collection + collection, + teams ); const closedDate = pullRequest.closed_at @@ -68,7 +69,7 @@ export const collectData = ( ["total", userKey, ...(teams[userKey] || [])].forEach((key) => { ["total", dateKey].forEach((innerKey) => { - if (checkUserInclusive(userKey)) { + if (checkUserInclusive(userKey, teams)) { set( collection, [key, innerKey], @@ -87,7 +88,8 @@ export const collectData = ( reviews, reviewRequests?.[0], statuses, - get(collection, [key, innerKey], {}) + get(collection, [key, innerKey], {}), + teams ) ); }); diff --git a/src/converters/utils/calculations/checkUserInclusive.ts b/src/converters/utils/calculations/checkUserInclusive.ts index c63e198..419d311 100644 --- a/src/converters/utils/calculations/checkUserInclusive.ts +++ b/src/converters/utils/calculations/checkUserInclusive.ts @@ -1,5 +1,9 @@ import { getMultipleValuesInput } from "../../../common/utils"; -export const checkUserInclusive = (name: string) => { + +export const checkUserInclusive = ( + name: string, + teams: Record +) => { if ( getMultipleValuesInput("EXCLUDE_USERS").length === 0 && getMultipleValuesInput("INCLUDE_USERS").length === 0 @@ -8,11 +12,17 @@ export const checkUserInclusive = (name: string) => { } if ( getMultipleValuesInput("EXCLUDE_USERS").length > 0 && - getMultipleValuesInput("EXCLUDE_USERS").includes(name) + (getMultipleValuesInput("EXCLUDE_USERS").includes(name) || + teams[name]?.some((team) => + getMultipleValuesInput("EXCLUDE_USERS").includes(team) + )) ) { return false; } return getMultipleValuesInput("INCLUDE_USERS").length > 0 - ? getMultipleValuesInput("INCLUDE_USERS").includes(name) + ? getMultipleValuesInput("INCLUDE_USERS").includes(name) || + teams[name]?.some((team) => + getMultipleValuesInput("INCLUDE_USERS").includes(team) + ) : true; }; diff --git a/src/converters/utils/calculations/getApproveTime.ts b/src/converters/utils/calculations/getApproveTime.ts index 2b93e0a..de29774 100644 --- a/src/converters/utils/calculations/getApproveTime.ts +++ b/src/converters/utils/calculations/getApproveTime.ts @@ -5,7 +5,8 @@ import { checkUserInclusive } from "./checkUserInclusive"; export const getApproveTime = ( reviews: Awaited>["events"][number], - requiredApprovals: number + requiredApprovals: number, + teams: Record ) => { const statuses = Object.values( reviews?.reduce( @@ -14,7 +15,7 @@ export const getApproveTime = ( review: any ) => { const user = review.user?.login || invalidUserLogin; - if (!checkUserInclusive(user)) { + if (!checkUserInclusive(user, teams)) { return acc; } const statusesEntries = Object.keys(acc) as string[]; diff --git a/src/converters/utils/calculations/getResponses.ts b/src/converters/utils/calculations/getResponses.ts index 7fdf239..279b9e2 100644 --- a/src/converters/utils/calculations/getResponses.ts +++ b/src/converters/utils/calculations/getResponses.ts @@ -6,11 +6,14 @@ import { } from "../../constants"; import { checkUserInclusive } from "./checkUserInclusive"; -export const getResponses = (events: any[] | undefined | null = []) => { +export const getResponses = ( + events: any[] | undefined | null = [], + teams: Record +) => { return events?.reduce((acc, event) => { if (event.event === reviewRequestedTimelineEvent) { const user = event.requested_reviewer?.login || invalidUserLogin; - if (!checkUserInclusive(user)) { + if (!checkUserInclusive(user, teams)) { return acc; } return { @@ -20,7 +23,7 @@ export const getResponses = (events: any[] | undefined | null = []) => { } if (event.event === reviewedTimelineEvent) { const user = event.user?.login || invalidUserLogin; - if (!checkUserInclusive(user)) { + if (!checkUserInclusive(user, teams)) { return acc; } return { @@ -34,7 +37,7 @@ export const getResponses = (events: any[] | undefined | null = []) => { } if (event.event === reviewRequestRemoved) { const user = event.requested_reviewer?.login || invalidUserLogin; - if (!checkUserInclusive(user)) { + if (!checkUserInclusive(user, teams)) { return acc; } return { diff --git a/src/converters/utils/prepareActionsTime.ts b/src/converters/utils/prepareActionsTime.ts index f8c9ce1..8c5d05f 100644 --- a/src/converters/utils/prepareActionsTime.ts +++ b/src/converters/utils/prepareActionsTime.ts @@ -10,7 +10,8 @@ export const prepareActionsTime = ( ReturnType >["pullRequestInfo"][number], events: any[] | undefined = [], - collection: Record> + collection: Record>, + teams: Record ) => { const openingHour = pullRequest?.created_at ? getHours(parseISO(pullRequest?.created_at)) @@ -26,7 +27,7 @@ export const prepareActionsTime = ( ? getHours(parseISO(el?.submitted_at)) : -1; const user = el?.user?.login || invalidUserLogin; - if (submitHour !== -1 && checkUserInclusive(user)) { + if (submitHour !== -1 && checkUserInclusive(user, teams)) { const keys = ["total", "total", "actionsTime", submitHour, el.state]; set(collection, keys, (get(collection, keys, 0) as number) + 1); const userKeys = [user, "total", "actionsTime", submitHour, el.state]; @@ -34,13 +35,13 @@ export const prepareActionsTime = ( } }); const prAuthor = pullRequest?.user?.login || invalidUserLogin; - if (openingHour !== -1 && checkUserInclusive(prAuthor)) { + if (openingHour !== -1 && checkUserInclusive(prAuthor, teams)) { const keys = ["total", "total", "actionsTime", openingHour, "opened"]; set(collection, keys, get(collection, keys, 0) + 1); const userKeys = [prAuthor, "total", "actionsTime", openingHour, "opened"]; set(collection, userKeys, get(collection, userKeys, 0) + 1); } - if (mergingHour !== -1 && checkUserInclusive(prAuthor)) { + if (mergingHour !== -1 && checkUserInclusive(prAuthor, teams)) { const keys = ["total", "total", "actionsTime", mergingHour, "merged"]; set(collection, keys, get(collection, keys, 0) + 1); const userKeys = [prAuthor, "total", "actionsTime", mergingHour, "merged"]; diff --git a/src/converters/utils/prepareConductedReviews.ts b/src/converters/utils/prepareConductedReviews.ts index e1b510a..c1c2402 100644 --- a/src/converters/utils/prepareConductedReviews.ts +++ b/src/converters/utils/prepareConductedReviews.ts @@ -20,7 +20,7 @@ export const prepareConductedReviews = ( [pullRequestLogin, "total", ...(teams[pullRequestLogin] || [])].forEach( (key) => { - if(!checkUserInclusive(key)) return; + if(!checkUserInclusive(key, teams)) return; const statusesReviewsStats = statuses.reduce((acc, status) => { return { ...acc, diff --git a/src/converters/utils/prepareDiscussions.ts b/src/converters/utils/prepareDiscussions.ts index c884e2a..3a598f5 100644 --- a/src/converters/utils/prepareDiscussions.ts +++ b/src/converters/utils/prepareDiscussions.ts @@ -18,7 +18,7 @@ export const prepareDiscussions = ( const reviewComments = comments[index]?.filter( (comment) => pullRequestLogin !== (comment.user?.login || invalidUserLogin) && - checkUserInclusive(comment.user?.login || invalidUserLogin) + checkUserInclusive(comment.user?.login || invalidUserLogin, teams) ); const discussions = comments[index]?.filter((comment) => { @@ -26,7 +26,7 @@ export const prepareDiscussions = ( return ( !comment.in_reply_to_id && pullRequestLogin !== userLogin && - checkUserInclusive(userLogin) + checkUserInclusive(userLogin, teams) ); }); @@ -35,7 +35,7 @@ export const prepareDiscussions = ( const userLogin = discussion.user?.login || invalidUserLogin; getDiscussionType(discussion.body).forEach((type) => { [userLogin, ...(teams[userLogin] || []), "total"].forEach((userKey) => { - if (checkUserInclusive(userLogin)) { + if (checkUserInclusive(userLogin, teams)) { set(collection, [userKey, key, "discussionsTypes", type], { ...get(collection, [userKey, key, "discussionsTypes", type], {}), conducted: { @@ -85,7 +85,7 @@ export const prepareDiscussions = ( [pullRequestLogin, ...(teams[pullRequestLogin] || []), "total"].forEach( (userKey) => { - if (checkUserInclusive(userLogin)) { + if (checkUserInclusive(userLogin, teams)) { set(collection, [userKey, key, "discussionsTypes", type], { ...get( collection, @@ -142,7 +142,7 @@ export const prepareDiscussions = ( comments[index] ?.filter((comment) => - checkUserInclusive(comment.user?.login || invalidUserLogin) + checkUserInclusive(comment.user?.login || invalidUserLogin, teams) ) .forEach((comment) => { const userLogin = comment.user?.login || invalidUserLogin; @@ -159,7 +159,7 @@ export const prepareDiscussions = ( } }); - if (pullRequestLogin && checkUserInclusive(pullRequestLogin)) { + if (pullRequestLogin && checkUserInclusive(pullRequestLogin, teams)) { [pullRequestLogin, "total", ...(teams[pullRequestLogin] || [])].forEach( (userKey) => { set( @@ -211,7 +211,7 @@ export const prepareDiscussions = ( [pullRequestLogin, "total", ...(teams[pullRequestLogin] || [])].forEach( (userKey) => { - if (checkUserInclusive(pullRequestLogin)) { + if (checkUserInclusive(pullRequestLogin, teams)) { set(collection, [userKey, key, "discussions"], { ...get(collection, [userKey, key, "discussions"], {}), received: { diff --git a/src/converters/utils/preparePullRequestTimeline.ts b/src/converters/utils/preparePullRequestTimeline.ts index 5f1502e..74902b8 100644 --- a/src/converters/utils/preparePullRequestTimeline.ts +++ b/src/converters/utils/preparePullRequestTimeline.ts @@ -18,19 +18,21 @@ export const preparePullRequestTimeline = ( pullRequestReviews: any[] = [], reviewRequest: any | undefined, statuses: any[] | undefined = [], - collection: Collection + collection: Collection, + teams: Record ) => { - if (!checkUserInclusive(pullRequestInfo?.user?.login || invalidUserLogin)) { + if (!checkUserInclusive(pullRequestInfo?.user?.login || invalidUserLogin, teams)) { return collection; } const firstReview = pullRequestReviews?.find( (review) => review.user?.login !== pullRequestInfo?.user?.login && - checkUserInclusive(review.user?.login || invalidUserLogin) + checkUserInclusive(review.user?.login || invalidUserLogin, teams) ); const approveTime = getApproveTime( pullRequestReviews, - parseInt(getValueAsIs("REQUIRED_APPROVALS")) + parseInt(getValueAsIs("REQUIRED_APPROVALS")), + teams ); const timeToReviewRequest = calcDifferenceInMinutes( diff --git a/src/converters/utils/prepareRequestedReviews.ts b/src/converters/utils/prepareRequestedReviews.ts index 29491f1..69bd5a4 100644 --- a/src/converters/utils/prepareRequestedReviews.ts +++ b/src/converters/utils/prepareRequestedReviews.ts @@ -15,7 +15,7 @@ export const prepareRequestedReviews = ( const user = request.requested_reviewer ? request.requested_reviewer?.login || invalidUserLogin : request.requested_team?.name || "Invalid Team"; - if(!checkUserInclusive(user)) return acc; + if (!checkUserInclusive(user, teams)) return acc; return { ...acc, [user]: 1 }; }, {}); @@ -29,7 +29,7 @@ export const prepareRequestedReviews = ( [dateKey, "total"].forEach((date) => { Object.entries({ ...requestedReviewers }).forEach(([user, value]) => { - if (checkUserInclusive(user)) { + if (checkUserInclusive(user, teams)) { set( collection, [user, date, "reviewRequestsConducted"], diff --git a/src/converters/utils/prepareResponseTime.ts b/src/converters/utils/prepareResponseTime.ts index 3e05df0..b0ae7b4 100644 --- a/src/converters/utils/prepareResponseTime.ts +++ b/src/converters/utils/prepareResponseTime.ts @@ -21,7 +21,7 @@ export const prepareResponseTime = ( teams: Record ) => { if (!events) return; - const responses = getResponses(events); + const responses = getResponses(events, teams); const user = pullRequest?.user.login || invalidUserLogin; ["total", user, ...(teams[user] || [])].forEach((userKey) => { [dateKey, "total"].forEach((key) => { @@ -44,7 +44,7 @@ export const prepareResponseTime = ( ) ) .filter((el) => typeof el === "number") as number[]; - if (checkUserInclusive(userKey)) { + if (checkUserInclusive(userKey, teams)) { set( collection, [userKey, key, "timeWaitingForRepeatedReview"], @@ -99,7 +99,7 @@ export const prepareResponseTime = ( ); ["total", user, ...(teams[user] || [])].forEach((userKey) => { - if (checkUserInclusive(userKey)) { + if (checkUserInclusive(userKey, teams)) { set(collection, [userKey, key], { ...get(collection, [userKey, key], {}), timeFromInitialRequestToResponse: diff --git a/src/converters/utils/prepareReviews.ts b/src/converters/utils/prepareReviews.ts index 927e107..a565c05 100644 --- a/src/converters/utils/prepareReviews.ts +++ b/src/converters/utils/prepareReviews.ts @@ -19,7 +19,7 @@ export const prepareReviews = ( const users = Object.keys( reviews?.reduce((acc, review) => { const userLogin = review.user?.login || invalidUserLogin; - if (userLogin !== pullRequestLogin && checkUserInclusive(userLogin)) { + if (userLogin !== pullRequestLogin && checkUserInclusive(userLogin, teams)) { const teamsNames = (teams[userLogin] || []).reduce( (acc, team) => ({ ...acc, [team]: 1 }), {} @@ -36,11 +36,11 @@ export const prepareReviews = ( Array.isArray(reviews) && user !== "total" && !teamNames.includes(user) ? reviews?.filter((review) => { const userLogin = review.user?.login || invalidUserLogin; - return userLogin === user && checkUserInclusive(userLogin); + return userLogin === user && checkUserInclusive(userLogin, teams); }) : reviews?.filter((review) => { const userLogin = review.user?.login || invalidUserLogin; - return checkUserInclusive(userLogin); + return checkUserInclusive(userLogin, teams); }); [dateKey, "total"].forEach((key) => { set( From 4d34f3047ce5aec81643cec22835b94107508dc7 Mon Sep 17 00:00:00 2001 From: Aleksei Simatov Date: Mon, 24 Nov 2025 15:30:22 +0700 Subject: [PATCH 2/3] Feature: improve response table --- build/index.js | 2 +- src/converters/utils/prepareResponseTime.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/index.js b/build/index.js index eca62c4..2a57f97 100644 --- a/build/index.js +++ b/build/index.js @@ -1669,7 +1669,7 @@ const prepareResponseTime = (events = [], pullRequest, collection, dateKey, team startOfWorkingTime: (0, utils_1.getValueAsIs)("CORE_HOURS_START"), }, (0, utils_1.getMultipleValuesInput)("HOLIDAYS"))); ["total", user, ...(teams[user] || [])].forEach((userKey) => { - if ((0, calculations_1.checkUserInclusive)(userKey, teams)) { + if ((0, calculations_1.checkUserInclusive)(user, teams)) { (0, set_1.default)(collection, [userKey, key], { ...(0, get_1.default)(collection, [userKey, key], {}), timeFromInitialRequestToResponse: typeof timeFromInitialRequestToResponse === "number" diff --git a/src/converters/utils/prepareResponseTime.ts b/src/converters/utils/prepareResponseTime.ts index b0ae7b4..4be9a7d 100644 --- a/src/converters/utils/prepareResponseTime.ts +++ b/src/converters/utils/prepareResponseTime.ts @@ -99,7 +99,7 @@ export const prepareResponseTime = ( ); ["total", user, ...(teams[user] || [])].forEach((userKey) => { - if (checkUserInclusive(userKey, teams)) { + if (checkUserInclusive(user, teams)) { set(collection, [userKey, key], { ...get(collection, [userKey, key], {}), timeFromInitialRequestToResponse: From 40834b796fe0d5841cd4654ec00b5045d74a3f9f Mon Sep 17 00:00:00 2001 From: Aleksei Simatov Date: Mon, 24 Nov 2025 19:39:10 +0700 Subject: [PATCH 3/3] Feature: Update docs --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 839e821..eb3c1a6 100644 --- a/README.md +++ b/README.md @@ -276,12 +276,12 @@ Below is a table outlining the various configuration parameters available for ** | `USE_CHARTS` | Primarily uses charts and diagrams instead of tables to display data. Set the value to `true` to use charts instead of tables | `false` | | `SHOW_CORRELATION_GRAPHS` | Displays graphs showing the dependency of time to review, approval, and merge on pull request size. Set to `true` if this graph is needed. | `false` | | `SHOW_ACTIVITY_TIME_GRAPHS` | Displays graphs of user activity throughout the day for opening, merging, and reviewing PRs. Set to `true` if these graphs are required. | `false` | -| `HIDE_USERS` | Hides selected users from reports, while still including their data in the analytics. Use `total` to hide total stats. Users should be separated by commas. | - | -| `SHOW_USERS` | Displays only specified users in reports, but includes all users in the background analytics. Use `total` to show total stats. Users should be separated by commas. | - | +| `HIDE_USERS` | Hides selected users or teams from reports, while still including their data in the analytics. Use `total` to hide total stats. Users should be separated by commas. | - | +| `SHOW_USERS` | Displays only specified users or teams in reports, but includes all users in the background analytics. Use `total` to show total stats. Users should be separated by commas. | - | | `EXCLUDE_LABELS` | PRs with mentioned labels will be excluded from the report . Values should be separated by commas. Example: `bugfix, enhancement` | - | | `INCLUDE_LABELS` | Only PRs with mentioned labels will be included in the report. Values should be separated by commas. Example: `bugfix, enhancement` | - | -| `INCLUDE_USERS` | Only data for the specified users will be included in the report. Multiple values should be separated by commas. Example: `dev1, dev2` | - | -| `EXCLUDE_USERS` | Data for the specified users will be excluded from the report. Multiple values should be separated by commas. Example: `dev1, dev2` | - | +| `INCLUDE_USERS` | Only data for the specified users or teams will be included in the report. Multiple values should be separated by commas. Example: `dev1, dev2, team1` | - | +| `EXCLUDE_USERS` | Data for the specified users or teams will be excluded from the report. Multiple values should be separated by commas. Example: `dev1, dev2, team1` | - | | `EXECUTION_OUTCOME` | This parameter allows you to specify the format in which you wish to receive the report. Options include creating a new issue, updating an existing one, obtaining markdown, or JSON. Markdown and JSON will be available in outputs. Can take mulitple values separated by commas: `new-issue`, `markdown`, `collection`, `existing-issue`. This parameter is **required** Example: `existing-issue` | `new-issue` | | `ISSUE_NUMBER` | Issue number to update. Add `existing-issue` to `EXECUTION_OUTCOME` for updating existing issue. The specified issue must already exist at the time the action is executed. This parameter is mandatory if the `EXECUTION_OUTCOME` input includes `existing-issue` value | - | | `ALLOW_ANALYTICS` | Allows sending non-sensitive inputs to mixpanel for better understanding user's needs. Set the value to `false` to disable sending action parameter data | `true` |