@asagiri-design/labels-config 0.2.2 → 0.3.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 +62 -0
- package/dist/chunk-MM4GCVPE.mjs +549 -0
- package/dist/cli.js +522 -98
- package/dist/cli.mjs +256 -103
- package/dist/github/index.d.mts +49 -1
- package/dist/github/index.d.ts +49 -1
- package/dist/github/index.js +212 -0
- package/dist/github/index.mjs +3 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/docs/BATCH_SYNC.md +396 -0
- package/docs/NPM_SETUP.md +200 -0
- package/docs/QUICK_START.md +457 -0
- package/docs/RELEASE_FLOW.md +436 -0
- package/package.json +3 -6
- package/dist/chunk-4ZUJQMV7.mjs +0 -285
- package/dist/chunk-DGUMSQAI.mjs +0 -496
- package/dist/chunk-ZYHIDOG2.mjs +0 -247
package/dist/github/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
7
9
|
var __export = (target, all) => {
|
|
@@ -16,12 +18,21 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
18
|
}
|
|
17
19
|
return to;
|
|
18
20
|
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
19
29
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
30
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
21
31
|
|
|
22
32
|
// src/github/index.ts
|
|
23
33
|
var github_exports = {};
|
|
24
34
|
__export(github_exports, {
|
|
35
|
+
BatchLabelSync: () => BatchLabelSync,
|
|
25
36
|
GitHubClient: () => GitHubClient,
|
|
26
37
|
GitHubLabelSync: () => GitHubLabelSync
|
|
27
38
|
});
|
|
@@ -303,8 +314,209 @@ var _GitHubLabelSync = class _GitHubLabelSync {
|
|
|
303
314
|
};
|
|
304
315
|
__publicField(_GitHubLabelSync, "BATCH_SIZE", 5);
|
|
305
316
|
var GitHubLabelSync = _GitHubLabelSync;
|
|
317
|
+
|
|
318
|
+
// src/utils/ui.ts
|
|
319
|
+
var colors = {
|
|
320
|
+
reset: "\x1B[0m",
|
|
321
|
+
bright: "\x1B[1m",
|
|
322
|
+
dim: "\x1B[2m",
|
|
323
|
+
// Foreground colors
|
|
324
|
+
red: "\x1B[31m",
|
|
325
|
+
green: "\x1B[32m",
|
|
326
|
+
yellow: "\x1B[33m",
|
|
327
|
+
blue: "\x1B[34m",
|
|
328
|
+
magenta: "\x1B[35m",
|
|
329
|
+
cyan: "\x1B[36m",
|
|
330
|
+
white: "\x1B[37m",
|
|
331
|
+
gray: "\x1B[90m",
|
|
332
|
+
// Background colors
|
|
333
|
+
bgRed: "\x1B[41m",
|
|
334
|
+
bgGreen: "\x1B[42m",
|
|
335
|
+
bgYellow: "\x1B[43m",
|
|
336
|
+
bgBlue: "\x1B[44m"
|
|
337
|
+
};
|
|
338
|
+
function supportsColor() {
|
|
339
|
+
if (process.env.NO_COLOR) {
|
|
340
|
+
return false;
|
|
341
|
+
}
|
|
342
|
+
if (process.env.FORCE_COLOR) {
|
|
343
|
+
return true;
|
|
344
|
+
}
|
|
345
|
+
if (!process.stdout.isTTY) {
|
|
346
|
+
return false;
|
|
347
|
+
}
|
|
348
|
+
if (process.platform === "win32") {
|
|
349
|
+
return true;
|
|
350
|
+
}
|
|
351
|
+
return true;
|
|
352
|
+
}
|
|
353
|
+
function colorize(text, color) {
|
|
354
|
+
if (!supportsColor()) {
|
|
355
|
+
return text;
|
|
356
|
+
}
|
|
357
|
+
return `${colors[color]}${text}${colors.reset}`;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// src/github/batch-sync.ts
|
|
361
|
+
var _BatchLabelSync = class _BatchLabelSync {
|
|
362
|
+
/**
|
|
363
|
+
* 複数リポジトリへのラベル一括同期
|
|
364
|
+
*/
|
|
365
|
+
async syncMultiple(labels, options) {
|
|
366
|
+
const repos = await this.getTargetRepositories(options);
|
|
367
|
+
const results = [];
|
|
368
|
+
console.log(colorize(`
|
|
369
|
+
\u{1F4CB} Target repositories: ${repos.length}`, "cyan"));
|
|
370
|
+
let completed = 0;
|
|
371
|
+
const parallel = options.parallel || _BatchLabelSync.DEFAULT_PARALLEL;
|
|
372
|
+
for (let i = 0; i < repos.length; i += parallel) {
|
|
373
|
+
const batch = repos.slice(i, i + parallel);
|
|
374
|
+
const batchResults = await Promise.allSettled(
|
|
375
|
+
batch.map((repo) => this.syncSingleRepo(repo, labels, options))
|
|
376
|
+
);
|
|
377
|
+
batchResults.forEach((result, index) => {
|
|
378
|
+
const repo = batch[index];
|
|
379
|
+
if (result.status === "fulfilled") {
|
|
380
|
+
results.push(result.value);
|
|
381
|
+
completed++;
|
|
382
|
+
console.log(colorize(`\u2705 [${completed}/${repos.length}] ${repo}`, "green"));
|
|
383
|
+
} else {
|
|
384
|
+
results.push({
|
|
385
|
+
repository: repo,
|
|
386
|
+
status: "failed",
|
|
387
|
+
error: result.reason?.message || "Unknown error"
|
|
388
|
+
});
|
|
389
|
+
completed++;
|
|
390
|
+
console.log(colorize(`\u274C [${completed}/${repos.length}] ${repo}: ${result.reason}`, "red"));
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
return results;
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* 単一リポジトリへの同期
|
|
398
|
+
*/
|
|
399
|
+
async syncSingleRepo(repository, labels, options) {
|
|
400
|
+
try {
|
|
401
|
+
const [owner, repo] = repository.split("/");
|
|
402
|
+
if (!owner || !repo) {
|
|
403
|
+
throw new Error(`Invalid repository format: ${repository}. Expected format: owner/repo`);
|
|
404
|
+
}
|
|
405
|
+
const sync = new GitHubLabelSync({
|
|
406
|
+
owner,
|
|
407
|
+
repo,
|
|
408
|
+
deleteExtra: options.mode === "replace",
|
|
409
|
+
dryRun: options.dryRun || false
|
|
410
|
+
});
|
|
411
|
+
const result = await sync.syncLabels(labels);
|
|
412
|
+
return {
|
|
413
|
+
repository,
|
|
414
|
+
status: "success",
|
|
415
|
+
result
|
|
416
|
+
};
|
|
417
|
+
} catch (error) {
|
|
418
|
+
return {
|
|
419
|
+
repository,
|
|
420
|
+
status: "failed",
|
|
421
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* 対象リポジトリリストの取得
|
|
427
|
+
*/
|
|
428
|
+
async getTargetRepositories(options) {
|
|
429
|
+
if (options.repositories && options.repositories.length > 0) {
|
|
430
|
+
return options.repositories;
|
|
431
|
+
}
|
|
432
|
+
if (options.organization) {
|
|
433
|
+
return this.getOrganizationRepos(options.organization, options.filter);
|
|
434
|
+
}
|
|
435
|
+
if (options.user) {
|
|
436
|
+
return this.getUserRepos(options.user, options.filter);
|
|
437
|
+
}
|
|
438
|
+
throw new Error("No target repositories specified");
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* 組織のリポジトリ一覧を取得
|
|
442
|
+
*/
|
|
443
|
+
async getOrganizationRepos(org, filter) {
|
|
444
|
+
const { execSync: execSync2 } = await import("child_process");
|
|
445
|
+
try {
|
|
446
|
+
const command = `gh repo list ${org} --json nameWithOwner,visibility,language,isArchived --limit 1000`;
|
|
447
|
+
const output = execSync2(command, { encoding: "utf-8" });
|
|
448
|
+
const repos = JSON.parse(output);
|
|
449
|
+
return repos.filter((repo) => {
|
|
450
|
+
if (filter?.visibility && filter.visibility !== "all" && repo.visibility !== filter.visibility) {
|
|
451
|
+
return false;
|
|
452
|
+
}
|
|
453
|
+
if (filter?.language && repo.language !== filter.language) {
|
|
454
|
+
return false;
|
|
455
|
+
}
|
|
456
|
+
if (filter?.archived !== void 0 && repo.isArchived !== filter.archived) {
|
|
457
|
+
return false;
|
|
458
|
+
}
|
|
459
|
+
return true;
|
|
460
|
+
}).map((repo) => repo.nameWithOwner);
|
|
461
|
+
} catch (error) {
|
|
462
|
+
throw new Error(`Failed to fetch organization repos: ${error}`);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* ユーザーのリポジトリ一覧を取得
|
|
467
|
+
*/
|
|
468
|
+
async getUserRepos(user, filter) {
|
|
469
|
+
const { execSync: execSync2 } = await import("child_process");
|
|
470
|
+
try {
|
|
471
|
+
const command = `gh repo list ${user} --json nameWithOwner,visibility,language,isArchived --limit 1000`;
|
|
472
|
+
const output = execSync2(command, { encoding: "utf-8" });
|
|
473
|
+
const repos = JSON.parse(output);
|
|
474
|
+
return repos.filter((repo) => {
|
|
475
|
+
if (filter?.visibility && filter.visibility !== "all" && repo.visibility !== filter.visibility) {
|
|
476
|
+
return false;
|
|
477
|
+
}
|
|
478
|
+
if (filter?.language && repo.language !== filter.language) {
|
|
479
|
+
return false;
|
|
480
|
+
}
|
|
481
|
+
if (filter?.archived !== void 0 && repo.isArchived !== filter.archived) {
|
|
482
|
+
return false;
|
|
483
|
+
}
|
|
484
|
+
return true;
|
|
485
|
+
}).map((repo) => repo.nameWithOwner);
|
|
486
|
+
} catch (error) {
|
|
487
|
+
throw new Error(`Failed to fetch user repos: ${error}`);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* 結果サマリーの生成
|
|
492
|
+
*/
|
|
493
|
+
generateSummary(results) {
|
|
494
|
+
const successful = results.filter((r) => r.status === "success").length;
|
|
495
|
+
const failed = results.filter((r) => r.status === "failed").length;
|
|
496
|
+
const skipped = results.filter((r) => r.status === "skipped").length;
|
|
497
|
+
let summary = "\n\u{1F4CA} Batch Sync Summary:\n";
|
|
498
|
+
summary += `\u2705 Successful: ${successful}
|
|
499
|
+
`;
|
|
500
|
+
if (failed > 0) summary += `\u274C Failed: ${failed}
|
|
501
|
+
`;
|
|
502
|
+
if (skipped > 0) summary += `\u23ED\uFE0F Skipped: ${skipped}
|
|
503
|
+
`;
|
|
504
|
+
const failedRepos = results.filter((r) => r.status === "failed");
|
|
505
|
+
if (failedRepos.length > 0) {
|
|
506
|
+
summary += "\n\u274C Failed repositories:\n";
|
|
507
|
+
failedRepos.forEach((repo) => {
|
|
508
|
+
summary += ` - ${repo.repository}: ${repo.error}
|
|
509
|
+
`;
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
return summary;
|
|
513
|
+
}
|
|
514
|
+
};
|
|
515
|
+
__publicField(_BatchLabelSync, "DEFAULT_PARALLEL", 3);
|
|
516
|
+
var BatchLabelSync = _BatchLabelSync;
|
|
306
517
|
// Annotate the CommonJS export names for ESM import in node:
|
|
307
518
|
0 && (module.exports = {
|
|
519
|
+
BatchLabelSync,
|
|
308
520
|
GitHubClient,
|
|
309
521
|
GitHubLabelSync
|
|
310
522
|
});
|
package/dist/github/index.mjs
CHANGED
package/dist/index.d.mts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/index.mjs
CHANGED
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
# Batch Sync - 複数リポジトリ一括ラベル管理
|
|
2
|
+
|
|
3
|
+
`labels-config` の Batch Sync 機能を使用すると、複数のGitHubリポジトリに対して一括でラベルを同期できます。
|
|
4
|
+
|
|
5
|
+
## 主要機能
|
|
6
|
+
|
|
7
|
+
### 1. コマンドラインからの一括同期 (`batch-sync`)
|
|
8
|
+
|
|
9
|
+
複数のリポジトリに対して、コマンドラインから直接ラベルを同期できます。
|
|
10
|
+
|
|
11
|
+
#### 組織全体のリポジトリに同期
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# 組織の全リポジトリにテンプレートを適用
|
|
15
|
+
labels-config batch-sync --org your-org --template prod-ja
|
|
16
|
+
|
|
17
|
+
# ドライランで確認
|
|
18
|
+
labels-config batch-sync --org your-org --template prod-ja --dry-run
|
|
19
|
+
|
|
20
|
+
# 特定の言語でフィルタリング
|
|
21
|
+
labels-config batch-sync --org your-org --template react --filter-lang TypeScript
|
|
22
|
+
|
|
23
|
+
# 公開リポジトリのみに適用
|
|
24
|
+
labels-config batch-sync --org your-org --template prod-ja --filter-vis public
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
#### ユーザーの全リポジトリに同期
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# ユーザーの全リポジトリに同期
|
|
31
|
+
labels-config batch-sync --user your-username --template prod-ja
|
|
32
|
+
|
|
33
|
+
# プライベートリポジトリのみ
|
|
34
|
+
labels-config batch-sync --user your-username --template prod-ja --filter-vis private
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
#### 特定のリポジトリリストに同期
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# カスタムラベルファイルを使用
|
|
41
|
+
labels-config batch-sync \
|
|
42
|
+
--repos your-org/repo1,your-org/repo2,your-org/repo3 \
|
|
43
|
+
--file ./custom-labels.json
|
|
44
|
+
|
|
45
|
+
# テンプレートを使用
|
|
46
|
+
labels-config batch-sync \
|
|
47
|
+
--repos your-org/repo1,your-org/repo2 \
|
|
48
|
+
--template prod-ja
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
#### オプション
|
|
52
|
+
|
|
53
|
+
| オプション | 説明 | 例 |
|
|
54
|
+
|-----------|------|-----|
|
|
55
|
+
| `--org <name>` | 組織名 | `--org your-org` |
|
|
56
|
+
| `--user <name>` | ユーザー名 | `--user your-username` |
|
|
57
|
+
| `--repos <list>` | リポジトリリスト(カンマ区切り) | `--repos owner/repo1,owner/repo2` |
|
|
58
|
+
| `--template <name>` | テンプレート名 | `--template prod-ja` |
|
|
59
|
+
| `--file <path>` | カスタムラベルファイル | `--file ./labels.json` |
|
|
60
|
+
| `--filter-lang <lang>` | プログラミング言語でフィルタ | `--filter-lang TypeScript` |
|
|
61
|
+
| `--filter-vis <vis>` | 可視性でフィルタ | `--filter-vis public` |
|
|
62
|
+
| `--parallel <num>` | 並列実行数(デフォルト: 3) | `--parallel 5` |
|
|
63
|
+
| `--dry-run` | ドライラン(実際には変更しない) | `--dry-run` |
|
|
64
|
+
| `--delete-extra` | 設定にないラベルを削除(Replace モード) | `--delete-extra` |
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
### 2. 設定ファイルからの一括同期 (`batch-config`)
|
|
69
|
+
|
|
70
|
+
複雑な一括同期設定を JSON ファイルで定義して実行できます。
|
|
71
|
+
|
|
72
|
+
#### 設定ファイルの作成
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"version": "1.0.0",
|
|
77
|
+
"description": "your-org organization batch label sync",
|
|
78
|
+
"defaults": {
|
|
79
|
+
"template": "prod-ja",
|
|
80
|
+
"mode": "append",
|
|
81
|
+
"parallel": 3
|
|
82
|
+
},
|
|
83
|
+
"targets": [
|
|
84
|
+
{
|
|
85
|
+
"organization": "your-org",
|
|
86
|
+
"filter": {
|
|
87
|
+
"visibility": "public",
|
|
88
|
+
"language": "TypeScript",
|
|
89
|
+
"archived": false
|
|
90
|
+
},
|
|
91
|
+
"template": "react",
|
|
92
|
+
"mode": "append"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"repositories": [
|
|
96
|
+
"your-org/labels-config",
|
|
97
|
+
"your-org/my-project"
|
|
98
|
+
],
|
|
99
|
+
"template": "prod-ja",
|
|
100
|
+
"mode": "replace"
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"user": "your-username",
|
|
104
|
+
"filter": {
|
|
105
|
+
"visibility": "private"
|
|
106
|
+
},
|
|
107
|
+
"file": "./custom-labels.json"
|
|
108
|
+
}
|
|
109
|
+
]
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
#### 設定ファイルの実行
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
# 設定ファイルを実行
|
|
117
|
+
labels-config batch-config batch-config.json
|
|
118
|
+
|
|
119
|
+
# ドライランで確認
|
|
120
|
+
labels-config batch-config batch-config.json --dry-run
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
#### 設定ファイルの構造
|
|
124
|
+
|
|
125
|
+
**ルート要素:**
|
|
126
|
+
|
|
127
|
+
| フィールド | 型 | 必須 | 説明 |
|
|
128
|
+
|-----------|-----|------|------|
|
|
129
|
+
| `version` | string | ✓ | 設定ファイルのバージョン |
|
|
130
|
+
| `description` | string | | 説明 |
|
|
131
|
+
| `defaults` | object | | デフォルト設定 |
|
|
132
|
+
| `targets` | array | ✓ | ターゲット設定のリスト |
|
|
133
|
+
|
|
134
|
+
**defaults オブジェクト:**
|
|
135
|
+
|
|
136
|
+
| フィールド | 型 | デフォルト | 説明 |
|
|
137
|
+
|-----------|-----|-----------|------|
|
|
138
|
+
| `template` | string | | デフォルトテンプレート |
|
|
139
|
+
| `mode` | `"append"` \| `"replace"` | `"append"` | デフォルト同期モード |
|
|
140
|
+
| `parallel` | number | `3` | デフォルト並列実行数 |
|
|
141
|
+
|
|
142
|
+
**target オブジェクト:**
|
|
143
|
+
|
|
144
|
+
| フィールド | 型 | 必須 | 説明 |
|
|
145
|
+
|-----------|-----|------|------|
|
|
146
|
+
| `organization` | string | * | 組織名 |
|
|
147
|
+
| `user` | string | * | ユーザー名 |
|
|
148
|
+
| `repositories` | string[] | * | リポジトリリスト |
|
|
149
|
+
| `template` | string | ** | テンプレート名 |
|
|
150
|
+
| `file` | string | ** | ラベルファイルパス |
|
|
151
|
+
| `mode` | `"append"` \| `"replace"` | | 同期モード |
|
|
152
|
+
| `parallel` | number | | 並列実行数 |
|
|
153
|
+
| `filter` | object | | フィルタ設定 |
|
|
154
|
+
|
|
155
|
+
\* いずれか1つ必須
|
|
156
|
+
\*\* いずれか1つ必須
|
|
157
|
+
|
|
158
|
+
**filter オブジェクト:**
|
|
159
|
+
|
|
160
|
+
| フィールド | 型 | 説明 |
|
|
161
|
+
|-----------|-----|------|
|
|
162
|
+
| `visibility` | `"public"` \| `"private"` \| `"all"` | リポジトリの可視性 |
|
|
163
|
+
| `language` | string | プログラミング言語 |
|
|
164
|
+
| `archived` | boolean | アーカイブ済みリポジトリを含むか |
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## 同期モード
|
|
169
|
+
|
|
170
|
+
### Append モード(デフォルト)
|
|
171
|
+
|
|
172
|
+
- 新しいラベルを追加
|
|
173
|
+
- 既存のラベルを更新
|
|
174
|
+
- 設定にないラベルは**保持**
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
labels-config batch-sync --org your-org --template prod-ja
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Replace モード
|
|
181
|
+
|
|
182
|
+
- 新しいラベルを追加
|
|
183
|
+
- 既存のラベルを更新
|
|
184
|
+
- 設定にないラベルを**削除**
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
labels-config batch-sync --org your-org --template prod-ja --delete-extra
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## 利用例
|
|
193
|
+
|
|
194
|
+
### 例1: 組織の全TypeScriptリポジトリにReactテンプレートを適用
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
labels-config batch-sync \
|
|
198
|
+
--org your-org \
|
|
199
|
+
--template react \
|
|
200
|
+
--filter-lang TypeScript \
|
|
201
|
+
--filter-vis public \
|
|
202
|
+
--dry-run
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### 例2: 複数の設定を一度に実行
|
|
206
|
+
|
|
207
|
+
batch-config.json:
|
|
208
|
+
```json
|
|
209
|
+
{
|
|
210
|
+
"version": "1.0.0",
|
|
211
|
+
"defaults": {
|
|
212
|
+
"parallel": 5
|
|
213
|
+
},
|
|
214
|
+
"targets": [
|
|
215
|
+
{
|
|
216
|
+
"organization": "your-org",
|
|
217
|
+
"filter": { "language": "TypeScript" },
|
|
218
|
+
"template": "react"
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
"organization": "your-org",
|
|
222
|
+
"filter": { "language": "Go" },
|
|
223
|
+
"template": "minimal"
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"repositories": ["your-org/special-project"],
|
|
227
|
+
"file": "./special-labels.json",
|
|
228
|
+
"mode": "replace"
|
|
229
|
+
}
|
|
230
|
+
]
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
実行:
|
|
235
|
+
```bash
|
|
236
|
+
labels-config batch-config batch-config.json
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### 例3: 新規リポジトリへのラベル自動設置(GitHub Actionsと組み合わせ)
|
|
240
|
+
|
|
241
|
+
`.github/workflows/auto-label.yml`:
|
|
242
|
+
```yaml
|
|
243
|
+
name: Auto Label New Repositories
|
|
244
|
+
on:
|
|
245
|
+
repository_dispatch:
|
|
246
|
+
types: [new-repo-created]
|
|
247
|
+
|
|
248
|
+
jobs:
|
|
249
|
+
apply-labels:
|
|
250
|
+
runs-on: ubuntu-latest
|
|
251
|
+
steps:
|
|
252
|
+
- uses: actions/checkout@v4
|
|
253
|
+
|
|
254
|
+
- name: Setup Node.js
|
|
255
|
+
uses: actions/setup-node@v4
|
|
256
|
+
with:
|
|
257
|
+
node-version: '20'
|
|
258
|
+
|
|
259
|
+
- name: Install labels-config
|
|
260
|
+
run: npm install -g @asagiri-design/labels-config
|
|
261
|
+
|
|
262
|
+
- name: Apply labels
|
|
263
|
+
run: |
|
|
264
|
+
labels-config batch-sync \
|
|
265
|
+
--repos ${{ github.event.client_payload.repository }} \
|
|
266
|
+
--template prod-ja
|
|
267
|
+
env:
|
|
268
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## パフォーマンス最適化
|
|
274
|
+
|
|
275
|
+
### 並列処理
|
|
276
|
+
|
|
277
|
+
デフォルトでは3つのリポジトリを並列処理します。`--parallel` オプションで調整可能:
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
# 並列数を増やす(高速化)
|
|
281
|
+
labels-config batch-sync --org your-org --template prod-ja --parallel 10
|
|
282
|
+
|
|
283
|
+
# 並列数を減らす(安定性重視)
|
|
284
|
+
labels-config batch-sync --org your-org --template prod-ja --parallel 1
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### レート制限への対応
|
|
288
|
+
|
|
289
|
+
GitHub API のレート制限を考慮して、並列数を調整してください:
|
|
290
|
+
|
|
291
|
+
- **認証済み**: 5000リクエスト/時間
|
|
292
|
+
- **並列数3**: 約100リポジトリ/分
|
|
293
|
+
- **並列数10**: 約300リポジトリ/分
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## エラーハンドリング
|
|
298
|
+
|
|
299
|
+
### 部分的な失敗
|
|
300
|
+
|
|
301
|
+
一部のリポジトリで失敗しても、他のリポジトリの処理は継続されます:
|
|
302
|
+
|
|
303
|
+
```
|
|
304
|
+
✅ [1/10] your-org/repo1
|
|
305
|
+
❌ [2/10] your-org/repo2: Permission denied
|
|
306
|
+
✅ [3/10] your-org/repo3
|
|
307
|
+
...
|
|
308
|
+
|
|
309
|
+
📊 Batch Sync Summary:
|
|
310
|
+
✅ Successful: 8
|
|
311
|
+
❌ Failed: 2
|
|
312
|
+
|
|
313
|
+
❌ Failed repositories:
|
|
314
|
+
- your-org/repo2: Permission denied
|
|
315
|
+
- your-org/repo5: Repository not found
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### ドライランでの事前確認
|
|
319
|
+
|
|
320
|
+
本番実行前に必ずドライランで確認してください:
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
labels-config batch-sync --org your-org --template prod-ja --dry-run
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## よくある質問
|
|
329
|
+
|
|
330
|
+
### Q: 新規リポジトリ作成時に自動でラベルを設置できますか?
|
|
331
|
+
|
|
332
|
+
A: はい、GitHub Actions と組み合わせることで可能です。上記の「例3」を参照してください。
|
|
333
|
+
|
|
334
|
+
### Q: 既存のラベルを削除せずに追加だけできますか?
|
|
335
|
+
|
|
336
|
+
A: はい、デフォルトの Append モードで可能です(`--delete-extra` を指定しない)。
|
|
337
|
+
|
|
338
|
+
### Q: 組織の全リポジトリに一括適用できますか?
|
|
339
|
+
|
|
340
|
+
A: はい、`--org` オプションで可能です:
|
|
341
|
+
```bash
|
|
342
|
+
labels-config batch-sync --org your-org --template prod-ja
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### Q: 特定の条件でフィルタリングできますか?
|
|
346
|
+
|
|
347
|
+
A: はい、以下のフィルタが利用可能です:
|
|
348
|
+
- プログラミング言語(`--filter-lang`)
|
|
349
|
+
- 可視性(`--filter-vis`)
|
|
350
|
+
- アーカイブ状態(設定ファイルのみ)
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
## トラブルシューティング
|
|
355
|
+
|
|
356
|
+
### 権限エラー
|
|
357
|
+
|
|
358
|
+
```
|
|
359
|
+
Error: Permission denied for your-org/repo1
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
**解決方法:**
|
|
363
|
+
1. `gh auth status` で認証状態を確認
|
|
364
|
+
2. `gh auth refresh` で認証を更新
|
|
365
|
+
3. リポジトリへの管理者権限を確認
|
|
366
|
+
|
|
367
|
+
### レート制限エラー
|
|
368
|
+
|
|
369
|
+
```
|
|
370
|
+
Error: API rate limit exceeded
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
**解決方法:**
|
|
374
|
+
1. 並列数を減らす(`--parallel 1`)
|
|
375
|
+
2. 時間を置いて再実行
|
|
376
|
+
3. GitHub Token の認証状態を確認
|
|
377
|
+
|
|
378
|
+
### リポジトリが見つからない
|
|
379
|
+
|
|
380
|
+
```
|
|
381
|
+
Error: Repository not found: your-org/repo1
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
**解決方法:**
|
|
385
|
+
1. リポジトリ名のスペルを確認
|
|
386
|
+
2. リポジトリへのアクセス権限を確認
|
|
387
|
+
3. `gh repo list your-org` でリポジトリ一覧を確認
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
## 参考資料
|
|
392
|
+
|
|
393
|
+
- [Getting Started](./GETTING_STARTED.md)
|
|
394
|
+
- [API Documentation](./API.md)
|
|
395
|
+
- [Templates](../templates/)
|
|
396
|
+
- [Examples](../examples/)
|