0

Update Project Item Status

by
Published today

Set the Status of a project item (issue, pull request or draft issue). status is the Status option id. Classic tokens and OAuth connections need the project scope.

Script github Verified

The script

Submitted by hugo989 Typescript (fetch-only)
Verified 1 hour ago
1
//native
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
// Dropdown of the owner's projects; fill owner first.
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
export type DynSelect_item_id = string
54

55
// Dropdown of the project's items.
56
export async function item_id(
57
  auth: RT.Github,
58
  owner: string,
59
  project_number: string
60
) {
61
  if (!auth?.token || !owner || !project_number) return []
62
  const data = await graphql(
63
    auth,
64
    `
65
      query ($owner: String!, $number: Int!) {
66
        repositoryOwner(login: $owner) {
67
          ... on ProjectV2Owner {
68
            projectV2(number: $number) {
69
              items(first: 100) {
70
                nodes {
71
                  id
72
                  content {
73
                    ... on Issue {
74
                      number
75
                      title
76
                    }
77
                    ... on PullRequest {
78
                      number
79
                      title
80
                    }
81
                    ... on DraftIssue {
82
                      title
83
                    }
84
                  }
85
                }
86
              }
87
            }
88
          }
89
        }
90
      }
91
    `,
92
    { owner, number: Number(project_number) }
93
  )
94
  return (data.repositoryOwner?.projectV2?.items.nodes ?? []).map((i: any) => ({
95
    value: i.id,
96
    label: i.content?.number
97
      ? `#${i.content.number} ${i.content.title}`
98
      : (i.content?.title ?? i.id),
99
  }))
100
}
101

102
export type DynSelect_status = string
103

104
// Dropdown of the project's Status options.
105
export async function status(
106
  auth: RT.Github,
107
  owner: string,
108
  project_number: string
109
) {
110
  if (!auth?.token || !owner || !project_number) return []
111
  const data = await graphql(
112
    auth,
113
    `
114
      query ($owner: String!, $number: Int!) {
115
        repositoryOwner(login: $owner) {
116
          ... on ProjectV2Owner {
117
            projectV2(number: $number) {
118
              field(name: "Status") {
119
                ... on ProjectV2SingleSelectField {
120
                  options {
121
                    id
122
                    name
123
                  }
124
                }
125
              }
126
            }
127
          }
128
        }
129
      }
130
    `,
131
    { owner, number: Number(project_number) }
132
  )
133
  return (data.repositoryOwner?.projectV2?.field?.options ?? []).map(
134
    (o: any) => ({
135
      value: o.id,
136
      label: o.name,
137
    })
138
  )
139
}
140

141
/**
142
 * Update Project Item Status
143
 * Set the Status of a project item (issue, pull request or draft issue). status is the Status option id. Classic tokens and OAuth connections need the project scope.
144
 */
145
export async function main(
146
  auth: RT.Github,
147
  owner: string,
148
  project_number: DynSelect_project_number,
149
  item_id: DynSelect_item_id,
150
  status: DynSelect_status
151
) {
152
  const data = await graphql(
153
    auth,
154
    `
155
      query ($owner: String!, $number: Int!) {
156
        repositoryOwner(login: $owner) {
157
          ... on ProjectV2Owner {
158
            projectV2(number: $number) {
159
              id
160
              field(name: "Status") {
161
                ... on ProjectV2SingleSelectField {
162
                  id
163
                }
164
              }
165
            }
166
          }
167
        }
168
      }
169
    `,
170
    { owner, number: Number(project_number) }
171
  )
172
  const project = data.repositoryOwner?.projectV2
173
  if (!project?.field)
174
    throw new Error(`Project ${project_number} has no Status field`)
175

176
  const result = await graphql(
177
    auth,
178
    `
179
      mutation (
180
        $projectId: ID!
181
        $itemId: ID!
182
        $fieldId: ID!
183
        $optionId: String!
184
      ) {
185
        updateProjectV2ItemFieldValue(
186
          input: {
187
            projectId: $projectId
188
            itemId: $itemId
189
            fieldId: $fieldId
190
            value: { singleSelectOptionId: $optionId }
191
          }
192
        ) {
193
          projectV2Item {
194
            id
195
          }
196
        }
197
      }
198
    `,
199
    {
200
      projectId: project.id,
201
      itemId: item_id,
202
      fieldId: project.field.id,
203
      optionId: status,
204
    }
205
  )
206
  return result.updateProjectV2ItemFieldValue.projectV2Item
207
}
208