Skip to content

Commit b5c8522

Browse files
committed
- make error handling robust
- add retries and handle GitHub API rate limiting errors
1 parent ea57293 commit b5c8522

File tree

2 files changed

+61
-6
lines changed

2 files changed

+61
-6
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "git-repo-lines-of-code",
3-
"version": "1.0.2",
3+
"version": "1.0.3",
44
"description": "Get your Github repository's lines of code with an option of excluding any files from the stat",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",

src/index.ts

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import * as fs from "fs";
22
import * as path from "path";
33

4+
const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
5+
const MAX_RETRIES = 3;
6+
47
/**
58
* Reads the content of the given relative file paths and returns the total number of lines of code.
69
*
@@ -24,6 +27,49 @@ const getLinesOfCodeToExclude = async (filePaths: string[]): Promise<number> =>
2427
return locToExclude;
2528
}
2629

30+
/**
31+
* Fetches data from a given GitHub API URL with retry logic for rate limiting.
32+
*
33+
* This function attempts to fetch data from the specified GitHub API URL. In case of a 403 response due to rate limiting,
34+
* it will wait until the rate limit resets and retry the request up to a maximum number of retries.
35+
*
36+
* @param retryCount The current retry attempt count. Automatically managed by the function.
37+
* @param url The GitHub API URL to fetch data from.
38+
* @returns A promise that resolves to an object containing the HTTP response, calculated lines of code, and raw data.
39+
* @throws Any error encountered during the fetch process after exhausting retry attempts.
40+
*/
41+
async function fetchGithubData(retryCount = 0, url: string): Promise<any> {
42+
try {
43+
const response = await fetch(url);
44+
45+
// Check if rate limited
46+
if (response.status === 403 && response.headers.get('x-ratelimit-remaining') === '0') {
47+
if (retryCount < MAX_RETRIES) {
48+
// Get reset time from headers
49+
const resetTime = parseInt(response.headers.get('x-ratelimit-reset') || '0') * 1000;
50+
const waitTime = Math.max(resetTime - Date.now(), 0);
51+
52+
// Wait for rate limit to reset (with some buffer)
53+
await wait(waitTime + 1000);
54+
55+
// Retry the request
56+
return fetchGithubData(retryCount + 1, url);
57+
}
58+
}
59+
60+
const data = await response?.json();
61+
let linesOfCode = Array.isArray(data) ? data.reduce((acc: number, curr: number[]) => acc + (curr[1] - Math.abs(curr[2])), 0) : null;
62+
63+
return { response, linesOfCode, data };
64+
} catch (error) {
65+
if (retryCount < MAX_RETRIES) {
66+
// Exponential backoff: 2^retryCount seconds
67+
await wait(Math.pow(2, retryCount) * 1000);
68+
return fetchGithubData(retryCount + 1, url);
69+
}
70+
throw error;
71+
}
72+
}
2773

2874
/**
2975
* Gets the total number of lines of code in a given Github repository.
@@ -40,13 +86,22 @@ const getRepoLinesOfCode = async (owner: string, repo: string, excludeFilePaths:
4086
const url = `https://api.github.com/repos/${owner}/${repo}/stats/code_frequency`;
4187

4288
try {
43-
const response = await fetch(url);
44-
const data = await response?.json();
45-
46-
const linesOfCode = Array.isArray(data) ? data.reduce((acc: number, curr: number[]) => acc + (curr[1] - Math.abs(curr[2])), 0) : null;
89+
const { response, linesOfCode, data } = await fetchGithubData(0, url);
4790

91+
if (!response.ok) {
92+
return `Github API error: ${response.status} ${response.statusText}`;
93+
}
94+
95+
if (!data) {
96+
return "Github API error: Received empty response";
97+
}
98+
99+
if (!Array.isArray(data)) {
100+
return `Github API error - Invalid data format received: ${JSON.stringify(data)}`;
101+
}
102+
48103
if (!linesOfCode) {
49-
return "Github - No data found for the given repository";
104+
return "Github - Rate limit exceeded. Please try again later.";
50105
}
51106

52107
if (excludeFilePaths.length > 0) {

0 commit comments

Comments
 (0)