diff --git a/package-lock.json b/package-lock.json index a44505b4a..85c71d042 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1844,6 +1844,11 @@ "dev": true, "optional": true }, + "compare-versions": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.5.1.tgz", + "integrity": "sha512-9fGPIB7C6AyM18CJJBHt5EnCZDG3oiTJYy0NjfIAGjKpzv0tkxWko7TNQHF5ymqm7IH03tqmeuBxtvD+Izh6mg==" + }, "component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", @@ -2930,6 +2935,14 @@ "locate-path": "^2.0.0" } }, + "find-versions": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz", + "integrity": "sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww==", + "requires": { + "semver-regex": "^2.0.0" + } + }, "flat-cache": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", @@ -7242,6 +7255,11 @@ "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=" }, + "semver-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz", + "integrity": "sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==" + }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", diff --git a/package.json b/package.json index a513732d8..84917ad22 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,9 @@ "dependencies": { "chalk": "^3.0.0", "ci-info": "^2.0.0", + "compare-versions": "^3.5.1", "cosmiconfig": "^6.0.0", + "find-versions": "^3.2.0", "opencollective-postinstall": "^2.0.2", "pkg-dir": "^4.2.0", "please-upgrade-node": "^3.2.0", diff --git a/src/installer/__tests__/checkGitVersion.ts b/src/installer/__tests__/checkGitVersion.ts new file mode 100644 index 000000000..c66e36fc4 --- /dev/null +++ b/src/installer/__tests__/checkGitVersion.ts @@ -0,0 +1,26 @@ +jest.mock('child_process') + +import cp from 'child_process' +import { checkGitVersion } from '../checkGitVersion' + +describe('checkGitVersion', (): void => { + it('should throw an error if version <2.13.0', (): void => { + // eslint-disable-next-line + // @ts-ignore + cp.spawnSync.mockReturnValue({ + status: 0, + stdout: Buffer.from('git version 2.12.0') + }) + expect(() => checkGitVersion()).toThrowError() + }) + + it('should not throw an error if version >=2.13.0', (): void => { + // eslint-disable-next-line + // @ts-ignore + cp.spawnSync.mockReturnValue({ + status: 0, + stdout: Buffer.from('git version 2.14.0') + }) + expect(() => checkGitVersion()).not.toThrowError() + }) +}) diff --git a/src/installer/bin.ts b/src/installer/bin.ts index ce06c00c5..4b99c3e92 100644 --- a/src/installer/bin.ts +++ b/src/installer/bin.ts @@ -7,6 +7,7 @@ import { checkGitDirEnv } from '../checkGitDirEnv' import { debug } from '../debug' import { install, uninstall } from './' import { gitRevParse } from './gitRevParse' +import { checkGitVersion } from './checkGitVersion' // Skip install if HUSKY_SKIP_INSTALL is true function checkSkipInstallEnv(): void { @@ -78,7 +79,11 @@ function run(): void { debug(`Current working directory is ${process.cwd()}`) - if (action === 'install') checkSkipInstallEnv() + if (action === 'install') { + checkSkipInstallEnv() + checkGitVersion() + } + const INIT_CWD = getInitCwdEnv() const userPkgDir = getUserPkgDir(INIT_CWD) checkGitDirEnv() diff --git a/src/installer/checkGitVersion.ts b/src/installer/checkGitVersion.ts new file mode 100644 index 000000000..8a051c28a --- /dev/null +++ b/src/installer/checkGitVersion.ts @@ -0,0 +1,17 @@ +import cp = require('child_process') +import findVersions from 'find-versions' +import compareVersions from 'compare-versions' + +export function checkGitVersion(): void { + const { status, stderr, stdout } = cp.spawnSync('git', ['--version']) + + if (status !== 0) { + throw new Error(stderr.toString()) + } + + const [version] = findVersions(stdout.toString()) + + if (compareVersions(version, '2.13.0') === -1) { + throw new Error(`Husky requires Git >=2.13.0. Got v${version}.`) + } +}