--version goes to stderr and the Docker image always reports "dev" #15

Closed
opened 2026-08-09 03:45:59 +02:00 by clawbot · 3 comments
Collaborator

main.go:37 declares Version and main.go:44 wires it into cobra, so -X main.Version=... does work from a local make build. Two things are still wrong.

The version string goes to stderr. main.go:54-55 routes cobra's output and error writers to os.Stderr, which is right for help and usage, but it also sends sfdupes --version there. A version string is the most machine-read output a CLI has; scripts expect it on stdout. README §Design goal 4 says everything on stdout is machine-readable data, which a version string is.

The shipped image can never report a real version. .dockerignore:1 excludes .git, so VERSION := $(shell git describe --tags --always --dirty ...) (Makefile:6) falls back to dev inside the container built at Dockerfile:52. docker run sfdupes --version therefore prints dev for every image ever built, including release images.

Also undocumented: README §Subcommands says "Three subcommands, all implemented" and the usage block lists only the three; neither --version nor -h/--help appears anywhere, nor which stream they use.

Definition of done

  1. sfdupes --version prints one line, sfdupes VERSION, to stdout, and exits 0. Help and usage stay on stderr.
  2. The Dockerfile takes ARG VERSION=dev and passes it through to the build ldflags, and script/docker supplies --build-arg VERSION=$(git describe --tags --always --dirty) so a locally built image reports the real tag. Do not un-exclude .git from .dockerignore.
  3. Per the Go styleguide the build embeds the version only — never build time or build user, which would make the image non-reproducible.
  4. README documents --version and --help, their output streams and their exit codes.
  5. Tests assert the version line goes to stdout, that stderr is empty for --version, and that the exit code is 0.
  6. make check green and make docker succeeds; docker run --rm sfdupes --version prints a real version rather than dev.
`main.go:37` declares `Version` and `main.go:44` wires it into cobra, so `-X main.Version=...` does work from a local `make build`. Two things are still wrong. **The version string goes to stderr.** `main.go:54-55` routes cobra's output and error writers to `os.Stderr`, which is right for help and usage, but it also sends `sfdupes --version` there. A version string is the most machine-read output a CLI has; scripts expect it on stdout. README §Design goal 4 says everything on stdout is machine-readable data, which a version string is. **The shipped image can never report a real version.** `.dockerignore:1` excludes `.git`, so `VERSION := $(shell git describe --tags --always --dirty ...)` (`Makefile:6`) falls back to `dev` inside the container built at `Dockerfile:52`. `docker run sfdupes --version` therefore prints `dev` for every image ever built, including release images. Also undocumented: README §Subcommands says "Three subcommands, all implemented" and the usage block lists only the three; neither `--version` nor `-h`/`--help` appears anywhere, nor which stream they use. ## Definition of done 1. `sfdupes --version` prints one line, `sfdupes VERSION`, to **stdout**, and exits 0. Help and usage stay on stderr. 2. The Dockerfile takes `ARG VERSION=dev` and passes it through to the build ldflags, and `script/docker` supplies `--build-arg VERSION=$(git describe --tags --always --dirty)` so a locally built image reports the real tag. Do not un-exclude `.git` from `.dockerignore`. 3. Per the Go styleguide the build embeds the version only — never build time or build user, which would make the image non-reproducible. 4. README documents `--version` and `--help`, their output streams and their exit codes. 5. Tests assert the version line goes to stdout, that stderr is empty for `--version`, and that the exit code is 0. 6. `make check` green and `make docker` succeeds; `docker run --rm sfdupes --version` prints a real version rather than `dev`.
clawbot added this to the 1.0.0 milestone 2026-08-09 03:45:59 +02:00
Author
Collaborator

The Docker image reporting dev moves to #67, under the owner's new rule that docker build . stamps the git tag or short commit (sneak/project-management#21). This issue keeps the --version output going to stderr.

Model: opus-5-5

The Docker image reporting `dev` moves to https://git.eeqj.de/sneak/sfdupes/issues/67, under the owner's new rule that `docker build .` stamps the git tag or short commit (https://git.eeqj.de/sneak/project-management/issues/21). This issue keeps the `--version` output going to stderr. Model: opus-5-5
Author
Collaborator

Plan (implementer's brief). The Docker half moved to #67 and is on next; this unit is items 1, 3, 4 and 5: --version output on stdout.

  • sfdupes --version prints sfdupes VERSION and a newline to stdout, nothing on stderr, exit 0. Help and usage stay on stderr. Today cobra prints the version through the command's output writer, which is set to stderr for help; find the plainest way to send only the version to stdout and say in the PR which you chose.
  • README.md documents --version and -h/--help: what each prints, on which stream, and the exit code.
  • Tests per the definition of done. If run needs a stdout writer to test this, add the parameter rather than swapping os.Stdout.

#30 may also touch run in main.go; whichever lands second rebases.

Model: opus-5-5

Plan (implementer's brief). The Docker half moved to https://git.eeqj.de/sneak/sfdupes/issues/67 and is on `next`; this unit is items 1, 3, 4 and 5: `--version` output on stdout. - `sfdupes --version` prints `sfdupes VERSION` and a newline to stdout, nothing on stderr, exit 0. Help and usage stay on stderr. Today cobra prints the version through the command's output writer, which is set to stderr for help; find the plainest way to send only the version to stdout and say in the PR which you chose. - `README.md` documents `--version` and `-h`/`--help`: what each prints, on which stream, and the exit code. - Tests per the definition of done. If `run` needs a stdout writer to test this, add the parameter rather than swapping `os.Stdout`. https://git.eeqj.de/sneak/sfdupes/issues/30 may also touch `run` in `main.go`; whichever lands second rebases. Model: opus-5-5
clawbot self-assigned this 2026-10-03 14:11:15 +02:00
Author
Collaborator

Built in #78: the root command defines its own -v/--version flag, which prints sfdupes VERSION to stdout, in place of cobra's, which printed to stderr. README documents --version and --help, their streams and exit codes.

Model: opus-5-5

Built in https://git.eeqj.de/sneak/sfdupes/pulls/78: the root command defines its own `-v`/`--version` flag, which prints `sfdupes VERSION` to stdout, in place of cobra's, which printed to stderr. README documents `--version` and `--help`, their streams and exit codes. Model: opus-5-5
Sign in to join this conversation.