bd sync: 2025-10-31 22:39:53
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -571,6 +571,7 @@ func init() {
|
||||
compactCmd.Flags().IntVar(&compactBatch, "batch-size", 10, "Issues per batch")
|
||||
compactCmd.Flags().IntVar(&compactWorkers, "workers", 5, "Parallel workers")
|
||||
compactCmd.Flags().BoolVar(&compactStats, "stats", false, "Show compaction statistics")
|
||||
compactCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output JSON format")
|
||||
|
||||
rootCmd.AddCommand(compactCmd)
|
||||
}
|
||||
|
||||
@@ -340,4 +340,55 @@ func TestCompactInitCommand(t *testing.T) {
|
||||
if len(compactCmd.Long) == 0 {
|
||||
t.Error("compactCmd should have Long description")
|
||||
}
|
||||
|
||||
// Verify --json flag exists
|
||||
jsonFlag := compactCmd.Flags().Lookup("json")
|
||||
if jsonFlag == nil {
|
||||
t.Error("compact command should have --json flag")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompactStatsJSON(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
dbPath := filepath.Join(tmpDir, ".beads", "beads.db")
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(dbPath), 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sqliteStore, err := sqlite.New(dbPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer sqliteStore.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Set issue_prefix
|
||||
if err := sqliteStore.SetConfig(ctx, "issue_prefix", "test"); err != nil {
|
||||
t.Fatalf("Failed to set issue_prefix: %v", err)
|
||||
}
|
||||
|
||||
// Create a closed issue eligible for Tier 1
|
||||
issue := &types.Issue{
|
||||
ID: "test-1",
|
||||
Title: "Test Issue",
|
||||
Description: string(make([]byte, 500)),
|
||||
Status: types.StatusClosed,
|
||||
Priority: 2,
|
||||
IssueType: types.TypeTask,
|
||||
CreatedAt: time.Now().Add(-60 * 24 * time.Hour),
|
||||
ClosedAt: ptrTime(time.Now().Add(-35 * 24 * time.Hour)),
|
||||
}
|
||||
if err := sqliteStore.CreateIssue(ctx, issue, "test"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Test with JSON output
|
||||
savedJSONOutput := jsonOutput
|
||||
jsonOutput = true
|
||||
defer func() { jsonOutput = savedJSONOutput }()
|
||||
|
||||
// Should not panic and should execute JSON path
|
||||
runCompactStats(ctx, sqliteStore)
|
||||
}
|
||||
|
||||
@@ -184,6 +184,7 @@ func init() {
|
||||
daemonCmd.Flags().Bool("migrate-to-global", false, "Migrate from local to global daemon")
|
||||
daemonCmd.Flags().String("log", "", "Log file path (default: .beads/daemon.log)")
|
||||
daemonCmd.Flags().Bool("global", false, "Run as global daemon (socket at ~/.beads/bd.sock)")
|
||||
daemonCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output JSON format")
|
||||
rootCmd.AddCommand(daemonCmd)
|
||||
}
|
||||
|
||||
@@ -324,19 +325,47 @@ func showDaemonStatus(pidFile string, global bool) {
|
||||
if global {
|
||||
scope = "global"
|
||||
}
|
||||
fmt.Printf("Daemon is running (PID %d, %s)\n", pid, scope)
|
||||
|
||||
|
||||
var started string
|
||||
if info, err := os.Stat(pidFile); err == nil {
|
||||
fmt.Printf(" Started: %s\n", info.ModTime().Format("2006-01-02 15:04:05"))
|
||||
started = info.ModTime().Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
logPath, err := getLogFilePath("", global)
|
||||
if err == nil {
|
||||
if _, err := os.Stat(logPath); err == nil {
|
||||
fmt.Printf(" Log: %s\n", logPath)
|
||||
var logPath string
|
||||
if lp, err := getLogFilePath("", global); err == nil {
|
||||
if _, err := os.Stat(lp); err == nil {
|
||||
logPath = lp
|
||||
}
|
||||
}
|
||||
|
||||
if jsonOutput {
|
||||
status := map[string]interface{}{
|
||||
"running": true,
|
||||
"pid": pid,
|
||||
"scope": scope,
|
||||
}
|
||||
if started != "" {
|
||||
status["started"] = started
|
||||
}
|
||||
if logPath != "" {
|
||||
status["log_path"] = logPath
|
||||
}
|
||||
outputJSON(status)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("Daemon is running (PID %d, %s)\n", pid, scope)
|
||||
if started != "" {
|
||||
fmt.Printf(" Started: %s\n", started)
|
||||
}
|
||||
if logPath != "" {
|
||||
fmt.Printf(" Log: %s\n", logPath)
|
||||
}
|
||||
} else {
|
||||
if jsonOutput {
|
||||
outputJSON(map[string]interface{}{"running": false})
|
||||
return
|
||||
}
|
||||
fmt.Println("Daemon is not running")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,6 +308,21 @@ Output to stdout by default, or use -o flag for file output.`,
|
||||
fmt.Fprintf(os.Stderr, "Warning: failed to set file permissions: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Output statistics if JSON format requested
|
||||
if jsonOutput {
|
||||
stats := map[string]interface{}{
|
||||
"success": true,
|
||||
"exported": len(exportedIDs),
|
||||
"skipped": skippedCount,
|
||||
"total_issues": len(issues),
|
||||
}
|
||||
if output != "" {
|
||||
stats["output_file"] = output
|
||||
}
|
||||
data, _ := json.MarshalIndent(stats, "", " ")
|
||||
fmt.Fprintln(os.Stderr, string(data))
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@@ -316,5 +331,6 @@ func init() {
|
||||
exportCmd.Flags().StringP("output", "o", "", "Output file (default: stdout)")
|
||||
exportCmd.Flags().StringP("status", "s", "", "Filter by status")
|
||||
exportCmd.Flags().Bool("force", false, "Force export even if database is empty")
|
||||
exportCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output export statistics in JSON format")
|
||||
rootCmd.AddCommand(exportCmd)
|
||||
}
|
||||
|
||||
@@ -249,5 +249,6 @@ func init() {
|
||||
importCmd.Flags().Bool("dedupe-after", false, "Detect and report content duplicates after import")
|
||||
importCmd.Flags().Bool("dry-run", false, "Preview collision detection without making changes")
|
||||
importCmd.Flags().Bool("rename-on-import", false, "Rename imported issues to match database prefix (updates all references)")
|
||||
importCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output import statistics in JSON format")
|
||||
rootCmd.AddCommand(importCmd)
|
||||
}
|
||||
|
||||
@@ -588,5 +588,6 @@ func init() {
|
||||
migrateCmd.Flags().Bool("dry-run", false, "Show what would be done without making changes")
|
||||
migrateCmd.Flags().Bool("update-repo-id", false, "Update repository ID (use after changing git remote)")
|
||||
migrateCmd.Flags().Bool("to-hash-ids", false, "Migrate sequential IDs to hash-based IDs")
|
||||
migrateCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output migration statistics in JSON format")
|
||||
rootCmd.AddCommand(migrateCmd)
|
||||
}
|
||||
|
||||
@@ -171,5 +171,6 @@ Interactive mode with --interactive prompts for each orphan.`,
|
||||
func init() {
|
||||
repairDepsCmd.Flags().Bool("fix", false, "Automatically remove orphaned dependencies")
|
||||
repairDepsCmd.Flags().Bool("interactive", false, "Interactively review each orphaned dependency")
|
||||
repairDepsCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output repair results in JSON format")
|
||||
rootCmd.AddCommand(repairDepsCmd)
|
||||
}
|
||||
|
||||
@@ -112,6 +112,7 @@ This is read-only and does not modify the database or git state.`,
|
||||
}
|
||||
|
||||
func init() {
|
||||
restoreCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output restore results in JSON format")
|
||||
rootCmd.AddCommand(restoreCmd)
|
||||
}
|
||||
|
||||
|
||||
@@ -247,6 +247,7 @@ func init() {
|
||||
syncCmd.Flags().Bool("rename-on-import", false, "Rename imported issues to match database prefix (updates all references)")
|
||||
syncCmd.Flags().Bool("flush-only", false, "Only export pending changes to JSONL (skip git operations)")
|
||||
syncCmd.Flags().Bool("import-only", false, "Only import from JSONL (skip git operations, useful after git pull)")
|
||||
syncCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output sync statistics in JSON format")
|
||||
rootCmd.AddCommand(syncCmd)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user