feat: change lettaignore logic (#1375)
Co-authored-by: Letta Code <noreply@letta.com>
This commit is contained in:
@@ -37,6 +37,15 @@ beforeEach(() => {
|
||||
writeFileSync(join(TEST_DIR, "src/components/Input.tsx"), "export Input");
|
||||
writeFileSync(join(TEST_DIR, "tests/app.test.ts"), "test()");
|
||||
|
||||
// Provide a .lettaignore so the file index respects exclusions.
|
||||
// .letta itself is listed so this directory doesn't affect entry counts.
|
||||
mkdirSync(join(TEST_DIR, ".letta"), { recursive: true });
|
||||
writeFileSync(
|
||||
join(TEST_DIR, ".letta", ".lettaignore"),
|
||||
"node_modules\n.git\nvenv\n.venv\n__pycache__\ndist\nbuild\n.letta\n",
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
process.chdir(TEST_DIR);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,16 +1,43 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
||||
import { mkdirSync, rmSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import {
|
||||
shouldExcludeEntry,
|
||||
shouldHardExcludeEntry,
|
||||
} from "../../cli/helpers/fileSearchConfig";
|
||||
|
||||
// These tests rely on there being NO .letta/.lettaignore in the working
|
||||
// directory — they verify that nothing is excluded unless the user explicitly
|
||||
// opts in via .letta/.lettaignore. Each test therefore runs from a fresh
|
||||
// temporary directory that contains no ignore file.
|
||||
|
||||
let testDir: string;
|
||||
let originalCwd: string;
|
||||
|
||||
beforeEach(() => {
|
||||
originalCwd = process.cwd();
|
||||
testDir = join(
|
||||
tmpdir(),
|
||||
`letta-fsc-test-${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
||||
);
|
||||
mkdirSync(testDir, { recursive: true });
|
||||
process.chdir(testDir);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
process.chdir(originalCwd);
|
||||
rmSync(testDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// shouldExcludeEntry — hardcoded defaults
|
||||
// shouldExcludeEntry — driven by .lettaignore only (no hardcoded defaults)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe("shouldExcludeEntry", () => {
|
||||
describe("hardcoded defaults", () => {
|
||||
const hardcoded = [
|
||||
describe("no hardcoded defaults", () => {
|
||||
// Without a .lettaignore, none of these entries are excluded.
|
||||
const formerlyHardcoded = [
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"dist",
|
||||
@@ -28,18 +55,11 @@ describe("shouldExcludeEntry", () => {
|
||||
".cache",
|
||||
];
|
||||
|
||||
for (const name of hardcoded) {
|
||||
test(`excludes "${name}"`, () => {
|
||||
expect(shouldExcludeEntry(name)).toBe(true);
|
||||
for (const name of formerlyHardcoded) {
|
||||
test(`does not exclude "${name}" without a .lettaignore entry`, () => {
|
||||
expect(shouldExcludeEntry(name)).toBe(false);
|
||||
});
|
||||
}
|
||||
|
||||
test("exclusion is case-insensitive", () => {
|
||||
expect(shouldExcludeEntry("Node_Modules")).toBe(true);
|
||||
expect(shouldExcludeEntry("DIST")).toBe(true);
|
||||
expect(shouldExcludeEntry("BUILD")).toBe(true);
|
||||
expect(shouldExcludeEntry(".GIT")).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("non-excluded entries", () => {
|
||||
@@ -59,19 +79,14 @@ describe("shouldExcludeEntry", () => {
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// shouldHardExcludeEntry — hardcoded only, no .lettaignore
|
||||
// shouldHardExcludeEntry — driven by .lettaignore name patterns only
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe("shouldHardExcludeEntry", () => {
|
||||
test("excludes hardcoded defaults", () => {
|
||||
expect(shouldHardExcludeEntry("node_modules")).toBe(true);
|
||||
expect(shouldHardExcludeEntry(".git")).toBe(true);
|
||||
expect(shouldHardExcludeEntry("dist")).toBe(true);
|
||||
});
|
||||
|
||||
test("exclusion is case-insensitive", () => {
|
||||
expect(shouldHardExcludeEntry("Node_Modules")).toBe(true);
|
||||
expect(shouldHardExcludeEntry("DIST")).toBe(true);
|
||||
test("does not exclude previously hardcoded entries without a .lettaignore entry", () => {
|
||||
expect(shouldHardExcludeEntry("node_modules")).toBe(false);
|
||||
expect(shouldHardExcludeEntry(".git")).toBe(false);
|
||||
expect(shouldHardExcludeEntry("dist")).toBe(false);
|
||||
});
|
||||
|
||||
test("does not exclude normal entries", () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { afterEach, describe, expect, test } from "bun:test";
|
||||
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
||||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import {
|
||||
ensureLettaIgnoreFile,
|
||||
@@ -16,22 +16,27 @@ describe("ensureLettaIgnoreFile", () => {
|
||||
|
||||
test("creates .lettaignore when missing", () => {
|
||||
testDir = new TestDirectory();
|
||||
const filePath = join(testDir.path, ".lettaignore");
|
||||
const filePath = join(testDir.path, ".letta", ".lettaignore");
|
||||
|
||||
expect(existsSync(filePath)).toBe(false);
|
||||
ensureLettaIgnoreFile(testDir.path);
|
||||
expect(existsSync(filePath)).toBe(true);
|
||||
|
||||
const content = readFileSync(filePath, "utf-8");
|
||||
expect(content).toContain("package-lock.json");
|
||||
expect(content).toContain("*.log");
|
||||
expect(content).toContain(".DS_Store");
|
||||
// Common patterns are active by default
|
||||
const activePatterns = readLettaIgnorePatterns(testDir.path);
|
||||
expect(activePatterns).toContain("node_modules");
|
||||
expect(activePatterns).toContain("dist");
|
||||
expect(activePatterns).toContain(".git");
|
||||
expect(activePatterns).toContain("*.log");
|
||||
expect(activePatterns).toContain("package-lock.json");
|
||||
});
|
||||
|
||||
test("does not overwrite existing .lettaignore", () => {
|
||||
testDir = new TestDirectory();
|
||||
const filePath = join(testDir.path, ".lettaignore");
|
||||
const lettaDir = join(testDir.path, ".letta");
|
||||
const filePath = join(lettaDir, ".lettaignore");
|
||||
|
||||
mkdirSync(lettaDir, { recursive: true });
|
||||
writeFileSync(filePath, "custom-pattern\n", "utf-8");
|
||||
ensureLettaIgnoreFile(testDir.path);
|
||||
|
||||
@@ -55,8 +60,10 @@ describe("readLettaIgnorePatterns", () => {
|
||||
|
||||
test("parses patterns from file", () => {
|
||||
testDir = new TestDirectory();
|
||||
const lettaDir = join(testDir.path, ".letta");
|
||||
mkdirSync(lettaDir, { recursive: true });
|
||||
writeFileSync(
|
||||
join(testDir.path, ".lettaignore"),
|
||||
join(lettaDir, ".lettaignore"),
|
||||
"*.log\nvendor\nsrc/generated/**\n",
|
||||
"utf-8",
|
||||
);
|
||||
@@ -67,8 +74,10 @@ describe("readLettaIgnorePatterns", () => {
|
||||
|
||||
test("skips comments and blank lines", () => {
|
||||
testDir = new TestDirectory();
|
||||
const lettaDir = join(testDir.path, ".letta");
|
||||
mkdirSync(lettaDir, { recursive: true });
|
||||
writeFileSync(
|
||||
join(testDir.path, ".lettaignore"),
|
||||
join(lettaDir, ".lettaignore"),
|
||||
"# This is a comment\n\n \npattern1\n# Another comment\npattern2\n",
|
||||
"utf-8",
|
||||
);
|
||||
@@ -79,8 +88,10 @@ describe("readLettaIgnorePatterns", () => {
|
||||
|
||||
test("skips negation patterns", () => {
|
||||
testDir = new TestDirectory();
|
||||
const lettaDir = join(testDir.path, ".letta");
|
||||
mkdirSync(lettaDir, { recursive: true });
|
||||
writeFileSync(
|
||||
join(testDir.path, ".lettaignore"),
|
||||
join(lettaDir, ".lettaignore"),
|
||||
"*.log\n!important.log\nvendor\n",
|
||||
"utf-8",
|
||||
);
|
||||
@@ -91,8 +102,10 @@ describe("readLettaIgnorePatterns", () => {
|
||||
|
||||
test("trims whitespace from patterns", () => {
|
||||
testDir = new TestDirectory();
|
||||
const lettaDir = join(testDir.path, ".letta");
|
||||
mkdirSync(lettaDir, { recursive: true });
|
||||
writeFileSync(
|
||||
join(testDir.path, ".lettaignore"),
|
||||
join(lettaDir, ".lettaignore"),
|
||||
" *.log \n vendor \n",
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
@@ -20,6 +20,14 @@ beforeEach(() => {
|
||||
writeFileSync(join(TEST_DIR, "src/App.tsx"), "export default App");
|
||||
writeFileSync(join(TEST_DIR, "src/components/Button.tsx"), "export Button");
|
||||
writeFileSync(join(TEST_DIR, "tests/app.test.ts"), "test()");
|
||||
|
||||
// Provide a .lettaignore so exclusions work when the cwd is changed to TEST_DIR.
|
||||
mkdirSync(join(TEST_DIR, ".letta"), { recursive: true });
|
||||
writeFileSync(
|
||||
join(TEST_DIR, ".letta", ".lettaignore"),
|
||||
"node_modules\nvenv\n.venv\n__pycache__\n.letta\n",
|
||||
"utf-8",
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
Reference in New Issue
Block a user