Skip to content

Conversation

@AlexSim93
Copy link
Owner

@AlexSim93 AlexSim93 commented Jul 13, 2025

Pull Request

Description

Added new parameter REQUIRED_APPROVALS. It allows to configure amount of approvals required for PRs.

Related Issue(s)

Type of Change

  • Bug fix
  • New feature
  • Documentation update
  • Other (please specify)

How Has This Been Tested?

Tested it in my project in PRs with 2 or more approvals.

Checklist:

  • I have read the CONTRIBUTING document.
  • My code follows the code style of this project.
  • I have added tests to cover my changes.
  • My changes generate no new warnings.
  • I have updated the documentation accordingly.

Summary by CodeRabbit

  • New Features

    • Enhanced analytics tracking by including counts for included and excluded users, as well as the raw value for required approvals in action run events.
    • Added support for including the "REQUIRED_APPROVALS" parameter in generated report settings.
  • Bug Fixes

    • Improved approval time calculation to accurately reflect the required number of approvals and select the correct approval timestamp.
  • Tests

    • Expanded test coverage for approval time calculation to verify behavior with multiple required approvals.

@coderabbitai
Copy link

coderabbitai bot commented Jul 13, 2025

Walkthrough

The changes update analytics event payloads to include counts and raw values for user inclusion/exclusion and required approvals. The approval calculation logic now dynamically uses the required approvals parameter, determining approval status and timestamp based on this value. Configuration reporting also now includes the required approvals parameter.

Changes

Files/Paths Change Summary
src/analytics/sendActionRun.ts Added counts for "INCLUDE_USERS", "EXCLUDE_USERS", and raw "REQUIRED_APPROVALS" to analytics event payload.
src/converters/utils/calculations/getApproveTime.ts, src/converters/utils/calculations/getApproveTime.spec.ts, src/converters/utils/preparePullRequestTimeline.ts Modified approval logic to use dynamic required approvals count; adjusted timestamp selection to Nth approval; updated function signatures and calls accordingly.
src/view/utils/createConfigParamsCode.ts Added "REQUIRED_APPROVALS" to reported configuration parameters.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant getApproveTime
    participant getValueAsIs

    Caller->>getApproveTime: Call with PR reviews and requiredApprovals
    getApproveTime->>getApproveTime: Count approvals, compare to requiredApprovals
    getApproveTime-->>Caller: Return approval status and timestamp (Nth approval)
Loading

Assessment against linked issues

