/ src / lib / server / git-metadata.ts
git-metadata.ts
 1  import { execFileSync } from 'node:child_process'
 2  
 3  /**
 4   * Pure helpers for reading git metadata at runtime, with graceful degradation
 5   * when the working directory is not a git checkout (Docker production image,
 6   * npm tarball install, etc.).
 7   *
 8   * Always uses `execFileSync` with an arg array (no shell) so user input cannot
 9   * influence the command line.
10   */
11  export function safeGit(args: string[], cwd: string = process.cwd()): string | null {
12    try {
13      const out = execFileSync('git', args, {
14        cwd,
15        encoding: 'utf-8',
16        timeout: 15_000,
17        stdio: ['ignore', 'pipe', 'ignore'],
18      })
19      return typeof out === 'string' ? out.trim() : null
20    } catch {
21      return null
22    }
23  }
24  
25  let cachedAvailable: boolean | null = null
26  
27  /**
28   * Returns true when the current working directory looks like a git checkout
29   * (i.e. `git rev-parse --git-dir` succeeds). Cached for the lifetime of the
30   * process, since the answer does not change while a server is running.
31   *
32   * Exported `resetGitAvailableCache` is for unit tests only.
33   */
34  export function gitAvailable(): boolean {
35    if (cachedAvailable !== null) return cachedAvailable
36    cachedAvailable = safeGit(['rev-parse', '--git-dir']) !== null
37    return cachedAvailable
38  }
39  
40  export function resetGitAvailableCache(): void {
41    cachedAvailable = null
42  }