1 | |
2 |
|
3 | async function graphql(auth: RT.Github, query: string, variables: object) { |
4 | const response = await fetch("https://api.github.com/graphql", { |
5 | method: "POST", |
6 | headers: { |
7 | Authorization: `Bearer ${auth.token}`, |
8 | "Content-Type": "application/json", |
9 | Accept: "application/json", |
10 | }, |
11 | body: JSON.stringify({ query, variables }), |
12 | }) |
13 | if (!response.ok) { |
14 | throw new Error(`${response.status} ${await response.text()}`) |
15 | } |
16 | const { data, errors } = (await response.json()) as { |
17 | data: any |
18 | errors?: unknown[] |
19 | } |
20 | if (errors?.length) throw new Error(JSON.stringify(errors)) |
21 | return data |
22 | } |
23 |
|
24 | export type DynSelect_project_number = string |
25 |
|
26 | |
27 | export async function project_number(auth: RT.Github, owner: string) { |
28 | if (!auth?.token || !owner) return [] |
29 | const data = await graphql( |
30 | auth, |
31 | ` |
32 | query ($owner: String!) { |
33 | repositoryOwner(login: $owner) { |
34 | ... on ProjectV2Owner { |
35 | projectsV2(first: 100) { |
36 | nodes { |
37 | number |
38 | title |
39 | } |
40 | } |
41 | } |
42 | } |
43 | } |
44 | `, |
45 | { owner } |
46 | ) |
47 | return (data.repositoryOwner?.projectsV2?.nodes ?? []).map((p: any) => ({ |
48 | value: String(p.number), |
49 | label: `#${p.number} ${p.title}`, |
50 | })) |
51 | } |
52 |
|
53 | |
54 | * List Project Items |
55 | * List the items (issues, pull requests, draft issues) of a project with their Status. Paginate with after = pageInfo.endCursor. Classic tokens and OAuth connections need the read:project scope. |
56 | */ |
57 | export async function main( |
58 | auth: RT.Github, |
59 | owner: string, |
60 | project_number: DynSelect_project_number, |
61 | first: number = 50, |
62 | after: string | undefined |
63 | ) { |
64 | const data = await graphql( |
65 | auth, |
66 | ` |
67 | query ($owner: String!, $number: Int!, $first: Int!, $after: String) { |
68 | repositoryOwner(login: $owner) { |
69 | ... on ProjectV2Owner { |
70 | projectV2(number: $number) { |
71 | items(first: $first, after: $after) { |
72 | nodes { |
73 | id |
74 | type |
75 | isArchived |
76 | status: fieldValueByName(name: "Status") { |
77 | ... on ProjectV2ItemFieldSingleSelectValue { |
78 | name |
79 | optionId |
80 | } |
81 | } |
82 | content { |
83 | ... on Issue { |
84 | number |
85 | title |
86 | state |
87 | url |
88 | repository { |
89 | nameWithOwner |
90 | } |
91 | } |
92 | ... on PullRequest { |
93 | number |
94 | title |
95 | state |
96 | url |
97 | repository { |
98 | nameWithOwner |
99 | } |
100 | } |
101 | ... on DraftIssue { |
102 | title |
103 | } |
104 | } |
105 | } |
106 | pageInfo { |
107 | endCursor |
108 | hasNextPage |
109 | } |
110 | } |
111 | } |
112 | } |
113 | } |
114 | } |
115 | `, |
116 | { owner, number: Number(project_number), first, after: after || null } |
117 | ) |
118 | const project = data.repositoryOwner?.projectV2 |
119 | if (!project) |
120 | throw new Error(`Project ${project_number} not found for ${owner}`) |
121 | return project.items |
122 | } |
123 |
|