refactor(cli): move commands from cmd/ to pkg/ with self-registration
Implements defence in depth through build variants - only compiled code
exists in the binary. Commands now self-register via cli.RegisterCommands()
in their init() functions, mirroring the i18n.RegisterLocales() pattern.
Structure changes:
- cmd/{ai,build,ci,dev,docs,doctor,go,php,pkg,sdk,setup,test,vm}/ → pkg/*/cmd_*.go
- cmd/core_dev.go, cmd/core_ci.go → cmd/variants/{full,ci,php,minimal}.go
- Added pkg/cli/commands.go with RegisterCommands API
- Updated pkg/cli/runtime.go to attach registered commands
Build variants:
- go build → full (21MB, all 13 command groups)
- go build -tags ci → ci (18MB, build/ci/sdk/doctor)
- go build -tags php → php (14MB, php/doctor)
- go build -tags minimal → minimal (11MB, doctor only)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
f2f7e27e77
commit
9931593f9d
87 changed files with 537 additions and 408 deletions
27
cmd/core.go
27
cmd/core.go
|
|
@ -22,6 +22,10 @@ import (
|
|||
"github.com/host-uk/core/pkg/cli"
|
||||
"github.com/host-uk/core/pkg/framework"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
// Build variants import commands via self-registration.
|
||||
// See cmd/variants/ for available variants: full, ci, php, minimal.
|
||||
_ "github.com/host-uk/core/cmd/variants"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -29,21 +33,7 @@ const (
|
|||
appVersion = "0.1.0"
|
||||
)
|
||||
|
||||
// Terminal styles using Tailwind colour palette (from shared package).
|
||||
var (
|
||||
// coreStyle is used for primary headings and the CLI name.
|
||||
coreStyle = cli.RepoNameStyle
|
||||
|
||||
// linkStyle is used for URLs and clickable references.
|
||||
linkStyle = cli.LinkStyle
|
||||
)
|
||||
|
||||
// rootCmd is the base command for the CLI.
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: appName,
|
||||
Short: "CLI tool for development and production",
|
||||
Version: appVersion,
|
||||
}
|
||||
|
||||
// Execute initialises and runs the CLI application.
|
||||
// Commands are registered based on build tags (see core_ci.go and core_dev.go).
|
||||
|
|
@ -63,13 +53,12 @@ func Execute() error {
|
|||
}
|
||||
defer cli.Shutdown()
|
||||
|
||||
return rootCmd.Execute()
|
||||
// Add completion command to the CLI's root
|
||||
cli.RootCmd().AddCommand(completionCmd)
|
||||
|
||||
return cli.Execute()
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Add shell completion command
|
||||
rootCmd.AddCommand(completionCmd)
|
||||
}
|
||||
|
||||
// completionCmd generates shell completion scripts.
|
||||
var completionCmd = &cobra.Command{
|
||||
|
|
|
|||
|
|
@ -1,63 +0,0 @@
|
|||
//go:build !ci
|
||||
|
||||
// core_dev.go registers commands for the full development binary.
|
||||
//
|
||||
// Build with: go build (default)
|
||||
//
|
||||
// This is the default build variant with all development tools:
|
||||
// - dev: Multi-repo git workflows (commit, push, pull, sync)
|
||||
// - ai: AI agent task management
|
||||
// - go: Go module and build tools
|
||||
// - php: Laravel/Composer development tools
|
||||
// - build: Cross-platform compilation
|
||||
// - ci: Release publishing
|
||||
// - sdk: API compatibility checks
|
||||
// - pkg: Package management
|
||||
// - vm: LinuxKit VM management
|
||||
// - docs: Documentation generation
|
||||
// - setup: Repository cloning and setup
|
||||
// - doctor: Environment health checks
|
||||
// - test: Test runner with coverage
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/host-uk/core/cmd/ai"
|
||||
"github.com/host-uk/core/cmd/build"
|
||||
"github.com/host-uk/core/cmd/ci"
|
||||
"github.com/host-uk/core/cmd/dev"
|
||||
"github.com/host-uk/core/cmd/docs"
|
||||
"github.com/host-uk/core/cmd/doctor"
|
||||
gocmd "github.com/host-uk/core/cmd/go"
|
||||
"github.com/host-uk/core/cmd/php"
|
||||
"github.com/host-uk/core/cmd/pkg"
|
||||
"github.com/host-uk/core/cmd/sdk"
|
||||
"github.com/host-uk/core/cmd/setup"
|
||||
testcmd "github.com/host-uk/core/cmd/test"
|
||||
"github.com/host-uk/core/cmd/vm"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Multi-repo workflow
|
||||
dev.AddCommands(rootCmd)
|
||||
|
||||
// AI agent tools
|
||||
ai.AddCommands(rootCmd)
|
||||
|
||||
// Language tooling
|
||||
gocmd.AddCommands(rootCmd)
|
||||
php.AddCommands(rootCmd)
|
||||
|
||||
// Build and release
|
||||
build.AddCommands(rootCmd)
|
||||
ci.AddCommands(rootCmd)
|
||||
sdk.AddCommands(rootCmd)
|
||||
|
||||
// Environment management
|
||||
pkg.AddCommands(rootCmd)
|
||||
vm.AddCommands(rootCmd)
|
||||
docs.AddCommands(rootCmd)
|
||||
setup.AddCommands(rootCmd)
|
||||
doctor.AddCommands(rootCmd)
|
||||
testcmd.AddCommands(rootCmd)
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
// Package sdk provides SDK validation and API compatibility commands.
|
||||
//
|
||||
// Commands:
|
||||
// - diff: Check for breaking API changes between spec versions
|
||||
// - validate: Validate OpenAPI spec syntax
|
||||
//
|
||||
// Configuration via .core/sdk.yaml. For SDK generation, use: core build sdk
|
||||
package sdk
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
|
||||
// AddCommands registers the 'sdk' command and all subcommands.
|
||||
func AddCommands(root *cobra.Command) {
|
||||
root.AddCommand(sdkCmd)
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
//go:build ci
|
||||
|
||||
// core_ci.go registers commands for the minimal CI/release binary.
|
||||
// ci.go imports packages for the minimal CI/release binary.
|
||||
//
|
||||
// Build with: go build -tags ci
|
||||
//
|
||||
|
|
@ -12,18 +12,12 @@
|
|||
//
|
||||
// Use this build to reduce binary size and attack surface in production.
|
||||
|
||||
package cmd
|
||||
package variants
|
||||
|
||||
import (
|
||||
"github.com/host-uk/core/cmd/build"
|
||||
"github.com/host-uk/core/cmd/ci"
|
||||
"github.com/host-uk/core/cmd/doctor"
|
||||
"github.com/host-uk/core/cmd/sdk"
|
||||
// Commands via self-registration
|
||||
_ "github.com/host-uk/core/pkg/build/buildcmd"
|
||||
_ "github.com/host-uk/core/pkg/ci"
|
||||
_ "github.com/host-uk/core/pkg/doctor"
|
||||
_ "github.com/host-uk/core/pkg/sdk"
|
||||
)
|
||||
|
||||
func init() {
|
||||
build.AddCommands(rootCmd)
|
||||
ci.AddCommands(rootCmd)
|
||||
sdk.AddCommands(rootCmd)
|
||||
doctor.AddCommands(rootCmd)
|
||||
}
|
||||
39
cmd/variants/full.go
Normal file
39
cmd/variants/full.go
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
//go:build !ci && !php && !minimal
|
||||
|
||||
// full.go imports all packages for the full development binary.
|
||||
//
|
||||
// Build with: go build (default)
|
||||
//
|
||||
// This is the default build variant with all development tools:
|
||||
// - dev: Multi-repo git workflows (commit, push, pull, sync)
|
||||
// - ai: AI agent task management
|
||||
// - go: Go module and build tools
|
||||
// - php: Laravel/Composer development tools
|
||||
// - build: Cross-platform compilation
|
||||
// - ci: Release publishing
|
||||
// - sdk: API compatibility checks
|
||||
// - pkg: Package management
|
||||
// - vm: LinuxKit VM management
|
||||
// - docs: Documentation generation
|
||||
// - setup: Repository cloning and setup
|
||||
// - doctor: Environment health checks
|
||||
// - test: Test runner with coverage
|
||||
|
||||
package variants
|
||||
|
||||
import (
|
||||
// Commands via self-registration
|
||||
_ "github.com/host-uk/core/pkg/ai"
|
||||
_ "github.com/host-uk/core/pkg/build/buildcmd"
|
||||
_ "github.com/host-uk/core/pkg/ci"
|
||||
_ "github.com/host-uk/core/pkg/dev"
|
||||
_ "github.com/host-uk/core/pkg/docs"
|
||||
_ "github.com/host-uk/core/pkg/doctor"
|
||||
_ "github.com/host-uk/core/pkg/go"
|
||||
_ "github.com/host-uk/core/pkg/php"
|
||||
_ "github.com/host-uk/core/pkg/pkgcmd"
|
||||
_ "github.com/host-uk/core/pkg/sdk"
|
||||
_ "github.com/host-uk/core/pkg/setup"
|
||||
_ "github.com/host-uk/core/pkg/test"
|
||||
_ "github.com/host-uk/core/pkg/vm"
|
||||
)
|
||||
17
cmd/variants/minimal.go
Normal file
17
cmd/variants/minimal.go
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
//go:build minimal
|
||||
|
||||
// minimal.go imports only core packages for a minimal binary.
|
||||
//
|
||||
// Build with: go build -tags minimal
|
||||
//
|
||||
// This variant includes only the absolute essentials:
|
||||
// - doctor: Environment verification
|
||||
//
|
||||
// Use this for the smallest possible binary with just health checks.
|
||||
|
||||
package variants
|
||||
|
||||
import (
|
||||
// Commands via self-registration
|
||||
_ "github.com/host-uk/core/pkg/doctor"
|
||||
)
|
||||
19
cmd/variants/php.go
Normal file
19
cmd/variants/php.go
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
//go:build php
|
||||
|
||||
// php.go imports packages for the PHP-only binary.
|
||||
//
|
||||
// Build with: go build -tags php
|
||||
//
|
||||
// This variant includes only PHP/Laravel development tools:
|
||||
// - php: Laravel/Composer development tools
|
||||
// - doctor: Environment verification
|
||||
//
|
||||
// Use this for PHP-focused workflows without other tooling.
|
||||
|
||||
package variants
|
||||
|
||||
import (
|
||||
// Commands via self-registration
|
||||
_ "github.com/host-uk/core/pkg/doctor"
|
||||
_ "github.com/host-uk/core/pkg/php"
|
||||
)
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// ai.go defines styles and the AddAgenticCommands function for AI task management.
|
||||
// cmd_ai.go defines styles and the AddAgenticCommands function for AI task management.
|
||||
|
||||
package ai
|
||||
|
||||
|
|
@ -29,8 +29,8 @@ var (
|
|||
|
||||
// Task-specific styles (aliases to shared where possible)
|
||||
var (
|
||||
taskIDStyle = cli.TitleStyle // Bold + blue
|
||||
taskTitleStyle = cli.ValueStyle // Light gray
|
||||
taskIDStyle = cli.TitleStyle // Bold + blue
|
||||
taskTitleStyle = cli.ValueStyle // Light gray
|
||||
taskLabelStyle = cli.AccentLabelStyle // Violet for labels
|
||||
)
|
||||
|
||||
|
|
@ -11,10 +11,15 @@
|
|||
package ai
|
||||
|
||||
import (
|
||||
"github.com/host-uk/core/pkg/cli"
|
||||
"github.com/host-uk/core/pkg/i18n"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cli.RegisterCommands(AddAICommands)
|
||||
}
|
||||
|
||||
var aiCmd = &cobra.Command{
|
||||
Use: "ai",
|
||||
Short: i18n.T("cmd.ai.short"),
|
||||
|
|
@ -43,7 +48,7 @@ var claudeConfigCmd = &cobra.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
func initCommands() {
|
||||
// Add Claude subcommands
|
||||
claudeCmd.AddCommand(claudeRunCmd)
|
||||
claudeCmd.AddCommand(claudeConfigCmd)
|
||||
|
|
@ -55,8 +60,9 @@ func init() {
|
|||
AddAgenticCommands(aiCmd)
|
||||
}
|
||||
|
||||
// AddCommands registers the 'ai' command and all subcommands.
|
||||
func AddCommands(root *cobra.Command) {
|
||||
// AddAICommands registers the 'ai' command and all subcommands.
|
||||
func AddAICommands(root *cobra.Command) {
|
||||
initCommands()
|
||||
root.AddCommand(aiCmd)
|
||||
}
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// ai_git.go implements git integration commands for task commits and PRs.
|
||||
// cmd_git.go implements git integration commands for task commits and PRs.
|
||||
|
||||
package ai
|
||||
|
||||
|
|
@ -40,7 +40,7 @@ var taskCommitCmd = &cobra.Command{
|
|||
taskID := args[0]
|
||||
|
||||
if taskCommitMessage == "" {
|
||||
return fmt.Errorf(i18n.T("cmd.ai.task_commit.message_required"))
|
||||
return fmt.Errorf("%s", i18n.T("cmd.ai.task_commit.message_required"))
|
||||
}
|
||||
|
||||
cfg, err := agentic.LoadConfig("")
|
||||
|
|
@ -143,7 +143,7 @@ var taskPRCmd = &cobra.Command{
|
|||
}
|
||||
|
||||
if branch == "main" || branch == "master" {
|
||||
return fmt.Errorf(i18n.T("cmd.ai.task_pr.branch_error", map[string]interface{}{"Branch": branch}))
|
||||
return fmt.Errorf("%s", i18n.T("cmd.ai.task_pr.branch_error", map[string]interface{}{"Branch": branch}))
|
||||
}
|
||||
|
||||
// Push current branch
|
||||
|
|
@ -180,7 +180,7 @@ var taskPRCmd = &cobra.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
func initGitFlags() {
|
||||
// task:commit command flags
|
||||
taskCommitCmd.Flags().StringVarP(&taskCommitMessage, "message", "m", "", i18n.T("cmd.ai.task_commit.flag.message"))
|
||||
taskCommitCmd.Flags().StringVar(&taskCommitScope, "scope", "", i18n.T("cmd.ai.task_commit.flag.scope"))
|
||||
|
|
@ -194,6 +194,7 @@ func init() {
|
|||
}
|
||||
|
||||
func addTaskCommitCommand(parent *cobra.Command) {
|
||||
initGitFlags()
|
||||
parent.AddCommand(taskCommitCmd)
|
||||
}
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// ai_tasks.go implements task listing and viewing commands.
|
||||
// cmd_tasks.go implements task listing and viewing commands.
|
||||
|
||||
package ai
|
||||
|
||||
|
|
@ -135,7 +135,7 @@ var taskCmd = &cobra.Command{
|
|||
taskClaim = true // Auto-select implies claiming
|
||||
} else {
|
||||
if taskID == "" {
|
||||
return fmt.Errorf(i18n.T("cmd.ai.task.id_required"))
|
||||
return fmt.Errorf("%s", i18n.T("cmd.ai.task.id_required"))
|
||||
}
|
||||
|
||||
task, err = client.GetTask(ctx, taskID)
|
||||
|
|
@ -174,7 +174,7 @@ var taskCmd = &cobra.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
func initTasksFlags() {
|
||||
// tasks command flags
|
||||
tasksCmd.Flags().StringVar(&tasksStatus, "status", "", i18n.T("cmd.ai.tasks.flag.status"))
|
||||
tasksCmd.Flags().StringVar(&tasksPriority, "priority", "", i18n.T("cmd.ai.tasks.flag.priority"))
|
||||
|
|
@ -189,6 +189,7 @@ func init() {
|
|||
}
|
||||
|
||||
func addTasksCommand(parent *cobra.Command) {
|
||||
initTasksFlags()
|
||||
parent.AddCommand(tasksCmd)
|
||||
}
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// ai_updates.go implements task update and completion commands.
|
||||
// cmd_updates.go implements task update and completion commands.
|
||||
|
||||
package ai
|
||||
|
||||
|
|
@ -35,7 +35,7 @@ var taskUpdateCmd = &cobra.Command{
|
|||
taskID := args[0]
|
||||
|
||||
if taskUpdateStatus == "" && taskUpdateProgress == 0 && taskUpdateNotes == "" {
|
||||
return fmt.Errorf(i18n.T("cmd.ai.task_update.flag_required"))
|
||||
return fmt.Errorf("%s", i18n.T("cmd.ai.task_update.flag_required"))
|
||||
}
|
||||
|
||||
cfg, err := agentic.LoadConfig("")
|
||||
|
|
@ -102,7 +102,7 @@ var taskCompleteCmd = &cobra.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
func initUpdatesFlags() {
|
||||
// task:update command flags
|
||||
taskUpdateCmd.Flags().StringVar(&taskUpdateStatus, "status", "", i18n.T("cmd.ai.task_update.flag.status"))
|
||||
taskUpdateCmd.Flags().IntVar(&taskUpdateProgress, "progress", 0, i18n.T("cmd.ai.task_update.flag.progress"))
|
||||
|
|
@ -115,6 +115,7 @@ func init() {
|
|||
}
|
||||
|
||||
func addTaskUpdateCommand(parent *cobra.Command) {
|
||||
initUpdatesFlags()
|
||||
parent.AddCommand(taskUpdateCmd)
|
||||
}
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
// Package build provides project build commands with auto-detection.
|
||||
package build
|
||||
// Package buildcmd provides project build commands with auto-detection.
|
||||
package buildcmd
|
||||
|
||||
import (
|
||||
"embed"
|
||||
|
|
@ -9,6 +9,10 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cli.RegisterCommands(AddBuildCommands)
|
||||
}
|
||||
|
||||
// Style aliases from shared package
|
||||
var (
|
||||
buildHeaderStyle = cli.TitleStyle
|
||||
|
|
@ -93,7 +97,7 @@ var sdkBuildCmd = &cobra.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
func initBuildFlags() {
|
||||
// Main build command flags
|
||||
buildCmd.Flags().StringVar(&buildType, "type", "", i18n.T("cmd.build.flag.type"))
|
||||
buildCmd.Flags().BoolVar(&ciMode, "ci", false, i18n.T("cmd.build.flag.ci"))
|
||||
|
|
@ -130,7 +134,8 @@ func init() {
|
|||
buildCmd.AddCommand(sdkBuildCmd)
|
||||
}
|
||||
|
||||
// AddBuildCommand adds the new build command and its subcommands to the cobra app.
|
||||
func AddBuildCommand(root *cobra.Command) {
|
||||
// AddBuildCommands registers the 'build' command and all subcommands.
|
||||
func AddBuildCommands(root *cobra.Command) {
|
||||
initBuildFlags()
|
||||
root.AddCommand(buildCmd)
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// Package build provides project build commands with auto-detection.
|
||||
// Package buildcmd provides project build commands with auto-detection.
|
||||
//
|
||||
// Supports building:
|
||||
// - Go projects (standard and cross-compilation)
|
||||
|
|
@ -14,11 +14,8 @@
|
|||
// - build from-path: Build from a local static web app directory
|
||||
// - build pwa: Build from a live PWA URL
|
||||
// - build sdk: Generate API SDKs from OpenAPI spec
|
||||
package build
|
||||
package buildcmd
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
|
||||
// AddCommands registers the 'build' command and all subcommands.
|
||||
func AddCommands(root *cobra.Command) {
|
||||
AddBuildCommand(root)
|
||||
}
|
||||
// Note: The AddBuildCommands function is defined in cmd_build.go
|
||||
// This file exists for documentation purposes and maintains the original
|
||||
// package documentation from commands.go.
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
// build_project.go implements the main project build logic.
|
||||
// cmd_project.go implements the main project build logic.
|
||||
//
|
||||
// This handles auto-detection of project types (Go, Wails, Docker, LinuxKit, Taskfile)
|
||||
// and orchestrates the build process including signing, archiving, and checksums.
|
||||
|
||||
package build
|
||||
package buildcmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
@ -14,7 +14,7 @@ import (
|
|||
"runtime"
|
||||
"strings"
|
||||
|
||||
buildpkg "github.com/host-uk/core/pkg/build"
|
||||
"github.com/host-uk/core/pkg/build"
|
||||
"github.com/host-uk/core/pkg/build/builders"
|
||||
"github.com/host-uk/core/pkg/build/signing"
|
||||
"github.com/host-uk/core/pkg/i18n"
|
||||
|
|
@ -29,17 +29,17 @@ func runProjectBuild(buildType string, ciMode bool, targetsFlag string, outputDi
|
|||
}
|
||||
|
||||
// Load configuration from .core/build.yaml (or defaults)
|
||||
buildCfg, err := buildpkg.LoadConfig(projectDir)
|
||||
buildCfg, err := build.LoadConfig(projectDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "load config"}), err)
|
||||
}
|
||||
|
||||
// Detect project type if not specified
|
||||
var projectType buildpkg.ProjectType
|
||||
var projectType build.ProjectType
|
||||
if buildType != "" {
|
||||
projectType = buildpkg.ProjectType(buildType)
|
||||
projectType = build.ProjectType(buildType)
|
||||
} else {
|
||||
projectType, err = buildpkg.PrimaryType(projectDir)
|
||||
projectType, err = build.PrimaryType(projectDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "detect project type"}), err)
|
||||
}
|
||||
|
|
@ -49,7 +49,7 @@ func runProjectBuild(buildType string, ciMode bool, targetsFlag string, outputDi
|
|||
}
|
||||
|
||||
// Determine targets
|
||||
var buildTargets []buildpkg.Target
|
||||
var buildTargets []build.Target
|
||||
if targetsFlag != "" {
|
||||
// Parse from command line
|
||||
buildTargets, err = parseTargets(targetsFlag)
|
||||
|
|
@ -61,7 +61,7 @@ func runProjectBuild(buildType string, ciMode bool, targetsFlag string, outputDi
|
|||
buildTargets = buildCfg.ToTargets()
|
||||
} else {
|
||||
// Fall back to current OS/arch
|
||||
buildTargets = []buildpkg.Target{
|
||||
buildTargets = []build.Target{
|
||||
{OS: runtime.GOOS, Arch: runtime.GOARCH},
|
||||
}
|
||||
}
|
||||
|
|
@ -97,7 +97,7 @@ func runProjectBuild(buildType string, ciMode bool, targetsFlag string, outputDi
|
|||
}
|
||||
|
||||
// Create build config for the builder
|
||||
cfg := &buildpkg.Config{
|
||||
cfg := &build.Config{
|
||||
ProjectDir: projectDir,
|
||||
OutputDir: outputDir,
|
||||
Name: binaryName,
|
||||
|
|
@ -156,7 +156,7 @@ func runProjectBuild(buildType string, ciMode bool, targetsFlag string, outputDi
|
|||
fmt.Printf("%s %s\n", buildHeaderStyle.Render(i18n.T("cmd.build.label.sign")), i18n.T("cmd.build.signing_binaries"))
|
||||
}
|
||||
|
||||
// Convert buildpkg.Artifact to signing.Artifact
|
||||
// Convert build.Artifact to signing.Artifact
|
||||
signingArtifacts := make([]signing.Artifact, len(artifacts))
|
||||
for i, a := range artifacts {
|
||||
signingArtifacts[i] = signing.Artifact{Path: a.Path, OS: a.OS, Arch: a.Arch}
|
||||
|
|
@ -180,14 +180,14 @@ func runProjectBuild(buildType string, ciMode bool, targetsFlag string, outputDi
|
|||
}
|
||||
|
||||
// Archive artifacts if enabled
|
||||
var archivedArtifacts []buildpkg.Artifact
|
||||
var archivedArtifacts []build.Artifact
|
||||
if doArchive && len(artifacts) > 0 {
|
||||
if !ciMode {
|
||||
fmt.Println()
|
||||
fmt.Printf("%s %s\n", buildHeaderStyle.Render(i18n.T("cmd.build.label.archive")), i18n.T("cmd.build.creating_archives"))
|
||||
}
|
||||
|
||||
archivedArtifacts, err = buildpkg.ArchiveAll(artifacts)
|
||||
archivedArtifacts, err = build.ArchiveAll(artifacts)
|
||||
if err != nil {
|
||||
if !ciMode {
|
||||
fmt.Printf("%s %s: %v\n", buildErrorStyle.Render(i18n.T("common.label.error")), i18n.T("cmd.build.error.archive_failed"), err)
|
||||
|
|
@ -211,7 +211,7 @@ func runProjectBuild(buildType string, ciMode bool, targetsFlag string, outputDi
|
|||
}
|
||||
|
||||
// Compute checksums if enabled
|
||||
var checksummedArtifacts []buildpkg.Artifact
|
||||
var checksummedArtifacts []build.Artifact
|
||||
if doChecksum && len(archivedArtifacts) > 0 {
|
||||
checksummedArtifacts, err = computeAndWriteChecksums(ctx, projectDir, outputDir, archivedArtifacts, signCfg, ciMode)
|
||||
if err != nil {
|
||||
|
|
@ -228,7 +228,7 @@ func runProjectBuild(buildType string, ciMode bool, targetsFlag string, outputDi
|
|||
// Output results for CI mode
|
||||
if ciMode {
|
||||
// Determine which artifacts to output (prefer checksummed > archived > raw)
|
||||
var outputArtifacts []buildpkg.Artifact
|
||||
var outputArtifacts []build.Artifact
|
||||
if len(checksummedArtifacts) > 0 {
|
||||
outputArtifacts = checksummedArtifacts
|
||||
} else if len(archivedArtifacts) > 0 {
|
||||
|
|
@ -249,13 +249,13 @@ func runProjectBuild(buildType string, ciMode bool, targetsFlag string, outputDi
|
|||
}
|
||||
|
||||
// computeAndWriteChecksums computes checksums for artifacts and writes CHECKSUMS.txt.
|
||||
func computeAndWriteChecksums(ctx context.Context, projectDir, outputDir string, artifacts []buildpkg.Artifact, signCfg signing.SignConfig, ciMode bool) ([]buildpkg.Artifact, error) {
|
||||
func computeAndWriteChecksums(ctx context.Context, projectDir, outputDir string, artifacts []build.Artifact, signCfg signing.SignConfig, ciMode bool) ([]build.Artifact, error) {
|
||||
if !ciMode {
|
||||
fmt.Println()
|
||||
fmt.Printf("%s %s\n", buildHeaderStyle.Render(i18n.T("cmd.build.label.checksum")), i18n.T("cmd.build.computing_checksums"))
|
||||
}
|
||||
|
||||
checksummedArtifacts, err := buildpkg.ChecksumAll(artifacts)
|
||||
checksummedArtifacts, err := build.ChecksumAll(artifacts)
|
||||
if err != nil {
|
||||
if !ciMode {
|
||||
fmt.Printf("%s %s: %v\n", buildErrorStyle.Render(i18n.T("common.label.error")), i18n.T("cmd.build.error.checksum_failed"), err)
|
||||
|
|
@ -265,7 +265,7 @@ func computeAndWriteChecksums(ctx context.Context, projectDir, outputDir string,
|
|||
|
||||
// Write CHECKSUMS.txt
|
||||
checksumPath := filepath.Join(outputDir, "CHECKSUMS.txt")
|
||||
if err := buildpkg.WriteChecksumFile(checksummedArtifacts, checksumPath); err != nil {
|
||||
if err := build.WriteChecksumFile(checksummedArtifacts, checksumPath); err != nil {
|
||||
if !ciMode {
|
||||
fmt.Printf("%s %s: %v\n", buildErrorStyle.Render(i18n.T("common.label.error")), i18n.T("common.error.failed", map[string]any{"Action": "write CHECKSUMS.txt"}), err)
|
||||
}
|
||||
|
|
@ -309,9 +309,9 @@ func computeAndWriteChecksums(ctx context.Context, projectDir, outputDir string,
|
|||
}
|
||||
|
||||
// parseTargets parses a comma-separated list of OS/arch pairs.
|
||||
func parseTargets(targetsFlag string) ([]buildpkg.Target, error) {
|
||||
func parseTargets(targetsFlag string) ([]build.Target, error) {
|
||||
parts := strings.Split(targetsFlag, ",")
|
||||
var targets []buildpkg.Target
|
||||
var targets []build.Target
|
||||
|
||||
for _, part := range parts {
|
||||
part = strings.TrimSpace(part)
|
||||
|
|
@ -324,7 +324,7 @@ func parseTargets(targetsFlag string) ([]buildpkg.Target, error) {
|
|||
return nil, fmt.Errorf("%s", i18n.T("cmd.build.error.invalid_target", map[string]interface{}{"Target": part}))
|
||||
}
|
||||
|
||||
targets = append(targets, buildpkg.Target{
|
||||
targets = append(targets, build.Target{
|
||||
OS: strings.TrimSpace(osArch[0]),
|
||||
Arch: strings.TrimSpace(osArch[1]),
|
||||
})
|
||||
|
|
@ -338,7 +338,7 @@ func parseTargets(targetsFlag string) ([]buildpkg.Target, error) {
|
|||
}
|
||||
|
||||
// formatTargets returns a human-readable string of targets.
|
||||
func formatTargets(targets []buildpkg.Target) string {
|
||||
func formatTargets(targets []build.Target) string {
|
||||
var parts []string
|
||||
for _, t := range targets {
|
||||
parts = append(parts, t.String())
|
||||
|
|
@ -347,21 +347,21 @@ func formatTargets(targets []buildpkg.Target) string {
|
|||
}
|
||||
|
||||
// getBuilder returns the appropriate builder for the project type.
|
||||
func getBuilder(projectType buildpkg.ProjectType) (buildpkg.Builder, error) {
|
||||
func getBuilder(projectType build.ProjectType) (build.Builder, error) {
|
||||
switch projectType {
|
||||
case buildpkg.ProjectTypeWails:
|
||||
case build.ProjectTypeWails:
|
||||
return builders.NewWailsBuilder(), nil
|
||||
case buildpkg.ProjectTypeGo:
|
||||
case build.ProjectTypeGo:
|
||||
return builders.NewGoBuilder(), nil
|
||||
case buildpkg.ProjectTypeDocker:
|
||||
case build.ProjectTypeDocker:
|
||||
return builders.NewDockerBuilder(), nil
|
||||
case buildpkg.ProjectTypeLinuxKit:
|
||||
case build.ProjectTypeLinuxKit:
|
||||
return builders.NewLinuxKitBuilder(), nil
|
||||
case buildpkg.ProjectTypeTaskfile:
|
||||
case build.ProjectTypeTaskfile:
|
||||
return builders.NewTaskfileBuilder(), nil
|
||||
case buildpkg.ProjectTypeNode:
|
||||
case build.ProjectTypeNode:
|
||||
return nil, fmt.Errorf("%s", i18n.T("cmd.build.error.node_not_implemented"))
|
||||
case buildpkg.ProjectTypePHP:
|
||||
case build.ProjectTypePHP:
|
||||
return nil, fmt.Errorf("%s", i18n.T("cmd.build.error.php_not_implemented"))
|
||||
default:
|
||||
return nil, fmt.Errorf("%s: %s", i18n.T("cmd.build.error.unsupported_type"), projectType)
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
// build_pwa.go implements PWA and legacy GUI build functionality.
|
||||
// cmd_pwa.go implements PWA and legacy GUI build functionality.
|
||||
//
|
||||
// Supports building desktop applications from:
|
||||
// - Local static web application directories
|
||||
// - Live PWA URLs (downloads and packages)
|
||||
|
||||
package build
|
||||
package buildcmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
// build_sdk.go implements SDK generation from OpenAPI specifications.
|
||||
// cmd_sdk.go implements SDK generation from OpenAPI specifications.
|
||||
//
|
||||
// Generates typed API clients for TypeScript, Python, Go, and PHP
|
||||
// from OpenAPI/Swagger specifications.
|
||||
|
||||
package build
|
||||
package buildcmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
@ -9,9 +9,16 @@
|
|||
// Configuration via .core/release.yaml.
|
||||
package ci
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
import (
|
||||
"github.com/host-uk/core/pkg/cli"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// AddCommands registers the 'ci' command and all subcommands.
|
||||
func AddCommands(root *cobra.Command) {
|
||||
func init() {
|
||||
cli.RegisterCommands(AddCICommands)
|
||||
}
|
||||
|
||||
// AddCICommands registers the 'ci' command and all subcommands.
|
||||
func AddCICommands(root *cobra.Command) {
|
||||
root.AddCommand(ciCmd)
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package ci
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
|
|
@ -54,7 +55,7 @@ func runCIPublish(dryRun bool, version string, draft, prerelease bool) error {
|
|||
|
||||
// Check for publishers
|
||||
if len(cfg.Publishers) == 0 {
|
||||
return fmt.Errorf(i18n.T("cmd.ci.error.no_publishers"))
|
||||
return errors.New(i18n.T("cmd.ci.error.no_publishers"))
|
||||
}
|
||||
|
||||
// Publish pre-built artifacts
|
||||
50
pkg/cli/commands.go
Normal file
50
pkg/cli/commands.go
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
// Package cli provides the CLI runtime and utilities.
|
||||
package cli
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// CommandRegistration is a function that adds commands to the root.
|
||||
type CommandRegistration func(root *cobra.Command)
|
||||
|
||||
var (
|
||||
registeredCommands []CommandRegistration
|
||||
registeredCommandsMu sync.Mutex
|
||||
commandsAttached bool
|
||||
)
|
||||
|
||||
// RegisterCommands registers a function that adds commands to the CLI.
|
||||
// Call this in your package's init() to register commands.
|
||||
//
|
||||
// func init() {
|
||||
// cli.RegisterCommands(AddCommands)
|
||||
// }
|
||||
//
|
||||
// func AddCommands(root *cobra.Command) {
|
||||
// root.AddCommand(myCmd)
|
||||
// }
|
||||
func RegisterCommands(fn CommandRegistration) {
|
||||
registeredCommandsMu.Lock()
|
||||
defer registeredCommandsMu.Unlock()
|
||||
registeredCommands = append(registeredCommands, fn)
|
||||
|
||||
// If commands already attached (CLI already running), attach immediately
|
||||
if commandsAttached && instance != nil && instance.root != nil {
|
||||
fn(instance.root)
|
||||
}
|
||||
}
|
||||
|
||||
// attachRegisteredCommands calls all registered command functions.
|
||||
// Called by Init() after creating the root command.
|
||||
func attachRegisteredCommands(root *cobra.Command) {
|
||||
registeredCommandsMu.Lock()
|
||||
defer registeredCommandsMu.Unlock()
|
||||
|
||||
for _, fn := range registeredCommands {
|
||||
fn(root)
|
||||
}
|
||||
commandsAttached = true
|
||||
}
|
||||
|
|
@ -22,6 +22,7 @@ import (
|
|||
"syscall"
|
||||
|
||||
"github.com/host-uk/core/pkg/framework"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -32,6 +33,7 @@ var (
|
|||
// runtime is the CLI's internal Core runtime.
|
||||
type runtime struct {
|
||||
core *framework.Core
|
||||
root *cobra.Command
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
|
@ -54,14 +56,24 @@ func Init(opts Options) error {
|
|||
once.Do(func() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
// Create root command
|
||||
rootCmd := &cobra.Command{
|
||||
Use: opts.AppName,
|
||||
Version: opts.Version,
|
||||
}
|
||||
|
||||
// Attach all registered commands
|
||||
attachRegisteredCommands(rootCmd)
|
||||
|
||||
// Build signal service options
|
||||
var signalOpts []SignalOption
|
||||
if opts.OnReload != nil {
|
||||
signalOpts = append(signalOpts, WithReloadHandler(opts.OnReload))
|
||||
}
|
||||
|
||||
// Build options: signal service + any additional services
|
||||
// Build options: app, signal service + any additional services
|
||||
coreOpts := []framework.Option{
|
||||
framework.WithApp(rootCmd),
|
||||
framework.WithName("signal", newSignalService(cancel, signalOpts...)),
|
||||
}
|
||||
coreOpts = append(coreOpts, opts.Services...)
|
||||
|
|
@ -76,6 +88,7 @@ func Init(opts Options) error {
|
|||
|
||||
instance = &runtime{
|
||||
core: c,
|
||||
root: rootCmd,
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
}
|
||||
|
|
@ -102,6 +115,19 @@ func Core() *framework.Core {
|
|||
return instance.core
|
||||
}
|
||||
|
||||
// RootCmd returns the CLI's root cobra command.
|
||||
func RootCmd() *cobra.Command {
|
||||
mustInit()
|
||||
return instance.root
|
||||
}
|
||||
|
||||
// Execute runs the CLI root command.
|
||||
// Returns an error if the command fails.
|
||||
func Execute() error {
|
||||
mustInit()
|
||||
return instance.root.Execute()
|
||||
}
|
||||
|
||||
// Context returns the CLI's root context.
|
||||
// Cancelled on SIGINT/SIGTERM.
|
||||
func Context() context.Context {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import (
|
|||
"context"
|
||||
|
||||
"github.com/host-uk/core/pkg/agentic"
|
||||
devpkg "github.com/host-uk/core/pkg/dev"
|
||||
"github.com/host-uk/core/pkg/framework"
|
||||
"github.com/host-uk/core/pkg/git"
|
||||
)
|
||||
|
|
@ -24,7 +23,7 @@ type WorkBundleOptions struct {
|
|||
// Includes: dev (orchestration), git, agentic services.
|
||||
func NewWorkBundle(opts WorkBundleOptions) (*WorkBundle, error) {
|
||||
c, err := framework.New(
|
||||
framework.WithService(devpkg.NewService(devpkg.ServiceOptions{
|
||||
framework.WithService(NewService(ServiceOptions{
|
||||
RegistryPath: opts.RegistryPath,
|
||||
})),
|
||||
framework.WithService(git.NewService(git.ServiceOptions{})),
|
||||
|
|
@ -64,7 +63,7 @@ type StatusBundleOptions struct {
|
|||
// Includes: dev (orchestration), git services. No agentic - commits not available.
|
||||
func NewStatusBundle(opts StatusBundleOptions) (*StatusBundle, error) {
|
||||
c, err := framework.New(
|
||||
framework.WithService(devpkg.NewService(devpkg.ServiceOptions{
|
||||
framework.WithService(NewService(ServiceOptions{
|
||||
RegistryPath: opts.RegistryPath,
|
||||
})),
|
||||
framework.WithService(git.NewService(git.ServiceOptions{})),
|
||||
|
|
@ -2,6 +2,7 @@ package dev
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
|
@ -68,7 +69,7 @@ func addCICommand(parent *cobra.Command) {
|
|||
func runCI(registryPath string, branch string, failedOnly bool) error {
|
||||
// Check gh is available
|
||||
if _, err := exec.LookPath("gh"); err != nil {
|
||||
return fmt.Errorf(i18n.T("error.gh_not_found"))
|
||||
return errors.New(i18n.T("error.gh_not_found"))
|
||||
}
|
||||
|
||||
// Find or use provided registry
|
||||
|
|
@ -34,6 +34,10 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cli.RegisterCommands(AddDevCommands)
|
||||
}
|
||||
|
||||
// Style aliases from shared package
|
||||
var (
|
||||
successStyle = cli.SuccessStyle
|
||||
|
|
@ -52,8 +56,8 @@ var (
|
|||
cleanStyle = cli.GitCleanStyle.Padding(0, 1)
|
||||
)
|
||||
|
||||
// AddCommands registers the 'dev' command and all subcommands.
|
||||
func AddCommands(root *cobra.Command) {
|
||||
// AddDevCommands registers the 'dev' command and all subcommands.
|
||||
func AddDevCommands(root *cobra.Command) {
|
||||
devCmd := &cobra.Command{
|
||||
Use: "dev",
|
||||
Short: i18n.T("cmd.dev.short"),
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package dev
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
|
|
@ -55,14 +56,14 @@ func runImpact(registryPath string, repoName string) error {
|
|||
return fmt.Errorf("failed to load registry: %w", err)
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf(i18n.T("cmd.dev.impact.requires_registry"))
|
||||
return errors.New(i18n.T("cmd.dev.impact.requires_registry"))
|
||||
}
|
||||
}
|
||||
|
||||
// Check repo exists
|
||||
repo, exists := reg.Get(repoName)
|
||||
if !exists {
|
||||
return fmt.Errorf(i18n.T("error.repo_not_found", map[string]interface{}{"Name": repoName}))
|
||||
return errors.New(i18n.T("error.repo_not_found", map[string]interface{}{"Name": repoName}))
|
||||
}
|
||||
|
||||
// Build reverse dependency graph
|
||||
|
|
@ -2,6 +2,7 @@ package dev
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
|
@ -82,7 +83,7 @@ func addIssuesCommand(parent *cobra.Command) {
|
|||
func runIssues(registryPath string, limit int, assignee string) error {
|
||||
// Check gh is available
|
||||
if _, err := exec.LookPath("gh"); err != nil {
|
||||
return fmt.Errorf(i18n.T("error.gh_not_found"))
|
||||
return errors.New(i18n.T("error.gh_not_found"))
|
||||
}
|
||||
|
||||
// Find or use provided registry, fall back to directory scan
|
||||
|
|
@ -2,6 +2,7 @@ package dev
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
|
@ -79,7 +80,7 @@ func addReviewsCommand(parent *cobra.Command) {
|
|||
func runReviews(registryPath string, author string, showAll bool) error {
|
||||
// Check gh is available
|
||||
if _, err := exec.LookPath("gh"); err != nil {
|
||||
return fmt.Errorf(i18n.T("error.gh_not_found"))
|
||||
return errors.New(i18n.T("error.gh_not_found"))
|
||||
}
|
||||
|
||||
// Find or use provided registry, fall back to directory scan
|
||||
|
|
@ -2,6 +2,7 @@ package dev
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
|
@ -118,7 +119,7 @@ func runVMBoot(memory, cpus int, fresh bool) error {
|
|||
}
|
||||
|
||||
if !d.IsInstalled() {
|
||||
return fmt.Errorf(i18n.T("cmd.dev.vm.not_installed"))
|
||||
return errors.New(i18n.T("cmd.dev.vm.not_installed"))
|
||||
}
|
||||
|
||||
opts := devops.DefaultBootOptions()
|
||||
|
|
@ -8,8 +8,8 @@ import (
|
|||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/host-uk/core/pkg/cli"
|
||||
"github.com/host-uk/core/pkg/agentic"
|
||||
"github.com/host-uk/core/pkg/cli"
|
||||
"github.com/host-uk/core/pkg/git"
|
||||
"github.com/host-uk/core/pkg/i18n"
|
||||
"github.com/host-uk/core/pkg/repos"
|
||||
|
|
@ -8,9 +8,16 @@
|
|||
// to a central location for unified documentation builds.
|
||||
package docs
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
import (
|
||||
"github.com/host-uk/core/pkg/cli"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// AddCommands registers the 'docs' command and all subcommands.
|
||||
func AddCommands(root *cobra.Command) {
|
||||
func init() {
|
||||
cli.RegisterCommands(AddDocsCommands)
|
||||
}
|
||||
|
||||
// AddDocsCommands registers the 'docs' command and all subcommands.
|
||||
func AddDocsCommands(root *cobra.Command) {
|
||||
root.AddCommand(docsCmd)
|
||||
}
|
||||
|
|
@ -10,9 +10,16 @@
|
|||
// Provides platform-specific installation instructions for missing tools.
|
||||
package doctor
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
import (
|
||||
"github.com/host-uk/core/pkg/cli"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// AddCommands registers the 'doctor' command and all subcommands.
|
||||
func AddCommands(root *cobra.Command) {
|
||||
func init() {
|
||||
cli.RegisterCommands(AddDoctorCommands)
|
||||
}
|
||||
|
||||
// AddDoctorCommands registers the 'doctor' command and all subcommands.
|
||||
func AddDoctorCommands(root *cobra.Command) {
|
||||
root.AddCommand(doctorCmd)
|
||||
}
|
||||
|
|
@ -14,9 +14,8 @@
|
|||
// Sets MACOSX_DEPLOYMENT_TARGET to suppress linker warnings on macOS.
|
||||
package gocmd
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
import "github.com/host-uk/core/pkg/cli"
|
||||
|
||||
// AddCommands registers the 'go' command and all subcommands.
|
||||
func AddCommands(root *cobra.Command) {
|
||||
AddGoCommands(root)
|
||||
func init() {
|
||||
cli.RegisterCommands(AddGoCommands)
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package gocmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
|
@ -179,7 +180,7 @@ func addGoCovCommand(parent *cobra.Command) {
|
|||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "discover test packages"}), err)
|
||||
}
|
||||
if len(pkgs) == 0 {
|
||||
return fmt.Errorf(i18n.T("cmd.go.cov.error.no_packages"))
|
||||
return errors.New(i18n.T("cmd.go.cov.error.no_packages"))
|
||||
}
|
||||
pkg = strings.Join(pkgs, " ")
|
||||
}
|
||||
|
|
@ -275,7 +276,7 @@ func addGoCovCommand(parent *cobra.Command) {
|
|||
"Actual": fmt.Sprintf("%.1f", totalCov),
|
||||
"Threshold": fmt.Sprintf("%.1f", covThreshold),
|
||||
})))
|
||||
return fmt.Errorf(i18n.T("cmd.go.cov.error.below_threshold"))
|
||||
return errors.New(i18n.T("cmd.go.cov.error.below_threshold"))
|
||||
}
|
||||
|
||||
if testErr != nil {
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package gocmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
|
@ -193,7 +194,7 @@ func addGoWorkCommand(parent *cobra.Command) {
|
|||
// Auto-detect modules
|
||||
modules := findGoModules(".")
|
||||
if len(modules) == 0 {
|
||||
return fmt.Errorf(i18n.T("cmd.go.work.error.no_modules"))
|
||||
return errors.New(i18n.T("cmd.go.work.error.no_modules"))
|
||||
}
|
||||
for _, mod := range modules {
|
||||
execCmd := exec.Command("go", "work", "use", mod)
|
||||
|
|
@ -8,6 +8,10 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cli.RegisterCommands(AddPHPCommands)
|
||||
}
|
||||
|
||||
// Style aliases from shared
|
||||
var (
|
||||
successStyle = cli.SuccessStyle
|
||||
|
|
@ -2,12 +2,12 @@ package php
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/host-uk/core/pkg/i18n"
|
||||
phppkg "github.com/host-uk/core/pkg/php"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
|
@ -83,14 +83,14 @@ type linuxKitBuildOptions struct {
|
|||
}
|
||||
|
||||
func runPHPBuildDocker(ctx context.Context, projectDir string, opts dockerBuildOptions) error {
|
||||
if !phppkg.IsPHPProject(projectDir) {
|
||||
return fmt.Errorf(i18n.T("cmd.php.error.not_php"))
|
||||
if !IsPHPProject(projectDir) {
|
||||
return errors.New(i18n.T("cmd.php.error.not_php"))
|
||||
}
|
||||
|
||||
fmt.Printf("%s %s\n\n", dimStyle.Render(i18n.T("cmd.php.label.php")), i18n.T("cmd.php.build.building_docker"))
|
||||
|
||||
// Show detected configuration
|
||||
config, err := phppkg.DetectDockerfileConfig(projectDir)
|
||||
config, err := DetectDockerfileConfig(projectDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "detect project configuration"}), err)
|
||||
}
|
||||
|
|
@ -105,7 +105,7 @@ func runPHPBuildDocker(ctx context.Context, projectDir string, opts dockerBuildO
|
|||
fmt.Println()
|
||||
|
||||
// Build options
|
||||
buildOpts := phppkg.DockerBuildOptions{
|
||||
buildOpts := DockerBuildOptions{
|
||||
ProjectDir: projectDir,
|
||||
ImageName: opts.ImageName,
|
||||
Tag: opts.Tag,
|
||||
|
|
@ -116,7 +116,7 @@ func runPHPBuildDocker(ctx context.Context, projectDir string, opts dockerBuildO
|
|||
}
|
||||
|
||||
if buildOpts.ImageName == "" {
|
||||
buildOpts.ImageName = phppkg.GetLaravelAppName(projectDir)
|
||||
buildOpts.ImageName = GetLaravelAppName(projectDir)
|
||||
if buildOpts.ImageName == "" {
|
||||
buildOpts.ImageName = "php-app"
|
||||
}
|
||||
|
|
@ -134,7 +134,7 @@ func runPHPBuildDocker(ctx context.Context, projectDir string, opts dockerBuildO
|
|||
}
|
||||
fmt.Println()
|
||||
|
||||
if err := phppkg.BuildDocker(ctx, buildOpts); err != nil {
|
||||
if err := BuildDocker(ctx, buildOpts); err != nil {
|
||||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "build"}), err)
|
||||
}
|
||||
|
||||
|
|
@ -147,13 +147,13 @@ func runPHPBuildDocker(ctx context.Context, projectDir string, opts dockerBuildO
|
|||
}
|
||||
|
||||
func runPHPBuildLinuxKit(ctx context.Context, projectDir string, opts linuxKitBuildOptions) error {
|
||||
if !phppkg.IsPHPProject(projectDir) {
|
||||
return fmt.Errorf(i18n.T("cmd.php.error.not_php"))
|
||||
if !IsPHPProject(projectDir) {
|
||||
return errors.New(i18n.T("cmd.php.error.not_php"))
|
||||
}
|
||||
|
||||
fmt.Printf("%s %s\n\n", dimStyle.Render(i18n.T("cmd.php.label.php")), i18n.T("cmd.php.build.building_linuxkit"))
|
||||
|
||||
buildOpts := phppkg.LinuxKitBuildOptions{
|
||||
buildOpts := LinuxKitBuildOptions{
|
||||
ProjectDir: projectDir,
|
||||
OutputPath: opts.OutputPath,
|
||||
Format: opts.Format,
|
||||
|
|
@ -172,7 +172,7 @@ func runPHPBuildLinuxKit(ctx context.Context, projectDir string, opts linuxKitBu
|
|||
fmt.Printf("%s %s\n", dimStyle.Render(i18n.T("cmd.php.build.format")), buildOpts.Format)
|
||||
fmt.Println()
|
||||
|
||||
if err := phppkg.BuildLinuxKit(ctx, buildOpts); err != nil {
|
||||
if err := BuildLinuxKit(ctx, buildOpts); err != nil {
|
||||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "build"}), err)
|
||||
}
|
||||
|
||||
|
|
@ -201,19 +201,19 @@ func addPHPServeCommand(parent *cobra.Command) {
|
|||
// Try to detect from current directory
|
||||
cwd, err := os.Getwd()
|
||||
if err == nil {
|
||||
imageName = phppkg.GetLaravelAppName(cwd)
|
||||
imageName = GetLaravelAppName(cwd)
|
||||
if imageName != "" {
|
||||
imageName = strings.ToLower(strings.ReplaceAll(imageName, " ", "-"))
|
||||
}
|
||||
}
|
||||
if imageName == "" {
|
||||
return fmt.Errorf(i18n.T("cmd.php.serve.name_required"))
|
||||
return errors.New(i18n.T("cmd.php.serve.name_required"))
|
||||
}
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
opts := phppkg.ServeOptions{
|
||||
opts := ServeOptions{
|
||||
ImageName: imageName,
|
||||
Tag: serveTag,
|
||||
ContainerName: serveContainerName,
|
||||
|
|
@ -245,7 +245,7 @@ func addPHPServeCommand(parent *cobra.Command) {
|
|||
dimStyle.Render("Ports:"), effectivePort, effectiveHTTPSPort)
|
||||
fmt.Println()
|
||||
|
||||
if err := phppkg.ServeProduction(ctx, opts); err != nil {
|
||||
if err := ServeProduction(ctx, opts); err != nil {
|
||||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "start container"}), err)
|
||||
}
|
||||
|
||||
|
|
@ -279,7 +279,7 @@ func addPHPShellCommand(parent *cobra.Command) {
|
|||
|
||||
fmt.Printf("%s %s\n", dimStyle.Render(i18n.T("cmd.php.label.php")), i18n.T("cmd.php.shell.opening", map[string]interface{}{"Container": args[0]}))
|
||||
|
||||
if err := phppkg.Shell(ctx, args[0]); err != nil {
|
||||
if err := Shell(ctx, args[0]); err != nil {
|
||||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "open shell"}), err)
|
||||
}
|
||||
|
||||
|
|
@ -8,7 +8,6 @@ import (
|
|||
|
||||
"github.com/host-uk/core/pkg/cli"
|
||||
"github.com/host-uk/core/pkg/i18n"
|
||||
phppkg "github.com/host-uk/core/pkg/php"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
|
@ -50,23 +49,23 @@ func addPHPDeployCommand(parent *cobra.Command) {
|
|||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "get working directory"}), err)
|
||||
}
|
||||
|
||||
env := phppkg.EnvProduction
|
||||
env := EnvProduction
|
||||
if deployStaging {
|
||||
env = phppkg.EnvStaging
|
||||
env = EnvStaging
|
||||
}
|
||||
|
||||
fmt.Printf("%s %s\n\n", dimStyle.Render(i18n.T("cmd.php.label.deploy")), i18n.T("cmd.php.deploy.deploying", map[string]interface{}{"Environment": env}))
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
opts := phppkg.DeployOptions{
|
||||
opts := DeployOptions{
|
||||
Dir: cwd,
|
||||
Environment: env,
|
||||
Force: deployForce,
|
||||
Wait: deployWait,
|
||||
}
|
||||
|
||||
status, err := phppkg.Deploy(ctx, opts)
|
||||
status, err := Deploy(ctx, opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %w", i18n.T("cmd.php.error.deploy_failed"), err)
|
||||
}
|
||||
|
|
@ -74,7 +73,7 @@ func addPHPDeployCommand(parent *cobra.Command) {
|
|||
printDeploymentStatus(status)
|
||||
|
||||
if deployWait {
|
||||
if phppkg.IsDeploymentSuccessful(status.Status) {
|
||||
if IsDeploymentSuccessful(status.Status) {
|
||||
fmt.Printf("\n%s %s\n", successStyle.Render(i18n.T("common.label.done")), i18n.T("common.success.completed", map[string]any{"Action": "Deployment completed"}))
|
||||
} else {
|
||||
fmt.Printf("\n%s %s\n", errorStyle.Render(i18n.T("common.label.warning")), i18n.T("cmd.php.deploy.warning_status", map[string]interface{}{"Status": status.Status}))
|
||||
|
|
@ -110,22 +109,22 @@ func addPHPDeployStatusCommand(parent *cobra.Command) {
|
|||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "get working directory"}), err)
|
||||
}
|
||||
|
||||
env := phppkg.EnvProduction
|
||||
env := EnvProduction
|
||||
if deployStatusStaging {
|
||||
env = phppkg.EnvStaging
|
||||
env = EnvStaging
|
||||
}
|
||||
|
||||
fmt.Printf("%s %s\n\n", dimStyle.Render(i18n.T("cmd.php.label.deploy")), i18n.T("common.progress.checking", map[string]any{"Item": "deployment status"}))
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
opts := phppkg.StatusOptions{
|
||||
opts := StatusOptions{
|
||||
Dir: cwd,
|
||||
Environment: env,
|
||||
DeploymentID: deployStatusDeploymentID,
|
||||
}
|
||||
|
||||
status, err := phppkg.DeployStatus(ctx, opts)
|
||||
status, err := DeployStatus(ctx, opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "get status"}), err)
|
||||
}
|
||||
|
|
@ -159,23 +158,23 @@ func addPHPDeployRollbackCommand(parent *cobra.Command) {
|
|||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "get working directory"}), err)
|
||||
}
|
||||
|
||||
env := phppkg.EnvProduction
|
||||
env := EnvProduction
|
||||
if rollbackStaging {
|
||||
env = phppkg.EnvStaging
|
||||
env = EnvStaging
|
||||
}
|
||||
|
||||
fmt.Printf("%s %s\n\n", dimStyle.Render(i18n.T("cmd.php.label.deploy")), i18n.T("cmd.php.deploy_rollback.rolling_back", map[string]interface{}{"Environment": env}))
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
opts := phppkg.RollbackOptions{
|
||||
opts := RollbackOptions{
|
||||
Dir: cwd,
|
||||
Environment: env,
|
||||
DeploymentID: rollbackDeploymentID,
|
||||
Wait: rollbackWait,
|
||||
}
|
||||
|
||||
status, err := phppkg.Rollback(ctx, opts)
|
||||
status, err := Rollback(ctx, opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %w", i18n.T("cmd.php.error.rollback_failed"), err)
|
||||
}
|
||||
|
|
@ -183,7 +182,7 @@ func addPHPDeployRollbackCommand(parent *cobra.Command) {
|
|||
printDeploymentStatus(status)
|
||||
|
||||
if rollbackWait {
|
||||
if phppkg.IsDeploymentSuccessful(status.Status) {
|
||||
if IsDeploymentSuccessful(status.Status) {
|
||||
fmt.Printf("\n%s %s\n", successStyle.Render(i18n.T("common.label.done")), i18n.T("common.success.completed", map[string]any{"Action": "Rollback completed"}))
|
||||
} else {
|
||||
fmt.Printf("\n%s %s\n", errorStyle.Render(i18n.T("common.label.warning")), i18n.T("cmd.php.deploy_rollback.warning_status", map[string]interface{}{"Status": status.Status}))
|
||||
|
|
@ -219,9 +218,9 @@ func addPHPDeployListCommand(parent *cobra.Command) {
|
|||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "get working directory"}), err)
|
||||
}
|
||||
|
||||
env := phppkg.EnvProduction
|
||||
env := EnvProduction
|
||||
if deployListStaging {
|
||||
env = phppkg.EnvStaging
|
||||
env = EnvStaging
|
||||
}
|
||||
|
||||
limit := deployListLimit
|
||||
|
|
@ -233,7 +232,7 @@ func addPHPDeployListCommand(parent *cobra.Command) {
|
|||
|
||||
ctx := context.Background()
|
||||
|
||||
deployments, err := phppkg.ListDeployments(ctx, cwd, env, limit)
|
||||
deployments, err := ListDeployments(ctx, cwd, env, limit)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "list deployments"}), err)
|
||||
}
|
||||
|
|
@ -257,7 +256,7 @@ func addPHPDeployListCommand(parent *cobra.Command) {
|
|||
parent.AddCommand(listCmd)
|
||||
}
|
||||
|
||||
func printDeploymentStatus(status *phppkg.DeploymentStatus) {
|
||||
func printDeploymentStatus(status *DeploymentStatus) {
|
||||
// Status with color
|
||||
statusStyle := phpDeployStyle
|
||||
switch status.Status {
|
||||
|
|
@ -310,7 +309,7 @@ func printDeploymentStatus(status *phppkg.DeploymentStatus) {
|
|||
}
|
||||
}
|
||||
|
||||
func printDeploymentSummary(index int, status *phppkg.DeploymentStatus) {
|
||||
func printDeploymentSummary(index int, status *DeploymentStatus) {
|
||||
// Status with color
|
||||
statusStyle := phpDeployStyle
|
||||
switch status.Status {
|
||||
|
|
@ -3,6 +3,7 @@ package php
|
|||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
|
|
@ -12,7 +13,6 @@ import (
|
|||
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/host-uk/core/pkg/i18n"
|
||||
phppkg "github.com/host-uk/core/pkg/php"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
|
@ -72,12 +72,12 @@ func runPHPDev(opts phpDevOptions) error {
|
|||
}
|
||||
|
||||
// Check if this is a Laravel project
|
||||
if !phppkg.IsLaravelProject(cwd) {
|
||||
return fmt.Errorf(i18n.T("cmd.php.error.not_laravel"))
|
||||
if !IsLaravelProject(cwd) {
|
||||
return errors.New(i18n.T("cmd.php.error.not_laravel"))
|
||||
}
|
||||
|
||||
// Get app name for display
|
||||
appName := phppkg.GetLaravelAppName(cwd)
|
||||
appName := GetLaravelAppName(cwd)
|
||||
if appName == "" {
|
||||
appName = "Laravel"
|
||||
}
|
||||
|
|
@ -85,7 +85,7 @@ func runPHPDev(opts phpDevOptions) error {
|
|||
fmt.Printf("%s %s\n\n", dimStyle.Render(i18n.T("cmd.php.label.php")), i18n.T("cmd.php.dev.starting", map[string]interface{}{"AppName": appName}))
|
||||
|
||||
// Detect services
|
||||
services := phppkg.DetectServices(cwd)
|
||||
services := DetectServices(cwd)
|
||||
fmt.Printf("%s %s\n", dimStyle.Render(i18n.T("cmd.php.label.services")), i18n.T("cmd.php.dev.detected_services"))
|
||||
for _, svc := range services {
|
||||
fmt.Printf(" %s %s\n", successStyle.Render("*"), svc)
|
||||
|
|
@ -98,7 +98,7 @@ func runPHPDev(opts phpDevOptions) error {
|
|||
port = 8000
|
||||
}
|
||||
|
||||
devOpts := phppkg.Options{
|
||||
devOpts := Options{
|
||||
Dir: cwd,
|
||||
NoVite: opts.NoVite,
|
||||
NoHorizon: opts.NoHorizon,
|
||||
|
|
@ -110,7 +110,7 @@ func runPHPDev(opts phpDevOptions) error {
|
|||
}
|
||||
|
||||
// Create and start dev server
|
||||
server := phppkg.NewDevServer(devOpts)
|
||||
server := NewDevServer(devOpts)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
|
@ -135,7 +135,7 @@ func runPHPDev(opts phpDevOptions) error {
|
|||
fmt.Println()
|
||||
|
||||
// Print URLs
|
||||
appURL := phppkg.GetLaravelAppURL(cwd)
|
||||
appURL := GetLaravelAppURL(cwd)
|
||||
if appURL == "" {
|
||||
if opts.HTTPS {
|
||||
appURL = fmt.Sprintf("https://localhost:%d", port)
|
||||
|
|
@ -146,7 +146,7 @@ func runPHPDev(opts phpDevOptions) error {
|
|||
fmt.Printf("%s %s\n", dimStyle.Render(i18n.T("cmd.php.label.app_url")), linkStyle.Render(appURL))
|
||||
|
||||
// Check for Vite
|
||||
if !opts.NoVite && containsService(services, phppkg.ServiceVite) {
|
||||
if !opts.NoVite && containsService(services, ServiceVite) {
|
||||
fmt.Printf("%s %s\n", dimStyle.Render(i18n.T("cmd.php.label.vite")), linkStyle.Render("http://localhost:5173"))
|
||||
}
|
||||
|
||||
|
|
@ -208,12 +208,12 @@ func runPHPLogs(service string, follow bool) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if !phppkg.IsLaravelProject(cwd) {
|
||||
return fmt.Errorf(i18n.T("cmd.php.error.not_laravel_short"))
|
||||
if !IsLaravelProject(cwd) {
|
||||
return errors.New(i18n.T("cmd.php.error.not_laravel_short"))
|
||||
}
|
||||
|
||||
// Create a minimal server just to access logs
|
||||
server := phppkg.NewDevServer(phppkg.Options{Dir: cwd})
|
||||
server := NewDevServer(Options{Dir: cwd})
|
||||
|
||||
logsReader, err := server.Logs(service, follow)
|
||||
if err != nil {
|
||||
|
|
@ -268,7 +268,7 @@ func runPHPStop() error {
|
|||
|
||||
// We need to find running processes
|
||||
// This is a simplified version - in practice you'd want to track PIDs
|
||||
server := phppkg.NewDevServer(phppkg.Options{Dir: cwd})
|
||||
server := NewDevServer(Options{Dir: cwd})
|
||||
if err := server.Stop(); err != nil {
|
||||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "stop services"}), err)
|
||||
}
|
||||
|
|
@ -295,11 +295,11 @@ func runPHPStatus() error {
|
|||
return err
|
||||
}
|
||||
|
||||
if !phppkg.IsLaravelProject(cwd) {
|
||||
return fmt.Errorf(i18n.T("cmd.php.error.not_laravel_short"))
|
||||
if !IsLaravelProject(cwd) {
|
||||
return errors.New(i18n.T("cmd.php.error.not_laravel_short"))
|
||||
}
|
||||
|
||||
appName := phppkg.GetLaravelAppName(cwd)
|
||||
appName := GetLaravelAppName(cwd)
|
||||
if appName == "" {
|
||||
appName = "Laravel"
|
||||
}
|
||||
|
|
@ -307,7 +307,7 @@ func runPHPStatus() error {
|
|||
fmt.Printf("%s %s\n\n", dimStyle.Render(i18n.T("common.label.project")), appName)
|
||||
|
||||
// Detect available services
|
||||
services := phppkg.DetectServices(cwd)
|
||||
services := DetectServices(cwd)
|
||||
fmt.Printf("%s\n", dimStyle.Render(i18n.T("cmd.php.status.detected_services")))
|
||||
for _, svc := range services {
|
||||
style := getServiceStyle(string(svc))
|
||||
|
|
@ -316,19 +316,19 @@ func runPHPStatus() error {
|
|||
fmt.Println()
|
||||
|
||||
// Package manager
|
||||
pm := phppkg.DetectPackageManager(cwd)
|
||||
pm := DetectPackageManager(cwd)
|
||||
fmt.Printf("%s %s\n", dimStyle.Render(i18n.T("cmd.php.status.package_manager")), pm)
|
||||
|
||||
// FrankenPHP status
|
||||
if phppkg.IsFrankenPHPProject(cwd) {
|
||||
if IsFrankenPHPProject(cwd) {
|
||||
fmt.Printf("%s %s\n", dimStyle.Render(i18n.T("cmd.php.status.octane_server")), "FrankenPHP")
|
||||
}
|
||||
|
||||
// SSL status
|
||||
appURL := phppkg.GetLaravelAppURL(cwd)
|
||||
appURL := GetLaravelAppURL(cwd)
|
||||
if appURL != "" {
|
||||
domain := phppkg.ExtractDomainFromURL(appURL)
|
||||
if phppkg.CertsExist(domain, phppkg.SSLOptions{}) {
|
||||
domain := ExtractDomainFromURL(appURL)
|
||||
if CertsExist(domain, SSLOptions{}) {
|
||||
fmt.Printf("%s %s\n", dimStyle.Render(i18n.T("cmd.php.status.ssl_certs")), successStyle.Render(i18n.T("cmd.php.status.ssl_installed")))
|
||||
} else {
|
||||
fmt.Printf("%s %s\n", dimStyle.Render(i18n.T("cmd.php.status.ssl_certs")), dimStyle.Render(i18n.T("cmd.php.status.ssl_not_setup")))
|
||||
|
|
@ -362,9 +362,9 @@ func runPHPSSL(domain string) error {
|
|||
|
||||
// Get domain from APP_URL if not specified
|
||||
if domain == "" {
|
||||
appURL := phppkg.GetLaravelAppURL(cwd)
|
||||
appURL := GetLaravelAppURL(cwd)
|
||||
if appURL != "" {
|
||||
domain = phppkg.ExtractDomainFromURL(appURL)
|
||||
domain = ExtractDomainFromURL(appURL)
|
||||
}
|
||||
}
|
||||
if domain == "" {
|
||||
|
|
@ -372,32 +372,32 @@ func runPHPSSL(domain string) error {
|
|||
}
|
||||
|
||||
// Check if mkcert is installed
|
||||
if !phppkg.IsMkcertInstalled() {
|
||||
if !IsMkcertInstalled() {
|
||||
fmt.Printf("%s %s\n", errorStyle.Render(i18n.T("common.label.error")), i18n.T("cmd.php.ssl.mkcert_not_installed"))
|
||||
fmt.Printf("\n%s\n", i18n.T("common.hint.install_with"))
|
||||
fmt.Printf(" %s\n", i18n.T("cmd.php.ssl.install_macos"))
|
||||
fmt.Printf(" %s\n", i18n.T("cmd.php.ssl.install_linux"))
|
||||
return fmt.Errorf(i18n.T("cmd.php.error.mkcert_not_installed"))
|
||||
return errors.New(i18n.T("cmd.php.error.mkcert_not_installed"))
|
||||
}
|
||||
|
||||
fmt.Printf("%s %s\n", dimStyle.Render("SSL:"), i18n.T("cmd.php.ssl.setting_up", map[string]interface{}{"Domain": domain}))
|
||||
|
||||
// Check if certs already exist
|
||||
if phppkg.CertsExist(domain, phppkg.SSLOptions{}) {
|
||||
if CertsExist(domain, SSLOptions{}) {
|
||||
fmt.Printf("%s %s\n", dimStyle.Render(i18n.T("common.label.skip")), i18n.T("cmd.php.ssl.certs_exist"))
|
||||
|
||||
certFile, keyFile, _ := phppkg.CertPaths(domain, phppkg.SSLOptions{})
|
||||
certFile, keyFile, _ := CertPaths(domain, SSLOptions{})
|
||||
fmt.Printf("%s %s\n", dimStyle.Render(i18n.T("cmd.php.ssl.cert_label")), certFile)
|
||||
fmt.Printf("%s %s\n", dimStyle.Render(i18n.T("cmd.php.ssl.key_label")), keyFile)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Setup SSL
|
||||
if err := phppkg.SetupSSL(domain, phppkg.SSLOptions{}); err != nil {
|
||||
if err := SetupSSL(domain, SSLOptions{}); err != nil {
|
||||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "setup SSL"}), err)
|
||||
}
|
||||
|
||||
certFile, keyFile, _ := phppkg.CertPaths(domain, phppkg.SSLOptions{})
|
||||
certFile, keyFile, _ := CertPaths(domain, SSLOptions{})
|
||||
|
||||
fmt.Printf("%s %s\n", successStyle.Render(i18n.T("common.label.done")), i18n.T("cmd.php.ssl.certs_created"))
|
||||
fmt.Printf("%s %s\n", dimStyle.Render(i18n.T("cmd.php.ssl.cert_label")), certFile)
|
||||
|
|
@ -408,7 +408,7 @@ func runPHPSSL(domain string) error {
|
|||
|
||||
// Helper functions for dev commands
|
||||
|
||||
func printServiceStatuses(statuses []phppkg.ServiceStatus) {
|
||||
func printServiceStatuses(statuses []ServiceStatus) {
|
||||
for _, s := range statuses {
|
||||
style := getServiceStyle(s.Name)
|
||||
var statusText string
|
||||
|
|
@ -488,7 +488,7 @@ func getServiceStyle(name string) lipgloss.Style {
|
|||
}
|
||||
}
|
||||
|
||||
func containsService(services []phppkg.DetectedService, target phppkg.DetectedService) bool {
|
||||
func containsService(services []DetectedService, target DetectedService) bool {
|
||||
for _, s := range services {
|
||||
if s == target {
|
||||
return true
|
||||
|
|
@ -5,7 +5,6 @@ import (
|
|||
"os"
|
||||
|
||||
"github.com/host-uk/core/pkg/i18n"
|
||||
phppkg "github.com/host-uk/core/pkg/php"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
|
@ -37,7 +36,7 @@ func addPHPPackagesLinkCommand(parent *cobra.Command) {
|
|||
|
||||
fmt.Printf("%s %s\n\n", dimStyle.Render(i18n.T("cmd.php.label.php")), i18n.T("cmd.php.packages.link.linking"))
|
||||
|
||||
if err := phppkg.LinkPackages(cwd, args); err != nil {
|
||||
if err := LinkPackages(cwd, args); err != nil {
|
||||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "link packages"}), err)
|
||||
}
|
||||
|
||||
|
|
@ -63,7 +62,7 @@ func addPHPPackagesUnlinkCommand(parent *cobra.Command) {
|
|||
|
||||
fmt.Printf("%s %s\n\n", dimStyle.Render(i18n.T("cmd.php.label.php")), i18n.T("cmd.php.packages.unlink.unlinking"))
|
||||
|
||||
if err := phppkg.UnlinkPackages(cwd, args); err != nil {
|
||||
if err := UnlinkPackages(cwd, args); err != nil {
|
||||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "unlink packages"}), err)
|
||||
}
|
||||
|
||||
|
|
@ -88,7 +87,7 @@ func addPHPPackagesUpdateCommand(parent *cobra.Command) {
|
|||
|
||||
fmt.Printf("%s %s\n\n", dimStyle.Render(i18n.T("cmd.php.label.php")), i18n.T("cmd.php.packages.update.updating"))
|
||||
|
||||
if err := phppkg.UpdatePackages(cwd, args); err != nil {
|
||||
if err := UpdatePackages(cwd, args); err != nil {
|
||||
return fmt.Errorf("%s: %w", i18n.T("cmd.php.error.update_packages"), err)
|
||||
}
|
||||
|
||||
|
|
@ -111,7 +110,7 @@ func addPHPPackagesListCommand(parent *cobra.Command) {
|
|||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "get working directory"}), err)
|
||||
}
|
||||
|
||||
packages, err := phppkg.ListLinkedPackages(cwd)
|
||||
packages, err := ListLinkedPackages(cwd)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "list packages"}), err)
|
||||
}
|
||||
|
|
@ -10,7 +10,6 @@ import (
|
|||
|
||||
"github.com/host-uk/core/pkg/framework"
|
||||
"github.com/host-uk/core/pkg/i18n"
|
||||
phppkg "github.com/host-uk/core/pkg/php"
|
||||
"github.com/host-uk/core/pkg/process"
|
||||
)
|
||||
|
||||
|
|
@ -78,11 +77,11 @@ func (r *QARunner) buildSpec(check string) *process.RunSpec {
|
|||
}
|
||||
|
||||
case "fmt":
|
||||
formatter, found := phppkg.DetectFormatter(r.dir)
|
||||
formatter, found := DetectFormatter(r.dir)
|
||||
if !found {
|
||||
return nil
|
||||
}
|
||||
if formatter == phppkg.FormatterPint {
|
||||
if formatter == FormatterPint {
|
||||
vendorBin := filepath.Join(r.dir, "vendor", "bin", "pint")
|
||||
cmd := "pint"
|
||||
if _, err := os.Stat(vendorBin); err == nil {
|
||||
|
|
@ -103,7 +102,7 @@ func (r *QARunner) buildSpec(check string) *process.RunSpec {
|
|||
return nil
|
||||
|
||||
case "stan":
|
||||
_, found := phppkg.DetectAnalyser(r.dir)
|
||||
_, found := DetectAnalyser(r.dir)
|
||||
if !found {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -121,7 +120,7 @@ func (r *QARunner) buildSpec(check string) *process.RunSpec {
|
|||
}
|
||||
|
||||
case "psalm":
|
||||
_, found := phppkg.DetectPsalm(r.dir)
|
||||
_, found := DetectPsalm(r.dir)
|
||||
if !found {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -158,7 +157,7 @@ func (r *QARunner) buildSpec(check string) *process.RunSpec {
|
|||
|
||||
// Tests depend on stan (or psalm if available)
|
||||
after := []string{"stan"}
|
||||
if _, found := phppkg.DetectPsalm(r.dir); found {
|
||||
if _, found := DetectPsalm(r.dir); found {
|
||||
after = []string{"psalm"}
|
||||
}
|
||||
|
||||
|
|
@ -171,7 +170,7 @@ func (r *QARunner) buildSpec(check string) *process.RunSpec {
|
|||
}
|
||||
|
||||
case "rector":
|
||||
if !phppkg.DetectRector(r.dir) {
|
||||
if !DetectRector(r.dir) {
|
||||
return nil
|
||||
}
|
||||
vendorBin := filepath.Join(r.dir, "vendor", "bin", "rector")
|
||||
|
|
@ -193,7 +192,7 @@ func (r *QARunner) buildSpec(check string) *process.RunSpec {
|
|||
}
|
||||
|
||||
case "infection":
|
||||
if !phppkg.DetectInfection(r.dir) {
|
||||
if !DetectInfection(r.dir) {
|
||||
return nil
|
||||
}
|
||||
vendorBin := filepath.Join(r.dir, "vendor", "bin", "infection")
|
||||
|
|
@ -215,11 +214,11 @@ func (r *QARunner) buildSpec(check string) *process.RunSpec {
|
|||
}
|
||||
|
||||
// Run executes all QA checks and returns the results.
|
||||
func (r *QARunner) Run(ctx context.Context, stages []phppkg.QAStage) (*QARunResult, error) {
|
||||
func (r *QARunner) Run(ctx context.Context, stages []QAStage) (*QARunResult, error) {
|
||||
// Collect all checks from all stages
|
||||
var allChecks []string
|
||||
for _, stage := range stages {
|
||||
checks := phppkg.GetQAChecks(r.dir, stage)
|
||||
checks := GetQAChecks(r.dir, stage)
|
||||
allChecks = append(allChecks, checks...)
|
||||
}
|
||||
|
||||
|
|
@ -2,13 +2,13 @@ package php
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/host-uk/core/pkg/i18n"
|
||||
phppkg "github.com/host-uk/core/pkg/php"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
|
@ -30,15 +30,15 @@ func addPHPTestCommand(parent *cobra.Command) {
|
|||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "get working directory"}), err)
|
||||
}
|
||||
|
||||
if !phppkg.IsPHPProject(cwd) {
|
||||
return fmt.Errorf(i18n.T("cmd.php.error.not_php"))
|
||||
if !IsPHPProject(cwd) {
|
||||
return errors.New(i18n.T("cmd.php.error.not_php"))
|
||||
}
|
||||
|
||||
fmt.Printf("%s %s\n\n", dimStyle.Render(i18n.T("cmd.php.label.php")), i18n.T("common.progress.running", map[string]any{"Task": "tests"}))
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
opts := phppkg.TestOptions{
|
||||
opts := TestOptions{
|
||||
Dir: cwd,
|
||||
Filter: testFilter,
|
||||
Parallel: testParallel,
|
||||
|
|
@ -50,7 +50,7 @@ func addPHPTestCommand(parent *cobra.Command) {
|
|||
opts.Groups = []string{testGroup}
|
||||
}
|
||||
|
||||
if err := phppkg.RunTests(ctx, opts); err != nil {
|
||||
if err := RunTests(ctx, opts); err != nil {
|
||||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "run tests"}), err)
|
||||
}
|
||||
|
||||
|
|
@ -82,14 +82,14 @@ func addPHPFmtCommand(parent *cobra.Command) {
|
|||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "get working directory"}), err)
|
||||
}
|
||||
|
||||
if !phppkg.IsPHPProject(cwd) {
|
||||
return fmt.Errorf(i18n.T("cmd.php.error.not_php"))
|
||||
if !IsPHPProject(cwd) {
|
||||
return errors.New(i18n.T("cmd.php.error.not_php"))
|
||||
}
|
||||
|
||||
// Detect formatter
|
||||
formatter, found := phppkg.DetectFormatter(cwd)
|
||||
formatter, found := DetectFormatter(cwd)
|
||||
if !found {
|
||||
return fmt.Errorf(i18n.T("cmd.php.fmt.no_formatter"))
|
||||
return errors.New(i18n.T("cmd.php.fmt.no_formatter"))
|
||||
}
|
||||
|
||||
var msg string
|
||||
|
|
@ -102,7 +102,7 @@ func addPHPFmtCommand(parent *cobra.Command) {
|
|||
|
||||
ctx := context.Background()
|
||||
|
||||
opts := phppkg.FormatOptions{
|
||||
opts := FormatOptions{
|
||||
Dir: cwd,
|
||||
Fix: fmtFix,
|
||||
Diff: fmtDiff,
|
||||
|
|
@ -114,7 +114,7 @@ func addPHPFmtCommand(parent *cobra.Command) {
|
|||
opts.Paths = args
|
||||
}
|
||||
|
||||
if err := phppkg.Format(ctx, opts); err != nil {
|
||||
if err := Format(ctx, opts); err != nil {
|
||||
if fmtFix {
|
||||
return fmt.Errorf("%s: %w", i18n.T("cmd.php.error.fmt_failed"), err)
|
||||
}
|
||||
|
|
@ -153,21 +153,21 @@ func addPHPStanCommand(parent *cobra.Command) {
|
|||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "get working directory"}), err)
|
||||
}
|
||||
|
||||
if !phppkg.IsPHPProject(cwd) {
|
||||
return fmt.Errorf(i18n.T("cmd.php.error.not_php"))
|
||||
if !IsPHPProject(cwd) {
|
||||
return errors.New(i18n.T("cmd.php.error.not_php"))
|
||||
}
|
||||
|
||||
// Detect analyser
|
||||
_, found := phppkg.DetectAnalyser(cwd)
|
||||
_, found := DetectAnalyser(cwd)
|
||||
if !found {
|
||||
return fmt.Errorf(i18n.T("cmd.php.analyse.no_analyser"))
|
||||
return errors.New(i18n.T("cmd.php.analyse.no_analyser"))
|
||||
}
|
||||
|
||||
fmt.Printf("%s %s\n\n", dimStyle.Render(i18n.T("cmd.php.label.php")), i18n.T("common.progress.running", map[string]any{"Task": "static analysis"}))
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
opts := phppkg.AnalyseOptions{
|
||||
opts := AnalyseOptions{
|
||||
Dir: cwd,
|
||||
Level: stanLevel,
|
||||
Memory: stanMemory,
|
||||
|
|
@ -179,7 +179,7 @@ func addPHPStanCommand(parent *cobra.Command) {
|
|||
opts.Paths = args
|
||||
}
|
||||
|
||||
if err := phppkg.Analyse(ctx, opts); err != nil {
|
||||
if err := Analyse(ctx, opts); err != nil {
|
||||
return fmt.Errorf("%s: %w", i18n.T("cmd.php.error.analysis_issues"), err)
|
||||
}
|
||||
|
||||
|
|
@ -216,17 +216,17 @@ func addPHPPsalmCommand(parent *cobra.Command) {
|
|||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "get working directory"}), err)
|
||||
}
|
||||
|
||||
if !phppkg.IsPHPProject(cwd) {
|
||||
return fmt.Errorf(i18n.T("cmd.php.error.not_php"))
|
||||
if !IsPHPProject(cwd) {
|
||||
return errors.New(i18n.T("cmd.php.error.not_php"))
|
||||
}
|
||||
|
||||
// Check if Psalm is available
|
||||
_, found := phppkg.DetectPsalm(cwd)
|
||||
_, found := DetectPsalm(cwd)
|
||||
if !found {
|
||||
fmt.Printf("%s %s\n\n", errorStyle.Render(i18n.T("common.label.error")), i18n.T("cmd.php.psalm.not_found"))
|
||||
fmt.Printf("%s %s\n", dimStyle.Render(i18n.T("common.label.install")), i18n.T("cmd.php.psalm.install"))
|
||||
fmt.Printf("%s %s\n", dimStyle.Render(i18n.T("cmd.php.label.setup")), i18n.T("cmd.php.psalm.setup"))
|
||||
return fmt.Errorf(i18n.T("cmd.php.error.psalm_not_installed"))
|
||||
return errors.New(i18n.T("cmd.php.error.psalm_not_installed"))
|
||||
}
|
||||
|
||||
var msg string
|
||||
|
|
@ -239,7 +239,7 @@ func addPHPPsalmCommand(parent *cobra.Command) {
|
|||
|
||||
ctx := context.Background()
|
||||
|
||||
opts := phppkg.PsalmOptions{
|
||||
opts := PsalmOptions{
|
||||
Dir: cwd,
|
||||
Level: psalmLevel,
|
||||
Fix: psalmFix,
|
||||
|
|
@ -248,7 +248,7 @@ func addPHPPsalmCommand(parent *cobra.Command) {
|
|||
Output: os.Stdout,
|
||||
}
|
||||
|
||||
if err := phppkg.RunPsalm(ctx, opts); err != nil {
|
||||
if err := RunPsalm(ctx, opts); err != nil {
|
||||
return fmt.Errorf("%s: %w", i18n.T("cmd.php.error.psalm_issues"), err)
|
||||
}
|
||||
|
||||
|
|
@ -281,15 +281,15 @@ func addPHPAuditCommand(parent *cobra.Command) {
|
|||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "get working directory"}), err)
|
||||
}
|
||||
|
||||
if !phppkg.IsPHPProject(cwd) {
|
||||
return fmt.Errorf(i18n.T("cmd.php.error.not_php"))
|
||||
if !IsPHPProject(cwd) {
|
||||
return errors.New(i18n.T("cmd.php.error.not_php"))
|
||||
}
|
||||
|
||||
fmt.Printf("%s %s\n\n", dimStyle.Render(i18n.T("cmd.php.label.audit")), i18n.T("cmd.php.audit.scanning"))
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
results, err := phppkg.RunAudit(ctx, phppkg.AuditOptions{
|
||||
results, err := RunAudit(ctx, AuditOptions{
|
||||
Dir: cwd,
|
||||
JSON: auditJSONOutput,
|
||||
Fix: auditFix,
|
||||
|
|
@ -338,11 +338,11 @@ func addPHPAuditCommand(parent *cobra.Command) {
|
|||
if totalVulns > 0 {
|
||||
fmt.Printf("%s %s\n", errorStyle.Render(i18n.T("common.label.warning")), i18n.T("cmd.php.audit.found_vulns", map[string]interface{}{"Count": totalVulns}))
|
||||
fmt.Printf("%s %s\n", dimStyle.Render(i18n.T("common.label.fix")), i18n.T("common.hint.fix_deps"))
|
||||
return fmt.Errorf(i18n.T("cmd.php.error.vulns_found"))
|
||||
return errors.New(i18n.T("cmd.php.error.vulns_found"))
|
||||
}
|
||||
|
||||
if hasErrors {
|
||||
return fmt.Errorf(i18n.T("cmd.php.audit.completed_errors"))
|
||||
return errors.New(i18n.T("cmd.php.audit.completed_errors"))
|
||||
}
|
||||
|
||||
fmt.Printf("%s %s\n", successStyle.Render(i18n.T("common.label.done")), i18n.T("cmd.php.audit.all_secure"))
|
||||
|
|
@ -374,15 +374,15 @@ func addPHPSecurityCommand(parent *cobra.Command) {
|
|||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "get working directory"}), err)
|
||||
}
|
||||
|
||||
if !phppkg.IsPHPProject(cwd) {
|
||||
return fmt.Errorf(i18n.T("cmd.php.error.not_php"))
|
||||
if !IsPHPProject(cwd) {
|
||||
return errors.New(i18n.T("cmd.php.error.not_php"))
|
||||
}
|
||||
|
||||
fmt.Printf("%s %s\n\n", dimStyle.Render(i18n.T("cmd.php.label.security")), i18n.T("common.progress.running", map[string]any{"Task": "security checks"}))
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
result, err := phppkg.RunSecurityChecks(ctx, phppkg.SecurityOptions{
|
||||
result, err := RunSecurityChecks(ctx, SecurityOptions{
|
||||
Dir: cwd,
|
||||
Severity: securitySeverity,
|
||||
JSON: securityJSONOutput,
|
||||
|
|
@ -440,7 +440,7 @@ func addPHPSecurityCommand(parent *cobra.Command) {
|
|||
}
|
||||
|
||||
if result.Summary.Critical > 0 || result.Summary.High > 0 {
|
||||
return fmt.Errorf(i18n.T("cmd.php.error.critical_high_issues"))
|
||||
return errors.New(i18n.T("cmd.php.error.critical_high_issues"))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
@ -472,18 +472,18 @@ func addPHPQACommand(parent *cobra.Command) {
|
|||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "get working directory"}), err)
|
||||
}
|
||||
|
||||
if !phppkg.IsPHPProject(cwd) {
|
||||
return fmt.Errorf(i18n.T("cmd.php.error.not_php"))
|
||||
if !IsPHPProject(cwd) {
|
||||
return errors.New(i18n.T("cmd.php.error.not_php"))
|
||||
}
|
||||
|
||||
// Determine stages
|
||||
opts := phppkg.QAOptions{
|
||||
opts := QAOptions{
|
||||
Dir: cwd,
|
||||
Quick: qaQuick,
|
||||
Full: qaFull,
|
||||
Fix: qaFix,
|
||||
}
|
||||
stages := phppkg.GetQAStages(opts)
|
||||
stages := GetQAStages(opts)
|
||||
|
||||
// Print header
|
||||
fmt.Printf("%s %s\n\n", dimStyle.Render(i18n.Label("qa")), i18n.ProgressSubject("run", "QA pipeline"))
|
||||
|
|
@ -567,9 +567,9 @@ func addPHPQACommand(parent *cobra.Command) {
|
|||
}
|
||||
|
||||
// getCheckStage determines which stage a check belongs to.
|
||||
func getCheckStage(checkName string, stages []phppkg.QAStage, dir string) string {
|
||||
func getCheckStage(checkName string, stages []QAStage, dir string) string {
|
||||
for _, stage := range stages {
|
||||
checks := phppkg.GetQAChecks(dir, stage)
|
||||
checks := GetQAChecks(dir, stage)
|
||||
for _, c := range checks {
|
||||
if c == checkName {
|
||||
return string(stage)
|
||||
|
|
@ -622,16 +622,16 @@ func addPHPRectorCommand(parent *cobra.Command) {
|
|||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "get working directory"}), err)
|
||||
}
|
||||
|
||||
if !phppkg.IsPHPProject(cwd) {
|
||||
return fmt.Errorf(i18n.T("cmd.php.error.not_php"))
|
||||
if !IsPHPProject(cwd) {
|
||||
return errors.New(i18n.T("cmd.php.error.not_php"))
|
||||
}
|
||||
|
||||
// Check if Rector is available
|
||||
if !phppkg.DetectRector(cwd) {
|
||||
if !DetectRector(cwd) {
|
||||
fmt.Printf("%s %s\n\n", errorStyle.Render(i18n.T("common.label.error")), i18n.T("cmd.php.rector.not_found"))
|
||||
fmt.Printf("%s %s\n", dimStyle.Render(i18n.T("common.label.install")), i18n.T("cmd.php.rector.install"))
|
||||
fmt.Printf("%s %s\n", dimStyle.Render(i18n.T("cmd.php.label.setup")), i18n.T("cmd.php.rector.setup"))
|
||||
return fmt.Errorf(i18n.T("cmd.php.error.rector_not_installed"))
|
||||
return errors.New(i18n.T("cmd.php.error.rector_not_installed"))
|
||||
}
|
||||
|
||||
var msg string
|
||||
|
|
@ -644,7 +644,7 @@ func addPHPRectorCommand(parent *cobra.Command) {
|
|||
|
||||
ctx := context.Background()
|
||||
|
||||
opts := phppkg.RectorOptions{
|
||||
opts := RectorOptions{
|
||||
Dir: cwd,
|
||||
Fix: rectorFix,
|
||||
Diff: rectorDiff,
|
||||
|
|
@ -652,7 +652,7 @@ func addPHPRectorCommand(parent *cobra.Command) {
|
|||
Output: os.Stdout,
|
||||
}
|
||||
|
||||
if err := phppkg.RunRector(ctx, opts); err != nil {
|
||||
if err := RunRector(ctx, opts); err != nil {
|
||||
if rectorFix {
|
||||
return fmt.Errorf("%s: %w", i18n.T("cmd.php.error.rector_failed"), err)
|
||||
}
|
||||
|
|
@ -696,15 +696,15 @@ func addPHPInfectionCommand(parent *cobra.Command) {
|
|||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "get working directory"}), err)
|
||||
}
|
||||
|
||||
if !phppkg.IsPHPProject(cwd) {
|
||||
return fmt.Errorf(i18n.T("cmd.php.error.not_php"))
|
||||
if !IsPHPProject(cwd) {
|
||||
return errors.New(i18n.T("cmd.php.error.not_php"))
|
||||
}
|
||||
|
||||
// Check if Infection is available
|
||||
if !phppkg.DetectInfection(cwd) {
|
||||
if !DetectInfection(cwd) {
|
||||
fmt.Printf("%s %s\n\n", errorStyle.Render(i18n.T("common.label.error")), i18n.T("cmd.php.infection.not_found"))
|
||||
fmt.Printf("%s %s\n", dimStyle.Render(i18n.T("common.label.install")), i18n.T("cmd.php.infection.install"))
|
||||
return fmt.Errorf(i18n.T("cmd.php.error.infection_not_installed"))
|
||||
return errors.New(i18n.T("cmd.php.error.infection_not_installed"))
|
||||
}
|
||||
|
||||
fmt.Printf("%s %s\n", dimStyle.Render(i18n.T("cmd.php.label.infection")), i18n.T("common.progress.running", map[string]any{"Task": "mutation testing"}))
|
||||
|
|
@ -712,7 +712,7 @@ func addPHPInfectionCommand(parent *cobra.Command) {
|
|||
|
||||
ctx := context.Background()
|
||||
|
||||
opts := phppkg.InfectionOptions{
|
||||
opts := InfectionOptions{
|
||||
Dir: cwd,
|
||||
MinMSI: infectionMinMSI,
|
||||
MinCoveredMSI: infectionMinCoveredMSI,
|
||||
|
|
@ -722,7 +722,7 @@ func addPHPInfectionCommand(parent *cobra.Command) {
|
|||
Output: os.Stdout,
|
||||
}
|
||||
|
||||
if err := phppkg.RunInfection(ctx, opts); err != nil {
|
||||
if err := RunInfection(ctx, opts); err != nil {
|
||||
return fmt.Errorf("%s: %w", i18n.T("cmd.php.error.infection_failed"), err)
|
||||
}
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// Package pkg provides GitHub package management for host-uk repositories.
|
||||
// Package pkgcmd provides GitHub package management for host-uk repositories.
|
||||
//
|
||||
// Commands:
|
||||
// - search: Search GitHub org for repos (cached for 1 hour)
|
||||
|
|
@ -9,11 +9,4 @@
|
|||
//
|
||||
// Uses gh CLI for authenticated GitHub access. Results are cached in
|
||||
// .core/cache/ within the workspace directory.
|
||||
package pkg
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
|
||||
// AddCommands registers the 'pkg' command and all subcommands.
|
||||
func AddCommands(root *cobra.Command) {
|
||||
AddPkgCommands(root)
|
||||
}
|
||||
package pkgcmd
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
package pkg
|
||||
package pkgcmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
|
@ -13,8 +14,8 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
installTargetDir string
|
||||
installAddToReg bool
|
||||
installTargetDir string
|
||||
installAddToReg bool
|
||||
)
|
||||
|
||||
// addPkgInstallCommand adds the 'pkg install' command.
|
||||
|
|
@ -25,7 +26,7 @@ func addPkgInstallCommand(parent *cobra.Command) {
|
|||
Long: i18n.T("cmd.pkg.install.long"),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf(i18n.T("cmd.pkg.error.repo_required"))
|
||||
return errors.New(i18n.T("cmd.pkg.error.repo_required"))
|
||||
}
|
||||
return runPkgInstall(args[0], installTargetDir, installAddToReg)
|
||||
},
|
||||
|
|
@ -43,7 +44,7 @@ func runPkgInstall(repoArg, targetDir string, addToRegistry bool) error {
|
|||
// Parse org/repo
|
||||
parts := strings.Split(repoArg, "/")
|
||||
if len(parts) != 2 {
|
||||
return fmt.Errorf(i18n.T("cmd.pkg.error.invalid_repo_format"))
|
||||
return errors.New(i18n.T("cmd.pkg.error.invalid_repo_format"))
|
||||
}
|
||||
org, repoName := parts[0], parts[1]
|
||||
|
||||
|
|
@ -78,7 +79,7 @@ func runPkgInstall(repoArg, targetDir string, addToRegistry bool) error {
|
|||
}
|
||||
|
||||
if err := os.MkdirAll(targetDir, 0755); err != nil {
|
||||
return fmt.Errorf(i18n.T("common.error.failed", map[string]any{"Action": "create directory"}), err)
|
||||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "create directory"}), err)
|
||||
}
|
||||
|
||||
fmt.Printf("%s %s/%s\n", dimStyle.Render(i18n.T("cmd.pkg.install.installing_label")), org, repoName)
|
||||
|
|
@ -110,7 +111,7 @@ func runPkgInstall(repoArg, targetDir string, addToRegistry bool) error {
|
|||
func addToRegistryFile(org, repoName string) error {
|
||||
regPath, err := repos.FindRegistry()
|
||||
if err != nil {
|
||||
return fmt.Errorf(i18n.T("cmd.pkg.error.no_repos_yaml"))
|
||||
return errors.New(i18n.T("cmd.pkg.error.no_repos_yaml"))
|
||||
}
|
||||
|
||||
reg, err := repos.LoadRegistry(regPath)
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package pkg
|
||||
package pkgcmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
|
@ -29,12 +30,12 @@ func addPkgListCommand(parent *cobra.Command) {
|
|||
func runPkgList() error {
|
||||
regPath, err := repos.FindRegistry()
|
||||
if err != nil {
|
||||
return fmt.Errorf(i18n.T("cmd.pkg.error.no_repos_yaml_workspace"))
|
||||
return errors.New(i18n.T("cmd.pkg.error.no_repos_yaml_workspace"))
|
||||
}
|
||||
|
||||
reg, err := repos.LoadRegistry(regPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf(i18n.T("common.error.failed", map[string]any{"Action": "load registry"}), err)
|
||||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "load registry"}), err)
|
||||
}
|
||||
|
||||
basePath := reg.BasePath
|
||||
|
|
@ -101,7 +102,7 @@ func addPkgUpdateCommand(parent *cobra.Command) {
|
|||
Long: i18n.T("cmd.pkg.update.long"),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if !updateAll && len(args) == 0 {
|
||||
return fmt.Errorf(i18n.T("cmd.pkg.error.specify_package"))
|
||||
return errors.New(i18n.T("cmd.pkg.error.specify_package"))
|
||||
}
|
||||
return runPkgUpdate(args, updateAll)
|
||||
},
|
||||
|
|
@ -115,12 +116,12 @@ func addPkgUpdateCommand(parent *cobra.Command) {
|
|||
func runPkgUpdate(packages []string, all bool) error {
|
||||
regPath, err := repos.FindRegistry()
|
||||
if err != nil {
|
||||
return fmt.Errorf(i18n.T("cmd.pkg.error.no_repos_yaml"))
|
||||
return errors.New(i18n.T("cmd.pkg.error.no_repos_yaml"))
|
||||
}
|
||||
|
||||
reg, err := repos.LoadRegistry(regPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf(i18n.T("common.error.failed", map[string]any{"Action": "load registry"}), err)
|
||||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "load registry"}), err)
|
||||
}
|
||||
|
||||
basePath := reg.BasePath
|
||||
|
|
@ -195,12 +196,12 @@ func addPkgOutdatedCommand(parent *cobra.Command) {
|
|||
func runPkgOutdated() error {
|
||||
regPath, err := repos.FindRegistry()
|
||||
if err != nil {
|
||||
return fmt.Errorf(i18n.T("cmd.pkg.error.no_repos_yaml"))
|
||||
return errors.New(i18n.T("cmd.pkg.error.no_repos_yaml"))
|
||||
}
|
||||
|
||||
reg, err := repos.LoadRegistry(regPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf(i18n.T("common.error.failed", map[string]any{"Action": "load registry"}), err)
|
||||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "load registry"}), err)
|
||||
}
|
||||
|
||||
basePath := reg.BasePath
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
// Package pkg provides package management commands for core-* repos.
|
||||
package pkg
|
||||
// Package pkgcmd provides package management commands for core-* repos.
|
||||
package pkgcmd
|
||||
|
||||
import (
|
||||
"github.com/host-uk/core/pkg/cli"
|
||||
|
|
@ -7,6 +7,10 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cli.RegisterCommands(AddPkgCommands)
|
||||
}
|
||||
|
||||
// Style and utility aliases
|
||||
var (
|
||||
repoNameStyle = cli.RepoNameStyle
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
package pkg
|
||||
package pkgcmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
|
@ -93,7 +94,7 @@ func runPkgSearch(org, pattern, repoType string, limit int, refresh bool) error
|
|||
// Fetch from GitHub if not cached
|
||||
if !fromCache {
|
||||
if !ghAuthenticated() {
|
||||
return fmt.Errorf(i18n.T("cmd.pkg.error.gh_not_authenticated"))
|
||||
return errors.New(i18n.T("cmd.pkg.error.gh_not_authenticated"))
|
||||
}
|
||||
|
||||
if os.Getenv("GH_TOKEN") != "" {
|
||||
|
|
@ -112,13 +113,13 @@ func runPkgSearch(org, pattern, repoType string, limit int, refresh bool) error
|
|||
fmt.Println()
|
||||
errStr := strings.TrimSpace(string(output))
|
||||
if strings.Contains(errStr, "401") || strings.Contains(errStr, "Bad credentials") {
|
||||
return fmt.Errorf(i18n.T("cmd.pkg.error.auth_failed"))
|
||||
return errors.New(i18n.T("cmd.pkg.error.auth_failed"))
|
||||
}
|
||||
return fmt.Errorf(i18n.T("cmd.pkg.error.search_failed"), errStr)
|
||||
return fmt.Errorf("%s: %s", i18n.T("cmd.pkg.error.search_failed"), errStr)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(output, &ghRepos); err != nil {
|
||||
return fmt.Errorf(i18n.T("common.error.failed", map[string]any{"Action": "parse results"}), err)
|
||||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "parse results"}), err)
|
||||
}
|
||||
|
||||
if c != nil {
|
||||
|
|
@ -149,7 +150,7 @@ func runPkgSearch(org, pattern, repoType string, limit int, refresh bool) error
|
|||
return filtered[i].Name < filtered[j].Name
|
||||
})
|
||||
|
||||
fmt.Printf(i18n.T("cmd.pkg.search.found_repos", map[string]int{"Count": len(filtered)}) + "\n\n")
|
||||
fmt.Print(i18n.T("cmd.pkg.search.found_repos", map[string]int{"Count": len(filtered)}) + "\n\n")
|
||||
|
||||
for _, r := range filtered {
|
||||
visibility := ""
|
||||
8
pkg/sdk/cmd_commands.go
Normal file
8
pkg/sdk/cmd_commands.go
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
// SDK validation and API compatibility commands.
|
||||
//
|
||||
// Commands:
|
||||
// - diff: Check for breaking API changes between spec versions
|
||||
// - validate: Validate OpenAPI spec syntax
|
||||
//
|
||||
// Configuration via .core/sdk.yaml. For SDK generation, use: core build sdk
|
||||
package sdk
|
||||
|
|
@ -1,16 +1,19 @@
|
|||
// Package sdk provides SDK validation and API compatibility commands.
|
||||
package sdk
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/host-uk/core/pkg/cli"
|
||||
"github.com/host-uk/core/pkg/i18n"
|
||||
sdkpkg "github.com/host-uk/core/pkg/sdk"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cli.RegisterCommands(AddSDKCommands)
|
||||
}
|
||||
|
||||
// SDK styles (aliases to shared)
|
||||
var (
|
||||
sdkHeaderStyle = cli.TitleStyle
|
||||
|
|
@ -48,7 +51,7 @@ var sdkValidateCmd = &cobra.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
func initSDKCommands() {
|
||||
// sdk diff flags
|
||||
sdkDiffCmd.Flags().StringVar(&diffBasePath, "base", "", i18n.T("cmd.sdk.diff.flag.base"))
|
||||
sdkDiffCmd.Flags().StringVar(&diffSpecPath, "spec", "", i18n.T("cmd.sdk.diff.flag.spec"))
|
||||
|
|
@ -61,6 +64,12 @@ func init() {
|
|||
sdkCmd.AddCommand(sdkValidateCmd)
|
||||
}
|
||||
|
||||
// AddSDKCommands registers the 'sdk' command and all subcommands.
|
||||
func AddSDKCommands(root *cobra.Command) {
|
||||
initSDKCommands()
|
||||
root.AddCommand(sdkCmd)
|
||||
}
|
||||
|
||||
func runSDKDiff(basePath, specPath string) error {
|
||||
projectDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
|
|
@ -69,7 +78,7 @@ func runSDKDiff(basePath, specPath string) error {
|
|||
|
||||
// Detect current spec if not provided
|
||||
if specPath == "" {
|
||||
s := sdkpkg.New(projectDir, nil)
|
||||
s := New(projectDir, nil)
|
||||
specPath, err = s.DetectSpec()
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -77,7 +86,7 @@ func runSDKDiff(basePath, specPath string) error {
|
|||
}
|
||||
|
||||
if basePath == "" {
|
||||
return fmt.Errorf(i18n.T("cmd.sdk.diff.error.base_required"))
|
||||
return errors.New(i18n.T("cmd.sdk.diff.error.base_required"))
|
||||
}
|
||||
|
||||
fmt.Printf("%s %s\n", sdkHeaderStyle.Render(i18n.T("cmd.sdk.diff.label")), i18n.T("common.progress.checking", map[string]any{"Item": "breaking changes"}))
|
||||
|
|
@ -85,7 +94,7 @@ func runSDKDiff(basePath, specPath string) error {
|
|||
fmt.Printf(" %s %s\n", i18n.T("common.label.current"), sdkDimStyle.Render(specPath))
|
||||
fmt.Println()
|
||||
|
||||
result, err := sdkpkg.Diff(basePath, specPath)
|
||||
result, err := Diff(basePath, specPath)
|
||||
if err != nil {
|
||||
fmt.Printf("%s %v\n", sdkErrorStyle.Render(i18n.T("common.label.error")), err)
|
||||
os.Exit(2)
|
||||
|
|
@ -109,7 +118,7 @@ func runSDKValidate(specPath string) error {
|
|||
return fmt.Errorf("%s: %w", i18n.T("common.error.failed", map[string]any{"Action": "get working directory"}), err)
|
||||
}
|
||||
|
||||
s := sdkpkg.New(projectDir, &sdkpkg.Config{Spec: specPath})
|
||||
s := New(projectDir, &Config{Spec: specPath})
|
||||
|
||||
fmt.Printf("%s %s\n", sdkHeaderStyle.Render(i18n.T("cmd.sdk.label.sdk")), i18n.T("cmd.sdk.validate.validating"))
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// setup_bootstrap.go implements bootstrap mode for new workspaces.
|
||||
// cmd_bootstrap.go implements bootstrap mode for new workspaces.
|
||||
//
|
||||
// Bootstrap mode is activated when no repos.yaml exists in the current
|
||||
// directory or any parent. It clones core-devops first, then uses its
|
||||
|
|
@ -23,9 +23,16 @@
|
|||
// Uses gh CLI with HTTPS when authenticated, falls back to SSH.
|
||||
package setup
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
import (
|
||||
"github.com/host-uk/core/pkg/cli"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// AddCommands registers the 'setup' command and all subcommands.
|
||||
func AddCommands(root *cobra.Command) {
|
||||
func init() {
|
||||
cli.RegisterCommands(AddSetupCommands)
|
||||
}
|
||||
|
||||
// AddSetupCommands registers the 'setup' command and all subcommands.
|
||||
func AddSetupCommands(root *cobra.Command) {
|
||||
AddSetupCommand(root)
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// setup_registry.go implements registry mode for cloning packages.
|
||||
// cmd_registry.go implements registry mode for cloning packages.
|
||||
//
|
||||
// Registry mode is activated when a repos.yaml exists. It reads the registry
|
||||
// and clones all (or selected) packages into the configured packages directory.
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// setup_repo.go implements repository setup with .core/ configuration.
|
||||
// cmd_repo.go implements repository setup with .core/ configuration.
|
||||
//
|
||||
// When running setup in an existing git repository, this generates
|
||||
// build.yaml, release.yaml, and test.yaml configurations based on
|
||||
|
|
@ -41,7 +41,7 @@ var setupCmd = &cobra.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
func initSetupFlags() {
|
||||
setupCmd.Flags().StringVar(®istryPath, "registry", "", i18n.T("cmd.setup.flag.registry"))
|
||||
setupCmd.Flags().StringVar(&only, "only", "", i18n.T("cmd.setup.flag.only"))
|
||||
setupCmd.Flags().BoolVar(&dryRun, "dry-run", false, i18n.T("cmd.setup.flag.dry_run"))
|
||||
|
|
@ -52,5 +52,6 @@ func init() {
|
|||
|
||||
// AddSetupCommand adds the 'setup' command to the given parent command.
|
||||
func AddSetupCommand(root *cobra.Command) {
|
||||
initSetupFlags()
|
||||
root.AddCommand(setupCmd)
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// setup_wizard.go implements the interactive package selection wizard.
|
||||
// cmd_wizard.go implements the interactive package selection wizard.
|
||||
//
|
||||
// Uses charmbracelet/huh for a rich terminal UI with multi-select checkboxes.
|
||||
// Falls back to non-interactive mode when not in a TTY or --all is specified.
|
||||
|
|
@ -11,9 +11,8 @@
|
|||
// Flags: --verbose, --coverage, --short, --pkg, --run, --race, --json
|
||||
package testcmd
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
import "github.com/host-uk/core/pkg/cli"
|
||||
|
||||
// AddCommands registers the 'test' command and all subcommands.
|
||||
func AddCommands(root *cobra.Command) {
|
||||
root.AddCommand(testCmd)
|
||||
func init() {
|
||||
cli.RegisterCommands(AddTestCommands)
|
||||
}
|
||||
|
|
@ -41,7 +41,7 @@ var testCmd = &cobra.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
func initTestFlags() {
|
||||
testCmd.Flags().BoolVar(&testVerbose, "verbose", false, i18n.T("cmd.test.flag.verbose"))
|
||||
testCmd.Flags().BoolVar(&testCoverage, "coverage", false, i18n.T("common.flag.coverage"))
|
||||
testCmd.Flags().BoolVar(&testShort, "short", false, i18n.T("cmd.test.flag.short"))
|
||||
|
|
@ -50,3 +50,9 @@ func init() {
|
|||
testCmd.Flags().BoolVar(&testRace, "race", false, i18n.T("cmd.test.flag.race"))
|
||||
testCmd.Flags().BoolVar(&testJSON, "json", false, i18n.T("cmd.test.flag.json"))
|
||||
}
|
||||
|
||||
// AddTestCommands registers the 'test' command and all subcommands.
|
||||
func AddTestCommands(root *cobra.Command) {
|
||||
initTestFlags()
|
||||
root.AddCommand(testCmd)
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package testcmd
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
|
@ -15,7 +16,7 @@ import (
|
|||
func runTest(verbose, coverage, short bool, pkg, run string, race, jsonOutput bool) error {
|
||||
// Detect if we're in a Go project
|
||||
if _, err := os.Stat("go.mod"); os.IsNotExist(err) {
|
||||
return fmt.Errorf(i18n.T("cmd.test.error.no_go_mod"))
|
||||
return errors.New(i18n.T("cmd.test.error.no_go_mod"))
|
||||
}
|
||||
|
||||
// Build command arguments
|
||||
|
|
@ -93,7 +94,7 @@ func runTest(verbose, coverage, short bool, pkg, run string, race, jsonOutput bo
|
|||
// JSON output for CI/agents
|
||||
printJSONResults(results, exitCode)
|
||||
if exitCode != 0 {
|
||||
return fmt.Errorf(i18n.T("common.error.failed", map[string]any{"Action": "run tests"}))
|
||||
return errors.New(i18n.T("common.error.failed", map[string]any{"Action": "run tests"}))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -109,7 +110,7 @@ func runTest(verbose, coverage, short bool, pkg, run string, race, jsonOutput bo
|
|||
|
||||
if exitCode != 0 {
|
||||
fmt.Printf("\n%s %s\n", testFailStyle.Render(i18n.T("cli.fail")), i18n.T("cmd.test.tests_failed"))
|
||||
return fmt.Errorf(i18n.T("common.error.failed", map[string]any{"Action": "run tests"}))
|
||||
return errors.New(i18n.T("common.error.failed", map[string]any{"Action": "run tests"}))
|
||||
}
|
||||
|
||||
fmt.Printf("\n%s %s\n", testPassStyle.Render(i18n.T("cli.pass")), i18n.T("common.result.all_passed"))
|
||||
|
|
@ -11,10 +11,3 @@
|
|||
// Uses qemu or hyperkit depending on system availability.
|
||||
// Templates are built from YAML definitions and can include variables.
|
||||
package vm
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
|
||||
// AddCommands registers the 'vm' command and all subcommands.
|
||||
func AddCommands(root *cobra.Command) {
|
||||
AddVMCommands(root)
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package vm
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
|
@ -47,7 +48,7 @@ func addVMRunCommand(parent *cobra.Command) {
|
|||
|
||||
// Otherwise, require an image path
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf(i18n.T("cmd.vm.run.error.image_required"))
|
||||
return errors.New(i18n.T("cmd.vm.run.error.image_required"))
|
||||
}
|
||||
image := args[0]
|
||||
|
||||
|
|
@ -210,7 +211,7 @@ func addVMStopCommand(parent *cobra.Command) {
|
|||
Long: i18n.T("cmd.vm.stop.long"),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf(i18n.T("cmd.vm.error.id_required"))
|
||||
return errors.New(i18n.T("cmd.vm.error.id_required"))
|
||||
}
|
||||
return stopContainer(args[0])
|
||||
},
|
||||
|
|
@ -259,11 +260,11 @@ func resolveContainerID(manager *container.LinuxKitManager, partialID string) (s
|
|||
|
||||
switch len(matches) {
|
||||
case 0:
|
||||
return "", fmt.Errorf(i18n.T("cmd.vm.error.no_match", map[string]interface{}{"ID": partialID}))
|
||||
return "", errors.New(i18n.T("cmd.vm.error.no_match", map[string]interface{}{"ID": partialID}))
|
||||
case 1:
|
||||
return matches[0].ID, nil
|
||||
default:
|
||||
return "", fmt.Errorf(i18n.T("cmd.vm.error.multiple_match", map[string]interface{}{"ID": partialID}))
|
||||
return "", errors.New(i18n.T("cmd.vm.error.multiple_match", map[string]interface{}{"ID": partialID}))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -277,7 +278,7 @@ func addVMLogsCommand(parent *cobra.Command) {
|
|||
Long: i18n.T("cmd.vm.logs.long"),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf(i18n.T("cmd.vm.error.id_required"))
|
||||
return errors.New(i18n.T("cmd.vm.error.id_required"))
|
||||
}
|
||||
return viewLogs(args[0], logsFollow)
|
||||
},
|
||||
|
|
@ -318,7 +319,7 @@ func addVMExecCommand(parent *cobra.Command) {
|
|||
Long: i18n.T("cmd.vm.exec.long"),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 2 {
|
||||
return fmt.Errorf(i18n.T("cmd.vm.error.id_and_cmd_required"))
|
||||
return errors.New(i18n.T("cmd.vm.error.id_and_cmd_required"))
|
||||
}
|
||||
return execInContainer(args[0], args[1:])
|
||||
},
|
||||
|
|
@ -2,6 +2,7 @@ package vm
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
|
@ -40,7 +41,7 @@ func addTemplatesShowCommand(parent *cobra.Command) {
|
|||
Long: i18n.T("cmd.vm.templates.show.long"),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf(i18n.T("cmd.vm.error.template_required"))
|
||||
return errors.New(i18n.T("cmd.vm.error.template_required"))
|
||||
}
|
||||
return showTemplate(args[0])
|
||||
},
|
||||
|
|
@ -57,7 +58,7 @@ func addTemplatesVarsCommand(parent *cobra.Command) {
|
|||
Long: i18n.T("cmd.vm.templates.vars.long"),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf(i18n.T("cmd.vm.error.template_required"))
|
||||
return errors.New(i18n.T("cmd.vm.error.template_required"))
|
||||
}
|
||||
return showTemplateVars(args[0])
|
||||
},
|
||||
|
|
@ -177,7 +178,7 @@ func RunFromTemplate(templateName string, vars map[string]string, runOpts contai
|
|||
// Find the built image (linuxkit creates .iso or other format)
|
||||
imagePath := findBuiltImage(outputPath)
|
||||
if imagePath == "" {
|
||||
return fmt.Errorf(i18n.T("cmd.vm.error.no_image_found"))
|
||||
return errors.New(i18n.T("cmd.vm.error.no_image_found"))
|
||||
}
|
||||
|
||||
fmt.Printf("%s %s\n", dimStyle.Render(i18n.T("common.label.image")), imagePath)
|
||||
|
|
@ -286,7 +287,7 @@ func lookupLinuxKit() (string, error) {
|
|||
}
|
||||
}
|
||||
|
||||
return "", fmt.Errorf(i18n.T("cmd.vm.error.linuxkit_not_found"))
|
||||
return "", errors.New(i18n.T("cmd.vm.error.linuxkit_not_found"))
|
||||
}
|
||||
|
||||
// ParseVarFlags parses --var flags into a map.
|
||||
|
|
@ -8,6 +8,10 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cli.RegisterCommands(AddVMCommands)
|
||||
}
|
||||
|
||||
// Style aliases from shared
|
||||
var (
|
||||
repoNameStyle = cli.RepoNameStyle
|
||||
Loading…
Add table
Reference in a new issue