From 2691db01f5383ddd361b94dcb416a848d981ddcd Mon Sep 17 00:00:00 2001 From: Shashwat Upadhayay <112780808+ShashwatUpadhayay@users.noreply.github.com> Date: Wed, 24 Jun 2026 07:43:12 +0530 Subject: [PATCH 1/3] feat: make GitHub query limits configurable via env (#167) --- .env.example | 7 ++++++ README.md | 6 +++++ lib/github.test.ts | 29 ++++++++++++++++++++++ lib/github.ts | 62 ++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 99 insertions(+), 5 deletions(-) create mode 100644 lib/github.test.ts diff --git a/.env.example b/.env.example index d976952..d5909b8 100644 --- a/.env.example +++ b/.env.example @@ -3,6 +3,13 @@ GITHUB_TOKEN=your_github_token_here # If omitted, the app falls back to https://github.com/O2sa/DevImpact NEXT_PUBLIC_GITHUB_REPO_URL=your_github_repo_url_here + +# GitHub query limits +GITHUB_REPO_COUNT=30 +GITHUB_PR_COUNT=80 +GITHUB_ISSUE_COUNT=20 +GITHUB_DISCUSSION_COUNT=10 + # Redis caching (optional) # Use either redis://localhost:6379 or include password if enabled: redis://:password@localhost:6379 REDIS_URL= diff --git a/README.md b/README.md index cfba156..b306479 100644 --- a/README.md +++ b/README.md @@ -186,6 +186,12 @@ Create a `.env` file: ``` GITHUB_TOKEN=your_github_token +NEXT_PUBLIC_GITHUB_REPO_URL=your_github_repo_url +GITHUB_REPO_COUNT=30 +GITHUB_PR_COUNT=80 +GITHUB_ISSUE_COUNT=20 +GITHUB_DISCUSSION_COUNT=10 + ``` --- diff --git a/lib/github.test.ts b/lib/github.test.ts new file mode 100644 index 0000000..0de8090 --- /dev/null +++ b/lib/github.test.ts @@ -0,0 +1,29 @@ +import {describe, expect, it} from "vitest"; +import {parseCountEnv} from "./github"; + + +describe("parseCountEnv", () => { + it("uses fallback for undefined", () => { + expect(parseCountEnv(undefined, 30, 100)).toBe(30); + }); + + it("parses a valid value", () => { + expect(parseCountEnv("50", 30, 100)).toBe(50); + }); + + it("uses fallback for non-numeric input", () => { + expect(parseCountEnv("abc", 30, 100)).toBe(30); + }); + + it("uses fallback for zero", () => { + expect(parseCountEnv("0", 30, 100)).toBe(30); + }); + + it("uses fallback for negative values", () => { + expect(parseCountEnv("-5", 30, 100)).toBe(30); + }); + + it("clamps values above the maximum", () => { + expect(parseCountEnv("500", 30, 100)).toBe(100); + }); +}); \ No newline at end of file diff --git a/lib/github.ts b/lib/github.ts index 4c2a369..78d1b02 100644 --- a/lib/github.ts +++ b/lib/github.ts @@ -16,7 +16,7 @@ import type { type Logger = Pick; -type GitHubRawUser = { +type GitHubRawUser = { name: string | null; avatarUrl: string; repositories: { nodes: Array }; @@ -71,6 +71,31 @@ export type GitHubFetcherDependencies = { logger?: Logger; }; +const DEFAULT_GITHUB_REPO_COUNT = 30; +const DEFAULT_GITHUB_PR_COUNT = 80; +const DEFAULT_GITHUB_ISSUE_COUNT = 20; +const DEFAULT_GITHUB_DISCUSSION_COUNT = 10; + + +const MAX_GITHUB_REPO_COUNT = 100; +const MAX_GITHUB_PR_COUNT = 100; +const MAX_GITHUB_ISSUE_COUNT = 100; +const MAX_GITHUB_DISCUSSION_COUNT = 100; + +export function parseCountEnv( + value: string | undefined, + fallback: number, + maxValue: number, +): number{ + + const parsed = Number.parseInt(value ?? "", 10); + if(!Number.isInteger(parsed)|| parsed<=0){ + return fallback; + } + return Math.min(parsed, maxValue); + +} + const USER_AND_PULL_REQUESTS_QUERY = /* GraphQL */ ` query FetchUserAndPullRequests( $login: String! @@ -275,6 +300,8 @@ export function buildGitHubUserCacheKey( return `${namespace}:github-user:${normalizeGitHubUsername(username)}`; } + + async function fetchUserDataFromGitHub( executor: GitHubQueryExecutor, username: string, @@ -283,6 +310,31 @@ async function fetchUserDataFromGitHub( const externalIssueQuery = `type:issue author:${username} -user:${username}`; const externalDiscussionQuery = `author:${username} -user:${username}`; + +const repoCount = parseCountEnv( + process.env.GITHUB_REPO_COUNT, + DEFAULT_GITHUB_REPO_COUNT, + MAX_GITHUB_REPO_COUNT, +); + +const prCount = parseCountEnv( + process.env.GITHUB_PR_COUNT, + DEFAULT_GITHUB_PR_COUNT, + MAX_GITHUB_PR_COUNT, +); + +const issueCount = parseCountEnv( + process.env.GITHUB_ISSUE_COUNT, + DEFAULT_GITHUB_ISSUE_COUNT, + MAX_GITHUB_ISSUE_COUNT, +); + +const discussionCount = parseCountEnv( + process.env.GITHUB_DISCUSSION_COUNT, + DEFAULT_GITHUB_DISCUSSION_COUNT, + MAX_GITHUB_DISCUSSION_COUNT, +); + const userAndPrResponse = await executor.execute< FetchUserAndPullRequestsResponse, @@ -297,8 +349,8 @@ async function fetchUserDataFromGitHub( query: USER_AND_PULL_REQUESTS_QUERY, variables: { login: username, - repoCount: 30, - prCount: 80, + repoCount, + prCount, externalPrQuery, }, }); @@ -319,7 +371,7 @@ async function fetchUserDataFromGitHub( operationName: "FetchUserIssues", query: ISSUES_QUERY, variables: { - issueCount: 20, + issueCount, externalIssueQuery, }, }), @@ -333,7 +385,7 @@ async function fetchUserDataFromGitHub( operationName: "FetchUserDiscussions", query: DISCUSSIONS_QUERY, variables: { - discussionCount: 10, + discussionCount, externalDiscussionQuery, }, }), From bac3d5b0d0c833dbcfd8c19ae356b64f155d5d69 Mon Sep 17 00:00:00 2001 From: Osama Mabkhot <99215291+O2sa@users.noreply.github.com> Date: Wed, 24 Jun 2026 05:47:21 +0300 Subject: [PATCH 2/3] chore: Add GitHub token to first PR merged workflow --- .github/workflows/first-pr-merged.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/first-pr-merged.yml b/.github/workflows/first-pr-merged.yml index 1e8c66f..f12884a 100644 --- a/.github/workflows/first-pr-merged.yml +++ b/.github/workflows/first-pr-merged.yml @@ -16,6 +16,7 @@ jobs: - name: Thank contributor and ask for star uses: actions/github-script@v7 with: + github-token: ${{ secrets.YOUR_TOKEN_NAME }} script: | await new Promise(resolve => setTimeout(resolve, 3000)); From 3d0e9f586c56733d546601ff11b8ab8bfd1a6fe3 Mon Sep 17 00:00:00 2001 From: Osama Mabkhot <99215291+O2sa@users.noreply.github.com> Date: Wed, 24 Jun 2026 05:51:09 +0300 Subject: [PATCH 3/3] docs: Delete API Example section from README (#170) --- README.md | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/README.md b/README.md index b306479..fec9780 100644 --- a/README.md +++ b/README.md @@ -204,38 +204,6 @@ pnpm run dev --- ---- - -## 📡 API Example - -The compare endpoint accepts one or more `username` query parameters. - -### Example request - -```bash -curl "api/compare?username=devimpact&username=octocat" -``` - -### Example response - -```json -{ - "success": true, - "users": [ - { - "username": "octocat", - "name": "The Octocat", - "avatarUrl": "https://avatars.githubusercontent.com/u/583231?v=4", - "repoScore": 87, - "prScore": 64, - "contributionScore": 42, - "finalScore": 73, - "topRepos": [], - "topPullRequests": [] - } - ] -} -``` ## 🌍 Localization