Compare commits

...

2 Commits

Author SHA1 Message Date
97f24641e0 Properly copies issues over now (minus due date, lol) 2024-01-13 02:12:20 -05:00
d281200376 WIP send issue off to Jira 2024-01-13 01:31:39 -05:00
5 changed files with 172 additions and 20 deletions

View File

@ -1,9 +1,9 @@
{
"alan": "arocull@purdue.edu",
"Will": "montgow@purdue.edu",
"connor": "celswort@purdue.edu",
"shelby": "shockada@purdue.edu",
"tommy": "thochste@purdue.edu",
"matt": "mcschule@purdue.edu",
"patrick": "ryan227@purdue.edu"
"alan": "712020:fb70534b-d978-4df7-b54f-85f948202227",
"Will": "622aee8d49c900007023fccb",
"connor": "60d139e09469280070f87286",
"shelby": "712020:67143da0-4371-437d-a48f-e7400c89649c",
"tommy": "712020:63e73e0a-6680-4546-8034-4a4732b6b383",
"matt": "712020:02aa3220-cfc4-4027-9e67-52387f5fa227",
"patrick": "712020:a18c4048-38d2-48ac-a450-21defd4a005c"
}

View File

@ -5,24 +5,61 @@ import _ from 'lodash'
import express from 'express'
import fetch from 'node-fetch'
import Issue from './issue';
// Load configurations
import CONFIG from '../config/server.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
// 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 URL_GITEA = `${CONFIG['gitea']}/api/v1`;
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) => {
res.json().then((data) => {
console.log('Got data ');
console.log(data);
console.log(data.labels);
_.forEach(data, (ticket) => {
const issue = Issue.fromGitea(ticket, CONFIG['repository-default']);
database.push(issue);
// Now, search Jira issues to make sure this isn't already duplicated
const jiraIssueSearch = `project = "${SECRETS['jira-project']}" 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['key'];
})
})
} else {
console.log(`Issue "${issue.title_jira}" already existed, skipping`);
}
})
})
})
})
})

View File

@ -1,19 +1,108 @@
import _ from "lodash";
class Issue {
public id_gitea: number = -1;
public id_jira: number = -1;
constructor(
public title: String,
public desc: String,
public labels: String[],
public assignees: String[],
public dueDate: Date,
public open: boolean,
public repo: string,
public title: string,
protected desc: string = '',
protected labels: string[] = [],
protected reporter: string = '',
protected assignees: string[] = [],
protected open: boolean = true,
protected dueDate: string = '',
) {}
/**
* @summary Constructs an issue from a Gitea JSON struct
* @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['name'])
});
// 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, projectKey: 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]
},
"project": {
"key": projectKey
},
"issuetype": {
// If there is a bug inside the labels, count the issue as a bug, else it's a task
"name": this.labels.includes('Bug') ? 'Bug' : 'Task'
}
}
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};
}
public get title_jira(): string {
return `${this.repo.toUpperCase()}: ${this.title}`;
}
}

25
src/requests.ts Normal file
View File

@ -0,0 +1,25 @@
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: RequestInit = {
method: method,
headers: {
'Authorization': `Basic ${Buffer.from(OAUTH_JIRA).toString('base64')}`,
'Accept': 'application/json',
'Content-Type': 'application/json',
},
};
if (body !== null) {
options.body = JSON.stringify(body);
}
return fetch(`https://${SECRETS['jira-site']}.atlassian.net/rest/api/3/${protocol}`, <any>options);
}
export { jiraFetch };

View File

@ -68,6 +68,7 @@ const serverConfig = _.defaultsDeep(_.cloneDeep(commonConfig), {
if (ps !== null) {
console.log('Killing old process ...');
ps.kill();
startServer(); // Start a new process
} else {
startServer();
}