Help us shape the future of Go! Take the 2026 Go Developer Survey

cmdcomp

module
v0.7.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 21, 2026 License: MIT

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

Directories

Path Synopsis
cmd
cmdcomp command
pkg
cli
run

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL