121 lines
3.6 KiB
JavaScript
121 lines
3.6 KiB
JavaScript
// <bitbar.title>Github Pull requests</bitbar.title>
|
|
// <bitbar.version>v2.0</bitbar.version>
|
|
// <bitbar.author>Noam Knispel</bitbar.author>
|
|
// <bitbar.author.github>noamknispel</bitbar.author.github>
|
|
// <bitbar.desc>Get list of pull requests from Github for multiple repositories</bitbar.desc>
|
|
// <bitbar.dependencies>node.js request co bluebird</bitbar.dependencies>
|
|
|
|
import nodeFetch, { FetchError } from 'node-fetch';
|
|
|
|
const GITHUB_API = 'https://api.github.com';
|
|
|
|
// make fetch sane
|
|
const fetch = async (...args) => {
|
|
const res = await nodeFetch(...args);
|
|
if (res.ok) return res;
|
|
throw new FetchError(`Unsuccessful Request (${args[0]}) [${res.status}]`);
|
|
};
|
|
|
|
const api = ({ username, token }) => {
|
|
const getPull = async (repo, id) =>
|
|
fetch(`${GITHUB_API}/repos/${repo}/pulls/${id}`, {
|
|
method: 'GET',
|
|
headers: {
|
|
Authorization: `Basic ${Buffer.from(`${username}:${token}`).toString('base64')}`,
|
|
},
|
|
}).then(res => res.json());
|
|
|
|
return {
|
|
getPulls: async repo => {
|
|
const issues = await fetch(
|
|
`${GITHUB_API}/repos/${repo}/issues?state=open&sort=updated&creator=w33ble`,
|
|
{
|
|
method: 'GET',
|
|
headers: {
|
|
Authorization: `Basic ${Buffer.from(`${username}:${token}`).toString('base64')}`,
|
|
},
|
|
}
|
|
).then(res => res.json());
|
|
|
|
// remove non-pull issues
|
|
const pulls = issues.filter(issue => !!issue.pull_request);
|
|
|
|
// return actual pull info
|
|
return Promise.all(pulls.map(pull => getPull(repo, pull.number)));
|
|
},
|
|
|
|
getStatus: async (repo, sha) =>
|
|
fetch(`${GITHUB_API}/repos/${repo}/commits/${sha}/status`, {
|
|
method: 'GET',
|
|
headers: {
|
|
Authorization: `Basic ${Buffer.from(`${username}:${token}`).toString('base64')}`,
|
|
},
|
|
}).then(res => res.json()),
|
|
};
|
|
};
|
|
|
|
const getStatusColor = status => {
|
|
if (status === 'failure') return ' color=#aa0000';
|
|
if (status === 'success') return ' color=#00aa00';
|
|
if (status === 'pending') return ' color=#aaaa00';
|
|
return '';
|
|
};
|
|
|
|
export default async ({ username, token, repos = [] }) => {
|
|
const { getPulls, getStatus } = api({ username, token });
|
|
|
|
let failed = false;
|
|
const tasks = await (() => {
|
|
try {
|
|
return Promise.all(
|
|
repos.map(async repo => {
|
|
// fetch pulls for repo
|
|
const pulls = await getPulls(repo);
|
|
|
|
// fetch status for each pull
|
|
return Promise.all(
|
|
pulls.map(async pull => {
|
|
const status = await getStatus(repo, pull.head.sha);
|
|
return { repo, pull, status };
|
|
})
|
|
);
|
|
}, [])
|
|
);
|
|
} catch (err) {
|
|
console.log(`Request failed: ${err.message}`);
|
|
failed = true;
|
|
return false;
|
|
}
|
|
})();
|
|
|
|
if (failed) return false;
|
|
|
|
const { totalCount, failCount, strings } = tasks.reduce(
|
|
(acc, info) => {
|
|
// skip repo if there are no matches
|
|
if (info.length <= 0) return acc;
|
|
|
|
// build bitbar output
|
|
info.forEach(({ repo, pull, status }, i) => {
|
|
// append repo name
|
|
if (i === 0) acc.strings.push(`${repo} | color=#0000ff`);
|
|
|
|
// append information about each PR
|
|
acc.strings.push(
|
|
`#${pull.number} ${pull.title} | href=${pull.html_url} ${getStatusColor(status.state)}`
|
|
);
|
|
|
|
// add count to tally
|
|
acc.totalCount += 1;
|
|
if (status.state === 'failure') acc.failCount += 1;
|
|
});
|
|
return acc;
|
|
},
|
|
{ totalCount: 0, failCount: 0, strings: ['---'] }
|
|
);
|
|
|
|
strings.unshift(`${totalCount}/${failCount} PRs`);
|
|
strings.forEach(s => console.log(s));
|
|
return true;
|
|
};
|