Skip to content

feat: batch GitHub API calls into single GraphQL queries - #56

Open
santoshyadavdev wants to merge 8 commits into
mainfrom
santoshyadavdev-batch-github-api-calls
Open

feat: batch GitHub API calls into single GraphQL queries#56
santoshyadavdev wants to merge 8 commits into
mainfrom
santoshyadavdev-batch-github-api-calls

Conversation

@santoshyadavdev

@santoshyadavdev santoshyadavdev commented Jul 16, 2026

Copy link
Copy Markdown
Owner

Why

Users with long GitHub histories (10+ years) hit "Resource limits for this query exceeded" errors because the app fired a separate API call for each year -- potentially 20+ parallel requests for contributions and repository data.

Approach

Instead of making N per-year GraphQL requests, the new endpoints build a single query using GraphQL field aliases to fetch all years at once:

query($login: String!) {
  user(login: $login) {
    y2015: contributionsCollection(from: "2015-01-01T00:00:00Z", to: "2015-12-31T23:59:59Z") { ... }
    y2016: contributionsCollection(from: "2016-01-01T00:00:00Z", to: "2016-12-31T23:59:59Z") { ... }
    # all years in one request
  }
}

This reduces the total API calls from ~N*2 (contributions + repo contributions per year) down to 3 total (1 contributions batch + 1 repo contributions batch + 1 discussions).

Changes

Server (server.ts):

  • Added POST /api/github/contributions-batch -- accepts { username, years[] }, returns all yearly contribution stats in one response
  • Added POST /api/github/repository-contributions-batch -- same pattern for repository-level contributions
  • Both endpoints include SAML fallback handling (retries without restrictedContributionsCount if org requires SSO)

Frontend (github.service.ts):

  • Updated getAggregatedActivity() and getRepositoryInsights() to call the new batch endpoints
  • Existing per-year endpoints are preserved for backward compatibility

Notes

  • The original per-year endpoints (/api/github/contributions, /api/github/repository-contributions) are kept intact so nothing breaks if they are used elsewhere.
  • The response shape wraps results in a { years: [...] } envelope so the frontend can iterate without extra mapping.

Summary by CodeRabbit

  • New Features
    • Added batched GitHub contribution retrieval across multiple years.
    • Added batched repository contribution insights with per-year top repositories.
    • Introduced new POST API endpoints for contributions and repository contributions batches.
  • Performance
    • Reduced load time by consolidating multi-year data fetching into fewer requests.
  • Bug Fixes
    • Simplified contribution responses to always return private contribution counts as 0 when unavailable.
  • Behavior Changes
    • Added input validation/defaulting for batch year requests and improved error handling for API query failures.

Replace per-year API calls with batched endpoints that use GraphQL
field aliases to fetch all years in one request. This fixes 'Resource
limits exceeded' errors for users with many years of activity.

New server endpoints:
- POST /api/github/contributions-batch
- POST /api/github/repository-contributions-batch

Updated frontend service methods (getAggregatedActivity,
getRepositoryInsights) to use the batch endpoints, reducing
N+1 API calls down to 2 total (contributions + repo contributions).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

GitHubService and the Workers API now support batched multi-year contribution and repository contribution queries. Aggregation methods consume batched responses, merge repository data across years, and retain existing response structures.

Changes

GitHub batch contribution flow

Layer / File(s) Summary
Angular batch service contracts
yourstory/src/app/core/services/github.service.ts
Adds batched response types, a year cap, and public methods that POST usernames and year arrays to the new endpoints.
Batch API handlers and routing
yourstory/src/server.ts
Adds validated, chunked GraphQL batch endpoints, repository aggregation, simplified public contribution totals, and request routing.
Activity and repository aggregation
yourstory/src/app/core/services/github.service.ts
Updates aggregation flows to clamp year ranges, consume batched years, sum totals, and merge repositories across years.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GitHubService
  participant WorkersAPI
  participant GitHubGraphQL
  GitHubService->>WorkersAPI: POST username and years
  WorkersAPI->>GitHubGraphQL: Run chunked aliased queries
  GitHubGraphQL-->>WorkersAPI: Return contribution data by year
  WorkersAPI-->>GitHubService: Return batched response
  GitHubService->>GitHubService: Aggregate totals and merge repositories
