Skip to content

Commit 7cbdb80

Browse files
committed
ci(label-actions): composit actions to add and delete labels in bulk
Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com>
1 parent 0818e70 commit 7cbdb80

File tree

4 files changed

+410
-0
lines changed

4 files changed

+410
-0
lines changed
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
name: Add Label(s)
2+
description: adds label(s) to labelable
3+
inputs:
4+
gh_token:
5+
description: gh api access token to use
6+
default: ${{ secrets.GITHUB_TOKEN }}
7+
repository:
8+
description: the OWNER/REPOSITORY to operate on
9+
default: ${{ github.repository }}
10+
issues:
11+
description: a single or comma separated list of issue numbers
12+
required: true
13+
labels:
14+
description: a single or comma separated list of labels to apply to all listed issues
15+
required: true
16+
colors:
17+
description: |
18+
A single or comma separated list of colors to create the labels with if needed.
19+
the list order is the same as `labels`. Missing or blank values (e.g. `FFFFFF,,FFFFFF`) use the `default-color`
20+
default-color:
21+
description: default color to create labels with
22+
default: "#D4C5F9"
23+
24+
runs:
25+
using: "composite"
26+
steps:
27+
- name: Collect Repo Labels
28+
id: collect_labels
29+
shell: bash
30+
env:
31+
GH_TOKEN: ${{ inputs.gh_token }}
32+
REPOSITORY: ${{ inputs.repository }}
33+
LABELS: ${{ inputs.labels }}
34+
COLORS: ${{ inputs.colors }}
35+
DEFAULT_COLOR: ${{ inputs.default-color }}
36+
run: |
37+
owner=$(echo "$REPOSITORY" | cut -d '/' -f 1)
38+
repo=$(echo "$REPOSITORY" | cut -d '/' -f 2)
39+
query=$(
40+
jq -nr \
41+
--arg labels "$LABELS" \
42+
'
43+
(reduce ($labels | split (", *"; null) | .[]) as $i ([]; . + [$i])) as $labels
44+
| "query ($owner: String!, $repo: String!) {\n" +
45+
" repository(owner: $owner, name: $repo) {\n" +
46+
" id\n" +
47+
(
48+
reduce $labels[] as $i ([0, ""]; [
49+
.[0] + 1,
50+
.[1] + (
51+
" _" + (.[0] | tostring) +
52+
": label(name: \"" + $i + "\") {\n" +
53+
" id\n" +
54+
" name\n"+
55+
" }\n"
56+
)
57+
])
58+
| .[1]
59+
)+
60+
" }\n" +
61+
"}"
62+
'
63+
)
64+
data=$(
65+
gh api graphql \
66+
-f owner="$owner" \
67+
-f repo="$repo" \
68+
-f query="$query" \
69+
| jq -c \
70+
--arg labels "$LABELS" \
71+
--arg colors "$COLORS" \
72+
--arg defaultColor "$DEFAULT_COLOR" \
73+
'
74+
. as $in
75+
| ($labels | split(", *"; null)) as $labels
76+
| ($colors | split(", *"; null)) as $colors
77+
| (
78+
reduce ( [$labels, $colors] | transpose)[] as $i (
79+
{};
80+
.[$i[0]] = (
81+
if ($i[1] and $i[1] != "") then
82+
$i[1]
83+
else
84+
$defaultColor
85+
end
86+
| if startswith("#") then .[1:] else . end
87+
)
88+
)
89+
) as $colorMap
90+
| (
91+
reduce (
92+
$in.data.repository[]
93+
| select( objects | .name as $name | any($labels[]; . == $name ) )
94+
) as $i ({}; .[$i.name] = {"id": $i.id})
95+
) as $found
96+
| (
97+
reduce (
98+
$labels[]
99+
| select( . as $name | $found | has($name) | not )
100+
) as $i ({}; .[$i] = {"color": $colorMap[$i]})
101+
) as $missing
102+
| {
103+
"repoId": $in.data.repository.id,
104+
"found": $found,
105+
"missing": $missing,
106+
}
107+
'
108+
)
109+
echo "found=$(jq -c '.found' <<< "$data")" >> "$GITHUB_OUTPUT"
110+
echo "missing=$(jq -c '.missing' <<< "$data")" >> "$GITHUB_OUTPUT"
111+
echo "repo_id=$(jq -r '.repoId' <<< "$data")" >> "$GITHUB_OUTPUT"
112+
113+
- name: Collect Item Node IDs
114+
id: collect_ids
115+
shell: bash
116+
env:
117+
GH_TOKEN: ${{ inputs.gh_token }}
118+
REPOSITORY: ${{ inputs.repository }}
119+
ISSUES: ${{ inputs.labels }}
120+
run: |
121+
owner=$(echo "$REPOSITORY" | cut -d '/' -f 1)
122+
repo=$(echo "$REPOSITORY" | cut -d '/' -f 2)
123+
query=$(
124+
jq -nr \
125+
--arg issues "$ISSUES" \
126+
'
127+
(reduce ($issues | split (", *"; null) | .[]) as $i ([]; . + [$i])) as $issues
128+
|
129+
"query ($owner: String!, $repo: String!) {\n" +
130+
" repository(owner: $owner, name: $repo) {\n" +
131+
(
132+
reduce $issues[] as $i ([0, ""]; [
133+
.[0] + 1,
134+
.[1] + (
135+
" _" + (.[0] | tostring) +
136+
": issueOrPullRequest(number: " + ($i | tostring) +") {\n" +
137+
" ... on Issue {\n" +
138+
" id\n" +
139+
" }\n" +
140+
" ... on PullRequest {\n"+
141+
" id\n"+
142+
" }\n" +
143+
" }\n"
144+
)
145+
])
146+
| .[1]
147+
)+
148+
" }\n" +
149+
"}"
150+
'
151+
)
152+
data=$(
153+
gh api graphql \
154+
-f owner="$owner" \
155+
-f repo="$repo" \
156+
-f query="$query" \
157+
| jq -c 'reduce .data.repository[].id as $i ([]; . + [$i])'
158+
)
159+
echo "issue_ids=$data" >> "$GITHUB_OUTPUT"
160+
161+
- name: Create Missing Labels
162+
id: create_missing
163+
shell: bash
164+
env:
165+
GH_TOKEN: ${{ inputs.gh_token }}
166+
REPO_ID: ${{ steps.collect_labels.outputs.repo_id }}
167+
LABELS: ${{ steps.collect_labels.outputs.labels }}
168+
MISSING: ${{ steps.collect_labels.outputs.missing }}
169+
run: |
170+
query=$(
171+
jq -nr \
172+
--argjson labels "$MISSING" \
173+
--arg repo "$REPO_ID" \
174+
'
175+
"mutation {\n" + (
176+
reduce ($labels | keys | .[] | [., $labels[.]]) as $i ([0, ""]; [
177+
.[0] + 1,
178+
.[1] + (
179+
" _" + (.[0] | tostring) +
180+
": createLabel(input: {repositoryId: \"" + $repo +
181+
"\", name: \"" + $i[0] +
182+
"\", color: \"" + $i[1].color +
183+
"\"}) {\n" +
184+
" clientMutationId\n" +
185+
" label {\n" +
186+
" id\n" +
187+
" name\n" +
188+
" color\n" +
189+
" }\n" +
190+
" }\n"
191+
)
192+
])
193+
| .[1]
194+
) +
195+
"}"
196+
'
197+
)
198+
data=$(
199+
gh api graphql -f query="$query" \
200+
| jq --argjson existing "$LABELS" \
201+
'
202+
reduce .data[].label as $i ({}; .[$i.name] = {"id": $i.id, "color": $i.color })
203+
| . + $existing
204+
'
205+
)
206+
lable_ids=$(jq -c '[.[].id]' <<< "$data")
207+
echo "label_ids=$lable_ids" >> "$GITHUB_OUTPUT"
208+
209+
- name: Apply Labels
210+
id: apply_labels
211+
shell: bash
212+
env:
213+
GH_TOKEN: ${{ inputs.gh_token }}
214+
ISSUES: ${{ steps.collect_ids.outputs.issue_ids }}
215+
LABELS: ${{ steps.create_missing.outputs.label_ids }}
216+
run: |
217+
query=$(
218+
jq -nr \
219+
--argjson labels "$LABELS" \
220+
--argjson issues "$ISSUES" \
221+
'
222+
"mutation {\n" + (
223+
reduce $issues[] as $i ([0, ""]; [
224+
.[0] + 1,
225+
.[1] + (
226+
" _" + (.[0] | tostring) +
227+
": addLabelsToLabelable(input: {labelableId: \"" +
228+
$i + "\", labelIds: " + ($labels | tojson) + "}) {\n" +
229+
" clientMutationId\n" +
230+
" }\n"
231+
)
232+
])
233+
| .[1]
234+
) +
235+
"}"
236+
'
237+
)
238+
gh api graphql -f query="$query"
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
name: Delete Label(s)
2+
description: delete Label(s)
3+
inputs:
4+
gh_token:
5+
description: gh api access token to use
6+
default: ${{ secrets.GITHUB_TOKEN }}
7+
repository:
8+
description: the OWNER/REPOSITORY to operate on
9+
default: ${{ github.repository }}
10+
labels:
11+
description: a single or comma separated list of labels to delete
12+
required: true
13+
14+
runs:
15+
using: "composite"
16+
steps:
17+
- name: Collect Repo Labels
18+
id: collect_labels
19+
shell: bash
20+
env:
21+
GH_TOKEN: ${{ inputs.gh_token }}
22+
REPOSITORY: ${{ inputs.repository }}
23+
LABELS: ${{ inputs.labels }}
24+
run: |
25+
owner=$(echo "$REPOSITORY" | cut -d '/' -f 1)
26+
repo=$(echo "$REPOSITORY" | cut -d '/' -f 2)
27+
query=$(
28+
jq -nr \
29+
--arg labels "$LABELS" \
30+
'
31+
(reduce ($labels | split (", *"; null) | .[]) as $i ([]; . + [$i])) as $labels
32+
| "query ($owner: String!, $repo: String!) {\n" +
33+
" repository(owner: $owner, name: $repo) {\n" +
34+
(
35+
reduce $labels[] as $i ([0, ""]; [
36+
.[0] + 1,
37+
.[1] + (
38+
" _" + (.[0] | tostring) +
39+
": label(name: \"" + $i + "\") {\n" +
40+
" id\n" +
41+
" name\n"+
42+
" }\n"
43+
)
44+
])
45+
| .[1]
46+
)+
47+
" }\n" +
48+
"}"
49+
'
50+
)
51+
data=$(
52+
gh api graphql \
53+
-f owner="$owner" \
54+
-f repo="$repo" \
55+
-f query="$query" \
56+
| jq -c \
57+
--arg labels "$LABELS" \
58+
--arg colors "$COLORS" \
59+
--arg defaultColor "$DEFAULT_COLOR" \
60+
'
61+
. as $in
62+
| ($labels | split(", *"; null)) as $labels
63+
| (
64+
reduce (
65+
$in.data.repository[]
66+
| select( objects | .name as $name | any($labels[]; . == $name ) )
67+
) as $i ({}; .[$i.name] = {"id": $i.id})
68+
) as $found
69+
| [.[].id]
70+
'
71+
)
72+
echo "label_ids=$data" >>> "$GITHUB_OUTPUT"
73+
74+
- name: Delete Labels
75+
id: delete_labels
76+
shell: bash
77+
env:
78+
GH_TOKEN: ${{ inputs.gh_token }}
79+
LABELS: ${{ steps.collect_labels.outputs.label_ids }}
80+
run: |
81+
query=$(jq -r '
82+
. as $in
83+
| (
84+
"mutation {\n" + (
85+
reduce $in[] as $id ([0, ""]; [
86+
.[0] + 1 ,
87+
.[1] + (
88+
" _" + (.[0] | tostring) + ": deleteLabel(input: {id: \"" + $id + "\"}) {\n" +
89+
" clientMutationId\n" +
90+
" }\n"
91+
)
92+
])
93+
| .[1]
94+
) +
95+
"}"
96+
)
97+
' <<< "$LABELS"
98+
)
99+
gh api graphql -f query="$query"
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: Manual workflow to apply labels in bulk
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
issues:
7+
description: a single or comma separated list of issue numbers
8+
required: true
9+
type: string
10+
labels:
11+
description: a single or comma separated list of labels to apply to all listed issues
12+
required: true
13+
type: string
14+
colors:
15+
description: |
16+
A single or comma separated list of colors to create the labels with if needed.
17+
the list order is the same as `labels`. Missing or blank values (e.g. `FFFFFF,,FFFFFF`) use the `default_color`
18+
type: string
19+
default-color:
20+
description: default color to create labels with
21+
default: "#D4C5F9"
22+
type: string
23+
24+
jobs:
25+
apply-labels:
26+
name: Apply Labels
27+
runs-on: ubuntu-latest
28+
29+
permissions:
30+
issues: write
31+
pull-requests: write
32+
33+
steps:
34+
- name: Checkout Default Branch
35+
uses: actions/checkout@v4
36+
with:
37+
ref: ${{ github.event.repository.default_branch }}
38+
- name: Run Label Action
39+
uses: ./.github/actions/add-labels
40+
with:
41+
issues: ${{ inputs.issues }}
42+
labels: ${{ inputs.labels }}
43+
colors: ${{ inputs.colors }}
44+
default-color: ${{ inputs.default-color }}

0 commit comments

Comments
 (0)