run-and-notify 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +3 -0
- package/LICENSE +619 -0
- package/README.md +132 -0
- package/config.example.json +54 -0
- package/dist/bundle/run-and-notify.mjs +516 -0
- package/dist/bundle/run-and-notify.mjs.map +7 -0
- package/examples/apps/daily-digest-failure.mjs +17 -0
- package/examples/apps/daily-digest-html-success.mjs +14 -0
- package/examples/apps/daily-digest-success.mjs +16 -0
- package/examples/apps/full-html.mjs +14 -0
- package/examples/apps/full-markdown.mjs +19 -0
- package/examples/apps/full-raw.mjs +4 -0
- package/examples/apps/structured-jsonl-success.mjs +23 -0
- package/examples/config-html.json +8 -0
- package/examples/config-jsonl.json +8 -0
- package/examples/config-markdown.json +8 -0
- package/examples/config-raw.json +8 -0
- package/examples/daily-digest-html/config.json +46 -0
- package/examples/daily-digest-html/templates/error.email.html.hbs +9 -0
- package/examples/daily-digest-html/templates/error.slack.blocks.json.hbs +9 -0
- package/examples/daily-digest-html/templates/error.subject.hbs +1 -0
- package/examples/daily-digest-html/templates/error.text.hbs +7 -0
- package/examples/daily-digest-html/templates/success.email.html.hbs +1 -0
- package/examples/daily-digest-html/templates/success.slack.blocks.json.hbs +9 -0
- package/examples/daily-digest-html/templates/success.subject.hbs +1 -0
- package/examples/daily-digest-html/templates/success.text.hbs +1 -0
- package/examples/daily-digest-markdown/config.json +46 -0
- package/examples/daily-digest-markdown/templates/error.email.html.hbs +9 -0
- package/examples/daily-digest-markdown/templates/error.slack.blocks.json.hbs +16 -0
- package/examples/daily-digest-markdown/templates/error.subject.hbs +1 -0
- package/examples/daily-digest-markdown/templates/error.text.hbs +9 -0
- package/examples/daily-digest-markdown/templates/success.email.html.hbs +1 -0
- package/examples/daily-digest-markdown/templates/success.slack.blocks.json.hbs +9 -0
- package/examples/daily-digest-markdown/templates/success.subject.hbs +1 -0
- package/examples/daily-digest-markdown/templates/success.text.hbs +1 -0
- package/examples/full-html/config.json +46 -0
- package/examples/full-html/templates/email.html.hbs +22 -0
- package/examples/full-html/templates/slack.blocks.json.hbs +9 -0
- package/examples/full-html/templates/slack.text.hbs +1 -0
- package/examples/full-html/templates/subject.hbs +1 -0
- package/examples/full-html/templates/text.hbs +12 -0
- package/examples/full-markdown/config.json +46 -0
- package/examples/full-markdown/templates/email.html.hbs +1 -0
- package/examples/full-markdown/templates/slack.blocks.json.hbs +9 -0
- package/examples/full-markdown/templates/slack.text.hbs +1 -0
- package/examples/full-markdown/templates/subject.hbs +1 -0
- package/examples/full-markdown/templates/text.hbs +18 -0
- package/examples/full-raw/config.json +46 -0
- package/examples/full-raw/templates/email.html.hbs +22 -0
- package/examples/full-raw/templates/slack.blocks.json.hbs +16 -0
- package/examples/full-raw/templates/slack.text.hbs +1 -0
- package/examples/full-raw/templates/subject.hbs +1 -0
- package/examples/full-raw/templates/text.hbs +12 -0
- package/examples/minimal/config.json +20 -0
- package/examples/structured-jsonl-html/config.json +46 -0
- package/examples/structured-jsonl-html/templates/error.email.html.hbs +6 -0
- package/examples/structured-jsonl-html/templates/error.slack.blocks.json.hbs +9 -0
- package/examples/structured-jsonl-html/templates/error.subject.hbs +1 -0
- package/examples/structured-jsonl-html/templates/error.text.hbs +4 -0
- package/examples/structured-jsonl-html/templates/success.email.html.hbs +16 -0
- package/examples/structured-jsonl-html/templates/success.slack.blocks.json.hbs +9 -0
- package/examples/structured-jsonl-html/templates/success.subject.hbs +1 -0
- package/examples/structured-jsonl-html/templates/success.text.hbs +6 -0
- package/examples/structured-jsonl-markdown/config.json +46 -0
- package/examples/structured-jsonl-markdown/templates/error.email.html.hbs +9 -0
- package/examples/structured-jsonl-markdown/templates/error.slack.blocks.json.hbs +9 -0
- package/examples/structured-jsonl-markdown/templates/error.subject.hbs +1 -0
- package/examples/structured-jsonl-markdown/templates/error.text.hbs +9 -0
- package/examples/structured-jsonl-markdown/templates/success.email.html.hbs +1 -0
- package/examples/structured-jsonl-markdown/templates/success.slack.blocks.json.hbs +9 -0
- package/examples/structured-jsonl-markdown/templates/success.subject.hbs +1 -0
- package/examples/structured-jsonl-markdown/templates/success.text.hbs +19 -0
- package/package.json +79 -0
- package/schemas/config.schema.json +259 -0
package/README.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# run-and-notify
|
|
2
|
+
|
|
3
|
+
`run-and-notify` executes a command, captures stdout and stderr, renders Handlebars templates, and sends the result through Better-Notify transports. The default configuration targets SMTP email and Slack.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm install
|
|
9
|
+
pnpm run build
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Run a command by placing it after the run-and-notify options:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
run-and-notify --config=config.json --stdout.format=jsonl pnpm run test
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Configuration values can be overridden with dotted CLI flags such as `--cwd=/repo`, `--stdout.format=markdown`, `--dry-run`, `--no-propagate-exit-code`, or `--transports.smtp.enabled=false`. The command is a native yargs positional argument; options after the command are passed to the target command, and `--help` documents defaults from the JSON schema.
|
|
19
|
+
|
|
20
|
+
## Configuration
|
|
21
|
+
|
|
22
|
+
The canonical schema is [schemas/config.schema.json](./schemas/config.schema.json). `config.example.json` shows a complete SMTP and Slack setup.
|
|
23
|
+
|
|
24
|
+
Top-level fields:
|
|
25
|
+
|
|
26
|
+
- `name`: human-readable automation name used in default notification titles and subjects.
|
|
27
|
+
- `locale`: BCP 47 locale used by date and time helpers.
|
|
28
|
+
- `cwd`: optional working directory for the command.
|
|
29
|
+
- `dryRun`: when `true`, renders and logs notification payloads without sending them.
|
|
30
|
+
- `propagateExitCode`: when `true`, the CLI exits with the target command status after notifications are delivered. Defaults to `true`.
|
|
31
|
+
- `timeoutSeconds`: command timeout in seconds; `0` disables the timeout.
|
|
32
|
+
- `showStderrIfSuccess`: when `false`, success templates skip stderr unless they explicitly ignore this field.
|
|
33
|
+
- `hideCommandIfSuccess`: when `true`, success templates hide command metadata, visible separators, and the `Output` heading so only output content remains. Defaults to `false`.
|
|
34
|
+
- `templatesDir`: optional directory containing Handlebars templates and partials. When omitted, built-in templates bundled into the CLI are used.
|
|
35
|
+
- `stdout`: stdout parser settings.
|
|
36
|
+
- `stderr`: stderr parser settings.
|
|
37
|
+
- `transports`: Better-Notify transport settings.
|
|
38
|
+
- `success`: templates used when the command exits with status `0`.
|
|
39
|
+
- `error`: templates used when the command exits with a non-zero status.
|
|
40
|
+
|
|
41
|
+
`stdout.format` and `stderr.format` accept:
|
|
42
|
+
|
|
43
|
+
- `raw`: exposes `{ "format": "raw", "raw": "..." }`.
|
|
44
|
+
- `jsonl`: parses each line as JSON and wraps invalid lines as `{ "raw": "..." }`.
|
|
45
|
+
- `markdown`: exposes `{ "format": "markdown", "markdown": "..." }`.
|
|
46
|
+
- `html`: exposes `{ "format": "html", "html": "..." }`.
|
|
47
|
+
|
|
48
|
+
Only `jsonl` exposes `lines`. `raw`, `markdown`, and `html` preserve the full stream as a single string.
|
|
49
|
+
|
|
50
|
+
`transports.smtp` fields:
|
|
51
|
+
|
|
52
|
+
- `enabled`: enables SMTP email delivery.
|
|
53
|
+
- `host`: SMTP host.
|
|
54
|
+
- `port`: SMTP port, from `1` to `65535`.
|
|
55
|
+
- `secure`: use TLS from connection start.
|
|
56
|
+
- `from`: sender email address.
|
|
57
|
+
- `to`: one or more recipient email addresses.
|
|
58
|
+
- `auth.user`: optional SMTP username.
|
|
59
|
+
- `auth.passEnvVar`: environment variable containing the SMTP password.
|
|
60
|
+
|
|
61
|
+
The SMTP email delivery instance is scoped internally as `emailSmtp`/`email-smtp`, so future email transports can be added without overloading a generic email channel name.
|
|
62
|
+
|
|
63
|
+
`transports.slack` fields:
|
|
64
|
+
|
|
65
|
+
- `enabled`: enables Slack delivery through `@betternotify/slack`.
|
|
66
|
+
- `tokenEnvVar`: environment variable containing the Slack bot token passed to `slackTransport()`.
|
|
67
|
+
- `defaultChannel`: optional Slack channel ID or name used when the rendered payload does not set `to`.
|
|
68
|
+
|
|
69
|
+
Template fields under `success.email` and `error.email`:
|
|
70
|
+
|
|
71
|
+
- `subject`: email subject template filename.
|
|
72
|
+
- `html`: email HTML template filename.
|
|
73
|
+
- `text`: plain text email template filename.
|
|
74
|
+
|
|
75
|
+
Template fields under `success.slack` and `error.slack`:
|
|
76
|
+
|
|
77
|
+
- `text`: optional Slack fallback text template filename. When omitted, fallback text is generated from command and status.
|
|
78
|
+
- `blocks`: Slack blocks template filename; it must render a JSON array. Slack fallback text is generated from the command and status.
|
|
79
|
+
|
|
80
|
+
By default, `success` and `error` use built-in email and Slack templates. You can override any template with config or CLI flags such as `--success.email.html=custom-success.html.hbs`.
|
|
81
|
+
|
|
82
|
+
## Templates
|
|
83
|
+
|
|
84
|
+
Templates are loaded from `templatesDir` and may use partials from the same directory. If `templatesDir` is omitted, templates are loaded from built-ins imported into the bundled CLI. Built-in templates are registered first, so custom template directories may override any built-in by filename while still using built-in partials. The rendering context contains `config`, `stdout`, `stderr`, `status`, `command`, `cwd`, `timedOut`, `executedAt`, and `dryRun`.
|
|
85
|
+
|
|
86
|
+
Built-in email templates render `raw` as escaped preformatted text, `markdown` as HTML, `html` as provided HTML, and `jsonl` as itemized records. Built-in Slack block templates render Markdown through `markdown-to-slack-blocks`, split large block batches before sending, separate execution context with a divider when command metadata is visible, render `raw` as preformatted rich text, render `markdown` as Slack blocks, convert `html` to Markdown first, and render `jsonl` as nested itemized records.
|
|
87
|
+
|
|
88
|
+
Registered helpers:
|
|
89
|
+
|
|
90
|
+
- `dateFromISO8601`, `timeFromISO8601`, `datetimeFromISO8601`
|
|
91
|
+
- `dateFromUnixEpoch`, `timeFromUnixEpoch`, `datetimeFromUnixEpoch`
|
|
92
|
+
- `markdownToHtml`, `htmlToMarkdown`, `rawToHtml`
|
|
93
|
+
- `escapeHtml`, `escapeMarkdown`, `json`, `jsonValue`, `jsonString`, `concat`, `outputToSlack`, `slackCodeBlock`, `hasOutput`, `hideCommandIfSuccess`
|
|
94
|
+
- `shellCommand`, `shellToken`: formats command arrays and paths with space-delimited shell-friendly output, single-quoting values that contain whitespace.
|
|
95
|
+
|
|
96
|
+
## Environment
|
|
97
|
+
|
|
98
|
+
Copy `.env.example` when developing locally. The default examples reference these variables:
|
|
99
|
+
|
|
100
|
+
- `SMTP_PASS`: password used by `transports.smtp.auth.passEnvVar`.
|
|
101
|
+
- `SLACK_BOT_TOKEN`: token used by `transports.slack.tokenEnvVar`.
|
|
102
|
+
|
|
103
|
+
Variables loaded from the local `.env` file are used by `run-and-notify` itself, but are omitted from the target command environment so local provider secrets are not leaked to child processes by default. Variables that already exist before `run-and-notify` starts, such as an explicitly exported `SMTP_PASS`, `SLACK_BOT_TOKEN`, `LOG_LEVEL`, or any other environment variable, are still propagated to the child command.
|
|
104
|
+
|
|
105
|
+
## Examples
|
|
106
|
+
|
|
107
|
+
Complete example configurations and templates live under `examples/<name>/`, with sample target commands under `examples/apps/`.
|
|
108
|
+
|
|
109
|
+
- `full-raw`: raw stdout and stderr, including command metadata and execution timestamp.
|
|
110
|
+
- `minimal`: only transport configuration; uses parser, notification, and built-in template defaults.
|
|
111
|
+
- `full-markdown`: markdown stdout and stderr with fenced code blocks.
|
|
112
|
+
- `full-html`: HTML stdout and stderr, converted to markdown and wrapped in Slack code blocks.
|
|
113
|
+
- `daily-digest-markdown`: markdown success digest; failure renders JSONL pino stderr lines.
|
|
114
|
+
- `daily-digest-html`: HTML success digest; failure renders JSONL pino stderr lines.
|
|
115
|
+
- `structured-jsonl-markdown`: structured JSONL stdout rendered as markdown.
|
|
116
|
+
- `structured-jsonl-html`: structured JSONL stdout rendered as HTML.
|
|
117
|
+
|
|
118
|
+
## Exit Codes
|
|
119
|
+
|
|
120
|
+
If the command succeeds and notifications are delivered, `run-and-notify` exits `0`. If the command fails, notifications use the `error` templates and the CLI exits with the command status by default. Set `propagateExitCode` to `false`, pass `--propagateExitCode=false`, or pass `--no-propagate-exit-code` to return `0` after successful notification delivery even when the target command failed. If no transport is enabled, transport setup fails, or delivery through any configured transport fails, the CLI exits `1`; the target command is not executed unless at least one transport is ready.
|
|
121
|
+
|
|
122
|
+
Timed out commands are terminated and reported with status `124`.
|
|
123
|
+
|
|
124
|
+
`--dry-run` still requires enabled transport configuration, executes the target command, and renders provider payloads, but skips `send()` calls and logs what would have been sent.
|
|
125
|
+
|
|
126
|
+
## Development
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
pnpm run qa
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
The QA gate runs Biome checks, build, tests, and typecheck.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "run-and-notify",
|
|
3
|
+
"locale": "en-US",
|
|
4
|
+
"dryRun": false,
|
|
5
|
+
"propagateExitCode": true,
|
|
6
|
+
"timeoutSeconds": 0,
|
|
7
|
+
"showStderrIfSuccess": false,
|
|
8
|
+
"hideCommandIfSuccess": false,
|
|
9
|
+
"stdout": {
|
|
10
|
+
"format": "raw"
|
|
11
|
+
},
|
|
12
|
+
"stderr": {
|
|
13
|
+
"format": "raw"
|
|
14
|
+
},
|
|
15
|
+
"transports": {
|
|
16
|
+
"smtp": {
|
|
17
|
+
"enabled": true,
|
|
18
|
+
"host": "smtp.example.com",
|
|
19
|
+
"port": 587,
|
|
20
|
+
"secure": false,
|
|
21
|
+
"from": "run-and-notify@example.com",
|
|
22
|
+
"to": ["ops@example.com"],
|
|
23
|
+
"auth": {
|
|
24
|
+
"user": "run-and-notify@example.com",
|
|
25
|
+
"passEnvVar": "SMTP_PASS"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"slack": {
|
|
29
|
+
"enabled": true,
|
|
30
|
+
"tokenEnvVar": "SLACK_BOT_TOKEN",
|
|
31
|
+
"defaultChannel": "#ops"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"success": {
|
|
35
|
+
"email": {
|
|
36
|
+
"subject": "success.subject.hbs",
|
|
37
|
+
"html": "default.email.html.hbs",
|
|
38
|
+
"text": "default.text.hbs"
|
|
39
|
+
},
|
|
40
|
+
"slack": {
|
|
41
|
+
"blocks": "default.slack.blocks.json.hbs"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"error": {
|
|
45
|
+
"email": {
|
|
46
|
+
"subject": "error.subject.hbs",
|
|
47
|
+
"html": "default.email.html.hbs",
|
|
48
|
+
"text": "default.text.hbs"
|
|
49
|
+
},
|
|
50
|
+
"slack": {
|
|
51
|
+
"blocks": "default.slack.blocks.json.hbs"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|