diff --git a/.env.example b/.env.example index 35cc70f..d5909b8 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,14 @@ 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 + + +# 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 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/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 ( { + 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, }, }),