Skip to content

Commit 1d16005

Browse files
Merge pull request #12 from gitcommitshow/refactor-network-req
refactor: separate request responsibility
2 parents c6d25c6 + a9459eb commit 1d16005

File tree

4 files changed

+105
-68
lines changed

4 files changed

+105
-68
lines changed

contributors.js

Lines changed: 38 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33
* @example To archive contributors leaderboard data in csv file, run `node contributors.js`
44
*/
55

6-
exports.archiveContributorsLeaderboard = archiveContributorsLeaderboard
6+
exports.archiveContributorsLeaderboard = archiveContributorsLeaderboard;
7+
exports.getAllRepos = getAllRepos;
78
exports.getAllContributors = getAllContributors;
89
exports.getRepoContributors = getRepoContributors;
910

10-
const https = require('https');
1111
const path = require('path');
1212

13+
const { makeRequest } = require('./network.js');
14+
1315
// Configurations (Optional)
1416
// Repo owner that you want to analyze
1517
const REPO_OWNER = process.env.REPO_OWNER;
@@ -40,37 +42,23 @@ async function getAllRepos(owner=REPO_OWNER, options) {
4042
if(options && options.GITHUB_PERSONAL_TOKEN){
4143
GITHUB_REQUEST_OPTIONS.headers["Authorization"] = "token "+options.GITHUB_PERSONAL_TOKEN;
4244
}
43-
return new Promise((resolve, reject) => {
44-
let url = `https://api.github.com/orgs/${owner}/repos?per_page=100&page=${pageNo}`;
45-
console.log(url);
46-
https.get(url, GITHUB_REQUEST_OPTIONS, (res) => {
47-
console.log('statusCode:', res.statusCode);
48-
// console.log('headers:', res.headers);
49-
let data = '';
50-
res.on('data', (d) => {
51-
data += d;
52-
})
53-
res.on('end', async () => {
54-
console.log("Repo list request finished")
55-
// console.log(data)
56-
let dataJsonArray = JSON.parse(data);
57-
if (dataJsonArray.length == 100) {
58-
//It might have more data on the next page
59-
pageNo++;
60-
try {
61-
let dataFromNextPage = await getAllRepos(owner, { pageNo: pageNo } );
62-
dataJsonArray.push(...dataFromNextPage);
63-
} catch (err) {
64-
console.log("No more pagination needed")
65-
}
66-
}
67-
resolve(dataJsonArray);
68-
})
69-
}).on('error', (e) => {
70-
console.error(e);
71-
reject(e)
72-
});
73-
})
45+
let url = `https://api.github.com/orgs/${owner}/repos?per_page=100&page=${pageNo}`;
46+
const { res, data } = await makeRequest('GET', url, Object.assign({},GITHUB_REQUEST_OPTIONS));
47+
console.log("Repo list request finished");
48+
console.log('HTTP status: ', res.statusCode);
49+
// console.log(data)
50+
let dataJsonArray = JSON.parse(data);
51+
if (dataJsonArray.length == 100) {
52+
//It might have more data on the next page
53+
pageNo++;
54+
try {
55+
let dataFromNextPage = await getAllRepos(owner, { pageNo: pageNo } );
56+
dataJsonArray.push(...dataFromNextPage);
57+
} catch (err) {
58+
console.log("No more pagination needed")
59+
}
60+
}
61+
return dataJsonArray;
7462
}
7563

7664
/**
@@ -81,37 +69,23 @@ async function getAllRepos(owner=REPO_OWNER, options) {
8169
* @example getRepoContributors('myorghandle/myreponame').then((contributors) => console.log(contributors)).catch((err) => console.log(err))
8270
*/
8371
async function getRepoContributors(fullRepoName, pageNo = 1) {
84-
return new Promise((resolve, reject) => {
85-
let url = `https://api.github.com/repos/${fullRepoName}/contributors?per_page=100&page=${pageNo}`;
86-
console.log(url);
87-
https.get(url, GITHUB_REQUEST_OPTIONS, (res) => {
88-
console.log('statusCode:', res.statusCode);
89-
// console.log('headers:', res.headers);
90-
let data = '';
91-
res.on('data', (d) => {
92-
data += d;
93-
})
94-
res.on('end', async () => {
95-
console.log("Contributors request finished for " + fullRepoName)
96-
// console.log(data)
97-
let dataJsonArray = JSON.parse(data);
98-
if (dataJsonArray.length == 100) {
99-
//It might have more data on the next page
100-
pageNo++;
101-
try {
102-
let dataFromNextPage = await getRepoContributors(fullRepoName, pageNo);
103-
dataJsonArray.push(...dataFromNextPage);
104-
} catch (err) {
105-
console.log("No more pagination needed")
106-
}
107-
}
108-
resolve(dataJsonArray);
109-
})
110-
}).on('error', (e) => {
111-
console.error(e);
112-
reject(e)
113-
});
114-
})
72+
let url = `https://api.github.com/repos/${fullRepoName}/contributors?per_page=100&page=${pageNo}`;
73+
console.log(url);
74+
const { res, data } = await makeRequest('GET', url, Object.assign({},GITHUB_REQUEST_OPTIONS));
75+
console.log("Contributors request finished for " + fullRepoName)
76+
// console.log(data)
77+
let dataJsonArray = JSON.parse(data);
78+
if (dataJsonArray.length == 100) {
79+
//It might have more data on the next page
80+
pageNo++;
81+
try {
82+
let dataFromNextPage = await getRepoContributors(fullRepoName, pageNo);
83+
dataJsonArray.push(...dataFromNextPage);
84+
} catch (err) {
85+
console.log("No more pagination needed")
86+
}
87+
}
88+
return dataJsonArray;
11589
}
11690

