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(&compactBatch, "batch-size", 10, "Issues per batch")
|
||||||
compactCmd.Flags().IntVar(&compactWorkers, "workers", 5, "Parallel workers")
|
compactCmd.Flags().IntVar(&compactWorkers, "workers", 5, "Parallel workers")
|
||||||
compactCmd.Flags().BoolVar(&compactStats, "stats", false, "Show compaction statistics")
|
compactCmd.Flags().BoolVar(&compactStats, "stats", false, "Show compaction statistics")
|
||||||
|
compactCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output JSON format")
|
||||||
|
|
||||||
rootCmd.AddCommand(compactCmd)
|
rootCmd.AddCommand(compactCmd)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -340,4 +340,55 @@ func TestCompactInitCommand(t *testing.T) {
|
|||||||
if len(compactCmd.Long) == 0 {
|
if len(compactCmd.Long) == 0 {
|
||||||
t.Error("compactCmd should have Long description")
|
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().Bool("migrate-to-global", false, "Migrate from local to global daemon")
|
||||||
daemonCmd.Flags().String("log", "", "Log file path (default: .beads/daemon.log)")
|
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().Bool("global", false, "Run as global daemon (socket at ~/.beads/bd.sock)")
|
||||||
|
daemonCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output JSON format")
|
||||||
rootCmd.AddCommand(daemonCmd)
|
rootCmd.AddCommand(daemonCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,19 +325,47 @@ func showDaemonStatus(pidFile string, global bool) {
|
|||||||
if global {
|
if global {
|
||||||
scope = "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 {
|
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)
|
var logPath string
|
||||||
if err == nil {
|
if lp, err := getLogFilePath("", global); err == nil {
|
||||||
if _, err := os.Stat(logPath); err == nil {
|
if _, err := os.Stat(lp); err == nil {
|
||||||
fmt.Printf(" Log: %s\n", logPath)
|
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 {
|
} else {
|
||||||
|
if jsonOutput {
|
||||||
|
outputJSON(map[string]interface{}{"running": false})
|
||||||
|
return
|
||||||
|
}
|
||||||
fmt.Println("Daemon is not running")
|
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)
|
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("output", "o", "", "Output file (default: stdout)")
|
||||||
exportCmd.Flags().StringP("status", "s", "", "Filter by status")
|
exportCmd.Flags().StringP("status", "s", "", "Filter by status")
|
||||||
exportCmd.Flags().Bool("force", false, "Force export even if database is empty")
|
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)
|
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("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("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().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)
|
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("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("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().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)
|
rootCmd.AddCommand(migrateCmd)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -171,5 +171,6 @@ Interactive mode with --interactive prompts for each orphan.`,
|
|||||||
func init() {
|
func init() {
|
||||||
repairDepsCmd.Flags().Bool("fix", false, "Automatically remove orphaned dependencies")
|
repairDepsCmd.Flags().Bool("fix", false, "Automatically remove orphaned dependencies")
|
||||||
repairDepsCmd.Flags().Bool("interactive", false, "Interactively review each orphaned dependency")
|
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)
|
rootCmd.AddCommand(repairDepsCmd)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ This is read-only and does not modify the database or git state.`,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
restoreCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output restore results in JSON format")
|
||||||
rootCmd.AddCommand(restoreCmd)
|
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("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("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().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)
|
rootCmd.AddCommand(syncCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user