From c355317c07b217c73177dfada6fa0b77253f974d Mon Sep 17 00:00:00 2001 From: Steve King Date: Thu, 28 Mar 2024 18:54:40 +0000 Subject: [PATCH] Feature/array custom binary (#987) * Feature: enable the use of two commands for the `customBinary` Example: ```typescript simpleGit({ binary: 'git' }); // default simpleGit({ binary: ['./local/script/git'] }); // single item array simpleGit({ binary: ['wsl', 'git'] }); // string tuple ``` To avoid accidentally merging dangerous content into the binary - both commands are limited to alphanumeric with a restricted set of special characters `./\-_`. With `allowUnsafeCustomBinary` to ignore the validation of `binary` param inputs --- .changeset/forty-trains-float.md | 5 ++ docs/PLUGIN-CUSTOM-BINARY.md | 72 ++++++++++++++++ simple-git/readme.md | 5 +- simple-git/src/git.js | 7 +- simple-git/src/lib/git-factory.ts | 3 + .../src/lib/plugins/custom-binary.plugin.ts | 56 ++++++++++++ simple-git/src/lib/plugins/index.ts | 1 + simple-git/src/lib/plugins/plugin-store.ts | 27 +++++- .../src/lib/plugins/simple-git-plugin.ts | 4 + .../src/lib/runners/git-executor-chain.ts | 7 +- simple-git/src/lib/runners/git-executor.ts | 1 - simple-git/src/lib/types/index.ts | 20 +++-- .../unit/{ => plugins}/plugin.abort.spec.ts | 4 +- .../test/unit/plugins/plugin.binary.spec.ts | 85 +++++++++++++++++++ .../plugin.completion-detection.spec.ts | 4 +- .../unit/{ => plugins}/plugin.error.spec.ts | 4 +- .../{ => plugins}/plugin.pathspec.spec.ts | 6 +- .../unit/{ => plugins}/plugin.unsafe.spec.ts | 2 +- .../test/unit/{ => plugins}/plugins.spec.ts | 4 +- simple-git/typings/simple-git.d.ts | 2 +- 20 files changed, 288 insertions(+), 31 deletions(-) create mode 100644 .changeset/forty-trains-float.md create mode 100644 docs/PLUGIN-CUSTOM-BINARY.md create mode 100644 simple-git/src/lib/plugins/custom-binary.plugin.ts rename simple-git/test/unit/{ => plugins}/plugin.abort.spec.ts (96%) create mode 100644 simple-git/test/unit/plugins/plugin.binary.spec.ts rename simple-git/test/unit/{ => plugins}/plugin.completion-detection.spec.ts (89%) rename simple-git/test/unit/{ => plugins}/plugin.error.spec.ts (94%) rename simple-git/test/unit/{ => plugins}/plugin.pathspec.spec.ts (92%) rename simple-git/test/unit/{ => plugins}/plugin.unsafe.spec.ts (99%) rename simple-git/test/unit/{ => plugins}/plugins.spec.ts (98%) diff --git a/.changeset/forty-trains-float.md b/.changeset/forty-trains-float.md new file mode 100644 index 00000000..25ed0676 --- /dev/null +++ b/.changeset/forty-trains-float.md @@ -0,0 +1,5 @@ +--- +"simple-git": minor +--- + +Enable the use of a two part custom binary diff --git a/docs/PLUGIN-CUSTOM-BINARY.md b/docs/PLUGIN-CUSTOM-BINARY.md new file mode 100644 index 00000000..9285eaca --- /dev/null +++ b/docs/PLUGIN-CUSTOM-BINARY.md @@ -0,0 +1,72 @@ +## Custom Binary + +The `simple-git` library relies on `git` being available on the `$PATH` when spawning the child processes +to handle each `git` command. + +```typescript +simpleGit().init(); +``` + +Is equivalent to opening a terminal prompt and typing + +```shell +git init +``` + +### Configuring the binary for a new instance + +When `git` isn't available on the `$PATH`, which can often be the case if you're running in a custom +or virtualised container, the `git` binary can be replaced using the configuration object: + +```typescript +simpleGit({ binary: 'my-custom-git' }); +``` + +For environments where you need even further customisation of the path (for example flatpak or WSL), +the `binary` configuration property can be supplied as an array of up to two strings which will become +the command and first argument of the spawned child processes: + +```typescript +simpleGit({ binary: ['wsl', 'git'] }).init(); +``` + +Is equivalent to: + +```shell +wsl git init +``` + +### Changing the binary on an existing instance + +From v3.24.0 and above, the `simpleGit.customBinary` method supports the same parameter type and can be +used to change the `binary` configuration on an existing `simple-git` instance: + +```typescript +const git = await simpleGit().init(); +git.customBinary('./custom/git').raw('add', '.'); +``` + +Is equivalent to: + +```shell +git init +./custom/git add . +``` + +### Caveats / Security + +To prevent accidentally merging arbitrary code into the spawned child processes, the strings supplied +in the `binary` config are limited to alphanumeric, slashes, dot, hyphen and underscore. Colon is also +permitted when part of a valid windows path (ie: after one letter at the start of the string). + +This protection can be overridden by passing an additional unsafe configuration setting: + +```typescript +// this would normally throw because of the invalid value for `binary` +simpleGit({ + unsafe: { + allowUnsafeCustomBinary: true + }, + binary: '!' +}); +``` diff --git a/simple-git/readme.md b/simple-git/readme.md index 8e971565..6f338a85 100644 --- a/simple-git/readme.md +++ b/simple-git/readme.md @@ -90,6 +90,9 @@ await git.pull(); - [AbortController](https://github.com/steveukx/git-js/blob/main/docs/PLUGIN-ABORT-CONTROLLER.md) Terminate pending and future tasks in a `simple-git` instance (requires node >= 16). +- [Custom Binary](https://github.com/steveukx/git-js/blob/main/docs/PLUGIN-CUSTOM-BINARY.md) + Customise the `git` binary `simple-git` uses when spawning `git` child processes. + - [Completion Detection](https://github.com/steveukx/git-js/blob/main/docs/PLUGIN-COMPLETION-DETECTION.md) Customise how `simple-git` detects the end of a `git` process. @@ -195,7 +198,7 @@ in v2 (deprecation notices were logged to `stdout` as `console.warn` in v2). | `.clearQueue()` | immediately clears the queue of pending tasks (note: any command currently in progress will still call its completion callback) | | `.commit(message, handlerFn)` | commits changes in the current working directory with the supplied message where the message can be either a single string or array of strings to be passed as separate arguments (the `git` command line interface converts these to be separated by double line breaks) | | `.commit(message, [fileA, ...], options, handlerFn)` | commits changes on the named files with the supplied message, when supplied, the optional options object can contain any other parameters to pass to the commit command, setting the value of the property to be a string will add `name=value` to the command string, setting any other type of value will result in just the key from the object being passed (ie: just `name`), an example of setting the author is below | -| `.customBinary(gitPath)` | sets the command to use to reference git, allows for using a git binary not available on the path environment variable | +| `.customBinary(gitPath)` | sets the command to use to reference git, allows for using a git binary not available on the path environment variable [docs](https://github.com/steveukx/git-js/blob/main/docs/PLUGIN-CUSTOM-BINARY.md) | | `.env(name, value)` | Set environment variables to be passed to the spawned child processes, [see usage in detail below](#environment-variables). | | `.exec(handlerFn)` | calls a simple function in the current step | | `.fetch([options, ] handlerFn)` | update the local working copy database with changes from the default remote repo and branch, when supplied the options argument can be a standard [options object](#how-to-specify-options) either an array of string commands as supported by the [git fetch](https://git-scm.com/docs/git-fetch). | diff --git a/simple-git/src/git.js b/simple-git/src/git.js index af60fc6b..615fc20c 100644 --- a/simple-git/src/git.js +++ b/simple-git/src/git.js @@ -49,8 +49,8 @@ const { addAnnotatedTagTask, addTagTask, tagListTask } = require('./lib/tasks/ta const { straightThroughBufferTask, straightThroughStringTask } = require('./lib/tasks/task'); function Git(options, plugins) { + this._plugins = plugins; this._executor = new GitExecutor( - options.binary, options.baseDir, new Scheduler(options.maxConcurrentProcesses), plugins @@ -64,12 +64,9 @@ function Git(options, plugins) { /** * Sets the path to a custom git binary, should either be `git` when there is an installation of git available on * the system path, or a fully qualified path to the executable. - * - * @param {string} command - * @returns {Git} */ Git.prototype.customBinary = function (command) { - this._executor.binary = command; + this._plugins.reconfigure('binary', command); return this; }; diff --git a/simple-git/src/lib/git-factory.ts b/simple-git/src/lib/git-factory.ts index 8a780e82..684af558 100644 --- a/simple-git/src/lib/git-factory.ts +++ b/simple-git/src/lib/git-factory.ts @@ -6,6 +6,7 @@ import { blockUnsafeOperationsPlugin, commandConfigPrefixingPlugin, completionDetectionPlugin, + customBinaryPlugin, errorDetectionHandler, errorDetectionPlugin, PluginStore, @@ -68,5 +69,7 @@ export function gitInstanceFactory( plugins.add(errorDetectionPlugin(errorDetectionHandler(true))); config.errors && plugins.add(errorDetectionPlugin(config.errors)); + customBinaryPlugin(plugins, config.binary, config.unsafe?.allowUnsafeCustomBinary); + return new Git(config, plugins); } diff --git a/simple-git/src/lib/plugins/custom-binary.plugin.ts b/simple-git/src/lib/plugins/custom-binary.plugin.ts new file mode 100644 index 00000000..30574fef --- /dev/null +++ b/simple-git/src/lib/plugins/custom-binary.plugin.ts @@ -0,0 +1,56 @@ +import type { SimpleGitOptions } from '../types'; + +import { GitPluginError } from '../errors/git-plugin-error'; +import { asArray } from '../utils'; +import { PluginStore } from './plugin-store'; + +const WRONG_NUMBER_ERR = `Invalid value supplied for custom binary, requires a single string or an array containing either one or two strings`; +const WRONG_CHARS_ERR = `Invalid value supplied for custom binary, restricted characters must be removed or supply the unsafe.allowUnsafeCustomBinary option`; + +function isBadArgument(arg: string) { + return !arg || !/^([a-z]:)?([a-z0-9/.\\_-]+)$/i.test(arg); +} + +function toBinaryConfig( + input: string[], + allowUnsafe: boolean +): { binary: string; prefix?: string } { + if (input.length < 1 || input.length > 2) { + throw new GitPluginError(undefined, 'binary', WRONG_NUMBER_ERR); + } + + const isBad = input.some(isBadArgument); + if (isBad) { + if (allowUnsafe) { + console.warn(WRONG_CHARS_ERR); + } else { + throw new GitPluginError(undefined, 'binary', WRONG_CHARS_ERR); + } + } + + const [binary, prefix] = input; + return { + binary, + prefix, + }; +} + +export function customBinaryPlugin( + plugins: PluginStore, + input: SimpleGitOptions['binary'] = ['git'], + allowUnsafe = false +) { + let config = toBinaryConfig(asArray(input), allowUnsafe); + + plugins.on('binary', (input) => { + config = toBinaryConfig(asArray(input), allowUnsafe); + }); + + plugins.append('spawn.binary', () => { + return config.binary; + }); + + plugins.append('spawn.args', (data) => { + return config.prefix ? [config.prefix, ...data] : data; + }); +} diff --git a/simple-git/src/lib/plugins/index.ts b/simple-git/src/lib/plugins/index.ts index 8b0c1212..ac800733 100644 --- a/simple-git/src/lib/plugins/index.ts +++ b/simple-git/src/lib/plugins/index.ts @@ -2,6 +2,7 @@ export * from './abort-plugin'; export * from './block-unsafe-operations-plugin'; export * from './command-config-prefixing-plugin'; export * from './completion-detection.plugin'; +export * from './custom-binary.plugin'; export * from './error-detection.plugin'; export * from './plugin-store'; export * from './progress-monitor-plugin'; diff --git a/simple-git/src/lib/plugins/plugin-store.ts b/simple-git/src/lib/plugins/plugin-store.ts index 2b085879..2220e46b 100644 --- a/simple-git/src/lib/plugins/plugin-store.ts +++ b/simple-git/src/lib/plugins/plugin-store.ts @@ -1,8 +1,33 @@ -import { SimpleGitPlugin, SimpleGitPluginType, SimpleGitPluginTypes } from './simple-git-plugin'; +import { EventEmitter } from 'node:events'; + +import type { + SimpleGitPlugin, + SimpleGitPluginType, + SimpleGitPluginTypes, +} from './simple-git-plugin'; import { append, asArray } from '../utils'; +import type { SimpleGitPluginConfig } from '../types'; export class PluginStore { private plugins: Set> = new Set(); + private events = new EventEmitter(); + + on( + type: K, + listener: (data: SimpleGitPluginConfig[K]) => void + ) { + this.events.on(type, listener); + } + + reconfigure(type: K, data: SimpleGitPluginConfig[K]) { + this.events.emit(type, data); + } + + public append(type: T, action: SimpleGitPlugin['action']) { + const plugin = append(this.plugins, { type, action }); + + return () => this.plugins.delete(plugin); + } public add( plugin: void | SimpleGitPlugin | SimpleGitPlugin[] diff --git a/simple-git/src/lib/plugins/simple-git-plugin.ts b/simple-git/src/lib/plugins/simple-git-plugin.ts index d49f83e4..05733221 100644 --- a/simple-git/src/lib/plugins/simple-git-plugin.ts +++ b/simple-git/src/lib/plugins/simple-git-plugin.ts @@ -11,6 +11,10 @@ export interface SimpleGitPluginTypes { data: string[]; context: SimpleGitTaskPluginContext & {}; }; + 'spawn.binary': { + data: string; + context: SimpleGitTaskPluginContext & {}; + }; 'spawn.options': { data: Partial; context: SimpleGitTaskPluginContext & {}; diff --git a/simple-git/src/lib/runners/git-executor-chain.ts b/simple-git/src/lib/runners/git-executor-chain.ts index 73fb4434..2fceb2e8 100644 --- a/simple-git/src/lib/runners/git-executor-chain.ts +++ b/simple-git/src/lib/runners/git-executor-chain.ts @@ -20,10 +20,6 @@ export class GitExecutorChain implements SimpleGitExecutor { private _queue = new TasksPendingQueue(); private _cwd: string | undefined; - public get binary() { - return this._executor.binary; - } - public get cwd() { return this._cwd || this._executor.cwd; } @@ -84,6 +80,7 @@ export class GitExecutorChain implements SimpleGitExecutor { } private async attemptRemoteTask(task: RunnableTask, logger: OutputLogger) { + const binary = this._plugins.exec('spawn.binary', '', pluginContext(task, task.commands)); const args = this._plugins.exec( 'spawn.args', [...task.commands], @@ -92,7 +89,7 @@ export class GitExecutorChain implements SimpleGitExecutor { const raw = await this.gitResponse( task, - this.binary, + binary, args, this.outputHandler, logger.step('SPAWN') diff --git a/simple-git/src/lib/runners/git-executor.ts b/simple-git/src/lib/runners/git-executor.ts index 34e04301..02a3bdfe 100644 --- a/simple-git/src/lib/runners/git-executor.ts +++ b/simple-git/src/lib/runners/git-executor.ts @@ -11,7 +11,6 @@ export class GitExecutor implements SimpleGitExecutor { public outputHandler?: outputHandler; constructor( - public binary: string = 'git', public cwd: string, private _scheduler: Scheduler, private _plugins: PluginStore diff --git a/simple-git/src/lib/types/index.ts b/simple-git/src/lib/types/index.ts index fbe501db..bad8d645 100644 --- a/simple-git/src/lib/types/index.ts +++ b/simple-git/src/lib/types/index.ts @@ -45,7 +45,6 @@ export type GitExecutorEnv = NodeJS.ProcessEnv | undefined; export interface SimpleGitExecutor { env: GitExecutorEnv; outputHandler?: outputHandler; - binary: string; cwd: string; chain(): SimpleGitExecutor; @@ -66,6 +65,15 @@ export interface GitExecutorResult { export interface SimpleGitPluginConfig { abort: AbortSignal; + /** + * Name of the binary the child processes will spawn - defaults to `git`, + * supply as a tuple to enable the use of platforms that require `git` to be + * called through an alternative binary (eg: `wsl git ...`). + * Note: commands supplied in this way support a restricted set of characters + * and should not be used as a way to supply arbitrary config arguments etc. + */ + binary: string | [string] | [string, string]; + /** * Configures the events that should be used to determine when the unederlying child process has * been terminated. @@ -122,6 +130,12 @@ export interface SimpleGitPluginConfig { spawnOptions: Pick; unsafe: { + /** + * Allows potentially unsafe values to be supplied in the `binary` configuration option and + * `git.customBinary()` method call. + */ + allowUnsafeCustomBinary?: boolean; + /** * By default `simple-git` prevents the use of inline configuration * options to override the protocols available for the `git` child @@ -154,10 +168,6 @@ export interface SimpleGitOptions extends Partial { * Base directory for all tasks run through this `simple-git` instance */ baseDir: string; - /** - * Name of the binary the child processes will spawn - defaults to `git` - */ - binary: string; /** * Limit for the number of child processes that will be spawned concurrently from a `simple-git` instance */ diff --git a/simple-git/test/unit/plugin.abort.spec.ts b/simple-git/test/unit/plugins/plugin.abort.spec.ts similarity index 96% rename from simple-git/test/unit/plugin.abort.spec.ts rename to simple-git/test/unit/plugins/plugin.abort.spec.ts index 08733b74..c7bceb56 100644 --- a/simple-git/test/unit/plugin.abort.spec.ts +++ b/simple-git/test/unit/plugins/plugin.abort.spec.ts @@ -5,8 +5,8 @@ import { createAbortController, newSimpleGit, wait, -} from './__fixtures__'; -import { GitPluginError } from '../..'; +} from '../__fixtures__'; +import { GitPluginError } from '../../..'; describe('plugin.abort', function () { it('aborts an active child process', async () => { diff --git a/simple-git/test/unit/plugins/plugin.binary.spec.ts b/simple-git/test/unit/plugins/plugin.binary.spec.ts new file mode 100644 index 00000000..4171b757 --- /dev/null +++ b/simple-git/test/unit/plugins/plugin.binary.spec.ts @@ -0,0 +1,85 @@ +import { promiseError } from '@kwsites/promise-result'; +import { assertGitError, closeWithSuccess, newSimpleGit } from '../__fixtures__'; +import { mockChildProcessModule } from '../__mocks__/mock-child-process'; + +describe('binaryPlugin', () => { + it.each<[string, undefined | string | [string] | [string, string], string[]]>([ + ['undefined', undefined, ['git']], + ['string', 'simple', ['simple']], + ['string array', ['array'], ['array']], + ['strings array', ['array', 'tuple'], ['array', 'tuple']], + ])('allows binary set to %s', async (_, binary, command) => { + newSimpleGit({ binary }).raw('hello'); + + expect(await expected()).toEqual([...command, 'hello']); + }); + + each( + 'valid', + './bin/git', + 'c:\\path\\to\\git.exe', + 'custom-git', + 'GIT' + )('allows valid syntax "%s"', async (binary) => { + newSimpleGit({ binary }).raw('hello'); + expect(await expected()).toEqual([binary, 'hello']); + }); + + each( + 'long:\\path\\git.exe', + 'space fail', + '"dquote fail"', + "'squote fail'", + '$', + '!' + )('rejects invalid syntax "%s"', async (binary) => { + assertGitError( + await promiseError((async () => newSimpleGit({ binary }).raw('hello'))()), + 'Invalid value supplied for custom binary' + ); + }); + + it('works with config plugin', async () => { + newSimpleGit({ binary: ['alpha', 'beta'], config: ['gamma'] }).raw('hello'); + expect(await expected()).toEqual(['alpha', 'beta', '-c', 'gamma', 'hello']); + }); + + it('allows reconfiguring binary', async () => { + const git = newSimpleGit().raw('a'); + expect(await expected()).toEqual(['git', 'a']); + + git.customBinary('next').raw('b'); + expect(await expected()).toEqual(['next', 'b']); + + git.customBinary(['abc', 'def']).raw('g'); + expect(await expected()).toEqual(['abc', 'def', 'g']); + }); + + it('rejects reconfiguring to an invalid binary', async () => { + const git = newSimpleGit().raw('a'); + expect(await expected()).toEqual(['git', 'a']); + + assertGitError( + await promiseError((async () => git.customBinary('not valid'))()), + 'Invalid value supplied for custom binary' + ); + }); + + it('allows configuring to bad values when overridden', async () => { + const git = newSimpleGit({ unsafe: { allowUnsafeCustomBinary: true }, binary: '$' }).raw('a'); + expect(await expected()).toEqual(['$', 'a']); + + git.customBinary('!').raw('b'); + expect(await expected()).toEqual(['!', 'b']); + }); +}); + +function each(...things: string[]) { + return it.each(things.map((thing) => [thing])); +} + +async function expected() { + await closeWithSuccess(); + const recent = mockChildProcessModule.$mostRecent(); + return [recent.$command, ...recent.$args]; +} diff --git a/simple-git/test/unit/plugin.completion-detection.spec.ts b/simple-git/test/unit/plugins/plugin.completion-detection.spec.ts similarity index 89% rename from simple-git/test/unit/plugin.completion-detection.spec.ts rename to simple-git/test/unit/plugins/plugin.completion-detection.spec.ts index a2abea2d..5c5e23d9 100644 --- a/simple-git/test/unit/plugin.completion-detection.spec.ts +++ b/simple-git/test/unit/plugins/plugin.completion-detection.spec.ts @@ -1,5 +1,5 @@ -import { newSimpleGit, theChildProcessMatching, wait } from './__fixtures__'; -import { MockChildProcess } from './__mocks__/mock-child-process'; +import { newSimpleGit, theChildProcessMatching, wait } from '../__fixtures__'; +import { MockChildProcess } from '../__mocks__/mock-child-process'; describe('completionDetectionPlugin', () => { function process(proc: MockChildProcess, data: string, close = false, exit = false) { diff --git a/simple-git/test/unit/plugin.error.spec.ts b/simple-git/test/unit/plugins/plugin.error.spec.ts similarity index 94% rename from simple-git/test/unit/plugin.error.spec.ts rename to simple-git/test/unit/plugins/plugin.error.spec.ts index 6df05765..dbbcc6b4 100644 --- a/simple-git/test/unit/plugin.error.spec.ts +++ b/simple-git/test/unit/plugins/plugin.error.spec.ts @@ -1,7 +1,7 @@ import { promiseError } from '@kwsites/promise-result'; -import { assertGitError, closeWithError, closeWithSuccess, newSimpleGit } from './__fixtures__'; +import { assertGitError, closeWithError, closeWithSuccess, newSimpleGit } from '../__fixtures__'; -import { GitError } from '../..'; +import { GitError } from '../../..'; describe('errorDetectionPlugin', () => { it('can throw with custom content', async () => { diff --git a/simple-git/test/unit/plugin.pathspec.spec.ts b/simple-git/test/unit/plugins/plugin.pathspec.spec.ts similarity index 92% rename from simple-git/test/unit/plugin.pathspec.spec.ts rename to simple-git/test/unit/plugins/plugin.pathspec.spec.ts index 6d8e3dd7..55105c1d 100644 --- a/simple-git/test/unit/plugin.pathspec.spec.ts +++ b/simple-git/test/unit/plugins/plugin.pathspec.spec.ts @@ -1,6 +1,6 @@ -import { SimpleGit } from '../../typings'; -import { assertExecutedCommands, closeWithSuccess, newSimpleGit } from './__fixtures__'; -import { pathspec } from '../../src/lib/args/pathspec'; +import { SimpleGit } from '../../../typings'; +import { assertExecutedCommands, closeWithSuccess, newSimpleGit } from '../__fixtures__'; +import { pathspec } from '../../../src/lib/args/pathspec'; describe('suffixPathsPlugin', function () { let git: SimpleGit; diff --git a/simple-git/test/unit/plugin.unsafe.spec.ts b/simple-git/test/unit/plugins/plugin.unsafe.spec.ts similarity index 99% rename from simple-git/test/unit/plugin.unsafe.spec.ts rename to simple-git/test/unit/plugins/plugin.unsafe.spec.ts index 18b265c1..c9c34bfb 100644 --- a/simple-git/test/unit/plugin.unsafe.spec.ts +++ b/simple-git/test/unit/plugins/plugin.unsafe.spec.ts @@ -4,7 +4,7 @@ import { assertGitError, closeWithSuccess, newSimpleGit, -} from './__fixtures__'; +} from '../__fixtures__'; describe('blockUnsafeOperationsPlugin', () => { it.each([ diff --git a/simple-git/test/unit/plugins.spec.ts b/simple-git/test/unit/plugins/plugins.spec.ts similarity index 98% rename from simple-git/test/unit/plugins.spec.ts rename to simple-git/test/unit/plugins/plugins.spec.ts index 2075d220..e9b05b69 100644 --- a/simple-git/test/unit/plugins.spec.ts +++ b/simple-git/test/unit/plugins/plugins.spec.ts @@ -1,4 +1,4 @@ -import { SimpleGit } from '../../typings'; +import { SimpleGit } from '../../../typings'; import { assertChildProcessSpawnOptions, assertExecutedCommands, @@ -8,7 +8,7 @@ import { theChildProcess, writeToStdErr, writeToStdOut, -} from './__fixtures__'; +} from '../__fixtures__'; describe('plugins', () => { let git: SimpleGit; diff --git a/simple-git/typings/simple-git.d.ts b/simple-git/typings/simple-git.d.ts index ab94e7e5..2eeae354 100644 --- a/simple-git/typings/simple-git.d.ts +++ b/simple-git/typings/simple-git.d.ts @@ -452,7 +452,7 @@ export interface SimpleGit extends SimpleGitBase { * Sets the path to a custom git binary, should either be `git` when there is an installation of git available on * the system path, or a fully qualified path to the executable. */ - customBinary(command: string): this; + customBinary(command: Exclude): this; /** * Delete one local branch. Supply the branchName as a string to return a