Objective Addressed Explanation
Consider amount of required approvals for a PR being marked as approved (#66)

Possibly related PRs

Poem

In the warren of code, a hop and a leap,
Now approvals are counted, not just a peep!
Analytics track who’s in and who’s out,
Required approvals? Now there’s no doubt.
With each PR merged, the carrots abound—
Hooray for the changes, let’s thump the ground! 🥕

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary or @coderabbitai review to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🔭 Outside diff range comments (1)
src/converters/utils/calculations/getApproveTime.ts (1)

22-27: Add error handling for invalid REQUIRED_APPROVALS values.

The current implementation doesn't handle cases where REQUIRED_APPROVALS is undefined, null, or contains invalid data. This could lead to NaN values breaking the approval logic.

-        const isApproved =
-          statusesEntries.filter((user) => acc[user].state === "approved")
-            .length >= parseInt(getValueAsIs("REQUIRED_APPROVALS")) &&
+        const requiredApprovals = Number.parseInt(getValueAsIs("REQUIRED_APPROVALS") || "1", 10);
+        const isApproved =
+          statusesEntries.filter((user) => acc[user].state === "approved")
+            .length >= requiredApprovals &&
📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a6bf785 and a24e2d8.

⛔ Files ignored due to path filters (4)
  • README.md is excluded by none and included by none
  • action.yml is excluded by none and included by none
  • build/index.js is excluded by !build/** and included by none
  • package.json is excluded by none and included by none
📒 Files selected for processing (3)
  • src/analytics/sendActionRun.ts (1 hunks)
  • src/converters/utils/calculations/getApproveTime.ts (3 hunks)
  • src/view/utils/createConfigParamsCode.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/analytics/sendActionRun.ts (1)
src/common/utils/index.ts (2)
  • getMultipleValuesInput (4-4)
  • getValueAsIs (2-2)
src/converters/utils/calculations/getApproveTime.ts (2)
src/converters/utils/calculations/checkUserInclusive.ts (1)
  • checkUserInclusive (2-18)
src/common/utils/index.ts (1)
  • getValueAsIs (2-2)
🪛 Biome (1.9.4)
src/converters/utils/calculations/getApproveTime.ts

[error] 23-23: Use Number.parseInt instead of the equivalent global.

ES2015 moved some globals into the Number namespace for consistency.
Safe fix: Use Number.parseInt instead.

(lint/style/useNumberNamespace)


[error] 48-48: Use Number.parseInt instead of the equivalent global.

ES2015 moved some globals into the Number namespace for consistency.
Safe fix: Use Number.parseInt instead.

(lint/style/useNumberNamespace)


[error] 54-54: Use Number.parseInt instead of the equivalent global.

ES2015 moved some globals into the Number namespace for consistency.
Safe fix: Use Number.parseInt instead.

(lint/style/useNumberNamespace)

🔇 Additional comments (2)
src/view/utils/createConfigParamsCode.ts (1)

22-22: LGTM! Clean integration of the new parameter.

The addition of "REQUIRED_APPROVALS" to the configuration parameters list is consistent with the existing pattern and correctly integrates the new feature into the report settings output.

src/analytics/sendActionRun.ts (1)

32-36: LGTM! Consistent analytics tracking implementation.

The new analytics properties follow the established patterns:

  • INCLUDE_USERS and EXCLUDE_USERS correctly track array lengths
  • REQUIRED_APPROVALS appropriately captures the raw configuration value

This provides good visibility into how the new feature is being used.

Comment on lines 46 to 49
const isApproved =
statuses.some((status) => status.state === "approved") &&
statuses.filter((status) => status.state === "approved").length >=
parseInt(getValueAsIs("REQUIRED_APPROVALS")) &&
!statuses.some((status) => status.state === "changes_requested");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Fix parseInt usage and add error handling.

Static analysis correctly identifies that Number.parseInt should be used instead of global parseInt. Also add proper error handling for invalid values.

   const isApproved =
     statuses.filter((status) => status.state === "approved").length >=
-      parseInt(getValueAsIs("REQUIRED_APPROVALS")) &&
+      Number.parseInt(getValueAsIs("REQUIRED_APPROVALS") || "1", 10) &&
     !statuses.some((status) => status.state === "changes_requested");
🧰 Tools
🪛 Biome (1.9.4)

[error] 48-48: Use Number.parseInt instead of the equivalent global.

ES2015 moved some globals into the Number namespace for consistency.
Safe fix: Use Number.parseInt instead.

(lint/style/useNumberNamespace)

🤖 Prompt for AI Agents
In src/converters/utils/calculations/getApproveTime.ts around lines 46 to 49,
replace the global parseInt with Number.parseInt for better clarity and
consistency. Additionally, add error handling to check if the parsed value is a
valid number before using it in the comparison. If the value is invalid, handle
the error appropriately, such as by setting a default value or throwing an
error.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🔭 Outside diff range comments (1)
src/converters/utils/calculations/getApproveTime.spec.ts (1)

135-175: LGTM! Consider adding tests for different required approval counts.

The test updates correctly match the new function signature. However, since the PR introduces configurable approval requirements, consider adding test cases that verify the behavior with different requiredApprovals values (e.g., 2, 3).

Consider adding tests like:

+  it("Check PR with 2 approvals required - should return null with only 1 approval", () => {
+    expect(getApproveTime(approvedReview, 2)).toBe(null);
+  });
+  it("Check PR with 2 approvals required - should return second approval time", () => {
+    expect(getApproveTime(approvedTwiceReview, 2)).toBe("2024-01-11T09:00:00Z");
+  });
♻️ Duplicate comments (1)
src/converters/utils/calculations/getApproveTime.ts (1)

51-56: Add bounds checking for array access.

The array indexing could fail if requiredApprovals is less than 1 or greater than the number of available approvals. This issue was identified in past reviews and should be addressed.

Apply this diff to add safe array access:

+  const approvalIndex = Math.max(0, requiredApprovals - 1);
+  const sortedStatuses = statuses.sort((a, b) =>
+    isBefore(parseISO(a.submittedAt), parseISO(b.submittedAt)) ? 1 : -1
+  );
+  
  return isApproved
-   ? statuses.sort((a, b) =>
-       isBefore(parseISO(a.submittedAt), parseISO(b.submittedAt)) ? 1 : -1
-     )[requiredApprovals - 1]?.submittedAt
+   ? sortedStatuses[approvalIndex]?.submittedAt
    : null;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a24e2d8 and 64e1f71.

⛔ Files ignored due to path filters (1)
  • build/index.js is excluded by !build/** and included by none
📒 Files selected for processing (3)
  • src/converters/utils/calculations/getApproveTime.spec.ts (1 hunks)
  • src/converters/utils/calculations/getApproveTime.ts (3 hunks)
  • src/converters/utils/preparePullRequestTimeline.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/converters/utils/calculations/getApproveTime.spec.ts (1)
src/converters/utils/calculations/getApproveTime.ts (1)
  • getApproveTime (6-56)
🪛 Biome (1.9.4)
src/converters/utils/preparePullRequestTimeline.ts

[error] 33-33: Use Number.parseInt instead of the equivalent global.

ES2015 moved some globals into the Number namespace for consistency.
Safe fix: Use Number.parseInt instead.

(lint/style/useNumberNamespace)

🔇 Additional comments (2)
src/converters/utils/calculations/getApproveTime.ts (2)

6-9: LGTM! Parameterization approach improves function design.

Moving the configuration parsing to the caller is a good architectural decision that makes the function more testable and reusable.


17-17: LGTM! Logic correctly uses the requiredApprovals parameter.

The approval counting logic properly uses the requiredApprovals parameter instead of parsing configuration internally.

Also applies to: 22-23, 47-48

Comment on lines +31 to +34
const approveTime = getApproveTime(
pullRequestReviews,
parseInt(getValueAsIs("REQUIRED_APPROVALS"))
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Fix parseInt usage and add error handling for the config value.

The logic correctly passes the required approvals parameter, but there are two improvements needed:

  1. Static analysis correctly identifies that Number.parseInt should be used
  2. Add error handling for invalid or missing config values

Apply this diff:

  const approveTime = getApproveTime(
    pullRequestReviews,
-   parseInt(getValueAsIs("REQUIRED_APPROVALS"))
+   Number.parseInt(getValueAsIs("REQUIRED_APPROVALS") || "1", 10)
  );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const approveTime = getApproveTime(
pullRequestReviews,
parseInt(getValueAsIs("REQUIRED_APPROVALS"))
);
const approveTime = getApproveTime(
pullRequestReviews,
Number.parseInt(getValueAsIs("REQUIRED_APPROVALS") || "1", 10)
);
🧰 Tools
🪛 Biome (1.9.4)

[error] 33-33: Use Number.parseInt instead of the equivalent global.

ES2015 moved some globals into the Number namespace for consistency.
Safe fix: Use Number.parseInt instead.

(lint/style/useNumberNamespace)

🤖 Prompt for AI Agents
In src/converters/utils/preparePullRequestTimeline.ts around lines 31 to 34,
replace the use of parseInt with Number.parseInt for better clarity and static
analysis compliance. Additionally, add error handling to check if the config
value retrieved by getValueAsIs("REQUIRED_APPROVALS") is valid and a proper
number before parsing; if invalid or missing, handle the error gracefully, such
as by throwing an informative error or using a default value.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🔭 Outside diff range comments (2)
src/converters/utils/calculations/getApproveTime.ts (2)

60-64: Fix return logic to return the Nth approval timestamp.

The current implementation always returns the first approval timestamp ([0]), but it should return the timestamp of the Nth approval where N equals requiredApprovals. This breaks the expected behavior for multiple required approvals.

Based on the test case expecting the 2nd approval timestamp when requiredApprovals=2, the logic should be:

  return isApproved
    ? statuses.sort((a, b) =>
        isBefore(parseISO(a.submittedAt), parseISO(b.submittedAt)) ? 1 : -1
-      )[0]?.submittedAt
+      )[requiredApprovals - 1]?.submittedAt
    : null;

21-30: Refine early-exit logic in getApproveTime.ts to only trigger on new approvals

The current isApproved check (src/converters/utils/calculations/getApproveTime.ts, ~lines 21–30) will short-circuit on any review that isn’t a change request (e.g. comments), causing subsequent change requests or state flips to be ignored. To ensure we never miss a “changes_requested” after the threshold is reached, the early exit should only fire on additional approvals, not on arbitrary review events:

• File: src/converters/utils/calculations/getApproveTime.ts
Lines: ~21–30

Suggested diff:

- const isApproved =
-   statusesEntries.filter((u) => acc[u].state === "approved").length >= requiredApprovals &&
-   !statusesEntries.some((u) => acc[u].state === "changes_requested") &&
-   review.state !== "changes_requested";
+ const isApproved =
+   statusesEntries.filter((u) => acc[u].state === "approved").length >= requiredApprovals &&
+   !statusesEntries.some((u) => acc[u].state === "changes_requested") &&
+   review.state === "approved";

Additionally, please add unit tests to cover:

  1. A review switching from approvedchanges_requested after the threshold is reached
  2. A comment or other non-approval event occurring after threshold, followed by a changes_requested
  3. Multiple reviewers flipping statuses in sequence (approve → request changes → approve → request changes)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 64e1f71 and 8bdf44e.

⛔ Files ignored due to path filters (1)
  • build/index.js is excluded by !build/** and included by none
📒 Files selected for processing (2)
  • src/converters/utils/calculations/getApproveTime.spec.ts (1 hunks)
  • src/converters/utils/calculations/getApproveTime.ts (3 hunks)
🔇 Additional comments (3)
src/converters/utils/calculations/getApproveTime.spec.ts (2)

135-174: LGTM! Test updates correctly maintain existing behavior.

All existing test calls have been properly updated to include the new requiredApprovals parameter with a value of 1, which maintains the original behavior while adapting to the new function signature.


175-180: Well-designed test cases for multiple approval requirements.

The new test cases appropriately verify the function's behavior when requiring multiple approvals:

  • Testing that the second approval timestamp is returned when 2 approvals are required
  • Testing that null is returned when requesting more approvals than available

These test cases ensure the new functionality works as expected.

src/converters/utils/calculations/getApproveTime.ts (1)

7-8: Excellent approach - parameter-based design improves testability.

The updated function signature accepting requiredApprovals as a parameter is much better than the previous approach of calling getValueAsIs internally. This improves testability, performance, and separation of concerns.

Comment on lines 46 to 47
console.log(statuses);

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove debug console.log statements.

Console.log statements should not be included in production code as they can impact performance and clutter logs.

-  console.log(statuses);
-
-  console.log(
-    isApproved
-      ? statuses.sort((a, b) =>
-          isBefore(parseISO(a.submittedAt), parseISO(b.submittedAt)) ? 1 : -1
-        )
-      : null
-  );

Also applies to: 53-59

🤖 Prompt for AI Agents
In src/converters/utils/calculations/getApproveTime.ts at lines 46-47 and also
lines 53-59, remove all console.log statements used for debugging. These debug
logs should be eliminated from production code to avoid performance issues and
unnecessary log clutter.

@AlexSim93 AlexSim93 changed the base branch from master to v4 July 13, 2025 15:21
@AlexSim93 AlexSim93 merged commit 01d9a21 into v4 Jul 13, 2025
1 of 2 checks passed
@AlexSim93 AlexSim93 deleted the feature/configure-approvals-number branch July 13, 2025 15:22
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🔭 Outside diff range comments (1)
src/converters/utils/calculations/getApproveTime.ts (1)

55-55: Fix the approval timestamp logic to return the correct approval time.

The current implementation returns the latest approval timestamp ([0] after descending sort), but it should return the timestamp of the approval that reached the required threshold. For multiple required approvals, this should be the nth approval chronologically.

  return isApproved
    ? statuses.sort((a, b) =>
-        isBefore(parseISO(a.submittedAt), parseISO(b.submittedAt)) ? 1 : -1
-      )[0]?.submittedAt
+        isBefore(parseISO(a.submittedAt), parseISO(b.submittedAt)) ? -1 : 1
+      )[requiredApprovals - 1]?.submittedAt
    : null;

This change:

  1. Sorts in ascending chronological order (earliest first)
  2. Returns the timestamp of the final required approval (when the PR actually became approved)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 020a1ed and a8624ba.

⛔ Files ignored due to path filters (1)
  • build/index.js is excluded by !build/** and included by none
📒 Files selected for processing (1)
  • src/converters/utils/calculations/getApproveTime.ts (3 hunks)
🔇 Additional comments (3)
src/converters/utils/calculations/getApproveTime.ts (3)

6-8: LGTM: Function signature updated correctly.

The addition of the requiredApprovals parameter enables the configurable approval feature as intended.


22-23: LGTM: Approval counting logic updated correctly.

The change from some() to filter().length >= requiredApprovals properly implements the configurable approval threshold check.


48-49: LGTM: Final approval status check updated correctly.

Consistent with the reducer logic, this properly checks if the required number of approvals is met.

export const getApproveTime = (
reviews: Awaited<ReturnType<typeof makeComplexRequest>>["events"][number]
reviews: Awaited<ReturnType<typeof makeComplexRequest>>["events"][number],
requiredApprovals: number
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add validation for the requiredApprovals parameter.

Consider adding validation to ensure requiredApprovals is a positive integer to prevent unexpected behavior.

export const getApproveTime = (
  reviews: Awaited<ReturnType<typeof makeComplexRequest>>["events"][number],
  requiredApprovals: number
) => {
+  if (requiredApprovals <= 0 || !Number.isInteger(requiredApprovals)) {
+    throw new Error("requiredApprovals must be a positive integer");
+  }
+  
  const statuses = Object.values(
🤖 Prompt for AI Agents
In src/converters/utils/calculations/getApproveTime.ts at line 8, the
requiredApprovals parameter lacks validation. Add a check to ensure
requiredApprovals is a positive integer before using it, throwing an error or
handling invalid values appropriately to prevent unexpected behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Consider amount of required approvals for a PR being marked as approved

2 participants