github-labels-template 0.6.1-staging.3ace40c โ 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -49
- package/dist/index.js +16 -187
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,9 +14,7 @@ A CLI tool to apply a curated set of GitHub labels to any repository using `gh`
|
|
|
14
14
|
- ๐ **One Command Setup**: Apply all labels to any repo with `ghlt apply`
|
|
15
15
|
- ๐ **Auto-Detect Repo**: Automatically detects the current repository from git remote
|
|
16
16
|
- ๐ **Smart Conflict Handling**: Skips existing labels by default, `--force` to update
|
|
17
|
-
-
|
|
18
|
-
- ๐งน **Wipe Command**: Remove all or specific labels with a confirmation prompt
|
|
19
|
-
- ๐ซ **Apply with Exclusions**: Skip specific labels or entire categories with `--exclude` / `--exclude-category`
|
|
17
|
+
- ๐งน **Wipe Command**: Remove all existing labels with a confirmation prompt
|
|
20
18
|
- โ
**Pre-Flight Checks**: Validates `gh` CLI is installed and authenticated before doing anything
|
|
21
19
|
- ๐ **Clear Output**: Structured logging powered by [@wgtechlabs/log-engine](https://github.com/wgtechlabs/log-engine) with color-coded levels and emoji
|
|
22
20
|
- ๐จ **ASCII Banner**: Beautiful ANSI Shadow figlet banner with version and author info
|
|
@@ -85,15 +83,6 @@ ghlt apply --category community --label bug
|
|
|
85
83
|
# Combine with force and repo
|
|
86
84
|
ghlt apply --category type --force --repo owner/repo
|
|
87
85
|
|
|
88
|
-
# Apply all labels except specific ones
|
|
89
|
-
ghlt apply --exclude "bug,enhancement"
|
|
90
|
-
|
|
91
|
-
# Apply all labels except an entire category
|
|
92
|
-
ghlt apply --exclude-category type
|
|
93
|
-
|
|
94
|
-
# Combine: apply all community labels except hacktoberfest
|
|
95
|
-
ghlt apply --category community --exclude hacktoberfest
|
|
96
|
-
|
|
97
86
|
# Include custom labels from labels-custom.json
|
|
98
87
|
ghlt apply --custom
|
|
99
88
|
|
|
@@ -101,16 +90,6 @@ ghlt apply --custom
|
|
|
101
90
|
ghlt apply --custom --category type
|
|
102
91
|
```
|
|
103
92
|
|
|
104
|
-
### List Labels
|
|
105
|
-
|
|
106
|
-
```bash
|
|
107
|
-
# List all labels on the current repo
|
|
108
|
-
ghlt list
|
|
109
|
-
|
|
110
|
-
# List labels on a specific repo
|
|
111
|
-
ghlt list --repo owner/repo
|
|
112
|
-
```
|
|
113
|
-
|
|
114
93
|
### Generate Labels (AI)
|
|
115
94
|
|
|
116
95
|
Generate custom labels using GitHub Copilot โ following the Clean Labels convention. Requires a [GitHub Copilot](https://github.com/features/copilot) subscription.
|
|
@@ -166,18 +145,6 @@ ghlt wipe --repo owner/repo
|
|
|
166
145
|
|
|
167
146
|
# Skip confirmation prompt
|
|
168
147
|
ghlt wipe --yes
|
|
169
|
-
|
|
170
|
-
# Remove specific labels
|
|
171
|
-
ghlt wipe --label "bug,enhancement"
|
|
172
|
-
|
|
173
|
-
# Remove all labels from a category
|
|
174
|
-
ghlt wipe --category type
|
|
175
|
-
|
|
176
|
-
# Remove labels from multiple categories
|
|
177
|
-
ghlt wipe --category "type,status"
|
|
178
|
-
|
|
179
|
-
# Include custom labels in the selective wipe scope
|
|
180
|
-
ghlt wipe --category type --custom
|
|
181
148
|
```
|
|
182
149
|
|
|
183
150
|
### Preview Landing Page
|
|
@@ -276,30 +243,24 @@ Broad software layers โ universal across any project.
|
|
|
276
243
|
ghlt โ GitHub Labels Template CLI
|
|
277
244
|
|
|
278
245
|
USAGE
|
|
279
|
-
ghlt [OPTIONS] apply|wipe|migrate|generate|
|
|
246
|
+
ghlt [OPTIONS] apply|wipe|migrate|generate|preview
|
|
280
247
|
|
|
281
248
|
OPTIONS
|
|
282
249
|
-v, --version Show version number
|
|
283
250
|
|
|
284
251
|
COMMANDS
|
|
285
252
|
apply Apply labels from the template to a repository
|
|
286
|
-
wipe Remove all
|
|
253
|
+
wipe Remove all existing labels from a repository
|
|
287
254
|
migrate Wipe all existing labels and apply the template (clean slate)
|
|
288
255
|
generate Generate custom labels using AI (requires GitHub Copilot)
|
|
289
|
-
list List all labels in a repository
|
|
290
256
|
preview Preview the landing page locally in your browser
|
|
291
257
|
|
|
292
258
|
OPTIONS (apply)
|
|
293
|
-
-r, --repo <owner/repo> Target repository (default: auto-detect)
|
|
294
|
-
-f, --force Overwrite existing labels
|
|
295
|
-
-l, --label <name> Apply specific label(s) by name (comma-separated)
|
|
296
|
-
-c, --category <name> Apply labels from specific category(ies) (comma-separated)
|
|
297
|
-
-e, --exclude <name> Exclude specific label(s) by name (comma-separated)
|
|
298
|
-
--exclude-category <name> Exclude labels from specific category(ies) (comma-separated)
|
|
299
|
-
--custom Include custom labels from labels-custom.json
|
|
300
|
-
|
|
301
|
-
OPTIONS (list)
|
|
302
259
|
-r, --repo <owner/repo> Target repository (default: auto-detect)
|
|
260
|
+
-f, --force Overwrite existing labels
|
|
261
|
+
-l, --label <name> Apply specific label(s) by name (comma-separated)
|
|
262
|
+
-c, --category <name> Apply labels from specific category(ies) (comma-separated)
|
|
263
|
+
--custom Include custom labels from labels-custom.json
|
|
303
264
|
|
|
304
265
|
OPTIONS (migrate)
|
|
305
266
|
-r, --repo <owner/repo> Target repository (default: auto-detect)
|
|
@@ -314,9 +275,6 @@ OPTIONS (generate)
|
|
|
314
275
|
OPTIONS (wipe)
|
|
315
276
|
-r, --repo <owner/repo> Target repository (default: auto-detect)
|
|
316
277
|
-y, --yes Skip confirmation prompt
|
|
317
|
-
-l, --label <name> Remove specific label(s) by name (comma-separated)
|
|
318
|
-
-c, --category <name> Remove labels from specific category(ies) (comma-separated)
|
|
319
|
-
--custom Include custom labels when using --label or --category
|
|
320
278
|
|
|
321
279
|
OPTIONS (preview)
|
|
322
280
|
-p, --port <number> Port to serve on (default: 3000)
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { defineCommand as
|
|
4
|
+
import { defineCommand as defineCommand5, runMain } from "citty";
|
|
5
5
|
|
|
6
6
|
// src/commands/apply.ts
|
|
7
7
|
import { defineCommand } from "citty";
|
|
@@ -52,28 +52,6 @@ async function detectRepo() {
|
|
|
52
52
|
return null;
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
|
-
async function listLabelsDetailed(repo) {
|
|
56
|
-
const { exitCode, stdout } = await run([
|
|
57
|
-
"label",
|
|
58
|
-
"list",
|
|
59
|
-
"--repo",
|
|
60
|
-
repo,
|
|
61
|
-
"--json",
|
|
62
|
-
"name,color,description",
|
|
63
|
-
"--limit",
|
|
64
|
-
"100"
|
|
65
|
-
]);
|
|
66
|
-
if (exitCode !== 0)
|
|
67
|
-
return [];
|
|
68
|
-
const text = stdout.trim();
|
|
69
|
-
if (!text)
|
|
70
|
-
return [];
|
|
71
|
-
try {
|
|
72
|
-
return JSON.parse(text);
|
|
73
|
-
} catch {
|
|
74
|
-
return [];
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
55
|
async function listLabels(repo) {
|
|
78
56
|
const { exitCode, stdout } = await run([
|
|
79
57
|
"label",
|
|
@@ -183,9 +161,7 @@ function filterLabels(allLabels, options) {
|
|
|
183
161
|
const warnings = [];
|
|
184
162
|
const labelFilter = options.label ? options.label.split(",").map((l) => l.trim().toLowerCase()).filter(Boolean) : null;
|
|
185
163
|
const categoryFilter = options.category ? options.category.split(",").map((c) => c.trim().toLowerCase()).filter(Boolean) : null;
|
|
186
|
-
|
|
187
|
-
const excludeCategoryFilter = options.excludeCategory ? options.excludeCategory.split(",").map((c) => c.trim().toLowerCase()).filter(Boolean) : null;
|
|
188
|
-
if (!labelFilter && !categoryFilter && !excludeLabelFilter && !excludeCategoryFilter) {
|
|
164
|
+
if (!labelFilter && !categoryFilter) {
|
|
189
165
|
return {
|
|
190
166
|
entries: Object.entries(allLabels),
|
|
191
167
|
warnings
|
|
@@ -207,25 +183,7 @@ function filterLabels(allLabels, options) {
|
|
|
207
183
|
}
|
|
208
184
|
}
|
|
209
185
|
}
|
|
210
|
-
|
|
211
|
-
for (const cat of excludeCategoryFilter) {
|
|
212
|
-
if (!validCategories.includes(cat)) {
|
|
213
|
-
warnings.push(`Unknown exclude category "${cat}". Valid categories: ${validCategories.join(", ")}`);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
if (excludeLabelFilter) {
|
|
218
|
-
const allLabelNames = Object.values(allLabels).flat().map((l) => l.name.toLowerCase());
|
|
219
|
-
for (const name of excludeLabelFilter) {
|
|
220
|
-
if (!allLabelNames.includes(name)) {
|
|
221
|
-
warnings.push(`Exclude label "${name}" not found in the template.`);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
const included = Object.entries(allLabels).map(([category, categoryLabels]) => {
|
|
226
|
-
if (!labelFilter && !categoryFilter) {
|
|
227
|
-
return [category, categoryLabels];
|
|
228
|
-
}
|
|
186
|
+
const entries = Object.entries(allLabels).map(([category, categoryLabels]) => {
|
|
229
187
|
const categoryMatches = categoryFilter?.includes(category.toLowerCase()) ?? false;
|
|
230
188
|
if (categoryMatches) {
|
|
231
189
|
return [category, categoryLabels];
|
|
@@ -236,14 +194,6 @@ function filterLabels(allLabels, options) {
|
|
|
236
194
|
}
|
|
237
195
|
return [category, []];
|
|
238
196
|
}).filter(([, categoryLabels]) => categoryLabels.length > 0);
|
|
239
|
-
const entries = included.filter(([category]) => excludeCategoryFilter ? !excludeCategoryFilter.includes(category.toLowerCase()) : true).map(([category, categoryLabels]) => {
|
|
240
|
-
if (!excludeLabelFilter)
|
|
241
|
-
return [category, categoryLabels];
|
|
242
|
-
return [
|
|
243
|
-
category,
|
|
244
|
-
categoryLabels.filter((l) => !excludeLabelFilter.includes(l.name.toLowerCase()))
|
|
245
|
-
];
|
|
246
|
-
}).filter(([, categoryLabels]) => categoryLabels.length > 0);
|
|
247
197
|
return { entries, warnings };
|
|
248
198
|
}
|
|
249
199
|
|
|
@@ -356,15 +306,6 @@ var apply_default = defineCommand({
|
|
|
356
306
|
type: "boolean",
|
|
357
307
|
default: false,
|
|
358
308
|
description: "Include custom labels from labels-custom.json (generated via ghlt generate)"
|
|
359
|
-
},
|
|
360
|
-
exclude: {
|
|
361
|
-
type: "string",
|
|
362
|
-
alias: "e",
|
|
363
|
-
description: 'Exclude specific label(s) by name. Comma-separated for multiple (e.g., --exclude "bug,enhancement")'
|
|
364
|
-
},
|
|
365
|
-
"exclude-category": {
|
|
366
|
-
type: "string",
|
|
367
|
-
description: 'Exclude labels from specific category(ies). Comma-separated for multiple (e.g., --exclude-category "type,status")'
|
|
368
309
|
}
|
|
369
310
|
},
|
|
370
311
|
async run({ args }) {
|
|
@@ -409,9 +350,7 @@ var apply_default = defineCommand({
|
|
|
409
350
|
}
|
|
410
351
|
const { entries: filteredEntries, warnings } = filterLabels(labelPool, {
|
|
411
352
|
label: args.label,
|
|
412
|
-
category: args.category
|
|
413
|
-
excludeLabel: args.exclude,
|
|
414
|
-
excludeCategory: args["exclude-category"]
|
|
353
|
+
category: args.category
|
|
415
354
|
});
|
|
416
355
|
for (const w of warnings) {
|
|
417
356
|
warn(w);
|
|
@@ -422,12 +361,6 @@ var apply_default = defineCommand({
|
|
|
422
361
|
if (args.label) {
|
|
423
362
|
info(`Applying specific labels: ${args.label}`);
|
|
424
363
|
}
|
|
425
|
-
if (args["exclude-category"]) {
|
|
426
|
-
info(`Excluding categories: ${args["exclude-category"]}`);
|
|
427
|
-
}
|
|
428
|
-
if (args.exclude) {
|
|
429
|
-
info(`Excluding labels: ${args.exclude}`);
|
|
430
|
-
}
|
|
431
364
|
if (filteredEntries.length === 0) {
|
|
432
365
|
warn("No labels matched the specified filter(s).");
|
|
433
366
|
return;
|
|
@@ -507,21 +440,6 @@ var wipe_default = defineCommand2({
|
|
|
507
440
|
alias: "y",
|
|
508
441
|
default: false,
|
|
509
442
|
description: "Skip confirmation prompt"
|
|
510
|
-
},
|
|
511
|
-
label: {
|
|
512
|
-
type: "string",
|
|
513
|
-
alias: "l",
|
|
514
|
-
description: 'Remove specific label(s) by name. Comma-separated for multiple (e.g., --label "bug,enhancement")'
|
|
515
|
-
},
|
|
516
|
-
category: {
|
|
517
|
-
type: "string",
|
|
518
|
-
alias: "c",
|
|
519
|
-
description: 'Remove labels from specific category(ies). Comma-separated for multiple (e.g., --category "type,status")'
|
|
520
|
-
},
|
|
521
|
-
custom: {
|
|
522
|
-
type: "boolean",
|
|
523
|
-
default: false,
|
|
524
|
-
description: "Include custom labels from labels-custom.json when using --label or --category"
|
|
525
443
|
}
|
|
526
444
|
},
|
|
527
445
|
async run({ args }) {
|
|
@@ -544,57 +462,14 @@ var wipe_default = defineCommand2({
|
|
|
544
462
|
info("No labels found. Nothing to wipe.");
|
|
545
463
|
return;
|
|
546
464
|
}
|
|
547
|
-
const isSelective = !!(args.label || args.category);
|
|
548
|
-
let toDelete;
|
|
549
|
-
if (isSelective) {
|
|
550
|
-
const labelPool = {
|
|
551
|
-
...labels_default
|
|
552
|
-
};
|
|
553
|
-
if (args.custom) {
|
|
554
|
-
const custom = loadCustomLabels();
|
|
555
|
-
for (const [cat, catLabels] of Object.entries(custom)) {
|
|
556
|
-
if (!labelPool[cat])
|
|
557
|
-
labelPool[cat] = [];
|
|
558
|
-
for (const label of catLabels) {
|
|
559
|
-
const exists = labelPool[cat].some((l) => l.name.toLowerCase() === label.name.toLowerCase());
|
|
560
|
-
if (!exists)
|
|
561
|
-
labelPool[cat].push(label);
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
const { entries: filteredEntries, warnings } = filterLabels(labelPool, {
|
|
566
|
-
label: args.label,
|
|
567
|
-
category: args.category
|
|
568
|
-
});
|
|
569
|
-
for (const w of warnings) {
|
|
570
|
-
warn(w);
|
|
571
|
-
}
|
|
572
|
-
if (filteredEntries.length === 0) {
|
|
573
|
-
warn("No labels matched the specified filter(s).");
|
|
574
|
-
return;
|
|
575
|
-
}
|
|
576
|
-
const existingSet = new Set(existing.map((n) => n.toLowerCase()));
|
|
577
|
-
toDelete = filteredEntries.flatMap(([, categoryLabels]) => categoryLabels.map((l) => l.name)).filter((name) => existingSet.has(name.toLowerCase()));
|
|
578
|
-
if (toDelete.length === 0) {
|
|
579
|
-
info("None of the specified labels exist on the repo. Nothing to remove.");
|
|
580
|
-
return;
|
|
581
|
-
}
|
|
582
|
-
if (args.label)
|
|
583
|
-
info(`Removing specific labels: ${args.label}`);
|
|
584
|
-
if (args.category)
|
|
585
|
-
info(`Removing labels from category: ${args.category}`);
|
|
586
|
-
} else {
|
|
587
|
-
toDelete = existing;
|
|
588
|
-
}
|
|
589
465
|
if (!args.yes) {
|
|
590
|
-
const
|
|
591
|
-
const confirmed = await confirmPrompt(message);
|
|
466
|
+
const confirmed = await confirmPrompt(pc3.bold(pc3.red(`This will delete all ${existing.length} labels from ${repo}.`)));
|
|
592
467
|
if (!confirmed)
|
|
593
468
|
return;
|
|
594
469
|
}
|
|
595
470
|
heading("Deleting Labels");
|
|
596
471
|
const counts = { deleted: 0, failed: 0 };
|
|
597
|
-
for (const name of
|
|
472
|
+
for (const name of existing) {
|
|
598
473
|
const ok = await deleteLabel(repo, name);
|
|
599
474
|
if (ok) {
|
|
600
475
|
success(`${name} (deleted)`);
|
|
@@ -1018,58 +893,13 @@ var migrate_default = defineCommand4({
|
|
|
1018
893
|
}
|
|
1019
894
|
});
|
|
1020
895
|
|
|
1021
|
-
// src/commands/list.ts
|
|
1022
|
-
import { defineCommand as defineCommand5 } from "citty";
|
|
1023
|
-
import pc6 from "picocolors";
|
|
1024
|
-
var list_default = defineCommand5({
|
|
1025
|
-
meta: {
|
|
1026
|
-
name: "list",
|
|
1027
|
-
description: "List all labels in a repository"
|
|
1028
|
-
},
|
|
1029
|
-
args: {
|
|
1030
|
-
repo: {
|
|
1031
|
-
type: "string",
|
|
1032
|
-
alias: "r",
|
|
1033
|
-
description: "Target repository (owner/repo). Defaults to current repo."
|
|
1034
|
-
}
|
|
1035
|
-
},
|
|
1036
|
-
async run({ args }) {
|
|
1037
|
-
if (!await checkGhInstalled()) {
|
|
1038
|
-
error("gh CLI is not installed. Install it from https://cli.github.com");
|
|
1039
|
-
process.exit(1);
|
|
1040
|
-
}
|
|
1041
|
-
if (!await checkGhAuth()) {
|
|
1042
|
-
error("Not authenticated. Run `gh auth login` first.");
|
|
1043
|
-
process.exit(1);
|
|
1044
|
-
}
|
|
1045
|
-
const repo = args.repo || await detectRepo();
|
|
1046
|
-
if (!repo) {
|
|
1047
|
-
error("Could not detect repository. Use --repo <owner/repo> or run inside a git repo.");
|
|
1048
|
-
process.exit(1);
|
|
1049
|
-
}
|
|
1050
|
-
info(`Target: ${repo}`);
|
|
1051
|
-
const labels = await listLabelsDetailed(repo);
|
|
1052
|
-
if (labels.length === 0) {
|
|
1053
|
-
info("No labels found.");
|
|
1054
|
-
return;
|
|
1055
|
-
}
|
|
1056
|
-
heading(`Labels (${labels.length} total)`);
|
|
1057
|
-
for (const label of labels) {
|
|
1058
|
-
const name = pc6.bold(label.name.padEnd(30));
|
|
1059
|
-
const color = pc6.dim(`#${label.color}`);
|
|
1060
|
-
const desc = label.description ? pc6.dim(label.description) : "";
|
|
1061
|
-
console.log(` ${name} ${color} ${desc}`);
|
|
1062
|
-
}
|
|
1063
|
-
}
|
|
1064
|
-
});
|
|
1065
|
-
|
|
1066
896
|
// src/ui/banner.ts
|
|
1067
897
|
import figlet from "figlet";
|
|
1068
|
-
import
|
|
898
|
+
import pc6 from "picocolors";
|
|
1069
899
|
// package.json
|
|
1070
900
|
var package_default = {
|
|
1071
901
|
name: "github-labels-template",
|
|
1072
|
-
version: "0.6.1
|
|
902
|
+
version: "0.6.1",
|
|
1073
903
|
description: "A CLI tool to apply a curated GitHub labels template to any repository using gh CLI.",
|
|
1074
904
|
type: "module",
|
|
1075
905
|
bin: {
|
|
@@ -1134,15 +964,15 @@ function getAuthor() {
|
|
|
1134
964
|
return package_default.author ?? "unknown";
|
|
1135
965
|
}
|
|
1136
966
|
function showBanner(minimal = false) {
|
|
1137
|
-
console.log(
|
|
967
|
+
console.log(pc6.cyan(`
|
|
1138
968
|
` + LOGO));
|
|
1139
|
-
console.log(` ${
|
|
969
|
+
console.log(` ${pc6.dim("v" + getVersion())} ${pc6.dim("โ")} ${pc6.dim("Built by " + getAuthor())}`);
|
|
1140
970
|
if (!minimal) {
|
|
1141
|
-
console.log(` ${
|
|
971
|
+
console.log(` ${pc6.dim(package_default.description)}`);
|
|
1142
972
|
console.log();
|
|
1143
|
-
console.log(` ${
|
|
1144
|
-
console.log(` ${
|
|
1145
|
-
console.log(` ${
|
|
973
|
+
console.log(` ${pc6.yellow("Star")} ${pc6.cyan("https://gh.waren.build/github-labels-template")}`);
|
|
974
|
+
console.log(` ${pc6.green("Contribute")} ${pc6.cyan("https://gh.waren.build/github-labels-template/blob/main/CONTRIBUTING.md")}`);
|
|
975
|
+
console.log(` ${pc6.magenta("Sponsor")} ${pc6.cyan("https://warengonzaga.com/sponsor")}`);
|
|
1146
976
|
}
|
|
1147
977
|
console.log();
|
|
1148
978
|
}
|
|
@@ -1150,7 +980,7 @@ function showBanner(minimal = false) {
|
|
|
1150
980
|
// src/index.ts
|
|
1151
981
|
var isHelp = process.argv.includes("--help") || process.argv.includes("-h");
|
|
1152
982
|
showBanner(isHelp);
|
|
1153
|
-
var main =
|
|
983
|
+
var main = defineCommand5({
|
|
1154
984
|
meta: {
|
|
1155
985
|
name: "ghlt",
|
|
1156
986
|
version: getVersion(),
|
|
@@ -1167,8 +997,7 @@ var main = defineCommand6({
|
|
|
1167
997
|
apply: apply_default,
|
|
1168
998
|
wipe: wipe_default,
|
|
1169
999
|
migrate: migrate_default,
|
|
1170
|
-
generate: generate_default
|
|
1171
|
-
list: list_default
|
|
1000
|
+
generate: generate_default
|
|
1172
1001
|
},
|
|
1173
1002
|
run({ args }) {
|
|
1174
1003
|
if (args.version) {
|