-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.ts
119 lines (102 loc) · 3.47 KB
/
index.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
import * as core from '@actions/core';
import * as github from '@actions/github';
import fetch from 'node-fetch';
interface IssueId {
id: string;
key: string;
}
// eg https://openstax.atlassian.net/rest/dev-status/1.0/issue/details?issueId=10066&applicationType=github&dataType=pullrequest
interface DevStatusResponse {
detail: Array<{
pullRequests?: Array<{
url: string
}>
}>;
}
interface IssuesResponse {
startAt: number;
maxResults: number;
total: number;
issues: IssueId[];
}
/*
* jira docs:
* https://developer.atlassian.com/cloud/jira/platform/rest/v2/api-group-issue-search/#api-rest-api-2-search-id-post
*
*
* creating a javascript github action:
* https://docs.github.com/en/actions/creating-actions/creating-a-javascript-action
*/
const doCheck = async() => {
const site = core.getInput('jira_site');
const project = core.getInput('jira_project');
const authEmail = core.getInput('jira_email');
const authToken = core.getInput('jira_token');
const payload = github.context.payload;
const prUrl = payload.pull_request.html_url;
const queryDevStatus = (issue: IssueId): Promise<DevStatusResponse> => {
return fetch(`https://${site}.atlassian.net/rest/dev-status/1.0/issue/details?issueId=${issue.id}&applicationType=github&dataType=pullrequest`, {
headers: {
'Authorization': `Basic ${Buffer.from(
`${authEmail}:${authToken}`
).toString('base64')}`,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
})
.then(response => response.json())
;
};
const queryIssueIds = (options: {startAt: number}): Promise<IssuesResponse> => {
const bodyData = JSON.stringify({
...options,
jql: `project = ${project} and resolution is empty and development[pullrequests].all > 0`,
fields: ['id'],
maxResults: 1000,
});
return fetch(`https://${site}.atlassian.net/rest/api/2/search`, {
method: 'POST',
headers: {
'Authorization': `Basic ${Buffer.from(
`${authEmail}:${authToken}`
).toString('base64')}`,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: bodyData
})
.then(response => response.json())
;
};
const loadAllIssueIds = async (previous: IssueId[] = []): Promise<IssueId[]> => {
const issuesResponse = await queryIssueIds({startAt: previous.length});
const newIssues = [...previous, ...issuesResponse.issues];
if (issuesResponse.issues.length < 1 || issuesResponse.total <= newIssues.length) {
return newIssues;
}
return loadAllIssueIds(newIssues);
};
const issueIds = await loadAllIssueIds();
const matchingIssueIds: IssueId[] = [];
for (const issue of issueIds) {
const devStatus = await queryDevStatus(issue);
if (devStatus.detail.some(integration => integration.pullRequests?.some(pr => pr.url === prUrl))) {
matchingIssueIds.push(issue);
}
}
if (matchingIssueIds.length < 1) {
throw new Error('no matching issues found');
}
console.dir(matchingIssueIds, {depth: null});
const matchingIssueIdsString = matchingIssueIds.map(i => i.key).join(',');
core.setOutput("issues", matchingIssueIdsString);
};
doCheck().catch(error => {
if (error.message === 'no matching issues found') {
return new Promise(resolve => setTimeout(resolve, 60000)).then(() => doCheck().catch(err => {
core.setFailed(err.message);
}));
} else {
core.setFailed(error.message);
}
});