Add Gitea integration #31
19
README.md
19
README.md
@ -47,6 +47,25 @@ Point a GitHub organization webhook to the following URL:
|
|||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `KREDITS_GITHUB_REPO_BLACKLIST` | Repos which you do not want to issue kredits for. Format: `orgname/reponame`, e.g. `67P/test-one-two` |
|
| `KREDITS_GITHUB_REPO_BLACKLIST` | Repos which you do not want to issue kredits for. Format: `orgname/reponame`, e.g. `67P/test-one-two` |
|
||||||
|
|
||||||
|
### Gitea
|
||||||
|
|
||||||
|
The Gitea integration will watch for closed issues and merged pull requests,
|
||||||
|
which carry a kredits label: `kredits-1`, `kredits-2`, `kredits-3` for small,
|
||||||
|
medium and large contributions. If there are multiple people assigned, it will
|
||||||
|
issue contribution tokens for all of them.
|
||||||
|
|
||||||
|
#### Setup
|
||||||
|
|
||||||
|
Point a Gitea organization webhook to the following URL:
|
||||||
|
|
||||||
|
https://your-hubot.example.com/incoming/kredits/gitea/{webhook_token}
|
||||||
|
|
||||||
|
#### Config
|
||||||
|
|
||||||
|
| Key | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| `KREDITS_GITEA_REPO_BLACKLIST` | Repos which you do not want to issue kredits for. Format: `orgname/reponame`, e.g. `kosmos/test-one-two` |
|
||||||
|
|
||||||
### MediaWiki
|
### MediaWiki
|
||||||
|
|
||||||
The MediaWiki integration will periodically check for wiki page creations and
|
The MediaWiki integration will periodically check for wiki page creations and
|
||||||
|
1
index.js
1
index.js
@ -149,6 +149,7 @@ module.exports = async function(robot) {
|
|||||||
//
|
//
|
||||||
|
|
||||||
require('./integrations/github')(robot, kredits);
|
require('./integrations/github')(robot, kredits);
|
||||||
|
require('./integrations/gitea')(robot, kredits);
|
||||||
|
|
||||||
if (typeof process.env.KREDITS_MEDIAWIKI_URL !== 'undefined') {
|
if (typeof process.env.KREDITS_MEDIAWIKI_URL !== 'undefined') {
|
||||||
require('./integrations/mediawiki')(robot, kredits);
|
require('./integrations/mediawiki')(robot, kredits);
|
||||||
|
179
integrations/gitea.js
Normal file
179
integrations/gitea.js
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
const util = require('util');
|
||||||
|
const fetch = require('node-fetch');
|
||||||
|
|
||||||
|
function sleep(ms) {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = async function(robot, kredits) {
|
||||||
|
|
||||||
|
function messageRoom(message) {
|
||||||
|
robot.messageRoom(process.env.KREDITS_ROOM, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
robot.logger.debug('[hubot-kredits] Loading Gitea integration...');
|
||||||
|
|
||||||
|
let repoBlackList = [];
|
||||||
|
if (process.env.KREDITS_GITEA_REPO_BLACKLIST) {
|
||||||
|
repoBlackList = process.env.KREDITS_GITEA_REPO_BLACKLIST.split(',');
|
||||||
|
robot.logger.debug('[hubot-kredits] Ignoring Gitea actions from ', util.inspect(repoBlackList));
|
||||||
|
}
|
||||||
|
|
||||||
|
const Contributor = kredits.Contributor;
|
||||||
|
const Contribution = kredits.Contribution;
|
||||||
|
|
||||||
|
function getContributorByGiteaUser(username) {
|
||||||
|
return Contributor.all().then(contributors => {
|
||||||
|
const contrib = contributors.find(c => {
|
||||||
|
return c.gitea_username === username;
|
||||||
|
});
|
||||||
|
|||||||
|
if (!contrib) {
|
||||||
|
throw new Error(`No contributor found for ${username}`);
|
||||||
|
} else {
|
||||||
|
return contrib;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function createContribution(giteaUser, date, time, amount, description, url, details) {
|
||||||
|
return getContributorByGiteaUser(giteaUser).then(contributor => {
|
||||||
|
robot.logger.debug(`[hubot-kredits] Creating contribution token for ${amount}₭S to ${giteaUser} for ${url}...`);
|
||||||
|
|
||||||
|
const contributionAttr = {
|
||||||
|
contributorId: contributor.id,
|
||||||
|
contributorIpfsHash: contributor.ipfsHash,
|
||||||
|
date,
|
||||||
|
time,
|
||||||
|
amount,
|
||||||
|
url,
|
||||||
|
description,
|
||||||
|
details,
|
||||||
|
kind: 'dev'
|
||||||
|
};
|
||||||
|
|
||||||
|
return Contribution.addContribution(contributionAttr).catch(error => {
|
||||||
|
robot.logger.error(`[hubot-kredits] Error:`, error);
|
||||||
|
messageRoom(`I tried to add a contribution for ${giteaUser} for ${url}, but I encountered an error when submitting the tx:`);
|
||||||
|
messageRoom(error.message);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function amountFromLabels(labels) {
|
||||||
|
const kreditsLabel = 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 = 500;
|
||||||
|
break;
|
||||||
|
case 'kredits-2':
|
||||||
|
amount = 1500;
|
||||||
|
break;
|
||||||
|
case 'kredits-3':
|
||||||
|
amount = 5000;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleGiteaIssueClosed(data) {
|
||||||
|
const issue = data.issue;
|
||||||
|
const repoName = data.repository.full_name;
|
||||||
|
const web_url = `${data.repository.html_url}/issues/${issue.id}`;
|
||||||
|
const description = `${repoName}: ${issue.title}`;
|
||||||
|
const amount = amountFromLabels(issue.labels);
|
||||||
|
const assignees = issue.assignees ? issue.assignees.map(a => a.login) : [];
|
||||||
|
[ date, time ] = issue.closed_at.split('T');
|
||||||
|
|
||||||
|
if (amount === 0) {
|
||||||
|
robot.logger.info('[hubot-kredits] Kredits amount from issue label is zero; ignoring');
|
||||||
|
return Promise.resolve();
|
||||||
|
} else if (repoBlackList.includes(repoName)) {
|
||||||
|
robot.logger.debug(`[hubot-kredits] ${repoName} is on black list; ignoring`);
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
let recipients;
|
||||||
|
if (assignees.length > 0) {
|
||||||
|
recipients = assignees;
|
||||||
|
} else {
|
||||||
|
recipients = [issue.user.login];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const recipient of recipients) {
|
||||||
|
try {
|
||||||
|
await createContribution(recipient, date, time, amount, description, web_url,
|
||||||
|
{ issue, repository: data.repository });
|
||||||
|
await sleep(60000);
|
||||||
|
}
|
||||||
|
catch (err) { robot.logger.error(err); }
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleGiteaPullRequestClosed(data) {
|
||||||
|
const pull_request = data.pull_request;
|
||||||
|
const repoName = data.repository.full_name;
|
||||||
|
const web_url = pull_request.html_url;
|
||||||
|
const description = `${repoName}: ${pull_request.title}`;
|
||||||
|
const amount = amountFromLabels(pull_request.labels);
|
||||||
|
const assignees = pull_request.assignees ? pull_request.assignees.map(a => a.login) : [];
|
||||||
|
[ date, time ] = pull_request.merged_at.split('T');
|
||||||
|
|
||||||
|
if (amount === 0) {
|
||||||
|
robot.logger.info('[hubot-kredits] Kredits amount from issue label is zero; ignoring');
|
||||||
|
return Promise.resolve();
|
||||||
|
} else if (repoBlackList.includes(repoName)) {
|
||||||
|
robot.logger.debug(`[hubot-kredits] ${repoName} is on black list; ignoring`);
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
let recipients;
|
||||||
|
if (assignees.length > 0) {
|
||||||
|
recipients = assignees;
|
||||||
|
} else {
|
||||||
|
recipients = [pull_request.user.login];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (const recipient of recipients) {
|
||||||
|
try {
|
||||||
|
await createContribution(recipient, date, time, amount, description, web_url,
|
||||||
|
{ pull_request, repository: data.repository });
|
||||||
|
await sleep(60000);
|
||||||
|
}
|
||||||
|
catch (err) { robot.logger.error(err); }
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
robot.router.post('/incoming/kredits/gitea/'+process.env.KREDITS_WEBHOOK_TOKEN, (req, res) => {
|
||||||
|
const evt = req.header('X-Gitea-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 Gitea hook. Event: ${evt}, action: ${data.action}`);
|
||||||
|
|
||||||
|
if (evt === 'pull_request' && data.action === 'closed' && data.pull_request.merged) {
|
||||||
|
handleGiteaPullRequestClosed(data);
|
||||||
|
res.sendStatus(200);
|
||||||
|
}
|
||||||
|
else if (evt === 'issues' && data.action === 'closed') {
|
||||||
|
handleGiteaIssueClosed(data);
|
||||||
|
res.sendStatus(200);
|
||||||
|
} else {
|
||||||
|
res.sendStatus(200);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
18
package-lock.json
generated
18
package-lock.json
generated
@ -1175,14 +1175,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"kredits-contracts": {
|
"kredits-contracts": {
|
||||||
"version": "5.1.1",
|
"version": "5.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/kredits-contracts/-/kredits-contracts-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/kredits-contracts/-/kredits-contracts-5.3.0.tgz",
|
||||||
"integrity": "sha512-hEM/ZOcoYejOix8LMG/mMVQVoD/9q18yjQTXeQwuX2x/APP95CH8HK/UsPIqxXtMP1L3XklWnMuqTVbYUc5UYg==",
|
"integrity": "sha512-Wz4zuA6yo0Q4WbVEO61fvFin+6VTNjkBqHPhHCqq6dIoGdFSjUZ3BCKan1ei0axIAda7ZDP+eebe2vCr+eqcHg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"ethers": "^4.0.27",
|
"ethers": "^4.0.27",
|
||||||
"ipfs-http-client": "^30.1.1",
|
"ipfs-http-client": "^30.1.1",
|
||||||
"kosmos-schemas": "^2.0.0",
|
"kosmos-schemas": "^2.0.0",
|
||||||
"rsvp": "^4.8.2",
|
|
||||||
"tv4": "^1.3.0"
|
"tv4": "^1.3.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -1364,9 +1363,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"multicodec": {
|
"multicodec": {
|
||||||
"version": "0.5.0",
|
"version": "0.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/multicodec/-/multicodec-0.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/multicodec/-/multicodec-0.5.1.tgz",
|
||||||
"integrity": "sha512-lKsJeT4cKeSq0rVEWhO3oSBgDN4sMY1sNZKlvl68g/ZAahjPS1KIVyF4IqhuYmCdtOyKs4Q4hQ6M0C3iqRnuqQ==",
|
"integrity": "sha512-Q5glyZLdXVbbBxvRYHLQHpu8ydVf1422Z+v9fU47v2JCkiue7n+JcFS7uRv0cQW8hbVtgdtIDgYWPWaIKEXuXA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"varint": "^5.0.0"
|
"varint": "^5.0.0"
|
||||||
}
|
}
|
||||||
@ -1732,11 +1731,6 @@
|
|||||||
"optimist": "~0.3.5"
|
"optimist": "~0.3.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rsvp": {
|
|
||||||
"version": "4.8.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.4.tgz",
|
|
||||||
"integrity": "sha512-6FomvYPfs+Jy9TfXmBpBuMWNH94SgCsZmJKcanySzgNNP6LjWxBvyLTa9KaMfDDM5oxRfrKDB0r/qeRsLwnBfA=="
|
|
||||||
},
|
|
||||||
"safe-buffer": {
|
"safe-buffer": {
|
||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
"ethers": "^4.0.27",
|
"ethers": "^4.0.27",
|
||||||
"group-array": "^0.3.3",
|
"group-array": "^0.3.3",
|
||||||
"kosmos-schemas": "^1.1.2",
|
"kosmos-schemas": "^1.1.2",
|
||||||
"kredits-contracts": "^5.1.1",
|
"kredits-contracts": "^5.3.0",
|
||||||
"node-cron": "^2.0.3",
|
"node-cron": "^2.0.3",
|
||||||
"node-fetch": "^2.3.0",
|
"node-fetch": "^2.3.0",
|
||||||
"prompt": "^1.0.0"
|
"prompt": "^1.0.0"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user
there are contract methods for that: https://github.com/67P/kredits-contracts/blob/master/lib/contracts/contributor.js#L20-L38
should be something like:
Contributor.findByAccount({gitea_username: username, site: 'gitea something})
This is copied from the GitHub integration code, so I won't refactor things for this functionality now. Can do that for all integrations after we're not losing Gitea kredits anymore.
ok, maybe we should make an issue to not forget it. also that we don't use
gitea_username
here but theaccouts
array/hash somehow.