From 98a9abb8531eb438a0f2d608b2fcb31674617087 Mon Sep 17 00:00:00 2001 From: Anton Medvedev Date: Wed, 16 Feb 2022 20:25:31 +0100 Subject: [PATCH] Add retry & echo --- README.md | 27 +++++++++++++++++++++++++++ experimental.d.ts | 26 ++++++++++++++++++++++++++ experimental.mjs | 44 ++++++++++++++++++++++++++++++++++++++++++++ package.json | 3 ++- test.mjs | 9 +++++++++ 5 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 experimental.d.ts create mode 100644 experimental.mjs diff --git a/README.md b/README.md index 12548c30b5..1392eae199 100644 --- a/README.md +++ b/README.md @@ -338,6 +338,33 @@ files (when using `zx` executable). let {version} = require('./package.json') ``` +### Experimental + +The zx also provides a few experimental functions. Please leave a feedback about +those features in [the discussion](https://github.com/google/zx/discussions/299). + +#### `retry()` + +Retries a command a few times. Will return after the first +successful attempt, or will throw after specifies attempts count. + +```js +import {retry} from 'zx/experimental' + +let {stdout} = await retry(5)`curl localhost` +``` + +#### ``echo`...` `` + +A `console.log()` alternative which can take [ProcessOutput](#processoutput). + +```js +import {echo} from 'zx/experimental' + +let branch = await $`git branch --show-current` +echo`Current branch is ${branch}.` +``` + ### FAQ #### Passing env variables diff --git a/experimental.d.ts b/experimental.d.ts new file mode 100644 index 0000000000..273bbf3192 --- /dev/null +++ b/experimental.d.ts @@ -0,0 +1,26 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import {ProcessOutput} from './index' + +interface Echo { + (pieces: TemplateStringsArray, ...args: any[]): Promise +} + +interface Retry { + (pieces: TemplateStringsArray, ...args: any[]): Promise +} + +export const echo: Echo +export const retry: (count: number) => Retry diff --git a/experimental.mjs b/experimental.mjs new file mode 100644 index 0000000000..c1fe615269 --- /dev/null +++ b/experimental.mjs @@ -0,0 +1,44 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import {ProcessOutput} from './index.mjs' + +// Retries a command a few times. Will return after the first +// successful attempt, or will throw after specifies attempts count. +export const retry = (count = 5) => async (cmd, ...args) => { + while (count --> 0) try { + return await $(cmd, ...args) + } catch (p) { + if (count === 0) throw p + } +} + +// A console.log() alternative which can take ProcessOutput. +export const echo = (pieces, ...args) => { + if (!Array.isArray(pieces) || pieces.length - 1 !== args.length) { + throw new Error('The echo is a template string. Use as echo`...`.') + } + let msg = pieces[0], i = 0 + while (i < args.length) { + msg += stringify(args[i]) + pieces[++i] + } + console.log(msg) +} + +function stringify(arg) { + if (arg instanceof ProcessOutput) { + return arg.toString().replace(/\n$/, '') + } + return `${arg}` +} diff --git a/package.json b/package.json index ba6599233c..2cc3c884f9 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "main": "./index.mjs", "exports": { ".": "./index.mjs", - "./globals": "./globals.mjs" + "./globals": "./globals.mjs", + "./experimental": "./experimental.mjs" }, "types": "index.d.ts", "bin": { diff --git a/test.mjs b/test.mjs index ac69ba5511..7f3f2307cf 100755 --- a/test.mjs +++ b/test.mjs @@ -13,6 +13,7 @@ // limitations under the License. import {strict as assert} from 'assert' +import {retry} from './experimental.mjs' { // Only stdout is used during command substitution let hello = await $`echo Error >&2; echo Hello` @@ -218,6 +219,14 @@ import {strict as assert} from 'assert' console.log(chalk.greenBright('YAML works')) } +{ // Retry works. + try { + await retry(5)`exit 123` + } catch (p) { + assert.equal(p.exitCode, 123) + } +} + { // require() is working in ESM const {name, version} = require('./package.json') assert(typeof name === 'string')