Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions cli/cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,31 @@ func TestVersion(t *testing.T) {
runNoServer(t, "version").wantCode(t, 0).wantOut(t, "ccrawl")
}

// The version line is six facts glued into a sentence, and a CI job that wants
// one of them should not have to write a regular expression for it. Asking for
// a format gets the same six as data.
func TestVersionRendersAsData(t *testing.T) {
r := runNoServer(t, "version", "-o", "jsonl").wantCode(t, 0)
var got map[string]any
if err := json.Unmarshal([]byte(strings.TrimSpace(r.Out)), &got); err != nil {
t.Fatalf("-o jsonl is not JSON: %v\n%s", err, r.Out)
}
for _, k := range []string{"version", "commit", "built", "os", "arch", "go"} {
if _, ok := got[k]; !ok {
t.Errorf("no %q field: %v", k, got)
}
}
runNoServer(t, "version", "-o", "csv").wantCode(t, 0).wantOut(t, "version,commit,built,os,arch,go")

// auto keeps the sentence, in a pipe as well as on a terminal, because that
// is what ccrawl version has always printed and what anything grepping it
// expects. A test run is a pipe, so this is the case that would break.
runNoServer(t, "version").wantCode(t, 0).
wantOut(t, "ccrawl").
wantNotOut(t, `"version"`)
runNoServer(t, "version", "--short").wantCode(t, 0).wantNotOut(t, "commit")
}

// An unknown command and an unknown flag exit 1, not the 2 that means a usage
// error, because the argument parser rejects them before ccrawl sees anything.
// The reference says so under Caveat in docs/content/reference/exit-codes.md,
Expand Down
32 changes: 28 additions & 4 deletions cli/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ func newVersionCmd() kit.Command {
return kit.Command{
Use: "version",
Short: "Print version information",
Long: `Print the version, the commit it was built from, when it was built, and the platform and Go toolchain behind it.

The default is the one-line form people read. -o renders the same six fields as data, for a CI job that wants one of them without a regular expression:

ccrawl version -o json | jq -r .commit`,
Flags: v.flags,
Run: v.run,
}
Expand All @@ -27,12 +32,31 @@ func (v *versionCmd) flags(f *kit.FlagSet) {
f.BoolVar(&v.short, "short", false, "print just the version number")
}

func (v *versionCmd) run(_ context.Context, _ []string) error {
func (v *versionCmd) run(ctx context.Context, _ []string) error {
if v.short {
_, _ = fmt.Fprintln(cmdOut, Version)
return nil
}
_, _ = fmt.Fprintf(cmdOut, "ccrawl %s (commit %s, built %s, %s/%s, %s)\n",
Version, Commit, Date, runtime.GOOS, runtime.GOARCH, runtime.Version())
return nil
// auto stays the sentence, on a terminal and in a pipe alike. Everywhere
// else auto means "a table for a person, JSON Lines for a pipe", but this
// line is what `ccrawl version` has always printed and what a script that
// greps it expects, and changing that to help a script that does not exist
// yet is the wrong trade. Asking for a format is how you say you want data.
if st := kit.FromContext(ctx); st == nil || st.Output.Format == "" || st.Output.Format == "auto" {
_, _ = fmt.Fprintf(cmdOut, "ccrawl %s (commit %s, built %s, %s/%s, %s)\n",
Version, Commit, Date, runtime.GOOS, runtime.GOARCH, runtime.Version())
return nil
}

app := appFromCtx(ctx)
cols := []string{"version", "commit", "built", "os", "arch", "go"}
vals := []string{Version, Commit, Date, runtime.GOOS, runtime.GOARCH, runtime.Version()}
value := map[string]any{}
for i, c := range cols {
value[c] = vals[i]
}
if err := app.Out.Emit(Row{Cols: cols, Vals: vals, Value: value}); err != nil {
return err
}
return app.Out.Flush()
}
16 changes: 16 additions & 0 deletions docs/content/reference/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -1078,6 +1078,22 @@ The global flags apply, so `-c`, `--data-dir`, and `--no-cache` all set the serv

---

## version

```sh
ccrawl version # the one-line form
ccrawl version --short # just the version number
ccrawl version -o json # the same six fields as data
```

The default line is six facts glued into a sentence: `ccrawl 0.10.1 (commit 664360e, built 2026-08-13, darwin/arm64, go1.26.5)`. Pass `-o` and you get them separately, which is what a CI job wants when it needs one of them and would otherwise write a regular expression:

```bash
ccrawl version -o json | jq -r .commit
```

`-o auto`, which is the default, keeps the sentence whether the output is a terminal or a pipe. Every other command switches to JSONL when piped; this one does not, because that line is what `ccrawl version` has always printed and asking for a format is how you say you want data instead.

## config

```sh
Expand Down
Loading