README
¶
cmdcomp
cmdcomp -- compare the output of two commands with optional preprocessing and customizable diff
## Usage
```shell
cmdcomp [flags] -- COMMON_ARGS [-- LEFT_ARGS [-- RIGHT_ARGS]]
```
## Examples
```shell
# echo a > leftfile
# echo b > rightfile
# diff leftfile rightfile
cmdcomp -- echo -- a -- b
# echo a > leftfile
# echo b > rightfile
# diff -u leftfile rightfile
cmdcomp -x 'diff -u' -- echo -- a -- b
# echo a > leftfile
# echo b > rightfile
# diff -u leftfile rightfile --label echo___a --label echo___b
cmdcomp -x 'diff -u' -l -- echo -- a -- b
# echo a | sed 's|a|c|' > leftfile
# echo b | sed 's|a|c|' > rightfile
# diff leftfile rightfile
cmdcomp -p 'sed "s|a|c|"' -- echo -- a -- b
# helm repo update
# helm template datadog/datadog --version 3.68.0 | yq 'select(.kind=="Secret")' > leftfile
# helm template datadog/datadog --version 3.69.3 --set datadog.logLevel=debug | yq 'select(.kind=="Secret")' > rightfile
# objdiff -c leftfile rightfile
cmdcomp --startup 'helm repo update' -p "yq 'select(.kind==\"Secret\")'" -x 'objdiff -c' -- helm template datadog/datadog -- --version 3.68.0 -- --version 3.69.3 --set datadog.logLevel=debug
# helm template datadog/datadog --version 3.68.0 | yq 'select(.kind=="Deployment" and .metadata.name=="release-name-datadog-cluster-agent")' -o json > leftfile
# helm template datadog/datadog --version 3.69.3 --set datadog.logLevel=debug | yq 'select(.kind=="Deployment" and .metadata.name=="release-name-datadog-cluster-agent")' -o json > rightfile
# npx jsondiffpatch --format=jsonpatch leftfile rightfile
cmdcomp -p "yq 'select(.kind==\"Deployment\" and .metadata.name==\"release-name-datadog-cluster-agent\")' -o json" -x 'npx jsondiffpatch --format=jsonpatch' -- helm template datadog/datadog -- --version 3.68.0 -- --version 3.69.3 --set datadog.logLevel=debug
# helm template datadog/datadog --version 3.68.0 | yq 'select(.kind=="Deployment" and .metadata.name=="release-name-datadog-cluster-agent")' -o json | gron > leftfile
# helm template datadog/datadog --version 3.69.3 --set datadog.logLevel=debug | yq 'select(.kind=="Deployment" and .metadata.name=="release-name-datadog-cluster-agent")' -o json | gron > rightfile
# diff -u --color leftfile rightfile
cmdcomp -p "yq 'select(.kind==\"Deployment\" and .metadata.name==\"release-name-datadog-cluster-agent\")' -o json" -p 'gron' -x 'diff -u --color' -- helm template datadog/datadog -- --version 3.68.0 -- --version 3.69.3 --set datadog.logLevel=debug
# helm template ./charts/datadog > leftfile
# git checkout datadog-3.69.3
# helm template ./charts/datadog > rightfile
# objdiff -c leftfile rightfile
cmdcomp -i 'git checkout datadog-3.69.3' -x 'objdiff -c' -- helm template ./charts/datadog
# echo echo -- a > leftfile
# echo echo -- b > rightfile
# diff leftfile rightfile
cmdcomp -d '---' -- echo --- echo -- a --- echo -- b
# cmdcomp --success -- echo -- a -- b > leftfile
# cmdcomp --success -- echo -- a -- c > rightfile
# diff leftfile rightfile
cmdcomp -d '---' -- cmdcomp --success -- echo -- a -- --- b --- c
# helm show values datadog/datadog --version 3.69.3 | yq -o json | gron > leftfile
# helm show values datadog/datadog --version 3.164.1 | yq -o json | gron > rightfile
# diff -u --color leftfile rightfile
cmdcomp -x 'diff -u --color' -p 'yq -o json' -p 'gron' -- helm show values datadog/datadog --version -- 3.69.3 -- 3.164.1
```
## Config file
### Format
```yaml
presets:
example:
show-cmd-log: true
debug: true
startup:
- echo startup
interceptor:
- echo interceptor
preprocess:
- grep common
left-preprocess:
- grep left
right-preprocess:
- grep right
diff: diff
work-dir: workdir
shell: bash
delimiter: --
label: true
env:
- X=1
left-env:
- Y=2
right-env:
- Y=3
cleanup:
- echo cleanup
common-args:
- echo
left-args:
- common left
right-args:
- common right
success: true
```
### Builtin config
```yaml
presets:
dyff:
diff: dyff between --omit-header --set-exit-code
shell: bash
delimiter: --
helm:
startup:
- helm repo update
diff: objdiff -cv
shell: bash
delimiter: --
helm-chart:
startup:
- helm repo update
preprocess:
- yq -P 'sort_keys(..)'
diff: diff -u --color
shell: bash
delimiter: --
common-args:
- helm
- show
- chart
- $CHART
left-args:
- --version
- $LEFT
right-args:
- --version
- $RIGHT
helm-values:
startup:
- helm repo update
preprocess:
- yq -P 'sort_keys(..)'
diff: diff -u --color
shell: bash
delimiter: --
common-args:
- helm
- show
- values
- $CHART
left-args:
- --version
- $LEFT
right-args:
- --version
- $RIGHT
json:
preprocess:
- jq -S .
diff: diff -u --color
shell: bash
delimiter: --
k8s:
diff: objdiff -cv
shell: bash
delimiter: --
k8s-clean:
preprocess:
- yq 'del(.metadata.resourceVersion, .metadata.uid, .metadata.creationTimestamp, .metadata.generation, .metadata.managedFields, .status)'
diff: objdiff -cv
shell: bash
delimiter: --
yml:
preprocess:
- yq -P 'sort_keys(..)'
diff: diff -u --color
shell: bash
delimiter: --
```
### Usage
```shell
# use "example" preset
# overriding "diff" option
cmdcomp --config CONFIG_PATH --preset example -x 'diff -u'
# use builtin "json" preset
cmdcomp --preset json -- ...
```
### Examples
```yaml
presets:
sentry:
diff: objdiff -cv
common-args: ["helm", "template", "sentry/sentry", "--version", "$VERSION"]
```
then
```shell
# helm template sentry/sentry --version 28.0.3 > leftfile
# helm template sentry/sentry --version 29.5.1 > rightfile
# objdiff -cv leftfile rightfile
cmdcomp --config CONFIG --preset sentry --left-env 'VERSION=28.0.3' --right-env 'VERSION=29.5.1'
```
## Exit Codes
- 0: No diff detected, dryrun, version/help displayed, or diff detected with --success.
- 1: Diff detected (exit code of diff command).
- 2: Process failure (command error, hook error, pipeline error, timeout, config/flag error). Always returns 2 even if --success is specified.
## Environment Variables
All flags can be specified via environment variables using the 'CMDCOMP_' prefix (e.g. CMDCOMP_DIFF, CMDCOMP_PRESET, CMDCOMP_SHOW_CMD_LOG).
Precedence: Default/Preset < Environment Variables < Command-line Flags
- Command lists (CMDCOMP_STARTUP, CMDCOMP_PREPROCESS, etc.): Separate multiple commands with newline.
- Environment variable pairs (CMDCOMP_ENV, CMDCOMP_LEFT_ENV, CMDCOMP_RIGHT_ENV): Separate entries with comma (,).
## Flags
-c, --cleanup stringArray command(s) guaranteed to execute before cmdcomp exits, even on failure. Can be specified multiple times. In env vars, separate commands with newlines
--config string configuration file path (default search order: UserConfigDir/cmdcomp/config.yml, $HOME/.cmdcomp.yml, .cmdcomp.yml)
--debug enable debug log output
-d, --delimiter string delimiter token separating [COMMON_ARGS], [LEFT_ARGS], and [RIGHT_ARGS] (e.g. '---') (default "--")
-x, --diff string diff command invoked as '<diff> LEFT_FILE RIGHT_FILE' (e.g. 'diff -u', 'colordiff', 'dyff', 'objdiff -c') (default "diff")
--dry-run print generated bash script capturing the full execution pipeline without executing commands
-e, --env stringArray environment variables passed to all subcommands along with system environment (KEY=VALUE). Can be specified multiple times or comma-separated
-i, --interceptor stringArray command(s) executed sequentially after left command and before right command (e.g. git checkout). Can be specified multiple times. In env vars, separate commands with newlines
-l, --label pass '--label LEFT_ARG' and '--label RIGHT_ARG' to the diff command (useful for diff/colordiff)
--left-env stringArray environment variables passed only to left command and left preprocess (KEY=VALUE). Can be specified multiple times or comma-separated
--left-preprocess stringArray additional filter pipeline command(s) applied only to left output after common preprocess. Multiple flags form a piped chain. In env vars, separate commands with newlines
-p, --preprocess stringArray filter pipeline command(s) applied to both left and right outputs before diffing. Reads stdin, writes stdout (e.g. jq, yq, sed). Multiple flags form a piped chain. In env vars, separate commands with newlines
--preset string name of preset configuration to load from config file or built-in presets (e.g. 'json', 'yml', 'helm', 'k8s', 'dyff')
--process-timeout duration maximum timeout for each individual subcommand execution (e.g. '10s', '1m')
--right-env stringArray environment variables passed only to right command and right preprocess (KEY=VALUE). Can be specified multiple times or comma-separated
--right-preprocess stringArray additional filter pipeline command(s) applied only to right output after common preprocess. Multiple flags form a piped chain. In env vars, separate commands with newlines
-S, --shell string shell executable used to run subcommands (default "bash")
--show-cmd-log print stdout and stderr of executed subcommands to log output
-s, --startup stringArray command(s) executed sequentially before running commands (e.g. repo updates). Can be specified multiple times. In env vars, separate commands with newlines
--success exit 0 when diffs are detected (exit status 1 from diff command). Failures (exit code 2) still return 2
--timeout duration maximum timeout for entire cmdcomp execution (e.g. '30s', '2m')
--version display version and exit
-w, --work-dir string working directory for temporary output files. When specified, temporary files are preserved after execution
Install
go install github.com/berquerant/cmdcomp/cmd/cmdcomp@latest
Click to show internal directories.
Click to hide internal directories.