2026-01-28 17:59:02 +00:00
|
|
|
// Package build provides project type detection and cross-compilation for the Core build system.
|
|
|
|
|
// This file handles configuration loading from .core/build.yaml files.
|
|
|
|
|
package build
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"path/filepath"
|
|
|
|
|
|
2026-01-29 02:52:12 +00:00
|
|
|
"github.com/host-uk/core/pkg/build/signing"
|
2026-02-05 10:26:44 +00:00
|
|
|
"github.com/host-uk/core/pkg/config"
|
2026-02-04 17:59:10 +00:00
|
|
|
"github.com/host-uk/core/pkg/io"
|
2026-01-28 17:59:02 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// ConfigFileName is the name of the build configuration file.
|
|
|
|
|
const ConfigFileName = "build.yaml"
|
|
|
|
|
|
|
|
|
|
// ConfigDir is the directory where build configuration is stored.
|
|
|
|
|
const ConfigDir = ".core"
|
|
|
|
|
|
|
|
|
|
// BuildConfig holds the complete build configuration loaded from .core/build.yaml.
|
|
|
|
|
// This is distinct from Config which holds runtime build parameters.
|
|
|
|
|
type BuildConfig struct {
|
|
|
|
|
// Version is the config file format version.
|
2026-02-05 10:26:44 +00:00
|
|
|
Version int `yaml:"version" mapstructure:"version"`
|
2026-01-28 17:59:02 +00:00
|
|
|
// Project contains project metadata.
|
2026-02-05 10:26:44 +00:00
|
|
|
Project Project `yaml:"project" mapstructure:"project"`
|
2026-01-28 17:59:02 +00:00
|
|
|
// Build contains build settings.
|
2026-02-05 10:26:44 +00:00
|
|
|
Build Build `yaml:"build" mapstructure:"build"`
|
2026-01-28 17:59:02 +00:00
|
|
|
// Targets defines the build targets.
|
2026-02-05 10:26:44 +00:00
|
|
|
Targets []TargetConfig `yaml:"targets" mapstructure:"targets"`
|
2026-01-29 02:52:12 +00:00
|
|
|
// Sign contains code signing configuration.
|
2026-02-05 10:26:44 +00:00
|
|
|
Sign signing.SignConfig `yaml:"sign,omitempty" mapstructure:"sign,omitempty"`
|
2026-01-28 17:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Project holds project metadata.
|
|
|
|
|
type Project struct {
|
|
|
|
|
// Name is the project name.
|
2026-02-05 10:26:44 +00:00
|
|
|
Name string `yaml:"name" mapstructure:"name"`
|
2026-01-28 17:59:02 +00:00
|
|
|
// Description is a brief description of the project.
|
2026-02-05 10:26:44 +00:00
|
|
|
Description string `yaml:"description" mapstructure:"description"`
|
2026-01-28 17:59:02 +00:00
|
|
|
// Main is the path to the main package (e.g., ./cmd/core).
|
2026-02-05 10:26:44 +00:00
|
|
|
Main string `yaml:"main" mapstructure:"main"`
|
2026-01-28 17:59:02 +00:00
|
|
|
// Binary is the output binary name.
|
2026-02-05 10:26:44 +00:00
|
|
|
Binary string `yaml:"binary" mapstructure:"binary"`
|
2026-01-28 17:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Build holds build-time settings.
|
|
|
|
|
type Build struct {
|
|
|
|
|
// CGO enables CGO for the build.
|
2026-02-05 10:26:44 +00:00
|
|
|
CGO bool `yaml:"cgo" mapstructure:"cgo"`
|
2026-01-28 17:59:02 +00:00
|
|
|
// Flags are additional build flags (e.g., ["-trimpath"]).
|
2026-02-05 10:26:44 +00:00
|
|
|
Flags []string `yaml:"flags" mapstructure:"flags"`
|
2026-01-28 17:59:02 +00:00
|
|
|
// LDFlags are linker flags (e.g., ["-s", "-w"]).
|
2026-02-05 10:26:44 +00:00
|
|
|
LDFlags []string `yaml:"ldflags" mapstructure:"ldflags"`
|
2026-01-28 17:59:02 +00:00
|
|
|
// Env are additional environment variables.
|
2026-02-05 10:26:44 +00:00
|
|
|
Env []string `yaml:"env" mapstructure:"env"`
|
2026-01-28 17:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TargetConfig defines a build target in the config file.
|
|
|
|
|
// This is separate from Target to allow for additional config-specific fields.
|
|
|
|
|
type TargetConfig struct {
|
|
|
|
|
// OS is the target operating system (e.g., "linux", "darwin", "windows").
|
2026-02-05 10:26:44 +00:00
|
|
|
OS string `yaml:"os" mapstructure:"os"`
|
2026-01-28 17:59:02 +00:00
|
|
|
// Arch is the target architecture (e.g., "amd64", "arm64").
|
2026-02-05 10:26:44 +00:00
|
|
|
Arch string `yaml:"arch" mapstructure:"arch"`
|
2026-01-28 17:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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.
|
2026-02-04 17:59:10 +00:00
|
|
|
func LoadConfig(fs io.Medium, dir string) (*BuildConfig, error) {
|
2026-01-28 17:59:02 +00:00
|
|
|
configPath := filepath.Join(dir, ConfigDir, ConfigFileName)
|
|
|
|
|
|
2026-02-05 10:26:44 +00:00
|
|
|
if !fs.Exists(configPath) {
|
|
|
|
|
return DefaultConfig(), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Use centralized config service
|
|
|
|
|
c, err := config.New(config.WithMedium(fs), config.WithPath(configPath))
|
2026-01-28 17:59:02 +00:00
|
|
|
if err != nil {
|
2026-02-05 10:26:44 +00:00
|
|
|
return nil, fmt.Errorf("build.LoadConfig: %w", err)
|
2026-01-28 17:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-05 10:26:44 +00:00
|
|
|
cfg := DefaultConfig()
|
|
|
|
|
if err := c.Get("", cfg); err != nil {
|
|
|
|
|
return nil, fmt.Errorf("build.LoadConfig: %w", err)
|
2026-01-28 17:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-05 10:26:44 +00:00
|
|
|
// Apply defaults for any missing fields (centralized Get might not fill everything)
|
|
|
|
|
applyDefaults(cfg)
|
2026-01-28 17:59:02 +00:00
|
|
|
|
2026-02-05 10:26:44 +00:00
|
|
|
return cfg, nil
|
2026-01-28 17:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DefaultConfig returns sensible defaults for Go projects.
|
|
|
|
|
func DefaultConfig() *BuildConfig {
|
|
|
|
|
return &BuildConfig{
|
|
|
|
|
Version: 1,
|
|
|
|
|
Project: Project{
|
|
|
|
|
Name: "",
|
|
|
|
|
Main: ".",
|
|
|
|
|
Binary: "",
|
|
|
|
|
},
|
|
|
|
|
Build: Build{
|
|
|
|
|
CGO: false,
|
|
|
|
|
Flags: []string{"-trimpath"},
|
|
|
|
|
LDFlags: []string{"-s", "-w"},
|
|
|
|
|
Env: []string{},
|
|
|
|
|
},
|
|
|
|
|
Targets: []TargetConfig{
|
|
|
|
|
{OS: "linux", Arch: "amd64"},
|
|
|
|
|
{OS: "linux", Arch: "arm64"},
|
|
|
|
|
{OS: "darwin", Arch: "arm64"},
|
|
|
|
|
{OS: "windows", Arch: "amd64"},
|
|
|
|
|
},
|
2026-01-29 02:52:12 +00:00
|
|
|
Sign: signing.DefaultSignConfig(),
|
2026-01-28 17:59:02 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// applyDefaults fills in default values for any empty fields in the config.
|
|
|
|
|
func applyDefaults(cfg *BuildConfig) {
|
|
|
|
|
defaults := DefaultConfig()
|
|
|
|
|
|
|
|
|
|
if cfg.Version == 0 {
|
|
|
|
|
cfg.Version = defaults.Version
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if cfg.Project.Main == "" {
|
|
|
|
|
cfg.Project.Main = defaults.Project.Main
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if cfg.Build.Flags == nil {
|
|
|
|
|
cfg.Build.Flags = defaults.Build.Flags
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if cfg.Build.LDFlags == nil {
|
|
|
|
|
cfg.Build.LDFlags = defaults.Build.LDFlags
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if cfg.Build.Env == nil {
|
|
|
|
|
cfg.Build.Env = defaults.Build.Env
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(cfg.Targets) == 0 {
|
|
|
|
|
cfg.Targets = defaults.Targets
|
|
|
|
|
}
|
2026-01-29 02:52:12 +00:00
|
|
|
|
|
|
|
|
// Expand environment variables in sign config
|
|
|
|
|
cfg.Sign.ExpandEnv()
|
2026-01-28 17:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ConfigPath returns the path to the build config file for a given directory.
|
|
|
|
|
func ConfigPath(dir string) string {
|
|
|
|
|
return filepath.Join(dir, ConfigDir, ConfigFileName)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ConfigExists checks if a build config file exists in the given directory.
|
2026-02-04 17:59:10 +00:00
|
|
|
func ConfigExists(fs io.Medium, dir string) bool {
|
2026-02-05 10:26:44 +00:00
|
|
|
return fs.IsFile(ConfigPath(dir))
|
2026-01-28 17:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ToTargets converts TargetConfig slice to Target slice for use with builders.
|
|
|
|
|
func (cfg *BuildConfig) ToTargets() []Target {
|
|
|
|
|
targets := make([]Target, len(cfg.Targets))
|
|
|
|
|
for i, t := range cfg.Targets {
|
feat: git command, build improvements, and go fmt git-aware (#74)
* feat(go): make go fmt git-aware by default
- By default, only check changed Go files (modified, staged, untracked)
- Add --all flag to check all files (previous behaviour)
- Reduces noise when running fmt on large codebases
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(build): minimal output by default, add missing i18n
- Default output now shows single line: "Success Built N artifacts (dir)"
- Add --verbose/-v flag to show full detailed output
- Add all missing i18n translations for build commands
- Errors still show failure reason in minimal mode
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: add root-level `core git` command
- Create pkg/gitcmd with git workflow commands as root menu
- Export command builders from pkg/dev (AddCommitCommand, etc.)
- Commands available under both `core git` and `core dev` for compatibility
- Git commands: health, commit, push, pull, work, sync, apply
- GitHub orchestration stays in dev: issues, reviews, ci, impact
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(qa): add docblock coverage checking
Implement docblock/docstring coverage analysis for Go code:
- New `core qa docblock` command to check coverage
- Shows compact file:line list when under threshold
- Integrate with `core go qa` as a default check
- Add --docblock-threshold flag (default 80%)
The checker uses Go AST parsing to find exported symbols
(functions, types, consts, vars) without documentation.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: address CodeRabbit review feedback
- Fix doc comment: "status" → "health" in gitcmd package
- Implement --check flag for `core go fmt` (exits non-zero if files need formatting)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* docs: add docstrings for 100% coverage
Add documentation comments to all exported symbols:
- pkg/build: ProjectType constants
- pkg/cli: LogLevel, RenderStyle, TableStyle
- pkg/framework: ServiceFor, MustServiceFor, Core.Core
- pkg/git: GitError.Error, GitError.Unwrap
- pkg/i18n: Handler Match/Handle methods
- pkg/log: Level constants
- pkg/mcp: Tool input/output types
- pkg/php: Service constants, QA types, service methods
- pkg/process: ServiceError.Error
- pkg/repos: RepoType constants
- pkg/setup: ChangeType, ChangeCategory constants
- pkg/workspace: AddWorkspaceCommands
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore: standardize line endings to LF
Add .gitattributes to enforce LF line endings for all text files.
Normalize all existing files to use Unix-style line endings.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: address CodeRabbit review feedback
- cmd_format.go: validate --check/--fix mutual exclusivity, capture stderr
- cmd_docblock.go: return error instead of os.Exit(1) for proper error handling
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: address CodeRabbit review feedback (round 2)
- linuxkit.go: propagate state update errors, handle cmd.Wait() errors in waitForExit
- mcp.go: guard against empty old_string in editDiff to prevent runaway edits
- cmd_docblock.go: log parse errors instead of silently skipping
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 10:48:44 +00:00
|
|
|
targets[i] = Target(t)
|
2026-01-28 17:59:02 +00:00
|
|
|
}
|
|
|
|
|
return targets
|
|
|
|
|
}
|