diff --git a/README.md b/README.md index bf14bbd..59e9785 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,54 @@ # open-community-kit Tools and stats for open-source communities +# Installation + +``` +npm install -g open-community-kit +``` + +You can use npx as well if you just want to test a CLI command + # Usage ## Create a leaderboard of github contributors for all the repos of a user/org (Contributor with highest # of contributions at the top) -Run `node contributors.js` from your terminal +### Using CLI + +Run `open-community-kit yourGithubOrgName` from your terminal + +Note: You can also use the shorthand `ock` in place of `open-commmunity-kit` i.e. + +``` +ock yourGitHubOrgName +``` This will -* Fetch data from Github APIs and prepare a leaderboard of all the contributors to (default "Git-Commit-Show" org) the user or org you mention in REPO_OWNER variable inside `contributors.js` +* Fetch data from Github APIs and prepare a leaderboard of all the contributors to public repositories of your GitHub organization/user accout * Save the leaderboard in a csv file in the same folder -You will hit the API limits soon. To increase API limits, add GITHUB_PERSONAL_TOKEN in `contributors.js` +You will hit the API limits soon. **To increase API limits**, add [`GITHUB_PERSONAL_TOKEN`](https://github.com/settings/tokens) as well in the arguments i.e. + +``` +ock yourGitHubOrgName yourGitHubPersonalToken +``` + +### Using code + +```javascript +const OCK = require('open-community-kit').OCK; +OCK.contributors.github.archive('your_github_org_or_username', + { GITHUB_PERSONAL_TOKEN: 'your_gh_personal_token_optional' +}); +``` + +## Settings for repeated usage + +If you are going to use this command frequently, you might not want to set organization name and personal token again and again. Instead, you can set following environment variables and then you don't need to pass those variables as CLI arguments or function parameters + +``` +# Set these variables in the environment to avoid repeatedly specifying these variables +1. REPO_OWNER +2. GITHUB_PERSONAL_TOKEN +``` \ No newline at end of file diff --git a/cli.js b/cli.js new file mode 100755 index 0000000..5182057 --- /dev/null +++ b/cli.js @@ -0,0 +1,14 @@ +#!/usr/bin/env node + +const OCK = require('./index').OCK; + +let mainCommand = process.argv[1]; +console.log("Running "+mainCommand+"..."); +let REPO_OWNER = process.argv[2]; +let GITHUB_PERSONAL_TOKEN = process.argv[3]; + +let options = {}; +if(GITHUB_PERSONAL_TOKEN){ + options.GITHUB_PERSONAL_TOKEN = GITHUB_PERSONAL_TOKEN; +} +OCK.contributors.github.archive(REPO_OWNER, options); \ No newline at end of file diff --git a/contributors.js b/contributors.js index a80f01d..643e2fa 100644 --- a/contributors.js +++ b/contributors.js @@ -3,12 +3,14 @@ * @example To archive contributors leaderboard data in csv file, run `node contributors.js` */ +exports.archiveContributorsLeaderboard = archiveContributorsLeaderboard + const https = require('https'); -// INPUTS -// Mandatory: Repo owner that you want to analyze +// Configurations (Optional) +// Repo owner that you want to analyze const REPO_OWNER = process.env.REPO_OWNER; -// Optional: Authentication using github token. When used, it will increase the API limits from 60 to 5000/hr +// Authentication using github token. When used, it will increase the API limits from 60 to 5000/hr const GITHUB_PERSONAL_TOKEN = process.env.GITHUB_PERSONAL_TOKEN; // END OF INPUTS @@ -25,12 +27,16 @@ if(GITHUB_PERSONAL_TOKEN){ /** * Get all github repos of an owner(user/org) - * @param {String} owner - * @param {Number} pageNo + * @param {string} owner The organization or user name on GitHub + * @param {Object} options Additional options e.g. { pageNo: 1 } * @returns Promise | String> JSON array of data on success, error on failure * @example getAllRepos('myorghandle').then((repos) => console.log(repos)).catch((err) => console.log(err)) */ -async function getAllRepos(owner, pageNo = 1) { +async function getAllRepos(owner=REPO_OWNER, options) { + let pageNo = (options && options.pageNo) ? options.pageNo : 1; + if(options && options.GITHUB_PERSONAL_TOKEN){ + GITHUB_REQUEST_OPTIONS.headers["Authorization"] = "token "+options.GITHUB_PERSONAL_TOKEN; + } return new Promise((resolve, reject) => { let url = `https://api.github.com/orgs/${owner}/repos?per_page=100&page=${pageNo}`; console.log(url); @@ -49,7 +55,7 @@ async function getAllRepos(owner, pageNo = 1) { //It might have more data on the next page pageNo++; try { - let dataFromNextPage = await getAllRepos(owner, pageNo); + let dataFromNextPage = await getAllRepos(owner, { pageNo: pageNo } ); dataJsonArray.push(...dataFromNextPage); } catch (err) { console.log("No more pagination needed") @@ -66,8 +72,8 @@ async function getAllRepos(owner, pageNo = 1) { /** * Get contributors for a Github repo - * @param {*} fullRepoName e.g. myorghandle/myreponame - * @param {*} pageNo + * @param {string} fullRepoName e.g. myorghandle/myreponame + * @param {number} pageNo * @returns Promise | String> * @example getRepoContributors('myorghandle/myreponame').then((contributors) => console.log(contributors)).catch((err) => console.log(err)) */ @@ -107,10 +113,11 @@ async function getRepoContributors(fullRepoName, pageNo = 1) { /** * Get all contributors across all the repos of an owner - * @param {*} owner github user or org handle + * @param {string} owner github user or org handle + * @param {Object} options Additional options */ -async function getAllContributors(owner) { - let repos = await getAllRepos(owner); +async function getAllContributors(owner=REPO_OWNER, options) { + let repos = await getAllRepos(owner, options); if (!repos || repos.length < 1) { console.log("Error in getting repos for " + owner) throw ("Error in getting repos for " + owner) @@ -149,7 +156,7 @@ async function getAllContributors(owner) { /** * Adds up all the contributions by a contributor to different repos - * @param {*} contributors + * @param {Array} contributors */ function aggregateAllContributors(contributors) { return contributors.reduce(function (grouped, currentItem) { @@ -185,6 +192,10 @@ function sortReposByContributionsCount(repoContributionMappingArray){ }) } +/** + * Writes all contributors data to a file + * @param {Array} contributors + */ function writeContributorLeaderboardToFile(contributors) { const fs = require('fs'); let ghContributorLeaderboard = contributors.map((contributor) => { @@ -201,10 +212,11 @@ function writeContributorLeaderboardToFile(contributors) { /** * Archives contributors leaderboard data sorted by contrbutions in a file - * @param {*} owner + * @param {string} owner The organization or user name on GitHub + * @param {Object} options Additional options */ -async function archiveContributorsLeaderboard(owner) { - let contributors = await getAllContributors(); +async function archiveContributorsLeaderboard(owner=REPO_OWNER, options) { + let contributors = await getAllContributors(owner, options); if (!contributors || contributors.length < 1) { console.log("Failed to get contributors for "+owner); return; @@ -218,6 +230,4 @@ async function archiveContributorsLeaderboard(owner) { writeContributorLeaderboardToFile(contributors); return ghHandles; -} - -archiveContributorsLeaderboard(REPO_OWNER) +} \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..2c7f3ea --- /dev/null +++ b/index.js @@ -0,0 +1,18 @@ +const contributorsLib = require('./contributors'); + +/** + * Bundling all APIs together + * @param {*} options + */ + +const OCK = { + contributors: { + github: { + archive: async function(owner, options){ + contributorsLib.archiveContributorsLeaderboard(owner, options) + } + } + } +} + +exports.OCK = OCK; \ No newline at end of file diff --git a/package.json b/package.json index d3c84e5..f63fa33 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,12 @@ { "name": "open-community-kit", - "version": "1.0.0", + "version": "1.1.0", "description": "Tools and stats for open-source communities", "main": "contributors.js", + "bin": { + "ock": "cli.js", + "open-community-kit": "cli.js" + }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" },