Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/green-ants-cough.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"simple-git": patch
---

Add version parsing support for non-numeric patches (including "built from source" style `1.11.GIT`)
53 changes: 31 additions & 22 deletions simple-git/src/lib/tasks/version.ts
Original file line number Diff line number Diff line change
@@ -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;
}
Expand All @@ -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 {
Expand All @@ -30,7 +30,7 @@ function versionResponse(
'toString',
{
value() {
return `${major}.${minor}.${patch}`;
return `${this.major}.${this.minor}.${this.patch}`;
},
configurable: false,
enumerable: false,
Expand All @@ -48,24 +48,7 @@ export default function (): Pick<SimpleGit, 'version'> {
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));
Expand All @@ -77,3 +60,29 @@ export default function (): Pick<SimpleGit, 'version'> {
},
};
}

const parsers: LineParser<VersionResult>[] = [
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);
}
49 changes: 49 additions & 0 deletions simple-git/test/unit/version.spec.ts
Original file line number Diff line number Diff line change
@@ -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: '',
});
});
});