diff --git a/cmd/build/cmd_build.go b/cmd/build/cmd_build.go index 100f7f3..10ccabd 100644 --- a/cmd/build/cmd_build.go +++ b/cmd/build/cmd_build.go @@ -140,7 +140,8 @@ func initBuildFlags() { } // AddBuildCommands registers the 'build' command and all subcommands. -// Usage example: call buildcmd.AddBuildCommands(...) from integrating code. +// +// buildcmd.AddBuildCommands(root) func AddBuildCommands(root *cli.Command) { setBuildI18n() initBuildFlags() diff --git a/cmd/build/cmd_release.go b/cmd/build/cmd_release.go index bef9738..c381e59 100644 --- a/cmd/build/cmd_release.go +++ b/cmd/build/cmd_release.go @@ -40,7 +40,8 @@ func initReleaseFlags() { } // AddReleaseCommand adds the release subcommand to the build command. -// Usage example: call buildcmd.AddReleaseCommand(...) from integrating code. +// +// buildcmd.AddReleaseCommand(buildCmd) func AddReleaseCommand(buildCmd *cli.Command) { setReleaseI18n() initReleaseFlags() diff --git a/cmd/ci/cmd.go b/cmd/ci/cmd.go index 65e0c95..53a0259 100644 --- a/cmd/ci/cmd.go +++ b/cmd/ci/cmd.go @@ -18,7 +18,8 @@ func init() { } // AddCICommands registers the 'ci' command and all subcommands. -// Usage example: call ci.AddCICommands(...) from integrating code. +// +// ci.AddCICommands(root) func AddCICommands(root *cli.Command) { setCII18n() initCIFlags() diff --git a/cmd/sdk/cmd.go b/cmd/sdk/cmd.go index 05c8c01..8e4b321 100644 --- a/cmd/sdk/cmd.go +++ b/cmd/sdk/cmd.go @@ -60,7 +60,8 @@ func setSDKI18n() { } // AddSDKCommands registers the 'sdk' command and all subcommands. -// Usage example: call sdkcmd.AddSDKCommands(...) from integrating code. +// +// sdkcmd.AddSDKCommands(root) func AddSDKCommands(root *cli.Command) { setSDKI18n() diff --git a/internal/ax/ax.go b/internal/ax/ax.go index e0dc4ee..c71e811 100644 --- a/internal/ax/ax.go +++ b/internal/ax/ax.go @@ -4,7 +4,6 @@ import ( "context" "io" "io/fs" - "os" "runtime" "syscall" @@ -125,7 +124,7 @@ func FromSlash(path string) string { func Getwd() (string, error) { cwd := core.Env("DIR_CWD") if cwd == "" { - wd, err := os.Getwd() + wd, err := syscall.Getwd() if err != nil { return "", coreerr.E("ax.Getwd", "failed to get current working directory", err) } @@ -179,11 +178,8 @@ func WriteString(path, data string, mode fs.FileMode) error { // MkdirAll ensures a directory exists. // // Usage example: err := ax.MkdirAll("dist/linux_arm64", 0o755) -func MkdirAll(path string, mode fs.FileMode) error { - if mode == 0 { - mode = 0o755 - } - if err := os.MkdirAll(path, mode); err != nil { +func MkdirAll(path string, _ fs.FileMode) error { + if err := coreio.Local.EnsureDir(path); err != nil { return coreerr.E("ax.MkdirAll", "failed to create directory "+path, err) } return nil @@ -275,7 +271,7 @@ func IsDir(path string) bool { // // Usage example: err := ax.Chmod("dist/app", 0o755) func Chmod(path string, mode fs.FileMode) error { - if err := os.Chmod(path, mode); err != nil { + if err := syscall.Chmod(path, uint32(mode)); err != nil { return coreerr.E("ax.Chmod", "failed to change permissions on "+path, err) } return nil diff --git a/pkg/api/provider.go b/pkg/api/provider.go index 251a822..4ce0bf0 100644 --- a/pkg/api/provider.go +++ b/pkg/api/provider.go @@ -24,7 +24,8 @@ import ( // BuildProvider wraps go-build's build, release, and SDK operations as a // service provider. It implements Provider, Streamable, Describable, and // Renderable. -// Usage example: declare a value of type api.BuildProvider in integrating code. +// +// p := api.NewProvider(".", hub) type BuildProvider struct { hub *ws.Hub projectDir string @@ -42,7 +43,8 @@ var ( // NewProvider creates a BuildProvider for the given project directory. // If projectDir is empty, the current working directory is used. // The WS hub is used to emit real-time build events; pass nil if not available. -// Usage example: call api.NewProvider(...) from integrating code. +// +// p := api.NewProvider(".", hub) func NewProvider(projectDir string, hub *ws.Hub) *BuildProvider { if projectDir == "" { projectDir = "." @@ -55,15 +57,18 @@ func NewProvider(projectDir string, hub *ws.Hub) *BuildProvider { } // Name implements api.RouteGroup. -// Usage example: call value.Name(...) from integrating code. +// +// name := p.Name() // → "build" func (p *BuildProvider) Name() string { return "build" } // BasePath implements api.RouteGroup. -// Usage example: call value.BasePath(...) from integrating code. +// +// path := p.BasePath() // → "/api/v1/build" func (p *BuildProvider) BasePath() string { return "/api/v1/build" } // Element implements provider.Renderable. -// Usage example: call value.Element(...) from integrating code. +// +// spec := p.Element() // → {Tag: "core-build-panel", Source: "/assets/core-build.js"} func (p *BuildProvider) Element() provider.ElementSpec { return provider.ElementSpec{ Tag: "core-build-panel", @@ -72,7 +77,8 @@ func (p *BuildProvider) Element() provider.ElementSpec { } // Channels implements provider.Streamable. -// Usage example: call value.Channels(...) from integrating code. +// +// channels := p.Channels() // → ["build.started", "build.complete", ...] func (p *BuildProvider) Channels() []string { return []string{ "build.started", @@ -85,7 +91,8 @@ func (p *BuildProvider) Channels() []string { } // RegisterRoutes implements api.RouteGroup. -// Usage example: call value.RegisterRoutes(...) from integrating code. +// +// p.RegisterRoutes(rg) func (p *BuildProvider) RegisterRoutes(rg *gin.RouterGroup) { // Build rg.GET("/config", p.getConfig) @@ -104,7 +111,8 @@ func (p *BuildProvider) RegisterRoutes(rg *gin.RouterGroup) { } // Describe implements api.DescribableGroup. -// Usage example: call value.Describe(...) from integrating code. +// +// routes := p.Describe() // → [{Method: "GET", Path: "/config", ...}, ...] func (p *BuildProvider) Describe() []api.RouteDescription { return []api.RouteDescription{ { diff --git a/pkg/build/archive.go b/pkg/build/archive.go index e2dbb0e..4c7f9c4 100644 --- a/pkg/build/archive.go +++ b/pkg/build/archive.go @@ -16,7 +16,8 @@ import ( ) // ArchiveFormat specifies the compression format for archives. -// Usage example: declare a value of type build.ArchiveFormat in integrating code. +// +// var fmt build.ArchiveFormat = build.ArchiveFormatGzip type ArchiveFormat string const ( @@ -32,7 +33,8 @@ const ( // Uses tar.gz for linux/darwin and zip for windows. // The archive is created alongside the binary (e.g., dist/myapp_linux_amd64.tar.gz). // Returns a new Artifact with Path pointing to the archive. -// Usage example: call build.Archive(...) from integrating code. +// +// archived, err := build.Archive(io.Local, artifact) func Archive(fs io_interface.Medium, artifact Artifact) (Artifact, error) { return ArchiveWithFormat(fs, artifact, ArchiveFormatGzip) } @@ -40,7 +42,8 @@ func Archive(fs io_interface.Medium, artifact Artifact) (Artifact, error) { // ArchiveXZ creates an archive for a single artifact using xz compression. // Uses tar.xz for linux/darwin and zip for windows. // Returns a new Artifact with Path pointing to the archive. -// Usage example: call build.ArchiveXZ(...) from integrating code. +// +// archived, err := build.ArchiveXZ(io.Local, artifact) func ArchiveXZ(fs io_interface.Medium, artifact Artifact) (Artifact, error) { return ArchiveWithFormat(fs, artifact, ArchiveFormatXZ) } @@ -49,7 +52,8 @@ func ArchiveXZ(fs io_interface.Medium, artifact Artifact) (Artifact, error) { // Uses tar.gz or tar.xz for linux/darwin and zip for windows. // The archive is created alongside the binary (e.g., dist/myapp_linux_amd64.tar.xz). // Returns a new Artifact with Path pointing to the archive. -// Usage example: call build.ArchiveWithFormat(...) from integrating code. +// +// archived, err := build.ArchiveWithFormat(io.Local, artifact, build.ArchiveFormatXZ) func ArchiveWithFormat(fs io_interface.Medium, artifact Artifact, format ArchiveFormat) (Artifact, error) { if artifact.Path == "" { return Artifact{}, coreerr.E("build.Archive", "artifact path is empty", nil) @@ -97,21 +101,24 @@ func ArchiveWithFormat(fs io_interface.Medium, artifact Artifact, format Archive // ArchiveAll archives all artifacts using gzip compression. // Returns a slice of new artifacts pointing to the archives. -// Usage example: call build.ArchiveAll(...) from integrating code. +// +// archived, err := build.ArchiveAll(io.Local, artifacts) func ArchiveAll(fs io_interface.Medium, artifacts []Artifact) ([]Artifact, error) { return ArchiveAllWithFormat(fs, artifacts, ArchiveFormatGzip) } // ArchiveAllXZ archives all artifacts using xz compression. // Returns a slice of new artifacts pointing to the archives. -// Usage example: call build.ArchiveAllXZ(...) from integrating code. +// +// archived, err := build.ArchiveAllXZ(io.Local, artifacts) func ArchiveAllXZ(fs io_interface.Medium, artifacts []Artifact) ([]Artifact, error) { return ArchiveAllWithFormat(fs, artifacts, ArchiveFormatXZ) } // ArchiveAllWithFormat archives all artifacts with the specified format. // Returns a slice of new artifacts pointing to the archives. -// Usage example: call build.ArchiveAllWithFormat(...) from integrating code. +// +// archived, err := build.ArchiveAllWithFormat(io.Local, artifacts, build.ArchiveFormatXZ) func ArchiveAllWithFormat(fs io_interface.Medium, artifacts []Artifact, format ArchiveFormat) ([]Artifact, error) { if len(artifacts) == 0 { return nil, nil diff --git a/pkg/build/build.go b/pkg/build/build.go index 4d3e84e..18be145 100644 --- a/pkg/build/build.go +++ b/pkg/build/build.go @@ -10,7 +10,8 @@ import ( ) // ProjectType represents a detected project type. -// Usage example: declare a value of type build.ProjectType in integrating code. +// +// var t build.ProjectType = build.ProjectTypeGo type ProjectType string // Project type constants for build detection. @@ -34,20 +35,23 @@ const ( ) // Target represents a build target platform. -// Usage example: declare a value of type build.Target in integrating code. +// +// t := build.Target{OS: "linux", Arch: "amd64"} type Target struct { OS string Arch string } // String returns the target in GOOS/GOARCH format. -// Usage example: call value.String(...) from integrating code. +// +// s := t.String() // → "linux/amd64" func (t Target) String() string { return t.OS + "/" + t.Arch } // Artifact represents a build output file. -// Usage example: declare a value of type build.Artifact in integrating code. +// +// a := build.Artifact{Path: "dist/linux_amd64/myapp", OS: "linux", Arch: "amd64"} type Artifact struct { Path string OS string @@ -56,7 +60,8 @@ type Artifact struct { } // Config holds build configuration. -// Usage example: declare a value of type build.Config in integrating code. +// +// cfg := &build.Config{FS: io.Local, ProjectDir: ".", OutputDir: "dist", Name: "myapp"} type Config struct { // FS is the medium used for file operations. FS io.Medium @@ -87,7 +92,9 @@ type Config struct { } // Builder defines the interface for project-specific build implementations. -// Usage example: declare a value of type build.Builder in integrating code. +// +// var b build.Builder = builders.NewGoBuilder() +// artifacts, err := b.Build(ctx, cfg, targets) type Builder interface { // Name returns the builder's identifier. Name() string diff --git a/pkg/build/builders/cpp.go b/pkg/build/builders/cpp.go index 1561de7..edce401 100644 --- a/pkg/build/builders/cpp.go +++ b/pkg/build/builders/cpp.go @@ -14,31 +14,35 @@ import ( // CPPBuilder implements the Builder interface for C++ projects using CMake + Conan. // It wraps the Makefile-based build system from the .core/build submodule. -// Usage example: declare a value of type builders.CPPBuilder in integrating code. +// +// b := builders.NewCPPBuilder() type CPPBuilder struct{} // NewCPPBuilder creates a new CPPBuilder instance. -// Usage example: call builders.NewCPPBuilder(...) from integrating code. +// +// b := builders.NewCPPBuilder() func NewCPPBuilder() *CPPBuilder { return &CPPBuilder{} } // Name returns the builder's identifier. -// Usage example: call value.Name(...) from integrating code. +// +// name := b.Name() // → "cpp" func (b *CPPBuilder) Name() string { return "cpp" } -// Detect checks if this builder can handle the project in the given directory. -// Usage example: call value.Detect(...) from integrating code. +// Detect checks if this builder can handle the project (checks for CMakeLists.txt). +// +// ok, err := b.Detect(io.Local, ".") func (b *CPPBuilder) Detect(fs io.Medium, dir string) (bool, error) { return build.IsCPPProject(fs, dir), nil } // Build compiles the C++ project using Make targets. // The build flow is: make configure → make build → make package. -// Cross-compilation is handled via Conan profiles specified in .core/build.yaml. -// Usage example: call value.Build(...) from integrating code. +// +// artifacts, err := b.Build(ctx, cfg, []build.Target{{OS: "linux", Arch: "amd64"}}) func (b *CPPBuilder) Build(ctx context.Context, cfg *build.Config, targets []build.Target) ([]build.Artifact, error) { if cfg == nil { return nil, coreerr.E("CPPBuilder.Build", "config is nil", nil) diff --git a/pkg/build/builders/docker.go b/pkg/build/builders/docker.go index 18ce795..fbe6b79 100644 --- a/pkg/build/builders/docker.go +++ b/pkg/build/builders/docker.go @@ -12,23 +12,27 @@ import ( ) // DockerBuilder builds Docker images. -// Usage example: declare a value of type builders.DockerBuilder in integrating code. +// +// b := builders.NewDockerBuilder() type DockerBuilder struct{} // NewDockerBuilder creates a new Docker builder. -// Usage example: call builders.NewDockerBuilder(...) from integrating code. +// +// b := builders.NewDockerBuilder() func NewDockerBuilder() *DockerBuilder { return &DockerBuilder{} } // Name returns the builder's identifier. -// Usage example: call value.Name(...) from integrating code. +// +// name := b.Name() // → "docker" func (b *DockerBuilder) Name() string { return "docker" } // Detect checks if a Dockerfile exists in the directory. -// Usage example: call value.Detect(...) from integrating code. +// +// ok, err := b.Detect(io.Local, ".") func (b *DockerBuilder) Detect(fs io.Medium, dir string) (bool, error) { dockerfilePath := ax.Join(dir, "Dockerfile") if fs.IsFile(dockerfilePath) { @@ -38,7 +42,8 @@ func (b *DockerBuilder) Detect(fs io.Medium, dir string) (bool, error) { } // Build builds Docker images for the specified targets. -// Usage example: call value.Build(...) from integrating code. +// +// artifacts, err := b.Build(ctx, cfg, []build.Target{{OS: "linux", Arch: "amd64"}}) func (b *DockerBuilder) Build(ctx context.Context, cfg *build.Config, targets []build.Target) ([]build.Artifact, error) { dockerCommand, err := b.resolveDockerCli() if err != nil { diff --git a/pkg/build/builders/go.go b/pkg/build/builders/go.go index 1a496da..15fb3ac 100644 --- a/pkg/build/builders/go.go +++ b/pkg/build/builders/go.go @@ -12,32 +12,36 @@ import ( ) // GoBuilder implements the Builder interface for Go projects. -// Usage example: declare a value of type builders.GoBuilder in integrating code. +// +// b := builders.NewGoBuilder() type GoBuilder struct{} // NewGoBuilder creates a new GoBuilder instance. -// Usage example: call builders.NewGoBuilder(...) from integrating code. +// +// b := builders.NewGoBuilder() func NewGoBuilder() *GoBuilder { return &GoBuilder{} } // Name returns the builder's identifier. -// Usage example: call value.Name(...) from integrating code. +// +// name := b.Name() // → "go" func (b *GoBuilder) Name() string { return "go" } // Detect checks if this builder can handle the project in the given directory. // Uses IsGoProject from the build package which checks for go.mod or wails.json. -// Usage example: call value.Detect(...) from integrating code. +// +// ok, err := b.Detect(io.Local, ".") func (b *GoBuilder) Detect(fs io.Medium, dir string) (bool, error) { return build.IsGoProject(fs, dir), nil } // Build compiles the Go project for the specified targets. -// It sets GOOS, GOARCH, and CGO_ENABLED environment variables, -// applies ldflags and trimpath, and runs go build. -// Usage example: call value.Build(...) from integrating code. +// It sets GOOS, GOARCH, and CGO_ENABLED, applies ldflags and trimpath. +// +// artifacts, err := b.Build(ctx, cfg, []build.Target{{OS: "linux", Arch: "amd64"}}) func (b *GoBuilder) Build(ctx context.Context, cfg *build.Config, targets []build.Target) ([]build.Artifact, error) { if cfg == nil { return nil, coreerr.E("GoBuilder.Build", "config is nil", nil) diff --git a/pkg/build/builders/linuxkit.go b/pkg/build/builders/linuxkit.go index 335d48e..593742a 100644 --- a/pkg/build/builders/linuxkit.go +++ b/pkg/build/builders/linuxkit.go @@ -12,23 +12,27 @@ import ( ) // LinuxKitBuilder builds LinuxKit images. -// Usage example: declare a value of type builders.LinuxKitBuilder in integrating code. +// +// b := builders.NewLinuxKitBuilder() type LinuxKitBuilder struct{} // NewLinuxKitBuilder creates a new LinuxKit builder. -// Usage example: call builders.NewLinuxKitBuilder(...) from integrating code. +// +// b := builders.NewLinuxKitBuilder() func NewLinuxKitBuilder() *LinuxKitBuilder { return &LinuxKitBuilder{} } // Name returns the builder's identifier. -// Usage example: call value.Name(...) from integrating code. +// +// name := b.Name() // → "linuxkit" func (b *LinuxKitBuilder) Name() string { return "linuxkit" } // Detect checks if a linuxkit.yml or .yml config exists in the directory. -// Usage example: call value.Detect(...) from integrating code. +// +// ok, err := b.Detect(io.Local, ".") func (b *LinuxKitBuilder) Detect(fs io.Medium, dir string) (bool, error) { // Check for linuxkit.yml if fs.IsFile(ax.Join(dir, "linuxkit.yml")) { @@ -50,7 +54,8 @@ func (b *LinuxKitBuilder) Detect(fs io.Medium, dir string) (bool, error) { } // Build builds LinuxKit images for the specified targets. -// Usage example: call value.Build(...) from integrating code. +// +// artifacts, err := b.Build(ctx, cfg, []build.Target{{OS: "linux", Arch: "amd64"}}) func (b *LinuxKitBuilder) Build(ctx context.Context, cfg *build.Config, targets []build.Target) ([]build.Artifact, error) { linuxkitCommand, err := b.resolveLinuxKitCli() if err != nil { diff --git a/pkg/build/builders/taskfile.go b/pkg/build/builders/taskfile.go index 8bf78aa..07e9c04 100644 --- a/pkg/build/builders/taskfile.go +++ b/pkg/build/builders/taskfile.go @@ -14,23 +14,27 @@ import ( // TaskfileBuilder builds projects using Taskfile (https://taskfile.dev/). // This is a generic builder that can handle any project type that has a Taskfile. -// Usage example: declare a value of type builders.TaskfileBuilder in integrating code. +// +// b := builders.NewTaskfileBuilder() type TaskfileBuilder struct{} // NewTaskfileBuilder creates a new Taskfile builder. -// Usage example: call builders.NewTaskfileBuilder(...) from integrating code. +// +// b := builders.NewTaskfileBuilder() func NewTaskfileBuilder() *TaskfileBuilder { return &TaskfileBuilder{} } // Name returns the builder's identifier. -// Usage example: call value.Name(...) from integrating code. +// +// name := b.Name() // → "taskfile" func (b *TaskfileBuilder) Name() string { return "taskfile" } // Detect checks if a Taskfile exists in the directory. -// Usage example: call value.Detect(...) from integrating code. +// +// ok, err := b.Detect(io.Local, ".") func (b *TaskfileBuilder) Detect(fs io.Medium, dir string) (bool, error) { // Check for Taskfile.yml, Taskfile.yaml, or Taskfile taskfiles := []string{ @@ -50,7 +54,8 @@ func (b *TaskfileBuilder) Detect(fs io.Medium, dir string) (bool, error) { } // Build runs the Taskfile build task for each target platform. -// Usage example: call value.Build(...) from integrating code. +// +// artifacts, err := b.Build(ctx, cfg, []build.Target{{OS: "linux", Arch: "amd64"}}) func (b *TaskfileBuilder) Build(ctx context.Context, cfg *build.Config, targets []build.Target) ([]build.Artifact, error) { taskCommand, err := b.resolveTaskCli() if err != nil { diff --git a/pkg/build/builders/wails.go b/pkg/build/builders/wails.go index a2f31f8..59cdc33 100644 --- a/pkg/build/builders/wails.go +++ b/pkg/build/builders/wails.go @@ -12,33 +12,35 @@ import ( ) // WailsBuilder implements the Builder interface for Wails v3 projects. -// Usage example: declare a value of type builders.WailsBuilder in integrating code. +// +// b := builders.NewWailsBuilder() type WailsBuilder struct{} // NewWailsBuilder creates a new WailsBuilder instance. -// Usage example: call builders.NewWailsBuilder(...) from integrating code. +// +// b := builders.NewWailsBuilder() func NewWailsBuilder() *WailsBuilder { return &WailsBuilder{} } // Name returns the builder's identifier. -// Usage example: call value.Name(...) from integrating code. +// +// name := b.Name() // → "wails" func (b *WailsBuilder) Name() string { return "wails" } -// Detect checks if this builder can handle the project in the given directory. -// Uses IsWailsProject from the build package which checks for wails.json. -// Usage example: call value.Detect(...) from integrating code. +// Detect checks if this builder can handle the project (checks for wails.json). +// +// ok, err := b.Detect(io.Local, ".") func (b *WailsBuilder) Detect(fs io.Medium, dir string) (bool, error) { return build.IsWailsProject(fs, dir), nil } // Build compiles the Wails project for the specified targets. -// It detects the Wails version and chooses the appropriate build strategy: -// - Wails v3: Delegates to Taskfile (error if missing) -// - Wails v2: Uses 'wails build' command -// Usage example: call value.Build(...) from integrating code. +// Wails v3: delegates to Taskfile; Wails v2: uses 'wails build'. +// +// artifacts, err := b.Build(ctx, cfg, []build.Target{{OS: "darwin", Arch: "arm64"}}) func (b *WailsBuilder) Build(ctx context.Context, cfg *build.Config, targets []build.Target) ([]build.Artifact, error) { if cfg == nil { return nil, coreerr.E("WailsBuilder.Build", "config is nil", nil) diff --git a/pkg/build/checksum.go b/pkg/build/checksum.go index c48f8fd..22d65d2 100644 --- a/pkg/build/checksum.go +++ b/pkg/build/checksum.go @@ -13,7 +13,8 @@ import ( ) // Checksum computes SHA256 for an artifact and returns the artifact with the Checksum field filled. -// Usage example: call build.Checksum(...) from integrating code. +// +// cs, err := build.Checksum(io.Local, artifact) func Checksum(fs io_interface.Medium, artifact Artifact) (Artifact, error) { if artifact.Path == "" { return Artifact{}, coreerr.E("build.Checksum", "artifact path is empty", nil) @@ -44,7 +45,8 @@ func Checksum(fs io_interface.Medium, artifact Artifact) (Artifact, error) { // ChecksumAll computes checksums for all artifacts. // Returns a slice of artifacts with their Checksum fields filled. -// Usage example: call build.ChecksumAll(...) from integrating code. +// +// checked, err := build.ChecksumAll(io.Local, artifacts) func ChecksumAll(fs io_interface.Medium, artifacts []Artifact) ([]Artifact, error) { if len(artifacts) == 0 { return nil, nil @@ -69,7 +71,8 @@ func ChecksumAll(fs io_interface.Medium, artifacts []Artifact) ([]Artifact, erro // // The artifacts should have their Checksum fields filled (call ChecksumAll first). // Filenames are relative to the output directory (just the basename). -// Usage example: call build.WriteChecksumFile(...) from integrating code. +// +// err := build.WriteChecksumFile(io.Local, artifacts, "dist/CHECKSUMS.txt") func WriteChecksumFile(fs io_interface.Medium, artifacts []Artifact, path string) error { if len(artifacts) == 0 { return nil diff --git a/pkg/build/config.go b/pkg/build/config.go index 7acdbad..3c0538f 100644 --- a/pkg/build/config.go +++ b/pkg/build/config.go @@ -13,16 +13,19 @@ import ( ) // ConfigFileName is the name of the build configuration file. -// Usage example: reference build.ConfigFileName from package consumers. +// +// configPath := ax.Join(projectDir, build.ConfigDir, build.ConfigFileName) const ConfigFileName = "build.yaml" // ConfigDir is the directory where build configuration is stored. -// Usage example: reference build.ConfigDir from package consumers. +// +// configPath := ax.Join(projectDir, build.ConfigDir, build.ConfigFileName) const ConfigDir = ".core" // BuildConfig holds the complete build configuration loaded from .core/build.yaml. // This is distinct from Config which holds runtime build parameters. -// Usage example: declare a value of type build.BuildConfig in integrating code. +// +// cfg, err := build.LoadConfig(io.Local, ".") type BuildConfig struct { // Version is the config file format version. Version int `yaml:"version"` @@ -37,7 +40,8 @@ type BuildConfig struct { } // Project holds project metadata. -// Usage example: declare a value of type build.Project in integrating code. +// +// cfg.Project.Binary = "core-build" type Project struct { // Name is the project name. Name string `yaml:"name"` @@ -50,7 +54,8 @@ type Project struct { } // Build holds build-time settings. -// Usage example: declare a value of type build.Build in integrating code. +// +// cfg.Build.LDFlags = []string{"-s", "-w", "-X main.version=" + version} type Build struct { // Type overrides project type auto-detection (e.g., "go", "wails", "docker"). Type string `yaml:"type"` @@ -66,7 +71,8 @@ type Build struct { // TargetConfig defines a build target in the config file. // This is separate from Target to allow for additional config-specific fields. -// Usage example: declare a value of type build.TargetConfig in integrating code. +// +// cfg.Targets = []build.TargetConfig{{OS: "linux", Arch: "amd64"}, {OS: "darwin", Arch: "arm64"}} type TargetConfig struct { // OS is the target operating system (e.g., "linux", "darwin", "windows"). OS string `yaml:"os"` @@ -77,7 +83,8 @@ type TargetConfig struct { // LoadConfig loads build configuration from the .core/build.yaml file in the given directory. // If the config file does not exist, it returns DefaultConfig(). // Returns an error if the file exists but cannot be parsed. -// Usage example: call build.LoadConfig(...) from integrating code. +// +// cfg, err := build.LoadConfig(io.Local, ".") func LoadConfig(fs io.Medium, dir string) (*BuildConfig, error) { configPath := ax.Join(dir, ConfigDir, ConfigFileName) @@ -102,7 +109,8 @@ func LoadConfig(fs io.Medium, dir string) (*BuildConfig, error) { } // DefaultConfig returns sensible defaults for Go projects. -// Usage example: call build.DefaultConfig(...) from integrating code. +// +// cfg := build.DefaultConfig() func DefaultConfig() *BuildConfig { return &BuildConfig{ Version: 1, @@ -160,19 +168,22 @@ func applyDefaults(cfg *BuildConfig) { } // ConfigPath returns the path to the build config file for a given directory. -// Usage example: call build.ConfigPath(...) from integrating code. +// +// path := build.ConfigPath("/home/user/my-project") // → "/home/user/my-project/.core/build.yaml" func ConfigPath(dir string) string { return ax.Join(dir, ConfigDir, ConfigFileName) } // ConfigExists checks if a build config file exists in the given directory. -// Usage example: call build.ConfigExists(...) from integrating code. +// +// if build.ConfigExists(io.Local, ".") { ... } func ConfigExists(fs io.Medium, dir string) bool { return fileExists(fs, ConfigPath(dir)) } // TargetsIter returns an iterator for the build targets. -// Usage example: call value.TargetsIter(...) from integrating code. +// +// for t := range cfg.TargetsIter() { fmt.Println(t.OS, t.Arch) } func (cfg *BuildConfig) TargetsIter() iter.Seq[TargetConfig] { return func(yield func(TargetConfig) bool) { for _, t := range cfg.Targets { @@ -184,7 +195,8 @@ func (cfg *BuildConfig) TargetsIter() iter.Seq[TargetConfig] { } // ToTargets converts TargetConfig slice to Target slice for use with builders. -// Usage example: call value.ToTargets(...) from integrating code. +// +// targets := cfg.ToTargets() func (cfg *BuildConfig) ToTargets() []Target { targets := make([]Target, len(cfg.Targets)) for i, t := range cfg.Targets { diff --git a/pkg/build/discovery.go b/pkg/build/discovery.go index eadb28b..c64a6b3 100644 --- a/pkg/build/discovery.go +++ b/pkg/build/discovery.go @@ -32,7 +32,8 @@ var markers = []projectMarker{ // Discover detects project types in the given directory by checking for marker files. // Returns a slice of detected project types, ordered by priority (most specific first). // For example, a Wails project returns [wails, go] since it has both wails.json and go.mod. -// Usage example: call build.Discover(...) from integrating code. +// +// types, err := build.Discover(io.Local, "/home/user/my-project") // → [go] func Discover(fs io.Medium, dir string) ([]ProjectType, error) { var detected []ProjectType @@ -51,7 +52,8 @@ func Discover(fs io.Medium, dir string) ([]ProjectType, error) { // PrimaryType returns the most specific project type detected in the directory. // Returns empty string if no project type is detected. -// Usage example: call build.PrimaryType(...) from integrating code. +// +// pt, err := build.PrimaryType(io.Local, ".") // → "go" func PrimaryType(fs io.Medium, dir string) (ProjectType, error) { types, err := Discover(fs, dir) if err != nil { @@ -64,32 +66,37 @@ func PrimaryType(fs io.Medium, dir string) (ProjectType, error) { } // IsGoProject checks if the directory contains a Go project (go.mod or wails.json). -// Usage example: call build.IsGoProject(...) from integrating code. +// +// if build.IsGoProject(io.Local, ".") { ... } func IsGoProject(fs io.Medium, dir string) bool { return fileExists(fs, ax.Join(dir, markerGoMod)) || fileExists(fs, ax.Join(dir, markerWails)) } // IsWailsProject checks if the directory contains a Wails project. -// Usage example: call build.IsWailsProject(...) from integrating code. +// +// if build.IsWailsProject(io.Local, ".") { ... } func IsWailsProject(fs io.Medium, dir string) bool { return fileExists(fs, ax.Join(dir, markerWails)) } // IsNodeProject checks if the directory contains a Node.js project. -// Usage example: call build.IsNodeProject(...) from integrating code. +// +// if build.IsNodeProject(io.Local, ".") { ... } func IsNodeProject(fs io.Medium, dir string) bool { return fileExists(fs, ax.Join(dir, markerNodePackage)) } // IsPHPProject checks if the directory contains a PHP project. -// Usage example: call build.IsPHPProject(...) from integrating code. +// +// if build.IsPHPProject(io.Local, ".") { ... } func IsPHPProject(fs io.Medium, dir string) bool { return fileExists(fs, ax.Join(dir, markerComposer)) } // IsCPPProject checks if the directory contains a C++ project (CMakeLists.txt). -// Usage example: call build.IsCPPProject(...) from integrating code. +// +// if build.IsCPPProject(io.Local, ".") { ... } func IsCPPProject(fs io.Medium, dir string) bool { return fileExists(fs, ax.Join(dir, "CMakeLists.txt")) } diff --git a/pkg/build/signing/codesign.go b/pkg/build/signing/codesign.go index 52a15cf..3d40378 100644 --- a/pkg/build/signing/codesign.go +++ b/pkg/build/signing/codesign.go @@ -10,7 +10,8 @@ import ( ) // MacOSSigner signs binaries using macOS codesign. -// Usage example: declare a value of type signing.MacOSSigner in integrating code. +// +// s := signing.NewMacOSSigner(cfg.MacOS) type MacOSSigner struct { config MacOSConfig } @@ -19,19 +20,22 @@ type MacOSSigner struct { var _ Signer = (*MacOSSigner)(nil) // NewMacOSSigner creates a new macOS signer. -// Usage example: call signing.NewMacOSSigner(...) from integrating code. +// +// s := signing.NewMacOSSigner(cfg.MacOS) func NewMacOSSigner(cfg MacOSConfig) *MacOSSigner { return &MacOSSigner{config: cfg} } // Name returns "codesign". -// Usage example: call value.Name(...) from integrating code. +// +// name := s.Name() // → "codesign" func (s *MacOSSigner) Name() string { return "codesign" } // Available checks if running on macOS with codesign and identity configured. -// Usage example: call value.Available(...) from integrating code. +// +// ok := s.Available() // → true if on macOS with identity set func (s *MacOSSigner) Available() bool { if runtime.GOOS != "darwin" { return false @@ -44,7 +48,8 @@ func (s *MacOSSigner) Available() bool { } // Sign codesigns a binary with hardened runtime. -// Usage example: call value.Sign(...) from integrating code. +// +// err := s.Sign(ctx, io.Local, "dist/myapp") func (s *MacOSSigner) Sign(ctx context.Context, fs io.Medium, binary string) error { if !s.Available() { if runtime.GOOS != "darwin" { @@ -77,7 +82,8 @@ func (s *MacOSSigner) Sign(ctx context.Context, fs io.Medium, binary string) err // Notarize submits binary to Apple for notarization and staples the ticket. // This blocks until Apple responds (typically 1-5 minutes). -// Usage example: call value.Notarize(...) from integrating code. +// +// err := s.Notarize(ctx, io.Local, "dist/myapp") func (s *MacOSSigner) Notarize(ctx context.Context, fs io.Medium, binary string) error { if s.config.AppleID == "" || s.config.TeamID == "" || s.config.AppPassword == "" { return coreerr.E("codesign.Notarize", "missing Apple credentials (apple_id, team_id, app_password)", nil) @@ -120,7 +126,8 @@ func (s *MacOSSigner) Notarize(ctx context.Context, fs io.Medium, binary string) } // ShouldNotarize returns true if notarization is enabled. -// Usage example: call value.ShouldNotarize(...) from integrating code. +// +// if s.ShouldNotarize() { ... } func (s *MacOSSigner) ShouldNotarize() bool { return s.config.Notarize } diff --git a/pkg/build/signing/gpg.go b/pkg/build/signing/gpg.go index 86e92a6..b8de1e5 100644 --- a/pkg/build/signing/gpg.go +++ b/pkg/build/signing/gpg.go @@ -9,7 +9,8 @@ import ( ) // GPGSigner signs files using GPG. -// Usage example: declare a value of type signing.GPGSigner in integrating code. +// +// s := signing.NewGPGSigner("ABCD1234") type GPGSigner struct { KeyID string } @@ -18,19 +19,22 @@ type GPGSigner struct { var _ Signer = (*GPGSigner)(nil) // NewGPGSigner creates a new GPG signer. -// Usage example: call signing.NewGPGSigner(...) from integrating code. +// +// s := signing.NewGPGSigner("ABCD1234") func NewGPGSigner(keyID string) *GPGSigner { return &GPGSigner{KeyID: keyID} } // Name returns "gpg". -// Usage example: call value.Name(...) from integrating code. +// +// name := s.Name() // → "gpg" func (s *GPGSigner) Name() string { return "gpg" } // Available checks if gpg is installed and key is configured. -// Usage example: call value.Available(...) from integrating code. +// +// ok := s.Available() // → true if gpg is in PATH and key is set func (s *GPGSigner) Available() bool { if s.KeyID == "" { return false @@ -41,7 +45,8 @@ func (s *GPGSigner) Available() bool { // Sign creates a detached ASCII-armored signature. // For file.txt, creates file.txt.asc -// Usage example: call value.Sign(...) from integrating code. +// +// err := s.Sign(ctx, io.Local, "dist/CHECKSUMS.txt") // creates CHECKSUMS.txt.asc func (s *GPGSigner) Sign(ctx context.Context, fs io.Medium, file string) error { if s.KeyID == "" { return coreerr.E("gpg.Sign", "gpg not available or key not configured", nil) diff --git a/pkg/build/signing/sign.go b/pkg/build/signing/sign.go index 155cee5..661b159 100644 --- a/pkg/build/signing/sign.go +++ b/pkg/build/signing/sign.go @@ -11,7 +11,8 @@ import ( // Artifact represents a build output that can be signed. // This mirrors build.Artifact to avoid import cycles. -// Usage example: declare a value of type signing.Artifact in integrating code. +// +// a := signing.Artifact{Path: "dist/myapp", OS: "darwin", Arch: "arm64"} type Artifact struct { Path string OS string @@ -20,7 +21,8 @@ type Artifact struct { // SignBinaries signs macOS binaries in the artifacts list. // Only signs darwin binaries when running on macOS with a configured identity. -// Usage example: call signing.SignBinaries(...) from integrating code. +// +// err := signing.SignBinaries(ctx, io.Local, cfg, artifacts) func SignBinaries(ctx context.Context, fs io.Medium, cfg SignConfig, artifacts []Artifact) error { if !cfg.Enabled { return nil @@ -51,7 +53,8 @@ func SignBinaries(ctx context.Context, fs io.Medium, cfg SignConfig, artifacts [ } // NotarizeBinaries notarizes macOS binaries if enabled. -// Usage example: call signing.NotarizeBinaries(...) from integrating code. +// +// err := signing.NotarizeBinaries(ctx, io.Local, cfg, artifacts) func NotarizeBinaries(ctx context.Context, fs io.Medium, cfg SignConfig, artifacts []Artifact) error { if !cfg.Enabled || !cfg.MacOS.Notarize { return nil @@ -81,7 +84,8 @@ func NotarizeBinaries(ctx context.Context, fs io.Medium, cfg SignConfig, artifac } // SignChecksums signs the checksums file with GPG. -// Usage example: call signing.SignChecksums(...) from integrating code. +// +// err := signing.SignChecksums(ctx, io.Local, cfg, "dist/CHECKSUMS.txt") func SignChecksums(ctx context.Context, fs io.Medium, cfg SignConfig, checksumFile string) error { if !cfg.Enabled { return nil diff --git a/pkg/build/signing/signer.go b/pkg/build/signing/signer.go index a88591d..dea5636 100644 --- a/pkg/build/signing/signer.go +++ b/pkg/build/signing/signer.go @@ -9,7 +9,9 @@ import ( ) // Signer defines the interface for code signing implementations. -// Usage example: declare a value of type signing.Signer in integrating code. +// +// var s signing.Signer = signing.NewGPGSigner(keyID) +// err := s.Sign(ctx, io.Local, "dist/myapp") type Signer interface { // Name returns the signer's identifier. Name() string @@ -20,7 +22,8 @@ type Signer interface { } // SignConfig holds signing configuration from .core/build.yaml. -// Usage example: declare a value of type signing.SignConfig in integrating code. +// +// cfg := signing.DefaultSignConfig() type SignConfig struct { Enabled bool `yaml:"enabled"` GPG GPGConfig `yaml:"gpg,omitempty"` @@ -29,13 +32,15 @@ type SignConfig struct { } // GPGConfig holds GPG signing configuration. -// Usage example: declare a value of type signing.GPGConfig in integrating code. +// +// cfg := signing.GPGConfig{Key: "ABCD1234"} type GPGConfig struct { Key string `yaml:"key"` // Key ID or fingerprint, supports $ENV } // MacOSConfig holds macOS codesign configuration. -// Usage example: declare a value of type signing.MacOSConfig in integrating code. +// +// cfg := signing.MacOSConfig{Identity: "Developer ID Application: Acme Inc (TEAM123)"} type MacOSConfig struct { Identity string `yaml:"identity"` // Developer ID Application: ... Notarize bool `yaml:"notarize"` // Submit to Apple for notarization @@ -45,14 +50,16 @@ type MacOSConfig struct { } // WindowsConfig holds Windows signtool configuration (placeholder). -// Usage example: declare a value of type signing.WindowsConfig in integrating code. +// +// cfg := signing.WindowsConfig{Certificate: "cert.pfx", Password: "secret"} type WindowsConfig struct { Certificate string `yaml:"certificate"` // Path to .pfx Password string `yaml:"password"` // Certificate password } // DefaultSignConfig returns sensible defaults. -// Usage example: call signing.DefaultSignConfig(...) from integrating code. +// +// cfg := signing.DefaultSignConfig() func DefaultSignConfig() SignConfig { return SignConfig{ Enabled: true, @@ -69,7 +76,8 @@ func DefaultSignConfig() SignConfig { } // ExpandEnv expands environment variables in config values. -// Usage example: call value.ExpandEnv(...) from integrating code. +// +// cfg.ExpandEnv() // expands $GPG_KEY_ID, $CODESIGN_IDENTITY etc. func (c *SignConfig) ExpandEnv() { c.GPG.Key = expandEnv(c.GPG.Key) c.MacOS.Identity = expandEnv(c.MacOS.Identity) diff --git a/pkg/build/signing/signtool.go b/pkg/build/signing/signtool.go index 1e96ece..c4731ae 100644 --- a/pkg/build/signing/signtool.go +++ b/pkg/build/signing/signtool.go @@ -7,7 +7,8 @@ import ( ) // WindowsSigner signs binaries using Windows signtool (placeholder). -// Usage example: declare a value of type signing.WindowsSigner in integrating code. +// +// s := signing.NewWindowsSigner(cfg.Windows) type WindowsSigner struct { config WindowsConfig } @@ -16,25 +17,29 @@ type WindowsSigner struct { var _ Signer = (*WindowsSigner)(nil) // NewWindowsSigner creates a new Windows signer. -// Usage example: call signing.NewWindowsSigner(...) from integrating code. +// +// s := signing.NewWindowsSigner(cfg.Windows) func NewWindowsSigner(cfg WindowsConfig) *WindowsSigner { return &WindowsSigner{config: cfg} } // Name returns "signtool". -// Usage example: call value.Name(...) from integrating code. +// +// name := s.Name() // → "signtool" func (s *WindowsSigner) Name() string { return "signtool" } // Available returns false (not yet implemented). -// Usage example: call value.Available(...) from integrating code. +// +// ok := s.Available() // → false (placeholder) func (s *WindowsSigner) Available() bool { return false } // Sign is a placeholder that does nothing. -// Usage example: call value.Sign(...) from integrating code. +// +// err := s.Sign(ctx, io.Local, "dist/myapp.exe") // no-op until implemented func (s *WindowsSigner) Sign(ctx context.Context, fs io.Medium, binary string) error { // TODO: Implement Windows signing return nil diff --git a/pkg/release/changelog.go b/pkg/release/changelog.go index a76b3c5..3bad87f 100644 --- a/pkg/release/changelog.go +++ b/pkg/release/changelog.go @@ -16,7 +16,8 @@ import ( ) // ConventionalCommit represents a parsed conventional commit. -// Usage example: declare a value of type release.ConventionalCommit in integrating code. +// +// commit := release.ConventionalCommit{Type: "feat", Scope: "build", Description: "add linuxkit support"} type ConventionalCommit struct { Type string // feat, fix, etc. Scope string // optional scope in parentheses @@ -62,7 +63,8 @@ var conventionalCommitRegex = regexp.MustCompile(`^(\w+)(?:\(([^)]+)\))?(!)?:\s* // Generate generates a markdown changelog from git commits between two refs. // If fromRef is empty, it uses the previous tag or initial commit. // If toRef is empty, it uses HEAD. -// Usage example: call release.Generate(...) from integrating code. +// +// md, err := release.Generate(".", "v1.2.3", "HEAD") func Generate(dir, fromRef, toRef string) (string, error) { return GenerateWithContext(context.Background(), dir, fromRef, toRef) } @@ -70,7 +72,8 @@ func Generate(dir, fromRef, toRef string) (string, error) { // GenerateWithContext generates a markdown changelog while honouring caller cancellation. // If fromRef is empty, it uses the previous tag or initial commit. // If toRef is empty, it uses HEAD. -// Usage example: call release.GenerateWithContext(...) from integrating code. +// +// md, err := release.GenerateWithContext(ctx, ".", "v1.2.3", "HEAD") func GenerateWithContext(ctx context.Context, dir, fromRef, toRef string) (string, error) { if toRef == "" { toRef = "HEAD" @@ -110,13 +113,15 @@ func GenerateWithContext(ctx context.Context, dir, fromRef, toRef string) (strin } // GenerateWithConfig generates a changelog with filtering based on config. -// Usage example: call release.GenerateWithConfig(...) from integrating code. +// +// md, err := release.GenerateWithConfig(".", "v1.2.3", "HEAD", &cfg.Changelog) func GenerateWithConfig(dir, fromRef, toRef string, cfg *ChangelogConfig) (string, error) { return GenerateWithConfigWithContext(context.Background(), dir, fromRef, toRef, cfg) } // GenerateWithConfigWithContext generates a filtered changelog while honouring caller cancellation. -// Usage example: call release.GenerateWithConfigWithContext(...) from integrating code. +// +// md, err := release.GenerateWithConfigWithContext(ctx, ".", "v1.2.3", "HEAD", &cfg.Changelog) func GenerateWithConfigWithContext(ctx context.Context, dir, fromRef, toRef string, cfg *ChangelogConfig) (string, error) { if toRef == "" { toRef = "HEAD" @@ -322,7 +327,8 @@ func formatCommitLine(commit ConventionalCommit) string { // ParseCommitType extracts the type from a conventional commit subject. // Returns empty string if not a conventional commit. -// Usage example: call release.ParseCommitType(...) from integrating code. +// +// t := release.ParseCommitType("feat(build): add linuxkit support") // → "feat" func ParseCommitType(subject string) string { matches := conventionalCommitRegex.FindStringSubmatch(subject) if matches == nil { diff --git a/pkg/release/config.go b/pkg/release/config.go index d9b4cea..6e33c09 100644 --- a/pkg/release/config.go +++ b/pkg/release/config.go @@ -10,15 +10,18 @@ import ( ) // ConfigFileName is the name of the release configuration file. -// Usage example: reference release.ConfigFileName from package consumers. +// +// configPath := ax.Join(projectDir, release.ConfigDir, release.ConfigFileName) const ConfigFileName = "release.yaml" // ConfigDir is the directory where release configuration is stored. -// Usage example: reference release.ConfigDir from package consumers. +// +// configPath := ax.Join(projectDir, release.ConfigDir, release.ConfigFileName) const ConfigDir = ".core" // Config holds the complete release configuration loaded from .core/release.yaml. -// Usage example: declare a value of type release.Config in integrating code. +// +// cfg, err := release.LoadConfig(".") type Config struct { // Version is the config file format version. Version int `yaml:"version"` @@ -39,7 +42,8 @@ type Config struct { } // ProjectConfig holds project metadata for releases. -// Usage example: declare a value of type release.ProjectConfig in integrating code. +// +// cfg.Project = release.ProjectConfig{Name: "core-build", Repository: "host-uk/core-build"} type ProjectConfig struct { // Name is the project name. Name string `yaml:"name"` @@ -48,14 +52,16 @@ type ProjectConfig struct { } // BuildConfig holds build settings for releases. -// Usage example: declare a value of type release.BuildConfig in integrating code. +// +// cfg.Build.Targets = []release.TargetConfig{{OS: "linux", Arch: "amd64"}} type BuildConfig struct { // Targets defines the build targets. Targets []TargetConfig `yaml:"targets"` } // TargetConfig defines a build target. -// Usage example: declare a value of type release.TargetConfig in integrating code. +// +// t := release.TargetConfig{OS: "linux", Arch: "arm64"} type TargetConfig struct { // OS is the target operating system (e.g., "linux", "darwin", "windows"). OS string `yaml:"os"` @@ -64,7 +70,8 @@ type TargetConfig struct { } // PublisherConfig holds configuration for a publisher. -// Usage example: declare a value of type release.PublisherConfig in integrating code. +// +// cfg.Publishers = []release.PublisherConfig{{Type: "github", Draft: false}} type PublisherConfig struct { // Type is the publisher type (e.g., "github", "linuxkit", "docker"). Type string `yaml:"type"` @@ -123,7 +130,8 @@ type PublisherConfig struct { } // OfficialConfig holds configuration for generating files for official repo PRs. -// Usage example: declare a value of type release.OfficialConfig in integrating code. +// +// pub.Official = &release.OfficialConfig{Enabled: true, Output: "dist/homebrew"} type OfficialConfig struct { // Enabled determines whether to generate files for official repos. Enabled bool `yaml:"enabled"` @@ -132,7 +140,8 @@ type OfficialConfig struct { } // SDKConfig holds SDK generation configuration. -// Usage example: declare a value of type release.SDKConfig in integrating code. +// +// cfg.SDK = &release.SDKConfig{Spec: "docs/openapi.yaml", Languages: []string{"typescript", "go"}} type SDKConfig struct { // Spec is the path to the OpenAPI spec file. Spec string `yaml:"spec,omitempty"` @@ -149,28 +158,32 @@ type SDKConfig struct { } // SDKPackageConfig holds package naming configuration. -// Usage example: declare a value of type release.SDKPackageConfig in integrating code. +// +// cfg.SDK.Package = release.SDKPackageConfig{Name: "@host-uk/api-client", Version: "1.0.0"} type SDKPackageConfig struct { Name string `yaml:"name,omitempty"` Version string `yaml:"version,omitempty"` } // SDKDiffConfig holds diff configuration. -// Usage example: declare a value of type release.SDKDiffConfig in integrating code. +// +// cfg.SDK.Diff = release.SDKDiffConfig{Enabled: true, FailOnBreaking: true} type SDKDiffConfig struct { Enabled bool `yaml:"enabled,omitempty"` FailOnBreaking bool `yaml:"fail_on_breaking,omitempty"` } // SDKPublishConfig holds monorepo publish configuration. -// Usage example: declare a value of type release.SDKPublishConfig in integrating code. +// +// cfg.SDK.Publish = release.SDKPublishConfig{Repo: "host-uk/ts", Path: "packages/api-client"} type SDKPublishConfig struct { Repo string `yaml:"repo,omitempty"` Path string `yaml:"path,omitempty"` } // ChangelogConfig holds changelog generation settings. -// Usage example: declare a value of type release.ChangelogConfig in integrating code. +// +// cfg.Changelog = release.ChangelogConfig{Include: []string{"feat", "fix"}, Exclude: []string{"chore"}} type ChangelogConfig struct { // Include specifies commit types to include in the changelog. Include []string `yaml:"include"` @@ -179,7 +192,8 @@ type ChangelogConfig struct { } // PublishersIter returns an iterator for the publishers. -// Usage example: call value.PublishersIter(...) from integrating code. +// +// for p := range cfg.PublishersIter() { fmt.Println(p.Type) } func (c *Config) PublishersIter() iter.Seq[PublisherConfig] { return func(yield func(PublisherConfig) bool) { for _, p := range c.Publishers { @@ -193,7 +207,8 @@ func (c *Config) PublishersIter() iter.Seq[PublisherConfig] { // LoadConfig loads release configuration from the .core/release.yaml file in the given directory. // If the config file does not exist, it returns DefaultConfig(). // Returns an error if the file exists but cannot be parsed. -// Usage example: call release.LoadConfig(...) from integrating code. +// +// cfg, err := release.LoadConfig(".") func LoadConfig(dir string) (*Config, error) { configPath := ax.Join(dir, ConfigDir, ConfigFileName) @@ -226,7 +241,8 @@ func LoadConfig(dir string) (*Config, error) { } // DefaultConfig returns sensible defaults for release configuration. -// Usage example: call release.DefaultConfig(...) from integrating code. +// +// cfg := release.DefaultConfig() func DefaultConfig() *Config { return &Config{ Version: 1, @@ -279,25 +295,29 @@ func applyDefaults(cfg *Config) { } // SetProjectDir sets the project directory on the config. -// Usage example: call value.SetProjectDir(...) from integrating code. +// +// cfg.SetProjectDir("/home/user/my-project") func (c *Config) SetProjectDir(dir string) { c.projectDir = dir } // SetVersion sets the version override on the config. -// Usage example: call value.SetVersion(...) from integrating code. +// +// cfg.SetVersion("v1.2.3") func (c *Config) SetVersion(version string) { c.version = version } // ConfigPath returns the path to the release config file for a given directory. -// Usage example: call release.ConfigPath(...) from integrating code. +// +// path := release.ConfigPath("/home/user/my-project") // → "/home/user/my-project/.core/release.yaml" func ConfigPath(dir string) string { return ax.Join(dir, ConfigDir, ConfigFileName) } // ConfigExists checks if a release config file exists in the given directory. -// Usage example: call release.ConfigExists(...) from integrating code. +// +// if release.ConfigExists(".") { ... } func ConfigExists(dir string) bool { configPath := ConfigPath(dir) absPath, err := ax.Abs(configPath) @@ -308,19 +328,22 @@ func ConfigExists(dir string) bool { } // GetRepository returns the repository from the config. -// Usage example: call value.GetRepository(...) from integrating code. +// +// repo := cfg.GetRepository() // → "host-uk/core-build" func (c *Config) GetRepository() string { return c.Project.Repository } // GetProjectName returns the project name from the config. -// Usage example: call value.GetProjectName(...) from integrating code. +// +// name := cfg.GetProjectName() // → "core-build" func (c *Config) GetProjectName() string { return c.Project.Name } // WriteConfig writes the config to the .core/release.yaml file. -// Usage example: call release.WriteConfig(...) from integrating code. +// +// err := release.WriteConfig(cfg, ".") func WriteConfig(cfg *Config, dir string) error { configPath := ConfigPath(dir) diff --git a/pkg/release/publishers/aur.go b/pkg/release/publishers/aur.go index 3c3adab..ef66830 100644 --- a/pkg/release/publishers/aur.go +++ b/pkg/release/publishers/aur.go @@ -18,7 +18,8 @@ import ( var aurTemplates embed.FS // AURConfig holds AUR-specific configuration. -// Usage example: declare a value of type publishers.AURConfig in integrating code. +// +// cfg := publishers.AURConfig{Package: "core-build", Maintainer: "Jane Doe "} type AURConfig struct { // Package is the AUR package name. Package string @@ -29,23 +30,27 @@ type AURConfig struct { } // AURPublisher publishes releases to AUR. -// Usage example: declare a value of type publishers.AURPublisher in integrating code. +// +// pub := publishers.NewAURPublisher() type AURPublisher struct{} // NewAURPublisher creates a new AUR publisher. -// Usage example: call publishers.NewAURPublisher(...) from integrating code. +// +// pub := publishers.NewAURPublisher() func NewAURPublisher() *AURPublisher { return &AURPublisher{} } // Name returns the publisher's identifier. -// Usage example: call value.Name(...) from integrating code. +// +// name := pub.Name() // → "aur" func (p *AURPublisher) Name() string { return "aur" } // Publish publishes the release to AUR. -// Usage example: call value.Publish(...) from integrating code. +// +// err := pub.Publish(ctx, rel, pubCfg, relCfg, false) func (p *AURPublisher) Publish(ctx context.Context, release *Release, pubCfg PublisherConfig, relCfg ReleaseConfig, dryRun bool) error { cfg := p.parseConfig(pubCfg, relCfg) diff --git a/pkg/release/publishers/chocolatey.go b/pkg/release/publishers/chocolatey.go index 8754860..f525694 100644 --- a/pkg/release/publishers/chocolatey.go +++ b/pkg/release/publishers/chocolatey.go @@ -19,7 +19,8 @@ import ( var chocolateyTemplates embed.FS // ChocolateyConfig holds Chocolatey-specific configuration. -// Usage example: declare a value of type publishers.ChocolateyConfig in integrating code. +// +// cfg := publishers.ChocolateyConfig{Package: "core-build", Push: true} type ChocolateyConfig struct { // Package is the Chocolatey package name. Package string @@ -30,23 +31,27 @@ type ChocolateyConfig struct { } // ChocolateyPublisher publishes releases to Chocolatey. -// Usage example: declare a value of type publishers.ChocolateyPublisher in integrating code. +// +// pub := publishers.NewChocolateyPublisher() type ChocolateyPublisher struct{} // NewChocolateyPublisher creates a new Chocolatey publisher. -// Usage example: call publishers.NewChocolateyPublisher(...) from integrating code. +// +// pub := publishers.NewChocolateyPublisher() func NewChocolateyPublisher() *ChocolateyPublisher { return &ChocolateyPublisher{} } // Name returns the publisher's identifier. -// Usage example: call value.Name(...) from integrating code. +// +// name := pub.Name() // → "chocolatey" func (p *ChocolateyPublisher) Name() string { return "chocolatey" } // Publish publishes the release to Chocolatey. -// Usage example: call value.Publish(...) from integrating code. +// +// err := pub.Publish(ctx, rel, pubCfg, relCfg, false) func (p *ChocolateyPublisher) Publish(ctx context.Context, release *Release, pubCfg PublisherConfig, relCfg ReleaseConfig, dryRun bool) error { cfg := p.parseConfig(pubCfg, relCfg) diff --git a/pkg/release/publishers/docker.go b/pkg/release/publishers/docker.go index 3ec9593..1d4b159 100644 --- a/pkg/release/publishers/docker.go +++ b/pkg/release/publishers/docker.go @@ -10,7 +10,8 @@ import ( ) // DockerConfig holds configuration for the Docker publisher. -// Usage example: declare a value of type publishers.DockerConfig in integrating code. +// +// cfg := publishers.DockerConfig{Registry: "ghcr.io", Image: "host-uk/core-build", Platforms: []string{"linux/amd64", "linux/arm64"}} type DockerConfig struct { // Registry is the container registry (default: ghcr.io). Registry string `yaml:"registry"` @@ -27,23 +28,27 @@ type DockerConfig struct { } // DockerPublisher builds and publishes Docker images. -// Usage example: declare a value of type publishers.DockerPublisher in integrating code. +// +// pub := publishers.NewDockerPublisher() type DockerPublisher struct{} // NewDockerPublisher creates a new Docker publisher. -// Usage example: call publishers.NewDockerPublisher(...) from integrating code. +// +// pub := publishers.NewDockerPublisher() func NewDockerPublisher() *DockerPublisher { return &DockerPublisher{} } // Name returns the publisher's identifier. -// Usage example: call value.Name(...) from integrating code. +// +// name := pub.Name() // → "docker" func (p *DockerPublisher) Name() string { return "docker" } // Publish builds and pushes Docker images. -// Usage example: call value.Publish(...) from integrating code. +// +// err := pub.Publish(ctx, rel, pubCfg, relCfg, false) func (p *DockerPublisher) Publish(ctx context.Context, release *Release, pubCfg PublisherConfig, relCfg ReleaseConfig, dryRun bool) error { // Parse Docker-specific config from publisher config dockerCfg := p.parseConfig(pubCfg, relCfg, release.ProjectDir) diff --git a/pkg/release/publishers/github.go b/pkg/release/publishers/github.go index 15f7c22..9c5c378 100644 --- a/pkg/release/publishers/github.go +++ b/pkg/release/publishers/github.go @@ -10,24 +10,27 @@ import ( ) // GitHubPublisher publishes releases to GitHub using the gh CLI. -// Usage example: declare a value of type publishers.GitHubPublisher in integrating code. +// +// pub := publishers.NewGitHubPublisher() type GitHubPublisher struct{} // NewGitHubPublisher creates a new GitHub publisher. -// Usage example: call publishers.NewGitHubPublisher(...) from integrating code. +// +// pub := publishers.NewGitHubPublisher() func NewGitHubPublisher() *GitHubPublisher { return &GitHubPublisher{} } // Name returns the publisher's identifier. -// Usage example: call value.Name(...) from integrating code. +// +// name := pub.Name() // → "github" func (p *GitHubPublisher) Name() string { return "github" } -// Publish publishes the release to GitHub. -// Uses the gh CLI for creating releases and uploading assets. -// Usage example: call value.Publish(...) from integrating code. +// Publish publishes the release to GitHub using the gh CLI. +// +// err := pub.Publish(ctx, rel, pubCfg, relCfg, false) // dryRun=true to preview func (p *GitHubPublisher) Publish(ctx context.Context, release *Release, pubCfg PublisherConfig, relCfg ReleaseConfig, dryRun bool) error { // Determine repository repo := "" @@ -218,7 +221,8 @@ func parseGitHubRepo(url string) (string, error) { // UploadArtifact uploads a single artifact to an existing release. // This can be used to add artifacts to a release after creation. -// Usage example: call publishers.UploadArtifact(...) from integrating code. +// +// err := publishers.UploadArtifact(ctx, "host-uk/core-build", "v1.2.3", "dist/core-build_v1.2.3_linux_amd64.tar.gz") func UploadArtifact(ctx context.Context, repo, version, artifactPath string) error { ghCommand, err := resolveGhCli() if err != nil { @@ -233,7 +237,8 @@ func UploadArtifact(ctx context.Context, repo, version, artifactPath string) err } // DeleteRelease deletes a release by tag name. -// Usage example: call publishers.DeleteRelease(...) from integrating code. +// +// err := publishers.DeleteRelease(ctx, "host-uk/core-build", "v1.2.3") func DeleteRelease(ctx context.Context, repo, version string) error { ghCommand, err := resolveGhCli() if err != nil { @@ -248,7 +253,8 @@ func DeleteRelease(ctx context.Context, repo, version string) error { } // ReleaseExists checks if a release exists for the given version. -// Usage example: call publishers.ReleaseExists(...) from integrating code. +// +// exists := publishers.ReleaseExists(ctx, "host-uk/core-build", "v1.2.3") func ReleaseExists(ctx context.Context, repo, version string) bool { ghCommand, err := resolveGhCli() if err != nil { diff --git a/pkg/release/publishers/homebrew.go b/pkg/release/publishers/homebrew.go index cb77299..3c8b2f5 100644 --- a/pkg/release/publishers/homebrew.go +++ b/pkg/release/publishers/homebrew.go @@ -18,7 +18,8 @@ import ( var homebrewTemplates embed.FS // HomebrewConfig holds Homebrew-specific configuration. -// Usage example: declare a value of type publishers.HomebrewConfig in integrating code. +// +// cfg := publishers.HomebrewConfig{Tap: "host-uk/homebrew-tap", Formula: "core-build"} type HomebrewConfig struct { // Tap is the Homebrew tap repository (e.g., "host-uk/homebrew-tap"). Tap string @@ -29,7 +30,8 @@ type HomebrewConfig struct { } // OfficialConfig holds configuration for generating files for official repo PRs. -// Usage example: declare a value of type publishers.OfficialConfig in integrating code. +// +// cfg.Official = &publishers.OfficialConfig{Enabled: true, Output: "dist/homebrew"} type OfficialConfig struct { // Enabled determines whether to generate files for official repos. Enabled bool @@ -38,23 +40,27 @@ type OfficialConfig struct { } // HomebrewPublisher publishes releases to Homebrew. -// Usage example: declare a value of type publishers.HomebrewPublisher in integrating code. +// +// pub := publishers.NewHomebrewPublisher() type HomebrewPublisher struct{} // NewHomebrewPublisher creates a new Homebrew publisher. -// Usage example: call publishers.NewHomebrewPublisher(...) from integrating code. +// +// pub := publishers.NewHomebrewPublisher() func NewHomebrewPublisher() *HomebrewPublisher { return &HomebrewPublisher{} } // Name returns the publisher's identifier. -// Usage example: call value.Name(...) from integrating code. +// +// name := pub.Name() // → "homebrew" func (p *HomebrewPublisher) Name() string { return "homebrew" } // Publish publishes the release to Homebrew. -// Usage example: call value.Publish(...) from integrating code. +// +// err := pub.Publish(ctx, rel, pubCfg, relCfg, false) func (p *HomebrewPublisher) Publish(ctx context.Context, release *Release, pubCfg PublisherConfig, relCfg ReleaseConfig, dryRun bool) error { // Parse config cfg := p.parseConfig(pubCfg, relCfg) @@ -127,7 +133,8 @@ type homebrewTemplateData struct { } // ChecksumMap holds checksums for different platform/arch combinations. -// Usage example: declare a value of type publishers.ChecksumMap in integrating code. +// +// data.Checksums.LinuxAMD64 = "abc123..." type ChecksumMap struct { DarwinAmd64 string DarwinArm64 string diff --git a/pkg/release/publishers/linuxkit.go b/pkg/release/publishers/linuxkit.go index e0175ac..fed9428 100644 --- a/pkg/release/publishers/linuxkit.go +++ b/pkg/release/publishers/linuxkit.go @@ -10,7 +10,8 @@ import ( ) // LinuxKitConfig holds configuration for the LinuxKit publisher. -// Usage example: declare a value of type publishers.LinuxKitConfig in integrating code. +// +// cfg := publishers.LinuxKitConfig{Config: ".core/node.yaml", Formats: []string{"iso", "qcow2"}} type LinuxKitConfig struct { // Config is the path to the LinuxKit YAML configuration file. Config string `yaml:"config"` @@ -24,23 +25,27 @@ type LinuxKitConfig struct { } // LinuxKitPublisher builds and publishes LinuxKit images. -// Usage example: declare a value of type publishers.LinuxKitPublisher in integrating code. +// +// pub := publishers.NewLinuxKitPublisher() type LinuxKitPublisher struct{} // NewLinuxKitPublisher creates a new LinuxKit publisher. -// Usage example: call publishers.NewLinuxKitPublisher(...) from integrating code. +// +// pub := publishers.NewLinuxKitPublisher() func NewLinuxKitPublisher() *LinuxKitPublisher { return &LinuxKitPublisher{} } // Name returns the publisher's identifier. -// Usage example: call value.Name(...) from integrating code. +// +// name := pub.Name() // → "linuxkit" func (p *LinuxKitPublisher) Name() string { return "linuxkit" } // Publish builds LinuxKit images and uploads them to the GitHub release. -// Usage example: call value.Publish(...) from integrating code. +// +// err := pub.Publish(ctx, rel, pubCfg, relCfg, false) func (p *LinuxKitPublisher) Publish(ctx context.Context, release *Release, pubCfg PublisherConfig, relCfg ReleaseConfig, dryRun bool) error { linuxkitCommand, err := resolveLinuxKitCli() if err != nil { diff --git a/pkg/release/publishers/npm.go b/pkg/release/publishers/npm.go index 0060e34..5ed8b9f 100644 --- a/pkg/release/publishers/npm.go +++ b/pkg/release/publishers/npm.go @@ -17,7 +17,8 @@ import ( var npmTemplates embed.FS // NpmConfig holds npm-specific configuration. -// Usage example: declare a value of type publishers.NpmConfig in integrating code. +// +// cfg := publishers.NpmConfig{Package: "@host-uk/core-build", Access: "public"} type NpmConfig struct { // Package is the npm package name (e.g., "@host-uk/core"). Package string @@ -26,24 +27,27 @@ type NpmConfig struct { } // NpmPublisher publishes releases to npm using the binary wrapper pattern. -// Usage example: declare a value of type publishers.NpmPublisher in integrating code. +// +// pub := publishers.NewNpmPublisher() type NpmPublisher struct{} // NewNpmPublisher creates a new npm publisher. -// Usage example: call publishers.NewNpmPublisher(...) from integrating code. +// +// pub := publishers.NewNpmPublisher() func NewNpmPublisher() *NpmPublisher { return &NpmPublisher{} } // Name returns the publisher's identifier. -// Usage example: call value.Name(...) from integrating code. +// +// name := pub.Name() // → "npm" func (p *NpmPublisher) Name() string { return "npm" } -// Publish publishes the release to npm. -// It generates a binary wrapper package that downloads the correct platform binary on postinstall. -// Usage example: call value.Publish(...) from integrating code. +// Publish publishes the release to npm as a binary wrapper package. +// +// err := pub.Publish(ctx, rel, pubCfg, relCfg, false) func (p *NpmPublisher) Publish(ctx context.Context, release *Release, pubCfg PublisherConfig, relCfg ReleaseConfig, dryRun bool) error { // Parse npm config npmCfg := p.parseConfig(pubCfg, relCfg) diff --git a/pkg/release/publishers/publisher.go b/pkg/release/publishers/publisher.go index 724b5d6..3512f84 100644 --- a/pkg/release/publishers/publisher.go +++ b/pkg/release/publishers/publisher.go @@ -9,7 +9,8 @@ import ( ) // Release represents a release to be published. -// Usage example: declare a value of type publishers.Release in integrating code. +// +// rel := publishers.NewRelease("v1.2.3", artifacts, changelog, ".", io.Local) type Release struct { // Version is the semantic version string (e.g., "v1.2.3"). Version string @@ -24,7 +25,8 @@ type Release struct { } // PublisherConfig holds configuration for a publisher. -// Usage example: declare a value of type publishers.PublisherConfig in integrating code. +// +// cfg := publishers.NewPublisherConfig("github", false, false, nil) type PublisherConfig struct { // Type is the publisher type (e.g., "github", "linuxkit", "docker"). Type string @@ -37,14 +39,16 @@ type PublisherConfig struct { } // ReleaseConfig holds release configuration needed by publishers. -// Usage example: declare a value of type publishers.ReleaseConfig in integrating code. +// +// var relCfg publishers.ReleaseConfig = cfg // *release.Config implements this interface type ReleaseConfig interface { GetRepository() string GetProjectName() string } // Publisher defines the interface for release publishers. -// Usage example: declare a value of type publishers.Publisher in integrating code. +// +// var pub publishers.Publisher = publishers.NewGitHubPublisher() type Publisher interface { // Name returns the publisher's identifier. Name() string @@ -55,7 +59,8 @@ type Publisher interface { // NewRelease creates a Release from the release package's Release type. // This is a helper to convert between packages. -// Usage example: call publishers.NewRelease(...) from integrating code. +// +// rel := publishers.NewRelease("v1.2.3", artifacts, changelog, ".", io.Local) func NewRelease(version string, artifacts []build.Artifact, changelog, projectDir string, fs io.Medium) *Release { return &Release{ Version: version, @@ -67,7 +72,8 @@ func NewRelease(version string, artifacts []build.Artifact, changelog, projectDi } // NewPublisherConfig creates a PublisherConfig. -// Usage example: call publishers.NewPublisherConfig(...) from integrating code. +// +// cfg := publishers.NewPublisherConfig("github", false, false, nil) func NewPublisherConfig(pubType string, prerelease, draft bool, extended any) PublisherConfig { return PublisherConfig{ Type: pubType, diff --git a/pkg/release/publishers/scoop.go b/pkg/release/publishers/scoop.go index d009ecc..7b4451d 100644 --- a/pkg/release/publishers/scoop.go +++ b/pkg/release/publishers/scoop.go @@ -18,7 +18,8 @@ import ( var scoopTemplates embed.FS // ScoopConfig holds Scoop-specific configuration. -// Usage example: declare a value of type publishers.ScoopConfig in integrating code. +// +// cfg := publishers.ScoopConfig{Bucket: "host-uk/scoop-bucket"} type ScoopConfig struct { // Bucket is the Scoop bucket repository (e.g., "host-uk/scoop-bucket"). Bucket string @@ -27,23 +28,27 @@ type ScoopConfig struct { } // ScoopPublisher publishes releases to Scoop. -// Usage example: declare a value of type publishers.ScoopPublisher in integrating code. +// +// pub := publishers.NewScoopPublisher() type ScoopPublisher struct{} // NewScoopPublisher creates a new Scoop publisher. -// Usage example: call publishers.NewScoopPublisher(...) from integrating code. +// +// pub := publishers.NewScoopPublisher() func NewScoopPublisher() *ScoopPublisher { return &ScoopPublisher{} } // Name returns the publisher's identifier. -// Usage example: call value.Name(...) from integrating code. +// +// name := pub.Name() // → "scoop" func (p *ScoopPublisher) Name() string { return "scoop" } // Publish publishes the release to Scoop. -// Usage example: call value.Publish(...) from integrating code. +// +// err := pub.Publish(ctx, rel, pubCfg, relCfg, false) func (p *ScoopPublisher) Publish(ctx context.Context, release *Release, pubCfg PublisherConfig, relCfg ReleaseConfig, dryRun bool) error { cfg := p.parseConfig(pubCfg, relCfg) diff --git a/pkg/release/release.go b/pkg/release/release.go index 980da51..5fdef66 100644 --- a/pkg/release/release.go +++ b/pkg/release/release.go @@ -16,7 +16,8 @@ import ( ) // Release represents a release with its version, artifacts, and changelog. -// Usage example: declare a value of type release.Release in integrating code. +// +// rel, err := release.Publish(ctx, cfg, false) type Release struct { // Version is the semantic version string (e.g., "v1.2.3"). Version string @@ -32,8 +33,8 @@ type Release struct { // Publish publishes pre-built artifacts from dist/ to configured targets. // Use this after `core build` to separate build and publish concerns. -// If dryRun is true, it will show what would be done without actually publishing. -// Usage example: call release.Publish(...) from integrating code. +// +// rel, err := release.Publish(ctx, cfg, false) // dryRun=true to preview func Publish(ctx context.Context, cfg *Config, dryRun bool) (*Release, error) { if cfg == nil { return nil, coreerr.E("release.Publish", "config is nil", nil) @@ -146,9 +147,9 @@ func findArtifacts(m io.Medium, distDir string) ([]build.Artifact, error) { // Run executes the full release process: determine version, build artifacts, // generate changelog, and publish to configured targets. -// For separated concerns, prefer using `core build` then `core ci` (Publish). -// If dryRun is true, it will show what would be done without actually publishing. -// Usage example: call release.Run(...) from integrating code. +// For separated concerns, prefer `core build` then `core ci` (Publish). +// +// rel, err := release.Run(ctx, cfg, false) // dryRun=true to preview func Run(ctx context.Context, cfg *Config, dryRun bool) (*Release, error) { if cfg == nil { return nil, coreerr.E("release.Run", "config is nil", nil) diff --git a/pkg/release/sdk.go b/pkg/release/sdk.go index 6eac536..270c21b 100644 --- a/pkg/release/sdk.go +++ b/pkg/release/sdk.go @@ -10,7 +10,8 @@ import ( ) // SDKRelease holds the result of an SDK release. -// Usage example: declare a value of type release.SDKRelease in integrating code. +// +// rel, err := release.RunSDK(ctx, cfg, false) type SDKRelease struct { // Version is the SDK version. Version string @@ -21,8 +22,8 @@ type SDKRelease struct { } // RunSDK executes SDK-only release: diff check + generate. -// If dryRun is true, it shows what would be done without generating. -// Usage example: call release.RunSDK(...) from integrating code. +// +// rel, err := release.RunSDK(ctx, cfg, false) // dryRun=true to preview func RunSDK(ctx context.Context, cfg *Config, dryRun bool) (*SDKRelease, error) { if cfg == nil { return nil, coreerr.E("release.RunSDK", "config is nil", nil) diff --git a/pkg/release/version.go b/pkg/release/version.go index 0d7bfe6..f0d5057 100644 --- a/pkg/release/version.go +++ b/pkg/release/version.go @@ -20,7 +20,7 @@ var semverRegex = regexp.MustCompile(`^v?(\d+)\.(\d+)\.(\d+)(?:-([a-zA-Z0-9.-]+) // 2. Most recent tag + increment patch // 3. Default to v0.0.1 if no tags exist // -// Usage example: call release.DetermineVersion(...) from integrating code. +// version, err := release.DetermineVersion(".") // → "v1.2.4" func DetermineVersion(dir string) (string, error) { return DetermineVersionWithContext(context.Background(), dir) } @@ -31,7 +31,7 @@ func DetermineVersion(dir string) (string, error) { // 2. Most recent tag + increment patch // 3. Default to v0.0.1 if no tags exist // -// Usage example: call release.DetermineVersionWithContext(...) from integrating code. +// version, err := release.DetermineVersionWithContext(ctx, ".") // → "v1.2.4" func DetermineVersionWithContext(ctx context.Context, dir string) (string, error) { // Check if HEAD has a tag headTag, err := getTagOnHeadWithContext(ctx, dir) @@ -57,12 +57,11 @@ func DetermineVersionWithContext(ctx context.Context, dir string) (string, error } // IncrementVersion increments the patch version of a semver string. -// Examples: -// - "v1.2.3" -> "v1.2.4" -// - "1.2.3" -> "v1.2.4" -// - "v1.2.3-alpha" -> "v1.2.4" (strips prerelease) +// - "v1.2.3" → "v1.2.4" +// - "1.2.3" → "v1.2.4" +// - "v1.2.3-alpha" → "v1.2.4" (strips prerelease) // -// Usage example: call release.IncrementVersion(...) from integrating code. +// next := release.IncrementVersion("v1.2.3") // → "v1.2.4" func IncrementVersion(current string) string { matches := semverRegex.FindStringSubmatch(current) if matches == nil { @@ -81,11 +80,10 @@ func IncrementVersion(current string) string { } // IncrementMinor increments the minor version of a semver string. -// Examples: -// - "v1.2.3" -> "v1.3.0" -// - "1.2.3" -> "v1.3.0" +// - "v1.2.3" → "v1.3.0" +// - "1.2.3" → "v1.3.0" // -// Usage example: call release.IncrementMinor(...) from integrating code. +// next := release.IncrementMinor("v1.2.3") // → "v1.3.0" func IncrementMinor(current string) string { matches := semverRegex.FindStringSubmatch(current) if matches == nil { @@ -102,11 +100,10 @@ func IncrementMinor(current string) string { } // IncrementMajor increments the major version of a semver string. -// Examples: -// - "v1.2.3" -> "v2.0.0" -// - "1.2.3" -> "v2.0.0" +// - "v1.2.3" → "v2.0.0" +// - "1.2.3" → "v2.0.0" // -// Usage example: call release.IncrementMajor(...) from integrating code. +// next := release.IncrementMajor("v1.2.3") // → "v2.0.0" func IncrementMajor(current string) string { matches := semverRegex.FindStringSubmatch(current) if matches == nil { @@ -123,7 +120,8 @@ func IncrementMajor(current string) string { // ParseVersion parses a semver string into its components. // Returns (major, minor, patch, prerelease, build, error). -// Usage example: call release.ParseVersion(...) from integrating code. +// +// major, minor, patch, pre, build, err := release.ParseVersion("v1.2.3-alpha+001") func ParseVersion(version string) (int, int, int, string, string, error) { matches := semverRegex.FindStringSubmatch(version) if matches == nil { @@ -140,7 +138,8 @@ func ParseVersion(version string) (int, int, int, string, string, error) { } // ValidateVersion checks if a string is a valid semver. -// Usage example: call release.ValidateVersion(...) from integrating code. +// +// if release.ValidateVersion("v1.2.3") { ... } func ValidateVersion(version string) bool { return semverRegex.MatchString(version) } @@ -170,13 +169,9 @@ func getLatestTagWithContext(ctx context.Context, dir string) (string, error) { } // CompareVersions compares two semver strings. -// Returns: +// Returns -1 if a < b, 0 if a == b, 1 if a > b. // -// -1 if a < b -// 0 if a == b -// 1 if a > b -// -// Usage example: call release.CompareVersions(...) from integrating code. +// result := release.CompareVersions("v1.2.3", "v1.2.4") // → -1 func CompareVersions(a, b string) int { aMajor, aMinor, aPatch, _, _, errA := ParseVersion(a) bMajor, bMinor, bPatch, _, _, errB := ParseVersion(b) diff --git a/pkg/sdk/detect.go b/pkg/sdk/detect.go index cb40a4e..df0deb4 100644 --- a/pkg/sdk/detect.go +++ b/pkg/sdk/detect.go @@ -22,7 +22,8 @@ var commonSpecPaths = []string{ // DetectSpec finds the OpenAPI spec file. // Priority: config path -> common paths -> Laravel Scramble. -// Usage example: call value.DetectSpec(...) from integrating code. +// +// path, err := s.DetectSpec() // → "api/openapi.yaml", nil func (s *SDK) DetectSpec() (string, error) { // 1. Check configured path if s.config.Spec != "" { diff --git a/pkg/sdk/diff.go b/pkg/sdk/diff.go index 5751533..b7bf73d 100644 --- a/pkg/sdk/diff.go +++ b/pkg/sdk/diff.go @@ -10,7 +10,8 @@ import ( ) // DiffResult holds the result of comparing two OpenAPI specs. -// Usage example: declare a value of type sdk.DiffResult in integrating code. +// +// result, err := sdk.Diff("docs/openapi.v1.yaml", "docs/openapi.yaml") type DiffResult struct { // Breaking is true if breaking changes were detected. Breaking bool @@ -21,7 +22,8 @@ type DiffResult struct { } // Diff compares two OpenAPI specs and detects breaking changes. -// Usage example: call sdk.Diff(...) from integrating code. +// +// result, err := sdk.Diff("docs/openapi.v1.yaml", "docs/openapi.yaml") func Diff(basePath, revisionPath string) (*DiffResult, error) { loader := openapi3.NewLoader() loader.IsExternalRefsAllowed = true @@ -74,8 +76,9 @@ func Diff(basePath, revisionPath string) (*DiffResult, error) { } // DiffExitCode returns the exit code for CI integration. -// 0 = no breaking changes, 1 = breaking changes, 2 = error -// Usage example: call sdk.DiffExitCode(...) from integrating code. +// 0 = no breaking changes, 1 = breaking changes, 2 = error. +// +// os.Exit(sdk.DiffExitCode(sdk.Diff("old.yaml", "new.yaml"))) func DiffExitCode(result *DiffResult, err error) int { if err != nil { return 2 diff --git a/pkg/sdk/generators/generator.go b/pkg/sdk/generators/generator.go index 340cabc..9ad6aad 100644 --- a/pkg/sdk/generators/generator.go +++ b/pkg/sdk/generators/generator.go @@ -12,7 +12,8 @@ import ( ) // Options holds common generation options. -// Usage example: declare a value of type generators.Options in integrating code. +// +// opts := generators.Options{SpecPath: "docs/openapi.yaml", OutputDir: "sdk/typescript", PackageName: "@host-uk/api-client", Version: "1.0.0"} type Options struct { // SpecPath is the path to the OpenAPI spec file. SpecPath string @@ -25,7 +26,9 @@ type Options struct { } // Generator defines the interface for SDK generators. -// Usage example: declare a value of type generators.Generator in integrating code. +// +// gen := generators.NewTypeScriptGenerator() +// err := gen.Generate(ctx, opts) type Generator interface { // Language returns the generator's target language identifier. Language() string @@ -41,13 +44,15 @@ type Generator interface { } // Registry holds available generators. -// Usage example: declare a value of type generators.Registry in integrating code. +// +// r := generators.NewRegistry() type Registry struct { generators map[string]Generator } // NewRegistry creates a registry with all available generators. -// Usage example: call generators.NewRegistry(...) from integrating code. +// +// r := generators.NewRegistry() func NewRegistry() *Registry { r := &Registry{ generators: make(map[string]Generator), @@ -57,20 +62,23 @@ func NewRegistry() *Registry { } // Get returns a generator by language. -// Usage example: call value.Get(...) from integrating code. +// +// gen, ok := r.Get("typescript") func (r *Registry) Get(lang string) (Generator, bool) { g, ok := r.generators[lang] return g, ok } // Register adds a generator to the registry. -// Usage example: call value.Register(...) from integrating code. +// +// r.Register(generators.NewTypeScriptGenerator()) func (r *Registry) Register(g Generator) { r.generators[g.Language()] = g } // Languages returns all registered language identifiers. -// Usage example: call value.Languages(...) from integrating code. +// +// langs := r.Languages() // → ["go", "php", "python", "typescript"] func (r *Registry) Languages() []string { var languages []string for lang := range r.LanguagesIter() { @@ -80,7 +88,8 @@ func (r *Registry) Languages() []string { } // LanguagesIter returns an iterator for all registered language identifiers. -// Usage example: call value.LanguagesIter(...) from integrating code. +// +// for lang := range r.LanguagesIter() { fmt.Println(lang) } func (r *Registry) LanguagesIter() iter.Seq[string] { return func(yield func(string) bool) { // Sort keys for deterministic iteration diff --git a/pkg/sdk/generators/go.go b/pkg/sdk/generators/go.go index 263f07c..1db5d32 100644 --- a/pkg/sdk/generators/go.go +++ b/pkg/sdk/generators/go.go @@ -9,36 +9,42 @@ import ( ) // GoGenerator generates Go SDKs from OpenAPI specs. -// Usage example: declare a value of type generators.GoGenerator in integrating code. +// +// g := generators.NewGoGenerator() type GoGenerator struct{} // NewGoGenerator creates a new Go generator. -// Usage example: call generators.NewGoGenerator(...) from integrating code. +// +// g := generators.NewGoGenerator() func NewGoGenerator() *GoGenerator { return &GoGenerator{} } // Language returns the generator's target language identifier. -// Usage example: call value.Language(...) from integrating code. +// +// lang := g.Language() // → "go" func (g *GoGenerator) Language() string { return "go" } // Available checks if generator dependencies are installed. -// Usage example: call value.Available(...) from integrating code. +// +// if g.Available() { err = g.Generate(ctx, opts) } func (g *GoGenerator) Available() bool { _, err := g.resolveNativeCli() return err == nil || dockerRuntimeAvailable() } // Install returns instructions for installing the generator. -// Usage example: call value.Install(...) from integrating code. +// +// fmt.Println(g.Install()) // → "go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest" func (g *GoGenerator) Install() string { return "go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest" } // Generate creates SDK from OpenAPI spec. -// Usage example: call value.Generate(...) from integrating code. +// +// err := g.Generate(ctx, generators.Options{SpecPath: "docs/openapi.yaml", OutputDir: "sdk/go"}) func (g *GoGenerator) Generate(ctx context.Context, opts Options) error { if err := ctx.Err(); err != nil { return coreerr.E("go.Generate", "generation cancelled", err) diff --git a/pkg/sdk/generators/php.go b/pkg/sdk/generators/php.go index 57e6cb7..10ae1f5 100644 --- a/pkg/sdk/generators/php.go +++ b/pkg/sdk/generators/php.go @@ -8,35 +8,41 @@ import ( ) // PHPGenerator generates PHP SDKs from OpenAPI specs. -// Usage example: declare a value of type generators.PHPGenerator in integrating code. +// +// g := generators.NewPHPGenerator() type PHPGenerator struct{} // NewPHPGenerator creates a new PHP generator. -// Usage example: call generators.NewPHPGenerator(...) from integrating code. +// +// g := generators.NewPHPGenerator() func NewPHPGenerator() *PHPGenerator { return &PHPGenerator{} } // Language returns the generator's target language identifier. -// Usage example: call value.Language(...) from integrating code. +// +// lang := g.Language() // → "php" func (g *PHPGenerator) Language() string { return "php" } -// Available checks if generator dependencies are installed. -// Usage example: call value.Available(...) from integrating code. +// Available checks if generator dependencies are installed (requires Docker). +// +// if g.Available() { err = g.Generate(ctx, opts) } func (g *PHPGenerator) Available() bool { return dockerRuntimeAvailable() } // Install returns instructions for installing the generator. -// Usage example: call value.Install(...) from integrating code. +// +// fmt.Println(g.Install()) // → "Docker is required for PHP SDK generation" func (g *PHPGenerator) Install() string { return "Docker is required for PHP SDK generation" } -// Generate creates SDK from OpenAPI spec. -// Usage example: call value.Generate(...) from integrating code. +// Generate creates SDK from OpenAPI spec (requires Docker). +// +// err := g.Generate(ctx, generators.Options{SpecPath: "docs/openapi.yaml", OutputDir: "sdk/php"}) func (g *PHPGenerator) Generate(ctx context.Context, opts Options) error { if err := ctx.Err(); err != nil { return coreerr.E("php.Generate", "generation cancelled", err) diff --git a/pkg/sdk/generators/python.go b/pkg/sdk/generators/python.go index 0c2f07f..f927a9e 100644 --- a/pkg/sdk/generators/python.go +++ b/pkg/sdk/generators/python.go @@ -8,36 +8,42 @@ import ( ) // PythonGenerator generates Python SDKs from OpenAPI specs. -// Usage example: declare a value of type generators.PythonGenerator in integrating code. +// +// g := generators.NewPythonGenerator() type PythonGenerator struct{} // NewPythonGenerator creates a new Python generator. -// Usage example: call generators.NewPythonGenerator(...) from integrating code. +// +// g := generators.NewPythonGenerator() func NewPythonGenerator() *PythonGenerator { return &PythonGenerator{} } // Language returns the generator's target language identifier. -// Usage example: call value.Language(...) from integrating code. +// +// lang := g.Language() // → "python" func (g *PythonGenerator) Language() string { return "python" } // Available checks if generator dependencies are installed. -// Usage example: call value.Available(...) from integrating code. +// +// if g.Available() { err = g.Generate(ctx, opts) } func (g *PythonGenerator) Available() bool { _, err := g.resolveNativeCli() return err == nil || dockerRuntimeAvailable() } // Install returns instructions for installing the generator. -// Usage example: call value.Install(...) from integrating code. +// +// fmt.Println(g.Install()) // → "pip install openapi-python-client" func (g *PythonGenerator) Install() string { return "pip install openapi-python-client" } // Generate creates SDK from OpenAPI spec. -// Usage example: call value.Generate(...) from integrating code. +// +// err := g.Generate(ctx, generators.Options{SpecPath: "docs/openapi.yaml", OutputDir: "sdk/python"}) func (g *PythonGenerator) Generate(ctx context.Context, opts Options) error { if err := ctx.Err(); err != nil { return coreerr.E("python.Generate", "generation cancelled", err) diff --git a/pkg/sdk/generators/typescript.go b/pkg/sdk/generators/typescript.go index 21e1a22..51e4356 100644 --- a/pkg/sdk/generators/typescript.go +++ b/pkg/sdk/generators/typescript.go @@ -8,35 +8,41 @@ import ( ) // TypeScriptGenerator generates TypeScript SDKs from OpenAPI specs. -// Usage example: declare a value of type generators.TypeScriptGenerator in integrating code. +// +// g := generators.NewTypeScriptGenerator() type TypeScriptGenerator struct{} // NewTypeScriptGenerator creates a new TypeScript generator. -// Usage example: call generators.NewTypeScriptGenerator(...) from integrating code. +// +// g := generators.NewTypeScriptGenerator() func NewTypeScriptGenerator() *TypeScriptGenerator { return &TypeScriptGenerator{} } // Language returns the generator's target language identifier. -// Usage example: call value.Language(...) from integrating code. +// +// lang := g.Language() // → "typescript" func (g *TypeScriptGenerator) Language() string { return "typescript" } // Available checks if generator dependencies are installed. -// Usage example: call value.Available(...) from integrating code. +// +// if g.Available() { err = g.Generate(ctx, opts) } func (g *TypeScriptGenerator) Available() bool { return g.nativeAvailable() || g.npxAvailable() || dockerRuntimeAvailable() } // Install returns instructions for installing the generator. -// Usage example: call value.Install(...) from integrating code. +// +// fmt.Println(g.Install()) // → "npm install -g openapi-typescript-codegen" func (g *TypeScriptGenerator) Install() string { return "npm install -g openapi-typescript-codegen" } // Generate creates SDK from OpenAPI spec. -// Usage example: call value.Generate(...) from integrating code. +// +// err := g.Generate(ctx, generators.Options{SpecPath: "docs/openapi.yaml", OutputDir: "sdk/typescript"}) func (g *TypeScriptGenerator) Generate(ctx context.Context, opts Options) error { if err := ctx.Err(); err != nil { return coreerr.E("typescript.Generate", "generation cancelled", err) diff --git a/pkg/sdk/generators/typescript_test.go b/pkg/sdk/generators/typescript_test.go index 1b1766b..8352992 100644 --- a/pkg/sdk/generators/typescript_test.go +++ b/pkg/sdk/generators/typescript_test.go @@ -2,10 +2,10 @@ package generators import ( "context" - "os" "testing" "time" + "dappco.re/go/core" "dappco.re/go/core/build/internal/ax" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -99,7 +99,7 @@ func TestTypeScript_TypeScriptGeneratorNpxAvailabilityUsesProbeTimeout_Bad(t *te func TestTypeScript_TypeScriptGeneratorGenerate_Good(t *testing.T) { commandDir := t.TempDir() writeFakeTypeScriptGenerator(t, commandDir) - t.Setenv("PATH", commandDir+string(os.PathListSeparator)+os.Getenv("PATH")) + t.Setenv("PATH", commandDir+core.Env("PS")+core.Env("PATH")) g := NewTypeScriptGenerator() require.True(t, g.Available()) diff --git a/pkg/sdk/sdk.go b/pkg/sdk/sdk.go index f2f6711..433ae8e 100644 --- a/pkg/sdk/sdk.go +++ b/pkg/sdk/sdk.go @@ -11,7 +11,8 @@ import ( ) // Config holds SDK generation configuration from .core/release.yaml. -// Usage example: declare a value of type sdk.Config in integrating code. +// +// cfg := &sdk.Config{Languages: []string{"typescript"}, Output: "sdk"} type Config struct { // Spec is the path to the OpenAPI spec file (auto-detected if empty). Spec string `yaml:"spec,omitempty"` @@ -28,7 +29,8 @@ type Config struct { } // PackageConfig holds package naming configuration. -// Usage example: declare a value of type sdk.PackageConfig in integrating code. +// +// cfg.Package = sdk.PackageConfig{Name: "@host-uk/api-client", Version: "1.0.0"} type PackageConfig struct { // Name is the base package name. Name string `yaml:"name,omitempty"` @@ -37,7 +39,8 @@ type PackageConfig struct { } // DiffConfig holds breaking change detection configuration. -// Usage example: declare a value of type sdk.DiffConfig in integrating code. +// +// cfg.Diff = sdk.DiffConfig{Enabled: true, FailOnBreaking: true} type DiffConfig struct { // Enabled determines whether to run diff checks. Enabled bool `yaml:"enabled,omitempty"` @@ -46,7 +49,8 @@ type DiffConfig struct { } // PublishConfig holds monorepo publishing configuration. -// Usage example: declare a value of type sdk.PublishConfig in integrating code. +// +// cfg.Publish = sdk.PublishConfig{Repo: "host-uk/ts", Path: "packages/api-client"} type PublishConfig struct { // Repo is the SDK monorepo (e.g., "myorg/sdks"). Repo string `yaml:"repo,omitempty"` @@ -55,7 +59,8 @@ type PublishConfig struct { } // SDK orchestrates OpenAPI SDK generation. -// Usage example: declare a value of type sdk.SDK in integrating code. +// +// s := sdk.New(".", cfg) type SDK struct { config *Config projectDir string @@ -63,7 +68,8 @@ type SDK struct { } // New creates a new SDK instance. -// Usage example: call sdk.New(...) from integrating code. +// +// s := sdk.New(".", &sdk.Config{Languages: []string{"typescript"}, Output: "sdk"}) func New(projectDir string, config *Config) *SDK { if config == nil { config = DefaultConfig() @@ -76,7 +82,8 @@ func New(projectDir string, config *Config) *SDK { // SetVersion sets the SDK version for generation. // This updates both the internal version field and the config's Package.Version. -// Usage example: call value.SetVersion(...) from integrating code. +// +// s.SetVersion("v1.2.3") func (s *SDK) SetVersion(version string) { s.version = version if s.config != nil { @@ -85,7 +92,8 @@ func (s *SDK) SetVersion(version string) { } // DefaultConfig returns sensible defaults for SDK configuration. -// Usage example: call sdk.DefaultConfig(...) from integrating code. +// +// cfg := sdk.DefaultConfig() // languages: typescript, python, go, php func DefaultConfig() *Config { return &Config{ Languages: []string{"typescript", "python", "go", "php"}, @@ -98,7 +106,8 @@ func DefaultConfig() *Config { } // Generate generates SDKs for all configured languages. -// Usage example: call value.Generate(...) from integrating code. +// +// err := s.Generate(ctx) // generates sdk/typescript/, sdk/python/, etc. func (s *SDK) Generate(ctx context.Context) error { // Generate for each language for _, lang := range s.config.Languages { @@ -111,7 +120,8 @@ func (s *SDK) Generate(ctx context.Context) error { } // GenerateLanguage generates SDK for a specific language. -// Usage example: call value.GenerateLanguage(...) from integrating code. +// +// err := s.GenerateLanguage(ctx, "typescript") // generates sdk/typescript/ func (s *SDK) GenerateLanguage(ctx context.Context, lang string) error { specPath, err := s.DetectSpec() if err != nil {