Loading

Possibly related PRs

Suggested labels: enhancement

Poem

I’m a bunny with batches, hopping year by year,
One GraphQL carrot makes the totals clear.
Repositories merge in a tidy row,
Private counts gently say “not so.”
Fewer hops, more data—off we go!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: batching GitHub GraphQL calls into single requests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch santoshyadavdev-batch-github-api-calls

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 16, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
commitstory cffb917 Commit Preview URL

Branch Preview URL
Jul 17 2026, 10:08 AM

@coderabbitai coderabbitai Bot added the enhancement New feature or request label Jul 16, 2026
- Contributions batch: chunked into groups of 5 years per query
- Repo contributions batch: chunked into groups of 3 years per query
- Reduced maxRepositories from 100 to 20 per year to lower node count
- Added rateLimit { cost remaining } to queries for debugging
- Sequential chunk execution prevents hitting GitHub's resource limits

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@yourstory/src/server.ts`:
- Around line 378-400: Validate body.years in both batch handlers at
yourstory/src/server.ts lines 378-400 and 530-554 before constructing queries or
calling chunkArray: require an array of integers within the supported year range
and enforce a maximum list size. Return the existing 400-style validation
response for invalid, out-of-range, empty, or oversized input, while preserving
the default current-year behavior when years is omitted.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0c59fa48-e308-475d-95c4-544934c5bbb9

📥 Commits

Reviewing files that changed from the base of the PR and between 9bccc5a and f3bcdbe.

📒 Files selected for processing (2)
  • yourstory/src/app/core/services/github.service.ts
  • yourstory/src/server.ts

Comment thread yourstory/src/server.ts Outdated
Comment on lines +378 to +400
const body = (await request.json()) as { username?: string; years?: number[] };
const login = body.username ?? '';
if (!login) return json({ error: 'username is required' }, 400);

const token = env.GITHUB_TOKEN;
if (!token) return json({ error: 'GITHUB_TOKEN is not configured' }, 503);

const years = body.years ?? [new Date().getFullYear()];
if (years.length === 0) return json({ error: 'years array is empty' }, 400);

// Build aliased fragments for each year
const contribFields = `
totalCommitContributions
totalIssueContributions
totalPullRequestContributions
totalPullRequestReviewContributions
restrictedContributionsCount
`;

const yearFragments = years.map(
(y) =>
`y${y}: contributionsCollection(from: "${y}-01-01T00:00:00Z", to: "${y}-12-31T23:59:59Z") { ${contribFields} }`
).join('\n ');

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the file and inspect relevant slices.
wc -l yourstory/src/server.ts
sed -n '340,430p' yourstory/src/server.ts
printf '\n--- SECOND RANGE ---\n'
sed -n '500,590p' yourstory/src/server.ts

printf '\n--- SEARCH FOR VALIDATION HELPERS ---\n'
rg -n "years|username|validate|schema|zod|parse" yourstory/src/server.ts

Repository: santoshyadavdev/commitstory

Length of output: 13381


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the batching/query construction and any size checks.
sed -n '430,540p' yourstory/src/server.ts
printf '\n--- REPO BATCH CONTINUATION ---\n'
sed -n '591,690p' yourstory/src/server.ts

printf '\n--- SEARCH FOR MAX/YEARS LIMITS ---\n'
rg -n "MAX_.*YEAR|chunkArray\\(|years\\.length|Array\\.isArray|Number\\.isInteger|Integer|plausible|unique" yourstory/src/server.ts

Repository: santoshyadavdev/commitstory

Length of output: 8534


Validate years before either batch query is assembled.
body.years is only null-coalesced today; a non-array payload can still reach chunkArray(...) and fail at runtime, and large lists can make the aliased GraphQL queries much more expensive. Add explicit array/integer/range/size checks in both batch handlers before constructing the query.

📍 Affects 1 file
  • yourstory/src/server.ts#L378-L400 (this comment)
  • yourstory/src/server.ts#L530-L554
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@yourstory/src/server.ts` around lines 378 - 400, Validate body.years in both
batch handlers at yourstory/src/server.ts lines 378-400 and 530-554 before
constructing queries or calling chunkArray: require an array of integers within
the supported year range and enforce a maximum list size. Return the existing
400-style validation response for invalid, out-of-range, empty, or oversized
input, while preserving the default current-year behavior when years is omitted.

