split-by-codeowners 1.0.0 → 1.0.3
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/action.yml +10 -0
- package/dist/index.js +133 -11
- package/dist/index.js.map +1 -1
- package/dist-cli/index.js +141 -11
- package/dist-cli/index.js.map +1 -1
- package/package.json +1 -1
package/action.yml
CHANGED
|
@@ -91,6 +91,16 @@ inputs:
|
|
|
91
91
|
required: false
|
|
92
92
|
default: "Automated changes bucketed by CODEOWNERS.\n\nOwners: {owners}\nBucket key: {bucket_key}\n\nFiles:\n{files}\n"
|
|
93
93
|
|
|
94
|
+
pr_body_mode:
|
|
95
|
+
description: "PR body mode for PR creation: custom | template | template_with_bucket | none"
|
|
96
|
+
required: false
|
|
97
|
+
default: "custom"
|
|
98
|
+
|
|
99
|
+
pr_template_path:
|
|
100
|
+
description: "Path to pull request template file (used when pr_body_mode=template*)."
|
|
101
|
+
required: false
|
|
102
|
+
default: ".github/pull_request_template.md"
|
|
103
|
+
|
|
94
104
|
draft:
|
|
95
105
|
description: "Create PRs as drafts."
|
|
96
106
|
required: false
|
package/dist/index.js
CHANGED
|
@@ -27470,6 +27470,7 @@ const codeowners_1 = __nccwpck_require__(3586);
|
|
|
27470
27470
|
const git_1 = __nccwpck_require__(1243);
|
|
27471
27471
|
const github_1 = __nccwpck_require__(9248);
|
|
27472
27472
|
const ghcli_1 = __nccwpck_require__(8064);
|
|
27473
|
+
const pr_template_1 = __nccwpck_require__(2456);
|
|
27473
27474
|
function formatTemplate(tpl, vars) {
|
|
27474
27475
|
let out = tpl;
|
|
27475
27476
|
for (const [k, v] of Object.entries(vars))
|
|
@@ -27589,8 +27590,22 @@ async function runSplit(config, logger) {
|
|
|
27589
27590
|
(0, git_1.pushBranch)(config.remoteName, branch, worktreeDir);
|
|
27590
27591
|
const ownersStr = b.owners.length ? b.owners.join(", ") : "(unowned)";
|
|
27591
27592
|
const filesStr = b.files.map(f => `- ${f.file}`).join("\n");
|
|
27593
|
+
const bucketInfo = formatTemplate("Automated changes bucketed by CODEOWNERS.\n\nOwners: {owners}\nBucket key: {bucket_key}\n\nFiles:\n{files}\n", { owners: ownersStr, bucket_key: b.key, files: filesStr });
|
|
27592
27594
|
const title = formatTemplate(config.prTitle, { owners: ownersStr, bucket_key: b.key });
|
|
27593
|
-
|
|
27595
|
+
let body;
|
|
27596
|
+
if (config.prBodyMode === "none") {
|
|
27597
|
+
body = undefined;
|
|
27598
|
+
}
|
|
27599
|
+
else if (config.prBodyMode === "custom") {
|
|
27600
|
+
body = formatTemplate(config.prBody, { owners: ownersStr, bucket_key: b.key, files: filesStr });
|
|
27601
|
+
}
|
|
27602
|
+
else {
|
|
27603
|
+
const template = (0, pr_template_1.readPrTemplate)(worktreeDir, config.prTemplatePath) ?? "";
|
|
27604
|
+
body =
|
|
27605
|
+
config.prBodyMode === "template_with_bucket"
|
|
27606
|
+
? (template ? template.trimEnd() + "\n\n---\n\n" + bucketInfo : bucketInfo)
|
|
27607
|
+
: (template || bucketInfo);
|
|
27608
|
+
}
|
|
27594
27609
|
const pr = useGhCli
|
|
27595
27610
|
? (() => {
|
|
27596
27611
|
return (0, ghcli_1.upsertPullRequestViaGh)({
|
|
@@ -27598,7 +27613,7 @@ async function runSplit(config, logger) {
|
|
|
27598
27613
|
base: baseBranch,
|
|
27599
27614
|
head: branch,
|
|
27600
27615
|
title,
|
|
27601
|
-
body,
|
|
27616
|
+
body: body ?? "",
|
|
27602
27617
|
draft: config.draft,
|
|
27603
27618
|
bucketKey: b.key
|
|
27604
27619
|
});
|
|
@@ -27609,7 +27624,7 @@ async function runSplit(config, logger) {
|
|
|
27609
27624
|
base: baseBranch,
|
|
27610
27625
|
head: branch,
|
|
27611
27626
|
title,
|
|
27612
|
-
body,
|
|
27627
|
+
body: body ?? "",
|
|
27613
27628
|
draft: config.draft,
|
|
27614
27629
|
bucketKey: b.key
|
|
27615
27630
|
});
|
|
@@ -27714,6 +27729,35 @@ exports.parseCodeowners = parseCodeowners;
|
|
|
27714
27729
|
exports.ownersForFile = ownersForFile;
|
|
27715
27730
|
const node_fs_1 = __importDefault(__nccwpck_require__(3024));
|
|
27716
27731
|
const minimatch_1 = __nccwpck_require__(6507);
|
|
27732
|
+
function splitPatternOwners(line) {
|
|
27733
|
+
// CODEOWNERS lines are: <pattern><whitespace><owner>...
|
|
27734
|
+
// Patterns may contain spaces if escaped as `\ `.
|
|
27735
|
+
// We parse by finding the first whitespace not escaped by a backslash.
|
|
27736
|
+
let i = 0;
|
|
27737
|
+
let escaped = false;
|
|
27738
|
+
for (; i < line.length; i++) {
|
|
27739
|
+
const ch = line[i];
|
|
27740
|
+
if (escaped) {
|
|
27741
|
+
escaped = false;
|
|
27742
|
+
continue;
|
|
27743
|
+
}
|
|
27744
|
+
if (ch === "\\") {
|
|
27745
|
+
escaped = true;
|
|
27746
|
+
continue;
|
|
27747
|
+
}
|
|
27748
|
+
if (/\s/.test(ch))
|
|
27749
|
+
break;
|
|
27750
|
+
}
|
|
27751
|
+
const rawPattern = line.slice(0, i).trim();
|
|
27752
|
+
const rest = line.slice(i).trim();
|
|
27753
|
+
if (!rawPattern || !rest)
|
|
27754
|
+
return null;
|
|
27755
|
+
const pattern = rawPattern.replaceAll("\\ ", " ");
|
|
27756
|
+
const owners = rest.split(/\s+/).filter(Boolean);
|
|
27757
|
+
if (!owners.length)
|
|
27758
|
+
return null;
|
|
27759
|
+
return { pattern, owners };
|
|
27760
|
+
}
|
|
27717
27761
|
function parseCodeowners(path) {
|
|
27718
27762
|
const text = node_fs_1.default.readFileSync(path, "utf8");
|
|
27719
27763
|
const rules = [];
|
|
@@ -27721,18 +27765,60 @@ function parseCodeowners(path) {
|
|
|
27721
27765
|
const line = raw.trim();
|
|
27722
27766
|
if (!line || line.startsWith("#"))
|
|
27723
27767
|
continue;
|
|
27724
|
-
const
|
|
27725
|
-
if (
|
|
27768
|
+
const parsed = splitPatternOwners(line);
|
|
27769
|
+
if (!parsed)
|
|
27726
27770
|
continue;
|
|
27727
|
-
rules.push({ pattern:
|
|
27771
|
+
rules.push({ pattern: parsed.pattern, owners: parsed.owners });
|
|
27728
27772
|
}
|
|
27729
27773
|
return rules;
|
|
27730
27774
|
}
|
|
27775
|
+
function hasGlobMagic(p) {
|
|
27776
|
+
// Good-enough heuristic for gitignore-style globs.
|
|
27777
|
+
return /[*?\[]/.test(p);
|
|
27778
|
+
}
|
|
27731
27779
|
function matches(file, pattern) {
|
|
27732
|
-
|
|
27733
|
-
//
|
|
27734
|
-
|
|
27735
|
-
|
|
27780
|
+
// GitHub CODEOWNERS patterns are gitignore-like:
|
|
27781
|
+
// - Leading `/` anchors to repo root
|
|
27782
|
+
// - Pattern without `/` matches a basename anywhere
|
|
27783
|
+
// - A directory pattern matches everything under it (e.g. `/frontend/admin` should match `/frontend/admin/**`)
|
|
27784
|
+
const f = file.replace(/\\/g, "/").replace(/^\.?\//, "");
|
|
27785
|
+
let pat = pattern.replace(/\\/g, "/").trim();
|
|
27786
|
+
if (!pat)
|
|
27787
|
+
return false;
|
|
27788
|
+
const anchored = pat.startsWith("/");
|
|
27789
|
+
if (anchored)
|
|
27790
|
+
pat = pat.slice(1);
|
|
27791
|
+
// Directory patterns: trailing `/` means directory; also treat non-glob literal paths as directory-or-file match.
|
|
27792
|
+
const trailingSlash = pat.endsWith("/");
|
|
27793
|
+
if (trailingSlash)
|
|
27794
|
+
pat = pat.slice(0, -1);
|
|
27795
|
+
const isLiteral = !hasGlobMagic(pat);
|
|
27796
|
+
const hasSlash = pat.includes("/");
|
|
27797
|
+
// Literal path: match exact file OR directory subtree.
|
|
27798
|
+
if (isLiteral && (anchored || hasSlash)) {
|
|
27799
|
+
return f === pat || f.startsWith(pat + "/");
|
|
27800
|
+
}
|
|
27801
|
+
// Literal basename: match basename OR directory subtree anywhere.
|
|
27802
|
+
if (isLiteral && !hasSlash) {
|
|
27803
|
+
const base = f.split("/").pop() ?? f;
|
|
27804
|
+
if (base === pat)
|
|
27805
|
+
return true;
|
|
27806
|
+
return f.includes("/" + pat + "/");
|
|
27807
|
+
}
|
|
27808
|
+
// Glob patterns: use minimatch.
|
|
27809
|
+
// - If anchored: match from repo root.
|
|
27810
|
+
// - If not anchored and no slash: match basename anywhere.
|
|
27811
|
+
// - If not anchored but includes a slash: match relative to repo root (like a root CODEOWNERS / .gitignore).
|
|
27812
|
+
const matchBase = !anchored && !hasSlash;
|
|
27813
|
+
const mm = (0, minimatch_1.minimatch)(f, pat, { dot: true, matchBase });
|
|
27814
|
+
if (mm)
|
|
27815
|
+
return true;
|
|
27816
|
+
// If the pattern explicitly denotes a directory (trailing slash), also match directory subtree.
|
|
27817
|
+
if (trailingSlash) {
|
|
27818
|
+
// Convert `dir/` to subtree match.
|
|
27819
|
+
return (0, minimatch_1.minimatch)(f, pat + "/**", { dot: true, matchBase: false });
|
|
27820
|
+
}
|
|
27821
|
+
return false;
|
|
27736
27822
|
}
|
|
27737
27823
|
function ownersForFile(file, rules) {
|
|
27738
27824
|
let hit;
|
|
@@ -28039,7 +28125,7 @@ async function upsertPullRequest(params) {
|
|
|
28039
28125
|
head,
|
|
28040
28126
|
base,
|
|
28041
28127
|
title,
|
|
28042
|
-
body,
|
|
28128
|
+
body: body || "",
|
|
28043
28129
|
draft
|
|
28044
28130
|
});
|
|
28045
28131
|
return { bucket_key: bucketKey, branch: head, number: created.data.number, url: created.data.html_url };
|
|
@@ -28111,6 +28197,8 @@ async function run() {
|
|
|
28111
28197
|
prTitle: core.getInput("pr_title") || "chore: automated changes ({owners})",
|
|
28112
28198
|
prBody: core.getInput("pr_body") ||
|
|
28113
28199
|
"Automated changes bucketed by CODEOWNERS.\n\nOwners: {owners}\nBucket key: {bucket_key}\n\nFiles:\n{files}\n",
|
|
28200
|
+
prBodyMode: (core.getInput("pr_body_mode") || "custom"),
|
|
28201
|
+
prTemplatePath: core.getInput("pr_template_path") || ".github/pull_request_template.md",
|
|
28114
28202
|
draft: (0, buckets_1.parseBool)(core.getInput("draft")),
|
|
28115
28203
|
remoteName: "origin",
|
|
28116
28204
|
};
|
|
@@ -28127,6 +28215,40 @@ async function run() {
|
|
|
28127
28215
|
run();
|
|
28128
28216
|
|
|
28129
28217
|
|
|
28218
|
+
/***/ }),
|
|
28219
|
+
|
|
28220
|
+
/***/ 2456:
|
|
28221
|
+
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
|
28222
|
+
|
|
28223
|
+
"use strict";
|
|
28224
|
+
|
|
28225
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
28226
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
28227
|
+
};
|
|
28228
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
28229
|
+
exports.readPrTemplate = readPrTemplate;
|
|
28230
|
+
const node_fs_1 = __importDefault(__nccwpck_require__(3024));
|
|
28231
|
+
const node_path_1 = __importDefault(__nccwpck_require__(6760));
|
|
28232
|
+
function readPrTemplate(cwd, templatePath) {
|
|
28233
|
+
const candidates = [];
|
|
28234
|
+
if (templatePath && templatePath.trim()) {
|
|
28235
|
+
candidates.push(templatePath.trim());
|
|
28236
|
+
}
|
|
28237
|
+
else {
|
|
28238
|
+
candidates.push(".github/pull_request_template.md");
|
|
28239
|
+
candidates.push(".github/PULL_REQUEST_TEMPLATE.md");
|
|
28240
|
+
candidates.push("pull_request_template.md");
|
|
28241
|
+
}
|
|
28242
|
+
for (const rel of candidates) {
|
|
28243
|
+
const abs = node_path_1.default.resolve(cwd, rel);
|
|
28244
|
+
if (node_fs_1.default.existsSync(abs) && node_fs_1.default.statSync(abs).isFile()) {
|
|
28245
|
+
return node_fs_1.default.readFileSync(abs, "utf8");
|
|
28246
|
+
}
|
|
28247
|
+
}
|
|
28248
|
+
return null;
|
|
28249
|
+
}
|
|
28250
|
+
|
|
28251
|
+
|
|
28130
28252
|
/***/ }),
|
|
28131
28253
|
|
|
28132
28254
|
/***/ 2613:
|