Split out integrations, add code section comments
This commit is contained in:
parent
33cefac88e
commit
5259b56e53
188
index.js
188
index.js
@ -31,6 +31,15 @@ const ipfsConfig = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
module.exports = async function(robot) {
|
module.exports = async function(robot) {
|
||||||
|
|
||||||
|
function messageRoom(message) {
|
||||||
|
robot.messageRoom(process.env.KREDITS_ROOM, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Ethereum wallet setup
|
||||||
|
//
|
||||||
|
|
||||||
let wallet;
|
let wallet;
|
||||||
try {
|
try {
|
||||||
wallet = await ethers.Wallet.fromEncryptedWallet(walletJson, process.env.KREDITS_WALLET_PASSWORD);
|
wallet = await ethers.Wallet.fromEncryptedWallet(walletJson, process.env.KREDITS_WALLET_PASSWORD);
|
||||||
@ -39,10 +48,18 @@ module.exports = async function(robot) {
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Ethereum provider/node setup
|
||||||
|
//
|
||||||
|
|
||||||
const ethProvider = new ethers.providers.JsonRpcProvider(providerUrl, {chainId: networkId});
|
const ethProvider = new ethers.providers.JsonRpcProvider(providerUrl, {chainId: networkId});
|
||||||
ethProvider.signer = wallet;
|
ethProvider.signer = wallet;
|
||||||
wallet.provider = ethProvider;
|
wallet.provider = ethProvider;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Kredits contracts setup
|
||||||
|
//
|
||||||
|
|
||||||
let kredits;
|
let kredits;
|
||||||
try {
|
try {
|
||||||
kredits = await Kredits.setup(ethProvider, wallet, ipfsConfig);
|
kredits = await Kredits.setup(ethProvider, wallet, ipfsConfig);
|
||||||
@ -53,12 +70,12 @@ module.exports = async function(robot) {
|
|||||||
const Contributor = kredits.Contributor;
|
const Contributor = kredits.Contributor;
|
||||||
const Operator = kredits.Operator;
|
const Operator = kredits.Operator;
|
||||||
|
|
||||||
function messageRoom(message) {
|
|
||||||
robot.messageRoom(process.env.KREDITS_ROOM, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
robot.logger.info('[hubot-kredits] Wallet address: ' + wallet.address);
|
robot.logger.info('[hubot-kredits] Wallet address: ' + wallet.address);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check robot's wallet balance and alert when it's broke
|
||||||
|
//
|
||||||
|
|
||||||
ethProvider.getBalance(wallet.address).then(balance => {
|
ethProvider.getBalance(wallet.address).then(balance => {
|
||||||
robot.logger.info('[hubot-kredits] Wallet balance: ' + ethers.utils.formatEther(balance) + 'ETH');
|
robot.logger.info('[hubot-kredits] Wallet balance: ' + ethers.utils.formatEther(balance) + 'ETH');
|
||||||
if (balance.lt(ethers.utils.parseEther('0.0001'))) {
|
if (balance.lt(ethers.utils.parseEther('0.0001'))) {
|
||||||
@ -66,6 +83,10 @@ module.exports = async function(robot) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//
|
||||||
|
// Robot chat commands/interaction
|
||||||
|
//
|
||||||
|
|
||||||
robot.respond(/got ETH\??/i, res => {
|
robot.respond(/got ETH\??/i, res => {
|
||||||
ethProvider.getBalance(wallet.address).then((balance) => {
|
ethProvider.getBalance(wallet.address).then((balance) => {
|
||||||
res.send(`my wallet contains ${ethers.utils.formatEther(balance)} ETH`);
|
res.send(`my wallet contains ${ethers.utils.formatEther(balance)} ETH`);
|
||||||
@ -93,156 +114,9 @@ module.exports = async function(robot) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function getContributorByGithubUser(username) {
|
//
|
||||||
return Contributor.all().then(contributors => {
|
// Smart contract events
|
||||||
let contrib = contributors.find(c => {
|
//
|
||||||
return c.github_username === username;
|
|
||||||
});
|
|
||||||
if (!contrib) {
|
|
||||||
throw new Error(`No contributor found for ${username}`);A
|
|
||||||
} else {
|
|
||||||
return contrib;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function createProposal(githubUser, amount, description, url, details) {
|
|
||||||
return getContributorByGithubUser(githubUser).then((contributor) => {
|
|
||||||
robot.logger.debug(`[kredits] Creating proposal to issue ${amount}₭S to ${githubUser} for ${url}...`);
|
|
||||||
let contributionAttr = {
|
|
||||||
contributorId: contributor.id,
|
|
||||||
amount: amount,
|
|
||||||
contributorIpfsHash: contributor.ipfsHash,
|
|
||||||
url,
|
|
||||||
description,
|
|
||||||
details,
|
|
||||||
kind: 'dev'
|
|
||||||
};
|
|
||||||
return Operator.addProposal(contributionAttr).then((result) => {
|
|
||||||
robot.logger.debug('[kredits] proposal created:', util.inspect(result));
|
|
||||||
});
|
|
||||||
}).catch((error) => {
|
|
||||||
console.log([hubot-kredits] Error:, error);
|
|
||||||
messageRoom(`I wanted to propose giving kredits to ${githubUser} for ${url}, but I can't find their contact data. Please add them as a contributor: https://kredits.kosmos.org`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function amountFromIssueLabels(issue) {
|
|
||||||
let kreditsLabel = issue.labels.map(l => l.name)
|
|
||||||
.filter(n => n.match(/^kredits/))[0];
|
|
||||||
// No label, no kredits
|
|
||||||
if (typeof kreditsLabel === 'undefined') { return 0; }
|
|
||||||
|
|
||||||
// TODO move to config maybe?
|
|
||||||
let amount;
|
|
||||||
switch(kreditsLabel) {
|
|
||||||
case 'kredits-1':
|
|
||||||
amount = 50;
|
|
||||||
break;
|
|
||||||
case 'kredits-2':
|
|
||||||
amount = 150;
|
|
||||||
break;
|
|
||||||
case 'kredits-3':
|
|
||||||
amount = 500;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleGitHubIssueClosed(data) {
|
|
||||||
let recipients;
|
|
||||||
let issue = data.issue;
|
|
||||||
let assignees = issue.assignees.map(a => a.login);
|
|
||||||
let web_url = issue.html_url;
|
|
||||||
|
|
||||||
let amount = amountFromIssueLabels(issue);
|
|
||||||
if (amount === 0) {
|
|
||||||
console.log('[hubot-kredits] Proposal amount from issue label is zero; ignoring');
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (assignees.length > 0) {
|
|
||||||
recipients = assignees;
|
|
||||||
} else {
|
|
||||||
recipients = [issue.user.login];
|
|
||||||
}
|
|
||||||
|
|
||||||
let repoName = issue.repository_url.match(/.*\/(.+\/.+)$/)[1];
|
|
||||||
let description = `${repoName}: ${issue.title}`;
|
|
||||||
|
|
||||||
let proposalPromisses = [];
|
|
||||||
recipients.forEach(recipient => {
|
|
||||||
proposalPromisses.push(
|
|
||||||
createProposal(recipient, amount, description, web_url, issue)
|
|
||||||
.catch(err => robot.logger.error(err))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
return Promise.all(proposalPromisses);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleGitHubPullRequestClosed(data) {
|
|
||||||
let recipients;
|
|
||||||
let pull_request = data.pull_request;
|
|
||||||
let assignees = pull_request.assignees.map(a => a.login);
|
|
||||||
let web_url = pull_request._links.html.href;
|
|
||||||
let pr_issue_url = pull_request.issue_url;
|
|
||||||
|
|
||||||
if (assignees.length > 0) {
|
|
||||||
recipients = assignees;
|
|
||||||
} else {
|
|
||||||
recipients = [pull_request.user.login];
|
|
||||||
}
|
|
||||||
|
|
||||||
return fetch(pr_issue_url)
|
|
||||||
.then(response => {
|
|
||||||
if (response.status >= 400) {
|
|
||||||
throw new Error('Bad response from fetching PR issue');
|
|
||||||
}
|
|
||||||
return response.json();
|
|
||||||
})
|
|
||||||
.then(issue => {
|
|
||||||
let amount = amountFromIssueLabels(issue);
|
|
||||||
if (amount === 0) {
|
|
||||||
console.log('[hubot-kredits] Proposal amount from issue label is zero; ignoring');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let repoName = pull_request.base.repo.full_name;
|
|
||||||
let description = `${repoName}: ${pull_request.title}`;
|
|
||||||
|
|
||||||
let proposalPromisses = [];
|
|
||||||
recipients.forEach(recipient => {
|
|
||||||
console.debug(`[hubot-kredits] Creating proposal for ${recipient}...`);
|
|
||||||
proposalPromisses.push(
|
|
||||||
createProposal(recipient, amount, description, web_url, pull_request)
|
|
||||||
.catch(err => robot.logger.error(err))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
return Promise.all(proposalPromisses);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
robot.router.post('/incoming/kredits/github/'+process.env.KREDITS_WEBHOOK_TOKEN, (req, res) => {
|
|
||||||
let evt = req.header('X-GitHub-Event');
|
|
||||||
let data = req.body;
|
|
||||||
// For some reason data is contained in a payload property on one
|
|
||||||
// machine, but directly in the root of the object on others
|
|
||||||
if (data.payload) { data = JSON.parse(data.payload); }
|
|
||||||
|
|
||||||
robot.logger.info(`Received GitHub hook. Event: ${evt}, action: ${data.action}`);
|
|
||||||
|
|
||||||
if (evt === 'pull_request' && data.action === 'closed') {
|
|
||||||
handleGitHubPullRequestClosed(data).then(() => res.send(200));
|
|
||||||
}
|
|
||||||
else if (evt === 'issues' && data.action === 'closed') {
|
|
||||||
handleGitHubIssueClosed(data).then(() => res.send(200));
|
|
||||||
} else {
|
|
||||||
res.send(200);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function watchContractEvents() {
|
function watchContractEvents() {
|
||||||
ethProvider.getBlockNumber().then((blockNumber) => {
|
ethProvider.getBlockNumber().then((blockNumber) => {
|
||||||
@ -267,4 +141,10 @@ module.exports = async function(robot) {
|
|||||||
|
|
||||||
watchContractEvents();
|
watchContractEvents();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Integrations
|
||||||
|
//
|
||||||
|
|
||||||
|
require('integrations/github')(robot, kredits);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
153
integrations/github.js
Normal file
153
integrations/github.js
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
module.exports = async function(robot, kredits) {
|
||||||
|
|
||||||
|
function getContributorByGithubUser(username) {
|
||||||
|
return Contributor.all().then(contributors => {
|
||||||
|
let contrib = contributors.find(c => {
|
||||||
|
return c.github_username === username;
|
||||||
|
});
|
||||||
|
if (!contrib) {
|
||||||
|
throw new Error(`No contributor found for ${username}`);A
|
||||||
|
} else {
|
||||||
|
return contrib;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function createProposal(githubUser, amount, description, url, details) {
|
||||||
|
return getContributorByGithubUser(githubUser).then((contributor) => {
|
||||||
|
robot.logger.debug(`[kredits] Creating proposal to issue ${amount}₭S to ${githubUser} for ${url}...`);
|
||||||
|
let contributionAttr = {
|
||||||
|
contributorId: contributor.id,
|
||||||
|
amount: amount,
|
||||||
|
contributorIpfsHash: contributor.ipfsHash,
|
||||||
|
url,
|
||||||
|
description,
|
||||||
|
details,
|
||||||
|
kind: 'dev'
|
||||||
|
};
|
||||||
|
return Operator.addProposal(contributionAttr).then((result) => {
|
||||||
|
robot.logger.debug('[kredits] proposal created:', util.inspect(result));
|
||||||
|
});
|
||||||
|
}).catch((error) => {
|
||||||
|
console.log([hubot-kredits] Error:, error);
|
||||||
|
messageRoom(`I wanted to propose giving kredits to ${githubUser} for ${url}, but I can't find their contact data. Please add them as a contributor: https://kredits.kosmos.org`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function amountFromIssueLabels(issue) {
|
||||||
|
let kreditsLabel = issue.labels.map(l => l.name)
|
||||||
|
.filter(n => n.match(/^kredits/))[0];
|
||||||
|
// No label, no kredits
|
||||||
|
if (typeof kreditsLabel === 'undefined') { return 0; }
|
||||||
|
|
||||||
|
// TODO move to config maybe?
|
||||||
|
let amount;
|
||||||
|
switch(kreditsLabel) {
|
||||||
|
case 'kredits-1':
|
||||||
|
amount = 50;
|
||||||
|
break;
|
||||||
|
case 'kredits-2':
|
||||||
|
amount = 150;
|
||||||
|
break;
|
||||||
|
case 'kredits-3':
|
||||||
|
amount = 500;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleGitHubIssueClosed(data) {
|
||||||
|
let recipients;
|
||||||
|
let issue = data.issue;
|
||||||
|
let assignees = issue.assignees.map(a => a.login);
|
||||||
|
let web_url = issue.html_url;
|
||||||
|
|
||||||
|
let amount = amountFromIssueLabels(issue);
|
||||||
|
if (amount === 0) {
|
||||||
|
console.log('[hubot-kredits] Proposal amount from issue label is zero; ignoring');
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (assignees.length > 0) {
|
||||||
|
recipients = assignees;
|
||||||
|
} else {
|
||||||
|
recipients = [issue.user.login];
|
||||||
|
}
|
||||||
|
|
||||||
|
let repoName = issue.repository_url.match(/.*\/(.+\/.+)$/)[1];
|
||||||
|
let description = `${repoName}: ${issue.title}`;
|
||||||
|
|
||||||
|
let proposalPromisses = [];
|
||||||
|
recipients.forEach(recipient => {
|
||||||
|
proposalPromisses.push(
|
||||||
|
createProposal(recipient, amount, description, web_url, issue)
|
||||||
|
.catch(err => robot.logger.error(err))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(proposalPromisses);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleGitHubPullRequestClosed(data) {
|
||||||
|
let recipients;
|
||||||
|
let pull_request = data.pull_request;
|
||||||
|
let assignees = pull_request.assignees.map(a => a.login);
|
||||||
|
let web_url = pull_request._links.html.href;
|
||||||
|
let pr_issue_url = pull_request.issue_url;
|
||||||
|
|
||||||
|
if (assignees.length > 0) {
|
||||||
|
recipients = assignees;
|
||||||
|
} else {
|
||||||
|
recipients = [pull_request.user.login];
|
||||||
|
}
|
||||||
|
|
||||||
|
return fetch(pr_issue_url)
|
||||||
|
.then(response => {
|
||||||
|
if (response.status >= 400) {
|
||||||
|
throw new Error('Bad response from fetching PR issue');
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(issue => {
|
||||||
|
let amount = amountFromIssueLabels(issue);
|
||||||
|
if (amount === 0) {
|
||||||
|
console.log('[hubot-kredits] Proposal amount from issue label is zero; ignoring');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let repoName = pull_request.base.repo.full_name;
|
||||||
|
let description = `${repoName}: ${pull_request.title}`;
|
||||||
|
|
||||||
|
let proposalPromisses = [];
|
||||||
|
recipients.forEach(recipient => {
|
||||||
|
console.debug(`[hubot-kredits] Creating proposal for ${recipient}...`);
|
||||||
|
proposalPromisses.push(
|
||||||
|
createProposal(recipient, amount, description, web_url, pull_request)
|
||||||
|
.catch(err => robot.logger.error(err))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return Promise.all(proposalPromisses);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
robot.router.post('/incoming/kredits/github/'+process.env.KREDITS_WEBHOOK_TOKEN, (req, res) => {
|
||||||
|
let evt = req.header('X-GitHub-Event');
|
||||||
|
let data = req.body;
|
||||||
|
// For some reason data is contained in a payload property on one
|
||||||
|
// machine, but directly in the root of the object on others
|
||||||
|
if (data.payload) { data = JSON.parse(data.payload); }
|
||||||
|
|
||||||
|
robot.logger.info(`Received GitHub hook. Event: ${evt}, action: ${data.action}`);
|
||||||
|
|
||||||
|
if (evt === 'pull_request' && data.action === 'closed') {
|
||||||
|
handleGitHubPullRequestClosed(data).then(() => res.send(200));
|
||||||
|
}
|
||||||
|
else if (evt === 'issues' && data.action === 'closed') {
|
||||||
|
handleGitHubIssueClosed(data).then(() => res.send(200));
|
||||||
|
} else {
|
||||||
|
res.send(200);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user