- Contributions: 3 years per chunk (scalars only, lightweight)
- Repo contributions: 1 year per chunk (safest, avoids node limits)
- maxRepositories: reduced from 20 to 10

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@yourstory/src/server.ts`:
- Around line 504-512: Update the frontend aggregation flow in github.service.ts
to consume privateContributionsBlocked from the yearly contribution results and
propagate the unavailable status instead of treating privateContributions: 0 as
an actual total. Ensure the aggregate contract marks private contributions
incomplete, or represents the value as nullable, while preserving normal totals
when the flag is not set.
- Around line 445-450: Update the GraphQL query in the batch handler around the
rateLimit selection so its cost and remaining values are either surfaced through
the existing logs or returned payload, or remove the rateLimit field entirely if
they are not needed. Ensure both batch handlers consistently handle the
rate-limit data rather than querying and ignoring it.
- Around line 466-472: Update the hasSamlError calculation in the GraphQL error
handling block to require every error in data.errors to satisfy the existing
SAML indicators, using all() rather than any-error matching. Preserve the
current non-SAML response behavior so mixed or unrelated failures return the
first error instead of entering the SAML fallback.
- Around line 436-440: Keep SAML failure state scoped to the current chunk in
the loop within the server handler: replace the shared privateBlocked state with
a per-chunk flag initialized for each iteration, and use it only when selecting
contribution fields and applying that chunk’s fallback. Preserve normal private
contributions and restrictedContributionsCount for later chunks whose queries
succeed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: f9b8ce7a-38ef-469c-974d-90f886c2ed09

📥 Commits

Reviewing files that changed from the base of the PR and between f3bcdbe and 3183ecf.

📒 Files selected for processing (1)
  • yourstory/src/server.ts

Comment thread yourstory/src/server.ts Outdated
Comment on lines +436 to +440
let privateBlocked = false;

try {
for (const chunk of chunks) {
const fields = privateBlocked ? contribFieldsNoPrivate : contribFields;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the relevant region with line numbers
sed -n '380,560p' yourstory/src/server.ts

echo '--- SEARCH privateBlocked ---'
rg -n "privateBlocked|contribFieldsNoPrivate|privateContributionsBlocked|restrictedContributionsCount" yourstory/src/server.ts

Repository: santoshyadavdev/commitstory

Length of output: 8165


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
p = Path('yourstory/src/server.ts')
text = p.read_text()
for needle in ['privateBlocked', 'contribFieldsNoPrivate', 'privateContributionsBlocked', 'restrictedContributionsCount']:
    print(f'--- {needle} ---')
    for i, line in enumerate(text.splitlines(), start=1):
        if needle in line:
            print(f'{i}: {line}')
PY

Repository: santoshyadavdev/commitstory

Length of output: 2056


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find how the batch response is consumed and whether privateContributions is summed.
rg -n "privateContributions|privateContributionsBlocked|contributions-batch|years\s*:\s*allResults|sum\(" yourstory/src

Repository: santoshyadavdev/commitstory

Length of output: 3000


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n "contributions-batch|privateContributionsBlocked|privateContributions" yourstory/src yourstory -g '!**/*.map'

Repository: santoshyadavdev/commitstory

Length of output: 5563


🌐 Web query:

GitHub GraphQL restrictedContributionsCount SAML failure contributionsCollection query error per range or per user

💡 Result:

When querying the GitHub GraphQL API for contributionsCollection, users may experience issues related to restricted contributions or SAML enforcement if their Personal Access Token (PAT) is not correctly authorized for the organization’s SAML single sign-on (SSO) session [1][2][3]. ### Understanding the Behavior 1. SAML Enforcement: If you are a member of an organization that enforces SAML SSO, the GitHub GraphQL API will restrict access to data related to that organization unless the OAuth token or PAT has been explicitly authorized for the organization's SSO session [1][2][3]. Queries that touch protected resources—even if the information seems public—may fail or return partial/zeroed results if the session is not active [1][2]. 2. ContributionsCollection and SSO: When fetching contribution data, the API will not include activity from SAML-protected organizations if there is no active, authorized SSO session associated with the token [1]. This often manifests as missing data or zero counts in the contributionsCollection response, even when the user has contributions in those organizations [1][4]. 3. Restricted Contributions: The field restrictedContributionsCount represents contributions made in private or internal repositories that the viewer cannot access [5][6]. This field only contains non-zero values if the user has specifically chosen to share their private contribution counts on their profile [5][6]. Note that restrictedContributionsCount is distinct from the SAML-related access issues; it is a privacy setting managed by the user, not a result of SAML enforcement [5]. ### Recommended Troubleshooting Steps * Authorize your PAT for SAML SSO: If you are receiving errors or missing data for a specific organization, you must authorize your PAT for that organization's SAML SSO [3]. You can do this through the GitHub web interface: navigate to your Personal Access Tokens settings, select the relevant token, and choose "Configure SSO" to authorize it for your organization [3]. * Check Token Permissions: Ensure your token has the necessary scopes (read:user, repo, etc.) required for the data you are accessing [5][7]. While classic PATs are generally recommended for avoiding expiration, ensure the permissions match the data requested [7]. * Verify User Privacy Settings: If you are querying restrictedContributionsCount and getting zero, verify that the target user has enabled "Include private contributions on my profile" in their GitHub account settings [5][6]. * Use Appropriate Endpoints: If you require information that is specifically protected by SAML, ensure the API request includes the necessary authentication headers for the SSO session. If you only need broad, non-protected data, you may need to filter your queries to avoid explicitly triggering protected resource lookups that require active SSO [2]. If you receive a specific GraphQL error with an extensions field containing saml_failure: true, this is a definitive indicator that your token lacks the required SSO authorization for that specific organization [2].

Citations:


Keep the SAML fallback local to the chunk. Flipping privateBlocked here zeroes privateContributions for every later year and suppresses restrictedContributionsCount even when those queries would succeed, so the batch undercounts totals after the first SAML failure.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@yourstory/src/server.ts` around lines 436 - 440, Keep SAML failure state
scoped to the current chunk in the loop within the server handler: replace the
shared privateBlocked state with a per-chunk flag initialized for each
iteration, and use it only when selecting contribution fields and applying that
chunk’s fallback. Preserve normal private contributions and
restrictedContributionsCount for later chunks whose queries succeed.

