codeowners-git 1.2.0 → 1.3.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 +22 -4
- package/dist/cli.js +72 -47
- 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
|
|
|
15
|
+
> **Note:** This tool works with **unstaged files**. Make sure to check if your files are unstaged before proceeding.
|
|
16
|
+
|
|
15
17
|
https://github.com/user-attachments/assets/7cc0a924-f03e-47f3-baad-63eca9e8e4a8
|
|
16
18
|
|
|
17
19
|
## Installation
|
|
@@ -107,7 +109,7 @@ codeowners-git multi-branch [options]
|
|
|
107
109
|
|
|
108
110
|
Options:
|
|
109
111
|
|
|
110
|
-
- `--branch, -b` Base branch name (will be
|
|
112
|
+
- `--branch, -b` Base branch name (will be suffixed with codeowner name)
|
|
111
113
|
- `--message, -m` Base commit message (will be suffixed with codeowner name)
|
|
112
114
|
- `--no-verify, -n` Skips lint-staged and other checks before committing
|
|
113
115
|
- `--push, -p` Push branches to remote after commit
|
|
@@ -115,18 +117,34 @@ Options:
|
|
|
115
117
|
- `--upstream, -u` Upstream branch name pattern (defaults to local branch name)
|
|
116
118
|
- `--force, -f` Force push to remote
|
|
117
119
|
- `--keep-branch-on-failure, -k` Keep created branches even if operation fails
|
|
120
|
+
- `--default-owner, -d` Default owner to use when no codeowners are found for changed files
|
|
121
|
+
- `--ignore` Comma-separated patterns to exclude codeowners (e.g., 'team-a,team-b')
|
|
122
|
+
- `--include` Comma-separated patterns to include codeowners (e.g., 'team-_,@org/_')
|
|
123
|
+
|
|
124
|
+
> **Note:** You cannot use both `--ignore` and `--include` options at the same time.
|
|
118
125
|
|
|
119
126
|
Example:
|
|
120
127
|
|
|
121
128
|
```bash
|
|
129
|
+
# Create branches for all codeowners
|
|
122
130
|
codeowners-git multi-branch -b "feature/new-feature" -m "Add new feature" -p
|
|
131
|
+
|
|
132
|
+
# Exclude specific teams
|
|
133
|
+
codeowners-git multi-branch -b "feature/new-feature" -m "Add new feature" --ignore "@ce-orca,@ce-ece"
|
|
134
|
+
|
|
135
|
+
# Include only specific patterns
|
|
136
|
+
codeowners-git multi-branch -b "feature/new-feature" -m "Add new feature" --include "@team-*"
|
|
137
|
+
|
|
138
|
+
# Use default owner when no codeowners found
|
|
139
|
+
codeowners-git multi-branch -b "feature/new-feature" -m "Add new feature" -d "@default-team"
|
|
123
140
|
```
|
|
124
141
|
|
|
125
142
|
This will:
|
|
126
143
|
|
|
127
|
-
1. Find all codeowners for the
|
|
128
|
-
2.
|
|
129
|
-
|
|
144
|
+
1. Find all codeowners for the staged files in your repository
|
|
145
|
+
2. Apply any ignore/include filters if specified
|
|
146
|
+
3. For each codeowner (e.g., @team-a, @team-b):
|
|
147
|
+
- Create a branch like `feature/new-feature/team-a`
|
|
130
148
|
- Commit only the files owned by that team
|
|
131
149
|
- Add a commit message like "Add new feature - @team-a"
|
|
132
150
|
- Push each branch to the remote if the `-p` flag is provided
|
package/dist/cli.js
CHANGED
|
@@ -965,8 +965,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
965
965
|
this._exitCallback = (err) => {
|
|
966
966
|
if (err.code !== "commander.executeSubCommandAsync") {
|
|
967
967
|
throw err;
|
|
968
|
-
} else {
|
|
969
|
-
}
|
|
968
|
+
} else {}
|
|
970
969
|
};
|
|
971
970
|
}
|
|
972
971
|
return this;
|
|
@@ -2133,8 +2132,7 @@ var require_p_locate = __commonJS((exports, module) => {
|
|
|
2133
2132
|
const limit = pLimit(opts.concurrency);
|
|
2134
2133
|
const items = Array.from(iterable).map((el) => [el, limit(() => Promise.resolve(el).then(tester))]);
|
|
2135
2134
|
const checkLimit = pLimit(opts.preserveOrder ? 1 : Infinity);
|
|
2136
|
-
return Promise.all(items.map((el) => checkLimit(() => finder(el)))).then(() => {
|
|
2137
|
-
}).catch((err) => err instanceof EndError ? err.value : Promise.reject(err));
|
|
2135
|
+
return Promise.all(items.map((el) => checkLimit(() => finder(el)))).then(() => {}).catch((err) => err instanceof EndError ? err.value : Promise.reject(err));
|
|
2138
2136
|
};
|
|
2139
2137
|
});
|
|
2140
2138
|
|
|
@@ -2992,8 +2990,7 @@ var require_minimatch = __commonJS((exports, module) => {
|
|
|
2992
2990
|
var path = function() {
|
|
2993
2991
|
try {
|
|
2994
2992
|
return __require("path");
|
|
2995
|
-
} catch (e) {
|
|
2996
|
-
}
|
|
2993
|
+
} catch (e) {}
|
|
2997
2994
|
}() || {
|
|
2998
2995
|
sep: "/"
|
|
2999
2996
|
};
|
|
@@ -3101,8 +3098,7 @@ var require_minimatch = __commonJS((exports, module) => {
|
|
|
3101
3098
|
this.partial = !!options.partial;
|
|
3102
3099
|
this.make();
|
|
3103
3100
|
}
|
|
3104
|
-
Minimatch.prototype.debug = function() {
|
|
3105
|
-
};
|
|
3101
|
+
Minimatch.prototype.debug = function() {};
|
|
3106
3102
|
Minimatch.prototype.make = make;
|
|
3107
3103
|
function make() {
|
|
3108
3104
|
var pattern = this.pattern;
|
|
@@ -3224,7 +3220,7 @@ var require_minimatch = __commonJS((exports, module) => {
|
|
|
3224
3220
|
}
|
|
3225
3221
|
}
|
|
3226
3222
|
for (var i = 0, len = pattern.length, c;i < len && (c = pattern.charAt(i)); i++) {
|
|
3227
|
-
this.debug("%s
|
|
3223
|
+
this.debug("%s %s %s %j", pattern, i, re, c);
|
|
3228
3224
|
if (escaping && reSpecials[c]) {
|
|
3229
3225
|
re += "\\" + c;
|
|
3230
3226
|
escaping = false;
|
|
@@ -3243,7 +3239,7 @@ var require_minimatch = __commonJS((exports, module) => {
|
|
|
3243
3239
|
case "+":
|
|
3244
3240
|
case "@":
|
|
3245
3241
|
case "!":
|
|
3246
|
-
this.debug("%s
|
|
3242
|
+
this.debug("%s %s %s %j <-- stateChar", pattern, i, re, c);
|
|
3247
3243
|
if (inClass) {
|
|
3248
3244
|
this.debug(" in class");
|
|
3249
3245
|
if (c === "!" && i === classStart + 1)
|
|
@@ -3593,8 +3589,7 @@ var require_inherits_browser = __commonJS((exports, module) => {
|
|
|
3593
3589
|
module.exports = function inherits(ctor, superCtor) {
|
|
3594
3590
|
if (superCtor) {
|
|
3595
3591
|
ctor.super_ = superCtor;
|
|
3596
|
-
var TempCtor = function() {
|
|
3597
|
-
};
|
|
3592
|
+
var TempCtor = function() {};
|
|
3598
3593
|
TempCtor.prototype = superCtor.prototype;
|
|
3599
3594
|
ctor.prototype = new TempCtor;
|
|
3600
3595
|
ctor.prototype.constructor = ctor;
|
|
@@ -5331,8 +5326,7 @@ var require_browser = __commonJS((exports, module) => {
|
|
|
5331
5326
|
});
|
|
5332
5327
|
args.splice(lastC, 0, c);
|
|
5333
5328
|
}
|
|
5334
|
-
exports.log = console.debug || console.log || (() => {
|
|
5335
|
-
});
|
|
5329
|
+
exports.log = console.debug || console.log || (() => {});
|
|
5336
5330
|
function save(namespaces) {
|
|
5337
5331
|
try {
|
|
5338
5332
|
if (namespaces) {
|
|
@@ -5340,15 +5334,13 @@ var require_browser = __commonJS((exports, module) => {
|
|
|
5340
5334
|
} else {
|
|
5341
5335
|
exports.storage.removeItem("debug");
|
|
5342
5336
|
}
|
|
5343
|
-
} catch (error) {
|
|
5344
|
-
}
|
|
5337
|
+
} catch (error) {}
|
|
5345
5338
|
}
|
|
5346
5339
|
function load() {
|
|
5347
5340
|
let r;
|
|
5348
5341
|
try {
|
|
5349
5342
|
r = exports.storage.getItem("debug");
|
|
5350
|
-
} catch (error) {
|
|
5351
|
-
}
|
|
5343
|
+
} catch (error) {}
|
|
5352
5344
|
if (!r && typeof process !== "undefined" && "env" in process) {
|
|
5353
5345
|
r = process.env.DEBUG;
|
|
5354
5346
|
}
|
|
@@ -5357,8 +5349,7 @@ var require_browser = __commonJS((exports, module) => {
|
|
|
5357
5349
|
function localstorage() {
|
|
5358
5350
|
try {
|
|
5359
5351
|
return localStorage;
|
|
5360
|
-
} catch (error) {
|
|
5361
|
-
}
|
|
5352
|
+
} catch (error) {}
|
|
5362
5353
|
}
|
|
5363
5354
|
module.exports = require_common2()(exports);
|
|
5364
5355
|
var { formatters } = module.exports;
|
|
@@ -5419,8 +5410,7 @@ var require_node = __commonJS((exports, module) => {
|
|
|
5419
5410
|
exports.save = save;
|
|
5420
5411
|
exports.load = load;
|
|
5421
5412
|
exports.useColors = useColors;
|
|
5422
|
-
exports.destroy = util.deprecate(() => {
|
|
5423
|
-
}, "Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.");
|
|
5413
|
+
exports.destroy = util.deprecate(() => {}, "Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.");
|
|
5424
5414
|
exports.colors = [6, 2, 3, 4, 5, 1];
|
|
5425
5415
|
try {
|
|
5426
5416
|
const supportsColor = require_supports_color();
|
|
@@ -5504,8 +5494,7 @@ var require_node = __commonJS((exports, module) => {
|
|
|
5504
5494
|
221
|
|
5505
5495
|
];
|
|
5506
5496
|
}
|
|
5507
|
-
} catch (error) {
|
|
5508
|
-
}
|
|
5497
|
+
} catch (error) {}
|
|
5509
5498
|
exports.inspectOpts = Object.keys(process.env).filter((key) => {
|
|
5510
5499
|
return /^debug_/i.test(key);
|
|
5511
5500
|
}).reduce((obj, key) => {
|
|
@@ -6633,8 +6622,7 @@ var require_colors = __commonJS((exports, module) => {
|
|
|
6633
6622
|
});
|
|
6634
6623
|
return ret;
|
|
6635
6624
|
}();
|
|
6636
|
-
var proto2 = defineProps(function colors() {
|
|
6637
|
-
}, styles3);
|
|
6625
|
+
var proto2 = defineProps(function colors() {}, styles3);
|
|
6638
6626
|
function applyStyle2() {
|
|
6639
6627
|
var args = Array.prototype.slice.call(arguments);
|
|
6640
6628
|
var str = args.map(function(arg) {
|
|
@@ -6822,8 +6810,7 @@ var require_cell = __commonJS((exports, module) => {
|
|
|
6822
6810
|
let content = utils.truncate(this.content, 10, this.truncate);
|
|
6823
6811
|
if (!lineNum) {
|
|
6824
6812
|
info(`${this.y}-${this.x}: ${this.rowSpan - lineNum}x${this.colSpan} Cell ${content}`);
|
|
6825
|
-
} else {
|
|
6826
|
-
}
|
|
6813
|
+
} else {}
|
|
6827
6814
|
let padLen = Math.max(this.height - this.lines.length, 0);
|
|
6828
6815
|
let padTop;
|
|
6829
6816
|
switch (this.vAlign) {
|
|
@@ -6957,18 +6944,15 @@ var require_cell = __commonJS((exports, module) => {
|
|
|
6957
6944
|
}
|
|
6958
6945
|
|
|
6959
6946
|
class ColSpanCell {
|
|
6960
|
-
constructor() {
|
|
6961
|
-
}
|
|
6947
|
+
constructor() {}
|
|
6962
6948
|
draw(lineNum) {
|
|
6963
6949
|
if (typeof lineNum === "number") {
|
|
6964
6950
|
debug2(`${this.y}-${this.x}: 1x1 ColSpanCell`);
|
|
6965
6951
|
}
|
|
6966
6952
|
return "";
|
|
6967
6953
|
}
|
|
6968
|
-
init() {
|
|
6969
|
-
}
|
|
6970
|
-
mergeTableOptions() {
|
|
6971
|
-
}
|
|
6954
|
+
init() {}
|
|
6955
|
+
mergeTableOptions() {}
|
|
6972
6956
|
}
|
|
6973
6957
|
|
|
6974
6958
|
class RowSpanCell {
|
|
@@ -6991,8 +6975,7 @@ var require_cell = __commonJS((exports, module) => {
|
|
|
6991
6975
|
debug2(`${this.y}-${this.x}: 1x${this.colSpan} RowSpanCell for ${this.originalCell.content}`);
|
|
6992
6976
|
return this.originalCell.draw(this.offset + 1 + lineNum);
|
|
6993
6977
|
}
|
|
6994
|
-
mergeTableOptions() {
|
|
6995
|
-
}
|
|
6978
|
+
mergeTableOptions() {}
|
|
6996
6979
|
}
|
|
6997
6980
|
function firstDefined(...args) {
|
|
6998
6981
|
return args.filter((v) => v !== undefined && v !== null).shift();
|
|
@@ -10260,8 +10243,7 @@ var objectToString;
|
|
|
10260
10243
|
var init_util = __esm({
|
|
10261
10244
|
"src/lib/utils/util.ts"() {
|
|
10262
10245
|
NULL = "\x00";
|
|
10263
|
-
NOOP = () => {
|
|
10264
|
-
};
|
|
10246
|
+
NOOP = () => {};
|
|
10265
10247
|
objectToString = Object.prototype.toString.call.bind(Object.prototype.toString);
|
|
10266
10248
|
}
|
|
10267
10249
|
});
|
|
@@ -14458,8 +14440,7 @@ for (const model of usedModels) {
|
|
|
14458
14440
|
}
|
|
14459
14441
|
};
|
|
14460
14442
|
}
|
|
14461
|
-
var proto = Object.defineProperties(() => {
|
|
14462
|
-
}, {
|
|
14443
|
+
var proto = Object.defineProperties(() => {}, {
|
|
14463
14444
|
...styles2,
|
|
14464
14445
|
level: {
|
|
14465
14446
|
enumerable: true,
|
|
@@ -14547,6 +14528,7 @@ var log = {
|
|
|
14547
14528
|
success: (message) => console.log(source_default.green(`✓ ${message}`)),
|
|
14548
14529
|
error: (message) => console.error(source_default.red(`✗ ${message}`)),
|
|
14549
14530
|
info: (message) => console.log(source_default.bold(`ℹ ${message}`)),
|
|
14531
|
+
warn: (message) => console.warn(source_default.yellow(`⚠ ${message}`)),
|
|
14550
14532
|
header: (message) => console.log(source_default.bold.cyan(`
|
|
14551
14533
|
${message}`)),
|
|
14552
14534
|
file: (path) => console.log(`- ${source_default.dim(path)}`),
|
|
@@ -14706,9 +14688,22 @@ var pushBranch = async (branchName, {
|
|
|
14706
14688
|
};
|
|
14707
14689
|
|
|
14708
14690
|
// src/utils/codeowners.ts
|
|
14709
|
-
var codeowners
|
|
14691
|
+
var codeowners;
|
|
14692
|
+
var getCodeownersInstance = () => {
|
|
14693
|
+
if (!codeowners) {
|
|
14694
|
+
try {
|
|
14695
|
+
codeowners = new import_codeowners.default;
|
|
14696
|
+
} catch (error) {
|
|
14697
|
+
return {
|
|
14698
|
+
getOwner: () => []
|
|
14699
|
+
};
|
|
14700
|
+
}
|
|
14701
|
+
}
|
|
14702
|
+
return codeowners;
|
|
14703
|
+
};
|
|
14710
14704
|
var getOwner = (filePath) => {
|
|
14711
|
-
const
|
|
14705
|
+
const instance = getCodeownersInstance();
|
|
14706
|
+
const owner = instance.getOwner(filePath);
|
|
14712
14707
|
return owner;
|
|
14713
14708
|
};
|
|
14714
14709
|
var getOwnerFiles = async (owner) => {
|
|
@@ -14793,7 +14788,8 @@ var branch = async (options) => {
|
|
|
14793
14788
|
log.info(`Currently on branch: ${originalBranch}`);
|
|
14794
14789
|
filesToCommit = await getOwnerFiles(options.owner);
|
|
14795
14790
|
if (filesToCommit.length <= 0) {
|
|
14796
|
-
|
|
14791
|
+
log.warn(`No files found for ${options.owner}. Skipping branch creation.`);
|
|
14792
|
+
return;
|
|
14797
14793
|
}
|
|
14798
14794
|
log.file(`Files to be committed:
|
|
14799
14795
|
${filesToCommit.join(`
|
|
@@ -14858,11 +14854,15 @@ var branch = async (options) => {
|
|
|
14858
14854
|
};
|
|
14859
14855
|
|
|
14860
14856
|
// src/commands/multi-branch.ts
|
|
14857
|
+
var import_micromatch2 = __toESM(require_micromatch(), 1);
|
|
14861
14858
|
var multiBranch = async (options) => {
|
|
14862
14859
|
try {
|
|
14863
14860
|
if (!options.branch || !options.message) {
|
|
14864
14861
|
throw new Error("Missing required options for multi-branch creation");
|
|
14865
14862
|
}
|
|
14863
|
+
if (options.ignore && options.include) {
|
|
14864
|
+
throw new Error("Cannot use both --ignore and --include options at the same time");
|
|
14865
|
+
}
|
|
14866
14866
|
log.info("Starting multi-branch creation process...");
|
|
14867
14867
|
const changedFiles = await getChangedFiles();
|
|
14868
14868
|
if (changedFiles.length === 0) {
|
|
@@ -14875,11 +14875,36 @@ var multiBranch = async (options) => {
|
|
|
14875
14875
|
ownerSet.add(owner);
|
|
14876
14876
|
}
|
|
14877
14877
|
}
|
|
14878
|
-
|
|
14878
|
+
let codeowners2 = Array.from(ownerSet);
|
|
14879
14879
|
if (codeowners2.length === 0) {
|
|
14880
|
-
|
|
14880
|
+
log.warn("No codeowners found for the changed files");
|
|
14881
|
+
if (options.defaultOwner) {
|
|
14882
|
+
log.info(`Using default owner: ${options.defaultOwner}`);
|
|
14883
|
+
codeowners2.push(options.defaultOwner);
|
|
14884
|
+
} else {
|
|
14885
|
+
log.info("Continuing without creating any branches (use --default-owner to specify a fallback)");
|
|
14886
|
+
return;
|
|
14887
|
+
}
|
|
14888
|
+
} else {
|
|
14889
|
+
log.info(`Found ${codeowners2.length} codeowners: ${codeowners2.join(", ")}`);
|
|
14890
|
+
}
|
|
14891
|
+
if (options.ignore || options.include) {
|
|
14892
|
+
const originalCount = codeowners2.length;
|
|
14893
|
+
if (options.ignore) {
|
|
14894
|
+
const ignorePatterns = options.ignore.split(",").map((p) => p.trim());
|
|
14895
|
+
codeowners2 = codeowners2.filter((owner) => !import_micromatch2.default.isMatch(owner, ignorePatterns));
|
|
14896
|
+
log.info(`Filtered out ${originalCount - codeowners2.length} codeowners using ignore patterns: ${ignorePatterns.join(", ")}`);
|
|
14897
|
+
} else if (options.include) {
|
|
14898
|
+
const includePatterns = options.include.split(",").map((p) => p.trim());
|
|
14899
|
+
codeowners2 = codeowners2.filter((owner) => import_micromatch2.default.isMatch(owner, includePatterns));
|
|
14900
|
+
log.info(`Filtered to ${codeowners2.length} codeowners using include patterns: ${includePatterns.join(", ")}`);
|
|
14901
|
+
}
|
|
14902
|
+
if (codeowners2.length === 0) {
|
|
14903
|
+
log.warn("No codeowners left after filtering");
|
|
14904
|
+
return;
|
|
14905
|
+
}
|
|
14906
|
+
log.info(`Processing ${codeowners2.length} codeowners after filtering: ${codeowners2.join(", ")}`);
|
|
14881
14907
|
}
|
|
14882
|
-
log.info(`Found ${codeowners2.length} codeowners: ${codeowners2.join(", ")}`);
|
|
14883
14908
|
const results = {
|
|
14884
14909
|
success: [],
|
|
14885
14910
|
failure: []
|
|
@@ -14926,5 +14951,5 @@ var program2 = new Command;
|
|
|
14926
14951
|
program2.name("codeowners").description("CLI tool for grouping and managing staged files by CODEOWNERS");
|
|
14927
14952
|
program2.command("list").description("Lists all git changed files by CODEOWNER").option("-o, --owner <owner>", "Filter by specific code owner").option("-i, --include <patterns>", "Filter by owner patterns").action(listCodeowners);
|
|
14928
14953
|
program2.command("branch").description("Create new branch with codeowner changes").requiredOption("-o, --owner <owner>", "Code owner name").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").action(branch);
|
|
14929
|
-
program2.command("multi-branch").description("Create branches for all codeowners").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").action(multiBranch);
|
|
14954
|
+
program2.command("multi-branch").description("Create branches for all codeowners").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/*')").action(multiBranch);
|
|
14930
14955
|
program2.parse(process.argv);
|