Skip to content

cmd: add generic command builder (PRINFRA-121) - #10

Merged
somanshreddy merged 1 commit into
mainfrom
03-31-cmd_add_generic_command_builder_for_generated_specs
Mar 31, 2026
Merged

somanshreddy merged 1 commit into
mainfrom
03-31-cmd_add_generic_command_builder_for_generated_specs

Conversation

@somanshreddy

@somanshreddy somanshreddy commented Mar 31, 2026 •

Copy link
Copy Markdown
Collaborator

Description

Adds the generic command builder — the bridge between generated Specs (pure data) and the Cobra command tree.

The problem: Codegen produces command.Spec structs — endpoint, method, flags, args. Cobra needs *cobra.Command objects with RunE functions, registered flags, and arg validators. Something needs to convert one to the other. That's what buildCobraCommand does.

What it does for every generated command:

  1. Creates a Cobra command with Use, Short, Long, Example derived from the Spec
  2. Registers typed flags — dispatches by FlagSpec.Type: --limit becomes IntVar, --title becomes StringVar, --draft becomes BoolVar, --events becomes StringSliceVar. Defaults, required flags, and enum help text all handled automatically.
  3. Adds -d/--data flag for commands with BodyEncoding: "json" — the escape hatch for complex request bodies (discriminated unions, nested objects). Accepts inline JSON, a file path, or - for stdin. Named to match curl and Stripe CLI conventions.
  4. Sets positional arg validation — cobra.ExactArgs(len(spec.Args)) ensures the right number of positional args
  5. Wires RunE — when the user runs the command:
    • Parses -d input if provided (inline JSON, file, or stdin via readData)
    • Calls spec.BuildInvocation() to resolve flags + args into an Invocation (with merge order: -d base → positional args → flags overlay)
    • Calls client.Execute(spec, inv) to send the HTTP request
    • Calls formatter.Data(result) to write JSON to stdout

Why this matters: This is what makes "generated commands are data, not logic" work. All 40 generated commands go through this same function. No per-command code. Add a new endpoint to the OpenAPI spec, run make generate, and it works — because the builder handles everything generically.

Also in this PR: newRootCmdWithSpecs — a test helper that builds a full Cobra tree from Specs instead of hand-written commands. This enables integration tests that prove the builder produces identical behavior to the M0 hand-written video list command.

Testing

6 integration tests using httptest mocks:

  • Video list via Spec (verifies parity with hand-written command)
  • Query flag forwarding (limit, folder-id, token)
  • POST with body flags (webhook create with url + entity-id)
  • Path param substitution (video get with video-id)
  • Bodyless POST sends no request body (avatar create)
  • Enum validation returns exit code 2 (voice list with invalid --type)

Files

  • cmd/heygen/builder.go — buildCobraCommand, registerFlag, readData, buildUseLine
  • cmd/heygen/builder_test.go — 6 integration tests with httptest
  • cmd/heygen/root.go — added newRootCmdWithSpecs for test support

somanshreddy commented Mar 31, 2026 •

Copy link
Copy Markdown
Collaborator Author

@linear

linear Bot commented Mar 31, 2026

Copy link
Copy Markdown
PRINFRA-121 CLI M1: OpenAPI codegen pipeline

Build the code generation pipeline that reads openapi/external-api.json and produces CommandSpec structs.

Scope

  • Go program in codegen/ using text/template
  • Parse OpenAPI spec, filter to v3 endpoints only
  • Generate CommandSpec data structs in gen/ (zero logic)
  • overrides.yaml for:
    • Positional arg promotion (prompt, text, file)
    • Command group naming (video-translations → translate, webhooks/endpoints → webhook)
    • Help examples per command
  • make generate SPEC=... target
  • Nested path collapsing (e.g., /webhooks/endpoints/{id}/rotate-secret → webhook rotate-secret)
  • Golden file tests for codegen output stability
  • Generate all ~30 commands, wire into Cobra at startup

Mapping Rules

  • OpenAPI tag → command group
  • POST → create, GET (list) → list, GET (by id) → get, DELETE → delete, PATCH → update
  • Path params → positional args, query params → flags, body fields → flags
  • overrides.yaml exceptions for positional promotion and group naming

Acceptance Criteria

  • make generate produces compilable CommandSpec files for all v3 endpoints
  • Adding a new endpoint to spec + re-running codegen produces new command
  • Generated help text includes descriptions and examples
  • Golden file tests pass
  • Override validation: make generate fails if overrides reference non-existent endpoints

@somanshreddy
somanshreddy force-pushed the 03-31-cmd_add_generic_command_builder_for_generated_specs branch from 038909b to 1c8298f Compare March 31, 2026 21:06
@somanshreddy
somanshreddy force-pushed the 03-31-client_refactor_executor_to_use_command.spec_command.invocation branch from 691cf11 to 8116acf Compare March 31, 2026 21:06
@somanshreddy
somanshreddy force-pushed the 03-31-cmd_add_generic_command_builder_for_generated_specs branch from 1c8298f to d9d1b26 Compare March 31, 2026 21:25
@somanshreddy
somanshreddy force-pushed the 03-31-client_refactor_executor_to_use_command.spec_command.invocation branch 2 times, most recently from 6d230d5 to 6dd7748 Compare March 31, 2026 21:55
@somanshreddy
somanshreddy force-pushed the 03-31-cmd_add_generic_command_builder_for_generated_specs branch from d9d1b26 to 6cdb863 Compare March 31, 2026 21:55
@somanshreddy
somanshreddy marked this pull request as ready for review March 31, 2026 22:01
@somanshreddy
somanshreddy force-pushed the 03-31-cmd_add_generic_command_builder_for_generated_specs branch from 6cdb863 to 8ff960a Compare March 31, 2026 22:02
@somanshreddy
somanshreddy requested a review from jrusso1020 March 31, 2026 22:07
Comment thread cmd/heygen/root.go Outdated
Comment thread cmd/heygen/root.go Outdated
@somanshreddy
somanshreddy force-pushed the 03-31-cmd_add_generic_command_builder_for_generated_specs branch from 8ff960a to 836b5d0 Compare March 31, 2026 22:34

somanshreddy commented Mar 31, 2026 •

Copy link
Copy Markdown
Collaborator Author

Merge activity

  • Mar 31, 10:38 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Mar 31, 10:42 PM UTC: Graphite rebased this pull request as part of a merge.
  • Mar 31, 10:44 PM UTC: @somanshreddy merged this pull request with Graphite.

@somanshreddy
somanshreddy changed the base branch from 03-31-client_refactor_executor_to_use_command.spec_command.invocation to graphite-base/10 March 31, 2026 22:39
@somanshreddy
somanshreddy changed the base branch from graphite-base/10 to main March 31, 2026 22:41
buildGenCommand converts a command.Spec into a Cobra command: registers
typed flags, adds --json-body for JSON body endpoints, validates enums
and min/max, builds Invocation from parsed flags/args. Also adds
newRootCmdWithSpecs for testing spec-based command registration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@somanshreddy
somanshreddy force-pushed the 03-31-cmd_add_generic_command_builder_for_generated_specs branch from 836b5d0 to d9adbc8 Compare March 31, 2026 22:42
@somanshreddy
somanshreddy merged commit 4725ce1 into main Mar 31, 2026
9 checks passed
@somanshreddy
somanshreddy deleted the 03-31-cmd_add_generic_command_builder_for_generated_specs branch March 31, 2026 22:44
@somanshreddy somanshreddy added this to the M1: Codegen Pipeline milestone Apr 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants