Skip to content

Commit

Permalink
refactor the request class
Browse files Browse the repository at this point in the history
  • Loading branch information
joyeecheung committed Nov 2, 2017
1 parent ebb6a60 commit f463deb
Show file tree
Hide file tree
Showing 6 changed files with 705 additions and 101 deletions.
14 changes: 6 additions & 8 deletions bin/metadata.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
'use strict';

const { EOL } = require('os');
const { request, requestAll } = require('../lib/request');
const requestPromise = require('request-promise-native');
const Request = require('../lib/request');
const auth = require('../lib/auth');

const loggerFactory = require('../lib/logger');
const PRData = require('../lib/pr_data');
Expand All @@ -17,10 +17,11 @@ const OWNER = process.argv[3] || 'nodejs';
const REPO = process.argv[4] || 'node';

async function main(prid, owner, repo, logger) {
const req = { request, requestAll, requestPromise };
const data = new PRData(prid, owner, repo, logger, req);
const credentials = await auth();
const request = new Request(credentials);

const data = new PRData(prid, owner, repo, logger, request);
await data.getAll();
data.analyzeReviewers();

const metadata = new MetadataGenerator(data).getMetadata();
const [SCISSOR_LEFT, SCISSOR_RIGHT] = MetadataGenerator.SCISSORS;
Expand All @@ -31,9 +32,6 @@ async function main(prid, owner, repo, logger) {
if (!process.stdout.isTTY) {
process.stdout.write(`${metadata}${EOL}`);
}
/**
* TODO: put all these data into one object with a class
*/
const checker = new PRChecker(logger, data);
checker.checkAll();
}
Expand Down
6 changes: 1 addition & 5 deletions lib/collaborators.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,9 @@ Collaborator.TYPES = {
TSC, COLLABORATOR
};

async function getCollaborators(requestPromise, logger, owner, repo) {
async function getCollaborators(readme, logger, owner, repo) {
// This is more or less taken from
// https://github.com/rvagg/iojs-tools/blob/master/pr-metadata/pr-metadata.js
const url = `https://raw.githubusercontent.com/${owner}/${repo}/master/README.md`;

const readme = await requestPromise({ url });

const members = new Map();
let m;

Expand Down
52 changes: 23 additions & 29 deletions lib/pr_data.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,30 @@
'use strict';

const fs = require('fs');
const path = require('path');

function loadQuery(file) {
const filePath = path.resolve(__dirname, '..', 'queries', `${file}.gql`);
return fs.readFileSync(filePath, 'utf8');
}

const PR_QUERY = loadQuery('PR');
const REVIEWS_QUERY = loadQuery('Reviews');
const COMMENTS_QUERY = loadQuery('PRComments');
const COMMITS_QUERY = loadQuery('PRCommits');
const USER_QUERY = loadQuery('User');

// TODO(joyeecheung): make it mockable with req.rp ?
const { getCollaborators } = require('../lib/collaborators');
const { ReviewAnalyzer } = require('../lib/reviews');

// queries/*.gql file names
const PR_QUERY = 'PR';
const REVIEWS_QUERY = 'Reviews';
const COMMENTS_QUERY = 'PRComments';
const COMMITS_QUERY = 'PRCommits';
const USER_QUERY = 'User';

class PRData {
/**
* @param {number} prid
* @param {string} owner
* @param {string} repo
* @param {Object} logger
* @param {Object} req
* @param {Object} request
*/
constructor(prid, owner, repo, logger, req) {
constructor(prid, owner, repo, logger, request) {
this.prid = prid;
this.owner = owner;
this.repo = repo;
this.logger = logger;
this.request = req.request;
this.requestAll = req.requestAll;
this.requestPromise = req.requestPromise;
this.request = request;

// Data
this.collaborators = new Map();
Expand All @@ -52,53 +43,56 @@ class PRData {
this.getComments(),
this.getCommits()
]);
this.analyzeReviewers();
}

analyzeReviewers() {
this.reviewers = new ReviewAnalyzer(this).getReviewers();
}

async getCollaborators() {
const { owner, repo, logger, requestPromise } = this;
const { owner, repo, logger, request } = this;
logger.trace(`Getting collaborator contacts from README of ${owner}/${repo}`);
this.collaborators = await getCollaborators(requestPromise, logger, owner, repo);
const url = `https://raw.githubusercontent.com/${owner}/${repo}/master/README.md`;
const readme = await request.promise({ url });
this.collaborators = await getCollaborators(readme, logger, owner, repo);
}

async getPR() {
const { prid, owner, repo, logger, request } = this;
logger.trace(`Getting PR from ${owner}/${repo}/pull/${prid}`);
const prData = await request(PR_QUERY, { prid, owner, repo });
const prData = await request.gql(PR_QUERY, { prid, owner, repo });
const pr = this.pr = prData.repository.pullRequest;
// Get the mail
logger.trace(`Getting User information for ${pr.author.login}`);
const userData = await request(USER_QUERY, { login: pr.author.login });
const userData = await request.gql(USER_QUERY, { login: pr.author.login });
const user = userData.user;
Object.assign(this.pr.author, user);
}

async getReviews() {
const { prid, owner, repo, logger, requestAll } = this;
const { prid, owner, repo, logger, request } = this;
const vars = { prid, owner, repo };
logger.trace(`Getting reviews from ${owner}/${repo}/pull/${prid}`);
this.reviews = await requestAll(REVIEWS_QUERY, vars, [
this.reviews = await request.gql(REVIEWS_QUERY, vars, [
'repository', 'pullRequest', 'reviews'
]);
}

async getComments() {
const { prid, owner, repo, logger, requestAll } = this;
const { prid, owner, repo, logger, request } = this;
const vars = { prid, owner, repo };
logger.trace(`Getting comments from ${owner}/${repo}/pull/${prid}`);
this.comments = await requestAll(COMMENTS_QUERY, vars, [
this.comments = await request.gql(COMMENTS_QUERY, vars, [
'repository', 'pullRequest', 'comments'
]);
}

async getCommits() {
const { prid, owner, repo, logger, requestAll } = this;
const { prid, owner, repo, logger, request } = this;
const vars = { prid, owner, repo };
logger.trace(`Getting commits from ${owner}/${repo}/pull/${prid}`);
this.commits = await requestAll(COMMITS_QUERY, vars, [
this.commits = await request.gql(COMMITS_QUERY, vars, [
'repository', 'pullRequest', 'commits'
]);
}
Expand Down
134 changes: 79 additions & 55 deletions lib/request.js
Original file line number Diff line number Diff line change
@@ -1,66 +1,90 @@
'use strict';

const rp = require('request-promise-native');
const auth = require('./auth');
const fs = require('fs');
const path = require('path');

async function request(query, variables) {
const options = {
uri: 'https://api.github.com/graphql',
method: 'POST',
headers: {
'Authorization': `Basic ${await auth()}`,
'User-Agent': 'node-check-pr'
},
json: true,
gzip: true,
body: {
query: query,
variables: variables
}
};
// console.log(options);
const result = await rp(options);
if (result.errors) {
const err = new Error('GraphQL request Error');
err.data = {
// query: query,
variables: variables,
errors: result.errors
};
throw err;
class Request {
constructor(credentials) {
this.credentials = credentials;
}
return result.data;
}

async function requestAll(query, variables, path) {
let after = null;
let all = [];
// first page
do {
const varWithPage = Object.assign({
after
}, variables);
const data = await request(query, varWithPage);
let current = data;
for (const step of path) {
current = current[step];
}
// current should have:
// totalCount
// pageInfo { hasNextPage, endCursor }
// nodes
all = all.concat(current.nodes);
if (current.pageInfo.hasNextPage) {
after = current.pageInfo.endCursor;
loadQuery(file) {
const filePath = path.resolve(__dirname, '..', 'queries', `${file}.gql`);
return fs.readFileSync(filePath, 'utf8');
}

async promise() {
return rp(...arguments);
}

async gql(name, variables, path) {
const query = this.loadQuery(name);
if (path) {
const result = await this.requestAll(query, variables, path);
return result;
} else {
after = null;
const result = await this.request(query, variables);
return result;
}
} while (after !== null);
}

return all;
async request(query, variables) {
const options = {
uri: 'https://api.github.com/graphql',
method: 'POST',
headers: {
'Authorization': `Basic ${this.credentials}`,
'User-Agent': 'node-core-utils'
},
json: true,
gzip: true,
body: {
query: query,
variables: variables
}
};
// console.log(options);
const result = await rp(options);
if (result.errors) {
const err = new Error('GraphQL request Error');
err.data = {
// query: query,
variables: variables,
errors: result.errors
};
throw err;
}
return result.data;
}

async requestAll(query, variables, path) {
let after = null;
let all = [];
// first page
do {
const varWithPage = Object.assign({
after
}, variables);
const data = await this.request(query, varWithPage);
let current = data;
for (const step of path) {
current = current[step];
}
// current should have:
// totalCount
// pageInfo { hasNextPage, endCursor }
// nodes
all = all.concat(current.nodes);
if (current.pageInfo.hasNextPage) {
after = current.pageInfo.endCursor;
} else {
after = null;
}
} while (after !== null);

return all;
}
}

module.exports = {
request,
requestAll
};
module.exports = Request;
Loading

0 comments on commit f463deb

Please sign in to comment.