-
Notifications
You must be signed in to change notification settings - Fork 2.1k
144 lines (127 loc) · 4.67 KB
/
Copy pathlabeler.yml
File metadata and controls
144 lines (127 loc) · 4.67 KB
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
name: "Pull Request Labeler"
on:
schedule:
# Reconcile recently updated PRs promptly, including unapproved forks and
# conflicted PRs for which pull_request workflows do not run.
- cron: "7,22,37,52 * * * *"
# Reconcile one stable shard of all open PRs each hour to recover from
# delayed or missed scheduled runs.
- cron: "12 * * * *"
workflow_dispatch:
inputs:
pr_number:
description: "Open pull request number to reconcile"
required: true
type: string
permissions: {}
concurrency:
group: pull-request-labeler
cancel-in-progress: false
jobs:
triage:
if: github.ref_name == github.event.repository.default_branch
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v5
with:
persist-credentials: false
sparse-checkout: .github/labeler.yml
sparse-checkout-cone-mode: false
- name: Collect pull requests to reconcile
id: collect
env:
GH_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
EVENT_NAME: ${{ github.event_name }}
SCHEDULE: ${{ github.event.schedule }}
REQUESTED_PR: ${{ inputs.pr_number }}
run: |
set -euo pipefail
if [ "$EVENT_NAME" = "workflow_dispatch" ]; then
if [[ ! "$REQUESTED_PR" =~ ^[1-9][0-9]*$ ]]; then
echo "Invalid pull request number: $REQUESTED_PR"
exit 1
fi
pr_json=$(gh api "repos/$REPO/pulls/$REQUESTED_PR")
candidates=$(jq -c '[{
number: .number,
head_sha: .head.sha
}]' <<<"$pr_json")
else
pulls_json=$(gh api --paginate \
"repos/$REPO/pulls?state=open&sort=updated&direction=desc&per_page=100" |
jq -cs 'add')
if [ "$SCHEDULE" = "12 * * * *" ]; then
shard=$(( ($(date -u +%s) / 3600) % 6 ))
candidates=$(jq -c --argjson shard "$shard" \
'[.[] | select((.number % 6) == $shard) | {
number: .number,
head_sha: .head.sha
}]' <<<"$pulls_json")
else
cutoff=$(date -u -d "1 hour ago" "+%Y-%m-%dT%H:%M:%SZ")
# Hourly shards reconcile any candidates beyond this API budget.
candidates=$(jq -c --arg cutoff "$cutoff" \
'[.[] | select(.updated_at >= $cutoff) | {
number: .number,
head_sha: .head.sha
}][0:100]' <<<"$pulls_json")
fi
fi
echo "Collected $(jq 'length' <<<"$candidates") pull request(s)."
{
echo "candidates<<EOF"
echo "$candidates"
echo "EOF"
} >> "$GITHUB_OUTPUT"
- name: Validate pull request state
id: validate
env:
GH_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
CANDIDATES: ${{ steps.collect.outputs.candidates }}
run: |
set -euo pipefail
valid_numbers=()
while IFS=$'\t' read -r pr_number expected_sha; do
if [[ ! "$pr_number" =~ ^[1-9][0-9]*$ ]] ||
[[ ! "$expected_sha" =~ ^[0-9a-f]{40}$ ]]; then
echo "Skipping malformed pull request candidate."
continue
fi
if ! pr_json=$(gh api "repos/$REPO/pulls/$pr_number"); then
echo "Pull request #$pr_number could not be fetched; skipping."
continue
fi
if ! jq -e \
--arg repo "$REPO" \
--arg sha "$expected_sha" \
'.state == "open" and
.base.repo.full_name == $repo and
.head.sha == $sha and
(.head.repo.full_name | type == "string")' \
>/dev/null <<<"$pr_json"; then
echo "Pull request #$pr_number changed or is no longer open; skipping."
continue
fi
valid_numbers+=("$pr_number")
done < <(jq -r '.[] | [.number, .head_sha] | @tsv' <<<"$CANDIDATES")
if [ "${#valid_numbers[@]}" -eq 0 ]; then
echo "has_prs=false" >> "$GITHUB_OUTPUT"
exit 0
fi
{
echo "has_prs=true"
echo "pr_numbers<<EOF"
printf '%s\n' "${valid_numbers[@]}"
echo "EOF"
} >> "$GITHUB_OUTPUT"
- uses: actions/labeler@v4
if: steps.validate.outputs.has_prs == 'true'
with:
repo-token: "${{ github.token }}"
pr-number: ${{ steps.validate.outputs.pr_numbers }}