@quikit/quikpilot-runner 9.0.0 → 9.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 +10 -0
- package/dist/index.js +368 -36
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -26,6 +26,16 @@ Releases follow [SemVer](https://semver.org/): a major version bump means the wo
|
|
|
26
26
|
shape changed (inputs, permissions) and requires a new pull request regardless of this package's
|
|
27
27
|
version; minor/patch releases are runner-logic fixes safe to pick up on the next re-bootstrap.
|
|
28
28
|
|
|
29
|
+
**9.1.0 — the code-writing step sees the files the changed file imports.** For every existing file a run changes (code or
|
|
30
|
+
test), the runner now reads that file's own imports (JavaScript and TypeScript, one hop, never what those files import)
|
|
31
|
+
and sends the repository files they point to as extra context. They come after the files targeting named and never in
|
|
32
|
+
place of them. Packages, path aliases (`@/…`), stylesheets and images are not followed; a denied path is never read; the
|
|
33
|
+
extra files share the existing size limits, and if the runtime still finds the context too large the call is retried
|
|
34
|
+
without them. The `codegen.context` log line now also carries `importedPaths`, what was skipped and why (`import: too
|
|
35
|
+
large`, `import: over budget`, `import: unreadable`, `import: denied`, `import: not in workspace`) and how many path
|
|
36
|
+
aliases were not followed. The workflow file is unchanged, so a repository on 9.0.0 picks this up with its next
|
|
37
|
+
"runner version" pull request.
|
|
38
|
+
|
|
29
39
|
**9.0.0 — a failed run keeps its files.** When a run fails after code generation, the runner writes the files it
|
|
30
40
|
generated, a copy of the last test report and a short `manifest.json` (run, targets, files, the reason it stopped;
|
|
31
41
|
no credentials) to `quikpilot-failure/`, and the workflow's new `Keep the files of a failed run` step uploads that folder
|
package/dist/index.js
CHANGED
|
@@ -230,7 +230,7 @@ function commitAndPush(branch, runId, installationToken, targeted, issueKey, iss
|
|
|
230
230
|
|
|
231
231
|
// src/codegen.ts
|
|
232
232
|
var import_node_fs = require("node:fs");
|
|
233
|
-
var
|
|
233
|
+
var import_node_path2 = require("node:path");
|
|
234
234
|
|
|
235
235
|
// src/deniedPaths.ts
|
|
236
236
|
function globToRegExp(pattern) {
|
|
@@ -382,6 +382,315 @@ function unwrapExecute(envelope, useCase) {
|
|
|
382
382
|
return envelope.structuredJson;
|
|
383
383
|
}
|
|
384
384
|
|
|
385
|
+
// src/importContext.ts
|
|
386
|
+
var import_node_path = require("node:path");
|
|
387
|
+
var REGEX_PRECEDING_KEYWORDS = /* @__PURE__ */ new Set([
|
|
388
|
+
"return",
|
|
389
|
+
"typeof",
|
|
390
|
+
"instanceof",
|
|
391
|
+
"in",
|
|
392
|
+
"of",
|
|
393
|
+
"new",
|
|
394
|
+
"delete",
|
|
395
|
+
"void",
|
|
396
|
+
"throw",
|
|
397
|
+
"case",
|
|
398
|
+
"do",
|
|
399
|
+
"else",
|
|
400
|
+
"yield",
|
|
401
|
+
"await"
|
|
402
|
+
]);
|
|
403
|
+
var SPACE_CODES = /* @__PURE__ */ new Set([32, 9, 10, 11, 12, 13, 160, 5760, 8232, 8233, 8239, 8287, 12288, 65279]);
|
|
404
|
+
var isSpace = (c) => {
|
|
405
|
+
const code = c.charCodeAt(0);
|
|
406
|
+
return SPACE_CODES.has(code) || code >= 8192 && code <= 8202;
|
|
407
|
+
};
|
|
408
|
+
var isIdStart = (c) => !isSpace(c) && (/[A-Za-z_$]/.test(c) || c.charCodeAt(0) > 127);
|
|
409
|
+
var isIdPart = (c) => !isSpace(c) && (/[A-Za-z0-9_$]/.test(c) || c.charCodeAt(0) > 127);
|
|
410
|
+
function tokenize(src) {
|
|
411
|
+
const out = [];
|
|
412
|
+
const n = src.length;
|
|
413
|
+
function regexAllowed() {
|
|
414
|
+
const prev = out[out.length - 1];
|
|
415
|
+
if (!prev) return true;
|
|
416
|
+
if (prev.k === "p") return prev.v !== ")" && prev.v !== "]" && prev.v !== "}";
|
|
417
|
+
if (prev.k === "id") return REGEX_PRECEDING_KEYWORDS.has(prev.v);
|
|
418
|
+
return false;
|
|
419
|
+
}
|
|
420
|
+
function scan(start, inSubstitution) {
|
|
421
|
+
let i = start;
|
|
422
|
+
let depth = 0;
|
|
423
|
+
while (i < n) {
|
|
424
|
+
const c = src[i];
|
|
425
|
+
if (isSpace(c)) {
|
|
426
|
+
i++;
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
if (c === "/" && src[i + 1] === "/") {
|
|
430
|
+
while (i < n && src[i] !== "\n") i++;
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
if (c === "/" && src[i + 1] === "*") {
|
|
434
|
+
const end = src.indexOf("*/", i + 2);
|
|
435
|
+
i = end === -1 ? n : end + 2;
|
|
436
|
+
continue;
|
|
437
|
+
}
|
|
438
|
+
if (c === "'" || c === '"') {
|
|
439
|
+
let j = i + 1;
|
|
440
|
+
let closed = false;
|
|
441
|
+
while (j < n) {
|
|
442
|
+
const d = src[j];
|
|
443
|
+
if (d === "\\") {
|
|
444
|
+
j += 2;
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
447
|
+
if (d === c) {
|
|
448
|
+
closed = true;
|
|
449
|
+
break;
|
|
450
|
+
}
|
|
451
|
+
if (d === "\n" || d === "\r") break;
|
|
452
|
+
j++;
|
|
453
|
+
}
|
|
454
|
+
if (closed) out.push({ k: "str", v: src.slice(i + 1, j) });
|
|
455
|
+
i = closed ? j + 1 : j;
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
if (c === "`") {
|
|
459
|
+
let j = i + 1;
|
|
460
|
+
let hasSubstitution = false;
|
|
461
|
+
let closed = false;
|
|
462
|
+
const textStart = j;
|
|
463
|
+
let textEnd = j;
|
|
464
|
+
while (j < n) {
|
|
465
|
+
const d = src[j];
|
|
466
|
+
if (d === "\\") {
|
|
467
|
+
j += 2;
|
|
468
|
+
continue;
|
|
469
|
+
}
|
|
470
|
+
if (d === "`") {
|
|
471
|
+
closed = true;
|
|
472
|
+
textEnd = hasSubstitution ? textEnd : j;
|
|
473
|
+
break;
|
|
474
|
+
}
|
|
475
|
+
if (d === "$" && src[j + 1] === "{") {
|
|
476
|
+
hasSubstitution = true;
|
|
477
|
+
j = scan(j + 2, true);
|
|
478
|
+
continue;
|
|
479
|
+
}
|
|
480
|
+
j++;
|
|
481
|
+
}
|
|
482
|
+
if (closed) out.push(hasSubstitution ? { k: "tpl", v: "" } : { k: "str", v: src.slice(textStart, textEnd) });
|
|
483
|
+
i = closed ? j + 1 : n;
|
|
484
|
+
continue;
|
|
485
|
+
}
|
|
486
|
+
if (c === "/" && regexAllowed()) {
|
|
487
|
+
let j = i + 1;
|
|
488
|
+
let inClass = false;
|
|
489
|
+
let closed = false;
|
|
490
|
+
while (j < n) {
|
|
491
|
+
const d = src[j];
|
|
492
|
+
if (d === "\\") {
|
|
493
|
+
j += 2;
|
|
494
|
+
continue;
|
|
495
|
+
}
|
|
496
|
+
if (d === "\n" || d === "\r") break;
|
|
497
|
+
if (d === "[") inClass = true;
|
|
498
|
+
else if (d === "]") inClass = false;
|
|
499
|
+
else if (d === "/" && !inClass) {
|
|
500
|
+
closed = true;
|
|
501
|
+
break;
|
|
502
|
+
}
|
|
503
|
+
j++;
|
|
504
|
+
}
|
|
505
|
+
if (closed) {
|
|
506
|
+
j++;
|
|
507
|
+
while (j < n && /[a-z]/i.test(src[j])) j++;
|
|
508
|
+
out.push({ k: "num", v: "/re/" });
|
|
509
|
+
i = j;
|
|
510
|
+
continue;
|
|
511
|
+
}
|
|
512
|
+
out.push({ k: "p", v: "/" });
|
|
513
|
+
i++;
|
|
514
|
+
continue;
|
|
515
|
+
}
|
|
516
|
+
if (/[0-9]/.test(c)) {
|
|
517
|
+
let j = i + 1;
|
|
518
|
+
while (j < n && /[0-9A-Za-z_.]/.test(src[j])) j++;
|
|
519
|
+
out.push({ k: "num", v: src.slice(i, j) });
|
|
520
|
+
i = j;
|
|
521
|
+
continue;
|
|
522
|
+
}
|
|
523
|
+
if (isIdStart(c)) {
|
|
524
|
+
let j = i + 1;
|
|
525
|
+
while (j < n && isIdPart(src[j])) j++;
|
|
526
|
+
out.push({ k: "id", v: src.slice(i, j) });
|
|
527
|
+
i = j;
|
|
528
|
+
continue;
|
|
529
|
+
}
|
|
530
|
+
if (inSubstitution) {
|
|
531
|
+
if (c === "{") depth++;
|
|
532
|
+
else if (c === "}") {
|
|
533
|
+
if (depth === 0) return i + 1;
|
|
534
|
+
depth--;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
out.push({ k: "p", v: c });
|
|
538
|
+
i++;
|
|
539
|
+
}
|
|
540
|
+
return n;
|
|
541
|
+
}
|
|
542
|
+
scan(0, false);
|
|
543
|
+
return out;
|
|
544
|
+
}
|
|
545
|
+
function extractImportSpecifiers(source) {
|
|
546
|
+
const t = tokenize(source);
|
|
547
|
+
const found = [];
|
|
548
|
+
const seen = /* @__PURE__ */ new Set();
|
|
549
|
+
const add = (s) => {
|
|
550
|
+
if (!seen.has(s)) {
|
|
551
|
+
seen.add(s);
|
|
552
|
+
found.push(s);
|
|
553
|
+
}
|
|
554
|
+
};
|
|
555
|
+
const isP = (tok, v) => tok?.k === "p" && tok.v === v;
|
|
556
|
+
for (let i = 0; i < t.length; i++) {
|
|
557
|
+
const tok = t[i];
|
|
558
|
+
if (tok.k !== "id") continue;
|
|
559
|
+
if (isP(t[i - 1], ".")) continue;
|
|
560
|
+
if (tok.v === "require") {
|
|
561
|
+
if (isP(t[i + 1], "(") && t[i + 2]?.k === "str" && isP(t[i + 3], ")")) add(t[i + 2].v);
|
|
562
|
+
continue;
|
|
563
|
+
}
|
|
564
|
+
if (tok.v !== "import" && tok.v !== "export") continue;
|
|
565
|
+
const next = t[i + 1];
|
|
566
|
+
if (tok.v === "import") {
|
|
567
|
+
if (next?.k === "str") {
|
|
568
|
+
add(next.v);
|
|
569
|
+
continue;
|
|
570
|
+
}
|
|
571
|
+
if (isP(next, "(")) {
|
|
572
|
+
if (t[i + 2]?.k === "str" && (isP(t[i + 3], ")") || isP(t[i + 3], ","))) add(t[i + 2].v);
|
|
573
|
+
continue;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
for (let j = i + 1; j < t.length; j++) {
|
|
577
|
+
const c = t[j];
|
|
578
|
+
if (c.k === "id") {
|
|
579
|
+
if (c.v === "import" || c.v === "export") break;
|
|
580
|
+
if (c.v === "from" && t[j + 1]?.k === "str") {
|
|
581
|
+
add(t[j + 1].v);
|
|
582
|
+
break;
|
|
583
|
+
}
|
|
584
|
+
continue;
|
|
585
|
+
}
|
|
586
|
+
if (c.k === "p" && (c.v === "{" || c.v === "}" || c.v === "," || c.v === "*")) continue;
|
|
587
|
+
break;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
return found;
|
|
591
|
+
}
|
|
592
|
+
function supportsImportScan(path) {
|
|
593
|
+
return /\.(?:[cm]?[jt]sx?)$/i.test(path);
|
|
594
|
+
}
|
|
595
|
+
var CODE_EXTS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts", ".json"];
|
|
596
|
+
var ASSET_EXTS = /* @__PURE__ */ new Set([
|
|
597
|
+
".css",
|
|
598
|
+
".scss",
|
|
599
|
+
".sass",
|
|
600
|
+
".less",
|
|
601
|
+
".svg",
|
|
602
|
+
".png",
|
|
603
|
+
".jpg",
|
|
604
|
+
".jpeg",
|
|
605
|
+
".gif",
|
|
606
|
+
".webp",
|
|
607
|
+
".avif",
|
|
608
|
+
".ico",
|
|
609
|
+
".bmp",
|
|
610
|
+
".woff",
|
|
611
|
+
".woff2",
|
|
612
|
+
".ttf",
|
|
613
|
+
".otf",
|
|
614
|
+
".eot",
|
|
615
|
+
".mp3",
|
|
616
|
+
".mp4",
|
|
617
|
+
".webm",
|
|
618
|
+
".wav",
|
|
619
|
+
".pdf",
|
|
620
|
+
".zip",
|
|
621
|
+
".wasm"
|
|
622
|
+
]);
|
|
623
|
+
var TS_SIBLINGS = { ".js": [".ts", ".tsx"], ".jsx": [".tsx"], ".mjs": [".mts"], ".cjs": [".cts"] };
|
|
624
|
+
function resolveImport(fromPath, specifier, listing) {
|
|
625
|
+
if (/^(?:@\/|~\/|#|\$|\/)/.test(specifier)) return { kind: "unresolved", reason: "alias" };
|
|
626
|
+
const clean = specifier.replace(/[?#].*$/, "");
|
|
627
|
+
const relative4 = clean === "." || clean === ".." || clean.startsWith("./") || clean.startsWith("../");
|
|
628
|
+
if (!relative4) return { kind: "external" };
|
|
629
|
+
const base = import_node_path.posix.normalize(import_node_path.posix.join(import_node_path.posix.dirname(fromPath), clean));
|
|
630
|
+
if (base === ".." || base.startsWith("../") || import_node_path.posix.isAbsolute(base)) return { kind: "unresolved", reason: "not found" };
|
|
631
|
+
const ext = import_node_path.posix.extname(base);
|
|
632
|
+
if (ASSET_EXTS.has(ext.toLowerCase())) return { kind: "unresolved", reason: "asset" };
|
|
633
|
+
const candidates = [];
|
|
634
|
+
if (CODE_EXTS.includes(ext)) {
|
|
635
|
+
candidates.push(base);
|
|
636
|
+
for (const sibling of TS_SIBLINGS[ext] ?? []) candidates.push(base.slice(0, -ext.length) + sibling);
|
|
637
|
+
}
|
|
638
|
+
for (const e of CODE_EXTS) candidates.push(base + e);
|
|
639
|
+
candidates.push(base + ".d.ts");
|
|
640
|
+
for (const e of CODE_EXTS) candidates.push(`${base}/index${e}`);
|
|
641
|
+
for (const candidate of candidates) {
|
|
642
|
+
if (listing.has(candidate)) return { kind: "repo", path: candidate };
|
|
643
|
+
}
|
|
644
|
+
return { kind: "unresolved", reason: "not found", attempted: base };
|
|
645
|
+
}
|
|
646
|
+
var ACTIONABLE_IMPORT_SKIPS = /* @__PURE__ */ new Set(["import: too large", "import: over budget", "import: unreadable"]);
|
|
647
|
+
function collectImportContext(p) {
|
|
648
|
+
const out = { entries: [], skipped: [], importedPaths: [], aliasImports: 0 };
|
|
649
|
+
if (!supportsImportScan(p.targetPath)) return out;
|
|
650
|
+
const seen = new Set(p.alreadyNamed);
|
|
651
|
+
seen.add(p.targetPath);
|
|
652
|
+
let total = p.spentChars;
|
|
653
|
+
for (const specifier of extractImportSpecifiers(p.source)) {
|
|
654
|
+
const resolved = resolveImport(p.targetPath, specifier, p.listing);
|
|
655
|
+
if (resolved.kind === "external") continue;
|
|
656
|
+
if (resolved.kind === "unresolved") {
|
|
657
|
+
if (resolved.reason === "alias") out.aliasImports++;
|
|
658
|
+
else if (resolved.reason === "not found") {
|
|
659
|
+
const path2 = resolved.attempted ?? specifier;
|
|
660
|
+
if (!seen.has(path2)) {
|
|
661
|
+
seen.add(path2);
|
|
662
|
+
out.skipped.push({ path: path2, reason: "import: not in workspace" });
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
continue;
|
|
666
|
+
}
|
|
667
|
+
const path = resolved.path;
|
|
668
|
+
if (seen.has(path)) continue;
|
|
669
|
+
seen.add(path);
|
|
670
|
+
if (matchesDeniedPath(path, p.deniedPaths)) {
|
|
671
|
+
out.skipped.push({ path, reason: "import: denied" });
|
|
672
|
+
continue;
|
|
673
|
+
}
|
|
674
|
+
let content;
|
|
675
|
+
try {
|
|
676
|
+
content = p.readFile(path);
|
|
677
|
+
} catch {
|
|
678
|
+
out.skipped.push({ path, reason: "import: unreadable" });
|
|
679
|
+
continue;
|
|
680
|
+
}
|
|
681
|
+
if (content.length > p.maxFileChars) {
|
|
682
|
+
out.skipped.push({ path, reason: "import: too large" });
|
|
683
|
+
} else if (total + content.length > p.maxTotalChars) {
|
|
684
|
+
out.skipped.push({ path, reason: "import: over budget" });
|
|
685
|
+
} else {
|
|
686
|
+
total += content.length;
|
|
687
|
+
out.entries.push({ path, content });
|
|
688
|
+
out.importedPaths.push(path);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
return out;
|
|
692
|
+
}
|
|
693
|
+
|
|
385
694
|
// src/retryFetch.ts
|
|
386
695
|
var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([502, 503, 504]);
|
|
387
696
|
var RETRYABLE_NETWORK_ERROR_CODES = /* @__PURE__ */ new Set(["ECONNRESET", "ETIMEDOUT"]);
|
|
@@ -604,16 +913,38 @@ async function runCodegen(gateway, targets, workspaceListing, requiredTests, den
|
|
|
604
913
|
}
|
|
605
914
|
}
|
|
606
915
|
const namedContents = contextPaths.map((path2) => ({ path: path2, content: (0, import_node_fs.readFileSync)(path2, "utf8") }));
|
|
607
|
-
const
|
|
608
|
-
const
|
|
609
|
-
for (const s of added.skipped) {
|
|
916
|
+
const runFiles = collectRunContext(target, targets, new Set(contextPaths), deniedPaths);
|
|
917
|
+
for (const s of runFiles.skipped) {
|
|
610
918
|
warnings.push(`not shown to the test for ${target.path}: ${s.path} (${s.reason})`);
|
|
611
919
|
}
|
|
920
|
+
const imports = isNewFile ? { entries: [], skipped: [], importedPaths: [], aliasImports: 0 } : collectImportContext({
|
|
921
|
+
targetPath: target.path,
|
|
922
|
+
source: currentContent,
|
|
923
|
+
alreadyNamed: /* @__PURE__ */ new Set([...contextPaths, ...runFiles.entries.map((e) => e.path)]),
|
|
924
|
+
deniedPaths,
|
|
925
|
+
listing,
|
|
926
|
+
readFile: (p) => (0, import_node_fs.readFileSync)(p, "utf8"),
|
|
927
|
+
maxFileChars: MAX_ADDED_FILE_CHARS,
|
|
928
|
+
maxTotalChars: MAX_ADDED_CONTEXT_CHARS,
|
|
929
|
+
spentChars: runFiles.entries.reduce((n, e) => n + e.content.length, 0)
|
|
930
|
+
});
|
|
931
|
+
for (const s of imports.skipped) {
|
|
932
|
+
if (ACTIONABLE_IMPORT_SKIPS.has(s.reason)) {
|
|
933
|
+
warnings.push(`not shown with ${target.path}: ${s.path} (imported by it; ${s.reason.replace(/^import: /, "")})`);
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
const added = {
|
|
937
|
+
entries: [...runFiles.entries, ...imports.entries],
|
|
938
|
+
skipped: [...runFiles.skipped, ...imports.skipped]
|
|
939
|
+
};
|
|
940
|
+
const contextContents = [...namedContents, ...added.entries];
|
|
612
941
|
const contextRecord = {
|
|
613
942
|
targetPath: target.path,
|
|
614
943
|
contextPaths,
|
|
615
944
|
addedPaths: added.entries.map((e) => e.path),
|
|
616
|
-
skipped: added.skipped
|
|
945
|
+
skipped: added.skipped,
|
|
946
|
+
...imports.importedPaths.length > 0 ? { importedPaths: imports.importedPaths } : {},
|
|
947
|
+
...imports.aliasImports > 0 ? { aliasImports: imports.aliasImports } : {}
|
|
617
948
|
};
|
|
618
949
|
console.log(JSON.stringify({ event: "codegen.context", ...contextRecord }));
|
|
619
950
|
contextLog?.push(contextRecord);
|
|
@@ -679,6 +1010,7 @@ async function runCodegen(gateway, targets, workspaceListing, requiredTests, den
|
|
|
679
1010
|
contextData.contextContents = namedContents;
|
|
680
1011
|
warnings.push(`context for ${target.path} was too large with the run's other files; retried without them`);
|
|
681
1012
|
contextRecord.addedPaths = [];
|
|
1013
|
+
delete contextRecord.importedPaths;
|
|
682
1014
|
contextRecord.retriedWithoutAdded = true;
|
|
683
1015
|
res = await callCodegen();
|
|
684
1016
|
if (!res.ok) {
|
|
@@ -794,14 +1126,14 @@ async function runCodegen(gateway, targets, workspaceListing, requiredTests, den
|
|
|
794
1126
|
}
|
|
795
1127
|
function flushCodegenResults(results) {
|
|
796
1128
|
for (const { targetPath, newContent } of results) {
|
|
797
|
-
(0, import_node_fs.mkdirSync)((0,
|
|
1129
|
+
(0, import_node_fs.mkdirSync)((0, import_node_path2.dirname)(targetPath), { recursive: true });
|
|
798
1130
|
(0, import_node_fs.writeFileSync)(targetPath, newContent);
|
|
799
1131
|
}
|
|
800
1132
|
}
|
|
801
1133
|
|
|
802
1134
|
// src/dependencyCheck.ts
|
|
803
1135
|
var import_node_fs2 = require("node:fs");
|
|
804
|
-
var
|
|
1136
|
+
var import_node_path3 = require("node:path");
|
|
805
1137
|
var SCANNABLE_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"];
|
|
806
1138
|
var IMPORT_RE = /(?:\bimport\b[^'"]*?\bfrom\s*|\bimport\s*\(\s*|\bexport\b[^'"]*?\bfrom\s*|\brequire\s*\(\s*|\bimport\s+)(['"])([^'"]+)\1/g;
|
|
807
1139
|
var NODE_BUILTINS = /* @__PURE__ */ new Set([
|
|
@@ -880,8 +1212,8 @@ function dependencyNames(pkg) {
|
|
|
880
1212
|
]);
|
|
881
1213
|
}
|
|
882
1214
|
function readDeclaredDependencies(results, workspaceRoot) {
|
|
883
|
-
const packageJsonPath = (0,
|
|
884
|
-
const generated = results.find((r) => (0,
|
|
1215
|
+
const packageJsonPath = (0, import_node_path3.join)((0, import_node_path3.resolve)(workspaceRoot ?? "."), "package.json");
|
|
1216
|
+
const generated = results.find((r) => (0, import_node_path3.resolve)(r.targetPath) === packageJsonPath);
|
|
885
1217
|
let raw;
|
|
886
1218
|
if (generated) {
|
|
887
1219
|
raw = generated.newContent;
|
|
@@ -951,10 +1283,10 @@ function stripJsonComments(text) {
|
|
|
951
1283
|
return out.replace(/,(\s*[}\]])/g, "$1");
|
|
952
1284
|
}
|
|
953
1285
|
function resolveAliasPrefixes(results, workspaceRoot) {
|
|
954
|
-
const root = (0,
|
|
1286
|
+
const root = (0, import_node_path3.resolve)(workspaceRoot ?? ".");
|
|
955
1287
|
for (const filename of ["tsconfig.json", "jsconfig.json"]) {
|
|
956
|
-
const configPath = (0,
|
|
957
|
-
const generated = results.find((r) => (0,
|
|
1288
|
+
const configPath = (0, import_node_path3.join)(root, filename);
|
|
1289
|
+
const generated = results.find((r) => (0, import_node_path3.resolve)(r.targetPath) === configPath);
|
|
958
1290
|
let raw;
|
|
959
1291
|
if (generated) {
|
|
960
1292
|
raw = generated.newContent;
|
|
@@ -1161,7 +1493,7 @@ function writePhase0Marker(runId) {
|
|
|
1161
1493
|
|
|
1162
1494
|
// src/quiktest.ts
|
|
1163
1495
|
var import_node_fs4 = require("node:fs");
|
|
1164
|
-
var
|
|
1496
|
+
var import_node_path4 = require("node:path");
|
|
1165
1497
|
var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git"]);
|
|
1166
1498
|
function walkForJUnitByName(dir) {
|
|
1167
1499
|
let entries;
|
|
@@ -1172,7 +1504,7 @@ function walkForJUnitByName(dir) {
|
|
|
1172
1504
|
}
|
|
1173
1505
|
for (const entry of entries) {
|
|
1174
1506
|
if (SKIP_DIRS.has(entry)) continue;
|
|
1175
|
-
const full = (0,
|
|
1507
|
+
const full = (0, import_node_path4.join)(dir, entry);
|
|
1176
1508
|
let stat;
|
|
1177
1509
|
try {
|
|
1178
1510
|
stat = (0, import_node_fs4.statSync)(full);
|
|
@@ -1196,7 +1528,7 @@ function firstXmlIn(dir, namePattern) {
|
|
|
1196
1528
|
return null;
|
|
1197
1529
|
}
|
|
1198
1530
|
const match = entries.find((e) => namePattern.test(e));
|
|
1199
|
-
return match ? (0,
|
|
1531
|
+
return match ? (0, import_node_path4.join)(dir, match) : null;
|
|
1200
1532
|
}
|
|
1201
1533
|
function readTestReportBytes(cwd = process.cwd()) {
|
|
1202
1534
|
try {
|
|
@@ -1207,7 +1539,7 @@ function readTestReportBytes(cwd = process.cwd()) {
|
|
|
1207
1539
|
}
|
|
1208
1540
|
}
|
|
1209
1541
|
function findJUnitReport(cwd = process.cwd()) {
|
|
1210
|
-
return walkForJUnitByName(cwd) ?? firstXmlIn((0,
|
|
1542
|
+
return walkForJUnitByName(cwd) ?? firstXmlIn((0, import_node_path4.join)(cwd, "test-results"), /\.xml$/) ?? firstXmlIn((0, import_node_path4.join)(cwd, "reports"), /^junit.*\.xml$/) ?? firstXmlIn((0, import_node_path4.join)(cwd, "target", "surefire-reports"), /\.xml$/);
|
|
1211
1543
|
}
|
|
1212
1544
|
function buildCiUrl(serverUrl, repository, githubRunId) {
|
|
1213
1545
|
return `${serverUrl}/${repository}/actions/runs/${githubRunId}`;
|
|
@@ -1262,7 +1594,7 @@ async function reportToQuikTest(params) {
|
|
|
1262
1594
|
// src/baselineCheck.ts
|
|
1263
1595
|
var import_node_child_process3 = require("node:child_process");
|
|
1264
1596
|
var import_node_fs6 = require("node:fs");
|
|
1265
|
-
var
|
|
1597
|
+
var import_node_path5 = require("node:path");
|
|
1266
1598
|
|
|
1267
1599
|
// src/regressionCheck.ts
|
|
1268
1600
|
var import_node_fs5 = require("node:fs");
|
|
@@ -1448,16 +1780,16 @@ function checkableIds(ids, types) {
|
|
|
1448
1780
|
});
|
|
1449
1781
|
}
|
|
1450
1782
|
function insideCheckout(cwd, path) {
|
|
1451
|
-
const abs = (0,
|
|
1452
|
-
const rel = (0,
|
|
1453
|
-
return rel === "" || rel.startsWith("..") || (0,
|
|
1783
|
+
const abs = (0, import_node_path5.resolve)(cwd, path);
|
|
1784
|
+
const rel = (0, import_node_path5.relative)(cwd, abs);
|
|
1785
|
+
return rel === "" || rel.startsWith("..") || (0, import_node_path5.isAbsolute)(rel) ? null : abs;
|
|
1454
1786
|
}
|
|
1455
1787
|
function writeForCheck(abs, content) {
|
|
1456
1788
|
const original = (0, import_node_fs6.existsSync)(abs) ? (0, import_node_fs6.readFileSync)(abs) : null;
|
|
1457
1789
|
const createdDirs = [];
|
|
1458
1790
|
if (original === null) {
|
|
1459
1791
|
const missing = [];
|
|
1460
|
-
for (let d = (0,
|
|
1792
|
+
for (let d = (0, import_node_path5.dirname)(abs); !(0, import_node_fs6.existsSync)(d); d = (0, import_node_path5.dirname)(d)) missing.push(d);
|
|
1461
1793
|
for (const d of missing.reverse()) {
|
|
1462
1794
|
(0, import_node_fs6.mkdirSync)(d);
|
|
1463
1795
|
createdDirs.push(d);
|
|
@@ -1609,7 +1941,7 @@ async function runBaselineCheck(params) {
|
|
|
1609
1941
|
|
|
1610
1942
|
// src/failureArtifact.ts
|
|
1611
1943
|
var import_node_fs7 = require("node:fs");
|
|
1612
|
-
var
|
|
1944
|
+
var import_node_path6 = require("node:path");
|
|
1613
1945
|
|
|
1614
1946
|
// src/failureReason.ts
|
|
1615
1947
|
var MAX_FAILURE_REASON = 1e3;
|
|
@@ -1650,18 +1982,18 @@ var FAILURE_ARTIFACT_DIR = "quikpilot-failure";
|
|
|
1650
1982
|
var REPORT_COPY = "final-test-report.xml";
|
|
1651
1983
|
var MAX_REPORT_BYTES = 5 * 1024 * 1024;
|
|
1652
1984
|
var MAX_FILES = 200;
|
|
1653
|
-
var RUNNER_VERSION = true ? "9.
|
|
1985
|
+
var RUNNER_VERSION = true ? "9.1.0" : "dev";
|
|
1654
1986
|
function safeDestination(base, repoPath) {
|
|
1655
|
-
if (!repoPath || (0,
|
|
1656
|
-
const destination = (0,
|
|
1657
|
-
const rel = (0,
|
|
1658
|
-
if (!rel || rel.startsWith("..") || (0,
|
|
1987
|
+
if (!repoPath || (0, import_node_path6.isAbsolute)(repoPath)) return null;
|
|
1988
|
+
const destination = (0, import_node_path6.resolve)(base, repoPath);
|
|
1989
|
+
const rel = (0, import_node_path6.relative)(base, destination);
|
|
1990
|
+
if (!rel || rel.startsWith("..") || (0, import_node_path6.isAbsolute)(rel)) return null;
|
|
1659
1991
|
return destination;
|
|
1660
1992
|
}
|
|
1661
1993
|
function writeFailureArtifact(input) {
|
|
1662
1994
|
if (input.results.length === 0) return { written: false };
|
|
1663
1995
|
try {
|
|
1664
|
-
const base = (0,
|
|
1996
|
+
const base = (0, import_node_path6.resolve)(input.cwd, FAILURE_ARTIFACT_DIR);
|
|
1665
1997
|
(0, import_node_fs7.rmSync)(base, { recursive: true, force: true });
|
|
1666
1998
|
(0, import_node_fs7.mkdirSync)(base, { recursive: true });
|
|
1667
1999
|
const files = [];
|
|
@@ -1672,7 +2004,7 @@ function writeFailureArtifact(input) {
|
|
|
1672
2004
|
skipped.push(result.targetPath);
|
|
1673
2005
|
continue;
|
|
1674
2006
|
}
|
|
1675
|
-
(0, import_node_fs7.mkdirSync)((0,
|
|
2007
|
+
(0, import_node_fs7.mkdirSync)((0, import_node_path6.dirname)(destination), { recursive: true });
|
|
1676
2008
|
(0, import_node_fs7.writeFileSync)(destination, result.newContent);
|
|
1677
2009
|
files.push({ path: result.targetPath, bytes: Buffer.byteLength(result.newContent) });
|
|
1678
2010
|
}
|
|
@@ -1681,7 +2013,7 @@ function writeFailureArtifact(input) {
|
|
|
1681
2013
|
if (input.testReport.byteLength > MAX_REPORT_BYTES) {
|
|
1682
2014
|
testReport = "too-large";
|
|
1683
2015
|
} else {
|
|
1684
|
-
(0, import_node_fs7.writeFileSync)((0,
|
|
2016
|
+
(0, import_node_fs7.writeFileSync)((0, import_node_path6.join)(base, REPORT_COPY), input.testReport);
|
|
1685
2017
|
testReport = "included";
|
|
1686
2018
|
}
|
|
1687
2019
|
}
|
|
@@ -1701,8 +2033,8 @@ function writeFailureArtifact(input) {
|
|
|
1701
2033
|
failureReasons: input.failureReasons
|
|
1702
2034
|
};
|
|
1703
2035
|
const text = JSON.stringify(manifest, (_key, value) => typeof value === "string" ? scrubSecrets(value, input.secrets) : value, 2);
|
|
1704
|
-
(0, import_node_fs7.writeFileSync)((0,
|
|
1705
|
-
return { written: (0, import_node_fs7.existsSync)((0,
|
|
2036
|
+
(0, import_node_fs7.writeFileSync)((0, import_node_path6.join)(base, "manifest.json"), text);
|
|
2037
|
+
return { written: (0, import_node_fs7.existsSync)((0, import_node_path6.join)(base, "manifest.json")) };
|
|
1706
2038
|
} catch (err) {
|
|
1707
2039
|
console.warn(`::warning::Could not keep the failed run's files: ${err instanceof Error ? err.message : String(err)}`);
|
|
1708
2040
|
return { written: false };
|
|
@@ -1786,7 +2118,7 @@ function describeScopeViolations(check) {
|
|
|
1786
2118
|
}
|
|
1787
2119
|
|
|
1788
2120
|
// src/targeting.ts
|
|
1789
|
-
var
|
|
2121
|
+
var import_node_path7 = require("node:path");
|
|
1790
2122
|
var CONTRACT_VERSION2 = "test-targets-1";
|
|
1791
2123
|
function listWorkspaceFiles(workspaceRoot) {
|
|
1792
2124
|
return listFiles(workspaceRoot ?? ".");
|
|
@@ -1815,9 +2147,9 @@ function validateTarget(target, workspaceRoot, workspaceListing, deniedPaths) {
|
|
|
1815
2147
|
}
|
|
1816
2148
|
return;
|
|
1817
2149
|
}
|
|
1818
|
-
const root = (0,
|
|
1819
|
-
const rel = (0,
|
|
1820
|
-
if (rel.startsWith("..") || (0,
|
|
2150
|
+
const root = (0, import_node_path7.resolve)(workspaceRoot ?? ".");
|
|
2151
|
+
const rel = (0, import_node_path7.relative)(root, (0, import_node_path7.resolve)(target.path));
|
|
2152
|
+
if (rel.startsWith("..") || (0, import_node_path7.isAbsolute)(rel)) {
|
|
1821
2153
|
throw new Error(
|
|
1822
2154
|
`pilot.targeting named a NEW_FILE path that escapes the workspace root: ${target.path}`
|
|
1823
2155
|
);
|