codeowners-git 2.0.1 → 2.1.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 +315 -0
- package/dist/cli.js +507 -38
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,6 +12,8 @@ Managing large-scale migrations in big monorepos with multiple codeowners can be
|
|
|
12
12
|
- Creating compact, team-specific branches with only their affected files.
|
|
13
13
|
- Streamlining the review process with smaller, targeted PRs.
|
|
14
14
|
- **Graceful error handling** with automatic recovery from failures.
|
|
15
|
+
- **Dry-run previews** to see exactly what will happen before committing.
|
|
16
|
+
- **JSON output** for piping to other tools, scripts, and agent workflows.
|
|
15
17
|
|
|
16
18
|
> ❗❗ ❗ **Note:** Starting from v2.0.0, this tool works with **staged files**. Stage your changes with `git add` before running commands.
|
|
17
19
|
|
|
@@ -149,6 +151,7 @@ Options:
|
|
|
149
151
|
- `--group, -g` Group files by code owner
|
|
150
152
|
- `--exclusive, -e` Only include files with a single owner (no co-owned files)
|
|
151
153
|
- `--co-owned, -c` Only include files with multiple owners (co-owned files)
|
|
154
|
+
- `--json` Output results as JSON (suppresses all other output)
|
|
152
155
|
|
|
153
156
|
Examples:
|
|
154
157
|
|
|
@@ -180,6 +183,12 @@ cg list --co-owned
|
|
|
180
183
|
|
|
181
184
|
# List co-owned files where @myteam is one of the owners
|
|
182
185
|
cg list --include "@myteam" --co-owned
|
|
186
|
+
|
|
187
|
+
# Output as JSON for piping to other tools
|
|
188
|
+
cg list --json
|
|
189
|
+
|
|
190
|
+
# JSON output with filters (pipe to jq)
|
|
191
|
+
cg list -i "@myteam" --group --json | jq '.grouped'
|
|
183
192
|
```
|
|
184
193
|
|
|
185
194
|
### `branch`
|
|
@@ -214,6 +223,8 @@ Options:
|
|
|
214
223
|
- `--draft-pr` Create a draft pull request after pushing (requires `--push` and GitHub CLI)
|
|
215
224
|
- `--exclusive, -e` Only include files where the owner is the sole owner (no co-owned files)
|
|
216
225
|
- `--co-owned, -c` Only include files with multiple owners (co-owned files)
|
|
226
|
+
- `--dry-run` Preview the operation without making any changes
|
|
227
|
+
- `--json` Output results as JSON (suppresses all other output)
|
|
217
228
|
|
|
218
229
|
Example:
|
|
219
230
|
|
|
@@ -253,6 +264,15 @@ cg branch -i @myteam -b "feature/exclusive" -m "Team exclusive changes" -p --exc
|
|
|
253
264
|
|
|
254
265
|
# Only include co-owned files where @myteam is one of the owners
|
|
255
266
|
cg branch -i @myteam -b "feature/co-owned" -m "Co-owned changes" -p --co-owned
|
|
267
|
+
|
|
268
|
+
# Preview what would happen without making any changes
|
|
269
|
+
cg branch -i @myteam -b "feature/new" -m "Add feature" --dry-run
|
|
270
|
+
|
|
271
|
+
# Dry-run with JSON output (for agents/scripts)
|
|
272
|
+
cg branch -i @myteam -b "feature/new" -m "Add feature" --dry-run --json
|
|
273
|
+
|
|
274
|
+
# Normal execution with JSON output
|
|
275
|
+
cg branch -i @myteam -b "feature/new" -m "Add feature" -p --json
|
|
256
276
|
```
|
|
257
277
|
|
|
258
278
|
### `multi-branch`
|
|
@@ -289,6 +309,8 @@ Options:
|
|
|
289
309
|
- `--draft-pr` Create draft pull requests after pushing (requires `--push` and GitHub CLI)
|
|
290
310
|
- `--exclusive, -e` Only include files where each owner is the sole owner (no co-owned files)
|
|
291
311
|
- `--co-owned, -c` Only include files with multiple owners (co-owned files)
|
|
312
|
+
- `--dry-run` Preview the operation without making any changes
|
|
313
|
+
- `--json` Output results as JSON (suppresses all other output)
|
|
292
314
|
|
|
293
315
|
> **Note:** You cannot use both `--ignore` and `--include` options at the same time. You also cannot use both `--exclusive` and `--co-owned` options at the same time.
|
|
294
316
|
|
|
@@ -336,6 +358,18 @@ cg multi-branch -b "feature/exclusive" -m "Exclusive changes" -p --exclusive
|
|
|
336
358
|
|
|
337
359
|
# Only include co-owned files
|
|
338
360
|
cg multi-branch -b "feature/co-owned" -m "Co-owned changes" -p --co-owned
|
|
361
|
+
|
|
362
|
+
# Preview all branches that would be created
|
|
363
|
+
cg multi-branch -b "feature/migration" -m "Migrate" --dry-run
|
|
364
|
+
|
|
365
|
+
# Dry-run with JSON output
|
|
366
|
+
cg multi-branch -b "feature/migration" -m "Migrate" --dry-run --json
|
|
367
|
+
|
|
368
|
+
# Pipe dry-run JSON to see owners with matching files
|
|
369
|
+
cg multi-branch -b "mig" -m "Fix" --dry-run --json | jq '.owners[] | select(.files | length > 0)'
|
|
370
|
+
|
|
371
|
+
# Normal execution with JSON output
|
|
372
|
+
cg multi-branch -b "feature/migration" -m "Migrate" -p --json
|
|
339
373
|
```
|
|
340
374
|
|
|
341
375
|
This will:
|
|
@@ -371,6 +405,8 @@ Options:
|
|
|
371
405
|
- `--compare-main` Compare source against main branch instead of detecting merge-base
|
|
372
406
|
- `--exclusive, -e` Only include files where the owner is the sole owner (no co-owned files)
|
|
373
407
|
- `--co-owned, -c` Only include files with multiple owners (co-owned files)
|
|
408
|
+
- `--dry-run` Preview the operation without making any changes
|
|
409
|
+
- `--json` Output results as JSON (suppresses all other output)
|
|
374
410
|
|
|
375
411
|
Examples:
|
|
376
412
|
|
|
@@ -403,6 +439,21 @@ cg extract -s feature/other-team --co-owned
|
|
|
403
439
|
|
|
404
440
|
# Extract co-owned files where @my-team is one of the owners
|
|
405
441
|
cg extract -s feature/other-team -i "@my-team" --co-owned
|
|
442
|
+
|
|
443
|
+
# Preview what would be extracted without making any changes
|
|
444
|
+
cg extract -s feature/other-team --dry-run
|
|
445
|
+
|
|
446
|
+
# Dry-run with owner filter
|
|
447
|
+
cg extract -s feature/other-team -i "@my-team" --dry-run
|
|
448
|
+
|
|
449
|
+
# Dry-run with JSON output (for agents/scripts)
|
|
450
|
+
cg extract -s feature/other-team -i "@my-team" --dry-run --json
|
|
451
|
+
|
|
452
|
+
# Normal execution with JSON output
|
|
453
|
+
cg extract -s feature/other-team -i "@my-team" --json
|
|
454
|
+
|
|
455
|
+
# Pipe JSON to jq to get just the file list
|
|
456
|
+
cg extract -s feature/other-team --json | jq '.files'
|
|
406
457
|
```
|
|
407
458
|
|
|
408
459
|
> **Note:** Files are extracted to your working directory (unstaged), allowing you to review and modify them. Stage the files with `git add`, then use the `branch` command to create a branch, commit, push, and create PRs.
|
|
@@ -477,6 +528,270 @@ The tool automatically handles:
|
|
|
477
528
|
|
|
478
529
|
> **Note:** State files are stored in `~/.codeowners-git/state/` outside your project directory, so no `.gitignore` entries are needed.
|
|
479
530
|
|
|
531
|
+
## Dry Run & JSON Output
|
|
532
|
+
|
|
533
|
+
### Dry Run (`--dry-run`)
|
|
534
|
+
|
|
535
|
+
Available on: `branch`, `multi-branch`, `extract`
|
|
536
|
+
|
|
537
|
+
The `--dry-run` flag shows a complete preview of what would happen without performing any git operations. No branches are created, no files are committed, and nothing is pushed.
|
|
538
|
+
|
|
539
|
+
```bash
|
|
540
|
+
# Preview branch creation
|
|
541
|
+
cg branch -i @myteam -b "feature/new" -m "Add feature" --dry-run
|
|
542
|
+
|
|
543
|
+
# Preview all branches in a multi-branch run
|
|
544
|
+
cg multi-branch -b "feature/migration" -m "Migrate" --dry-run
|
|
545
|
+
|
|
546
|
+
# Preview file extraction
|
|
547
|
+
cg extract -s feature/other-team -i "@myteam" --dry-run
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
The dry-run output includes:
|
|
551
|
+
|
|
552
|
+
- **branch**: Owner, branch name, branch existence, commit message, matched files, excluded files, push/PR/flag settings
|
|
553
|
+
- **multi-branch**: Per-owner breakdown (branch, message, files), uncovered files, unowned files, summary totals
|
|
554
|
+
- **extract**: Source, compare target, files to extract, excluded files, filter settings
|
|
555
|
+
|
|
556
|
+
### JSON Output (`--json`)
|
|
557
|
+
|
|
558
|
+
Available on: `list`, `branch`, `multi-branch`, `extract`
|
|
559
|
+
|
|
560
|
+
The `--json` flag outputs machine-readable JSON to stdout and suppresses all human-readable log messages. This is useful for piping to other tools, scripts, and agent workflows.
|
|
561
|
+
|
|
562
|
+
```bash
|
|
563
|
+
# JSON output for any command
|
|
564
|
+
cg list --json
|
|
565
|
+
cg branch -i @myteam -b "feature/new" -m "Add feature" --json
|
|
566
|
+
cg multi-branch -b "feature/migration" -m "Migrate" --json
|
|
567
|
+
cg extract -s feature/other-team --json
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
### Combining `--dry-run` and `--json`
|
|
571
|
+
|
|
572
|
+
The two flags work together — `--dry-run --json` outputs the dry-run preview as structured JSON:
|
|
573
|
+
|
|
574
|
+
```bash
|
|
575
|
+
cg branch -i @myteam -b "feature/new" -m "Add feature" --dry-run --json
|
|
576
|
+
cg multi-branch -b "feature/migration" -m "Migrate" --dry-run --json
|
|
577
|
+
cg extract -s feature/other-team --dry-run --json
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
### JSON Schema Examples
|
|
581
|
+
|
|
582
|
+
Every JSON response includes a `command` field identifying the source command.
|
|
583
|
+
|
|
584
|
+
**`list --json`**
|
|
585
|
+
|
|
586
|
+
```json
|
|
587
|
+
{
|
|
588
|
+
"command": "list",
|
|
589
|
+
"files": [
|
|
590
|
+
{ "file": "src/index.ts", "owners": ["@org/team-a"] },
|
|
591
|
+
{ "file": "src/shared.ts", "owners": ["@org/team-a", "@org/team-b"] }
|
|
592
|
+
],
|
|
593
|
+
"filters": {
|
|
594
|
+
"include": null,
|
|
595
|
+
"pathPattern": null,
|
|
596
|
+
"exclusive": false,
|
|
597
|
+
"coOwned": false
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
**`list --group --json`**
|
|
603
|
+
|
|
604
|
+
```json
|
|
605
|
+
{
|
|
606
|
+
"command": "list",
|
|
607
|
+
"grouped": {
|
|
608
|
+
"@org/team-a": ["src/index.ts", "src/shared.ts"],
|
|
609
|
+
"@org/team-b": ["src/shared.ts"]
|
|
610
|
+
},
|
|
611
|
+
"filters": {
|
|
612
|
+
"include": null,
|
|
613
|
+
"pathPattern": null,
|
|
614
|
+
"exclusive": false,
|
|
615
|
+
"coOwned": false
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
**`branch --dry-run --json`**
|
|
621
|
+
|
|
622
|
+
```json
|
|
623
|
+
{
|
|
624
|
+
"command": "branch",
|
|
625
|
+
"dryRun": true,
|
|
626
|
+
"owner": "@org/team-a",
|
|
627
|
+
"branch": "feature/new/team-a",
|
|
628
|
+
"branchExists": false,
|
|
629
|
+
"message": "Add feature - @org/team-a",
|
|
630
|
+
"files": ["src/index.ts"],
|
|
631
|
+
"excludedFiles": ["src/other.ts"],
|
|
632
|
+
"options": {
|
|
633
|
+
"push": true,
|
|
634
|
+
"remote": "origin",
|
|
635
|
+
"force": false,
|
|
636
|
+
"pr": false,
|
|
637
|
+
"draftPr": false,
|
|
638
|
+
"noVerify": false,
|
|
639
|
+
"append": false,
|
|
640
|
+
"exclusive": false,
|
|
641
|
+
"coOwned": false,
|
|
642
|
+
"pathPattern": null
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
**`branch --json`** (normal execution)
|
|
648
|
+
|
|
649
|
+
```json
|
|
650
|
+
{
|
|
651
|
+
"command": "branch",
|
|
652
|
+
"dryRun": false,
|
|
653
|
+
"success": true,
|
|
654
|
+
"branchName": "feature/new/team-a",
|
|
655
|
+
"owner": "@org/team-a",
|
|
656
|
+
"files": ["src/index.ts"],
|
|
657
|
+
"pushed": true,
|
|
658
|
+
"prUrl": "https://github.com/org/repo/pull/42",
|
|
659
|
+
"prNumber": 42,
|
|
660
|
+
"error": null
|
|
661
|
+
}
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
**`multi-branch --dry-run --json`**
|
|
665
|
+
|
|
666
|
+
```json
|
|
667
|
+
{
|
|
668
|
+
"command": "multi-branch",
|
|
669
|
+
"dryRun": true,
|
|
670
|
+
"owners": [
|
|
671
|
+
{
|
|
672
|
+
"owner": "@org/team-a",
|
|
673
|
+
"branch": "feature/migration/team-a",
|
|
674
|
+
"message": "Migrate - @org/team-a",
|
|
675
|
+
"files": ["src/index.ts"]
|
|
676
|
+
},
|
|
677
|
+
{
|
|
678
|
+
"owner": "@org/team-b",
|
|
679
|
+
"branch": "feature/migration/team-b",
|
|
680
|
+
"message": "Migrate - @org/team-b",
|
|
681
|
+
"files": ["src/shared.ts"]
|
|
682
|
+
}
|
|
683
|
+
],
|
|
684
|
+
"uncoveredFiles": [],
|
|
685
|
+
"filesWithoutOwners": [],
|
|
686
|
+
"totalFiles": 2,
|
|
687
|
+
"coveredFiles": 2,
|
|
688
|
+
"options": {
|
|
689
|
+
"baseBranch": "feature/migration",
|
|
690
|
+
"baseMessage": "Migrate",
|
|
691
|
+
"push": false,
|
|
692
|
+
"remote": "origin",
|
|
693
|
+
"force": false,
|
|
694
|
+
"pr": false,
|
|
695
|
+
"draftPr": false,
|
|
696
|
+
"noVerify": false,
|
|
697
|
+
"append": false,
|
|
698
|
+
"exclusive": false,
|
|
699
|
+
"coOwned": false,
|
|
700
|
+
"pathPattern": null,
|
|
701
|
+
"defaultOwner": null
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
**`multi-branch --json`** (normal execution)
|
|
707
|
+
|
|
708
|
+
```json
|
|
709
|
+
{
|
|
710
|
+
"command": "multi-branch",
|
|
711
|
+
"dryRun": false,
|
|
712
|
+
"success": true,
|
|
713
|
+
"totalOwners": 2,
|
|
714
|
+
"successCount": 2,
|
|
715
|
+
"failureCount": 0,
|
|
716
|
+
"results": [
|
|
717
|
+
{
|
|
718
|
+
"owner": "@org/team-a",
|
|
719
|
+
"branch": "feature/migration/team-a",
|
|
720
|
+
"success": true,
|
|
721
|
+
"files": ["src/index.ts"],
|
|
722
|
+
"pushed": true,
|
|
723
|
+
"prUrl": null,
|
|
724
|
+
"prNumber": null,
|
|
725
|
+
"error": null
|
|
726
|
+
}
|
|
727
|
+
]
|
|
728
|
+
}
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
**`extract --dry-run --json`**
|
|
732
|
+
|
|
733
|
+
```json
|
|
734
|
+
{
|
|
735
|
+
"command": "extract",
|
|
736
|
+
"dryRun": true,
|
|
737
|
+
"source": "feature/other-team",
|
|
738
|
+
"compareTarget": "main",
|
|
739
|
+
"files": ["src/component.tsx"],
|
|
740
|
+
"excludedFiles": ["src/unrelated.ts"],
|
|
741
|
+
"totalChanged": 2,
|
|
742
|
+
"options": {
|
|
743
|
+
"include": "@org/team-a",
|
|
744
|
+
"pathPattern": null,
|
|
745
|
+
"exclusive": false,
|
|
746
|
+
"coOwned": false,
|
|
747
|
+
"compareMain": false
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
**`extract --json`** (normal execution)
|
|
753
|
+
|
|
754
|
+
```json
|
|
755
|
+
{
|
|
756
|
+
"command": "extract",
|
|
757
|
+
"dryRun": false,
|
|
758
|
+
"source": "feature/other-team",
|
|
759
|
+
"compareTarget": "main",
|
|
760
|
+
"files": ["src/component.tsx"],
|
|
761
|
+
"totalChanged": 2
|
|
762
|
+
}
|
|
763
|
+
```
|
|
764
|
+
|
|
765
|
+
**Error responses** (any command)
|
|
766
|
+
|
|
767
|
+
```json
|
|
768
|
+
{
|
|
769
|
+
"command": "branch",
|
|
770
|
+
"error": "Error: No staged files found"
|
|
771
|
+
}
|
|
772
|
+
```
|
|
773
|
+
|
|
774
|
+
### Piping Examples
|
|
775
|
+
|
|
776
|
+
```bash
|
|
777
|
+
# Count files per owner
|
|
778
|
+
cg list --group --json | jq '.grouped | to_entries[] | {owner: .key, count: (.value | length)}'
|
|
779
|
+
|
|
780
|
+
# Get list of branches that would be created
|
|
781
|
+
cg multi-branch -b "mig" -m "Fix" --dry-run --json | jq '.owners[].branch'
|
|
782
|
+
|
|
783
|
+
# Find owners with more than 5 files
|
|
784
|
+
cg multi-branch -b "mig" -m "Fix" --dry-run --json | jq '.owners[] | select(.files | length > 5) | .owner'
|
|
785
|
+
|
|
786
|
+
# Check if a branch operation succeeded
|
|
787
|
+
cg branch -i @myteam -b "feat" -m "Update" -p --json | jq '.success'
|
|
788
|
+
|
|
789
|
+
# List only extracted file paths
|
|
790
|
+
cg extract -s feature/other --json | jq -r '.files[]'
|
|
791
|
+
```
|
|
792
|
+
|
|
793
|
+
> **Note:** The `recover` command does not support `--dry-run` or `--json` because it is an interactive command with user prompts.
|
|
794
|
+
|
|
480
795
|
## Contributing
|
|
481
796
|
|
|
482
797
|
1. Clone the repository
|
package/dist/cli.js
CHANGED
|
@@ -5,15 +5,29 @@ var __getProtoOf = Object.getPrototypeOf;
|
|
|
5
5
|
var __defProp = Object.defineProperty;
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
function __accessProp(key) {
|
|
9
|
+
return this[key];
|
|
10
|
+
}
|
|
11
|
+
var __toESMCache_node;
|
|
12
|
+
var __toESMCache_esm;
|
|
8
13
|
var __toESM = (mod, isNodeMode, target) => {
|
|
14
|
+
var canCache = mod != null && typeof mod === "object";
|
|
15
|
+
if (canCache) {
|
|
16
|
+
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
17
|
+
var cached = cache.get(mod);
|
|
18
|
+
if (cached)
|
|
19
|
+
return cached;
|
|
20
|
+
}
|
|
9
21
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
10
22
|
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
11
23
|
for (let key of __getOwnPropNames(mod))
|
|
12
24
|
if (!__hasOwnProp.call(to, key))
|
|
13
25
|
__defProp(to, key, {
|
|
14
|
-
get: (
|
|
26
|
+
get: __accessProp.bind(mod, key),
|
|
15
27
|
enumerable: true
|
|
16
28
|
});
|
|
29
|
+
if (canCache)
|
|
30
|
+
cache.set(mod, to);
|
|
17
31
|
return to;
|
|
18
32
|
};
|
|
19
33
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
@@ -2287,7 +2301,7 @@ var require_ignore = __commonJS((exports, module) => {
|
|
|
2287
2301
|
}
|
|
2288
2302
|
}, {
|
|
2289
2303
|
key: "filter",
|
|
2290
|
-
value: function
|
|
2304
|
+
value: function filter2(paths) {
|
|
2291
2305
|
var _this = this;
|
|
2292
2306
|
return make_array(paths).filter(function(path) {
|
|
2293
2307
|
return _this._filter(path);
|
|
@@ -2438,7 +2452,7 @@ var require_ignore = __commonJS((exports, module) => {
|
|
|
2438
2452
|
}
|
|
2439
2453
|
if (typeof process !== "undefined" && (process.env && process.env.IGNORE_TEST_WIN32 || process.platform === "win32")) {
|
|
2440
2454
|
filter = IgnoreBase.prototype._filter;
|
|
2441
|
-
make_posix = function
|
|
2455
|
+
make_posix = function make_posix2(str) {
|
|
2442
2456
|
return /^\\\\\?\\/.test(str) || /[^\x00-\x80]+/.test(str) ? str : str.replace(/\\/g, "/");
|
|
2443
2457
|
};
|
|
2444
2458
|
IgnoreBase.prototype._filter = function(path, slices) {
|
|
@@ -3039,25 +3053,25 @@ var require_minimatch = __commonJS((exports, module) => {
|
|
|
3039
3053
|
return minimatch;
|
|
3040
3054
|
}
|
|
3041
3055
|
var orig = minimatch;
|
|
3042
|
-
var m = function
|
|
3056
|
+
var m = function minimatch2(p, pattern, options) {
|
|
3043
3057
|
return orig(p, pattern, ext(def, options));
|
|
3044
3058
|
};
|
|
3045
|
-
m.Minimatch = function
|
|
3059
|
+
m.Minimatch = function Minimatch2(pattern, options) {
|
|
3046
3060
|
return new orig.Minimatch(pattern, ext(def, options));
|
|
3047
3061
|
};
|
|
3048
3062
|
m.Minimatch.defaults = function defaults(options) {
|
|
3049
3063
|
return orig.defaults(ext(def, options)).Minimatch;
|
|
3050
3064
|
};
|
|
3051
|
-
m.filter = function
|
|
3065
|
+
m.filter = function filter2(pattern, options) {
|
|
3052
3066
|
return orig.filter(pattern, ext(def, options));
|
|
3053
3067
|
};
|
|
3054
3068
|
m.defaults = function defaults(options) {
|
|
3055
3069
|
return orig.defaults(ext(def, options));
|
|
3056
3070
|
};
|
|
3057
|
-
m.makeRe = function
|
|
3071
|
+
m.makeRe = function makeRe2(pattern, options) {
|
|
3058
3072
|
return orig.makeRe(pattern, ext(def, options));
|
|
3059
3073
|
};
|
|
3060
|
-
m.braceExpand = function
|
|
3074
|
+
m.braceExpand = function braceExpand2(pattern, options) {
|
|
3061
3075
|
return orig.braceExpand(pattern, ext(def, options));
|
|
3062
3076
|
};
|
|
3063
3077
|
m.match = function(list, pattern, options) {
|
|
@@ -6584,7 +6598,7 @@ var require_colors = __commonJS((exports, module) => {
|
|
|
6584
6598
|
colors.stripColors = colors.strip = function(str) {
|
|
6585
6599
|
return ("" + str).replace(/\x1B\[\d+m/g, "");
|
|
6586
6600
|
};
|
|
6587
|
-
var stylize = colors.stylize = function
|
|
6601
|
+
var stylize = colors.stylize = function stylize2(str, style) {
|
|
6588
6602
|
if (!colors.enabled) {
|
|
6589
6603
|
return str + "";
|
|
6590
6604
|
}
|
|
@@ -6602,8 +6616,8 @@ var require_colors = __commonJS((exports, module) => {
|
|
|
6602
6616
|
return str.replace(matchOperatorsRe, "\\$&");
|
|
6603
6617
|
};
|
|
6604
6618
|
function build(_styles) {
|
|
6605
|
-
var builder = function
|
|
6606
|
-
return applyStyle2.apply(
|
|
6619
|
+
var builder = function builder2() {
|
|
6620
|
+
return applyStyle2.apply(builder2, arguments);
|
|
6607
6621
|
};
|
|
6608
6622
|
builder._styles = _styles;
|
|
6609
6623
|
builder.__proto__ = proto2;
|
|
@@ -6622,7 +6636,7 @@ var require_colors = __commonJS((exports, module) => {
|
|
|
6622
6636
|
});
|
|
6623
6637
|
return ret;
|
|
6624
6638
|
}();
|
|
6625
|
-
var proto2 = defineProps(function
|
|
6639
|
+
var proto2 = defineProps(function colors2() {}, styles3);
|
|
6626
6640
|
function applyStyle2() {
|
|
6627
6641
|
var args = Array.prototype.slice.call(arguments);
|
|
6628
6642
|
var str = args.map(function(arg) {
|
|
@@ -6681,7 +6695,7 @@ var require_colors = __commonJS((exports, module) => {
|
|
|
6681
6695
|
});
|
|
6682
6696
|
return ret;
|
|
6683
6697
|
}
|
|
6684
|
-
var sequencer = function
|
|
6698
|
+
var sequencer = function sequencer2(map2, str) {
|
|
6685
6699
|
var exploded = str.split("");
|
|
6686
6700
|
exploded = exploded.map(map2);
|
|
6687
6701
|
return exploded.join("");
|
|
@@ -11612,7 +11626,7 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
|
11612
11626
|
var __esm = (fn, res) => function __init() {
|
|
11613
11627
|
return fn && (res = (0, fn[__getOwnPropNames2(fn)[0]])(fn = 0)), res;
|
|
11614
11628
|
};
|
|
11615
|
-
var __commonJS2 = (cb, mod) => function
|
|
11629
|
+
var __commonJS2 = (cb, mod) => function __require2() {
|
|
11616
11630
|
return mod || (0, cb[__getOwnPropNames2(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
11617
11631
|
};
|
|
11618
11632
|
var __export = (target, all) => {
|
|
@@ -16080,6 +16094,26 @@ var import_cli_table3 = __toESM(require_table(), 1);
|
|
|
16080
16094
|
var DEFAULT_COLUMN_WIDTH = 50;
|
|
16081
16095
|
var MAX_LINE_LENGTH = 80;
|
|
16082
16096
|
var MAX_PATH_LENGTH = 60;
|
|
16097
|
+
var _silent = false;
|
|
16098
|
+
var _origConsoleLog = console.log;
|
|
16099
|
+
var _origConsoleWarn = console.warn;
|
|
16100
|
+
var _origConsoleError = console.error;
|
|
16101
|
+
var noop = () => {};
|
|
16102
|
+
var setSilent = (silent) => {
|
|
16103
|
+
_silent = silent;
|
|
16104
|
+
if (silent) {
|
|
16105
|
+
console.log = noop;
|
|
16106
|
+
console.warn = noop;
|
|
16107
|
+
console.error = noop;
|
|
16108
|
+
} else {
|
|
16109
|
+
console.log = _origConsoleLog;
|
|
16110
|
+
console.warn = _origConsoleWarn;
|
|
16111
|
+
console.error = _origConsoleError;
|
|
16112
|
+
}
|
|
16113
|
+
};
|
|
16114
|
+
var outputJson = (data) => {
|
|
16115
|
+
_origConsoleLog(JSON.stringify(data, null, 2));
|
|
16116
|
+
};
|
|
16083
16117
|
var log = {
|
|
16084
16118
|
success: (message) => console.log(source_default.green(`✓ ${message}`)),
|
|
16085
16119
|
error: (message) => console.error(source_default.red(`✗ ${message}`)),
|
|
@@ -16154,6 +16188,14 @@ var hasUnstagedChanges = async () => {
|
|
|
16154
16188
|
const unstagedFiles = await getUnstagedFiles();
|
|
16155
16189
|
return unstagedFiles.length > 0;
|
|
16156
16190
|
};
|
|
16191
|
+
var getStagedFiles = async () => {
|
|
16192
|
+
const status = await git.status();
|
|
16193
|
+
return status.files.filter((file) => file.index !== " " && file.index !== "?").map((file) => file.path);
|
|
16194
|
+
};
|
|
16195
|
+
var hasStagedChanges = async () => {
|
|
16196
|
+
const stagedFiles = await getStagedFiles();
|
|
16197
|
+
return stagedFiles.length > 0;
|
|
16198
|
+
};
|
|
16157
16199
|
var branchExists = async (branchName) => {
|
|
16158
16200
|
try {
|
|
16159
16201
|
const branches = await git.branch();
|
|
@@ -16219,10 +16261,8 @@ var checkout = async (name) => {
|
|
|
16219
16261
|
};
|
|
16220
16262
|
var commitChanges = async (files, { message, noVerify = false }) => {
|
|
16221
16263
|
try {
|
|
16222
|
-
log.info("Adding files to commit...");
|
|
16223
|
-
await git.add(files);
|
|
16224
16264
|
log.info(`Running commit with message: "${message}"`);
|
|
16225
|
-
await git.commit(message,
|
|
16265
|
+
await git.commit(message, files, {
|
|
16226
16266
|
...noVerify ? { "--no-verify": null } : {}
|
|
16227
16267
|
});
|
|
16228
16268
|
log.info("Commit finished successfully.");
|
|
@@ -16242,7 +16282,8 @@ var pushBranch = async (branchName, {
|
|
|
16242
16282
|
remote = "origin",
|
|
16243
16283
|
upstream,
|
|
16244
16284
|
force = false,
|
|
16245
|
-
noVerify = false
|
|
16285
|
+
noVerify = false,
|
|
16286
|
+
silent = false
|
|
16246
16287
|
} = {}) => {
|
|
16247
16288
|
const targetUpstream = upstream || branchName;
|
|
16248
16289
|
log.info(`Pushing branch "${branchName}" to ${remote}/${targetUpstream}...`);
|
|
@@ -16255,8 +16296,9 @@ var pushBranch = async (branchName, {
|
|
|
16255
16296
|
if (noVerify) {
|
|
16256
16297
|
pushArgs.push("--no-verify");
|
|
16257
16298
|
}
|
|
16299
|
+
const stdioOption = silent ? ["pipe", "pipe", "pipe"] : ["inherit", "inherit", "inherit"];
|
|
16258
16300
|
const gitProcess = spawn2("git", ["push", ...pushArgs], {
|
|
16259
|
-
stdio:
|
|
16301
|
+
stdio: stdioOption
|
|
16260
16302
|
});
|
|
16261
16303
|
return new Promise((resolve, reject) => {
|
|
16262
16304
|
gitProcess.on("close", (code) => {
|
|
@@ -16432,6 +16474,9 @@ var getOwnerFiles = async (ownerPattern, includeUnowned = false, pathPattern, ex
|
|
|
16432
16474
|
// src/commands/list.ts
|
|
16433
16475
|
var listCodeowners = async (options) => {
|
|
16434
16476
|
try {
|
|
16477
|
+
if (options.json) {
|
|
16478
|
+
setSilent(true);
|
|
16479
|
+
}
|
|
16435
16480
|
if (await hasUnstagedChanges()) {
|
|
16436
16481
|
const unstagedFiles = await getUnstagedFiles();
|
|
16437
16482
|
log.warn("Warning: Unstaged changes detected (these will be ignored):");
|
|
@@ -16464,6 +16509,34 @@ Only staged files will be processed.`);
|
|
|
16464
16509
|
return matchFn(owners, patterns);
|
|
16465
16510
|
});
|
|
16466
16511
|
}
|
|
16512
|
+
if (options.json) {
|
|
16513
|
+
let grouped;
|
|
16514
|
+
if (options.group) {
|
|
16515
|
+
grouped = {};
|
|
16516
|
+
for (const { file, owners } of filteredFiles) {
|
|
16517
|
+
if (owners.length === 0) {
|
|
16518
|
+
grouped["(unowned)"] = grouped["(unowned)"] || [];
|
|
16519
|
+
grouped["(unowned)"].push(file);
|
|
16520
|
+
} else {
|
|
16521
|
+
for (const owner of owners) {
|
|
16522
|
+
grouped[owner] = grouped[owner] || [];
|
|
16523
|
+
grouped[owner].push(file);
|
|
16524
|
+
}
|
|
16525
|
+
}
|
|
16526
|
+
}
|
|
16527
|
+
}
|
|
16528
|
+
outputJson({
|
|
16529
|
+
command: "list",
|
|
16530
|
+
...grouped ? { grouped } : { files: filteredFiles.map(({ file, owners }) => ({ file, owners })) },
|
|
16531
|
+
filters: {
|
|
16532
|
+
include: options.include || null,
|
|
16533
|
+
pathPattern: options.pathPattern || null,
|
|
16534
|
+
exclusive: options.exclusive || false,
|
|
16535
|
+
coOwned: options.coOwned || false
|
|
16536
|
+
}
|
|
16537
|
+
});
|
|
16538
|
+
return;
|
|
16539
|
+
}
|
|
16467
16540
|
if (options.group) {
|
|
16468
16541
|
const ownerGroups = new Map;
|
|
16469
16542
|
for (const { file, owners } of filteredFiles) {
|
|
@@ -16530,6 +16603,10 @@ Only staged files will be processed.`);
|
|
|
16530
16603
|
]);
|
|
16531
16604
|
}
|
|
16532
16605
|
} catch (err) {
|
|
16606
|
+
if (options.json) {
|
|
16607
|
+
outputJson({ command: "list", error: String(err) });
|
|
16608
|
+
process.exit(1);
|
|
16609
|
+
}
|
|
16533
16610
|
log.error(err);
|
|
16534
16611
|
process.exit(1);
|
|
16535
16612
|
}
|
|
@@ -16782,6 +16859,9 @@ var branch = async (options) => {
|
|
|
16782
16859
|
let operationState = options.operationState || null;
|
|
16783
16860
|
const isSubOperation = !!options.operationState;
|
|
16784
16861
|
let autoRecoverySucceeded = false;
|
|
16862
|
+
if (options.json && !isSubOperation) {
|
|
16863
|
+
setSilent(true);
|
|
16864
|
+
}
|
|
16785
16865
|
try {
|
|
16786
16866
|
if (!options.branch || !options.message || !options.include) {
|
|
16787
16867
|
throw new Error("Missing required options for branch creation");
|
|
@@ -16831,6 +16911,93 @@ Only staged files will be processed.`);
|
|
|
16831
16911
|
log.file(`Files to be committed:
|
|
16832
16912
|
${filesToCommit.join(`
|
|
16833
16913
|
`)}`);
|
|
16914
|
+
if (options.dryRun) {
|
|
16915
|
+
const allStagedFiles = await getChangedFiles();
|
|
16916
|
+
const excludedFiles = allStagedFiles.filter((f) => !filesToCommit.includes(f));
|
|
16917
|
+
const branchAlreadyExistsDry = await branchExists(options.branch);
|
|
16918
|
+
if (options.json && !isSubOperation) {
|
|
16919
|
+
outputJson({
|
|
16920
|
+
command: "branch",
|
|
16921
|
+
dryRun: true,
|
|
16922
|
+
owner: options.include,
|
|
16923
|
+
branch: options.branch,
|
|
16924
|
+
branchExists: branchAlreadyExistsDry,
|
|
16925
|
+
message: options.message,
|
|
16926
|
+
files: filesToCommit,
|
|
16927
|
+
excludedFiles,
|
|
16928
|
+
options: {
|
|
16929
|
+
push: options.push || false,
|
|
16930
|
+
remote: options.remote || "origin",
|
|
16931
|
+
force: options.force || false,
|
|
16932
|
+
pr: options.pr || false,
|
|
16933
|
+
draftPr: options.draftPr || false,
|
|
16934
|
+
noVerify: !options.verify,
|
|
16935
|
+
append: options.append || false,
|
|
16936
|
+
exclusive: options.exclusive || false,
|
|
16937
|
+
coOwned: options.coOwned || false,
|
|
16938
|
+
pathPattern: options.pathPattern || null
|
|
16939
|
+
}
|
|
16940
|
+
});
|
|
16941
|
+
return {
|
|
16942
|
+
success: true,
|
|
16943
|
+
branchName: options.branch,
|
|
16944
|
+
owner: options.include,
|
|
16945
|
+
files: filesToCommit,
|
|
16946
|
+
pushed: false
|
|
16947
|
+
};
|
|
16948
|
+
}
|
|
16949
|
+
if (!isSubOperation) {
|
|
16950
|
+
log.header("Dry Run Preview — branch");
|
|
16951
|
+
console.log("");
|
|
16952
|
+
}
|
|
16953
|
+
const detailsTable = new import_cli_table32.default({
|
|
16954
|
+
style: { head: ["cyan"] },
|
|
16955
|
+
wordWrap: true
|
|
16956
|
+
});
|
|
16957
|
+
detailsTable.push({ [source_default.bold("Owner pattern")]: options.include }, { [source_default.bold("Branch name")]: options.branch }, {
|
|
16958
|
+
[source_default.bold("Branch exists")]: branchAlreadyExistsDry ? options.append ? "Yes (--append: will add commit)" : "Yes (will fail without --append)" : "No (will be created)"
|
|
16959
|
+
}, { [source_default.bold("Commit message")]: options.message }, {
|
|
16960
|
+
[source_default.bold("Files matched")]: `${filesToCommit.length} file${filesToCommit.length !== 1 ? "s" : ""}`
|
|
16961
|
+
}, {
|
|
16962
|
+
[source_default.bold("Files excluded")]: `${excludedFiles.length} staged file${excludedFiles.length !== 1 ? "s" : ""} not matching`
|
|
16963
|
+
}, { [source_default.bold("No-verify")]: !options.verify ? "Yes" : "No" }, {
|
|
16964
|
+
[source_default.bold("Push")]: options.push ? `Yes → ${options.remote || "origin"}${options.force ? " (force)" : ""}` : "No"
|
|
16965
|
+
}, {
|
|
16966
|
+
[source_default.bold("Pull request")]: options.pr ? "Yes" : options.draftPr ? "Yes (draft)" : "No"
|
|
16967
|
+
});
|
|
16968
|
+
if (options.pathPattern) {
|
|
16969
|
+
detailsTable.push({
|
|
16970
|
+
[source_default.bold("Path filter")]: options.pathPattern
|
|
16971
|
+
});
|
|
16972
|
+
}
|
|
16973
|
+
if (options.exclusive) {
|
|
16974
|
+
detailsTable.push({
|
|
16975
|
+
[source_default.bold("Exclusive mode")]: "Yes (only files solely owned by this owner)"
|
|
16976
|
+
});
|
|
16977
|
+
}
|
|
16978
|
+
if (options.coOwned) {
|
|
16979
|
+
detailsTable.push({
|
|
16980
|
+
[source_default.bold("Co-owned mode")]: "Yes (only files with multiple owners)"
|
|
16981
|
+
});
|
|
16982
|
+
}
|
|
16983
|
+
console.log(detailsTable.toString());
|
|
16984
|
+
console.log(source_default.bold.green(`
|
|
16985
|
+
Files to be committed (${filesToCommit.length}):`));
|
|
16986
|
+
filesToCommit.forEach((file) => console.log(` ${source_default.green("+")} ${file}`));
|
|
16987
|
+
if (excludedFiles.length > 0) {
|
|
16988
|
+
console.log(source_default.bold.dim(`
|
|
16989
|
+
Excluded staged files (${excludedFiles.length}):`));
|
|
16990
|
+
excludedFiles.forEach((file) => console.log(` ${source_default.dim("-")} ${source_default.dim(file)}`));
|
|
16991
|
+
}
|
|
16992
|
+
console.log("");
|
|
16993
|
+
return {
|
|
16994
|
+
success: true,
|
|
16995
|
+
branchName: options.branch,
|
|
16996
|
+
owner: options.include,
|
|
16997
|
+
files: filesToCommit,
|
|
16998
|
+
pushed: false
|
|
16999
|
+
};
|
|
17000
|
+
}
|
|
16834
17001
|
const branchAlreadyExists = await branchExists(options.branch);
|
|
16835
17002
|
if (branchAlreadyExists && !options.append) {
|
|
16836
17003
|
throw new Error(`Branch "${options.branch}" already exists. Use --append to add commits to it, or use a different name.`);
|
|
@@ -16885,7 +17052,8 @@ Only staged files will be processed.`);
|
|
|
16885
17052
|
remote: options.remote,
|
|
16886
17053
|
upstream: options.upstream,
|
|
16887
17054
|
force: options.force,
|
|
16888
|
-
noVerify: !options.verify
|
|
17055
|
+
noVerify: !options.verify,
|
|
17056
|
+
silent: !!options.json
|
|
16889
17057
|
});
|
|
16890
17058
|
pushed = true;
|
|
16891
17059
|
if (operationState) {
|
|
@@ -16951,7 +17119,7 @@ Only staged files will be processed.`);
|
|
|
16951
17119
|
Files committed:`);
|
|
16952
17120
|
filesToCommit.forEach((file) => console.log(` - ${file}`));
|
|
16953
17121
|
}
|
|
16954
|
-
|
|
17122
|
+
const result = {
|
|
16955
17123
|
success: true,
|
|
16956
17124
|
branchName: options.branch,
|
|
16957
17125
|
owner: options.include,
|
|
@@ -16960,6 +17128,15 @@ Files committed:`);
|
|
|
16960
17128
|
prUrl,
|
|
16961
17129
|
prNumber
|
|
16962
17130
|
};
|
|
17131
|
+
if (options.json && !isSubOperation) {
|
|
17132
|
+
outputJson({
|
|
17133
|
+
command: "branch",
|
|
17134
|
+
dryRun: false,
|
|
17135
|
+
...result,
|
|
17136
|
+
error: null
|
|
17137
|
+
});
|
|
17138
|
+
}
|
|
17139
|
+
return result;
|
|
16963
17140
|
} catch (operationError) {
|
|
16964
17141
|
log.error(`Operation failed: ${operationError}`);
|
|
16965
17142
|
if (operationState && !isSubOperation) {
|
|
@@ -17029,6 +17206,21 @@ Files committed:`);
|
|
|
17029
17206
|
error: String(err)
|
|
17030
17207
|
};
|
|
17031
17208
|
}
|
|
17209
|
+
if (options.json && !isSubOperation) {
|
|
17210
|
+
outputJson({
|
|
17211
|
+
command: "branch",
|
|
17212
|
+
dryRun: false,
|
|
17213
|
+
success: false,
|
|
17214
|
+
branchName: options.branch ?? "",
|
|
17215
|
+
owner: options.include ?? "",
|
|
17216
|
+
files: filesToCommit,
|
|
17217
|
+
pushed,
|
|
17218
|
+
prUrl: prUrl || null,
|
|
17219
|
+
prNumber: prNumber || null,
|
|
17220
|
+
error: String(err)
|
|
17221
|
+
});
|
|
17222
|
+
process.exit(1);
|
|
17223
|
+
}
|
|
17032
17224
|
if (operationState && !autoRecoverySucceeded) {
|
|
17033
17225
|
log.info(`
|
|
17034
17226
|
Auto-recovery failed. Manual recovery options:`);
|
|
@@ -17051,7 +17243,6 @@ Auto-recovery failed. Manual recovery options:`);
|
|
|
17051
17243
|
}
|
|
17052
17244
|
}
|
|
17053
17245
|
};
|
|
17054
|
-
|
|
17055
17246
|
// node_modules/@inquirer/core/dist/esm/lib/key.js
|
|
17056
17247
|
var isUpKey = (key) => key.name === "up" || key.name === "k" || key.ctrl && key.name === "p";
|
|
17057
17248
|
var isDownKey = (key) => key.name === "down" || key.name === "j" || key.ctrl && key.name === "n";
|
|
@@ -18339,9 +18530,21 @@ Operation ID: ${op.id}`);
|
|
|
18339
18530
|
log.info(formatBranchState(op));
|
|
18340
18531
|
}
|
|
18341
18532
|
};
|
|
18342
|
-
var performRecovery = async (state, keepBranches) => {
|
|
18533
|
+
var performRecovery = async (state, keepBranches, options) => {
|
|
18343
18534
|
log.header(`Recovering from operation ${state.id}`);
|
|
18344
18535
|
let hadWarnings = false;
|
|
18536
|
+
if (!options?.skipDirtyCheck) {
|
|
18537
|
+
const hasUnstaged = await hasUnstagedChanges();
|
|
18538
|
+
const hasStaged = await hasStagedChanges();
|
|
18539
|
+
if (hasUnstaged || hasStaged) {
|
|
18540
|
+
log.warn("Working directory has uncommitted changes.");
|
|
18541
|
+
log.warn("Recovery may overwrite files in your working directory.");
|
|
18542
|
+
log.info("Consider committing or stashing your changes first:");
|
|
18543
|
+
log.info(" git stash push -m 'before recovery'");
|
|
18544
|
+
throw new Error("Working directory is not clean. Commit or stash changes before recovering.");
|
|
18545
|
+
}
|
|
18546
|
+
}
|
|
18547
|
+
const branchesWithRestoreFailure = new Set;
|
|
18345
18548
|
const currentBranch = await getCurrentBranch();
|
|
18346
18549
|
if (currentBranch !== state.originalBranch) {
|
|
18347
18550
|
try {
|
|
@@ -18372,7 +18575,8 @@ Restoring files from branches...`);
|
|
|
18372
18575
|
}
|
|
18373
18576
|
} catch (error) {
|
|
18374
18577
|
log.error(`Failed to restore files from ${branch2.name}: ${error}`);
|
|
18375
|
-
log.
|
|
18578
|
+
log.warn(`Branch ${branch2.name} will be kept to prevent data loss`);
|
|
18579
|
+
branchesWithRestoreFailure.add(branch2.name);
|
|
18376
18580
|
hadWarnings = true;
|
|
18377
18581
|
}
|
|
18378
18582
|
}
|
|
@@ -18383,6 +18587,12 @@ Restoring files from branches...`);
|
|
|
18383
18587
|
Cleaning up created branches...`);
|
|
18384
18588
|
for (const branch2 of state.branches) {
|
|
18385
18589
|
if (branch2.created) {
|
|
18590
|
+
if (branchesWithRestoreFailure.has(branch2.name)) {
|
|
18591
|
+
log.warn(`Skipping deletion of ${branch2.name} — file restoration failed, branch preserved to prevent data loss`);
|
|
18592
|
+
log.info(` To recover files manually: git checkout ${branch2.name} -- <file>`);
|
|
18593
|
+
log.info(` To delete manually when done: git branch -D ${branch2.name}`);
|
|
18594
|
+
continue;
|
|
18595
|
+
}
|
|
18386
18596
|
try {
|
|
18387
18597
|
const exists2 = await branchExists(branch2.name);
|
|
18388
18598
|
if (exists2) {
|
|
@@ -18480,6 +18690,9 @@ Operation details:`);
|
|
|
18480
18690
|
var import_cli_table33 = __toESM(require_table(), 1);
|
|
18481
18691
|
var multiBranch = async (options) => {
|
|
18482
18692
|
let operationState = null;
|
|
18693
|
+
if (options.json) {
|
|
18694
|
+
setSilent(true);
|
|
18695
|
+
}
|
|
18483
18696
|
try {
|
|
18484
18697
|
if (!options.branch || !options.message) {
|
|
18485
18698
|
throw new Error("Missing required options for multi-branch creation");
|
|
@@ -18558,6 +18771,137 @@ Only staged files will be processed.`);
|
|
|
18558
18771
|
}
|
|
18559
18772
|
log.info(`Processing ${codeowners2.length} codeowners after filtering: ${codeowners2.join(", ")}`);
|
|
18560
18773
|
}
|
|
18774
|
+
if (options.dryRun) {
|
|
18775
|
+
const previews = [];
|
|
18776
|
+
const allCoveredFiles = new Set;
|
|
18777
|
+
for (const owner of codeowners2) {
|
|
18778
|
+
const sanitizedOwner = owner.replace(/[^a-zA-Z0-9-_@]/g, "-").replace(/^@/, "");
|
|
18779
|
+
const branchName = `${options.branch}/${sanitizedOwner}`;
|
|
18780
|
+
const commitMessage = `${options.message} - ${owner}`;
|
|
18781
|
+
const ownerFiles = await getOwnerFiles(owner, owner === options.defaultOwner, options.pathPattern, options.exclusive || false, options.coOwned || false);
|
|
18782
|
+
for (const f of ownerFiles)
|
|
18783
|
+
allCoveredFiles.add(f);
|
|
18784
|
+
previews.push({
|
|
18785
|
+
owner,
|
|
18786
|
+
branchName,
|
|
18787
|
+
commitMessage,
|
|
18788
|
+
files: ownerFiles
|
|
18789
|
+
});
|
|
18790
|
+
}
|
|
18791
|
+
const uncoveredFiles = changedFiles.filter((f) => !allCoveredFiles.has(f));
|
|
18792
|
+
if (options.json) {
|
|
18793
|
+
outputJson({
|
|
18794
|
+
command: "multi-branch",
|
|
18795
|
+
dryRun: true,
|
|
18796
|
+
owners: previews.map((p) => ({
|
|
18797
|
+
owner: p.owner,
|
|
18798
|
+
branch: p.branchName,
|
|
18799
|
+
message: p.commitMessage,
|
|
18800
|
+
files: p.files
|
|
18801
|
+
})),
|
|
18802
|
+
uncoveredFiles,
|
|
18803
|
+
filesWithoutOwners: options.defaultOwner ? [] : filesWithoutOwners,
|
|
18804
|
+
totalFiles: changedFiles.length,
|
|
18805
|
+
coveredFiles: allCoveredFiles.size,
|
|
18806
|
+
options: {
|
|
18807
|
+
baseBranch: options.branch,
|
|
18808
|
+
baseMessage: options.message,
|
|
18809
|
+
push: options.push || false,
|
|
18810
|
+
remote: options.remote || "origin",
|
|
18811
|
+
force: options.force || false,
|
|
18812
|
+
pr: options.pr || false,
|
|
18813
|
+
draftPr: options.draftPr || false,
|
|
18814
|
+
noVerify: !options.verify,
|
|
18815
|
+
append: options.append || false,
|
|
18816
|
+
exclusive: options.exclusive || false,
|
|
18817
|
+
coOwned: options.coOwned || false,
|
|
18818
|
+
pathPattern: options.pathPattern || null,
|
|
18819
|
+
defaultOwner: options.defaultOwner || null
|
|
18820
|
+
}
|
|
18821
|
+
});
|
|
18822
|
+
return;
|
|
18823
|
+
}
|
|
18824
|
+
log.header("Dry Run Preview — multi-branch");
|
|
18825
|
+
console.log("");
|
|
18826
|
+
const settingsTable = new import_cli_table33.default({
|
|
18827
|
+
style: { head: ["cyan"] },
|
|
18828
|
+
wordWrap: true
|
|
18829
|
+
});
|
|
18830
|
+
settingsTable.push({ [source_default.bold("Base branch name")]: options.branch }, { [source_default.bold("Base commit message")]: options.message }, { [source_default.bold("Total codeowners")]: `${codeowners2.length}` }, { [source_default.bold("No-verify")]: !options.verify ? "Yes" : "No" }, {
|
|
18831
|
+
[source_default.bold("Push")]: options.push ? `Yes → ${options.remote || "origin"}${options.force ? " (force)" : ""}` : "No"
|
|
18832
|
+
}, {
|
|
18833
|
+
[source_default.bold("Pull request")]: options.pr ? "Yes" : options.draftPr ? "Yes (draft)" : "No"
|
|
18834
|
+
}, { [source_default.bold("Append mode")]: options.append ? "Yes" : "No" });
|
|
18835
|
+
if (options.pathPattern) {
|
|
18836
|
+
settingsTable.push({
|
|
18837
|
+
[source_default.bold("Path filter")]: options.pathPattern
|
|
18838
|
+
});
|
|
18839
|
+
}
|
|
18840
|
+
if (options.exclusive) {
|
|
18841
|
+
settingsTable.push({
|
|
18842
|
+
[source_default.bold("Exclusive mode")]: "Yes (only files solely owned by each owner)"
|
|
18843
|
+
});
|
|
18844
|
+
}
|
|
18845
|
+
if (options.coOwned) {
|
|
18846
|
+
settingsTable.push({
|
|
18847
|
+
[source_default.bold("Co-owned mode")]: "Yes (only files with multiple owners)"
|
|
18848
|
+
});
|
|
18849
|
+
}
|
|
18850
|
+
if (options.defaultOwner) {
|
|
18851
|
+
settingsTable.push({
|
|
18852
|
+
[source_default.bold("Default owner")]: options.defaultOwner
|
|
18853
|
+
});
|
|
18854
|
+
}
|
|
18855
|
+
console.log(settingsTable.toString());
|
|
18856
|
+
console.log("");
|
|
18857
|
+
const summaryTable = new import_cli_table33.default({
|
|
18858
|
+
head: ["Owner", "Branch", "Files", "Commit Message"],
|
|
18859
|
+
colWidths: [22, 35, 8, 45],
|
|
18860
|
+
wordWrap: true,
|
|
18861
|
+
style: { head: ["cyan"] }
|
|
18862
|
+
});
|
|
18863
|
+
for (const p of previews) {
|
|
18864
|
+
summaryTable.push([
|
|
18865
|
+
p.owner,
|
|
18866
|
+
p.branchName,
|
|
18867
|
+
`${p.files.length}`,
|
|
18868
|
+
p.commitMessage
|
|
18869
|
+
]);
|
|
18870
|
+
}
|
|
18871
|
+
console.log(summaryTable.toString());
|
|
18872
|
+
console.log(source_default.bold.cyan(`
|
|
18873
|
+
Files by branch:`));
|
|
18874
|
+
for (const p of previews) {
|
|
18875
|
+
if (p.files.length > 0) {
|
|
18876
|
+
console.log(`
|
|
18877
|
+
${source_default.bold(p.branchName)} ${source_default.dim(`(${p.owner})`)} — ${p.files.length} file${p.files.length !== 1 ? "s" : ""}:`);
|
|
18878
|
+
p.files.forEach((file) => console.log(` ${source_default.green("+")} ${file}`));
|
|
18879
|
+
} else {
|
|
18880
|
+
console.log(`
|
|
18881
|
+
${source_default.bold(p.branchName)} ${source_default.dim(`(${p.owner})`)} — ${source_default.yellow("0 files (branch will be skipped)")}`);
|
|
18882
|
+
}
|
|
18883
|
+
}
|
|
18884
|
+
if (uncoveredFiles.length > 0) {
|
|
18885
|
+
console.log(source_default.bold.yellow(`
|
|
18886
|
+
Uncovered staged files (${uncoveredFiles.length}) — not included in any branch:`));
|
|
18887
|
+
uncoveredFiles.forEach((file) => console.log(` ${source_default.yellow("!")} ${file}`));
|
|
18888
|
+
}
|
|
18889
|
+
if (filesWithoutOwners.length > 0 && !options.defaultOwner) {
|
|
18890
|
+
console.log(source_default.bold.yellow(`
|
|
18891
|
+
Files without CODEOWNERS (${filesWithoutOwners.length}):`));
|
|
18892
|
+
filesWithoutOwners.forEach((file) => console.log(` ${source_default.yellow("?")} ${file}`));
|
|
18893
|
+
console.log(source_default.dim(" Tip: Use --default-owner <owner> to assign these files"));
|
|
18894
|
+
}
|
|
18895
|
+
console.log(source_default.bold.cyan(`
|
|
18896
|
+
Summary:`));
|
|
18897
|
+
console.log(` Branches to create: ${source_default.bold(`${previews.length}`)}`);
|
|
18898
|
+
console.log(` Total files covered: ${source_default.bold(`${allCoveredFiles.size}`)} of ${changedFiles.length} staged`);
|
|
18899
|
+
if (uncoveredFiles.length > 0) {
|
|
18900
|
+
console.log(` Uncovered files: ${source_default.yellow(`${uncoveredFiles.length}`)}`);
|
|
18901
|
+
}
|
|
18902
|
+
console.log("");
|
|
18903
|
+
return;
|
|
18904
|
+
}
|
|
18561
18905
|
const results = [];
|
|
18562
18906
|
for (const owner of codeowners2) {
|
|
18563
18907
|
const sanitizedOwner = owner.replace(/[^a-zA-Z0-9-_@]/g, "-").replace(/^@/, "");
|
|
@@ -18581,7 +18925,8 @@ Only staged files will be processed.`);
|
|
|
18581
18925
|
operationState: operationState || undefined,
|
|
18582
18926
|
pathPattern: options.pathPattern,
|
|
18583
18927
|
exclusive: options.exclusive,
|
|
18584
|
-
coOwned: options.coOwned
|
|
18928
|
+
coOwned: options.coOwned,
|
|
18929
|
+
json: options.json
|
|
18585
18930
|
});
|
|
18586
18931
|
results.push(result);
|
|
18587
18932
|
}
|
|
@@ -18644,7 +18989,36 @@ Note: ${failureCount} branch(es) failed. Files were auto-restored to working dir
|
|
|
18644
18989
|
log.info(`State preserved for reference. Run 'codeowners-git recover --id ${operationState.id}' if needed.`);
|
|
18645
18990
|
}
|
|
18646
18991
|
}
|
|
18992
|
+
if (options.json) {
|
|
18993
|
+
outputJson({
|
|
18994
|
+
command: "multi-branch",
|
|
18995
|
+
dryRun: false,
|
|
18996
|
+
success: failureCount === 0,
|
|
18997
|
+
totalOwners: codeowners2.length,
|
|
18998
|
+
successCount,
|
|
18999
|
+
failureCount,
|
|
19000
|
+
results: results.map((r) => ({
|
|
19001
|
+
owner: r.owner,
|
|
19002
|
+
branch: r.branchName,
|
|
19003
|
+
success: r.success,
|
|
19004
|
+
files: r.files,
|
|
19005
|
+
pushed: r.pushed,
|
|
19006
|
+
prUrl: r.prUrl || null,
|
|
19007
|
+
prNumber: r.prNumber || null,
|
|
19008
|
+
error: r.error || null
|
|
19009
|
+
}))
|
|
19010
|
+
});
|
|
19011
|
+
}
|
|
18647
19012
|
} catch (err) {
|
|
19013
|
+
if (options.json) {
|
|
19014
|
+
outputJson({
|
|
19015
|
+
command: "multi-branch",
|
|
19016
|
+
dryRun: false,
|
|
19017
|
+
success: false,
|
|
19018
|
+
error: String(err)
|
|
19019
|
+
});
|
|
19020
|
+
process.exit(1);
|
|
19021
|
+
}
|
|
18648
19022
|
log.error(`Multi-branch operation failed: ${err}`);
|
|
18649
19023
|
if (operationState) {
|
|
18650
19024
|
log.info(`
|
|
@@ -18652,7 +19026,7 @@ Attempting auto-recovery...`);
|
|
|
18652
19026
|
const currentState = loadOperationState(operationState.id);
|
|
18653
19027
|
if (currentState) {
|
|
18654
19028
|
try {
|
|
18655
|
-
const recovered = await performRecovery(currentState, false);
|
|
19029
|
+
const recovered = await performRecovery(currentState, false, { skipDirtyCheck: true });
|
|
18656
19030
|
if (recovered) {
|
|
18657
19031
|
log.success("Auto-recovery completed successfully");
|
|
18658
19032
|
} else {
|
|
@@ -18672,7 +19046,11 @@ Manual recovery options:`);
|
|
|
18672
19046
|
};
|
|
18673
19047
|
|
|
18674
19048
|
// src/commands/extract.ts
|
|
19049
|
+
var import_cli_table34 = __toESM(require_table(), 1);
|
|
18675
19050
|
var extract = async (options) => {
|
|
19051
|
+
if (options.json) {
|
|
19052
|
+
setSilent(true);
|
|
19053
|
+
}
|
|
18676
19054
|
try {
|
|
18677
19055
|
if (!options.source) {
|
|
18678
19056
|
log.error("Missing required option: --source");
|
|
@@ -18760,8 +19138,82 @@ Only staged files will be processed.`);
|
|
|
18760
19138
|
}
|
|
18761
19139
|
log.info(`Filtered to ${filesToExtract.length} file${filesToExtract.length !== 1 ? "s" : ""}`);
|
|
18762
19140
|
}
|
|
19141
|
+
if (options.dryRun) {
|
|
19142
|
+
const excludedFiles = changedFiles.filter((f) => !filesToExtract.includes(f));
|
|
19143
|
+
if (options.json) {
|
|
19144
|
+
outputJson({
|
|
19145
|
+
command: "extract",
|
|
19146
|
+
dryRun: true,
|
|
19147
|
+
source: options.source,
|
|
19148
|
+
compareTarget: compareTarget || null,
|
|
19149
|
+
files: filesToExtract,
|
|
19150
|
+
excludedFiles,
|
|
19151
|
+
totalChanged: changedFiles.length,
|
|
19152
|
+
options: {
|
|
19153
|
+
include: options.include || null,
|
|
19154
|
+
pathPattern: options.pathPattern || null,
|
|
19155
|
+
exclusive: options.exclusive || false,
|
|
19156
|
+
coOwned: options.coOwned || false,
|
|
19157
|
+
compareMain: options.compareMain || false
|
|
19158
|
+
}
|
|
19159
|
+
});
|
|
19160
|
+
return;
|
|
19161
|
+
}
|
|
19162
|
+
log.header("Dry Run Preview — extract");
|
|
19163
|
+
console.log("");
|
|
19164
|
+
const detailsTable = new import_cli_table34.default({
|
|
19165
|
+
style: { head: ["cyan"] },
|
|
19166
|
+
wordWrap: true
|
|
19167
|
+
});
|
|
19168
|
+
detailsTable.push({ [source_default.bold("Source")]: options.source }, {
|
|
19169
|
+
[source_default.bold("Compare target")]: compareTarget || "auto-detected"
|
|
19170
|
+
}, {
|
|
19171
|
+
[source_default.bold("Files in source")]: `${changedFiles.length} changed file${changedFiles.length !== 1 ? "s" : ""}`
|
|
19172
|
+
}, {
|
|
19173
|
+
[source_default.bold("Files to extract")]: `${filesToExtract.length} file${filesToExtract.length !== 1 ? "s" : ""}`
|
|
19174
|
+
}, {
|
|
19175
|
+
[source_default.bold("Files excluded")]: `${excludedFiles.length} file${excludedFiles.length !== 1 ? "s" : ""} (filtered out)`
|
|
19176
|
+
});
|
|
19177
|
+
if (options.include) {
|
|
19178
|
+
detailsTable.push({
|
|
19179
|
+
[source_default.bold("Owner filter")]: `${options.include}${options.exclusive ? " (exclusive)" : ""}`
|
|
19180
|
+
});
|
|
19181
|
+
}
|
|
19182
|
+
if (options.pathPattern) {
|
|
19183
|
+
detailsTable.push({
|
|
19184
|
+
[source_default.bold("Path filter")]: options.pathPattern
|
|
19185
|
+
});
|
|
19186
|
+
}
|
|
19187
|
+
if (options.coOwned) {
|
|
19188
|
+
detailsTable.push({
|
|
19189
|
+
[source_default.bold("Co-owned mode")]: "Yes (only files with multiple owners)"
|
|
19190
|
+
});
|
|
19191
|
+
}
|
|
19192
|
+
console.log(detailsTable.toString());
|
|
19193
|
+
console.log(source_default.bold.green(`
|
|
19194
|
+
Files to be extracted (${filesToExtract.length}):`));
|
|
19195
|
+
filesToExtract.forEach((file) => console.log(` ${source_default.green("+")} ${file}`));
|
|
19196
|
+
if (excludedFiles.length > 0) {
|
|
19197
|
+
console.log(source_default.bold.dim(`
|
|
19198
|
+
Excluded files (${excludedFiles.length}):`));
|
|
19199
|
+
excludedFiles.forEach((file) => console.log(` ${source_default.dim("-")} ${source_default.dim(file)}`));
|
|
19200
|
+
}
|
|
19201
|
+
console.log("");
|
|
19202
|
+
return;
|
|
19203
|
+
}
|
|
18763
19204
|
log.info("Extracting files to working directory...");
|
|
18764
19205
|
await extractFilesFromRef(options.source, filesToExtract);
|
|
19206
|
+
if (options.json) {
|
|
19207
|
+
outputJson({
|
|
19208
|
+
command: "extract",
|
|
19209
|
+
dryRun: false,
|
|
19210
|
+
source: options.source,
|
|
19211
|
+
compareTarget: compareTarget || null,
|
|
19212
|
+
files: filesToExtract,
|
|
19213
|
+
totalChanged: changedFiles.length
|
|
19214
|
+
});
|
|
19215
|
+
return;
|
|
19216
|
+
}
|
|
18765
19217
|
log.success(`
|
|
18766
19218
|
✓ Extracted ${filesToExtract.length} file${filesToExtract.length !== 1 ? "s" : ""} to working directory (unstaged)`);
|
|
18767
19219
|
log.info(`
|
|
@@ -18773,13 +19225,17 @@ Next steps:`);
|
|
|
18773
19225
|
log.info(" - Use 'cg branch' command to create a branch and commit");
|
|
18774
19226
|
log.info(" - Example: cg branch -i @my-team -b my-branch -m 'Commit message' -p");
|
|
18775
19227
|
} catch (err) {
|
|
19228
|
+
if (options.json) {
|
|
19229
|
+
outputJson({ command: "extract", error: String(err) });
|
|
19230
|
+
process.exit(1);
|
|
19231
|
+
}
|
|
18776
19232
|
log.error(`
|
|
18777
19233
|
✗ Extraction failed: ${err}`);
|
|
18778
19234
|
process.exit(1);
|
|
18779
19235
|
}
|
|
18780
19236
|
};
|
|
18781
19237
|
// package.json
|
|
18782
|
-
var version = "2.0
|
|
19238
|
+
var version = "2.1.0";
|
|
18783
19239
|
|
|
18784
19240
|
// src/commands/version.ts
|
|
18785
19241
|
function getVersion() {
|
|
@@ -18800,15 +19256,28 @@ Force exiting...`);
|
|
|
18800
19256
|
|
|
18801
19257
|
Received ${signal}. Gracefully shutting down...`);
|
|
18802
19258
|
const incompleteOps = getIncompleteOperations();
|
|
18803
|
-
if (incompleteOps.length
|
|
18804
|
-
|
|
19259
|
+
if (incompleteOps.length === 0) {
|
|
19260
|
+
process.exit(130);
|
|
19261
|
+
return;
|
|
19262
|
+
}
|
|
19263
|
+
const mostRecent = incompleteOps[0];
|
|
19264
|
+
log.warn(`Found ${incompleteOps.length} incomplete operation(s).`);
|
|
19265
|
+
getCurrentBranch().then((currentBranch) => {
|
|
19266
|
+
if (currentBranch !== mostRecent.originalBranch) {
|
|
19267
|
+
log.info(`Returning to original branch: ${mostRecent.originalBranch}...`);
|
|
19268
|
+
return checkout(mostRecent.originalBranch).then(() => {
|
|
19269
|
+
log.success(`Returned to ${mostRecent.originalBranch}`);
|
|
19270
|
+
});
|
|
19271
|
+
}
|
|
19272
|
+
}).catch(() => {
|
|
19273
|
+
log.warn("Could not return to original branch automatically.");
|
|
19274
|
+
}).finally(() => {
|
|
18805
19275
|
log.info(`
|
|
18806
|
-
To recover from incomplete operations, run:`);
|
|
18807
|
-
log.info(" codeowners-git recover --list # List all incomplete operations");
|
|
19276
|
+
To fully recover from incomplete operations, run:`);
|
|
18808
19277
|
log.info(" codeowners-git recover --auto # Auto-recover most recent operation");
|
|
18809
|
-
log.info(" codeowners-git recover --
|
|
18810
|
-
|
|
18811
|
-
|
|
19278
|
+
log.info(" codeowners-git recover --list # List all incomplete operations");
|
|
19279
|
+
process.exit(130);
|
|
19280
|
+
});
|
|
18812
19281
|
};
|
|
18813
19282
|
process.on("SIGINT", () => handleShutdown("SIGINT"));
|
|
18814
19283
|
process.on("SIGTERM", () => handleShutdown("SIGTERM"));
|
|
@@ -18818,7 +19287,7 @@ To recover from incomplete operations, run:`);
|
|
|
18818
19287
|
setupSignalHandlers();
|
|
18819
19288
|
var program2 = new Command;
|
|
18820
19289
|
program2.name("codeowners-git (cg)").description("CLI tool for grouping and managing staged files by CODEOWNERS").version(getVersion());
|
|
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) => {
|
|
19290
|
+
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)").option("--json", "Output results as JSON (suppresses all other output)").action((pattern, options) => {
|
|
18822
19291
|
if (options.exclusive && options.coOwned) {
|
|
18823
19292
|
console.error("Error: Cannot use both --exclusive and --co-owned options");
|
|
18824
19293
|
process.exit(1);
|
|
@@ -18828,7 +19297,7 @@ program2.command("list").description("Lists all git changed files by CODEOWNER")
|
|
|
18828
19297
|
pathPattern: pattern
|
|
18829
19298
|
});
|
|
18830
19299
|
});
|
|
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) => {
|
|
19300
|
+
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)").option("--dry-run", "Preview the operation without making any changes").option("--json", "Output results as JSON (suppresses all other output)").action((pattern, options) => {
|
|
18832
19301
|
if (options.exclusive && options.coOwned) {
|
|
18833
19302
|
console.error("Error: Cannot use both --exclusive and --co-owned options");
|
|
18834
19303
|
process.exit(1);
|
|
@@ -18838,7 +19307,7 @@ program2.command("branch").description("Create new branch with codeowner changes
|
|
|
18838
19307
|
pathPattern: pattern
|
|
18839
19308
|
});
|
|
18840
19309
|
});
|
|
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) => {
|
|
19310
|
+
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)").option("--dry-run", "Preview the operation without making any changes").option("--json", "Output results as JSON (suppresses all other output)").action((pattern, options) => {
|
|
18842
19311
|
if (options.exclusive && options.coOwned) {
|
|
18843
19312
|
console.error("Error: Cannot use both --exclusive and --co-owned options");
|
|
18844
19313
|
process.exit(1);
|
|
@@ -18848,7 +19317,7 @@ program2.command("multi-branch").description("Create branches for all codeowners
|
|
|
18848
19317
|
pathPattern: pattern
|
|
18849
19318
|
});
|
|
18850
19319
|
});
|
|
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) => {
|
|
19320
|
+
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)").option("--dry-run", "Preview the operation without making any changes").option("--json", "Output results as JSON (suppresses all other output)").action((pattern, options) => {
|
|
18852
19321
|
if (options.exclusive && options.coOwned) {
|
|
18853
19322
|
console.error("Error: Cannot use both --exclusive and --co-owned options");
|
|
18854
19323
|
process.exit(1);
|