feat: add version sync check to bd preflight --check (bd-lfak.5)

- Implement runVersionSyncCheck() to compare version.go and default.nix
- Reports version mismatch as hard failure
- Gracefully skips if default.nix is missing
- Fix version mismatch: update default.nix from 0.37.0 to 0.42.0

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Executed-By: beads/crew/dave
Rig: beads
Role: crew
This commit is contained in:
beads/crew/dave
2025-12-31 00:08:40 -08:00
committed by Steve Yegge
parent 6298359b60
commit 82611834df
2 changed files with 82 additions and 1 deletions

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"os"
"os/exec"
"regexp"
"strings"
"github.com/spf13/cobra"
@@ -99,6 +100,10 @@ func runChecks(jsonOutput bool) {
nixResult := runNixHashCheck()
results = append(results, nixResult)
// Run version sync check
versionResult := runVersionSyncCheck()
results = append(results, versionResult)
// Calculate overall result
allPassed := true
passCount := 0
@@ -244,6 +249,82 @@ func runNixHashCheck() CheckResult {
}
}
// runVersionSyncCheck checks that version.go matches default.nix.
func runVersionSyncCheck() CheckResult {
command := "Compare cmd/bd/version.go and default.nix"
// Read version.go
versionGoContent, err := os.ReadFile("cmd/bd/version.go")
if err != nil {
return CheckResult{
Name: "Version sync",
Passed: false,
Skipped: true,
Output: fmt.Sprintf("Cannot read cmd/bd/version.go: %v", err),
Command: command,
}
}
// Extract version from version.go
// Pattern: Version = "X.Y.Z"
versionGoRe := regexp.MustCompile(`Version\s*=\s*"([^"]+)"`)
versionGoMatch := versionGoRe.FindSubmatch(versionGoContent)
if versionGoMatch == nil {
return CheckResult{
Name: "Version sync",
Passed: false,
Skipped: true,
Output: "Cannot parse version from version.go",
Command: command,
}
}
goVersion := string(versionGoMatch[1])
// Read default.nix
nixContent, err := os.ReadFile("default.nix")
if err != nil {
// No nix file = skip version check (not an error)
return CheckResult{
Name: "Version sync",
Passed: true,
Skipped: true,
Output: "default.nix not found (skipping nix version check)",
Command: command,
}
}
// Extract version from default.nix
// Pattern: version = "X.Y.Z";
nixRe := regexp.MustCompile(`version\s*=\s*"([^"]+)"`)
nixMatch := nixRe.FindSubmatch(nixContent)
if nixMatch == nil {
return CheckResult{
Name: "Version sync",
Passed: false,
Skipped: true,
Output: "Cannot parse version from default.nix",
Command: command,
}
}
nixVersion := string(nixMatch[1])
if goVersion != nixVersion {
return CheckResult{
Name: "Version sync",
Passed: false,
Output: fmt.Sprintf("Version mismatch: version.go=%s, default.nix=%s", goVersion, nixVersion),
Command: command,
}
}
return CheckResult{
Name: "Version sync",
Passed: true,
Output: fmt.Sprintf("Versions match: %s", goVersion),
Command: command,
}
}
// truncateOutput truncates output to maxLen characters, adding ellipsis if truncated.
func truncateOutput(s string, maxLen int) string {
if len(s) <= maxLen {