hillclimb 0.4.0 → 0.4.1
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/dist/cli.js +102 -31
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -13515,7 +13515,7 @@ var EXEC_OPTS = {
|
|
|
13515
13515
|
maxBuffer: 50 * 1024 * 1024
|
|
13516
13516
|
};
|
|
13517
13517
|
var MAX_ERROR_OUTPUT_CHARS = 2e3;
|
|
13518
|
-
var
|
|
13518
|
+
var MAX_SNAPSHOT_FILE_BYTES = 10 * 1024 * 1024;
|
|
13519
13519
|
var EMPTY_TREE_SHA = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
|
|
13520
13520
|
function quoteGitArg(arg) {
|
|
13521
13521
|
if (/^[A-Za-z0-9_./:=@%+,-]+$/.test(arg)) return arg;
|
|
@@ -13619,7 +13619,55 @@ function captureSnapshotSha(repoRoot) {
|
|
|
13619
13619
|
}
|
|
13620
13620
|
return git(repoRoot, ["rev-parse", "HEAD"]);
|
|
13621
13621
|
}
|
|
13622
|
-
function
|
|
13622
|
+
function recordOmittedSnapshotFile(omittedFiles, file) {
|
|
13623
|
+
omittedFiles?.push(file);
|
|
13624
|
+
const action = file.tracked ? "omitting tracked" : "skipping untracked";
|
|
13625
|
+
appendLog(
|
|
13626
|
+
"warn",
|
|
13627
|
+
`git-traces: ${action} ${file.path} (${file.sizeBytes} bytes > ${MAX_SNAPSHOT_FILE_BYTES} limit)`
|
|
13628
|
+
);
|
|
13629
|
+
}
|
|
13630
|
+
function parseLsTreeLongZ(output) {
|
|
13631
|
+
const entries = [];
|
|
13632
|
+
for (const record of output.toString("utf-8").split("\0")) {
|
|
13633
|
+
if (!record) continue;
|
|
13634
|
+
const tab = record.indexOf(" ");
|
|
13635
|
+
if (tab === -1) continue;
|
|
13636
|
+
const meta = record.slice(0, tab);
|
|
13637
|
+
const filePath = record.slice(tab + 1);
|
|
13638
|
+
const [mode, type, sha, sizeRaw] = meta.trim().split(/\s+/);
|
|
13639
|
+
if (type !== "blob" || !mode || !sha || !sizeRaw) continue;
|
|
13640
|
+
const sizeBytes = Number.parseInt(sizeRaw, 10);
|
|
13641
|
+
if (!Number.isFinite(sizeBytes)) continue;
|
|
13642
|
+
entries.push({ mode, sha, sizeBytes, path: filePath });
|
|
13643
|
+
}
|
|
13644
|
+
return entries;
|
|
13645
|
+
}
|
|
13646
|
+
function listOversizedTreeFiles(repoRoot, treeSha, omittedFiles) {
|
|
13647
|
+
const output = gitBuffer(repoRoot, ["ls-tree", "-r", "-l", "-z", treeSha]);
|
|
13648
|
+
const oversized = [];
|
|
13649
|
+
for (const entry of parseLsTreeLongZ(output)) {
|
|
13650
|
+
if (entry.sizeBytes <= MAX_SNAPSHOT_FILE_BYTES) continue;
|
|
13651
|
+
const file = {
|
|
13652
|
+
path: entry.path,
|
|
13653
|
+
sizeBytes: entry.sizeBytes,
|
|
13654
|
+
tracked: true,
|
|
13655
|
+
reason: "file-over-limit",
|
|
13656
|
+
gitObjectSha: entry.sha
|
|
13657
|
+
};
|
|
13658
|
+
oversized.push(file);
|
|
13659
|
+
recordOmittedSnapshotFile(omittedFiles, file);
|
|
13660
|
+
}
|
|
13661
|
+
return oversized;
|
|
13662
|
+
}
|
|
13663
|
+
function removePathsFromIndex(repoRoot, env, paths) {
|
|
13664
|
+
if (paths.length === 0) return;
|
|
13665
|
+
gitBuffer(repoRoot, ["update-index", "--force-remove", "-z", "--stdin"], {
|
|
13666
|
+
input: `${paths.join("\0")}\0`,
|
|
13667
|
+
env
|
|
13668
|
+
});
|
|
13669
|
+
}
|
|
13670
|
+
function buildUntrackedTree(repoRoot, omittedFiles) {
|
|
13623
13671
|
const list = git(repoRoot, [
|
|
13624
13672
|
"ls-files",
|
|
13625
13673
|
"--others",
|
|
@@ -13632,11 +13680,13 @@ function buildUntrackedTree(repoRoot) {
|
|
|
13632
13680
|
if (!relPath) continue;
|
|
13633
13681
|
try {
|
|
13634
13682
|
const stat = fs11.lstatSync(path14.join(repoRoot, relPath));
|
|
13635
|
-
if (stat.size >
|
|
13636
|
-
|
|
13637
|
-
|
|
13638
|
-
|
|
13639
|
-
|
|
13683
|
+
if (stat.size > MAX_SNAPSHOT_FILE_BYTES) {
|
|
13684
|
+
recordOmittedSnapshotFile(omittedFiles, {
|
|
13685
|
+
path: relPath,
|
|
13686
|
+
sizeBytes: stat.size,
|
|
13687
|
+
tracked: false,
|
|
13688
|
+
reason: "file-over-limit"
|
|
13689
|
+
});
|
|
13640
13690
|
continue;
|
|
13641
13691
|
}
|
|
13642
13692
|
kept.push(relPath);
|
|
@@ -13662,10 +13712,15 @@ function buildUntrackedTree(repoRoot) {
|
|
|
13662
13712
|
}
|
|
13663
13713
|
}
|
|
13664
13714
|
}
|
|
13665
|
-
function buildSnapshotTree(repoRoot, stashSha) {
|
|
13715
|
+
function buildSnapshotTree(repoRoot, stashSha, options = {}) {
|
|
13666
13716
|
const trackedTree = git(repoRoot, ["rev-parse", `${stashSha}^{tree}`]);
|
|
13667
|
-
const
|
|
13668
|
-
|
|
13717
|
+
const oversizedTracked = listOversizedTreeFiles(
|
|
13718
|
+
repoRoot,
|
|
13719
|
+
trackedTree,
|
|
13720
|
+
options.omittedFiles
|
|
13721
|
+
);
|
|
13722
|
+
const untrackedTree = buildUntrackedTree(repoRoot, options.omittedFiles);
|
|
13723
|
+
if (oversizedTracked.length === 0 && (!untrackedTree || untrackedTree === EMPTY_TREE_SHA)) {
|
|
13669
13724
|
return trackedTree;
|
|
13670
13725
|
}
|
|
13671
13726
|
const tmpIndex = path14.join(
|
|
@@ -13675,23 +13730,30 @@ function buildSnapshotTree(repoRoot, stashSha) {
|
|
|
13675
13730
|
const env = { ...process.env, GIT_INDEX_FILE: tmpIndex };
|
|
13676
13731
|
try {
|
|
13677
13732
|
gitWithEnv(repoRoot, ["read-tree", trackedTree], env);
|
|
13678
|
-
|
|
13733
|
+
removePathsFromIndex(
|
|
13679
13734
|
repoRoot,
|
|
13680
|
-
|
|
13681
|
-
|
|
13682
|
-
|
|
13735
|
+
env,
|
|
13736
|
+
oversizedTracked.map((file) => file.path)
|
|
13737
|
+
);
|
|
13738
|
+
if (untrackedTree && untrackedTree !== EMPTY_TREE_SHA) {
|
|
13739
|
+
const untrackedList = gitBuffer(
|
|
13740
|
+
repoRoot,
|
|
13741
|
+
["ls-tree", "-r", untrackedTree],
|
|
13742
|
+
{
|
|
13743
|
+
env
|
|
13744
|
+
}
|
|
13745
|
+
).toString("utf-8");
|
|
13746
|
+
const indexInfo = untrackedList.split("\n").filter(Boolean).map((line) => {
|
|
13747
|
+
const [meta, filePath] = line.split(" ");
|
|
13748
|
+
const [mode, , sha] = meta.split(/\s+/);
|
|
13749
|
+
return `${mode} ${sha} ${filePath}`;
|
|
13750
|
+
}).join("\n");
|
|
13751
|
+
if (indexInfo) {
|
|
13752
|
+
gitBuffer(repoRoot, ["update-index", "--index-info"], {
|
|
13753
|
+
input: indexInfo,
|
|
13754
|
+
env
|
|
13755
|
+
});
|
|
13683
13756
|
}
|
|
13684
|
-
).toString("utf-8");
|
|
13685
|
-
const indexInfo = untrackedList.split("\n").filter(Boolean).map((line) => {
|
|
13686
|
-
const [meta, filePath] = line.split(" ");
|
|
13687
|
-
const [mode, , sha] = meta.split(/\s+/);
|
|
13688
|
-
return `${mode} ${sha} ${filePath}`;
|
|
13689
|
-
}).join("\n");
|
|
13690
|
-
if (indexInfo) {
|
|
13691
|
-
gitBuffer(repoRoot, ["update-index", "--index-info"], {
|
|
13692
|
-
input: indexInfo,
|
|
13693
|
-
env
|
|
13694
|
-
});
|
|
13695
13757
|
}
|
|
13696
13758
|
return gitWithEnv(repoRoot, ["write-tree"], env);
|
|
13697
13759
|
} finally {
|
|
@@ -13778,7 +13840,7 @@ function parseDirtyFilesFromStatus(status) {
|
|
|
13778
13840
|
return pathPart;
|
|
13779
13841
|
}).filter(Boolean);
|
|
13780
13842
|
}
|
|
13781
|
-
function buildBaselineMetadata(repoRoot, sessionId, tool, baselineSha, cliVersion, epoch, prevHeadSha, transitionKind, startedAt) {
|
|
13843
|
+
function buildBaselineMetadata(repoRoot, sessionId, tool, baselineSha, cliVersion, epoch, prevHeadSha, transitionKind, startedAt, omittedFiles = []) {
|
|
13782
13844
|
const headSha = safeGit(repoRoot, ["rev-parse", "HEAD"]) ?? "unknown";
|
|
13783
13845
|
const branch = safeGit(repoRoot, ["rev-parse", "--abbrev-ref", "HEAD"]) ?? null;
|
|
13784
13846
|
const remoteUrl = safeGit(repoRoot, ["config", "--get", "remote.origin.url"]) ?? null;
|
|
@@ -13802,7 +13864,8 @@ function buildBaselineMetadata(repoRoot, sessionId, tool, baselineSha, cliVersio
|
|
|
13802
13864
|
branch,
|
|
13803
13865
|
remoteUrl,
|
|
13804
13866
|
isDirty: dirtyFiles.length > 0,
|
|
13805
|
-
dirtyFiles
|
|
13867
|
+
dirtyFiles,
|
|
13868
|
+
...omittedFiles.length > 0 ? { omittedFiles } : {}
|
|
13806
13869
|
},
|
|
13807
13870
|
author: { name: authorName, email: authorEmail },
|
|
13808
13871
|
hostname: os6.hostname(),
|
|
@@ -14246,6 +14309,10 @@ function freezeEpochBaseline(params) {
|
|
|
14246
14309
|
sessionId,
|
|
14247
14310
|
epoch
|
|
14248
14311
|
);
|
|
14312
|
+
const omittedFiles = [];
|
|
14313
|
+
const baselineTreeSha = buildSnapshotTree(repoRoot, baselineSha, {
|
|
14314
|
+
omittedFiles
|
|
14315
|
+
});
|
|
14249
14316
|
const baselineMetadata = buildBaselineMetadata(
|
|
14250
14317
|
repoRoot,
|
|
14251
14318
|
sessionId,
|
|
@@ -14255,9 +14322,9 @@ function freezeEpochBaseline(params) {
|
|
|
14255
14322
|
epoch,
|
|
14256
14323
|
prevHeadSha,
|
|
14257
14324
|
transitionKind,
|
|
14258
|
-
startedAt
|
|
14325
|
+
startedAt,
|
|
14326
|
+
omittedFiles
|
|
14259
14327
|
);
|
|
14260
|
-
const baselineTreeSha = buildSnapshotTree(repoRoot, baselineSha);
|
|
14261
14328
|
pinFrozenBaselineTree(repoRoot, sessionId, epoch, baselineTreeSha);
|
|
14262
14329
|
return { baselineSha, baselineTreeSha, baselineMetadata, headSha };
|
|
14263
14330
|
} catch (err) {
|
|
@@ -14303,6 +14370,10 @@ function buildEpochBaselineArtifacts(params) {
|
|
|
14303
14370
|
} = params;
|
|
14304
14371
|
const prefix = epochPrefix(epoch);
|
|
14305
14372
|
try {
|
|
14373
|
+
const omittedFiles = [];
|
|
14374
|
+
const baselineTreeSha = buildSnapshotTree(repoRoot, baselineSha, {
|
|
14375
|
+
omittedFiles
|
|
14376
|
+
});
|
|
14306
14377
|
const metadata = buildBaselineMetadata(
|
|
14307
14378
|
repoRoot,
|
|
14308
14379
|
sessionId,
|
|
@@ -14312,9 +14383,9 @@ function buildEpochBaselineArtifacts(params) {
|
|
|
14312
14383
|
epoch,
|
|
14313
14384
|
prevHeadSha,
|
|
14314
14385
|
transitionKind,
|
|
14315
|
-
startedAt
|
|
14386
|
+
startedAt,
|
|
14387
|
+
omittedFiles
|
|
14316
14388
|
);
|
|
14317
|
-
const baselineTreeSha = buildSnapshotTree(repoRoot, baselineSha);
|
|
14318
14389
|
return buildFrozenEpochBaselineArtifacts({
|
|
14319
14390
|
repoRoot,
|
|
14320
14391
|
sessionId,
|