fix(ax): replace banned os imports and add usage example comments
- Remove `os` import from internal/ax/ax.go; replace os.Getwd() with
syscall.Getwd(), os.MkdirAll() with coreio.Local.EnsureDir(), and
os.Chmod() with syscall.Chmod()
- Remove `os` import from pkg/sdk/generators/typescript_test.go;
replace os.PathListSeparator and os.Getenv() with core.Env("PS")
and core.Env("PATH")
- Replace all "Usage example: call/declare ... from integrating code"
placeholder comments with concrete code examples across 45 files
covering build, release, sdk, signing, publishers, builders, and cmd
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
1573807fc4
commit
febe858942
45 changed files with 507 additions and 288 deletions
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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{
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <jane@example.com>"}
|
||||
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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 != "" {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue