diff --git a/README.md b/README.md index 1ebdd85..8860d9f 100644 --- a/README.md +++ b/README.md @@ -32,8 +32,11 @@ Examples: octoherd/cli octoherd run -S path/to/script.js -T $TOKEN -R Avoid any prompts octoherd/cli --octoherd-bypass-confirms + cat list.txt | octoherd run -S path/to/script.js -T $TOKEN ``` +When piping a list of repositories, lines starting with a comment delimiter such as `#` or `//` will be ignored. + The `script` must export a `script` function which takes three parameters: ```js diff --git a/bin/octoherd.js b/bin/octoherd.js index a65b985..f80555c 100755 --- a/bin/octoherd.js +++ b/bin/octoherd.js @@ -4,9 +4,11 @@ import yargs from "yargs"; import { hideBin } from "yargs/helpers"; import chalk from "chalk"; +import getStdin from 'get-stdin'; import { octoherd } from "../index.js"; import { VERSION } from "../version.js"; +import { parseInput } from "./parse-input.js"; import runCommand from "./commands/run.js"; const EPILOG = chalk.gray(`Questions? Ideas? Feedback? @@ -20,6 +22,10 @@ const argv = await yargs(hideBin(process.argv)) .version(VERSION) .epilog(EPILOG).argv; +const stdin = await getStdin(); + +argv.octoherdRepos = [...argv.octoherdRepos || [], ...parseInput(stdin)]; + try { await octoherd(argv); } catch (error) { diff --git a/bin/parse-input.js b/bin/parse-input.js new file mode 100644 index 0000000..ba94d35 --- /dev/null +++ b/bin/parse-input.js @@ -0,0 +1,16 @@ +const commentsDelimiter = ['//', '#']; + +export function parseInput(content = '') { + return content + .split('\n') + .map(line => line.trim()) + .filter(Boolean) // Ignore empty lines + .filter(line => { + // Ignore lines starting with a comment delimiter + if (commentsDelimiter.some(block => line.startsWith(block))) { + return false; + } + + return true; + }); +} diff --git a/index.js b/index.js index 5a288be..f3ba957 100644 --- a/index.js +++ b/index.js @@ -108,7 +108,7 @@ export async function octoherd(options) { octokit, script: octoherdScript, userOptions, - octoherdReposPassedAsFlag: !!octoherdRepos, + octoherdReposPassedAsFlag: octoherdRepos.length, }; await runScriptAgainstRepositories(state, octoherdRepos); diff --git a/package-lock.json b/package-lock.json index 4dd4eba..cb37637 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "chalk": "^5.0.0", "clipboardy": "^3.0.0", "enquirer": "^2.3.6", + "get-stdin": "^9.0.0", "jsonfile": "^6.0.1", "mkdirp": "^1.0.4", "tempy": "^2.0.0", @@ -1436,6 +1437,17 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-stdin": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", + "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -7303,6 +7315,11 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" }, + "get-stdin": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", + "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==" + }, "get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", diff --git a/package.json b/package.json index 55988a4..758eaa2 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "chalk": "^5.0.0", "clipboardy": "^3.0.0", "enquirer": "^2.3.6", + "get-stdin": "^9.0.0", "jsonfile": "^6.0.1", "mkdirp": "^1.0.4", "tempy": "^2.0.0", diff --git a/tests/parse-input.test.js b/tests/parse-input.test.js new file mode 100644 index 0000000..6061259 --- /dev/null +++ b/tests/parse-input.test.js @@ -0,0 +1,31 @@ +import { parseInput } from "../bin/parse-input.js"; +import { suite } from "uvu"; +import { equal } from "uvu/assert"; + +const parseTest = suite("parse-input"); + +parseTest("when input is empty", () => { + equal([], parseInput()); +}); + +parseTest("when input is a single line", () => { + equal(['foo'], parseInput('foo')); +}); + +parseTest("when input has multipe lines", () => { + equal(['foo', 'bar'], parseInput('foo\nbar')); +}); + +parseTest("when input contains multipe empty lines", () => { + equal(['foo', 'bar', 'baz'], parseInput('foo\n\n\nbar\n\nbaz\n\n')); +}); + +parseTest("when line contains leading or trailing whitespaces", () => { + equal(['foo', 'bar'], parseInput('foo \n bar')); +}); + +parseTest("when lines start with a comment delimiter", () => { + equal(['foo'], parseInput('foo\n//bar\n#baz')); +}); + +parseTest.run();