# δyƒƒ /ˈdʏf/ [![License](https://img.shields.io/github/license/homeport/dyff.svg)](https://github.com/homeport/dyff/blob/main/LICENSE) [![Go Report Card](https://goreportcard.com/badge/github.com/homeport/dyff)](https://goreportcard.com/report/github.com/homeport/dyff) [![Tests](https://github.com/homeport/dyff/workflows/Tests/badge.svg)](https://github.com/homeport/dyff/actions?query=workflow%3A%22Tests%22) [![Codecov](https://img.shields.io/codecov/c/github/homeport/dyff/main.svg)](https://codecov.io/gh/homeport/dyff) [![Go Reference](https://pkg.go.dev/badge/github.com/homeport/dyff.svg)](https://pkg.go.dev/github.com/homeport/dyff) [![Release](https://img.shields.io/github/release/homeport/dyff.svg)](https://github.com/homeport/dyff/releases/latest) [![Packaging status](https://repology.org/badge/tiny-repos/dyff.svg)](https://repology.org/project/dyff/versions) ![dyff](.docs/logo.png?raw=true "dyff logo - the letters d, y, and f in the colors green, yellow and red") ## Description A diff tool for YAML files, and sometimes JSON. `dyff` is inspired by the way the old [BOSH v1](https://bosh.io/) deployment output reported changes from one version to another by only showing the parts of a YAML file that change. Each difference is referenced by its location in the YAML document by using either the [Spruce](https://github.com/geofffranks/spruce) dot-style syntax (`some.path.in.the.file`) or [go-patch](https://github.com/cppforlife/go-patch) path syntax (`/some/name=path/in/the/id=file`). The output report aims to be as compact as possible to give a clear and simple overview of the change. Similar to the standard `diff` tool, it follows the principle of describing the change by going from the `from` input file to the target `to` input file. Input files can be local files (filesystem path), remote files (URI), or the standard input stream (using `-`). All orders of keys in hashes are preserved during processing and output to the terminal, most notably in the sub-commands to convert YAML to JSON and vice versa. ## Command documentation See [command documentation](.docs/commands/dyff.md) for details about each command and its flags. ## Use cases and examples - Show differences between the live configuration of Kubernetes resources and what would be applied (`kubectl` version >= `v1.20.0`): ```bash # Setup export KUBECTL_EXTERNAL_DIFF="dyff between --omit-header --set-exit-code" # Usage kubectl diff [...] ``` ![dyff between example with kubectl diff](.docs/dyff-between-kubectl-diff.png?raw=true "dyff in kubectl diff example") The `--set-exit-code` flag is required so that the `dyff` exit code matches `kubectl` expectations. An exit code `0` refers to no differences, `1` in case differences are detected. Other exit codes are treated as program issues. _Note:_ Versions of `kubectl` older than `v1.20.0` did not split the environment variable into field, therefore you cannot use command arguments. In this case, you need to wrap the `dyff` command with its argument into a helper shell script and use this instead. - Show the differences between two versions of [`cf-deployment`](https://github.com/cloudfoundry/cf-deployment/) YAMLs: ```bash dyff between \ https://raw.githubusercontent.com/cloudfoundry/cf-deployment/v1.10.0/cf-deployment.yml \ https://raw.githubusercontent.com/cloudfoundry/cf-deployment/v1.20.0/cf-deployment.yml ``` ![dyff between example](.docs/dyff-between-deployment-manifest-example.png?raw=true "dyff between example of two cf-deployment versions") - Embed `dyff` into **Git** for better understandable differences ```bash # Setup... git config --local diff.dyff.command 'dyff_between() { dyff --color on between --omit-header "$2" "$5"; }; dyff_between' echo '*.yml diff=dyff' >> .gitattributes # And have fun, e.g.: git log --ext-diff -u git show --ext-diff HEAD ``` ![dyff between example of a Git commit](.docs/dyff-between-git-commits-example.png?raw=true "dyff in Git example of an example commit") - Convert a JSON stream to YAML ```bash sometool --json | jq --raw-output '.data' | dyff yaml - ``` - Sometimes you end up with YAML or JSON files, where the order of the keys in maps was sorted alphabetically. With `dyff` you can restructure keys in maps to a more human appealing order: ```bash sometool --export --json | dyff yaml --restructure - ``` Or, rewrite a file _in place_ with the restructured order of keys. ```bash dyff yaml --restructure --in-place somefile.yml ``` - Just print a YAML (or JSON) file to the terminal to look at it. By default, `dyff` will use a neat output schema which includes different colors and indent helper lines to improve readability. The colors are roughly based on the default [Atom](https://atom.io) schema and work best on dark terminal backgrounds. The neat output is disabled if the output of `dyff` is redirected into a pipe, or you can disable it explicitly using the `--plain` flag. ```bash dyff yaml somefile.yml ``` - Convert a YAML file to JSON and vice versa: ```bash dyff json https://raw.githubusercontent.com/cloudfoundry/cf-deployment/v1.19.0/cf-deployment.yml ``` The `dyff` sub-command (`yaml`, or `json`) defines the output format, the tool automatically detects the input format itself. ```bash dyff yaml https://raw.githubusercontent.com/homeport/dyff/main/assets/bosh-yaml/manifest.json ``` ## Installation ### FreeBSD Install via ports: ```bash cd /usr/ports/textproc/dyff make install clean ``` Install via package (pkg): ```bash pkg install dyff ``` ### Homebrew The `homeport/tap` has macOS and GNU/Linux pre-built binaries available: ```bash brew install homeport/tap/dyff ``` ### Mise Using [mise](https://github.com/jdx/mise) you could do: ```bash mise use -g dyff@latest ``` ### MacPorts On macOS, `dyff` is also [available via MacPorts](https://ports.macports.org/port/dyff/): ```bash sudo port install dyff ``` ### Pre-built binaries in GitHub Prebuilt binaries can be [downloaded from the GitHub Releases section](https://github.com/homeport/dyff/releases/latest). ### Curl To Shell Convenience Script There is a convenience script to download the latest release for Linux or macOS if you want to need it simple (you need `curl` and `jq` installed on your machine): ```bash curl --silent --location https://git.io/JYfAY | bash ``` ### Build from Source Starting with Go 1.17, you can install `dyff` from source using `go install`: ```bash go install github.com/homeport/dyff/cmd/dyff@latest ``` _Please note:_ This will install `dyff` based on the latest available code base. Even though the goal is that the latest commit on the `main` branch should always be a stable and usable version, this is not the recommended way to install and use `dyff`. If you find an issue with this version, please make sure to note the commit SHA or date in the GitHub issue to indicate that it is not based on a released version. The version output will show `dyff version (development)` for `go install` based builds. ## Contributing We are happy to have other people contributing to the project. If you decide to do that, here's how to: - get Go (`dyff` requires Go version 1.23 or greater) - fork the project - create a new branch - make your changes - open a PR. Git commit messages should be meaningful and follow the rules nicely written down by [Chris Beams](https://chris.beams.io/posts/git-commit/): > The seven rules of a great Git commit message > > 1. Separate subject from body with a blank line > 1. Limit the subject line to 50 characters > 1. Capitalize the subject line > 1. Do not end the subject line with a period > 1. Use the imperative mood in the subject line > 1. Wrap the body at 72 characters > 1. Use the body to explain what and why vs. how ### Running test cases and binaries generation Run test cases: ```bash ginkgo run ./... ``` Create binaries: ```bash goreleaser build --clean --snapshot ``` ## License Licensed under [MIT License](https://github.com/homeport/dyff/blob/main/LICENSE)