WIP send issue off to Jira
This commit is contained in:
parent
baa2983231
commit
d281200376
@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"alan": "arocull@purdue.edu",
|
"alan": "712020:fb70534b-d978-4df7-b54f-85f948202227",
|
||||||
"Will": "montgow@purdue.edu",
|
"Will": "622aee8d49c900007023fccb",
|
||||||
"connor": "celswort@purdue.edu",
|
"connor": "60d139e09469280070f87286",
|
||||||
"shelby": "shockada@purdue.edu",
|
"shelby": "712020:67143da0-4371-437d-a48f-e7400c89649c",
|
||||||
"tommy": "thochste@purdue.edu",
|
"tommy": "712020:63e73e0a-6680-4546-8034-4a4732b6b383",
|
||||||
"matt": "mcschule@purdue.edu",
|
"matt": "712020:02aa3220-cfc4-4027-9e67-52387f5fa227",
|
||||||
"patrick": "ryan227@purdue.edu"
|
"patrick": "712020:a18c4048-38d2-48ac-a450-21defd4a005c"
|
||||||
}
|
}
|
51
src/index.ts
51
src/index.ts
@ -5,24 +5,63 @@ import _ from 'lodash'
|
|||||||
import express from 'express'
|
import express from 'express'
|
||||||
import fetch from 'node-fetch'
|
import fetch from 'node-fetch'
|
||||||
|
|
||||||
|
import Issue from './issue';
|
||||||
|
|
||||||
// Load configurations
|
// Load configurations
|
||||||
import CONFIG from '../config/server.json';
|
import CONFIG from '../config/server.json';
|
||||||
import SECRETS from '../config/secrets.json';
|
import SECRETS from '../config/secrets.json';
|
||||||
// import uGiteaToJira from '../config/user_remap.json';
|
import uGiteaToJira from '../config/user_remap.json';
|
||||||
|
import { jiraFetch } from './requests'
|
||||||
|
|
||||||
// BUILD OAUTH
|
// BUILD OAUTH
|
||||||
// const OAUTH_JIRA = `${SECRETS['jira-email']}:${SECRETS['jira-token']}`;
|
const OAUTH_JIRA = `${SECRETS['jira-email']}:${SECRETS['jira-token']}`;
|
||||||
const OAUTH_GITEA = `token=${SECRETS['gitea-token']}`;
|
const OAUTH_GITEA = `token=${SECRETS['gitea-token']}`;
|
||||||
|
|
||||||
const URL_GITEA = `${CONFIG['gitea']}/api/v1`;
|
const URL_GITEA = `${CONFIG['gitea']}/api/v1`;
|
||||||
|
|
||||||
const url = `${URL_GITEA}/repos/${CONFIG['repositories']['bot']}/issues?state=all&${OAUTH_GITEA}`
|
const url = `${URL_GITEA}/repos/${CONFIG['repositories']['bot']}/issues?state=all&${OAUTH_GITEA}`
|
||||||
|
|
||||||
console.log('Getting: ', url);
|
const database: Issue[] = [];
|
||||||
|
|
||||||
|
// Copy issues over from Gitea to Jira
|
||||||
fetch(url).then((res) => {
|
fetch(url).then((res) => {
|
||||||
res.json().then((data) => {
|
res.json().then((data) => {
|
||||||
console.log('Got data ');
|
_.forEach(data, (ticket) => {
|
||||||
console.log(data);
|
const issue = Issue.fromGitea(ticket, CONFIG['repository-default']);
|
||||||
console.log(data.labels);
|
database.push(issue);
|
||||||
|
|
||||||
|
console.log(issue);
|
||||||
|
|
||||||
|
console.log(issue.toJira(uGiteaToJira, SECRETS['jira-project']));
|
||||||
|
// Now, search Jira issues to make sure this isn't already duplicated
|
||||||
|
const jiraIssueSearch = `project = "AAA" and summary ~ "${issue.title_jira}"\nORDER BY created DESC`
|
||||||
|
|
||||||
|
jiraFetch(`issue/picker?currentJQL=${jiraIssueSearch}`, 'GET').then((jiraSearch) => {
|
||||||
|
jiraSearch.json().then((searchJSON) => {
|
||||||
|
let issueFound: any = null;
|
||||||
|
|
||||||
|
_.forEach(searchJSON['sections'], (searchSection) => {
|
||||||
|
const issueList: any[] = searchSection['issues']
|
||||||
|
if (issueList.length > 0) { // If any issues were found
|
||||||
|
issueFound = issueList[0]; // Select the first one (probably matches best)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// If the issue does not exist...
|
||||||
|
if (issueFound === null) {
|
||||||
|
// ...then create one!
|
||||||
|
console.log(`Issue "${issue.title_jira}" not found on Jira, creating one...`);
|
||||||
|
|
||||||
|
jiraFetch('issue', 'POST', issue.toJira(uGiteaToJira, SECRETS['jira-project'])).then((res) => {
|
||||||
|
res.json().then((createdIssue) => {
|
||||||
|
console.log(createdIssue);
|
||||||
|
issue.id_jira = createdIssue['id'];
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
99
src/issue.ts
99
src/issue.ts
@ -1,19 +1,104 @@
|
|||||||
|
import _ from "lodash";
|
||||||
|
|
||||||
class Issue {
|
class Issue {
|
||||||
|
public id_gitea: number = -1;
|
||||||
|
public id_jira: number = -1;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public title: String,
|
public repo: string,
|
||||||
public desc: String,
|
public title: string,
|
||||||
public labels: String[],
|
protected desc: string = '',
|
||||||
public assignees: String[],
|
protected labels: string[] = [],
|
||||||
public dueDate: Date,
|
protected reporter: string = '',
|
||||||
public open: boolean,
|
protected assignees: string[] = [],
|
||||||
|
protected open: boolean = true,
|
||||||
|
protected dueDate: string = '',
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @summary Constructs an issue from a Gitea JSON struct
|
||||||
* @param obj JSON Object
|
* @param obj JSON Object
|
||||||
*/
|
*/
|
||||||
public static fromGitea(obj: any) {
|
public static fromGitea(obj: any, repo: string): Issue {
|
||||||
|
const open = obj['open'] === 'open';
|
||||||
|
|
||||||
|
// Fetch labels
|
||||||
|
const labels: string[] = [];
|
||||||
|
|
||||||
|
_.forEach(obj['labels'], (label: any) => {
|
||||||
|
labels.push(label['id'])
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fetch assignees
|
||||||
|
const assignees: string[] = [];
|
||||||
|
_.forEach(obj['assignees'], (user: any) => {
|
||||||
|
assignees.push(user['login'])
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get due date, if there is one
|
||||||
|
let due: string = '';
|
||||||
|
if (obj['due_date'] !== null) {
|
||||||
|
due = obj['due_date'];
|
||||||
|
}
|
||||||
|
|
||||||
|
const issue = new Issue(
|
||||||
|
repo,
|
||||||
|
obj['title'],
|
||||||
|
obj['body'],
|
||||||
|
labels,
|
||||||
|
obj['user']['login'],
|
||||||
|
assignees,
|
||||||
|
open,
|
||||||
|
due,
|
||||||
|
)
|
||||||
|
issue.id_gitea = obj['id']
|
||||||
|
|
||||||
|
return issue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Converts this to a Jira JSoN object
|
||||||
|
* https://developer.atlassian.com/server/jira/platform/jira-rest-api-examples/#creating-an-issue-examples
|
||||||
|
*/
|
||||||
|
public toJira(remap: any, parent: string): any {
|
||||||
|
const obj: any = {
|
||||||
|
"labels": this.labels,
|
||||||
|
"summary": this.title_jira,
|
||||||
|
"description": {
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"text": `${this.desc}\n\nManaged by GiteaJiraBot`,
|
||||||
|
"type": "text"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "paragraph"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "doc",
|
||||||
|
"version": 1,
|
||||||
|
},
|
||||||
|
"reporter": {
|
||||||
|
"id": remap[this.reporter]
|
||||||
|
},
|
||||||
|
"parent": {
|
||||||
|
"key": parent
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.assignees.length > 0) {
|
||||||
|
obj['assignee'] = remap[this.assignees[0]];
|
||||||
|
}
|
||||||
|
if (this.dueDate !== '') {
|
||||||
|
obj['duedate'] = this.dueDate.slice(0, this.dueDate.indexOf('T'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return {"fields": obj, "update": {}};
|
||||||
|
}
|
||||||
|
|
||||||
|
public get title_jira(): string {
|
||||||
|
return `${this.repo.toUpperCase()}: ${this.title}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
24
src/requests.ts
Normal file
24
src/requests.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import fetch from 'node-fetch'
|
||||||
|
|
||||||
|
import SECRETS from '../config/secrets.json';
|
||||||
|
|
||||||
|
const OAUTH_JIRA = `${SECRETS['jira-email']}:${SECRETS['jira-token']}`;
|
||||||
|
const OAUTH_GITEA = `token=${SECRETS['gitea-token']}`;
|
||||||
|
|
||||||
|
function jiraFetch(protocol: string, method: string = 'POST', body: any = null) {
|
||||||
|
const options: any = {
|
||||||
|
method: method,
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Basic ${Buffer.from(OAUTH_JIRA).toString('base64')}`,
|
||||||
|
'Accept': 'application/json'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (body !== null) {
|
||||||
|
options['body'] = JSON.stringify(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fetch(`https://${SECRETS['jira-site']}.atlassian.net/rest/api/3/${protocol}`, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { jiraFetch };
|
@ -68,6 +68,7 @@ const serverConfig = _.defaultsDeep(_.cloneDeep(commonConfig), {
|
|||||||
if (ps !== null) {
|
if (ps !== null) {
|
||||||
console.log('Killing old process ...');
|
console.log('Killing old process ...');
|
||||||
ps.kill();
|
ps.kill();
|
||||||
|
startServer(); // Start a new process
|
||||||
} else {
|
} else {
|
||||||
startServer();
|
startServer();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user