Files
go-ocds/README.md
T

3.2 KiB

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.

  • generate writes the Go types. -p defaults to the output directory's name. -o - writes to stdout. --check writes nothing and fails if the file is missing or stale, for CI: ocdsgen generate --check --strict.
  • resolve lists every extension the config pulls in, dependencies first, in the order their patches are applied.
  • schema writes 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.