1 | |
2 |
|
3 | async function get(auth: RT.Jira, path: string) { |
4 | const response = await fetch(`https://${auth.domain}.atlassian.net${path}`, { |
5 | headers: { |
6 | Authorization: `Basic ${btoa(`${auth.username}:${auth.password}`)}`, |
7 | Accept: "application/json", |
8 | }, |
9 | }) |
10 | if (!response.ok) { |
11 | throw new Error(`${response.status} ${await response.text()}`) |
12 | } |
13 | return await response.json() |
14 | } |
15 |
|
16 | export type DynSelect_project_id = string |
17 |
|
18 | |
19 | export async function project_id(auth: RT.Jira) { |
20 | const { values } = await get( |
21 | auth, |
22 | "/rest/api/3/project/search?maxResults=100" |
23 | ) |
24 | return values.map((p: { id: string; key: string; name: string }) => ({ |
25 | value: p.id, |
26 | label: `${p.name} (${p.key})`, |
27 | })) |
28 | } |
29 |
|
30 | export type DynSelect_issue_type_id = string |
31 |
|
32 | |
33 | export async function issue_type_id(auth: RT.Jira, project_id: string) { |
34 | if (!project_id) return [] |
35 | const types = await get( |
36 | auth, |
37 | `/rest/api/3/issuetype/project?projectId=${project_id}` |
38 | ) |
39 | return types.map((t: { id: string; name: string }) => ({ |
40 | value: t.id, |
41 | label: t.name, |
42 | })) |
43 | } |
44 |
|
45 | |
46 | function adf(text: string) { |
47 | return { |
48 | type: "doc", |
49 | version: 1, |
50 | content: text.split("\n").map((line) => ({ |
51 | type: "paragraph", |
52 | content: line ? [{ type: "text", text: line }] : [], |
53 | })), |
54 | } |
55 | } |
56 |
|
57 | |
58 | * Create Issue |
59 | * Create an issue in a project. The description is plain text (converted to Atlassian Document Format, one paragraph per line); set any other field through `fields`, keyed by field ID, e.g. `{ "labels": ["bug"], "priority": { "name": "High" }, "assignee": { "accountId": "..." }, "parent": { "key": "PROJ-1" } }`. |
60 | */ |
61 | export async function main( |
62 | auth: RT.Jira, |
63 | project_id: DynSelect_project_id, |
64 | issue_type_id: DynSelect_issue_type_id, |
65 | summary: string, |
66 | description: string | undefined, |
67 | fields: { [key: string]: any } | undefined, |
68 | update: { [key: string]: any } | undefined |
69 | ) { |
70 | const url = new URL(`https://${auth.domain}.atlassian.net/rest/api/3/issue`) |
71 |
|
72 | const body: { [key: string]: any } = { |
73 | fields: { |
74 | ...fields, |
75 | project: { id: project_id }, |
76 | issuetype: { id: issue_type_id }, |
77 | summary, |
78 | }, |
79 | } |
80 | if (description != null && description !== "") { |
81 | body.fields.description = adf(description) |
82 | } |
83 | if (update && Object.keys(update).length) { |
84 | body.update = update |
85 | } |
86 |
|
87 | const response = await fetch(url, { |
88 | method: "POST", |
89 | headers: { |
90 | Authorization: `Basic ${btoa(`${auth.username}:${auth.password}`)}`, |
91 | "Content-Type": "application/json", |
92 | Accept: "application/json", |
93 | }, |
94 | body: JSON.stringify(body), |
95 | }) |
96 |
|
97 | if (!response.ok) { |
98 | throw new Error(`${response.status} ${await response.text()}`) |
99 | } |
100 |
|
101 | return await response.json() |
102 | } |
103 |
|