Skip to content

Commit f3018c2

Browse files
committed
fix(functions/emulator): apply hidden-path watcher filter relative to functionsDir
chokidar's ignored matcher was evaluating the hidden-segment regex against the absolute file path. When the project was located under a dot-prefixed ancestor directory (e.g. `.worktrees/`, `.cache/`), every file change was silently filtered out and the emulator never reloaded triggers. Match against the path relative to `backend.functionsDir` instead so that the hidden-segment rule only hides dot-prefixed entries inside the watched directory. The other built-in ignore patterns and user-supplied `backend.ignore` globs are unchanged. Fixes #10187
1 parent e28281f commit f3018c2

4 files changed

Lines changed: 73 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Fixed Functions emulator file watcher silently ignoring changes when the project path contains a dot-prefixed ancestor directory (e.g. `.worktrees/`). (#10187)

src/emulator/functionsEmulator.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import {
3535
prepareEndpoints,
3636
BlockingTrigger,
3737
getTemporarySocketPath,
38+
shouldIgnoreWatchPath,
3839
} from "./functionsEmulatorShared";
3940
import { EmulatorRegistry } from "./registry";
4041
import { EmulatorLogger, Verbosity } from "./emulatorLogger";
@@ -519,7 +520,12 @@ export class FunctionsEmulator implements EmulatorInstance {
519520
} else {
520521
const watcher = chokidar.watch(backend.functionsDir, {
521522
ignored: [
522-
/(^|[\/\\])\../, // Ignore hidden files/dirs (covers .dart_tool, .git, etc.)
523+
// Ignore hidden files/dirs within the watched directory (covers
524+
// .dart_tool, .git, etc.). Match against the path relative to
525+
// functionsDir so a dot-prefixed ancestor directory (e.g.
526+
// `.worktrees/`) does not cause every file change to be ignored.
527+
// See https://github.com/firebase/firebase-tools/issues/10187.
528+
(filePath: string) => shouldIgnoreWatchPath(backend.functionsDir, filePath),
523529
/.+\.log/, // Ignore log files
524530
/.+?[\\\/]node_modules[\\\/].+?/, // Ignore node_modules
525531
/.+?[\\\/]venv[\\\/].+?/, // Ignore venv

src/emulator/functionsEmulatorShared.spec.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { expect } from "chai";
2+
import * as path from "path";
23
import { BackendInfo, EmulatableBackend } from "./functionsEmulator";
34
import * as functionsEmulatorShared from "./functionsEmulatorShared";
45
import {
@@ -295,4 +296,47 @@ describe("FunctionsEmulatorShared", () => {
295296
});
296297
}
297298
});
299+
300+
describe(`${functionsEmulatorShared.shouldIgnoreWatchPath.name}`, () => {
301+
const functionsDir = path.join("/", "home", "user", ".worktrees", "project", "functions");
302+
303+
it("ignores hidden files inside the functions directory", () => {
304+
const target = path.join(functionsDir, ".git", "HEAD");
305+
expect(functionsEmulatorShared.shouldIgnoreWatchPath(functionsDir, target)).to.be.true;
306+
});
307+
308+
it("ignores a hidden segment nested within the functions directory", () => {
309+
const target = path.join(functionsDir, "src", ".cache", "module.js");
310+
expect(functionsEmulatorShared.shouldIgnoreWatchPath(functionsDir, target)).to.be.true;
311+
});
312+
313+
it("does not ignore a regular source file even when the functions directory is nested under a dot-prefixed ancestor", () => {
314+
const target = path.join(functionsDir, "src", "index.ts");
315+
expect(functionsEmulatorShared.shouldIgnoreWatchPath(functionsDir, target)).to.be.false;
316+
});
317+
318+
it("does not ignore a nested source file without any hidden segment", () => {
319+
const target = path.join(functionsDir, "lib", "handlers", "index.js");
320+
expect(functionsEmulatorShared.shouldIgnoreWatchPath(functionsDir, target)).to.be.false;
321+
});
322+
323+
it("does not ignore the functions directory itself", () => {
324+
expect(functionsEmulatorShared.shouldIgnoreWatchPath(functionsDir, functionsDir)).to.be.false;
325+
});
326+
327+
describe("when the functions directory has no dot-prefixed ancestor", () => {
328+
const plainFunctionsDir = path.join("/", "home", "user", "project", "functions");
329+
330+
it("still ignores hidden files inside the functions directory", () => {
331+
const target = path.join(plainFunctionsDir, ".git", "HEAD");
332+
expect(functionsEmulatorShared.shouldIgnoreWatchPath(plainFunctionsDir, target)).to.be.true;
333+
});
334+
335+
it("does not ignore a regular source file", () => {
336+
const target = path.join(plainFunctionsDir, "src", "index.ts");
337+
expect(functionsEmulatorShared.shouldIgnoreWatchPath(plainFunctionsDir, target)).to.be
338+
.false;
339+
});
340+
});
341+
});
298342
});

src/emulator/functionsEmulatorShared.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,3 +545,24 @@ export function toBackendInfo(
545545
}),
546546
);
547547
}
548+
549+
// Matches paths whose last segment starts with a dot (e.g. ".git", ".cache").
550+
const HIDDEN_SEGMENT_REGEX = /(^|[\/\\])\../;
551+
552+
/**
553+
* Whether the functions emulator file watcher should ignore `filePath`.
554+
*
555+
* The hidden-segment check is applied against the path relative to
556+
* `functionsDir`. chokidar invokes the ignore matcher with the absolute path,
557+
* so matching the pattern against that path would also match dot-prefixed
558+
* ancestor directories (e.g. `.worktrees/`, `.cache/`) in the containing
559+
* project path and cause every file change to be ignored. See
560+
* https://github.com/firebase/firebase-tools/issues/10187.
561+
*/
562+
export function shouldIgnoreWatchPath(functionsDir: string, filePath: string): boolean {
563+
const rel = path.relative(functionsDir, filePath);
564+
if (!rel) {
565+
return false;
566+
}
567+
return HIDDEN_SEGMENT_REGEX.test(rel);
568+
}

0 commit comments

Comments
 (0)