codeowners-git 1.8.0 → 2.0.0
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 +182 -41
- package/dist/cli.js +702 -494
- package/package.json +2 -1
package/dist/cli.js
CHANGED
|
@@ -16080,20 +16080,6 @@ var import_cli_table3 = __toESM(require_table(), 1);
|
|
|
16080
16080
|
var DEFAULT_COLUMN_WIDTH = 50;
|
|
16081
16081
|
var MAX_LINE_LENGTH = 80;
|
|
16082
16082
|
var MAX_PATH_LENGTH = 60;
|
|
16083
|
-
var logFileList = (files, owner) => {
|
|
16084
|
-
if (files.length === 0) {
|
|
16085
|
-
log.info("No matching files found");
|
|
16086
|
-
return;
|
|
16087
|
-
}
|
|
16088
|
-
if (owner) {
|
|
16089
|
-
log.header(`Files owned by ${log.owner(owner)}:`);
|
|
16090
|
-
} else {
|
|
16091
|
-
log.header("Changed files:");
|
|
16092
|
-
}
|
|
16093
|
-
for (const file of files) {
|
|
16094
|
-
log.file(file);
|
|
16095
|
-
}
|
|
16096
|
-
};
|
|
16097
16083
|
var log = {
|
|
16098
16084
|
success: (message) => console.log(source_default.green(`✓ ${message}`)),
|
|
16099
16085
|
error: (message) => console.error(source_default.red(`✗ ${message}`)),
|
|
@@ -16158,15 +16144,15 @@ import { spawn as spawn2 } from "child_process";
|
|
|
16158
16144
|
var git = esm_default();
|
|
16159
16145
|
var getChangedFiles = async () => {
|
|
16160
16146
|
const status = await git.status();
|
|
16161
|
-
return status.files.filter((file) => file.
|
|
16147
|
+
return status.files.filter((file) => file.index !== " " && file.index !== "?").map((file) => file.path);
|
|
16162
16148
|
};
|
|
16163
|
-
var
|
|
16149
|
+
var getUnstagedFiles = async () => {
|
|
16164
16150
|
const status = await git.status();
|
|
16165
|
-
return status.files.filter((file) => file.
|
|
16151
|
+
return status.files.filter((file) => file.working_dir !== " ").map((file) => file.path);
|
|
16166
16152
|
};
|
|
16167
|
-
var
|
|
16168
|
-
const
|
|
16169
|
-
return
|
|
16153
|
+
var hasUnstagedChanges = async () => {
|
|
16154
|
+
const unstagedFiles = await getUnstagedFiles();
|
|
16155
|
+
return unstagedFiles.length > 0;
|
|
16170
16156
|
};
|
|
16171
16157
|
var branchExists = async (branchName) => {
|
|
16172
16158
|
try {
|
|
@@ -16362,6 +16348,50 @@ var extractFilesFromRef = async (ref, files) => {
|
|
|
16362
16348
|
}
|
|
16363
16349
|
};
|
|
16364
16350
|
|
|
16351
|
+
// src/utils/matcher.ts
|
|
16352
|
+
var import_micromatch = __toESM(require_micromatch(), 1);
|
|
16353
|
+
var normalizeForMatching = (value) => {
|
|
16354
|
+
return value.replace(/\//g, "");
|
|
16355
|
+
};
|
|
16356
|
+
var matchOwnerPattern = (owner, patterns) => {
|
|
16357
|
+
if (!patterns || !patterns.trim())
|
|
16358
|
+
return false;
|
|
16359
|
+
const normalizedOwner = normalizeForMatching(owner);
|
|
16360
|
+
const normalizedPatterns = patterns.split(",").map((p) => normalizeForMatching(p.trim())).filter((p) => p.length > 0);
|
|
16361
|
+
return import_micromatch.default.isMatch(normalizedOwner, normalizedPatterns);
|
|
16362
|
+
};
|
|
16363
|
+
var matchOwners = (owners, patterns) => {
|
|
16364
|
+
if (!patterns || !patterns.trim())
|
|
16365
|
+
return false;
|
|
16366
|
+
const normalizedOwners = owners.map(normalizeForMatching);
|
|
16367
|
+
const normalizedPatterns = patterns.split(",").map((p) => normalizeForMatching(p.trim())).filter((p) => p.length > 0);
|
|
16368
|
+
return import_micromatch.default(normalizedOwners, normalizedPatterns).length > 0;
|
|
16369
|
+
};
|
|
16370
|
+
var matchOwnersExclusive = (owners, patterns) => {
|
|
16371
|
+
if (!patterns || !patterns.trim())
|
|
16372
|
+
return false;
|
|
16373
|
+
if (owners.length === 0)
|
|
16374
|
+
return false;
|
|
16375
|
+
return owners.every((owner) => matchOwnerPattern(owner, patterns));
|
|
16376
|
+
};
|
|
16377
|
+
var filterByPathPatterns = (files, pattern) => {
|
|
16378
|
+
if (!pattern || !pattern.trim())
|
|
16379
|
+
return files;
|
|
16380
|
+
let finalPattern = pattern.trim();
|
|
16381
|
+
if (finalPattern === ".") {
|
|
16382
|
+
finalPattern = "**";
|
|
16383
|
+
} else if (finalPattern.endsWith("/")) {
|
|
16384
|
+
finalPattern = `${finalPattern}**`;
|
|
16385
|
+
} else {
|
|
16386
|
+
const lastSegment = finalPattern.split("/").pop() || "";
|
|
16387
|
+
const looksLikeFile = /\.[^*?[\]{}!/]+$/.test(lastSegment);
|
|
16388
|
+
if (!looksLikeFile) {
|
|
16389
|
+
finalPattern = `${finalPattern}/**`;
|
|
16390
|
+
}
|
|
16391
|
+
}
|
|
16392
|
+
return import_micromatch.default(files, [finalPattern], { dot: true });
|
|
16393
|
+
};
|
|
16394
|
+
|
|
16365
16395
|
// src/utils/codeowners.ts
|
|
16366
16396
|
var codeowners;
|
|
16367
16397
|
var getCodeownersInstance = () => {
|
|
@@ -16381,47 +16411,101 @@ var getOwner = (filePath) => {
|
|
|
16381
16411
|
const owner = instance.getOwner(filePath);
|
|
16382
16412
|
return owner;
|
|
16383
16413
|
};
|
|
16384
|
-
var getOwnerFiles = async (
|
|
16385
|
-
|
|
16414
|
+
var getOwnerFiles = async (ownerPattern, includeUnowned = false, pathPattern, exclusive = false, coOwned = false) => {
|
|
16415
|
+
let changedFiles = await getChangedFiles();
|
|
16416
|
+
changedFiles = filterByPathPatterns(changedFiles, pathPattern);
|
|
16386
16417
|
return changedFiles.filter((file) => {
|
|
16387
16418
|
const owners = getOwner(file);
|
|
16388
16419
|
if (includeUnowned && owners.length === 0) {
|
|
16389
16420
|
return true;
|
|
16390
16421
|
}
|
|
16391
|
-
|
|
16392
|
-
|
|
16393
|
-
}
|
|
16394
|
-
|
|
16395
|
-
|
|
16396
|
-
|
|
16397
|
-
|
|
16398
|
-
if (!patterns || !patterns.trim())
|
|
16399
|
-
return false;
|
|
16400
|
-
const normalizedOwners = owners.map((owner) => {
|
|
16401
|
-
return owner.replace(/\//g, "");
|
|
16422
|
+
if (coOwned && owners.length < 2) {
|
|
16423
|
+
return false;
|
|
16424
|
+
}
|
|
16425
|
+
if (exclusive) {
|
|
16426
|
+
return matchOwnersExclusive(owners, ownerPattern);
|
|
16427
|
+
}
|
|
16428
|
+
return owners.some((owner) => matchOwnerPattern(owner, ownerPattern));
|
|
16402
16429
|
});
|
|
16403
|
-
const normalizedPatterns = patterns.replace(/\//g, "").split(",");
|
|
16404
|
-
const matches = import_micromatch.default(normalizedOwners, normalizedPatterns);
|
|
16405
|
-
return matches.length > 0;
|
|
16406
16430
|
};
|
|
16407
16431
|
|
|
16408
16432
|
// src/commands/list.ts
|
|
16409
16433
|
var listCodeowners = async (options) => {
|
|
16410
16434
|
try {
|
|
16411
|
-
if (
|
|
16412
|
-
const
|
|
16413
|
-
|
|
16414
|
-
|
|
16415
|
-
|
|
16416
|
-
|
|
16417
|
-
|
|
16418
|
-
|
|
16419
|
-
|
|
16420
|
-
|
|
16421
|
-
|
|
16422
|
-
|
|
16423
|
-
|
|
16435
|
+
if (await hasUnstagedChanges()) {
|
|
16436
|
+
const unstagedFiles = await getUnstagedFiles();
|
|
16437
|
+
log.warn("Warning: Unstaged changes detected (these will be ignored):");
|
|
16438
|
+
unstagedFiles.forEach((file) => log.warn(` - ${file}`));
|
|
16439
|
+
log.info(`
|
|
16440
|
+
Only staged files will be processed.`);
|
|
16441
|
+
log.info("To stage files: git add <file>");
|
|
16442
|
+
log.info("");
|
|
16443
|
+
}
|
|
16444
|
+
let changedFiles = await getChangedFiles();
|
|
16445
|
+
changedFiles = filterByPathPatterns(changedFiles, options.pathPattern);
|
|
16446
|
+
const filesWithOwners = changedFiles.map((file) => ({
|
|
16447
|
+
file,
|
|
16448
|
+
owners: getOwner(file)
|
|
16449
|
+
}));
|
|
16450
|
+
let filteredFiles = filesWithOwners;
|
|
16451
|
+
if (options.exclusive && !options.include) {
|
|
16452
|
+
filteredFiles = filesWithOwners.filter(({ owners }) => owners.length === 1);
|
|
16453
|
+
}
|
|
16454
|
+
if (options.coOwned && !options.include) {
|
|
16455
|
+
filteredFiles = filesWithOwners.filter(({ owners }) => owners.length > 1);
|
|
16456
|
+
}
|
|
16457
|
+
if (options.include) {
|
|
16458
|
+
const patterns = options.include;
|
|
16459
|
+
const matchFn = options.exclusive ? matchOwnersExclusive : matchOwners;
|
|
16460
|
+
filteredFiles = filesWithOwners.filter(({ owners }) => {
|
|
16461
|
+
if (options.coOwned && owners.length < 2) {
|
|
16462
|
+
return false;
|
|
16463
|
+
}
|
|
16464
|
+
return matchFn(owners, patterns);
|
|
16465
|
+
});
|
|
16466
|
+
}
|
|
16467
|
+
if (options.group) {
|
|
16468
|
+
const ownerGroups = new Map;
|
|
16469
|
+
for (const { file, owners } of filteredFiles) {
|
|
16470
|
+
if (owners.length === 0) {
|
|
16471
|
+
const unownedFiles = ownerGroups.get("(unowned)") || [];
|
|
16472
|
+
unownedFiles.push(file);
|
|
16473
|
+
ownerGroups.set("(unowned)", unownedFiles);
|
|
16474
|
+
} else {
|
|
16475
|
+
for (const owner of owners) {
|
|
16476
|
+
const files = ownerGroups.get(owner) || [];
|
|
16477
|
+
files.push(file);
|
|
16478
|
+
ownerGroups.set(owner, files);
|
|
16479
|
+
}
|
|
16480
|
+
}
|
|
16481
|
+
}
|
|
16482
|
+
const sortedOwners = Array.from(ownerGroups.keys()).sort((a, b) => {
|
|
16483
|
+
if (a === "(unowned)")
|
|
16484
|
+
return 1;
|
|
16485
|
+
if (b === "(unowned)")
|
|
16486
|
+
return -1;
|
|
16487
|
+
return a.localeCompare(b);
|
|
16488
|
+
});
|
|
16489
|
+
for (const owner of sortedOwners) {
|
|
16490
|
+
const files = ownerGroups.get(owner) || [];
|
|
16491
|
+
const tableData = files.map((file, index) => ({
|
|
16492
|
+
No: index + 1,
|
|
16493
|
+
File: file
|
|
16494
|
+
}));
|
|
16495
|
+
log.header(`Files owned by ${log.owner(owner)}:`);
|
|
16496
|
+
log.formattedTable(tableData, [
|
|
16497
|
+
{
|
|
16498
|
+
name: "No",
|
|
16499
|
+
width: 8
|
|
16500
|
+
},
|
|
16501
|
+
{
|
|
16502
|
+
name: "File",
|
|
16503
|
+
width: 100,
|
|
16504
|
+
formatter: (value) => log.smartFile(value)
|
|
16505
|
+
}
|
|
16506
|
+
]);
|
|
16424
16507
|
}
|
|
16508
|
+
} else {
|
|
16425
16509
|
const tableData = filteredFiles.map(({ file, owners }, index) => ({
|
|
16426
16510
|
No: index + 1,
|
|
16427
16511
|
File: file,
|
|
@@ -16550,6 +16634,9 @@ var createPRWithTemplate = async (title, branchName, options = {}) => {
|
|
|
16550
16634
|
});
|
|
16551
16635
|
};
|
|
16552
16636
|
|
|
16637
|
+
// src/commands/branch.ts
|
|
16638
|
+
var import_cli_table32 = __toESM(require_table(), 1);
|
|
16639
|
+
|
|
16553
16640
|
// src/utils/state.ts
|
|
16554
16641
|
import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync, unlinkSync } from "fs";
|
|
16555
16642
|
import { join } from "path";
|
|
@@ -16694,8 +16781,9 @@ var branch = async (options) => {
|
|
|
16694
16781
|
let pushed = false;
|
|
16695
16782
|
let operationState = options.operationState || null;
|
|
16696
16783
|
const isSubOperation = !!options.operationState;
|
|
16784
|
+
let autoRecoverySucceeded = false;
|
|
16697
16785
|
try {
|
|
16698
|
-
if (!options.branch || !options.message || !options.
|
|
16786
|
+
if (!options.branch || !options.message || !options.include) {
|
|
16699
16787
|
throw new Error("Missing required options for branch creation");
|
|
16700
16788
|
}
|
|
16701
16789
|
if ((options.pr || options.draftPr) && !options.push) {
|
|
@@ -16704,19 +16792,14 @@ var branch = async (options) => {
|
|
|
16704
16792
|
if (options.pr && options.draftPr) {
|
|
16705
16793
|
throw new Error("Cannot use both --pr and --draft-pr options");
|
|
16706
16794
|
}
|
|
16707
|
-
if (await
|
|
16708
|
-
const
|
|
16709
|
-
log.
|
|
16710
|
-
log.
|
|
16711
|
-
Staged files detected:`);
|
|
16712
|
-
stagedFiles.forEach((file) => log.info(` - ${file}`));
|
|
16713
|
-
log.info(`
|
|
16714
|
-
To unstage files, run:`);
|
|
16715
|
-
log.info(" git restore --staged .");
|
|
16795
|
+
if (await hasUnstagedChanges()) {
|
|
16796
|
+
const unstagedFiles = await getUnstagedFiles();
|
|
16797
|
+
log.warn("Warning: Unstaged changes detected (these will be ignored):");
|
|
16798
|
+
unstagedFiles.forEach((file) => log.warn(` - ${file}`));
|
|
16716
16799
|
log.info(`
|
|
16717
|
-
|
|
16718
|
-
log.info("
|
|
16719
|
-
|
|
16800
|
+
Only staged files will be processed.`);
|
|
16801
|
+
log.info("To stage files: git add <file>");
|
|
16802
|
+
log.info("");
|
|
16720
16803
|
}
|
|
16721
16804
|
log.info(options.append ? "Starting branch update process..." : "Starting branch creation process...");
|
|
16722
16805
|
originalBranch = await getCurrentBranch();
|
|
@@ -16733,13 +16816,13 @@ Or to unstage specific files:`);
|
|
|
16733
16816
|
});
|
|
16734
16817
|
log.info(`Operation ID: ${operationState.id}`);
|
|
16735
16818
|
}
|
|
16736
|
-
filesToCommit = await getOwnerFiles(options.
|
|
16819
|
+
filesToCommit = await getOwnerFiles(options.include, options.isDefaultOwner || false, options.pathPattern, options.exclusive || false, options.coOwned || false);
|
|
16737
16820
|
if (filesToCommit.length <= 0) {
|
|
16738
|
-
log.warn(`No files found for ${options.
|
|
16821
|
+
log.warn(`No files found for ${options.include}. Skipping branch creation.`);
|
|
16739
16822
|
return {
|
|
16740
16823
|
success: false,
|
|
16741
16824
|
branchName: options.branch,
|
|
16742
|
-
owner: options.
|
|
16825
|
+
owner: options.include,
|
|
16743
16826
|
files: [],
|
|
16744
16827
|
pushed: false,
|
|
16745
16828
|
error: "No files found for this owner"
|
|
@@ -16759,7 +16842,7 @@ Or to unstage specific files:`);
|
|
|
16759
16842
|
});
|
|
16760
16843
|
updateBranchState(operationState.id, options.branch, {
|
|
16761
16844
|
name: options.branch,
|
|
16762
|
-
owner: options.
|
|
16845
|
+
owner: options.include || "",
|
|
16763
16846
|
files: filesToCommit,
|
|
16764
16847
|
created: false,
|
|
16765
16848
|
committed: false,
|
|
@@ -16848,15 +16931,30 @@ Or to unstage specific files:`);
|
|
|
16848
16931
|
if (operationState && !isSubOperation) {
|
|
16849
16932
|
completeOperation(operationState.id, true);
|
|
16850
16933
|
}
|
|
16851
|
-
if (
|
|
16852
|
-
log.
|
|
16853
|
-
|
|
16854
|
-
|
|
16934
|
+
if (!isSubOperation) {
|
|
16935
|
+
log.header(options.append ? "Branch update summary" : "Branch creation summary");
|
|
16936
|
+
const table = new import_cli_table32.default({
|
|
16937
|
+
head: ["Status", "Owner", "Branch", "Files", "Pushed", "PR"],
|
|
16938
|
+
colWidths: [10, 25, 35, 10, 10, 50],
|
|
16939
|
+
wordWrap: true
|
|
16940
|
+
});
|
|
16941
|
+
table.push([
|
|
16942
|
+
"✓",
|
|
16943
|
+
options.include,
|
|
16944
|
+
options.branch,
|
|
16945
|
+
`${filesToCommit.length} file${filesToCommit.length !== 1 ? "s" : ""}`,
|
|
16946
|
+
pushed ? "✓" : "-",
|
|
16947
|
+
prUrl || "-"
|
|
16948
|
+
]);
|
|
16949
|
+
console.log(table.toString());
|
|
16950
|
+
console.log(`
|
|
16951
|
+
Files committed:`);
|
|
16952
|
+
filesToCommit.forEach((file) => console.log(` - ${file}`));
|
|
16855
16953
|
}
|
|
16856
16954
|
return {
|
|
16857
16955
|
success: true,
|
|
16858
16956
|
branchName: options.branch,
|
|
16859
|
-
owner: options.
|
|
16957
|
+
owner: options.include,
|
|
16860
16958
|
files: filesToCommit,
|
|
16861
16959
|
pushed,
|
|
16862
16960
|
prUrl,
|
|
@@ -16902,6 +17000,17 @@ Or to unstage specific files:`);
|
|
|
16902
17000
|
}
|
|
16903
17001
|
} catch (cleanupError) {
|
|
16904
17002
|
log.error(`Error during cleanup: ${cleanupError}`);
|
|
17003
|
+
throw operationError;
|
|
17004
|
+
}
|
|
17005
|
+
autoRecoverySucceeded = true;
|
|
17006
|
+
log.success("Auto-recovery completed successfully");
|
|
17007
|
+
if (operationState && !isSubOperation) {
|
|
17008
|
+
deleteOperationState(operationState.id);
|
|
17009
|
+
}
|
|
17010
|
+
} else {
|
|
17011
|
+
autoRecoverySucceeded = true;
|
|
17012
|
+
if (operationState && !isSubOperation) {
|
|
17013
|
+
deleteOperationState(operationState.id);
|
|
16905
17014
|
}
|
|
16906
17015
|
}
|
|
16907
17016
|
throw operationError;
|
|
@@ -16912,7 +17021,7 @@ Or to unstage specific files:`);
|
|
|
16912
17021
|
return {
|
|
16913
17022
|
success: false,
|
|
16914
17023
|
branchName: options.branch ?? "",
|
|
16915
|
-
owner: options.
|
|
17024
|
+
owner: options.include ?? "",
|
|
16916
17025
|
files: filesToCommit,
|
|
16917
17026
|
pushed,
|
|
16918
17027
|
prUrl,
|
|
@@ -16920,9 +17029,9 @@ Or to unstage specific files:`);
|
|
|
16920
17029
|
error: String(err)
|
|
16921
17030
|
};
|
|
16922
17031
|
}
|
|
16923
|
-
if (operationState) {
|
|
17032
|
+
if (operationState && !autoRecoverySucceeded) {
|
|
16924
17033
|
log.info(`
|
|
16925
|
-
|
|
17034
|
+
Auto-recovery failed. Manual recovery options:`);
|
|
16926
17035
|
log.info(` 1. Run 'codeowners-git recover --id ${operationState.id}' to clean up and return to original branch`);
|
|
16927
17036
|
log.info(` 2. Run 'codeowners-git recover --id ${operationState.id} --keep-branches' to return without deleting branches`);
|
|
16928
17037
|
log.info(` 3. Run 'codeowners-git recover --list' to see all incomplete operations`);
|
|
@@ -16943,422 +17052,157 @@ Recovery options:`);
|
|
|
16943
17052
|
}
|
|
16944
17053
|
};
|
|
16945
17054
|
|
|
16946
|
-
//
|
|
16947
|
-
var
|
|
16948
|
-
var
|
|
16949
|
-
var
|
|
16950
|
-
|
|
16951
|
-
|
|
16952
|
-
|
|
16953
|
-
|
|
16954
|
-
|
|
16955
|
-
|
|
16956
|
-
|
|
16957
|
-
|
|
16958
|
-
|
|
16959
|
-
|
|
16960
|
-
|
|
16961
|
-
|
|
16962
|
-
|
|
17055
|
+
// node_modules/@inquirer/core/dist/esm/lib/key.js
|
|
17056
|
+
var isUpKey = (key) => key.name === "up" || key.name === "k" || key.ctrl && key.name === "p";
|
|
17057
|
+
var isDownKey = (key) => key.name === "down" || key.name === "j" || key.ctrl && key.name === "n";
|
|
17058
|
+
var isBackspaceKey = (key) => key.name === "backspace";
|
|
17059
|
+
var isNumberKey = (key) => "123456789".includes(key.name);
|
|
17060
|
+
var isEnterKey = (key) => key.name === "enter" || key.name === "return";
|
|
17061
|
+
// node_modules/@inquirer/core/dist/esm/lib/errors.js
|
|
17062
|
+
class AbortPromptError extends Error {
|
|
17063
|
+
name = "AbortPromptError";
|
|
17064
|
+
message = "Prompt was aborted";
|
|
17065
|
+
constructor(options) {
|
|
17066
|
+
super();
|
|
17067
|
+
this.cause = options?.cause;
|
|
17068
|
+
}
|
|
17069
|
+
}
|
|
17070
|
+
|
|
17071
|
+
class CancelPromptError extends Error {
|
|
17072
|
+
name = "CancelPromptError";
|
|
17073
|
+
message = "Prompt was canceled";
|
|
17074
|
+
}
|
|
17075
|
+
|
|
17076
|
+
class ExitPromptError extends Error {
|
|
17077
|
+
name = "ExitPromptError";
|
|
17078
|
+
}
|
|
17079
|
+
|
|
17080
|
+
class HookError extends Error {
|
|
17081
|
+
name = "HookError";
|
|
17082
|
+
}
|
|
17083
|
+
|
|
17084
|
+
class ValidationError extends Error {
|
|
17085
|
+
name = "ValidationError";
|
|
17086
|
+
}
|
|
17087
|
+
// node_modules/@inquirer/core/dist/esm/lib/use-prefix.js
|
|
17088
|
+
import { AsyncResource as AsyncResource2 } from "node:async_hooks";
|
|
17089
|
+
|
|
17090
|
+
// node_modules/@inquirer/core/dist/esm/lib/hook-engine.js
|
|
17091
|
+
import { AsyncLocalStorage, AsyncResource } from "node:async_hooks";
|
|
17092
|
+
var hookStorage = new AsyncLocalStorage;
|
|
17093
|
+
function createStore(rl) {
|
|
17094
|
+
const store = {
|
|
17095
|
+
rl,
|
|
17096
|
+
hooks: [],
|
|
17097
|
+
hooksCleanup: [],
|
|
17098
|
+
hooksEffect: [],
|
|
17099
|
+
index: 0,
|
|
17100
|
+
handleChange() {}
|
|
17101
|
+
};
|
|
17102
|
+
return store;
|
|
17103
|
+
}
|
|
17104
|
+
function withHooks(rl, cb) {
|
|
17105
|
+
const store = createStore(rl);
|
|
17106
|
+
return hookStorage.run(store, () => {
|
|
17107
|
+
function cycle(render) {
|
|
17108
|
+
store.handleChange = () => {
|
|
17109
|
+
store.index = 0;
|
|
17110
|
+
render();
|
|
17111
|
+
};
|
|
17112
|
+
store.handleChange();
|
|
16963
17113
|
}
|
|
16964
|
-
|
|
16965
|
-
|
|
16966
|
-
|
|
16967
|
-
|
|
16968
|
-
|
|
16969
|
-
|
|
16970
|
-
|
|
16971
|
-
|
|
16972
|
-
|
|
16973
|
-
|
|
16974
|
-
|
|
16975
|
-
|
|
16976
|
-
|
|
17114
|
+
return cb(cycle);
|
|
17115
|
+
});
|
|
17116
|
+
}
|
|
17117
|
+
function getStore() {
|
|
17118
|
+
const store = hookStorage.getStore();
|
|
17119
|
+
if (!store) {
|
|
17120
|
+
throw new HookError("[Inquirer] Hook functions can only be called from within a prompt");
|
|
17121
|
+
}
|
|
17122
|
+
return store;
|
|
17123
|
+
}
|
|
17124
|
+
function readline() {
|
|
17125
|
+
return getStore().rl;
|
|
17126
|
+
}
|
|
17127
|
+
function withUpdates(fn) {
|
|
17128
|
+
const wrapped = (...args) => {
|
|
17129
|
+
const store = getStore();
|
|
17130
|
+
let shouldUpdate = false;
|
|
17131
|
+
const oldHandleChange = store.handleChange;
|
|
17132
|
+
store.handleChange = () => {
|
|
17133
|
+
shouldUpdate = true;
|
|
17134
|
+
};
|
|
17135
|
+
const returnValue = fn(...args);
|
|
17136
|
+
if (shouldUpdate) {
|
|
17137
|
+
oldHandleChange();
|
|
16977
17138
|
}
|
|
16978
|
-
|
|
16979
|
-
|
|
16980
|
-
|
|
16981
|
-
|
|
16982
|
-
|
|
16983
|
-
|
|
16984
|
-
|
|
16985
|
-
|
|
16986
|
-
|
|
16987
|
-
|
|
17139
|
+
store.handleChange = oldHandleChange;
|
|
17140
|
+
return returnValue;
|
|
17141
|
+
};
|
|
17142
|
+
return AsyncResource.bind(wrapped);
|
|
17143
|
+
}
|
|
17144
|
+
function withPointer(cb) {
|
|
17145
|
+
const store = getStore();
|
|
17146
|
+
const { index } = store;
|
|
17147
|
+
const pointer = {
|
|
17148
|
+
get() {
|
|
17149
|
+
return store.hooks[index];
|
|
17150
|
+
},
|
|
17151
|
+
set(value) {
|
|
17152
|
+
store.hooks[index] = value;
|
|
17153
|
+
},
|
|
17154
|
+
initialized: index in store.hooks
|
|
17155
|
+
};
|
|
17156
|
+
const returnValue = cb(pointer);
|
|
17157
|
+
store.index++;
|
|
17158
|
+
return returnValue;
|
|
17159
|
+
}
|
|
17160
|
+
function handleChange() {
|
|
17161
|
+
getStore().handleChange();
|
|
17162
|
+
}
|
|
17163
|
+
var effectScheduler = {
|
|
17164
|
+
queue(cb) {
|
|
17165
|
+
const store = getStore();
|
|
17166
|
+
const { index } = store;
|
|
17167
|
+
store.hooksEffect.push(() => {
|
|
17168
|
+
store.hooksCleanup[index]?.();
|
|
17169
|
+
const cleanFn = cb(readline());
|
|
17170
|
+
if (cleanFn != null && typeof cleanFn !== "function") {
|
|
17171
|
+
throw new ValidationError("useEffect return value must be a cleanup function or nothing.");
|
|
17172
|
+
}
|
|
17173
|
+
store.hooksCleanup[index] = cleanFn;
|
|
16988
17174
|
});
|
|
16989
|
-
|
|
16990
|
-
|
|
16991
|
-
|
|
16992
|
-
|
|
16993
|
-
|
|
16994
|
-
|
|
16995
|
-
|
|
16996
|
-
|
|
16997
|
-
|
|
16998
|
-
|
|
16999
|
-
|
|
17000
|
-
|
|
17001
|
-
|
|
17002
|
-
|
|
17003
|
-
|
|
17004
|
-
|
|
17005
|
-
|
|
17006
|
-
|
|
17007
|
-
|
|
17008
|
-
|
|
17009
|
-
|
|
17010
|
-
|
|
17011
|
-
|
|
17012
|
-
|
|
17013
|
-
|
|
17014
|
-
|
|
17015
|
-
|
|
17016
|
-
|
|
17017
|
-
}
|
|
17018
|
-
if (
|
|
17019
|
-
|
|
17020
|
-
if (options.ignore) {
|
|
17021
|
-
const ignorePatterns = options.ignore.split(",").map((p) => p.trim());
|
|
17022
|
-
codeowners2 = codeowners2.filter((owner) => !import_micromatch2.default.isMatch(owner, ignorePatterns));
|
|
17023
|
-
log.info(`Filtered out ${originalCount - codeowners2.length} codeowners using ignore patterns: ${ignorePatterns.join(", ")}`);
|
|
17024
|
-
} else if (options.include) {
|
|
17025
|
-
const includePatterns = options.include.split(",").map((p) => p.trim());
|
|
17026
|
-
codeowners2 = codeowners2.filter((owner) => import_micromatch2.default.isMatch(owner, includePatterns));
|
|
17027
|
-
log.info(`Filtered to ${codeowners2.length} codeowners using include patterns: ${includePatterns.join(", ")}`);
|
|
17028
|
-
}
|
|
17029
|
-
if (codeowners2.length === 0) {
|
|
17030
|
-
log.warn("No codeowners left after filtering");
|
|
17031
|
-
return;
|
|
17032
|
-
}
|
|
17033
|
-
log.info(`Processing ${codeowners2.length} codeowners after filtering: ${codeowners2.join(", ")}`);
|
|
17034
|
-
}
|
|
17035
|
-
const results = [];
|
|
17036
|
-
for (const owner of codeowners2) {
|
|
17037
|
-
const sanitizedOwner = owner.replace(/[^a-zA-Z0-9-_@]/g, "-").replace(/^@/, "");
|
|
17038
|
-
const branchName = `${options.branch}/${sanitizedOwner}`;
|
|
17039
|
-
const commitMessage = `${options.message} - ${owner}`;
|
|
17040
|
-
log.info(options.append ? `Updating branch for ${owner}...` : `Creating branch for ${owner}...`);
|
|
17041
|
-
const result = await branch({
|
|
17042
|
-
owner,
|
|
17043
|
-
branch: branchName,
|
|
17044
|
-
message: commitMessage,
|
|
17045
|
-
verify: options.verify,
|
|
17046
|
-
push: options.push,
|
|
17047
|
-
remote: options.remote,
|
|
17048
|
-
upstream: options.upstream,
|
|
17049
|
-
force: options.force,
|
|
17050
|
-
keepBranchOnFailure: options.keepBranchOnFailure,
|
|
17051
|
-
isDefaultOwner: owner === options.defaultOwner,
|
|
17052
|
-
append: options.append,
|
|
17053
|
-
pr: options.pr,
|
|
17054
|
-
draftPr: options.draftPr,
|
|
17055
|
-
operationState: operationState || undefined
|
|
17056
|
-
});
|
|
17057
|
-
results.push(result);
|
|
17058
|
-
}
|
|
17059
|
-
const successCount = results.filter((r) => r.success).length;
|
|
17060
|
-
const failureCount = results.filter((r) => !r.success).length;
|
|
17061
|
-
log.header(options.append ? "Multi-branch update summary" : "Multi-branch creation summary");
|
|
17062
|
-
log.info(options.append ? `Successfully updated ${successCount} of ${codeowners2.length} branches` : `Successfully created ${successCount} of ${codeowners2.length} branches`);
|
|
17063
|
-
if (failureCount > 0) {
|
|
17064
|
-
log.error(`Failed: ${failureCount} branches`);
|
|
17065
|
-
}
|
|
17066
|
-
console.log("");
|
|
17067
|
-
const table = new import_cli_table32.default({
|
|
17068
|
-
head: ["Status", "Owner", "Branch", "Files", "Pushed", "PR"],
|
|
17069
|
-
colWidths: [10, 20, 40, 10, 10, 50],
|
|
17070
|
-
wordWrap: true
|
|
17071
|
-
});
|
|
17072
|
-
for (const result of results) {
|
|
17073
|
-
const status = result.success ? "✓" : "✗";
|
|
17074
|
-
const fileCount = result.files.length;
|
|
17075
|
-
const pushedStatus = result.pushed ? "✓" : "-";
|
|
17076
|
-
const prInfo = result.prUrl ? result.prUrl : result.error && result.error.includes("PR creation failed") ? "Failed" : "-";
|
|
17077
|
-
table.push([
|
|
17078
|
-
status,
|
|
17079
|
-
result.owner,
|
|
17080
|
-
result.branchName,
|
|
17081
|
-
`${fileCount} file${fileCount !== 1 ? "s" : ""}`,
|
|
17082
|
-
pushedStatus,
|
|
17083
|
-
prInfo
|
|
17084
|
-
]);
|
|
17085
|
-
}
|
|
17086
|
-
console.log(table.toString());
|
|
17087
|
-
if (results.length > 0) {
|
|
17088
|
-
console.log(`
|
|
17089
|
-
Files by branch:`);
|
|
17090
|
-
for (const result of results) {
|
|
17091
|
-
if (result.success && result.files.length > 0) {
|
|
17092
|
-
console.log(`
|
|
17093
|
-
${result.branchName} (${result.owner}):`);
|
|
17094
|
-
result.files.forEach((file) => console.log(` - ${file}`));
|
|
17095
|
-
}
|
|
17096
|
-
}
|
|
17097
|
-
}
|
|
17098
|
-
const errors = results.filter((r) => r.error);
|
|
17099
|
-
if (errors.length > 0) {
|
|
17100
|
-
console.log(`
|
|
17101
|
-
Errors:`);
|
|
17102
|
-
errors.forEach((result) => {
|
|
17103
|
-
console.log(`
|
|
17104
|
-
${result.branchName} (${result.owner}):`);
|
|
17105
|
-
console.log(` ${result.error}`);
|
|
17106
|
-
});
|
|
17107
|
-
}
|
|
17108
|
-
if (operationState) {
|
|
17109
|
-
completeOperation(operationState.id, true);
|
|
17110
|
-
}
|
|
17111
|
-
} catch (err) {
|
|
17112
|
-
log.error(`Multi-branch operation failed: ${err}`);
|
|
17113
|
-
if (operationState) {
|
|
17114
|
-
failOperation(operationState.id, String(err));
|
|
17115
|
-
log.info(`
|
|
17116
|
-
Recovery options:`);
|
|
17117
|
-
log.info(` 1. Run 'codeowners-git recover --id ${operationState.id}' to clean up and return to original branch`);
|
|
17118
|
-
log.info(` 2. Run 'codeowners-git recover --id ${operationState.id} --keep-branches' to return without deleting branches`);
|
|
17119
|
-
log.info(` 3. Run 'codeowners-git recover --list' to see all incomplete operations`);
|
|
17120
|
-
}
|
|
17121
|
-
process.exit(1);
|
|
17122
|
-
}
|
|
17123
|
-
};
|
|
17124
|
-
|
|
17125
|
-
// src/commands/extract.ts
|
|
17126
|
-
var import_micromatch3 = __toESM(require_micromatch(), 1);
|
|
17127
|
-
var extract = async (options) => {
|
|
17128
|
-
try {
|
|
17129
|
-
if (!options.source) {
|
|
17130
|
-
log.error("Missing required option: --source");
|
|
17131
|
-
log.info(`
|
|
17132
|
-
Usage:`);
|
|
17133
|
-
log.info(" cg extract -s <branch-or-commit>");
|
|
17134
|
-
log.info(`
|
|
17135
|
-
Examples:`);
|
|
17136
|
-
log.info(" cg extract -s feature/other-branch");
|
|
17137
|
-
log.info(" cg extract -s feature/other-branch -o '@team-*'");
|
|
17138
|
-
log.info(" cg extract -s abc123def --compare-main");
|
|
17139
|
-
process.exit(1);
|
|
17140
|
-
}
|
|
17141
|
-
if (await hasStagedChanges()) {
|
|
17142
|
-
const stagedFiles = await getStagedFiles();
|
|
17143
|
-
log.error("Changes need to be unstaged in order for this to work.");
|
|
17144
|
-
log.info(`
|
|
17145
|
-
Staged files detected:`);
|
|
17146
|
-
stagedFiles.forEach((file) => log.info(` - ${file}`));
|
|
17147
|
-
log.info(`
|
|
17148
|
-
To unstage files, run:`);
|
|
17149
|
-
log.info(" git restore --staged .");
|
|
17150
|
-
log.info(`
|
|
17151
|
-
Or to unstage specific files:`);
|
|
17152
|
-
log.info(" git restore --staged <file>");
|
|
17153
|
-
process.exit(1);
|
|
17154
|
-
}
|
|
17155
|
-
log.info("Starting file extraction process...");
|
|
17156
|
-
let compareTarget;
|
|
17157
|
-
if (options.compareMain) {
|
|
17158
|
-
compareTarget = await getDefaultBranch();
|
|
17159
|
-
log.info(`Comparing ${options.source} against ${compareTarget}...`);
|
|
17160
|
-
} else {
|
|
17161
|
-
const baseBranch = await getBaseBranch(options.source);
|
|
17162
|
-
compareTarget = baseBranch;
|
|
17163
|
-
log.info(`Detected base branch: ${baseBranch}`);
|
|
17164
|
-
log.info(`Extracting changes from ${options.source}...`);
|
|
17165
|
-
}
|
|
17166
|
-
const changedFiles = await getChangedFilesBetween(options.source, compareTarget);
|
|
17167
|
-
if (changedFiles.length === 0) {
|
|
17168
|
-
log.warn(`No changed files found in ${options.source}`);
|
|
17169
|
-
return;
|
|
17170
|
-
}
|
|
17171
|
-
log.info(`Found ${changedFiles.length} changed file${changedFiles.length !== 1 ? "s" : ""}`);
|
|
17172
|
-
let filesToExtract = changedFiles;
|
|
17173
|
-
if (options.owner) {
|
|
17174
|
-
log.info(`Filtering files by owner pattern: ${options.owner}`);
|
|
17175
|
-
const ownedFiles = [];
|
|
17176
|
-
for (const file of changedFiles) {
|
|
17177
|
-
const owners = await getOwner(file);
|
|
17178
|
-
if (owners.length > 0) {
|
|
17179
|
-
const matchingOwners = import_micromatch3.default(owners, options.owner);
|
|
17180
|
-
if (matchingOwners.length > 0) {
|
|
17181
|
-
ownedFiles.push(file);
|
|
17182
|
-
}
|
|
17183
|
-
}
|
|
17184
|
-
}
|
|
17185
|
-
filesToExtract = ownedFiles;
|
|
17186
|
-
if (filesToExtract.length === 0) {
|
|
17187
|
-
log.warn(`No files match the owner pattern: ${options.owner}`);
|
|
17188
|
-
return;
|
|
17189
|
-
}
|
|
17190
|
-
log.info(`Filtered to ${filesToExtract.length} file${filesToExtract.length !== 1 ? "s" : ""}`);
|
|
17191
|
-
}
|
|
17192
|
-
log.info("Extracting files to working directory...");
|
|
17193
|
-
await extractFilesFromRef(options.source, filesToExtract);
|
|
17194
|
-
log.success(`
|
|
17195
|
-
✓ Extracted ${filesToExtract.length} file${filesToExtract.length !== 1 ? "s" : ""} to working directory (unstaged)`);
|
|
17196
|
-
log.info(`
|
|
17197
|
-
Extracted files:`);
|
|
17198
|
-
filesToExtract.forEach((file) => log.info(` - ${file}`));
|
|
17199
|
-
log.info(`
|
|
17200
|
-
Next steps:`);
|
|
17201
|
-
log.info(" - Review the extracted files in your working directory");
|
|
17202
|
-
log.info(" - Use 'cg branch' command to create a branch and commit");
|
|
17203
|
-
log.info(" - Example: cg branch -o @my-team -b my-branch -m 'Commit message' -p");
|
|
17204
|
-
} catch (err) {
|
|
17205
|
-
log.error(`
|
|
17206
|
-
✗ Extraction failed: ${err}`);
|
|
17207
|
-
process.exit(1);
|
|
17208
|
-
}
|
|
17209
|
-
};
|
|
17210
|
-
|
|
17211
|
-
// node_modules/@inquirer/core/dist/esm/lib/key.js
|
|
17212
|
-
var isUpKey = (key) => key.name === "up" || key.name === "k" || key.ctrl && key.name === "p";
|
|
17213
|
-
var isDownKey = (key) => key.name === "down" || key.name === "j" || key.ctrl && key.name === "n";
|
|
17214
|
-
var isBackspaceKey = (key) => key.name === "backspace";
|
|
17215
|
-
var isNumberKey = (key) => "123456789".includes(key.name);
|
|
17216
|
-
var isEnterKey = (key) => key.name === "enter" || key.name === "return";
|
|
17217
|
-
// node_modules/@inquirer/core/dist/esm/lib/errors.js
|
|
17218
|
-
class AbortPromptError extends Error {
|
|
17219
|
-
name = "AbortPromptError";
|
|
17220
|
-
message = "Prompt was aborted";
|
|
17221
|
-
constructor(options) {
|
|
17222
|
-
super();
|
|
17223
|
-
this.cause = options?.cause;
|
|
17224
|
-
}
|
|
17225
|
-
}
|
|
17226
|
-
|
|
17227
|
-
class CancelPromptError extends Error {
|
|
17228
|
-
name = "CancelPromptError";
|
|
17229
|
-
message = "Prompt was canceled";
|
|
17230
|
-
}
|
|
17231
|
-
|
|
17232
|
-
class ExitPromptError extends Error {
|
|
17233
|
-
name = "ExitPromptError";
|
|
17234
|
-
}
|
|
17235
|
-
|
|
17236
|
-
class HookError extends Error {
|
|
17237
|
-
name = "HookError";
|
|
17238
|
-
}
|
|
17239
|
-
|
|
17240
|
-
class ValidationError extends Error {
|
|
17241
|
-
name = "ValidationError";
|
|
17242
|
-
}
|
|
17243
|
-
// node_modules/@inquirer/core/dist/esm/lib/use-prefix.js
|
|
17244
|
-
import { AsyncResource as AsyncResource2 } from "node:async_hooks";
|
|
17245
|
-
|
|
17246
|
-
// node_modules/@inquirer/core/dist/esm/lib/hook-engine.js
|
|
17247
|
-
import { AsyncLocalStorage, AsyncResource } from "node:async_hooks";
|
|
17248
|
-
var hookStorage = new AsyncLocalStorage;
|
|
17249
|
-
function createStore(rl) {
|
|
17250
|
-
const store = {
|
|
17251
|
-
rl,
|
|
17252
|
-
hooks: [],
|
|
17253
|
-
hooksCleanup: [],
|
|
17254
|
-
hooksEffect: [],
|
|
17255
|
-
index: 0,
|
|
17256
|
-
handleChange() {}
|
|
17257
|
-
};
|
|
17258
|
-
return store;
|
|
17259
|
-
}
|
|
17260
|
-
function withHooks(rl, cb) {
|
|
17261
|
-
const store = createStore(rl);
|
|
17262
|
-
return hookStorage.run(store, () => {
|
|
17263
|
-
function cycle(render) {
|
|
17264
|
-
store.handleChange = () => {
|
|
17265
|
-
store.index = 0;
|
|
17266
|
-
render();
|
|
17267
|
-
};
|
|
17268
|
-
store.handleChange();
|
|
17269
|
-
}
|
|
17270
|
-
return cb(cycle);
|
|
17271
|
-
});
|
|
17272
|
-
}
|
|
17273
|
-
function getStore() {
|
|
17274
|
-
const store = hookStorage.getStore();
|
|
17275
|
-
if (!store) {
|
|
17276
|
-
throw new HookError("[Inquirer] Hook functions can only be called from within a prompt");
|
|
17277
|
-
}
|
|
17278
|
-
return store;
|
|
17279
|
-
}
|
|
17280
|
-
function readline() {
|
|
17281
|
-
return getStore().rl;
|
|
17282
|
-
}
|
|
17283
|
-
function withUpdates(fn) {
|
|
17284
|
-
const wrapped = (...args) => {
|
|
17285
|
-
const store = getStore();
|
|
17286
|
-
let shouldUpdate = false;
|
|
17287
|
-
const oldHandleChange = store.handleChange;
|
|
17288
|
-
store.handleChange = () => {
|
|
17289
|
-
shouldUpdate = true;
|
|
17290
|
-
};
|
|
17291
|
-
const returnValue = fn(...args);
|
|
17292
|
-
if (shouldUpdate) {
|
|
17293
|
-
oldHandleChange();
|
|
17294
|
-
}
|
|
17295
|
-
store.handleChange = oldHandleChange;
|
|
17296
|
-
return returnValue;
|
|
17297
|
-
};
|
|
17298
|
-
return AsyncResource.bind(wrapped);
|
|
17299
|
-
}
|
|
17300
|
-
function withPointer(cb) {
|
|
17301
|
-
const store = getStore();
|
|
17302
|
-
const { index } = store;
|
|
17303
|
-
const pointer = {
|
|
17304
|
-
get() {
|
|
17305
|
-
return store.hooks[index];
|
|
17306
|
-
},
|
|
17307
|
-
set(value) {
|
|
17308
|
-
store.hooks[index] = value;
|
|
17309
|
-
},
|
|
17310
|
-
initialized: index in store.hooks
|
|
17311
|
-
};
|
|
17312
|
-
const returnValue = cb(pointer);
|
|
17313
|
-
store.index++;
|
|
17314
|
-
return returnValue;
|
|
17315
|
-
}
|
|
17316
|
-
function handleChange() {
|
|
17317
|
-
getStore().handleChange();
|
|
17318
|
-
}
|
|
17319
|
-
var effectScheduler = {
|
|
17320
|
-
queue(cb) {
|
|
17321
|
-
const store = getStore();
|
|
17322
|
-
const { index } = store;
|
|
17323
|
-
store.hooksEffect.push(() => {
|
|
17324
|
-
store.hooksCleanup[index]?.();
|
|
17325
|
-
const cleanFn = cb(readline());
|
|
17326
|
-
if (cleanFn != null && typeof cleanFn !== "function") {
|
|
17327
|
-
throw new ValidationError("useEffect return value must be a cleanup function or nothing.");
|
|
17328
|
-
}
|
|
17329
|
-
store.hooksCleanup[index] = cleanFn;
|
|
17330
|
-
});
|
|
17331
|
-
},
|
|
17332
|
-
run() {
|
|
17333
|
-
const store = getStore();
|
|
17334
|
-
withUpdates(() => {
|
|
17335
|
-
store.hooksEffect.forEach((effect) => {
|
|
17336
|
-
effect();
|
|
17337
|
-
});
|
|
17338
|
-
store.hooksEffect.length = 0;
|
|
17339
|
-
})();
|
|
17340
|
-
},
|
|
17341
|
-
clearAll() {
|
|
17342
|
-
const store = getStore();
|
|
17343
|
-
store.hooksCleanup.forEach((cleanFn) => {
|
|
17344
|
-
cleanFn?.();
|
|
17345
|
-
});
|
|
17346
|
-
store.hooksEffect.length = 0;
|
|
17347
|
-
store.hooksCleanup.length = 0;
|
|
17348
|
-
}
|
|
17349
|
-
};
|
|
17350
|
-
|
|
17351
|
-
// node_modules/@inquirer/core/dist/esm/lib/use-state.js
|
|
17352
|
-
function useState(defaultValue) {
|
|
17353
|
-
return withPointer((pointer) => {
|
|
17354
|
-
const setFn = (newValue) => {
|
|
17355
|
-
if (pointer.get() !== newValue) {
|
|
17356
|
-
pointer.set(newValue);
|
|
17357
|
-
handleChange();
|
|
17358
|
-
}
|
|
17359
|
-
};
|
|
17360
|
-
if (pointer.initialized) {
|
|
17361
|
-
return [pointer.get(), setFn];
|
|
17175
|
+
},
|
|
17176
|
+
run() {
|
|
17177
|
+
const store = getStore();
|
|
17178
|
+
withUpdates(() => {
|
|
17179
|
+
store.hooksEffect.forEach((effect) => {
|
|
17180
|
+
effect();
|
|
17181
|
+
});
|
|
17182
|
+
store.hooksEffect.length = 0;
|
|
17183
|
+
})();
|
|
17184
|
+
},
|
|
17185
|
+
clearAll() {
|
|
17186
|
+
const store = getStore();
|
|
17187
|
+
store.hooksCleanup.forEach((cleanFn) => {
|
|
17188
|
+
cleanFn?.();
|
|
17189
|
+
});
|
|
17190
|
+
store.hooksEffect.length = 0;
|
|
17191
|
+
store.hooksCleanup.length = 0;
|
|
17192
|
+
}
|
|
17193
|
+
};
|
|
17194
|
+
|
|
17195
|
+
// node_modules/@inquirer/core/dist/esm/lib/use-state.js
|
|
17196
|
+
function useState(defaultValue) {
|
|
17197
|
+
return withPointer((pointer) => {
|
|
17198
|
+
const setFn = (newValue) => {
|
|
17199
|
+
if (pointer.get() !== newValue) {
|
|
17200
|
+
pointer.set(newValue);
|
|
17201
|
+
handleChange();
|
|
17202
|
+
}
|
|
17203
|
+
};
|
|
17204
|
+
if (pointer.initialized) {
|
|
17205
|
+
return [pointer.get(), setFn];
|
|
17362
17206
|
}
|
|
17363
17207
|
const value = typeof defaultValue === "function" ? defaultValue() : defaultValue;
|
|
17364
17208
|
pointer.set(value);
|
|
@@ -18497,6 +18341,7 @@ Operation ID: ${op.id}`);
|
|
|
18497
18341
|
};
|
|
18498
18342
|
var performRecovery = async (state, keepBranches) => {
|
|
18499
18343
|
log.header(`Recovering from operation ${state.id}`);
|
|
18344
|
+
let hadWarnings = false;
|
|
18500
18345
|
const currentBranch = await getCurrentBranch();
|
|
18501
18346
|
if (currentBranch !== state.originalBranch) {
|
|
18502
18347
|
try {
|
|
@@ -18508,8 +18353,30 @@ var performRecovery = async (state, keepBranches) => {
|
|
|
18508
18353
|
log.info(`You may need to manually run: git checkout ${state.originalBranch}`);
|
|
18509
18354
|
throw error;
|
|
18510
18355
|
}
|
|
18511
|
-
} else {
|
|
18512
|
-
log.info(`Already on original branch: ${state.originalBranch}`);
|
|
18356
|
+
} else {
|
|
18357
|
+
log.info(`Already on original branch: ${state.originalBranch}`);
|
|
18358
|
+
}
|
|
18359
|
+
if (!keepBranches && state.branches.length > 0) {
|
|
18360
|
+
log.info(`
|
|
18361
|
+
Restoring files from branches...`);
|
|
18362
|
+
for (const branch2 of state.branches) {
|
|
18363
|
+
if (branch2.committed && branch2.files && branch2.files.length > 0) {
|
|
18364
|
+
try {
|
|
18365
|
+
const exists2 = await branchExists(branch2.name);
|
|
18366
|
+
if (exists2) {
|
|
18367
|
+
log.info(`Restoring ${branch2.files.length} file(s) from ${branch2.name}...`);
|
|
18368
|
+
await restoreFilesFromBranch(branch2.name, branch2.files);
|
|
18369
|
+
} else {
|
|
18370
|
+
log.warn(`Branch ${branch2.name} no longer exists, cannot restore files`);
|
|
18371
|
+
hadWarnings = true;
|
|
18372
|
+
}
|
|
18373
|
+
} catch (error) {
|
|
18374
|
+
log.error(`Failed to restore files from ${branch2.name}: ${error}`);
|
|
18375
|
+
log.info(`Files may still be accessible from the branch if it exists`);
|
|
18376
|
+
hadWarnings = true;
|
|
18377
|
+
}
|
|
18378
|
+
}
|
|
18379
|
+
}
|
|
18513
18380
|
}
|
|
18514
18381
|
if (!keepBranches && state.branches.length > 0) {
|
|
18515
18382
|
log.info(`
|
|
@@ -18527,6 +18394,7 @@ Cleaning up created branches...`);
|
|
|
18527
18394
|
} catch (error) {
|
|
18528
18395
|
log.error(`Failed to delete branch ${branch2.name}: ${error}`);
|
|
18529
18396
|
log.info(`You may need to manually run: git branch -D ${branch2.name}`);
|
|
18397
|
+
hadWarnings = true;
|
|
18530
18398
|
}
|
|
18531
18399
|
}
|
|
18532
18400
|
}
|
|
@@ -18545,6 +18413,7 @@ Cleaning up state file...`);
|
|
|
18545
18413
|
log.success(`State file deleted: ${state.id}`);
|
|
18546
18414
|
log.success(`
|
|
18547
18415
|
✓ Recovery complete!`);
|
|
18416
|
+
return !hadWarnings;
|
|
18548
18417
|
};
|
|
18549
18418
|
var recover = async (options) => {
|
|
18550
18419
|
try {
|
|
@@ -18606,8 +18475,311 @@ Operation details:`);
|
|
|
18606
18475
|
process.exit(1);
|
|
18607
18476
|
}
|
|
18608
18477
|
};
|
|
18478
|
+
|
|
18479
|
+
// src/commands/multi-branch.ts
|
|
18480
|
+
var import_cli_table33 = __toESM(require_table(), 1);
|
|
18481
|
+
var multiBranch = async (options) => {
|
|
18482
|
+
let operationState = null;
|
|
18483
|
+
try {
|
|
18484
|
+
if (!options.branch || !options.message) {
|
|
18485
|
+
throw new Error("Missing required options for multi-branch creation");
|
|
18486
|
+
}
|
|
18487
|
+
if (options.ignore && options.include) {
|
|
18488
|
+
throw new Error("Cannot use both --ignore and --include options at the same time");
|
|
18489
|
+
}
|
|
18490
|
+
if ((options.pr || options.draftPr) && !options.push) {
|
|
18491
|
+
throw new Error("Pull request creation requires --push option");
|
|
18492
|
+
}
|
|
18493
|
+
if (options.pr && options.draftPr) {
|
|
18494
|
+
throw new Error("Cannot use both --pr and --draft-pr options");
|
|
18495
|
+
}
|
|
18496
|
+
if (await hasUnstagedChanges()) {
|
|
18497
|
+
const unstagedFiles = await getUnstagedFiles();
|
|
18498
|
+
log.warn("Warning: Unstaged changes detected (these will be ignored):");
|
|
18499
|
+
unstagedFiles.forEach((file) => log.warn(` - ${file}`));
|
|
18500
|
+
log.info(`
|
|
18501
|
+
Only staged files will be processed.`);
|
|
18502
|
+
log.info("To stage files: git add <file>");
|
|
18503
|
+
log.info("");
|
|
18504
|
+
}
|
|
18505
|
+
log.info(options.append ? "Starting multi-branch update process..." : "Starting multi-branch creation process...");
|
|
18506
|
+
const originalBranch = await getCurrentBranch();
|
|
18507
|
+
operationState = createOperationState("multi-branch", originalBranch, {
|
|
18508
|
+
verify: options.verify,
|
|
18509
|
+
push: options.push,
|
|
18510
|
+
remote: options.remote,
|
|
18511
|
+
force: options.force,
|
|
18512
|
+
keepBranchOnFailure: options.keepBranchOnFailure,
|
|
18513
|
+
pr: options.pr,
|
|
18514
|
+
draftPr: options.draftPr
|
|
18515
|
+
});
|
|
18516
|
+
log.info(`Operation ID: ${operationState.id}`);
|
|
18517
|
+
let changedFiles = await getChangedFiles();
|
|
18518
|
+
changedFiles = filterByPathPatterns(changedFiles, options.pathPattern);
|
|
18519
|
+
if (changedFiles.length === 0) {
|
|
18520
|
+
throw new Error(options.pathPattern ? `No changed files found matching pattern: ${options.pathPattern}` : "No changed files found in the repository");
|
|
18521
|
+
}
|
|
18522
|
+
const ownerSet = new Set;
|
|
18523
|
+
const filesWithoutOwners = [];
|
|
18524
|
+
for (const file of changedFiles) {
|
|
18525
|
+
const owners = getOwner(file);
|
|
18526
|
+
if (owners.length === 0) {
|
|
18527
|
+
filesWithoutOwners.push(file);
|
|
18528
|
+
} else {
|
|
18529
|
+
for (const owner of owners) {
|
|
18530
|
+
ownerSet.add(owner);
|
|
18531
|
+
}
|
|
18532
|
+
}
|
|
18533
|
+
}
|
|
18534
|
+
let codeowners2 = Array.from(ownerSet);
|
|
18535
|
+
if (filesWithoutOwners.length > 0 && options.defaultOwner) {
|
|
18536
|
+
log.info(`Found ${filesWithoutOwners.length} files without owners. Adding default owner: ${options.defaultOwner}`);
|
|
18537
|
+
codeowners2.push(options.defaultOwner);
|
|
18538
|
+
}
|
|
18539
|
+
if (codeowners2.length === 0) {
|
|
18540
|
+
log.warn("No codeowners found for the changed files");
|
|
18541
|
+
log.info("Continuing without creating any branches (use --default-owner to specify a fallback)");
|
|
18542
|
+
return;
|
|
18543
|
+
} else {
|
|
18544
|
+
log.info(`Found ${codeowners2.length} codeowners: ${codeowners2.join(", ")}`);
|
|
18545
|
+
}
|
|
18546
|
+
if (options.ignore || options.include) {
|
|
18547
|
+
const originalCount = codeowners2.length;
|
|
18548
|
+
if (options.ignore) {
|
|
18549
|
+
codeowners2 = codeowners2.filter((owner) => !matchOwnerPattern(owner, options.ignore));
|
|
18550
|
+
log.info(`Filtered out ${originalCount - codeowners2.length} codeowners using ignore patterns: ${options.ignore}`);
|
|
18551
|
+
} else if (options.include) {
|
|
18552
|
+
codeowners2 = codeowners2.filter((owner) => matchOwnerPattern(owner, options.include));
|
|
18553
|
+
log.info(`Filtered to ${codeowners2.length} codeowners using include patterns: ${options.include}`);
|
|
18554
|
+
}
|
|
18555
|
+
if (codeowners2.length === 0) {
|
|
18556
|
+
log.warn("No codeowners left after filtering");
|
|
18557
|
+
return;
|
|
18558
|
+
}
|
|
18559
|
+
log.info(`Processing ${codeowners2.length} codeowners after filtering: ${codeowners2.join(", ")}`);
|
|
18560
|
+
}
|
|
18561
|
+
const results = [];
|
|
18562
|
+
for (const owner of codeowners2) {
|
|
18563
|
+
const sanitizedOwner = owner.replace(/[^a-zA-Z0-9-_@]/g, "-").replace(/^@/, "");
|
|
18564
|
+
const branchName = `${options.branch}/${sanitizedOwner}`;
|
|
18565
|
+
const commitMessage = `${options.message} - ${owner}`;
|
|
18566
|
+
log.info(options.append ? `Updating branch for ${owner}...` : `Creating branch for ${owner}...`);
|
|
18567
|
+
const result = await branch({
|
|
18568
|
+
include: owner,
|
|
18569
|
+
branch: branchName,
|
|
18570
|
+
message: commitMessage,
|
|
18571
|
+
verify: options.verify,
|
|
18572
|
+
push: options.push,
|
|
18573
|
+
remote: options.remote,
|
|
18574
|
+
upstream: options.upstream,
|
|
18575
|
+
force: options.force,
|
|
18576
|
+
keepBranchOnFailure: options.keepBranchOnFailure,
|
|
18577
|
+
isDefaultOwner: owner === options.defaultOwner,
|
|
18578
|
+
append: options.append,
|
|
18579
|
+
pr: options.pr,
|
|
18580
|
+
draftPr: options.draftPr,
|
|
18581
|
+
operationState: operationState || undefined,
|
|
18582
|
+
pathPattern: options.pathPattern,
|
|
18583
|
+
exclusive: options.exclusive,
|
|
18584
|
+
coOwned: options.coOwned
|
|
18585
|
+
});
|
|
18586
|
+
results.push(result);
|
|
18587
|
+
}
|
|
18588
|
+
const successCount = results.filter((r) => r.success).length;
|
|
18589
|
+
const failureCount = results.filter((r) => !r.success).length;
|
|
18590
|
+
log.header(options.append ? "Multi-branch update summary" : "Multi-branch creation summary");
|
|
18591
|
+
log.info(options.append ? `Successfully updated ${successCount} of ${codeowners2.length} branches` : `Successfully created ${successCount} of ${codeowners2.length} branches`);
|
|
18592
|
+
if (failureCount > 0) {
|
|
18593
|
+
log.error(`Failed: ${failureCount} branches`);
|
|
18594
|
+
}
|
|
18595
|
+
console.log("");
|
|
18596
|
+
const table = new import_cli_table33.default({
|
|
18597
|
+
head: ["Status", "Owner", "Branch", "Files", "Pushed", "PR"],
|
|
18598
|
+
colWidths: [10, 20, 40, 10, 10, 50],
|
|
18599
|
+
wordWrap: true
|
|
18600
|
+
});
|
|
18601
|
+
for (const result of results) {
|
|
18602
|
+
const status = result.success ? "✓" : "✗";
|
|
18603
|
+
const fileCount = result.files.length;
|
|
18604
|
+
const pushedStatus = result.pushed ? "✓" : "-";
|
|
18605
|
+
const prInfo = result.prUrl ? result.prUrl : result.error && result.error.includes("PR creation failed") ? "Failed" : "-";
|
|
18606
|
+
table.push([
|
|
18607
|
+
status,
|
|
18608
|
+
result.owner,
|
|
18609
|
+
result.branchName,
|
|
18610
|
+
`${fileCount} file${fileCount !== 1 ? "s" : ""}`,
|
|
18611
|
+
pushedStatus,
|
|
18612
|
+
prInfo
|
|
18613
|
+
]);
|
|
18614
|
+
}
|
|
18615
|
+
console.log(table.toString());
|
|
18616
|
+
if (results.length > 0) {
|
|
18617
|
+
console.log(`
|
|
18618
|
+
Files by branch:`);
|
|
18619
|
+
for (const result of results) {
|
|
18620
|
+
if (result.success && result.files.length > 0) {
|
|
18621
|
+
console.log(`
|
|
18622
|
+
${result.branchName} (${result.owner}):`);
|
|
18623
|
+
result.files.forEach((file) => console.log(` - ${file}`));
|
|
18624
|
+
}
|
|
18625
|
+
}
|
|
18626
|
+
}
|
|
18627
|
+
const errors2 = results.filter((r) => r.error);
|
|
18628
|
+
if (errors2.length > 0) {
|
|
18629
|
+
console.log(`
|
|
18630
|
+
Errors:`);
|
|
18631
|
+
errors2.forEach((result) => {
|
|
18632
|
+
console.log(`
|
|
18633
|
+
${result.branchName} (${result.owner}):`);
|
|
18634
|
+
console.log(` ${result.error}`);
|
|
18635
|
+
});
|
|
18636
|
+
}
|
|
18637
|
+
if (operationState) {
|
|
18638
|
+
if (failureCount === 0) {
|
|
18639
|
+
completeOperation(operationState.id, true);
|
|
18640
|
+
} else {
|
|
18641
|
+
failOperation(operationState.id, `${failureCount} branch(es) failed`);
|
|
18642
|
+
log.info(`
|
|
18643
|
+
Note: ${failureCount} branch(es) failed. Files were auto-restored to working directory.`);
|
|
18644
|
+
log.info(`State preserved for reference. Run 'codeowners-git recover --id ${operationState.id}' if needed.`);
|
|
18645
|
+
}
|
|
18646
|
+
}
|
|
18647
|
+
} catch (err) {
|
|
18648
|
+
log.error(`Multi-branch operation failed: ${err}`);
|
|
18649
|
+
if (operationState) {
|
|
18650
|
+
log.info(`
|
|
18651
|
+
Attempting auto-recovery...`);
|
|
18652
|
+
const currentState = loadOperationState(operationState.id);
|
|
18653
|
+
if (currentState) {
|
|
18654
|
+
try {
|
|
18655
|
+
const recovered = await performRecovery(currentState, false);
|
|
18656
|
+
if (recovered) {
|
|
18657
|
+
log.success("Auto-recovery completed successfully");
|
|
18658
|
+
} else {
|
|
18659
|
+
log.warn("Auto-recovery completed with warnings");
|
|
18660
|
+
}
|
|
18661
|
+
} catch (recoveryError) {
|
|
18662
|
+
log.error(`Auto-recovery failed: ${recoveryError}`);
|
|
18663
|
+
log.info(`
|
|
18664
|
+
Manual recovery options:`);
|
|
18665
|
+
log.info(` 1. Run 'codeowners-git recover --id ${operationState.id}' to clean up`);
|
|
18666
|
+
log.info(` 2. Run 'codeowners-git recover --list' to see all operations`);
|
|
18667
|
+
}
|
|
18668
|
+
}
|
|
18669
|
+
}
|
|
18670
|
+
process.exit(1);
|
|
18671
|
+
}
|
|
18672
|
+
};
|
|
18673
|
+
|
|
18674
|
+
// src/commands/extract.ts
|
|
18675
|
+
var extract = async (options) => {
|
|
18676
|
+
try {
|
|
18677
|
+
if (!options.source) {
|
|
18678
|
+
log.error("Missing required option: --source");
|
|
18679
|
+
log.info(`
|
|
18680
|
+
Usage:`);
|
|
18681
|
+
log.info(" cg extract -s <branch-or-commit>");
|
|
18682
|
+
log.info(`
|
|
18683
|
+
Examples:`);
|
|
18684
|
+
log.info(" cg extract -s feature/other-branch");
|
|
18685
|
+
log.info(" cg extract -s feature/other-branch -i '@team-*'");
|
|
18686
|
+
log.info(" cg extract -s abc123def --compare-main");
|
|
18687
|
+
process.exit(1);
|
|
18688
|
+
}
|
|
18689
|
+
if (await hasUnstagedChanges()) {
|
|
18690
|
+
const unstagedFiles = await getUnstagedFiles();
|
|
18691
|
+
log.warn("Warning: Unstaged changes detected (these will be ignored):");
|
|
18692
|
+
unstagedFiles.forEach((file) => log.warn(` - ${file}`));
|
|
18693
|
+
log.info(`
|
|
18694
|
+
Only staged files will be processed.`);
|
|
18695
|
+
log.info("To stage files: git add <file>");
|
|
18696
|
+
log.info("");
|
|
18697
|
+
}
|
|
18698
|
+
log.info("Starting file extraction process...");
|
|
18699
|
+
let compareTarget;
|
|
18700
|
+
if (options.compareMain) {
|
|
18701
|
+
compareTarget = await getDefaultBranch();
|
|
18702
|
+
log.info(`Comparing ${options.source} against ${compareTarget}...`);
|
|
18703
|
+
} else {
|
|
18704
|
+
const baseBranch = await getBaseBranch(options.source);
|
|
18705
|
+
compareTarget = baseBranch;
|
|
18706
|
+
log.info(`Detected base branch: ${baseBranch}`);
|
|
18707
|
+
log.info(`Extracting changes from ${options.source}...`);
|
|
18708
|
+
}
|
|
18709
|
+
let changedFiles = await getChangedFilesBetween(options.source, compareTarget);
|
|
18710
|
+
if (changedFiles.length === 0) {
|
|
18711
|
+
log.warn(`No changed files found in ${options.source}`);
|
|
18712
|
+
return;
|
|
18713
|
+
}
|
|
18714
|
+
log.info(`Found ${changedFiles.length} changed file${changedFiles.length !== 1 ? "s" : ""}`);
|
|
18715
|
+
if (options.pathPattern) {
|
|
18716
|
+
changedFiles = filterByPathPatterns(changedFiles, options.pathPattern);
|
|
18717
|
+
log.info(`Filtered to ${changedFiles.length} file${changedFiles.length !== 1 ? "s" : ""} matching pattern: ${options.pathPattern}`);
|
|
18718
|
+
if (changedFiles.length === 0) {
|
|
18719
|
+
log.warn(`No files match the path pattern: ${options.pathPattern}`);
|
|
18720
|
+
return;
|
|
18721
|
+
}
|
|
18722
|
+
}
|
|
18723
|
+
let filesToExtract = changedFiles;
|
|
18724
|
+
if (options.coOwned && !options.include) {
|
|
18725
|
+
log.info("Filtering to co-owned files (2+ owners)");
|
|
18726
|
+
filesToExtract = changedFiles.filter((file) => {
|
|
18727
|
+
const owners = getOwner(file);
|
|
18728
|
+
return owners.length > 1;
|
|
18729
|
+
});
|
|
18730
|
+
if (filesToExtract.length === 0) {
|
|
18731
|
+
log.warn("No co-owned files found");
|
|
18732
|
+
return;
|
|
18733
|
+
}
|
|
18734
|
+
log.info(`Filtered to ${filesToExtract.length} co-owned file${filesToExtract.length !== 1 ? "s" : ""}`);
|
|
18735
|
+
}
|
|
18736
|
+
if (options.include) {
|
|
18737
|
+
log.info(`Filtering files by owner pattern: ${options.include}${options.exclusive ? " (exclusive)" : ""}${options.coOwned ? " (co-owned)" : ""}`);
|
|
18738
|
+
const ownedFiles = [];
|
|
18739
|
+
for (const file of filesToExtract) {
|
|
18740
|
+
const owners = getOwner(file);
|
|
18741
|
+
if (owners.length > 0) {
|
|
18742
|
+
if (options.coOwned && owners.length < 2) {
|
|
18743
|
+
continue;
|
|
18744
|
+
}
|
|
18745
|
+
let matches;
|
|
18746
|
+
if (options.exclusive) {
|
|
18747
|
+
matches = matchOwnersExclusive(owners, options.include);
|
|
18748
|
+
} else {
|
|
18749
|
+
matches = owners.some((owner) => matchOwnerPattern(owner, options.include));
|
|
18750
|
+
}
|
|
18751
|
+
if (matches) {
|
|
18752
|
+
ownedFiles.push(file);
|
|
18753
|
+
}
|
|
18754
|
+
}
|
|
18755
|
+
}
|
|
18756
|
+
filesToExtract = ownedFiles;
|
|
18757
|
+
if (filesToExtract.length === 0) {
|
|
18758
|
+
log.warn(`No files match the owner pattern: ${options.include}`);
|
|
18759
|
+
return;
|
|
18760
|
+
}
|
|
18761
|
+
log.info(`Filtered to ${filesToExtract.length} file${filesToExtract.length !== 1 ? "s" : ""}`);
|
|
18762
|
+
}
|
|
18763
|
+
log.info("Extracting files to working directory...");
|
|
18764
|
+
await extractFilesFromRef(options.source, filesToExtract);
|
|
18765
|
+
log.success(`
|
|
18766
|
+
✓ Extracted ${filesToExtract.length} file${filesToExtract.length !== 1 ? "s" : ""} to working directory (unstaged)`);
|
|
18767
|
+
log.info(`
|
|
18768
|
+
Extracted files:`);
|
|
18769
|
+
filesToExtract.forEach((file) => log.info(` - ${file}`));
|
|
18770
|
+
log.info(`
|
|
18771
|
+
Next steps:`);
|
|
18772
|
+
log.info(" - Review the extracted files in your working directory");
|
|
18773
|
+
log.info(" - Use 'cg branch' command to create a branch and commit");
|
|
18774
|
+
log.info(" - Example: cg branch -i @my-team -b my-branch -m 'Commit message' -p");
|
|
18775
|
+
} catch (err) {
|
|
18776
|
+
log.error(`
|
|
18777
|
+
✗ Extraction failed: ${err}`);
|
|
18778
|
+
process.exit(1);
|
|
18779
|
+
}
|
|
18780
|
+
};
|
|
18609
18781
|
// package.json
|
|
18610
|
-
var version = "
|
|
18782
|
+
var version = "2.0.0";
|
|
18611
18783
|
|
|
18612
18784
|
// src/commands/version.ts
|
|
18613
18785
|
function getVersion() {
|
|
@@ -18646,9 +18818,45 @@ To recover from incomplete operations, run:`);
|
|
|
18646
18818
|
setupSignalHandlers();
|
|
18647
18819
|
var program2 = new Command;
|
|
18648
18820
|
program2.name("codeowners-git (cg)").description("CLI tool for grouping and managing staged files by CODEOWNERS").version(getVersion());
|
|
18649
|
-
program2.command("list").description("Lists all git changed files by CODEOWNER").option("-
|
|
18650
|
-
|
|
18651
|
-
|
|
18652
|
-
|
|
18821
|
+
program2.command("list").description("Lists all git changed files by CODEOWNER").argument("[pattern]", "Path pattern to filter files (micromatch syntax, comma-separated)").option("-i, --include <patterns>", "Filter by owner patterns").option("-g, --group", "Group files by code owner").option("-e, --exclusive", "Only include files where the owner is the sole owner (no co-owners)").option("-c, --co-owned", "Only include files with multiple owners (co-owned files)").action((pattern, options) => {
|
|
18822
|
+
if (options.exclusive && options.coOwned) {
|
|
18823
|
+
console.error("Error: Cannot use both --exclusive and --co-owned options");
|
|
18824
|
+
process.exit(1);
|
|
18825
|
+
}
|
|
18826
|
+
listCodeowners({
|
|
18827
|
+
...options,
|
|
18828
|
+
pathPattern: pattern
|
|
18829
|
+
});
|
|
18830
|
+
});
|
|
18831
|
+
program2.command("branch").description("Create new branch with codeowner changes").argument("[pattern]", "Path pattern to filter files (micromatch syntax, comma-separated)").requiredOption("-i, --include <patterns>", "Code owner pattern to filter files").requiredOption("-b, --branch <branch>", "Branch name").requiredOption("-m, --message <message>", "Commit message").option("-n, --no-verify", "Skip lint-staged or any other ci checks").option("-p, --push", "Push branch to remote after commit").option("-r, --remote <remote>", "Remote name to push to", "origin").option("-u, --upstream <upstream>", "Upstream branch name (defaults to local branch name)").option("-f, --force", "Force push to remote").option("-k, --keep-branch-on-failure", "Keep the created branch even if operation fails").option("--append", "Add commits to existing branch instead of creating a new one").option("--pr", "Create a pull request after pushing (requires --push)").option("--draft-pr", "Create a draft pull request after pushing (requires --push)").option("-e, --exclusive", "Only include files where the owner is the sole owner (no co-owners)").option("-c, --co-owned", "Only include files with multiple owners (co-owned files)").action((pattern, options) => {
|
|
18832
|
+
if (options.exclusive && options.coOwned) {
|
|
18833
|
+
console.error("Error: Cannot use both --exclusive and --co-owned options");
|
|
18834
|
+
process.exit(1);
|
|
18835
|
+
}
|
|
18836
|
+
branch({
|
|
18837
|
+
...options,
|
|
18838
|
+
pathPattern: pattern
|
|
18839
|
+
});
|
|
18840
|
+
});
|
|
18841
|
+
program2.command("multi-branch").description("Create branches for all codeowners").argument("[pattern]", "Path pattern to filter files (micromatch syntax, comma-separated)").requiredOption("-b, --branch <branch>", "Base branch name (will be suffixed with codeowner name)").requiredOption("-m, --message <message>", "Base commit message (will be suffixed with codeowner name)").option("-n, --no-verify", "Skip lint-staged or any other ci checks").option("-p, --push", "Push branches to remote after commit").option("-r, --remote <remote>", "Remote name to push to", "origin").option("-u, --upstream <upstream>", "Upstream branch name pattern (defaults to local branch name)").option("-f, --force", "Force push to remote").option("-k, --keep-branch-on-failure", "Keep created branches even if operation fails").option("-d, --default-owner <defaultOwner>", "Default owner to use when no codeowners are found for changed files").option("--ignore <patterns>", "Comma-separated patterns to exclude codeowners (e.g., 'team-a,team-b')").option("--include <patterns>", "Comma-separated patterns to include codeowners (e.g., 'team-*,@org/*')").option("--append", "Add commits to existing branches instead of creating new ones").option("--pr", "Create pull requests after pushing (requires --push)").option("--draft-pr", "Create draft pull requests after pushing (requires --push)").option("-e, --exclusive", "Only include files where each owner is the sole owner (no co-owners)").option("-c, --co-owned", "Only include files with multiple owners (co-owned files)").action((pattern, options) => {
|
|
18842
|
+
if (options.exclusive && options.coOwned) {
|
|
18843
|
+
console.error("Error: Cannot use both --exclusive and --co-owned options");
|
|
18844
|
+
process.exit(1);
|
|
18845
|
+
}
|
|
18846
|
+
multiBranch({
|
|
18847
|
+
...options,
|
|
18848
|
+
pathPattern: pattern
|
|
18849
|
+
});
|
|
18850
|
+
});
|
|
18851
|
+
program2.command("extract").description("Extract file changes from a branch or commit to working directory").argument("[pattern]", "Path pattern to filter files (micromatch syntax, comma-separated)").requiredOption("-s, --source <source>", "Source branch or commit to extract from").option("-i, --include <patterns>", "Filter extracted files by code owner pattern").option("--compare-main", "Compare source against main branch instead of detecting merge-base").option("-e, --exclusive", "Only include files where the owner is the sole owner (no co-owners)").option("-c, --co-owned", "Only include files with multiple owners (co-owned files)").action((pattern, options) => {
|
|
18852
|
+
if (options.exclusive && options.coOwned) {
|
|
18853
|
+
console.error("Error: Cannot use both --exclusive and --co-owned options");
|
|
18854
|
+
process.exit(1);
|
|
18855
|
+
}
|
|
18856
|
+
extract({
|
|
18857
|
+
...options,
|
|
18858
|
+
pathPattern: pattern
|
|
18859
|
+
});
|
|
18860
|
+
});
|
|
18653
18861
|
program2.command("recover").description("Recover from failed or incomplete operations").option("--id <operationId>", "Specific operation ID to recover").option("--keep-branches", "Keep created branches instead of deleting them").option("--list", "List all incomplete operations").option("--auto", "Automatically recover most recent operation without prompts").action(recover);
|
|
18654
18862
|
program2.parse(process.argv);
|