-
Notifications
You must be signed in to change notification settings - Fork 1
/
github.ts
124 lines (118 loc) · 4.66 KB
/
github.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
const { Octokit } = require("@octokit/rest");
const fs = require('fs');
const owner = 'damccorm';
const repo = 'test-migration-target';
const stateDir = `./repo-state/${owner}/${repo}`;
const stateFile = `${stateDir}/alreadyCreated.txt`;
export class GhIssue {
public Title: string;
public Labels: Set<string>;
public Description: string;
public State: string;
public Milestone: string;
public Assignee: string;
public JiraReferenceId: string;
public Children: GhIssue[];
constructor() {
this.Title = '';
this.Labels = new Set();
this.Description = "";
this.State = "open";
this.Milestone = "";
this.Assignee = "";
this.JiraReferenceId = "";
this.Children = [];
}
}
function sleep(seconds: number): Promise<null> {
const ms = seconds * 1000;
return new Promise(resolve => setTimeout(resolve, ms));
}
async function commentWithSubtasks(issueNumber: number, client: any, childNumbers: number[], retry: number = 0) {
try {
let resp = await client.rest.issues.createComment({
owner: owner,
repo: repo,
issue_number: issueNumber,
body: `The following subtask(s) are associated with this issue:${childNumbers.map(n => ` #${n}`).join(',')}`,
});
if (resp.status == 403) {
const backoffSeconds= 60*(2**(retry));
console.log(`Getting rate limited. Sleeping ${backoffSeconds} seconds`);
await sleep(backoffSeconds);
console.log("Trying again");
await commentWithSubtasks(issueNumber, client, childNumbers, retry+1);
} else if (resp.status > 210) {
throw new Error(`Failed to comment on issue with status code: ${resp.status}. Full response: ${resp}`);
}
} catch (ex) {
console.log(`Failed to comment on issue with error: ${ex}`);
const backoffSeconds= 60*(2**(retry));
console.log(`Sleeping ${backoffSeconds} seconds before retrying`);
await sleep(backoffSeconds);
console.log("Trying again");
await commentWithSubtasks(issueNumber, client, childNumbers, retry+1);
}
}
async function createIssue(issue: GhIssue, client: any, retry: number = 0, parent: number = -1): Promise<number> {
let description = issue.Description;
if (parent != -1) {
description += `\nSubtask of issue #${parent}`;
}
let assignees: string[] = [];
if (issue.Assignee) {
assignees.push(issue.Assignee);
}
try {
let resp = await client.rest.issues.create({
owner: owner,
repo: repo,
assignees: assignees,
title: issue.Title,
body: description,
labels: Array.from(issue.Labels)
});
if (resp.status == 403) {
const backoffSeconds= 60*(2**(retry));
console.log(`Getting rate limited. Sleeping ${backoffSeconds} seconds`);
await sleep(backoffSeconds);
console.log("Trying again");
return await createIssue(issue, client, retry+1, parent);
} else if (resp.status < 210) {
console.log(`Created issue: ${resp.data.title}`);
let issueNumbers: number[] = []
for (const child of issue.Children) {
issueNumbers.push(await createIssue(child, client, 0, resp.data.number));
}
if (issueNumbers.length > 0) {
await commentWithSubtasks(resp.data.number, client, issueNumbers, 0);
}
return resp.data.number;
} else {
throw new Error(`Failed to create issue: ${resp.data.title} with status code: ${resp.status}. Full response: ${resp}`);
}
} catch (ex) {
console.log(`Failed to create issue with error: ${ex}`);
const backoffSeconds= 60*(2**(retry));
console.log(`Sleeping ${backoffSeconds} seconds before retrying`);
await sleep(backoffSeconds);
console.log("Trying again");
return await createIssue(issue, client, retry+1, parent);
}
}
export async function createIssues(issues: GhIssue[], githubToken: string) {
const client = new Octokit({auth: githubToken});
let alreadyCreated: string[] = [];
if (fs.existsSync(stateFile)) {
alreadyCreated = fs.readFileSync(stateFile, {encoding:'utf8'}).split(',');
} else {
fs.mkdirSync(stateDir, { recursive: true });
}
for (const issue of issues) {
if (alreadyCreated.indexOf(issue.JiraReferenceId) < 0) {
await createIssue(issue, client);
alreadyCreated.push(issue.JiraReferenceId);
fs.writeFileSync(stateFile, alreadyCreated.join(','));
}
}
}