From 3f6c6ccc6800b47d0200a6d1e29e39381b75a28b Mon Sep 17 00:00:00 2001 From: ShashwatUpadhayay Date: Sat, 20 Jun 2026 22:02:12 +0530 Subject: [PATCH 1/2] feat: make GitHub repository URL configurable --- .env.example | 3 +++ components/github-link.tsx | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index 35cc70f..d976952 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,7 @@ GITHUB_TOKEN=your_github_token_here +# Public GitHub repository URL shown by the app. +# If omitted, the app falls back to https://github.com/O2sa/DevImpact +NEXT_PUBLIC_GITHUB_REPO_URL=your_github_repo_url_here # Redis caching (optional) # Use either redis://localhost:6379 or include password if enabled: redis://:password@localhost:6379 diff --git a/components/github-link.tsx b/components/github-link.tsx index 2c209c9..065282f 100644 --- a/components/github-link.tsx +++ b/components/github-link.tsx @@ -11,9 +11,10 @@ type GithubLinkProps = { export function GithubLink({ variant = "compact" }: GithubLinkProps) { const isProminent = variant === "prominent"; + const githubRepoUrl= process.env.NEXT_PUBLIC_GITHUB_REPO_URL || "https://github.com/O2sa/DevImpact"; return ( Date: Sun, 21 Jun 2026 21:20:18 +0530 Subject: [PATCH 2/2] feat: make GitHub query limits configurable via env --- .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, }, }),