* ci: consolidate duplicate workflows and merge CodeQL configs Remove 17 duplicate workflow files that were split copies of the combined originals. Each family (CI, CodeQL, Coverage, PR Build, Alpha Release) had the same job duplicated across separate push/pull_request/schedule/manual trigger files. Merge codeql.yml and codescan.yml into a single codeql.yml with a language matrix covering go, javascript-typescript, python, and actions — matching the previous default setup coverage. Remaining workflows (one per family): - ci.yml (push + PR + manual) - codeql.yml (push + PR + schedule, all languages) - coverage.yml (push + PR + manual) - alpha-release.yml (push + manual) - pr-build.yml (PR + manual) - release.yml (tag push) - agent-verify.yml, auto-label.yml, auto-project.yml Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: add collect, config, crypt, plugin packages and fix all lint issues Add four new infrastructure packages with CLI commands: - pkg/config: layered configuration (defaults → file → env → flags) - pkg/crypt: crypto primitives (Argon2id, AES-GCM, ChaCha20, HMAC, checksums) - pkg/plugin: plugin system with GitHub-based install/update/remove - pkg/collect: collection subsystem (GitHub, BitcoinTalk, market, papers, excavate) Fix all golangci-lint issues across the entire codebase (~100 errcheck, staticcheck SA1012/SA1019/ST1005, unused, ineffassign fixes) so that `core go qa` passes with 0 issues. Closes #167, #168, #170, #250, #251, #252, #253, #254, #255, #256 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
177 lines
4.4 KiB
Go
177 lines
4.4 KiB
Go
package gocmd
|
|
|
|
import (
|
|
"bufio"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/host-uk/core/pkg/cli"
|
|
"github.com/host-uk/core/pkg/i18n"
|
|
)
|
|
|
|
var (
|
|
fmtFix bool
|
|
fmtDiff bool
|
|
fmtCheck bool
|
|
fmtAll bool
|
|
)
|
|
|
|
func addGoFmtCommand(parent *cli.Command) {
|
|
fmtCmd := &cli.Command{
|
|
Use: "fmt",
|
|
Short: "Format Go code",
|
|
Long: "Format Go code using goimports or gofmt. By default only checks changed files.",
|
|
RunE: func(cmd *cli.Command, args []string) error {
|
|
// Get list of files to check
|
|
var files []string
|
|
if fmtAll {
|
|
// Check all Go files
|
|
files = []string{"."}
|
|
} else {
|
|
// Only check changed Go files (git-aware)
|
|
files = getChangedGoFiles()
|
|
if len(files) == 0 {
|
|
cli.Print("%s\n", i18n.T("cmd.go.fmt.no_changes"))
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// Validate flag combinations
|
|
if fmtCheck && fmtFix {
|
|
return cli.Err("--check and --fix are mutually exclusive")
|
|
}
|
|
|
|
fmtArgs := []string{}
|
|
if fmtFix {
|
|
fmtArgs = append(fmtArgs, "-w")
|
|
}
|
|
if fmtDiff {
|
|
fmtArgs = append(fmtArgs, "-d")
|
|
}
|
|
if !fmtFix && !fmtDiff {
|
|
fmtArgs = append(fmtArgs, "-l")
|
|
}
|
|
fmtArgs = append(fmtArgs, files...)
|
|
|
|
// Try goimports first, fall back to gofmt
|
|
var execCmd *exec.Cmd
|
|
if _, err := exec.LookPath("goimports"); err == nil {
|
|
execCmd = exec.Command("goimports", fmtArgs...)
|
|
} else {
|
|
execCmd = exec.Command("gofmt", fmtArgs...)
|
|
}
|
|
|
|
// For --check mode, capture output to detect unformatted files
|
|
if fmtCheck {
|
|
output, err := execCmd.CombinedOutput()
|
|
if err != nil {
|
|
_, _ = os.Stderr.Write(output)
|
|
return err
|
|
}
|
|
if len(output) > 0 {
|
|
_, _ = os.Stdout.Write(output)
|
|
return cli.Err("files need formatting (use --fix)")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
execCmd.Stdout = os.Stdout
|
|
execCmd.Stderr = os.Stderr
|
|
return execCmd.Run()
|
|
},
|
|
}
|
|
|
|
fmtCmd.Flags().BoolVar(&fmtFix, "fix", false, i18n.T("common.flag.fix"))
|
|
fmtCmd.Flags().BoolVar(&fmtDiff, "diff", false, i18n.T("common.flag.diff"))
|
|
fmtCmd.Flags().BoolVar(&fmtCheck, "check", false, i18n.T("cmd.go.fmt.flag.check"))
|
|
fmtCmd.Flags().BoolVar(&fmtAll, "all", false, i18n.T("cmd.go.fmt.flag.all"))
|
|
|
|
parent.AddCommand(fmtCmd)
|
|
}
|
|
|
|
// getChangedGoFiles returns Go files that have been modified, staged, or are untracked.
|
|
func getChangedGoFiles() []string {
|
|
var files []string
|
|
|
|
// Get modified and staged files
|
|
cmd := exec.Command("git", "diff", "--name-only", "--diff-filter=ACMR", "HEAD")
|
|
output, err := cmd.Output()
|
|
if err == nil {
|
|
files = append(files, filterGoFiles(string(output))...)
|
|
}
|
|
|
|
// Get untracked files
|
|
cmd = exec.Command("git", "ls-files", "--others", "--exclude-standard")
|
|
output, err = cmd.Output()
|
|
if err == nil {
|
|
files = append(files, filterGoFiles(string(output))...)
|
|
}
|
|
|
|
// Deduplicate
|
|
seen := make(map[string]bool)
|
|
var unique []string
|
|
for _, f := range files {
|
|
if !seen[f] {
|
|
seen[f] = true
|
|
// Verify file exists (might have been deleted)
|
|
if _, err := os.Stat(f); err == nil {
|
|
unique = append(unique, f)
|
|
}
|
|
}
|
|
}
|
|
|
|
return unique
|
|
}
|
|
|
|
// filterGoFiles filters a newline-separated list of files to only include .go files.
|
|
func filterGoFiles(output string) []string {
|
|
var goFiles []string
|
|
scanner := bufio.NewScanner(strings.NewReader(output))
|
|
for scanner.Scan() {
|
|
file := strings.TrimSpace(scanner.Text())
|
|
if file != "" && filepath.Ext(file) == ".go" {
|
|
goFiles = append(goFiles, file)
|
|
}
|
|
}
|
|
return goFiles
|
|
}
|
|
|
|
var (
|
|
lintFix bool
|
|
lintAll bool
|
|
)
|
|
|
|
func addGoLintCommand(parent *cli.Command) {
|
|
lintCmd := &cli.Command{
|
|
Use: "lint",
|
|
Short: "Run golangci-lint",
|
|
Long: "Run golangci-lint for comprehensive static analysis. By default only lints changed files.",
|
|
RunE: func(cmd *cli.Command, args []string) error {
|
|
lintArgs := []string{"run"}
|
|
if lintFix {
|
|
lintArgs = append(lintArgs, "--fix")
|
|
}
|
|
|
|
if !lintAll {
|
|
// Use --new-from-rev=HEAD to only report issues in uncommitted changes
|
|
// This is golangci-lint's native way to handle incremental linting
|
|
lintArgs = append(lintArgs, "--new-from-rev=HEAD")
|
|
}
|
|
|
|
// Always lint all packages
|
|
lintArgs = append(lintArgs, "./...")
|
|
|
|
execCmd := exec.Command("golangci-lint", lintArgs...)
|
|
execCmd.Stdout = os.Stdout
|
|
execCmd.Stderr = os.Stderr
|
|
return execCmd.Run()
|
|
},
|
|
}
|
|
|
|
lintCmd.Flags().BoolVar(&lintFix, "fix", false, i18n.T("common.flag.fix"))
|
|
lintCmd.Flags().BoolVar(&lintAll, "all", false, i18n.T("cmd.go.lint.flag.all"))
|
|
|
|
parent.AddCommand(lintCmd)
|
|
}
|