refactor: restructure build/release/sdk into pkg/ layout
Moves build/, release/, sdk/ into pkg/ following Go convention. Updates import paths in cmd/ci and cmd/sdk. Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
3a9b766eaf
commit
b2edc2d26d
107 changed files with 121 additions and 59 deletions
89
CLAUDE.md
89
CLAUDE.md
|
|
@ -1,37 +1,84 @@
|
|||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
`core/go-build` is the build system, release pipeline, and SDK generation tool. Three main packages: build (cross-compilation, archiving, signing), release (versioning, changelog, publishers), and sdk (OpenAPI diff, code generation).
|
||||
`core/go-build` is the build system, release pipeline, and SDK generation tool for the Core ecosystem. Three subsystems under `pkg/` — **build**, **release**, **sdk** — can be used as libraries or wired together via CLI commands in `cmd/`. This repo produces no standalone binary; `cmd/` packages register commands via `cli.RegisterCommands()` in `init()` functions, compiled into the `core` binary from `forge.lthn.ai/core/cli`.
|
||||
|
||||
## Build & Development
|
||||
## Build & Test
|
||||
|
||||
```bash
|
||||
go test ./...
|
||||
go build ./...
|
||||
go build ./... # compile all packages
|
||||
go test ./... # run all tests
|
||||
go test ./pkg/build/... -run TestLoadConfig_Good # single test by name
|
||||
go test -race ./... # with race detection
|
||||
```
|
||||
|
||||
**Go workspace**: this module is part of `~/Code/go.work`. Run `go work sync` after cloning. Set `GOPRIVATE=forge.lthn.ai/*` for private module fetching.
|
||||
|
||||
## Architecture
|
||||
|
||||
- `build/` — Build config (.core/build.yaml), project discovery, archiving, checksums
|
||||
- `build/builders/` — Go, Wails, Docker, LinuxKit, C++, Taskfile builders
|
||||
- `build/signing/` — Code signing (macOS notarisation, GPG)
|
||||
- `build/buildcmd/` — CLI commands for `core build`
|
||||
- `release/` — Versioning, changelog generation, release orchestration
|
||||
- `release/publishers/` — GitHub, Homebrew, Scoop, AUR, npm, Docker, Chocolatey
|
||||
- `sdk/` — OpenAPI spec diffing, SDK code generation
|
||||
- `cmd/ci/` — CI/release pipeline commands
|
||||
- `cmd/sdk/` — SDK validation commands
|
||||
The three subsystems share common types but are independent:
|
||||
|
||||
## Dependencies
|
||||
- **`pkg/build/`** — Config loading (`.core/build.yaml`), project discovery via marker files, `Builder` interface, archiving (tar.gz/zip), checksums (SHA-256)
|
||||
- **`pkg/build/builders/`** — Go, Wails, Docker, LinuxKit, C++, Taskfile builder implementations
|
||||
- **`pkg/build/signing/`** — `Signer` interface with GPG, macOS codesign/notarisation, Windows (placeholder). Credentials support `$ENV` expansion
|
||||
- **`pkg/release/`** — Version resolution from git tags, conventional-commit changelog generation, release orchestration. Two entry points: `Run()` (full pipeline) and `Publish()` (pre-built artifacts from `dist/`)
|
||||
- **`pkg/release/publishers/`** — `Publisher` interface: GitHub, Docker, npm, Homebrew, Scoop, AUR, Chocolatey, LinuxKit
|
||||
- **`pkg/sdk/`** — OpenAPI spec detection, breaking-change diff via oasdiff, SDK code generation
|
||||
- **`pkg/sdk/generators/`** — `Generator` interface with registry. TypeScript, Python, Go, PHP generators (native tool -> npx -> Docker fallback)
|
||||
- **`cmd/build/`** — `core build` commands (build, from-path, pwa, sdk, release)
|
||||
- **`cmd/ci/`** — `core ci` commands (publish, init, changelog, version)
|
||||
- **`cmd/sdk/`** — `core sdk` commands (diff, validate)
|
||||
|
||||
- `cli` — Command registration
|
||||
- `go-io` — File utilities
|
||||
- `go-i18n` — Internationalisation
|
||||
- `go-log` — Structured logging
|
||||
- Borg — Compression
|
||||
- kin-openapi, oasdiff — OpenAPI tooling
|
||||
### Key Data Flow
|
||||
|
||||
```
|
||||
.core/build.yaml -> LoadConfig() -> BuildConfig
|
||||
project dir -> Discover() -> ProjectType -> getBuilder() -> Builder.Build() -> []Artifact
|
||||
-> SignBinaries() -> ArchiveAll() -> ChecksumAll() -> Publisher.Publish()
|
||||
```
|
||||
|
||||
### Key Interfaces
|
||||
|
||||
- `build.Builder` — `Name()`, `Detect(fs, dir)`, `Build(ctx, cfg, targets)`
|
||||
- `publishers.Publisher` — `Name()`, `Publish(ctx, release, pubCfg, relCfg, dryRun)`
|
||||
- `signing.Signer` — `Name()`, `Available()`, `Sign(ctx, fs, path)`
|
||||
- `generators.Generator` — `Language()`, `Generate(ctx, opts)`, `Available()`, `Install()`
|
||||
|
||||
### Filesystem Abstraction
|
||||
|
||||
All file operations use `io.Medium` from `forge.lthn.ai/core/go-io`. Production uses `io.Local`; tests inject mocks for isolation.
|
||||
|
||||
### Configuration Files
|
||||
|
||||
- `.core/build.yaml` — Build config (targets, flags, signing)
|
||||
- `.core/release.yaml` — Release config (publishers, changelog, SDK settings)
|
||||
|
||||
## Coding Standards
|
||||
|
||||
- UK English, strict types, testify, EUPL-1.2
|
||||
- **UK English** in comments and strings (colour, organisation, notarisation)
|
||||
- **Strict types** — all parameters and return types explicitly typed
|
||||
- **Error wrapping** — `fmt.Errorf("package.Function: message: %w", err)`
|
||||
- **testify** (`assert`/`require`) for assertions
|
||||
- **Test naming** — `_Good` (happy path), `_Bad` (expected errors), `_Ugly` (edge cases)
|
||||
- **Conventional commits** — `type(scope): description`
|
||||
- **Licence** — EUPL-1.2
|
||||
|
||||
## Extension Points
|
||||
|
||||
**New builder**: implement `build.Builder` in `pkg/build/builders/`, add to `getBuilder()` in `cmd/build/cmd_project.go` and `pkg/release/release.go`, optionally add `ProjectType` to `pkg/build/build.go` and marker to `pkg/build/discovery.go`.
|
||||
|
||||
**New publisher**: implement `publishers.Publisher` in `pkg/release/publishers/`, add to `getPublisher()` in `pkg/release/release.go`, add config fields to `PublisherConfig` in `pkg/release/config.go` and `buildExtendedConfig()`.
|
||||
|
||||
**New SDK generator**: implement `generators.Generator` in `pkg/sdk/generators/`, register in `pkg/sdk/sdk.go` `GenerateLanguage()`.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- `forge.lthn.ai/core/cli` — Command registration (`cli.RegisterCommands`, `cli.Command`)
|
||||
- `forge.lthn.ai/core/go-io` — Filesystem abstraction (`io.Medium`, `io.Local`)
|
||||
- `forge.lthn.ai/core/go-i18n` — Internationalisation (`i18n.T()`, `i18n.Label()`)
|
||||
- `forge.lthn.ai/core/go-log` — Structured logging
|
||||
- `github.com/Snider/Borg` — XZ compression for archives
|
||||
- `github.com/getkin/kin-openapi` + `github.com/oasdiff/oasdiff` — OpenAPI parsing and diff
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@ import (
|
|||
"runtime"
|
||||
"strings"
|
||||
|
||||
"forge.lthn.ai/core/go-build/build"
|
||||
"forge.lthn.ai/core/go-build/build/builders"
|
||||
"forge.lthn.ai/core/go-build/build/signing"
|
||||
"forge.lthn.ai/core/go-build/pkg/build"
|
||||
"forge.lthn.ai/core/go-build/pkg/build/builders"
|
||||
"forge.lthn.ai/core/go-build/pkg/build/signing"
|
||||
"forge.lthn.ai/core/go-i18n"
|
||||
"forge.lthn.ai/core/go-io"
|
||||
)
|
||||
|
|
@ -42,6 +42,9 @@ func runProjectBuild(ctx context.Context, buildType string, ciMode bool, targets
|
|||
var projectType build.ProjectType
|
||||
if buildType != "" {
|
||||
projectType = build.ProjectType(buildType)
|
||||
} else if buildCfg.Build.Type != "" {
|
||||
// Use type from .core/build.yaml
|
||||
projectType = build.ProjectType(buildCfg.Build.Type)
|
||||
} else {
|
||||
projectType, err = build.PrimaryType(fs, projectDir)
|
||||
if err != nil {
|
||||
|
|
@ -117,6 +120,7 @@ func runProjectBuild(ctx context.Context, buildType string, ciMode bool, targets
|
|||
Name: binaryName,
|
||||
Version: buildCfg.Project.Name, // Could be enhanced with git describe
|
||||
LDFlags: buildCfg.Build.LDFlags,
|
||||
CGO: buildCfg.Build.CGO,
|
||||
// Docker/LinuxKit specific
|
||||
Dockerfile: configPath, // Reuse for Dockerfile path
|
||||
LinuxKitConfig: configPath,
|
||||
|
|
@ -9,7 +9,7 @@ import (
|
|||
"forge.lthn.ai/core/cli/pkg/cli"
|
||||
"forge.lthn.ai/core/go-log"
|
||||
"forge.lthn.ai/core/go-i18n"
|
||||
"forge.lthn.ai/core/go-build/release"
|
||||
"forge.lthn.ai/core/go-build/pkg/release"
|
||||
)
|
||||
|
||||
// Flag variables for release command
|
||||
|
|
@ -11,7 +11,7 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
|
||||
"forge.lthn.ai/core/go-build/sdk"
|
||||
"forge.lthn.ai/core/go-build/pkg/sdk"
|
||||
"forge.lthn.ai/core/go-i18n"
|
||||
)
|
||||
|
||||
|
|
@ -9,7 +9,7 @@ import (
|
|||
|
||||
"forge.lthn.ai/core/cli/pkg/cli"
|
||||
"forge.lthn.ai/core/go-i18n"
|
||||
"forge.lthn.ai/core/go-build/release"
|
||||
"forge.lthn.ai/core/go-build/pkg/release"
|
||||
)
|
||||
|
||||
// Style aliases from shared
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
|
||||
"forge.lthn.ai/core/go-build/sdk"
|
||||
"forge.lthn.ai/core/go-build/pkg/sdk"
|
||||
"forge.lthn.ai/core/cli/pkg/cli"
|
||||
"forge.lthn.ai/core/go-i18n"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -65,6 +65,8 @@ type Config struct {
|
|||
Version string
|
||||
// LDFlags are additional linker flags.
|
||||
LDFlags []string
|
||||
// CGO enables CGO for the build (required for Wails, FrankenPHP, etc).
|
||||
CGO bool
|
||||
|
||||
// Docker-specific config
|
||||
Dockerfile string // Path to Dockerfile (default: Dockerfile)
|
||||
|
|
@ -11,7 +11,7 @@ import (
|
|||
"runtime"
|
||||
"strings"
|
||||
|
||||
"forge.lthn.ai/core/go-build/build"
|
||||
"forge.lthn.ai/core/go-build/pkg/build"
|
||||
"forge.lthn.ai/core/go-io"
|
||||
)
|
||||
|
||||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"forge.lthn.ai/core/go-build/build"
|
||||
"forge.lthn.ai/core/go-build/pkg/build"
|
||||
"forge.lthn.ai/core/go-io"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
|
@ -10,7 +10,7 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"forge.lthn.ai/core/go-build/build"
|
||||
"forge.lthn.ai/core/go-build/pkg/build"
|
||||
"forge.lthn.ai/core/go-io"
|
||||
)
|
||||
|
||||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"forge.lthn.ai/core/go-build/build"
|
||||
"forge.lthn.ai/core/go-build/pkg/build"
|
||||
"forge.lthn.ai/core/go-io"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
|
@ -10,7 +10,7 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"forge.lthn.ai/core/go-build/build"
|
||||
"forge.lthn.ai/core/go-build/pkg/build"
|
||||
"forge.lthn.ai/core/go-io"
|
||||
)
|
||||
|
||||
|
|
@ -110,7 +110,11 @@ func (b *GoBuilder) buildTarget(ctx context.Context, cfg *build.Config, target b
|
|||
env := os.Environ()
|
||||
env = append(env, fmt.Sprintf("GOOS=%s", target.OS))
|
||||
env = append(env, fmt.Sprintf("GOARCH=%s", target.Arch))
|
||||
env = append(env, "CGO_ENABLED=0") // CGO disabled by default for cross-compilation
|
||||
if cfg.CGO {
|
||||
env = append(env, "CGO_ENABLED=1")
|
||||
} else {
|
||||
env = append(env, "CGO_ENABLED=0")
|
||||
}
|
||||
cmd.Env = env
|
||||
|
||||
// Capture output for error messages
|
||||
|
|
@ -7,7 +7,7 @@ import (
|
|||
"runtime"
|
||||
"testing"
|
||||
|
||||
"forge.lthn.ai/core/go-build/build"
|
||||
"forge.lthn.ai/core/go-build/pkg/build"
|
||||
"forge.lthn.ai/core/go-io"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
|
@ -10,7 +10,7 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"forge.lthn.ai/core/go-build/build"
|
||||
"forge.lthn.ai/core/go-build/pkg/build"
|
||||
"forge.lthn.ai/core/go-io"
|
||||
)
|
||||
|
||||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"forge.lthn.ai/core/go-build/build"
|
||||
"forge.lthn.ai/core/go-build/pkg/build"
|
||||
"forge.lthn.ai/core/go-io"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
|
@ -10,7 +10,7 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"forge.lthn.ai/core/go-build/build"
|
||||
"forge.lthn.ai/core/go-build/pkg/build"
|
||||
"forge.lthn.ai/core/go-io"
|
||||
)
|
||||
|
||||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"forge.lthn.ai/core/go-build/build"
|
||||
"forge.lthn.ai/core/go-build/pkg/build"
|
||||
"forge.lthn.ai/core/go-io"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
|
@ -9,7 +9,7 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"forge.lthn.ai/core/go-build/build"
|
||||
"forge.lthn.ai/core/go-build/pkg/build"
|
||||
"forge.lthn.ai/core/go-io"
|
||||
)
|
||||
|
||||
|
|
@ -49,12 +49,15 @@ func (b *WailsBuilder) Build(ctx context.Context, cfg *build.Config, targets []b
|
|||
isV3 := b.isWailsV3(cfg.FS, cfg.ProjectDir)
|
||||
|
||||
if isV3 {
|
||||
// Wails v3 strategy: Delegate to Taskfile
|
||||
// Wails v3 strategy: Delegate to Taskfile if present, otherwise use Go builder with CGO
|
||||
taskBuilder := NewTaskfileBuilder()
|
||||
if detected, _ := taskBuilder.Detect(cfg.FS, cfg.ProjectDir); detected {
|
||||
return taskBuilder.Build(ctx, cfg, targets)
|
||||
}
|
||||
return nil, errors.New("wails v3 projects require a Taskfile for building")
|
||||
// Fall back to Go builder — Wails v3 is just a Go project that needs CGO
|
||||
cfg.CGO = true
|
||||
goBuilder := NewGoBuilder()
|
||||
return goBuilder.Build(ctx, cfg, targets)
|
||||
}
|
||||
|
||||
// Wails v2 strategy: Use 'wails build'
|
||||
|
|
@ -8,7 +8,7 @@ import (
|
|||
"runtime"
|
||||
"testing"
|
||||
|
||||
"forge.lthn.ai/core/go-build/build"
|
||||
"forge.lthn.ai/core/go-build/pkg/build"
|
||||
"forge.lthn.ai/core/go-io"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
|
@ -8,7 +8,7 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"forge.lthn.ai/core/go-build/build/signing"
|
||||
"forge.lthn.ai/core/go-build/pkg/build/signing"
|
||||
"forge.lthn.ai/core/go-io"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
|
@ -48,6 +48,8 @@ type Project struct {
|
|||
|
||||
// Build holds build-time settings.
|
||||
type Build struct {
|
||||
// Type overrides project type auto-detection (e.g., "go", "wails", "docker").
|
||||
Type string `yaml:"type"`
|
||||
// CGO enables CGO for the build.
|
||||
CGO bool `yaml:"cgo"`
|
||||
// Flags are additional build flags (e.g., ["-trimpath"]).
|
||||
|
|
@ -13,7 +13,7 @@ import (
|
|||
"strings"
|
||||
"text/template"
|
||||
|
||||
"forge.lthn.ai/core/go-build/build"
|
||||
"forge.lthn.ai/core/go-build/pkg/build"
|
||||
"forge.lthn.ai/core/go-io"
|
||||
)
|
||||
|
||||
|
|
@ -13,7 +13,7 @@ import (
|
|||
"strings"
|
||||
"text/template"
|
||||
|
||||
"forge.lthn.ai/core/go-build/build"
|
||||
"forge.lthn.ai/core/go-build/pkg/build"
|
||||
"forge.lthn.ai/core/go-i18n"
|
||||
"forge.lthn.ai/core/go-io"
|
||||
)
|
||||
|
|
@ -8,7 +8,7 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"forge.lthn.ai/core/go-build/build"
|
||||
"forge.lthn.ai/core/go-build/pkg/build"
|
||||
"forge.lthn.ai/core/go-io"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
|
@ -13,7 +13,7 @@ import (
|
|||
"strings"
|
||||
"text/template"
|
||||
|
||||
"forge.lthn.ai/core/go-build/build"
|
||||
"forge.lthn.ai/core/go-build/pkg/build"
|
||||
"forge.lthn.ai/core/go-io"
|
||||
)
|
||||
|
||||
|
|
@ -6,7 +6,7 @@ import (
|
|||
"os"
|
||||
"testing"
|
||||
|
||||
"forge.lthn.ai/core/go-build/build"
|
||||
"forge.lthn.ai/core/go-build/pkg/build"
|
||||
"forge.lthn.ai/core/go-io"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
|
@ -8,7 +8,7 @@ import (
|
|||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"forge.lthn.ai/core/go-build/build"
|
||||
"forge.lthn.ai/core/go-build/pkg/build"
|
||||
"forge.lthn.ai/core/go-io"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
|
@ -4,7 +4,7 @@ package publishers
|
|||
import (
|
||||
"context"
|
||||
|
||||
"forge.lthn.ai/core/go-build/build"
|
||||
"forge.lthn.ai/core/go-build/pkg/build"
|
||||
"forge.lthn.ai/core/go-io"
|
||||
)
|
||||
|
||||
|
|
@ -13,7 +13,7 @@ import (
|
|||
"strings"
|
||||
"text/template"
|
||||
|
||||
"forge.lthn.ai/core/go-build/build"
|
||||
"forge.lthn.ai/core/go-build/pkg/build"
|
||||
"forge.lthn.ai/core/go-io"
|
||||
)
|
||||
|
||||
|
|
@ -10,9 +10,9 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"forge.lthn.ai/core/go-build/build"
|
||||
"forge.lthn.ai/core/go-build/build/builders"
|
||||
"forge.lthn.ai/core/go-build/release/publishers"
|
||||
"forge.lthn.ai/core/go-build/pkg/build"
|
||||
"forge.lthn.ai/core/go-build/pkg/build/builders"
|
||||
"forge.lthn.ai/core/go-build/pkg/release/publishers"
|
||||
"forge.lthn.ai/core/go-io"
|
||||
)
|
||||
|
||||
|
|
@ -7,7 +7,7 @@ import (
|
|||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"forge.lthn.ai/core/go-build/build"
|
||||
"forge.lthn.ai/core/go-build/pkg/build"
|
||||
"forge.lthn.ai/core/go-io"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
|
@ -6,7 +6,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
|
||||
"forge.lthn.ai/core/go-build/sdk"
|
||||
"forge.lthn.ai/core/go-build/pkg/sdk"
|
||||
)
|
||||
|
||||
// SDKRelease holds the result of an SDK release.
|
||||
|
|
@ -6,7 +6,7 @@ import (
|
|||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"forge.lthn.ai/core/go-build/sdk/generators"
|
||||
"forge.lthn.ai/core/go-build/pkg/sdk/generators"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue