codegen

package
v2.56.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 9, 2026 License: MIT Imports: 11 Imported by: 0

README

codegen — spec-driven CLI command generation

internal/codegen + cmd/gen-cli generate the cobra commands under pkg/cmd/**/*.auto.go from the JSON specifications in api/spec/json.

This is a Go port of the PowerShell pipeline under scripts/build-cli (New-C8yApi.ps1, New-C8yApiGoRootCommand.ps1, New-C8yApiGoCommand.ps1, New-C8yApiGoGetValueFromFlag.ps1) and implements step 1 of go-c8y-v2/docs/proposals/CLI_CODE_GENERATION.md.

internal/codegen/powershell + cmd/gen-powershell generate the PSc8y module from the same specifications: the cmdlets under tools/PSc8y/Public, the Pester tests under tools/PSc8y/Tests and the packaged module under tools/PSc8y/dist (the port of scripts/build-powershell and tools/PSc8y/tools/build.psm1).

Usage

go run ./cmd/gen-cli            # regenerate pkg/cmd/**/*.auto.go (in place)
go run ./cmd/gen-cli -check     # verify outputs are current (CI-friendly)
task generate-go-code           # same as the first command, with task deps
go test ./internal/codegen      # golden test: every spec vs committed output

go run ./cmd/gen-powershell           # regenerate + package the PSc8y module
go run ./cmd/gen-powershell -check    # verify cmdlets/tests are current
task build-powershell                 # same as the first command, with task deps
go test ./internal/codegen/powershell # golden test vs committed cmdlets/tests

Byte-exact compatibility

The port reproduces the PowerShell output byte-for-byte for all 365 generated files. That includes deliberately ported quirks — do not "fix" these without regenerating and reviewing the diff:

  • PowerShell string semantics: $true interpolates as True, property access and comparisons are case-insensitive, single-element arrays unwrap, empty StringBuilders are truthy.
  • Get-C8yGoArgs never receives $UseOption, so the shorthand-flag branches are dead code; unknown flag types yield a nil entry (no cmd.Flags() line) while their body setter is still emitted.
  • The || fallback in the Cumulocity query builder ($Properties.property || $Properties.name) never falls back in PowerShell 7 (an expression pipeline "succeeds" even when it yields $null), so only property is emitted.
  • Formatting parity comes from running the same formatters as the build scripts: go/format (gofmt) for root commands and golang.org/x/tools/imports (goimports) for subcommands, which also resolves the conditionally-needed pkg/c8ydata import.

The PSc8y generator reproduces all committed cmdlets and tests byte-for-byte as well, including these ported quirks:

  • The -replace operator uses .NET substitution semantics on the replacement string: a test command containing $_ expands to the entire template (see Get-BulkOperationOperationCollection.auto.Tests.ps1), which dotnetReplace reproduces.
  • Commands sharing a alias.powershell name overwrite each other; the last command of a specification wins (e.g. Remove-SoftwareVersion).
  • The skipTest flag of the last example applies to all test cases of a command, and stale files from removed commands are never deleted (only deprecated commands remove their files).
  • Function lists and .psm1 regions are ordered like Get-ChildItem sorts file names: case-insensitively.
  • One intentional deviation: the dist PSc8y.psd1 is version-stamped by substitution instead of Update-ModuleManifest, keeping the source formatting (the original rewrites the whole manifest). The result is semantically equivalent (verified with Import-PowerShellDataFile / Test-ModuleManifest), including the CmdletsToExport = @() and DefaultCommandPrefix normalizations.

Roadmap (from CLI_CODE_GENERATION.md) — status

  1. Port the generator to Go — ✅ done (this package).
  2. v2-service emitter — ❌ superseded. go-c8y-v2 has since adopted its own spec-driven generation (tools/c8ygen, see go-c8y-v2/docs/API_GEN.md): Layer 0 (zz_generated_*.go option structs, paths, enums, façade models) is generated from the OpenAPI spec + overlay, and the ergonomic service layer is deliberately hand-written, with a gating CI drift check. Emitting v2 services from the CLI spec would duplicate and conflict with that architecture. What remains useful from this step is vendoring/diffing: the CLI spec can be diffed against the OAS to find missing flags/endpoints.
  3. Thin-command emitter (CLI commands calling v2 services + the pkg/c8y/output streaming pipeline, ~40 lines per command instead of ~200) — pending, with prerequisites:
    • A v2 api.Client in the CLI cmdutil.Factory (session config → api.ClientOptions{BaseURL, Auth}); today only login and the output packages use the v2 module. This belongs to the feat/v2-output-streaming integration track.
    • A hand-written reference command (e.g. operations list) proving the flag-parsing → ListOptions → ListAll iterator → output.Render shape end-to-end, including dry-run and the commander test suite. The emitter should only be written once that reference exists (the same prove-the-seam order tools/c8ygen used for its alarms pilot).
    • Migration is then group-by-group, with old and new command styles coexisting behind the same root command (the jsonfilter fallback pattern).

