go-ocds (ocdsgen)
OCDS 1.1 types for Go, with extensions chosen per package.
The module contains a generator and some ready-made profiles:
cmd/ocdsgen/ CLI entry point (Cobra)
internal/cli/ command definitions: generate, resolve, schema
internal/generator/ fetch, resolve, merge and emit (no CLI code)
profiles/core/ no extensions
profiles/eu/ EU profile
profiles/uk/ UK extension to the EU profile
profiles/findTender/ UK gov Find A Tender service profile with extensions
example/ a consumer module generating its own packages
Every generated package is self-contained: it imports only the standard library, so a package's types depend only on its own extensions.json.
Use a ready-made profile
go get git.avsdev.uk/Go/go-ocds@v1.0.0
import "git.avsdev.uk/Go/go-ocds/profiles/uk"
var r uk.Release
Generate your own packages
Give each package its own extensions.json and a directive:
//go:generate go tool ocdsgen generate -c extensions.json -o ocds_gen.go -p tenders
Pin the generator in your go.mod (Go 1.24+):
go get -tool git.avsdev.uk/Go/go-ocds/cmd/ocdsgen@v1.0.0
On older Go, add a tools.go with a blank import of
git.avsdev.uk/Go/go-ocds/cmd/ocdsgen behind //go:build tools, and use
go run git.avsdev.uk/Go/go-ocds/cmd/ocdsgen in the directive
(see example/).
Then go generate ./... and commit the generated ocds_gen.go files.
Commands
ocdsgen generate [-c extensions.json] [-o ocds_gen.go] [-p name] [--check]
ocdsgen resolve [-c extensions.json] [--json]
ocdsgen schema [-c extensions.json] [--kind release|package] [-o file]
Global flags: --strict fails on any warning, -q/--quiet hides notes and
warnings, --timeout sets the per-request HTTP timeout. Run
ocdsgen <command> --help for details.
generatewrites the Go types.-pdefaults to the output directory's name.-o -writes to stdout.--checkwrites nothing and fails if the file is missing or stale, for CI:ocdsgen generate --check --strict.resolvelists every extension the config pulls in, dependencies first, in the order their patches are applied.schemawrites the merged JSON Schema the types are generated from, for debugging a config or validating data with other tools.
Paths in a config that aren't URLs are resolved relative to the config file, so a project can keep private or vendored extensions alongside it.
Adding a profile to this module
Create profiles/<name>/ with extensions.json and a generate.go like the
existing ones, run go generate ./..., and tag a release.
Generator warnings
- two extensions give the same field different types (the later one wins);
- the same extension repo is included at two versions;
- a definition is never referenced, which usually means an extension patches
a type (e.g.
Lot) whose defining extension (e.g. Lots) isn't in the config.
Type mapping
date-time→*time.Time,integer→*int,number→*float64,boolean→*bool,["string","integer"]→ID,- objects without properties →
map[string]any, - anything ambiguous →
json.RawMessage. - All non-required fields are
omitempty.