-
Notifications
You must be signed in to change notification settings - Fork 1
131 lines (121 loc) · 4.67 KB
/
Copy pathlabel-sync.yml
File metadata and controls
131 lines (121 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
# Keeps the org's labels matching .github/labels.js.
#
# Structure follows apache/maven-gh-actions-shared/.github/workflows/labels-sync.yml
# so the two orgs stay recognisably the same, with two differences:
#
# * the repository list comes from the GitHub API rather than gitbox, which
# the ASF has and codehaus-plexus does not. Archived repositories are
# filtered out, so retired components are never touched.
# * the scheduled run is REPORT-ONLY and needs no credentials. Reading labels
# from a public repository requires no permissions, so drift is detected on
# the default GITHUB_TOKEN. Only reconciling needs a token.
#
# Reconciling uses an optional LABEL_SYNC_TOKEN secret - a fine-grained PAT
# owned by the org with `Issues: Read and write`. Only an org owner can add it.
# Until one exists the drift report still works, and anyone with push rights can
# reconcile from a checkout by dispatching this workflow from their own fork or
# by running the equivalent locally.
name: Label sync
on:
schedule:
- cron: '0 6 * * 1'
workflow_dispatch:
inputs:
apply:
description: 'Reconcile labels (needs LABEL_SYNC_TOKEN). Leave off to only report drift.'
type: boolean
default: false
permissions:
contents: read
jobs:
repos:
name: Prepare repositories list
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.repo.outputs.matrix }}
steps:
- id: repo
env:
GH_TOKEN: ${{ github.token }}
run: |
{
echo 'matrix<<EOF'
gh api 'orgs/codehaus-plexus/repos?per_page=100' --paginate \
--jq '.[] | select(.archived == false) | .name' \
| sort | jq -Rsc 'split("\n") | map(select(length > 0))'
echo 'EOF'
} >> "$GITHUB_OUTPUT"
cat "$GITHUB_OUTPUT"
label-sync:
name: ${{ matrix.repo }}
runs-on: ubuntu-latest
needs: repos
strategy:
fail-fast: false
max-parallel: 10
matrix:
repo: ${{ fromJSON(needs.repos.outputs.matrix) }}
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- name: Check the token when reconciling
if: ${{ inputs.apply == true }}
env:
TOKEN: ${{ secrets.LABEL_SYNC_TOKEN }}
run: |
if [ -z "$TOKEN" ]; then
echo "::error::Reconciling needs the LABEL_SYNC_TOKEN secret, which only an org owner can add."
echo "::error::Re-run without 'apply' to get a drift report instead."
exit 1
fi
- name: Sync labels in ${{ matrix.repo }}
uses: actions/github-script@v9
env:
OWNER: codehaus-plexus
REPO: ${{ matrix.repo }}
APPLY: ${{ inputs.apply }}
with:
# Reading labels from a public repo needs no permissions, so the
# default token is enough for the report-only path.
github-token: ${{ secrets.LABEL_SYNC_TOKEN || github.token }}
script: |
const labels = require('./.github/labels.js');
const apply = process.env.APPLY === 'true';
const { OWNER: owner, REPO: repo } = process.env;
const current = await github.paginate(github.rest.issues.listLabelsForRepo, {
owner, repo, per_page: 100
});
const drift = [];
for (const label of labels) {
const existing = current.find(({ name }) => name === label.name);
if (!existing) {
drift.push(`missing: ${label.name}`);
if (apply) {
await github.rest.issues.createLabel({ owner, repo, ...label });
}
} else {
const what = [];
if (existing.color.toLowerCase() !== label.color.toLowerCase()) {
what.push(`colour #${existing.color} -> #${label.color}`);
}
if ((existing.description || '') !== label.description) {
what.push('description');
}
if (what.length) {
drift.push(`${label.name}: ${what.join(', ')}`);
if (apply) {
await github.rest.issues.updateLabel({ owner, repo, ...label });
}
}
}
}
if (drift.length === 0) {
core.info(`${repo}: up to date`);
return;
}
drift.forEach(d => core.info(`${repo}: ${d}`));
core.summary.addHeading(repo, 3).addList(drift).write();
if (!apply) {
core.setFailed(`${repo}: ${drift.length} label(s) drifted from .github/labels.js`);
}