11791
/**

network.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
const https = require('https');
2+
3+
exports.makeRequest = makeRequest;
4+
5+
/**
6+
* Sends an HTTPS request based on the specified method and options
7+
* This function returns a Promise that resolves with the response and data received from the server
8+
* @param {string} method - The HTTP method to use (e.g., 'GET', 'POST').
9+
* @param {string} url - The URL to which the request is sent.
10+
* @param {Object} [options] - The options for the request. This includes headers, request body (for POST/PUT), etc.
11+
* @returns {Promise<{res: https.IncomingMessage, data: string}>} A Promise that resolves with the response object and the body data as a string.
12+
* @throws {Error} Throws an error if the request cannot be completed
13+
*
14+
* @example
15+
* // Example usage for a GET request within an async function
16+
* async function getExample() {
17+
* try {
18+
* const { res, data } = await makeRequest('GET', 'https://example.com');
19+
* console.log('Status Code:', res.statusCode);
20+
* console.log('Body:', data);
21+
* } catch (error) {
22+
* console.error('Error:', error.message);
23+
* }
24+
* }
25+
* */
26+
async function makeRequest(method, url, options) {
27+
return new Promise((resolve, reject) => {
28+
// Ensure options is an object and set the method
29+
options = typeof options === 'object' ? options : {};
30+
options.method = method;
31+
32+
const req = https.request(url, options, res => {
33+
// Handle HTTP response stream
34+
let data = '';
35+
res.on('data', chunk => data += chunk);
36+
res.on('end', () => resolve({ res, data }));
37+
});
38+
39+
req.on('error', error => {
40+
console.error('Request error:', error);
41+
reject(error);
42+
});
43+
44+
// Handle POST/PUT data if provided
45+
if (options.data) {
46+
req.write(options.data);
47+
}
48+
49+
req.end();
50+
});
51+
}

test/contributors.test.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,24 @@ describe('contibutors.js', function() {
77

88
/** GitHub contrbutors test --START-- */
99

10+
describe.skip('#getAllRepos('+contributorsFixture.VALID_REPO_OWNER+');', async function() {
11+
it('should return the repos owned by '+contributorsFixture.VALID_REPO_OWNER, async function() {
12+
this.timeout(100000);
13+
let repos = await contributorsLib.getAllRepos(contributorsFixture.VALID_REPO_OWNER);
14+
assert.isNotNull(repos);
15+
expect(repos).to.be.an('array', 'Not an array')
16+
expect(repos.length).to.be.greaterThanOrEqual(contributorsFixture.REPO_COUNT_MIN);
17+
expect(repos[0]).to.include.all.keys('id', 'name', 'full_name', 'owner', 'private', 'html_url');
18+
})
19+
})
20+
1021
describe.skip('#getRepoContributors('+contributorsFixture.VALID_REPO+');', async function() {
1122
it('should return the repo contribuors', async function() {
1223
this.timeout(100000);
1324
let contributors = await contributorsLib.getRepoContributors(contributorsFixture.VALID_REPO)
1425
assert.isNotNull(contributors);
1526
expect(contributors).to.be.an('array', 'Not an array')
16-
expect(contributors.length).to.be.greaterThanOrEqual(contributorsFixture.REPO_CONTRIBUTOR_COUNT);
27+
expect(contributors.length).to.be.greaterThanOrEqual(contributorsFixture.REPO_CONTRIBUTOR_COUNT_MIN);
1728
expect(contributors[0]).to.include.all.keys('login','id','node_id','avatar_url','gravatar_id','url','html_url','followers_url','following_url','gists_url','starred_url','subscriptions_url','organizations_url','repos_url','events_url','received_events_url','type','site_admin','contributions');
1829
})
1930
})
@@ -24,7 +35,7 @@ describe('contibutors.js', function() {
2435
let contributors = await contributorsLib.getAllContributors(contributorsFixture.VALID_REPO_OWNER);
2536
assert.isNotNull(contributors);
2637
expect(contributors).to.be.an('array', 'Not an array')
27-
expect(contributors.length).to.be.greaterThanOrEqual(contributorsFixture.ALL_REPO_CONTRIBUTOR_COUNT);
38+
expect(contributors.length).to.be.greaterThanOrEqual(contributorsFixture.ALL_REPO_CONTRIBUTOR_COUNT_MIN);
2839
expect(contributors[0]).to.include.all.keys('login','id','node_id','avatar_url','gravatar_id','url','html_url','followers_url','following_url','gists_url','starred_url','subscriptions_url','organizations_url','repos_url','events_url','received_events_url','type','site_admin','contributions');
2940
})
3041
})

test/fixtures/contributors.fixture.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
exports.VALID_REPO_OWNER = "Git-Commit-Show";
22
exports.VALID_REPO = "Git-Commit-Show/landing-page";
3-
exports.REPO_CONTRIBUTOR_COUNT = 10;
4-
exports.ALL_REPO_CONTRIBUTOR_COUNT = 49;
3+
exports.REPO_COUNT_MIN = 10;
4+
exports.REPO_CONTRIBUTOR_COUNT_MIN = 10;
5+
exports.ALL_REPO_CONTRIBUTOR_COUNT_MIN = 49;
56
exports.VALID_CONTRIBUTOR_SAMPLE = {
67
login: "thenerdsuperuser",
78
id: 11832723,

0 commit comments

Comments
 (0)