Comment thread yourstory/src/server.ts
Comment thread yourstory/src/server.ts Outdated
Comment on lines +466 to +472
if (data.errors?.length) {
const hasSamlError = data.errors.some((e) => {
const msg = e.message?.toLowerCase() ?? '';
return e.extensions?.saml_failure === true || msg.includes('saml') || msg.includes('organization');
});

if (!hasSamlError) return json({ error: data.errors[0].message }, 400);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

sed -n '430,510p' yourstory/src/server.ts

Repository: santoshyadavdev/commitstory

Length of output: 3393


Avoid retrying mixed GraphQL failures. some() sends the whole response down the SAML fallback when any error looks SAML-related, so unrelated auth/query/rate-limit errors can be hidden. Retry only when all errors are SAML-related.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@yourstory/src/server.ts` around lines 466 - 472, Update the hasSamlError
calculation in the GraphQL error handling block to require every error in
data.errors to satisfy the existing SAML indicators, using all() rather than
any-error matching. Preserve the current non-SAML response behavior so mixed or
unrelated failures return the first error instead of entering the SAML fallback.

Comment thread yourstory/src/server.ts Outdated
Comment on lines +504 to +512
allResults.push({
year: y,
commits: c?.totalCommitContributions ?? 0,
issues: c?.totalIssueContributions ?? 0,
pullRequests: c?.totalPullRequestContributions ?? 0,
reviews: c?.totalPullRequestReviewContributions ?? 0,
privateContributions: 0,
privateContributionsBlocked: true,
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Propagate unavailable private totals through the frontend contract.

The fallback returns privateContributions: 0, but github.service.ts omits and ignores privateContributionsBlocked. The aggregate therefore presents incomplete data as a real zero. Consume this flag and mark the aggregate incomplete, or represent the value as nullable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@yourstory/src/server.ts` around lines 504 - 512, Update the frontend
aggregation flow in github.service.ts to consume privateContributionsBlocked
from the yearly contribution results and propagate the unavailable status
instead of treating privateContributions: 0 as an actual total. Ensure the
aggregate contract marks private contributions incomplete, or represents the
value as nullable, while preserving normal totals when the flag is not set.

santoshyadavdev and others added 2 commits July 16, 2026 23:26
The restrictedContributionsCount field forces GitHub to enumerate all
org memberships internally, causing 'Resource limits exceeded' for
users with many org contributions. Removed from both the single-year
and batch endpoints. privateContributions now returns 0.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Users with accounts older than 7 years were generating too many
year-scoped GraphQL queries. Cap startYear to (currentYear - 6)
so at most 7 years of data are fetched.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
yourstory/src/server.ts (1)

358-358: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Return 400 for malformed batch request JSON.

request.json() runs before the handler’s try, so invalid JSON escapes this endpoint’s error handling instead of producing a client validation response.

Proposed fix
-  const body = (await request.json()) as { username?: string; years?: number[] };
+  let body: { username?: string; years?: number[] };
+  try {
+    body = (await request.json()) as { username?: string; years?: number[] };
+  } catch {
+    return json({ error: 'invalid JSON body' }, 400);
+  }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@yourstory/src/server.ts` at line 358, Move the request.json() call in the
batch request handler inside its existing try block so malformed JSON is caught
and returns HTTP 400 through the endpoint’s validation error handling. Preserve
the current parsed body shape and successful request flow.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@yourstory/src/server.ts`:
- Line 358: Move the request.json() call in the batch request handler inside its
existing try block so malformed JSON is caught and returns HTTP 400 through the
endpoint’s validation error handling. Preserve the current parsed body shape and
successful request flow.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 70b031ca-2bc4-43bb-bada-3240a5bf9c0a

📥 Commits

Reviewing files that changed from the base of the PR and between db27ca1 and ad9cacf.

📒 Files selected for processing (2)
  • yourstory/src/app/core/services/github.service.ts
  • yourstory/src/server.ts

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
yourstory/src/app/core/services/github.service.ts (1)

94-109: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Enforce the year cap inside the batch helpers. These methods are public and pass years through unchanged, so any other caller can bypass MAX_YEARS and send an oversized batch. Move validation/deduping/capping here, or make the wrappers private.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@yourstory/src/app/core/services/github.service.ts` around lines 94 - 109,
Enforce MAX_YEARS within the public getContributionsBatch and
getRepositoryContributionsBatch helpers by validating, deduplicating, and
capping the years array before each HTTP request. Ensure both methods apply the
same bounded-year behavior so callers cannot bypass the limit; alternatively
make these wrappers private if validation remains exclusively elsewhere.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@yourstory/src/app/core/services/github.service.ts`:
- Around line 94-109: Enforce MAX_YEARS within the public getContributionsBatch
and getRepositoryContributionsBatch helpers by validating, deduplicating, and
capping the years array before each HTTP request. Ensure both methods apply the
same bounded-year behavior so callers cannot bypass the limit; alternatively
make these wrappers private if validation remains exclusively elsewhere.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 049359d3-a5f1-4dcc-b256-ecde9cade2ee

📥 Commits

Reviewing files that changed from the base of the PR and between ad9cacf and 581d18c.

📒 Files selected for processing (1)
  • yourstory/src/app/core/services/github.service.ts

santoshyadavdev and others added 2 commits July 17, 2026 11:52
3 years still exceeded resource limits for some accounts.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Years where GitHub returns 'Resource limits exceeded' are now
skipped instead of crashing the entire batch request. The response
includes a failedYears array so the frontend knows which data is
missing. This handles accounts with complex org memberships that
blow GitHub's internal node limits for certain year ranges.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant