Getting started

Requirements

You need Go 1.26 or newer. That is the go line of this module. Generated code imports the pkg/runtime package of this module. So your module requires it too, and gets the same minimum.

Install

Add the CLI as a tool of your module:

go get -tool github.com/mockzilla/mockzilla-codegen/cmd/mockzilla-codegen

This adds a tool line and a require line to your go.mod. go tool mockzilla-codegen then runs the version your module pins. That is also the version of the runtime package your generated code imports, so the two always match.

You can also install the binary on your PATH:

go install github.com/mockzilla/mockzilla-codegen/cmd/mockzilla-codegen@latest

Then keep it at the version your go.mod requires. When they differ, the generated code fails to compile (see Runtime guard).

First run

A spec is enough:

go tool mockzilla-codegen generate openapi.yaml

With no codegen.yaml in the current folder, you get the defaults. The models of the spec go to ./gen.go, in a package named after the folder.

More with flags

Flags turn on more:

go tool mockzilla-codegen generate openapi.yaml -server chi -client -o ./api/gen.go

A config file

For anything else, put the spec and a config next to each other:

# codegen.yaml
spec:
  path: ./openapi.yaml
output:
  file: ./api/gen.go

Then generate:

go tool mockzilla-codegen generate

This writes api/gen.go in package api. Paths in the config are relative to the config file. Configuration lists every key.

From go generate

To run it from go generate, add this line to any Go file of the package:

//go:generate go tool mockzilla-codegen generate -c ../codegen.yaml

Commands

mockzilla-codegen generate [-c codegen.yaml] [-dry-run | -check] [-strict] [-v] [flags] [spec]

Flag Meaning
-c Config file. Without it, codegen.yaml in the current folder when it exists, else the defaults.
-dry-run Print every file, its package, its parts and whether it would be written. Write nothing.
-check Write nothing. Exit 1 and list the generated files that are missing or differ from a new run.
-strict Exit 1 on a warning too, not only on an error.
-v Also print info diagnostics, and the table of files written.
-server <framework> Generate a server for the framework. Replaces server.framework of the config.
-client, -mcp Generate a client, or MCP tools, which need a client.
-no-server, -no-client, -no-mcp Leave that part out, whatever the config says.
-o <file> Replaces output.file, relative to the current folder.
-package <name> Replaces package.
spec A spec file or URL that replaces spec.path, relative to the current folder.

Flags and the config

  • A flag wins over the config: generate -no-client skips the client a config has.
  • A part turned on by a flag gets the defaults of its block.
  • Flags may come before or after the spec.

Diagnostics

Warnings and errors about the spec go to stderr on every run. Info goes there only with -v. The files are written either way.

Other commands

  • mockzilla-codegen schema prints the JSON schema of the config file.
  • mockzilla-codegen version prints the version.

Exit codes

Code Meaning
0 success
1 a failure, an error printed (a warning too with -strict), or stale files with -check
2 wrong usage

generate -dry-run -strict checks a spec in CI without writing anything.

Inside another program

Package pkg/cli is this command line. A Go program can offer it as one of its own commands. Name is what usage and messages call the program. If the generate command of your program runs the generator, pass its arguments as they are:

code := (&cli.Command{Name: "mytool", Stdout: os.Stdout, Stderr: os.Stderr}).Run(ctx, os.Args[1:])

mytool generate -c codegen.yaml then takes the same flags as mockzilla-codegen generate.

Check in CI

go tool mockzilla-codegen generate -check

It fails when:

  • someone changed the spec or the config without generating again
  • someone edited a generated file

Scaffold files are not checked. They are yours once written.

Generated files

Every file starts with // Code generated by mockzilla-codegen. DO NOT EDIT. Go tools look for this line to treat a file as generated. The header key replaces it. A custom header should keep such a line.

Every file the config names is written on every run, even when its parts hold nothing. So the set of files depends only on the config, and a type the spec dropped cannot stay behind in an old file.

Runtime guard

A generated file that imports the runtime package, or one of the packages beside it, has this line:

const _ = runtime.SupportsGeneratorV1

Each release of mockzilla-codegen writes code for one level of the runtime API. The runtime declares the levels it supports.

When the runtime your module requires does not support the level of the code, the build stops on this line with undefined: runtime.SupportsGeneratorV1. To fix it, do one of these:

  • Generate again with the version your go.mod requires.
  • Update the requirement to the version that generated the code.

With go tool, both come from the same line of go.mod, so this does not happen.