diff --git a/packages/cli-kit/src/public/node/context/local.test.ts b/packages/cli-kit/src/public/node/context/local.test.ts index abe71bb52b7..4893d031030 100644 --- a/packages/cli-kit/src/public/node/context/local.test.ts +++ b/packages/cli-kit/src/public/node/context/local.test.ts @@ -9,6 +9,7 @@ import { cloudEnvironment, macAddress, getThemeKitAccessDomain, + _resetHasGit, opentelemetryDomain, } from './local.js' import {fileExists} from '../fs.js' @@ -123,6 +124,10 @@ describe('isShopify', () => { }) describe('hasGit', () => { + afterEach(() => { + _resetHasGit() + }) + test('returns false if git --version errors', async () => { // Given vi.mocked(exec).mockRejectedValue(new Error('git not found')) @@ -132,6 +137,7 @@ describe('hasGit', () => { // Then expect(got).toBeFalsy() + expect(exec).toHaveBeenCalledWith('git', ['--version']) }) test('returns true if git --version succeeds', async () => { @@ -143,6 +149,19 @@ describe('hasGit', () => { // Then expect(got).toBeTruthy() + expect(exec).toHaveBeenCalledWith('git', ['--version']) + }) + + test('memoizes the result', async () => { + // Given + vi.mocked(exec).mockResolvedValue(undefined) + + // When + await hasGit() + await hasGit() + + // Then + expect(exec).toHaveBeenCalledTimes(1) }) }) diff --git a/packages/cli-kit/src/public/node/context/local.ts b/packages/cli-kit/src/public/node/context/local.ts index ad816399db9..a24bf0b6773 100644 --- a/packages/cli-kit/src/public/node/context/local.ts +++ b/packages/cli-kit/src/public/node/context/local.ts @@ -44,6 +44,11 @@ let memoizedIsVerbose: boolean | undefined */ let memoizedIsUnitTest: boolean | undefined +/** + * Memoized value for the hasGit check. + */ +let memoizedHasGit: Promise | undefined + /** * Returns true if the CLI is running in debug mode. * @@ -237,13 +242,23 @@ export function cloudEnvironment(env: NodeJS.ProcessEnv = process.env): { * @returns A promise that resolves with the value. */ export async function hasGit(): Promise { - try { - await lazyExec('git', ['--version']) - return true - // eslint-disable-next-line no-catch-all/no-catch-all - } catch { - return false - } + return (memoizedHasGit ??= (async () => { + try { + await lazyExec('git', ['--version']) + return true + // eslint-disable-next-line no-catch-all/no-catch-all + } catch { + return false + } + })()) +} + +/** + * Resets the memoized hasGit value. + * This is useful for testing. + */ +export function _resetHasGit(): void { + memoizedHasGit = undefined } /**