diff --git a/simple-git/src/lib/tasks/version.ts b/simple-git/src/lib/tasks/version.ts index 8143d9e9..0b9a87dc 100644 --- a/simple-git/src/lib/tasks/version.ts +++ b/simple-git/src/lib/tasks/version.ts @@ -1,11 +1,11 @@ import type { SimpleGitApi } from '../simple-git-api'; import type { SimpleGit } from '../../../typings'; -import { asNumber, ExitCodes } from '../utils'; +import { asNumber, ExitCodes, LineParser, parseStringResponse } from '../utils'; export interface VersionResult { major: number; minor: number; - patch: number; + patch: number | string; agent: string; installed: boolean; } @@ -15,7 +15,7 @@ const NOT_INSTALLED = 'installed=false'; function versionResponse( major = 0, minor = 0, - patch = 0, + patch: string | number = 0, agent = '', installed = true ): VersionResult { @@ -30,7 +30,7 @@ function versionResponse( 'toString', { value() { - return `${major}.${minor}.${patch}`; + return `${this.major}.${this.minor}.${this.patch}`; }, configurable: false, enumerable: false, @@ -48,24 +48,7 @@ export default function (): Pick { return this._runTask({ commands: ['--version'], format: 'utf-8', - parser(stdOut) { - if (stdOut === NOT_INSTALLED) { - return notInstalledResponse(); - } - - const version = /version (\d+)\.(\d+)\.(\d+)(?:\s*\((.+)\))?/.exec(stdOut); - - if (!version) { - return versionResponse(0, 0, 0, stdOut); - } - - return versionResponse( - asNumber(version[1]), - asNumber(version[2]), - asNumber(version[3]), - version[4] || '' - ); - }, + parser: versionParser, onError(result, error, done, fail) { if (result.exitCode === ExitCodes.NOT_FOUND) { return done(Buffer.from(NOT_INSTALLED)); @@ -77,3 +60,29 @@ export default function (): Pick { }, }; } + +const parsers: LineParser[] = [ + new LineParser( + /version (\d+)\.(\d+)\.(\d+)(?:\s*\((.+)\))?/, + (result, [major, minor, patch, agent = '']) => { + Object.assign( + result, + versionResponse(asNumber(major), asNumber(minor), asNumber(patch), agent) + ); + } + ), + new LineParser( + /version (\d+)\.(\d+)\.(\D+)(.+)?$/, + (result, [major, minor, patch, agent = '']) => { + Object.assign(result, versionResponse(asNumber(major), asNumber(minor), patch, agent)); + } + ), +]; + +function versionParser(stdOut: string) { + if (stdOut === NOT_INSTALLED) { + return notInstalledResponse(); + } + + return parseStringResponse(versionResponse(0, 0, 0, stdOut), parsers, stdOut); +} diff --git a/simple-git/test/unit/version.spec.ts b/simple-git/test/unit/version.spec.ts new file mode 100644 index 00000000..223a56c2 --- /dev/null +++ b/simple-git/test/unit/version.spec.ts @@ -0,0 +1,49 @@ +import { closeWithError, closeWithSuccess, newSimpleGit } from './__fixtures__'; + +describe('version', () => { + it('sringifies to version', async () => { + const version = newSimpleGit().version(); + await closeWithSuccess('git version 2.50.10 (Apple Git-133)'); + + expect(String(await version)).toBe('2.50.10'); + }); + + it('detects missing', async () => { + const version = newSimpleGit().version(); + await closeWithError('FAIL', -2); + + expect(await version).toEqual({ + installed: false, + major: 0, + minor: 0, + patch: 0, + agent: '', + }); + }); + + it('parses apple', async () => { + const version = newSimpleGit().version(); + await closeWithSuccess('git version 2.32.1 (Apple Git-133)'); + + expect(await version).toEqual({ + installed: true, + major: 2, + minor: 32, + patch: 1, + agent: 'Apple Git-133', + }); + }); + + it('parses git from source', async () => { + const version = newSimpleGit().version(); + await closeWithSuccess('git version 2.37.GIT'); + + expect(await version).toEqual({ + installed: true, + major: 2, + minor: 37, + patch: 'GIT', + agent: '', + }); + }); +});