Compare commits
5 Commits
edce909525
...
040c3a8c47
| Author | SHA1 | Date | |
|---|---|---|---|
| 040c3a8c47 | |||
| d2c24da7dc | |||
| b04849cc5a | |||
| 60eb31cfc9 | |||
| 56d982db17 |
|
|
@ -6,7 +6,7 @@ Transcript-based shell integration test runner. Bun + TypeScript.
|
||||||
|
|
||||||
- `bun test` — run unit tests
|
- `bun test` — run unit tests
|
||||||
- `bunx tsc --noEmit` — type check
|
- `bunx tsc --noEmit` — type check
|
||||||
- `bun run src/cli/index.ts [files...]` — run shout CLI
|
- `bun run src/cli/index.ts test [files...]` — run shout CLI
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
|
|
|
||||||
13
README.md
13
README.md
|
|
@ -33,21 +33,21 @@ ls: missing: No such file or directory
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```
|
```
|
||||||
$ shout
|
$ shout test
|
||||||
...............
|
...............
|
||||||
15 passed in 23ms
|
15 passed in 23ms
|
||||||
```
|
```
|
||||||
|
|
||||||
`shout` runs code in a temp directory. `-k`/`--keep` keeps it around.
|
`shout test` runs code in a temp directory. `-k`/`--keep` keeps it around.
|
||||||
|
|
||||||
`--update` will modify `.shout` files to match reality, without running any tests.
|
`--update` will modify `.shout` files to match reality, without running any tests.
|
||||||
|
|
||||||
Each line in a `.shout` file is run sequentially, unless `--parallel` is passed.
|
Each line in a `.shout` file is run sequentially, unless `--parallel` is passed.
|
||||||
|
|
||||||
```
|
```
|
||||||
Usage: shout [options] [files...]
|
Usage: shout test [options] [files...]
|
||||||
|
|
||||||
shell output tester.
|
Run .shout test files
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
files Files or directories to test
|
files Files or directories to test
|
||||||
|
|
@ -61,5 +61,10 @@ Options:
|
||||||
-v, --verbose Print each command as it runs
|
-v, --verbose Print each command as it runs
|
||||||
--parallel Run files in parallel
|
--parallel Run files in parallel
|
||||||
-h, --help display help for command
|
-h, --help display help for command
|
||||||
|
```
|
||||||
|
|
||||||
|
Print an example `.shout` file:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
$ shout example
|
||||||
|
```
|
||||||
|
|
|
||||||
189
SPEC.md
189
SPEC.md
|
|
@ -1,189 +0,0 @@
|
||||||
# shout
|
|
||||||
|
|
||||||
A transcript-based shell integration test runner.
|
|
||||||
|
|
||||||
## Format
|
|
||||||
|
|
||||||
A `.shout` file is a plain text transcript of a shell session. Lines starting
|
|
||||||
with `$ ` are commands. Everything after — until the next `$` or end of file
|
|
||||||
— is the expected output (stdout and stderr combined).
|
|
||||||
|
|
||||||
```
|
|
||||||
$ dev new "add auth"
|
|
||||||
created draft 1 "add auth"
|
|
||||||
|
|
||||||
$ dev save
|
|
||||||
saved draft 1 (v1)
|
|
||||||
```
|
|
||||||
|
|
||||||
Blank lines within expected output are significant. Trailing newline on the
|
|
||||||
file is ignored.
|
|
||||||
|
|
||||||
### Comments
|
|
||||||
|
|
||||||
`#` after a command is a comment and is stripped before execution. Comments
|
|
||||||
in expected output are matched literally.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ dev new "add auth" # create a draft from timeline HEAD
|
|
||||||
created draft 1 "add auth"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Wildcards
|
|
||||||
|
|
||||||
A `...` on its own line in expected output matches any number of lines
|
|
||||||
(including zero).
|
|
||||||
|
|
||||||
```
|
|
||||||
$ dev log
|
|
||||||
...
|
|
||||||
draft 1 "add auth"
|
|
||||||
```
|
|
||||||
|
|
||||||
A `...` inline matches any sequence of characters on that line.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ dev status
|
|
||||||
draft 1 "add auth" (v...)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Environment
|
|
||||||
|
|
||||||
Each `.shout` file runs in a fresh temporary directory. The directory is
|
|
||||||
created before the first command and removed after the last (unless
|
|
||||||
`--keep` is passed).
|
|
||||||
|
|
||||||
All commands in a file run in a single shell session (`/bin/sh`), so `cd`,
|
|
||||||
`export`, and other shell state persists between commands.
|
|
||||||
|
|
||||||
The following environment variables are set for every command:
|
|
||||||
|
|
||||||
| Variable | Value |
|
|
||||||
|---|---|
|
|
||||||
| `HOME` | the temp directory |
|
|
||||||
| `PATH` | inherited from host (or prepended via `--path`) |
|
|
||||||
| `CUE_DIR` | the temp directory |
|
|
||||||
|
|
||||||
All other environment variables are inherited from the host unless explicitly
|
|
||||||
cleared with `--clean-env`.
|
|
||||||
|
|
||||||
### Exit codes
|
|
||||||
|
|
||||||
By default, a non-zero exit code fails the test regardless of output. To
|
|
||||||
assert a specific exit code, append `[N]` on the last line of expected output:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ dev rm
|
|
||||||
error: draft 1 has children. use dev rm -f to cascade.
|
|
||||||
[1]
|
|
||||||
```
|
|
||||||
|
|
||||||
`[*]` accepts any non-zero exit code without asserting the value.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## CLI
|
|
||||||
|
|
||||||
```
|
|
||||||
shout [options] [files|dirs...]
|
|
||||||
```
|
|
||||||
|
|
||||||
If no files are given, shout runs all `*.shout` files in the current directory
|
|
||||||
and subdirectories. Each command in each shout file is run sequentially
|
|
||||||
(unless `--parallel` is passed).
|
|
||||||
|
|
||||||
### Options
|
|
||||||
|
|
||||||
| Flag | Description |
|
|
||||||
|---|---|
|
|
||||||
| `--update` / `-u` | Rewrite expected output in-place with actual output |
|
|
||||||
| `--keep` / `-k` | Keep temp directories after run (printed to stderr) |
|
|
||||||
| `--clean-env` | Start with empty environment (only `PATH` and `CUE_DIR` set) |
|
|
||||||
| `--path <path>` | Prepend `<path>` to `PATH` (repeatable) |
|
|
||||||
| `--timeout <dur>` | Per-command timeout, e.g. `500ms`, `10s`, `1m` (default: `10s`) |
|
|
||||||
| `--verbose` / `-v` | Print each command as it runs |
|
|
||||||
| `--parallel` | Run files in parallel (implies all files run regardless of failures) |
|
|
||||||
|
|
||||||
### Output
|
|
||||||
|
|
||||||
Passing files print a single `.` per file. Failing files print a unified diff:
|
|
||||||
|
|
||||||
```
|
|
||||||
FAIL tests/auth.shout
|
|
||||||
|
|
||||||
$ dev rm
|
|
||||||
- error: draft 1 has children. use dev rm -f to cascade.
|
|
||||||
+ error: draft 1 has dependents. use dev rm -f to cascade.
|
|
||||||
[1]
|
|
||||||
```
|
|
||||||
|
|
||||||
Summary line at the end:
|
|
||||||
|
|
||||||
```
|
|
||||||
12 passed, 1 failed in 340ms
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Update mode
|
|
||||||
|
|
||||||
`--update` rewrites the expected output sections of each `.shout` file with the
|
|
||||||
actual output from the run. Commands, comments, and whitespace are preserved.
|
|
||||||
Wildcard lines are left in place if the actual output matches them; they are
|
|
||||||
only replaced if the match fails.
|
|
||||||
|
|
||||||
This makes it safe to run `shout --update` routinely after intentional output
|
|
||||||
changes — review the diff, commit if correct.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## File layout
|
|
||||||
|
|
||||||
```
|
|
||||||
tests/
|
|
||||||
auth.shout
|
|
||||||
drafts.shout
|
|
||||||
stack.shout
|
|
||||||
```
|
|
||||||
|
|
||||||
No special directory structure is required. `.shout` files can live anywhere.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Implementation notes
|
|
||||||
|
|
||||||
- Bun + TypeScript
|
|
||||||
- Each file runs in a single `/bin/sh` session via `Bun.spawn`
|
|
||||||
- Stdout and stderr merged (same as a terminal)
|
|
||||||
- Shell state (`cd`, `export`, etc.) persists across commands within a file
|
|
||||||
- Commands are fed to the shell sequentially; output between commands is
|
|
||||||
captured by delimiting with sentinel `echo` statements
|
|
||||||
- shout exits `0` if all tests pass, `1` if any fail
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Example
|
|
||||||
|
|
||||||
```
|
|
||||||
$ dev new "add auth"
|
|
||||||
created draft 1 "add auth"
|
|
||||||
|
|
||||||
$ echo 'export function auth() {}' > auth.ts
|
|
||||||
$ dev save
|
|
||||||
saved draft 1 (v1)
|
|
||||||
|
|
||||||
$ echo 'export function auth(token: string) {}' > auth.ts
|
|
||||||
$ dev save
|
|
||||||
saved draft 1 (v2)
|
|
||||||
|
|
||||||
$ dev status
|
|
||||||
draft 1 "add auth" (v2)
|
|
||||||
modified: (none)
|
|
||||||
|
|
||||||
$ dev new "add db"
|
|
||||||
created draft 2 "add db"
|
|
||||||
|
|
||||||
$ dev rm 1
|
|
||||||
error: draft 1 has children. use dev rm -f to cascade.
|
|
||||||
[1]
|
|
||||||
```
|
|
||||||
250
index.html
Normal file
250
index.html
Normal file
|
|
@ -0,0 +1,250 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>shout — shell output tester</title>
|
||||||
|
<meta name="description" content="shell output tester">
|
||||||
|
<style>
|
||||||
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--bg: #fff;
|
||||||
|
--fg: #444;
|
||||||
|
--bright: #1a1a1a;
|
||||||
|
--green: #1a7f37;
|
||||||
|
--red: #cf222e;
|
||||||
|
--dim: #888;
|
||||||
|
--accent: #1a7f37;
|
||||||
|
--code-bg: #f5f5f5;
|
||||||
|
--border: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root {
|
||||||
|
--bg: #0a0a0a;
|
||||||
|
--fg: #b0b0b0;
|
||||||
|
--bright: #e0e0e0;
|
||||||
|
--green: #4ec966;
|
||||||
|
--red: #e55;
|
||||||
|
--dim: #555;
|
||||||
|
--accent: #4ec966;
|
||||||
|
--code-bg: #111;
|
||||||
|
--border: #222;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
html { font-size: 16px; }
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: var(--bg);
|
||||||
|
color: var(--fg);
|
||||||
|
font-family: 'SF Mono', 'Cascadia Code', 'Fira Code', 'JetBrains Mono', 'Menlo', 'Consolas', monospace;
|
||||||
|
line-height: 1.6;
|
||||||
|
padding: 0 1.5rem;
|
||||||
|
max-width: 680px;
|
||||||
|
margin: 0 auto;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
padding: 6rem 0 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--bright);
|
||||||
|
letter-spacing: -0.03em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 span {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tagline {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
color: var(--dim);
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.install {
|
||||||
|
margin-top: 2rem;
|
||||||
|
display: inline-block;
|
||||||
|
background: var(--code-bg);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
padding: 0.6rem 1.2rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--bright);
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
transition: border-color 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.install:hover {
|
||||||
|
border-color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.install .hint {
|
||||||
|
color: var(--dim);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
margin-left: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
padding: 0 0 2em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--dim);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.1em;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bright { color: var(--bright); }
|
||||||
|
.green { color: var(--green); }
|
||||||
|
.red { color: var(--red); }
|
||||||
|
.dim { color: var(--dim); }
|
||||||
|
|
||||||
|
pre {
|
||||||
|
background: var(--code-bg);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 1.2rem 1.4rem;
|
||||||
|
overflow-x: auto;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
line-height: 1.7;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre code {
|
||||||
|
color: var(--fg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt { color: var(--dim); }
|
||||||
|
.cmd { color: var(--bright); }
|
||||||
|
.output { color: var(--fg); }
|
||||||
|
.comment { color: var(--dim); font-style: italic; }
|
||||||
|
.wildcard { color: var(--accent); }
|
||||||
|
.exit-code { color: var(--red); }
|
||||||
|
.pass { color: var(--green); }
|
||||||
|
|
||||||
|
|
||||||
|
footer {
|
||||||
|
padding: 3rem 0;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
color: var(--dim);
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer a {
|
||||||
|
color: var(--fg);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer a:hover {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--accent);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 520px) {
|
||||||
|
header { padding: 3rem 0 2rem; }
|
||||||
|
h1 { font-size: 2rem; }
|
||||||
|
section { padding: 2rem 0; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<h1><span>$</span> shout</h1>
|
||||||
|
<p class="tagline">shell output tester</p>
|
||||||
|
<div class="install" onclick="navigator.clipboard.writeText('bun install -g @because/shout --registry=https://npm.nose.space')">
|
||||||
|
<span class="prompt">$</span> <span class="cmd">bun install -g @because/shout --registry=https://npm.nose.space</span>
|
||||||
|
<span class="hint">click to copy</span>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Write a test</h2>
|
||||||
|
<p>A <code>.shout</code> file is just a shell session. Commands start with <code class="bright">$</code>, everything else is expected output.</p>
|
||||||
|
<pre><code><span class="prompt">$</span> <span class="cmd">echo hello</span>
|
||||||
|
<span class="output">hello</span>
|
||||||
|
|
||||||
|
<span class="prompt">$</span> <span class="cmd">ls missing</span>
|
||||||
|
<span class="output">ls: missing: No such file or directory</span>
|
||||||
|
<span class="exit-code">[1]</span>
|
||||||
|
|
||||||
|
<span class="prompt">$</span> <span class="cmd">brew --version</span>
|
||||||
|
<span class="output">Homebrew 5</span><span class="wildcard">...</span></code></pre>
|
||||||
|
<p><code class="wildcard">...</code> matches anything — inline or across lines.</p>
|
||||||
|
<p><code class="exit-code">[1]</code> asserts the exit code.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Run it</h2>
|
||||||
|
<pre><code><span class="prompt">$</span> <span class="cmd">shout test</span>
|
||||||
|
<span class="pass">...............
|
||||||
|
15 passed</span> <span class="dim">in 23ms</span></code></pre>
|
||||||
|
<p>Each file gets a fresh temp directory and its own <code>/bin/sh</code> session. State carries between commands within a file.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Update expectations</h2>
|
||||||
|
<pre><code><span class="prompt">$</span> <span class="cmd">shout test --update</span></code></pre>
|
||||||
|
<p>Rewrites your <code>.shout</code> files with the actual output. No more copy-pasting from the terminal.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Usage</h2>
|
||||||
|
<pre><code><span class="prompt">$</span> <span class="cmd">shout test --help</span>
|
||||||
|
<span class="output">Usage: shout test [options] [files...]
|
||||||
|
|
||||||
|
Run .shout test files
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
files Files or directories to test
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-u, --update Rewrite expected output in-place with actual output
|
||||||
|
-k, --keep Keep temp directories after run
|
||||||
|
--clean-env Start with empty environment
|
||||||
|
--path <path> Prepend <path> to PATH (repeatable)
|
||||||
|
--timeout <dur> Per-command timeout (default: "10s")
|
||||||
|
-v, --verbose Print each command as it runs
|
||||||
|
--parallel Run files in parallel
|
||||||
|
-h, --help display help for command</span></code></pre>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Environment</h2>
|
||||||
|
<p>Shout sets these variables before running your commands:</p>
|
||||||
|
<pre><code><span class="bright">HOME</span> <span class="dim">→</span> <span class="output">temp directory for this test file</span>
|
||||||
|
<span class="bright">SHOUT_DIR</span> <span class="dim">→</span> <span class="output">same temp directory</span>
|
||||||
|
<span class="bright">PATH</span> <span class="dim">→</span> <span class="output">prepended with --path dirs, if any</span></code></pre>
|
||||||
|
<p>Each file runs in its own temp directory. <code>--clean-env</code> starts with an empty environment instead of inheriting yours.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<a href="https://github.com/because/shout">GitHub</a> · <a href="https://www.npmjs.com/package/@because/shout">npm</a>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@because/shout",
|
"name": "@because/shout",
|
||||||
"version": "0.0.2",
|
"version": "0.0.2",
|
||||||
"description": "test shell output",
|
"description": "shell output tester",
|
||||||
"module": "src/index.ts",
|
"module": "src/index.ts",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"files": [
|
"files": [
|
||||||
|
|
|
||||||
|
|
@ -43,9 +43,16 @@ async function findShoutFiles(paths: string[]): Promise<string[]> {
|
||||||
return files.sort()
|
return files.sort()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import pkg from "../../package.json"
|
||||||
|
|
||||||
program
|
program
|
||||||
.name("shout")
|
.name("shout")
|
||||||
.description("$ shell output tester")
|
.description("$ shell output tester")
|
||||||
|
.version(pkg.version)
|
||||||
|
|
||||||
|
program
|
||||||
|
.command("test")
|
||||||
|
.description("Run .shout test files")
|
||||||
.argument("[files...]", "Files or directories to test")
|
.argument("[files...]", "Files or directories to test")
|
||||||
.option("-u, --update", "Rewrite expected output in-place with actual output")
|
.option("-u, --update", "Rewrite expected output in-place with actual output")
|
||||||
.option("-k, --keep", "Keep temp directories after run")
|
.option("-k, --keep", "Keep temp directories after run")
|
||||||
|
|
@ -54,28 +61,7 @@ program
|
||||||
.option("--timeout <dur>", "Per-command timeout", "10s")
|
.option("--timeout <dur>", "Per-command timeout", "10s")
|
||||||
.option("-v, --verbose", "Print each command as it runs")
|
.option("-v, --verbose", "Print each command as it runs")
|
||||||
.option("--parallel", "Run files in parallel")
|
.option("--parallel", "Run files in parallel")
|
||||||
.option("--example", "Print an example .shout file and exit")
|
|
||||||
.action(async (fileArgs: string[], opts) => {
|
.action(async (fileArgs: string[], opts) => {
|
||||||
if (opts.example) {
|
|
||||||
console.log(`# Example .shout file
|
|
||||||
$ echo hello
|
|
||||||
hello
|
|
||||||
|
|
||||||
$ echo "one"; echo "two"; echo "three"
|
|
||||||
one
|
|
||||||
...
|
|
||||||
three
|
|
||||||
|
|
||||||
$ cat nonexistent
|
|
||||||
cat: nonexistent: ...
|
|
||||||
[1]
|
|
||||||
|
|
||||||
$ true
|
|
||||||
[0]`)
|
|
||||||
process.exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const timeoutMs = parseDuration(opts.timeout)
|
const timeoutMs = parseDuration(opts.timeout)
|
||||||
const paths = fileArgs.length > 0 ? fileArgs : ["."]
|
const paths = fileArgs.length > 0 ? fileArgs : ["."]
|
||||||
const files = await findShoutFiles(paths)
|
const files = await findShoutFiles(paths)
|
||||||
|
|
@ -171,4 +157,32 @@ $ true
|
||||||
process.exit(failures.length > 0 ? 1 : 0)
|
process.exit(failures.length > 0 ? 1 : 0)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
program
|
||||||
|
.command("version")
|
||||||
|
.description("Print the version")
|
||||||
|
.action(() => {
|
||||||
|
console.log(pkg.version)
|
||||||
|
})
|
||||||
|
|
||||||
|
program
|
||||||
|
.command("example")
|
||||||
|
.description("Print an example .shout file")
|
||||||
|
.action(() => {
|
||||||
|
console.log(`# Example .shout file
|
||||||
|
$ echo hello
|
||||||
|
hello
|
||||||
|
|
||||||
|
$ echo "one"; echo "two"; echo "three"
|
||||||
|
one
|
||||||
|
...
|
||||||
|
three
|
||||||
|
|
||||||
|
$ cat nonexistent
|
||||||
|
cat: nonexistent: ...
|
||||||
|
[1]
|
||||||
|
|
||||||
|
$ true
|
||||||
|
[0]`)
|
||||||
|
})
|
||||||
|
|
||||||
program.parse()
|
program.parse()
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ export async function runFile(
|
||||||
: { ...process.env as Record<string, string> }
|
: { ...process.env as Record<string, string> }
|
||||||
|
|
||||||
env["HOME"] = tmpDir
|
env["HOME"] = tmpDir
|
||||||
env["CUE_DIR"] = tmpDir
|
env["SHOUT_DIR"] = tmpDir
|
||||||
|
|
||||||
if (options.pathDirs?.length) {
|
if (options.pathDirs?.length) {
|
||||||
env["PATH"] = options.pathDirs.join(":") + ":" + (env["PATH"] ?? "")
|
env["PATH"] = options.pathDirs.join(":") + ":" + (env["PATH"] ?? "")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user