Integrate selected builds with candidate workflows

This commit is contained in:
2026-10-05 19:38:50 +00:00
parent 5d6a6d10bd
commit e98ee0f7b9
21 changed files with 848 additions and 31 deletions

View File

@@ -16,7 +16,7 @@ import (
"gitea.maximumdirect.net/eric/ReleaseKit/internal/process"
)
const Usage = "usage: releasekit version\n releasekit check [--repo DIR] [--config FILE] VERSION\n releasekit publish [--repo DIR] [--config FILE] VERSION"
const Usage = "usage: releasekit version\n releasekit check [--repo DIR] [--config FILE] VERSION\n releasekit publish [--repo DIR] [--config FILE] VERSION\n releasekit build [--repo DIR] [--config FILE] [--output DIR] VERSION"
type Command string
@@ -24,6 +24,7 @@ const (
VersionCommand Command = "version"
CheckAction Command = "check"
PublishAction Command = "publish"
BuildAction Command = "build"
)
// Invocation contains parsed command settings owned by the CLI adapter.
@@ -31,6 +32,7 @@ type Invocation struct {
Command Command
Repository string
ConfigPath string
OutputDir string
Version string
}
@@ -45,19 +47,23 @@ func Parse(args []string) (Invocation, error) {
return Invocation{}, errors.New("version takes no arguments")
}
return Invocation{Command: VersionCommand}, nil
case string(CheckAction), string(PublishAction):
case string(CheckAction), string(PublishAction), string(BuildAction):
action := Command(args[0])
flags := flag.NewFlagSet(string(action), flag.ContinueOnError)
flags.SetOutput(io.Discard)
repository := flags.String("repo", ".", "repository directory")
configPath := flags.String("config", "", "profile path")
var outputDir string
if action == BuildAction {
flags.StringVar(&outputDir, "output", "", "build output directory")
}
if err := flags.Parse(args[1:]); err != nil {
return Invocation{}, err
}
if flags.NArg() != 1 {
return Invocation{}, fmt.Errorf("%s requires one version argument", action)
}
return Invocation{Command: action, Repository: *repository, ConfigPath: *configPath, Version: flags.Arg(0)}, nil
return Invocation{Command: action, Repository: *repository, ConfigPath: *configPath, OutputDir: outputDir, Version: flags.Arg(0)}, nil
default:
return Invocation{}, fmt.Errorf("unknown command %q", args[0])
}
@@ -75,6 +81,14 @@ type Settings struct {
Product string `json:"product"`
Remote string `json:"remote,omitempty"`
Checks []CheckCommand `json:"checks,omitempty"`
Build *BuildSettings `json:"build,omitempty"`
}
// BuildSettings selects the Go application package, artifact name, and targets.
type BuildSettings struct {
MainPackage string `json:"main_package,omitempty"`
BinaryName string `json:"binary_name,omitempty"`
Targets []string `json:"targets,omitempty"`
}
// LoadSettings reads a profile path relative to repoDir unless it is absolute.
@@ -122,6 +136,31 @@ func LoadSettings(repoDir, configPath string) (Settings, error) {
return Settings{}, fmt.Errorf("profile %q: checks[%d].args must include a command", configPath, i)
}
}
if settings.Build != nil {
if len(settings.Build.Targets) != 0 {
if strings.TrimSpace(settings.Build.MainPackage) == "" {
return Settings{}, fmt.Errorf("profile %q: build.main_package is required when targets are selected", configPath)
}
if strings.TrimSpace(settings.Build.BinaryName) == "" {
return Settings{}, fmt.Errorf("profile %q: build.binary_name is required when targets are selected", configPath)
}
if strings.ContainsAny(settings.Build.BinaryName, "/\\\r\n") {
return Settings{}, fmt.Errorf("profile %q: build.binary_name must be a filename component", configPath)
}
}
for i, target := range settings.Build.Targets {
if strings.Count(target, "/") != 1 {
return Settings{}, fmt.Errorf("profile %q: build.targets[%d] must be GOOS/GOARCH", configPath, i)
}
goos, goarch, _ := strings.Cut(target, "/")
if strings.TrimSpace(goos) == "" || strings.TrimSpace(goarch) == "" {
return Settings{}, fmt.Errorf("profile %q: build.targets[%d] must be GOOS/GOARCH", configPath, i)
}
if strings.ContainsAny(goos+goarch, "\\\r\n") {
return Settings{}, fmt.Errorf("profile %q: build.targets[%d] contains an unsafe filename component", configPath, i)
}
}
}
return settings, nil
}