fix(desktop): bound review workspace scans
This commit is contained in:
parent
c5829fbb34
commit
5b73cfcc98
|
|
@ -6,7 +6,7 @@ import path from 'node:path'
|
|||
|
||||
import { afterEach, test } from 'vitest'
|
||||
|
||||
import { gitFor, repoStatus, resolveRenamePath } from './git-review-ops'
|
||||
import { gitFor, repoStatus, resolveRenamePath, REVIEW_FILE_CAP, reviewList } from './git-review-ops'
|
||||
|
||||
const tempDirs: string[] = []
|
||||
|
||||
|
|
@ -87,3 +87,33 @@ test('repoStatus reports an untracked directory without recursively listing its
|
|||
['generated/']
|
||||
)
|
||||
})
|
||||
|
||||
test('reviewList reports an untracked directory without recursively listing its contents', async () => {
|
||||
const dir = makeRepo()
|
||||
const nested = path.join(dir, 'browser-profile', 'Default', 'Cache')
|
||||
|
||||
fs.mkdirSync(nested, { recursive: true })
|
||||
|
||||
for (let i = 0; i < 20; i++) {
|
||||
fs.writeFileSync(path.join(nested, `cache-${i}.bin`), 'generated\n')
|
||||
}
|
||||
|
||||
const result = await reviewList(dir, 'uncommitted', null, 'git')
|
||||
|
||||
assert.deepEqual(
|
||||
result.files.map(file => file.path),
|
||||
['browser-profile/']
|
||||
)
|
||||
})
|
||||
|
||||
test('reviewList caps the file payload returned to the renderer', async () => {
|
||||
const dir = makeRepo()
|
||||
|
||||
for (let i = 0; i < REVIEW_FILE_CAP + 10; i++) {
|
||||
fs.writeFileSync(path.join(dir, `untracked-${String(i).padStart(4, '0')}.txt`), 'generated\n')
|
||||
}
|
||||
|
||||
const result = await reviewList(dir, 'uncommitted', null, 'git')
|
||||
|
||||
assert.equal(result.files.length, REVIEW_FILE_CAP)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import { resolveRequestedPathForIpc } from './hardening'
|
|||
|
||||
const COMMIT_CONTEXT_DIFF_MAX_CHARS = 120_000
|
||||
const COMMIT_CONTEXT_UNTRACKED_MAX = 80
|
||||
const REVIEW_FILE_CAP = 2_000
|
||||
const UNTRACKED_LINE_COUNT_CONCURRENCY = 16
|
||||
const UNTRACKED_LINE_COUNT_MAX_BYTES = 1024 * 1024
|
||||
|
||||
|
|
@ -253,7 +254,7 @@ async function reviewList(repoPath, scope, baseRef, gitBin) {
|
|||
const range = scope === 'branch' ? `${base}...HEAD` : base
|
||||
const summary = await git.diffSummary([range])
|
||||
|
||||
const files = summary.files.map(file => ({
|
||||
const files = summary.files.slice(0, REVIEW_FILE_CAP).map(file => ({
|
||||
path: resolveRenamePath(file.file),
|
||||
added: 'insertions' in file ? file.insertions : 0,
|
||||
removed: 'deletions' in file ? file.deletions : 0,
|
||||
|
|
@ -262,12 +263,22 @@ async function reviewList(repoPath, scope, baseRef, gitBin) {
|
|||
}))
|
||||
|
||||
// "Last turn" also surfaces files created since the baseline (untracked).
|
||||
if (scope === 'lastTurn') {
|
||||
const status = await git.status()
|
||||
if (scope === 'lastTurn' && files.length < REVIEW_FILE_CAP) {
|
||||
// Keep untracked directories compact. A recursive status can produce
|
||||
// hundreds of thousands of rows for browser profiles, generated
|
||||
// artifacts, or dependency trees before the response reaches the
|
||||
// renderer.
|
||||
const status = await git.status(['--untracked-files=normal'])
|
||||
const knownPaths = new Set(files.map(file => file.path))
|
||||
|
||||
for (const path of status.not_added) {
|
||||
if (!files.some(f => f.path === path)) {
|
||||
if (files.length >= REVIEW_FILE_CAP) {
|
||||
break
|
||||
}
|
||||
|
||||
if (!knownPaths.has(path)) {
|
||||
files.push({ path, added: 0, removed: 0, status: '?', staged: false })
|
||||
knownPaths.add(path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -280,7 +291,10 @@ async function reviewList(repoPath, scope, baseRef, gitBin) {
|
|||
|
||||
// Default: uncommitted (staged + unstaged + untracked), one row per path.
|
||||
const [status, staged, unstaged] = await Promise.all([
|
||||
git.status(),
|
||||
// `normal` reports an untracked directory as one row instead of walking
|
||||
// every descendant. The result is also capped before per-file stat/read
|
||||
// work and before crossing the Electron IPC boundary.
|
||||
git.status(['--untracked-files=normal']),
|
||||
git.diffSummary(['--cached']),
|
||||
git.diffSummary([])
|
||||
])
|
||||
|
|
@ -288,7 +302,7 @@ async function reviewList(repoPath, scope, baseRef, gitBin) {
|
|||
const stagedCounts = countsByPath(staged)
|
||||
const unstagedCounts = countsByPath(unstaged)
|
||||
|
||||
const files = status.files.map(file => {
|
||||
const files = status.files.slice(0, REVIEW_FILE_CAP).map(file => {
|
||||
const filePath = resolveRenamePath(file.path)
|
||||
const sc = stagedCounts.get(filePath) || { added: 0, removed: 0 }
|
||||
const uc = unstagedCounts.get(filePath) || { added: 0, removed: 0 }
|
||||
|
|
@ -696,6 +710,7 @@ export {
|
|||
gitFor,
|
||||
repoStatus,
|
||||
resolveRenamePath,
|
||||
REVIEW_FILE_CAP,
|
||||
reviewCommit,
|
||||
reviewCommitContext,
|
||||
reviewCreatePr,
|
||||
|
|
|
|||
Loading…
Reference in New Issue