Documentation

Overview

Package codegen generates the cobra CLI commands from the api/spec/json specifications. It is a port of the PowerShell scripts under scripts/build-cli and reproduces their output byte-for-byte.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GenerateCommand

func GenerateCommand(spec *Value, parentName string) (fileName string, src []byte)

GenerateCommand ports New-C8yApiGoCommand.ps1: it renders the unformatted source of one <alias>.auto.go subcommand file. parentName is the parent group package name (lowercased, dashes replaced).

func GenerateRootCommand

func GenerateRootCommand(spec *Value) (fileName string, src []byte)

GenerateRootCommand ports New-C8yApiGoRootCommand.ps1: it renders the unformatted source of the <group>.auto.go root command file that registers all subcommands of a group.

func GenerateSpec

func GenerateSpec(data []byte, outputDir string) ([]GeneratedFile, []Warning, error)

GenerateSpec generates all output files for one specification document. The returned list is empty when the spec is skipped. Formatting matches the PowerShell pipeline: root commands are gofmt-ed, subcommands run through goimports (which also removes the unused imports of the template).

func GenerateSpecFile

func GenerateSpecFile(specPath string, outputDir string) ([]GeneratedFile, []Warning, error)

GenerateSpecFile generates all output files for one specification file.

func ListSpecFiles

func ListSpecFiles(specDir string) ([]string, error)

ListSpecFiles returns the json specification files of a directory in name order.

Types

type GeneratedFile

type GeneratedFile struct {
	// RelPath is the file path relative to the output directory (pkg/cmd),
	// e.g. "alarms/list/list.auto.go".
	RelPath string
	// Source is the formatted Go source.
	Source []byte
}

GeneratedFile is one formatted output file of a specification.

type Kind

type Kind byte

Kind enumerates the JSON value kinds tracked by Value.

const (
	KindNull Kind = iota
	KindObject
	KindArray
	KindString
	KindNumber
	KindBool
)

JSON value kinds

type Value

type Value struct {
	// contains filtered or unexported fields
}

Value is an ordered, loosely typed JSON value. It mirrors how PowerShell's ConvertFrom-Json exposes the specification data: object keys keep their document order and member access is case-insensitive.

func ParseJSON

func ParseJSON(data []byte) (*Value, error)

ParseJSON decodes data into a Value preserving object key order.

func (*Value) Get

func (v *Value) Get(key string) *Value

Get returns the named member of an object (case-insensitive, like PowerShell property access). Returns nil when missing or when v is not an object. Safe to call on a nil receiver.

func (*Value) IsNull

func (v *Value) IsNull() bool

IsNull reports whether the value is missing or JSON null.

func (*Value) Items

func (v *Value) Items() []*Value

Items coerces the value to an array the way PowerShell's [array] cast does: nil stays empty, arrays return their elements and scalars become a single-element array.

func (*Value) Keys

func (v *Value) Keys() []string

Keys returns the object keys in document order.

func (*Value) Str

func (v *Value) Str() string

Str renders the value the way PowerShell string interpolation does: null -> "", bool -> True/False, numbers use their literal form.

func (*Value) StrEquals

func (v *Value) StrEquals(other string) bool

StrEquals reports a case-insensitive string comparison like PowerShell -eq.

func (*Value) Truthy

func (v *Value) Truthy() bool

Truthy reports the PowerShell boolean conversion of the value.

type Warning

type Warning struct {
	Spec    string
	Message string
}

Warning describes a non-fatal generation finding (mirrors the PowerShell Write-Warning messages that matter).

Directories

Path Synopsis
Package powershell generates the PSc8y PowerShell module cmdlets and Pester tests from the api/spec/json specifications and packages the module.
Package powershell generates the PSc8y PowerShell module cmdlets and Pester tests from the api/spec/json specifications and packages the module.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL