You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit c44d2ce
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: README.md
+32-9Lines changed: 32 additions & 9 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,6 +5,7 @@ This repository is a standalone GitHub label management repo for an organization
5
5
Its job is to:
6
6
7
7
- keep this repo's label config in sync with the labels currently defined on the repo
8
+
- track labels removed from that source config so they can be deleted from synced repositories
8
9
- validate config changes automatically
9
10
- sync the resulting label set across the rest of the organization
10
11
- remove an exact label from issues and pull requests across the filtered repository set
@@ -25,9 +26,10 @@ The normal flow is:
25
26
1. You run `Org-Label-Sync` manually.
26
27
2. It first calls `Config-Label_Sync`.
27
28
3.`Config-Label_Sync` reads the labels on this repository and rewrites `config/labels.jsonc` so the file matches the repo's current labels.
28
-
4. If that file changed, `Config-Label_Sync` commits and pushes the update.
29
-
5. That config change triggers `Validate-Configs`.
30
-
6.`Org-Label-Sync` then checks out the latest default branch, validates the config again, and syncs labels across the organization.
29
+
4. Any labels that were previously managed but are no longer on the source repository are moved to `config/deleted-labels.jsonc`.
30
+
5. If either config file changed, `Config-Label_Sync` commits and pushes the update.
31
+
6. That config change triggers `Validate-Configs`.
32
+
7.`Org-Label-Sync` then checks out the latest default branch, validates the config again, and syncs labels across the organization.
31
33
32
34
The reverse flow is:
33
35
@@ -48,6 +50,7 @@ The reverse flow is:
48
50
| |-- reverse-config-label-sync.yml
49
51
| `-- validate-configs.yml
50
52
|-- config/
53
+
| |-- deleted-labels.jsonc
51
54
| |-- github-default-labels.jsonc
52
55
| |-- labels.jsonc
53
56
| |-- properties.jsonc
@@ -67,6 +70,7 @@ The reverse flow is:
67
70
|-- sync-labels.mjs
68
71
`-- lib/
69
72
|-- changelog-utils.mjs
73
+
|-- config-validation.mjs
70
74
`-- config-utils.mjs
71
75
```
72
76
@@ -134,6 +138,20 @@ Example:
134
138
]
135
139
```
136
140
141
+
### `config/deleted-labels.jsonc`
142
+
143
+
This is the list of labels that should be deleted from synced repositories.
144
+
145
+
It is normally maintained automatically by `Config-Label_Sync`. When a label existed in `config/labels.jsonc` and is later removed from the source repository, the last managed label spec is moved here.
146
+
147
+
Each entry uses the same object shape as `config/labels.jsonc`:
148
+
149
+
-`name`
150
+
-`color`
151
+
-`description`
152
+
153
+
`Org-Label-Sync` deletes matching label names from target repositories regardless of color or description. If a label appears again on the source repository, `Config-Label_Sync` removes it from `config/deleted-labels.jsonc` and restores it to `config/labels.jsonc`.
154
+
137
155
### `config/github-default-labels.jsonc`
138
156
139
157
This is the list of exact GitHub default labels that can be removed from synced repositories when they are not managed by `config/labels.jsonc`.
@@ -218,8 +236,9 @@ What it does:
218
236
3. Resolves either the configured PAT or a GitHub App installation token
219
237
4. Reads the current labels on the source repository
220
238
5. Rewrites `config/labels.jsonc` so it exactly matches the source repository labels
8. Commits and pushes the change if either config file was updated
223
242
224
243
This workflow is the bridge between "the labels on this repo right now" and "the managed config we sync elsewhere."
225
244
@@ -242,6 +261,7 @@ Validation includes:
242
261
- JSONC parsing
243
262
- required property checks
244
263
- duplicate label detection
264
+
- deleted-label shape and duplicate-name validation
245
265
- repository filter shape and `useWhitelist` validation
246
266
- duplicate whitelist and blacklist detection
247
267
- invalid colors
@@ -295,9 +315,10 @@ What it does:
295
315
6. Discovers repos in the configured organization
296
316
7. Applies `config/repository-filter.jsonc`, unless `repositories` was provided as a workflow dispatch config override
297
317
8. Creates or updates labels from `config/labels.jsonc`
298
-
9. Deletes labels that exactly match entries in `config/github-default-labels.jsonc` only when the `delete_github_default_labels` workflow checkbox is checked, unless that label name is managed by `config/labels.jsonc`
299
-
10. Optionally deletes any other unmanaged labels only when the `delete_missing` workflow checkbox is checked; exact GitHub default labels are reserved for `delete_github_default_labels`
300
-
11. If at least one target repo changed or would change, writes a changelog and commits it with `[skip ci]`; real runs write to `changelogs/YYYY-MM-DD/`, while preview runs write fake changelogs to `fake-changelogs/YYYY-MM-DD/` and do not apply repository changes
318
+
9. Deletes labels whose names match entries in `config/deleted-labels.jsonc`
319
+
10. Deletes labels that exactly match entries in `config/github-default-labels.jsonc` only when the `delete_github_default_labels` workflow checkbox is checked, unless that label name is managed by `config/labels.jsonc`
320
+
11. Optionally deletes any other unmanaged labels only when the `delete_missing` workflow checkbox is checked; exact GitHub default labels are reserved for `delete_github_default_labels`
321
+
12. If at least one target repo changed or would change, writes a changelog and commits it with `[skip ci]`; real runs write to `changelogs/YYYY-MM-DD/`, while preview runs write fake changelogs to `fake-changelogs/YYYY-MM-DD/` and do not apply repository changes
301
322
302
323
### `Remove-Labels`
303
324
@@ -336,6 +357,7 @@ Each changelog file is created only when a workflow actually changes, or in prev
336
357
337
358
- created labels
338
359
- updated labels, including changed fields
360
+
- labels deleted by `config/deleted-labels.jsonc`
339
361
- GitHub default labels that were deleted
340
362
- unmanaged labels that were deleted when delete-missing is enabled
341
363
@@ -363,7 +385,7 @@ That PAT needs enough access to:
363
385
- read and update labels on target repositories
364
386
- read and update labels on the source repository when running `Reverse-Config-Label-Sync`
365
387
- read and update issues and pull requests when running `Remove-Labels`
366
-
- push config updates back to this repository when `Config-Label_Sync` changes `labels.jsonc`
388
+
- push config updates back to this repository when `Config-Label_Sync` changes `labels.jsonc` or `deleted-labels.jsonc`
367
389
- push changelog commits back to this repository when an action changes another repository
368
390
369
391
For GitHub App auth, create repository secrets whose names match:
@@ -388,6 +410,7 @@ The GitHub App installation must be granted access to this configuration reposit
388
410
## Safe Defaults
389
411
390
412
-`labels.jsonc` starts empty until you define or sync labels on this repo
413
+
-`deleted-labels.jsonc` starts empty and is populated when synced labels are removed from the source repository
391
414
- all repos in the org are targeted unless excluded by `repository-filter.jsonc`
392
415
- GitHub default labels are pruned by default when they exactly match `config/github-default-labels.jsonc`; uncheck `delete_github_default_labels` to keep them
393
416
- deleting unmanaged labels is off by default unless you check `delete_missing` when running `Org-Label-Sync`
assert(Array.isArray(labels),`${configPath} must contain an array.`);
180
180
181
181
constseen=newSet();
182
182
183
183
returnlabels.map((label,index)=>{
184
-
assert(label&&typeoflabel==="object"&&!Array.isArray(label),`Label at index ${index} must be an object.`);
185
-
assert(typeoflabel.name==="string"&&label.name.trim(),`Label at index ${index} is missing a valid name.`);
186
-
assert(typeoflabel.color==="string"&&/^[0-9a-fA-F]{6}$/.test(normalizeColor(label.color)),`Label "${label.name}" must have a 6-character hex color.`);
184
+
assert(label&&typeoflabel==="object"&&!Array.isArray(label),`${itemLabel} at index ${index} must be an object.`);
185
+
assert(typeoflabel.name==="string"&&label.name.trim(),`${itemLabel} at index ${index} is missing a valid name.`);
186
+
assert(typeoflabel.color==="string"&&/^[0-9a-fA-F]{6}$/.test(normalizeColor(label.color)),`${itemLabel} "${label.name}" must have a 6-character hex color.`);
187
187
188
188
constkey=normalizeName(label.name);
189
-
assert(!seen.has(key),`Duplicate label name detected: "${label.name}".`);
189
+
assert(!seen.has(key),`Duplicate ${itemLabel.toLowerCase()} name detected: "${label.name}".`);
190
190
seen.add(key);
191
191
192
192
if(label.description!==undefined){
193
-
assert(typeoflabel.description==="string",`Label "${label.name}" has a non-string description.`);
193
+
assert(typeoflabel.description==="string",`${itemLabel} "${label.name}" has a non-string description.`);
`Synced ${managedLabels.length} managed labels from ${repository} into config/labels.jsonc. Source labels take precedence over ${githubDefaultLabels.length} exact GitHub default label specs.`,
106
+
`Synced ${managedLabels.length} managed labels from ${repository} into config/labels.jsonc and tracked ${nextDeletedLabels.length} deleted labels in config/deleted-labels.jsonc. Source labels take precedence over ${githubDefaultLabels.length} exact GitHub default label specs.`,
0 commit comments