From d2a0c0ae83224f071053ce05d06fe03566cf48cb Mon Sep 17 00:00:00 2001 From: Garret Alfert Date: Wed, 30 Dec 2020 19:02:40 +0100 Subject: [PATCH] Fetch reviews for Github PRs --- .env.example | 1 + index.js | 4 ++ lib/github-reviews.js | 94 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 lib/github-reviews.js diff --git a/.env.example b/.env.example index 8e324f3..8a6fe92 100644 --- a/.env.example +++ b/.env.example @@ -1 +1,2 @@ GITEA_TOKEN=your-token-here +GITHUB_TOKEN=your-token-here \ No newline at end of file diff --git a/index.js b/index.js index 0ab2883..2f94917 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,6 @@ require('dotenv').config() const GiteaReviews = require('./lib/gitea-reviews'); +const GithubReviews = require('./lib/github-reviews'); const kreditsAmounts = { 'kredits-1': 100, @@ -19,6 +20,9 @@ giteaReviews.getReviewContributions(repos.gitea, startDate, endDate).then(review console.log('GITEA REVIEW CONTRIBUTIONS', reviewContributions); }); +const githubReviews = new GithubReviews(process.env.GITHUB_TOKEN, kreditsAmounts); +githubReviews.getReviewContributions(repos.github, startDate, endDate).then(reviewContributions => { + console.log('GITHUB REVIEW CONTRIBUTIONS', reviewContributions); }); diff --git a/lib/github-reviews.js b/lib/github-reviews.js new file mode 100644 index 0000000..708bb6f --- /dev/null +++ b/lib/github-reviews.js @@ -0,0 +1,94 @@ +const axios = require('axios'); + +module.exports = class GithubReviews { + + client = null; + kreditsAmounts = null; + pageLimit = 100; + + constructor (token, kreditsAmounts) { + this.kreditsAmounts = kreditsAmounts; + + this.client = axios.create({ + baseURL: 'https://api.github.com', + headers: { + 'Accept': 'application/vnd.github.v3+json', + 'User-Agent': 'Kosmos Kredits for reviews', + 'Authorization': `token ${token}` + } + }); + } + + async getReviewContributions (repos, startDate, endDate) { + let pulls = []; + let reviewContributions = {} + + await Promise.all(repos.map(async (repo) => { + let page = 1; + let result; + + do { + try { + result = await this.client.get(`/repos/${repo}/pulls?state=closed&perPage=${this.pageLimit}&page=${page}`); + } catch(error) { + console.log(`failed to fetch PRs for repo ${repo}:`, error.message); + continue; + } + + if (!result || !result.data || result.data.length === 0) { + continue; + } + + let pullRequests = result.data.filter(pr => { + if (!pr.merged_at) return false; // only interested in merged PRs + + // check if the PR has been merged in the given timeframe + const mergeDate = new Date(pr.merged_at); + if (mergeDate < startDate || mergeDate > endDate) return false; + + // check if the PR has a kredits label + return pr.labels.some(label => label.name.match(/kredits-[123]/)); + }); + + await Promise.all(pullRequests.map(async (pr) => { + let reviews; + try { + reviews = await this.client.get(`/repos/${repo}/pulls/${pr.number}/reviews`); + } catch(error) { + console.log(`failed to fetch reviews for repo ${repo}, PR ${pr.number}:`, error.message); + return; + } + + if (!reviews || !reviews.data || reviews.data.length === 0) { + return; + } + + reviews = reviews.data.filter(review => { + return ['APPROVED', 'REJECTED'].includes(review.state); + }); + + reviews.forEach(review => { + if (typeof reviewContributions[review.user.login] === 'undefined') { + reviewContributions[review.user.login] = []; + } + + let kreditsLabel = pr.labels.find(label => label.name.match(/kredits-[123]/)); + + reviewContributions[review.user.login].push({ + pr, + prNumber: pr.number, + review, + reviewState: review.state, + kredits: this.kreditsAmounts[kreditsLabel.name] + }); + }); + })); + + page++; + } while (result && result.data && result.data.length > 0); + })); + + return reviewContributions; + } + +}