From 9dac7cc16d50549c21e178bda66f080f840db593 Mon Sep 17 00:00:00 2001 From: Terastar-Paperclip Date: Tue, 19 May 2026 07:35:51 -0400 Subject: [PATCH] feat(compat): adopt quantcli/common/compat/formats as second consumer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wires liftoff-export-cli into the cross-CLI compat suite for §4 (--format) of CONTRACT.md, mirroring crono's machine-attestation pattern. - compat_contract_test.go (build tag: compat) runs compat/formats.RunContract against the built binary via LIFTOFF_EXPORT_BIN. - New CI job builds the binary, runs `go mod tidy`, then `go test -tags=compat -run TestContractFormats ./...`. - Existing `go vet + test` job kept untouched. - Subcommands list targets the four data-producing leaves that take --format without a required positional: `workouts list`, `workouts stats`, `bodyweights list`, `bodyweights stats`. Excludes `workouts show` because its mandatory positional would conflate "missing arg" with "bad format" in parse-level subtests. - SkipDataPath: true — liftoff's data path needs a stored OAuth token at ~/.config/liftoff-export/auth.json which CI does not provision; parse-level subtests still attest the §4 surface. - SupportedFormats: [markdown, json] — CSV is not yet wired, so CSVHasHeader skips with a named reason rather than failing. - go.mod pinned to merged-main pseudo-version v0.0.0-…-de9219e03369 (PR #12 nested-subcommand support + PR #14 SkipDataPath). Closes liftoff side of [QUA-16](/QUA/issues/QUA-16). Follows the crono pattern landed in [QUA-14](/QUA/issues/QUA-14). Co-Authored-By: Paperclip --- .github/workflows/ci.yml | 47 ++++++++++++++++++++++++++++++ compat_contract_test.go | 63 ++++++++++++++++++++++++++++++++++++++++ go.mod | 5 +++- go.sum | 2 ++ 4 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/ci.yml create mode 100644 compat_contract_test.go diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..8779909 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,47 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +permissions: + contents: read + +jobs: + go: + name: go vet + test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + - name: go vet + run: go vet ./... + - name: go test + run: go test ./... + + compat: + name: compat (CONTRACT machine-attestation) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + - name: resolve compat dependency + # The compat module lives at github.com/quantcli/common/compat + # under a subpath. `go mod tidy` materializes go.sum for it on + # first run; subsequent runs are cache-served. + run: go mod tidy + - name: build liftoff-export + run: go build -o /tmp/liftoff-export . + - name: run compat suite + env: + # Path the compat-tagged test reads from os.Getenv. + LIFTOFF_EXPORT_BIN: /tmp/liftoff-export + run: go test -tags=compat -run TestContractFormats ./... diff --git a/compat_contract_test.go b/compat_contract_test.go new file mode 100644 index 0000000..6d00ba1 --- /dev/null +++ b/compat_contract_test.go @@ -0,0 +1,63 @@ +//go:build compat + +// Compat-test entry point for liftoff-export-cli. +// +// This file is only compiled under the `compat` build tag, so it does +// not affect the default `go test ./...` run. CI invokes it as +// `go test -tags=compat ./...` after building the export binary and +// exposing its path through LIFTOFF_EXPORT_BIN. +// +// The actual assertions live in github.com/quantcli/common/compat. +// Drift between this CLI and CONTRACT.md surfaces as a failure here. +package main_test + +import ( + "os" + "testing" + + "github.com/quantcli/common/compat" + "github.com/quantcli/common/compat/formats" +) + +// liftoffFormatSubcommands is the §4 surface for liftoff — each +// data-producing leaf owns its own --format flag under a two-level +// cobra path (parent group + leaf). The compat Runner splits on +// whitespace so cobra sees separate argv entries (added in +// quantcli/common PR #12). +// +// `workouts show` is intentionally excluded: it requires a positional +// argument, so the parse-level subtests would fail on missing +// args rather than the --format flag itself. The four leaves below +// take --format with no required positional and exercise the §4 +// surface cleanly. +var liftoffFormatSubcommands = []string{ + "workouts list", + "workouts stats", + "bodyweights list", + "bodyweights stats", +} + +func TestContractFormats(t *testing.T) { + bin := os.Getenv("LIFTOFF_EXPORT_BIN") + if bin == "" { + t.Skip("LIFTOFF_EXPORT_BIN not set; skipping compat suite") + } + // liftoff implements --format markdown (default) and --format json + // today; CSV is not yet wired. SupportedFormats: ["markdown","json"] + // skips CSVHasHeader with a named reason rather than failing it. + // + // SkipDataPath: true opts out of JSONIsArray / CSVHasHeader / + // DefaultIsMarkdown — liftoff's data path requires a stored OAuth + // token at ~/.config/liftoff-export/auth.json which the compat CI + // job does not provision, so a clean `--format json` run exits + // non-zero with "not logged in" before the JSON-array assertion + // could run. The parse-level subtests (HelpDocumentsFormatFlag, + // UnknownFormatFails, FlagValidationIsHermetic) still attest the + // §4 surface. + formats.RunContract(t, compat.Runner{ + Binary: bin, + Subcommands: liftoffFormatSubcommands, + SupportedFormats: []string{"markdown", "json"}, + SkipDataPath: true, + }) +} diff --git a/go.mod b/go.mod index 7eec5e9..e2efc83 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,10 @@ module github.com/quantcli/liftoff-export-cli go 1.25.10 -require github.com/spf13/cobra v1.10.2 +require ( + github.com/quantcli/common/compat v0.0.0-20260519113336-de9219e03369 + github.com/spf13/cobra v1.10.2 +) require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect diff --git a/go.sum b/go.sum index a6ee3e0..7b3afba 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/quantcli/common/compat v0.0.0-20260519113336-de9219e03369 h1:Ph45Q92vEk4rpcR/NGH/j0oBM9pin2Dk8Rh+Q2mhj3k= +github.com/quantcli/common/compat v0.0.0-20260519113336-de9219e03369/go.mod h1:VBC/zEphSZgCZS1rhWsR3A8EWYSbTkP/MwqWHL7266s= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=