1 Build-System
Virgil edited this page 2026-02-19 17:00:12 +00:00

Build System

Multi-language project detection, cross-compilation, and OpenAPI SDK generation.

Project Detection

The build package auto-detects project types by scanning for well-known configuration files. This allows a single build pipeline to handle diverse projects without manual configuration.

Supported Project Types

type ProjectType string

const (
    ProjectGo       ProjectType = "go"       // go.mod
    ProjectWails    ProjectType = "wails"    // wails.json
    ProjectNode     ProjectType = "node"     // package.json
    ProjectPHP      ProjectType = "php"      // composer.json
    ProjectCPP      ProjectType = "cpp"      // CMakeLists.txt
    ProjectDocker   ProjectType = "docker"   // Dockerfile
    ProjectLinuxKit ProjectType = "linuxkit" // *.yml (LinuxKit format)
    ProjectTaskfile ProjectType = "taskfile" // Taskfile.yml
)

Detection Logic

import "forge.lthn.ai/core/go-devops/build"

// Auto-detect project type from directory contents
projectType := build.Detect("./my-project")

switch projectType {
case build.ProjectGo:
    // Found go.mod — Go project
case build.ProjectNode:
    // Found package.json — Node.js project
case build.ProjectPHP:
    // Found composer.json — PHP project
}
File Detected Type
go.mod go
wails.json wails
package.json node
composer.json php
CMakeLists.txt cpp
Dockerfile docker
*.yml (LinuxKit) linuxkit
Taskfile.yml taskfile

Build Configuration

type Config struct {
    FS         fs.FS   // Filesystem (for testing/embedding)
    ProjectDir string  // Root directory of the project
    OutputDir  string  // Where to place build artefacts
    Name       string  // Binary/output name
    Version    string  // Semantic version string
    LDFlags    string  // Go linker flags (-ldflags)
    Dockerfile string  // Path to Dockerfile (for docker builds)
}

Creating a Build

cfg := build.Config{
    ProjectDir: "./my-service",
    OutputDir:  "./dist",
    Name:       "my-service",
    Version:    "1.2.0",
    LDFlags:    "-s -w -X main.version=1.2.0",
}

builder := build.New(cfg)

Cross-Compilation

The Target type represents an OS/architecture pair for cross-compilation.

type Target struct {
    OS   string // e.g. "linux", "darwin", "windows"
    Arch string // e.g. "amd64", "arm64"
}

Building for Multiple Targets

targets := []build.Target{
    {OS: "linux", Arch: "amd64"},
    {OS: "linux", Arch: "arm64"},
    {OS: "darwin", Arch: "arm64"},
    {OS: "windows", Arch: "amd64"},
}

for _, target := range targets {
    artifact, err := builder.BuildFor(ctx, target)
    if err != nil {
        log.Fatalf("build failed for %s/%s: %v", target.OS, target.Arch, err)
    }
    fmt.Printf("Built: %s (checksum: %s)\n", artifact.Path, artifact.Checksum)
}

Build Artefacts

type Artifact struct {
    Path     string // Full path to the built artefact
    OS       string // Target operating system
    Arch     string // Target architecture
    Checksum string // SHA256 checksum of the artefact
}

SDK Generation

The sdk package generates client libraries from OpenAPI 3.x specifications, with support for breaking change detection via oasdiff.

SDK Configuration

type sdk.Config struct {
    Spec      string   // Path to OpenAPI spec file
    Languages []string // Target languages for generation
    Output    string   // Output directory for generated SDKs
    Package   string   // Package/module name
    Diff      string   // Path to previous spec (for diff)
    Publish   bool     // Whether to publish generated packages
}

Supported Languages

Language Output
Go Go module with typed client
Python pip-installable package
TypeScript npm package
Ruby gem
Rust cargo crate
Java Maven package

Generating SDKs

import "forge.lthn.ai/core/go-devops/sdk"

cfg := sdk.Config{
    Spec:      "./openapi.yaml",
    Languages: []string{"go", "python", "typescript"},
    Output:    "./sdk-output",
    Package:   "myapi",
}

err := sdk.Generate(cfg)

Breaking Change Detection

Before generating SDKs, you can detect breaking changes between spec versions using oasdiff integration.

cfg := sdk.Config{
    Spec: "./openapi-v2.yaml",
    Diff: "./openapi-v1.yaml",
}

changes, err := sdk.DetectBreaking(cfg)
if err != nil {
    log.Fatal(err)
}

for _, change := range changes {
    fmt.Printf("BREAKING: %s\n", change.Description)
}

See Also