From 4f7d40190dd8dd07de90efc9fa18fdbf1392424c Mon Sep 17 00:00:00 2001 From: Steve King Date: Sat, 8 Apr 2023 08:31:11 +0100 Subject: [PATCH] Add example documentation for the output handler --- examples/git-output-handler.md | 49 +++++++++++++++++++ simple-git/readme.md | 4 +- .../test/integration/output-handler.spec.ts | 34 +++++++++++++ 3 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 examples/git-output-handler.md create mode 100644 simple-git/test/integration/output-handler.spec.ts diff --git a/examples/git-output-handler.md b/examples/git-output-handler.md new file mode 100644 index 00000000..4c862e17 --- /dev/null +++ b/examples/git-output-handler.md @@ -0,0 +1,49 @@ +## Output Handler + +As `simple-git` receives data on either `stdout` or `stderr` streams from the `git` +child processes it spawns, the data is buffered for parsing when the process has +completed. + +Add an `outputHandler` to the instance to pipe these streams to another target, for +example piping to the main process `stdout` / `stderr`: + +```typescript +import { InitResult, SimpleGit, simpleGit } from "simple-git"; + +const git: SimpleGit = simpleGit() + .outputHandler((_command, stdout, stderr) => { + stdout.pipe(process.stdout); + stderr.pipe(process.stderr); + }); + +const init: InitResult = await git.init(); +``` + +Note: there is a single `outputHandler` per `simple-git` instance, calling the method again +will overwrite the existing `outputHandler`. + +Other uses for the `outputHandler` can include tracking the processes for metrics purposes, +such as checking how many commands are currently being executed: + +```typescript +let processes = new Set(); +const currentlyRunning = () => processes.size; +const git = context.git.outputHandler((_command, stdout, stderr) => { + const start = new Date(); + const onClose = () => processes.delete(start); + + stdout.on('close', onClose); + stderr.on('close', onClose); + + processes.add(start); +}); + +expect(currentlyRunning()).toBe(0); +const queue = [git.init(), git.add('*.txt')]; + +await wait(0); +expect(currentlyRunning()).toBe(2); + +await Promise.all(queue); +expect(currentlyRunning()).toBe(0); +``` diff --git a/simple-git/readme.md b/simple-git/readme.md index a59e2806..66705f97 100644 --- a/simple-git/readme.md +++ b/simple-git/readme.md @@ -186,7 +186,7 @@ For type details of the response for each of the tasks, please see the [TypeScri # API | API | What it does | -| ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ---------------------------------------------------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `.add([fileA, ...], handlerFn)` | adds one or more files to be under source control | | `.addAnnotatedTag(tagName, tagMessage, handlerFn)` | adds an annotated tag to the head of the current branch | | `.addTag(name, handlerFn)` | adds a lightweight tag to the head of the current branch | @@ -201,7 +201,7 @@ For type details of the response for each of the tasks, please see the [TypeScri | `.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). | | `.fetch(remote, branch, handlerFn)` | update the local working copy database with changes from a remote repo | | `.fetch(handlerFn)` | update the local working copy database with changes from the default remote repo and branch | -| `.outputHandler(handlerFn)` | attaches a handler that will be called with the name of the command being run and the `stdout` and `stderr` [readable streams](https://nodejs.org/api/stream.html#stream_class_stream_readable) created by the [child process](https://nodejs.org/api/child_process.html#child_process_class_childprocess) running that command | +| `.outputHandler(handlerFn)` | attaches a handler that will be called with the name of the command being run and the `stdout` and `stderr` [readable streams](https://nodejs.org/api/stream.html#stream_class_stream_readable) created by the [child process](https://nodejs.org/api/child_process.html#child_process_class_childprocess) running that command, see [examples](https://github.com/steveukx/git-js/blob/main/examples/git-output-handler.md) | | `.raw(args, [handlerFn])` | Execute any arbitrary array of commands supported by the underlying git binary. When the git process returns a non-zero signal on exit and it printed something to `stderr`, the command will be treated as an error, otherwise treated as a success. | | `.rebase([options,] handlerFn)` | Rebases the repo, `options` should be supplied as an array of string parameters supported by the [git rebase](https://git-scm.com/docs/git-rebase) command, or an object of options (see details below for option formats). | | `.revert(commit , [options , [handlerFn]])` | reverts one or more commits in the working copy. The commit can be any regular commit-ish value (hash, name or offset such as `HEAD~2`) or a range of commits (eg: `master~5..master~2`). When supplied the [options](#how-to-specify-options) argument contain any options accepted by [git-revert](https://git-scm.com/docs/git-revert). | diff --git a/simple-git/test/integration/output-handler.spec.ts b/simple-git/test/integration/output-handler.spec.ts new file mode 100644 index 00000000..67b66a67 --- /dev/null +++ b/simple-git/test/integration/output-handler.spec.ts @@ -0,0 +1,34 @@ +import { createTestContext, setUpInit, SimpleGitTestContext, wait } from '@simple-git/test-utils'; + +describe('outputHandler', function () { + let context: SimpleGitTestContext; + + beforeEach(async () => (context = await createTestContext())); + beforeEach(async () => { + await setUpInit(context); + await context.files('aaa.txt', 'bbb.txt', 'ccc.other'); + }); + + it('using the outputHandler to count currently running processes', async () => { + let processes = new Set(); + const currentlyRunning = () => processes.size; + const git = context.git.outputHandler((_x, stdout, stderr) => { + const start = new Date(); + const onClose = () => processes.delete(start); + + stdout.on('close', onClose); + stderr.on('close', onClose); + + processes.add(start); + }); + + expect(currentlyRunning()).toBe(0); + const queue = [git.init(), git.add('*.txt')]; + + await wait(0); + expect(currentlyRunning()).toBe(2); + + await Promise.all(queue); + expect(currentlyRunning()).toBe(0); + }); +});