fix: bd create -f now works with daemon mode (GH#719)
When using bd create -f with a running daemon, the command would fail with 'database not initialized' because it bypassed the daemon RPC path. The fix adds createIssuesFromMarkdownViaDaemon which: - Parses the markdown file (no store access needed) - Converts issue templates to CreateArgs - Uses daemon Batch RPC to create all issues efficiently - Preserves all features: labels, dependencies, hooks, JSON output Tested with daemon and non-daemon modes, verifying priority 0 is preserved correctly. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -11,6 +12,8 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/steveyegge/beads/internal/hooks"
|
||||
"github.com/steveyegge/beads/internal/rpc"
|
||||
"github.com/steveyegge/beads/internal/types"
|
||||
"github.com/steveyegge/beads/internal/ui"
|
||||
"github.com/steveyegge/beads/internal/validation"
|
||||
@@ -306,16 +309,7 @@ func parseMarkdownFile(path string) ([]*IssueTemplate, error) {
|
||||
|
||||
// createIssuesFromMarkdown parses a markdown file and creates multiple issues from it
|
||||
func createIssuesFromMarkdown(_ *cobra.Command, filepath string) {
|
||||
// Ensure globals are initialized (bd-m0tl: fix nil pointer when store not ready)
|
||||
if store == nil {
|
||||
fmt.Fprintf(os.Stderr, "Error: database not initialized\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
if actor == "" {
|
||||
actor = "bd" // Default actor if not set
|
||||
}
|
||||
|
||||
// Parse markdown file
|
||||
// Parse markdown file first (doesn't require store access)
|
||||
templates, err := parseMarkdownFile(filepath)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error parsing markdown file: %v\n", err)
|
||||
@@ -327,6 +321,21 @@ func createIssuesFromMarkdown(_ *cobra.Command, filepath string) {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// If daemon is running, use RPC batch create (GH#719)
|
||||
if daemonClient != nil {
|
||||
createIssuesFromMarkdownViaDaemon(templates, filepath)
|
||||
return
|
||||
}
|
||||
|
||||
// Direct mode: ensure globals are initialized
|
||||
if store == nil {
|
||||
fmt.Fprintf(os.Stderr, "Error: database not initialized\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
if actor == "" {
|
||||
actor = "bd" // Default actor if not set
|
||||
}
|
||||
|
||||
ctx := rootCtx
|
||||
createdIssues := []*types.Issue{}
|
||||
failedIssues := []string{}
|
||||
@@ -421,3 +430,98 @@ func createIssuesFromMarkdown(_ *cobra.Command, filepath string) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// createIssuesFromMarkdownViaDaemon creates issues via daemon RPC batch operation
|
||||
func createIssuesFromMarkdownViaDaemon(templates []*IssueTemplate, filepath string) {
|
||||
createdIssues := []*types.Issue{}
|
||||
failedIssues := []string{}
|
||||
|
||||
// Build batch operations for all issues
|
||||
operations := make([]rpc.BatchOperation, 0, len(templates))
|
||||
for _, template := range templates {
|
||||
createArgs := &rpc.CreateArgs{
|
||||
Title: template.Title,
|
||||
Description: template.Description,
|
||||
Design: template.Design,
|
||||
AcceptanceCriteria: template.AcceptanceCriteria,
|
||||
IssueType: string(template.IssueType),
|
||||
Priority: template.Priority,
|
||||
Assignee: template.Assignee,
|
||||
Labels: template.Labels,
|
||||
Dependencies: template.Dependencies,
|
||||
}
|
||||
|
||||
argsJSON, err := json.Marshal(createArgs)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error marshaling args for '%s': %v\n", template.Title, err)
|
||||
failedIssues = append(failedIssues, template.Title)
|
||||
continue
|
||||
}
|
||||
|
||||
operations = append(operations, rpc.BatchOperation{
|
||||
Operation: "create",
|
||||
Args: argsJSON,
|
||||
})
|
||||
}
|
||||
|
||||
// Execute batch
|
||||
batchArgs := &rpc.BatchArgs{Operations: operations}
|
||||
resp, err := daemonClient.Batch(batchArgs)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error executing batch create: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Parse batch response
|
||||
var batchResp rpc.BatchResponse
|
||||
if err := json.Unmarshal(resp.Data, &batchResp); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error parsing batch response: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Process results
|
||||
for i, result := range batchResp.Results {
|
||||
if i >= len(templates) {
|
||||
break
|
||||
}
|
||||
template := templates[i]
|
||||
|
||||
if !result.Success {
|
||||
fmt.Fprintf(os.Stderr, "Error creating issue '%s': %s\n", template.Title, result.Error)
|
||||
failedIssues = append(failedIssues, template.Title)
|
||||
continue
|
||||
}
|
||||
|
||||
var issue types.Issue
|
||||
if err := json.Unmarshal(result.Data, &issue); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Warning: created issue '%s' but failed to parse response: %v\n", template.Title, err)
|
||||
// Still count as success since the issue was created
|
||||
createdIssues = append(createdIssues, &types.Issue{Title: template.Title})
|
||||
continue
|
||||
}
|
||||
|
||||
// Run create hook for each issue
|
||||
if hookRunner != nil {
|
||||
hookRunner.Run(hooks.EventCreate, &issue)
|
||||
}
|
||||
|
||||
createdIssues = append(createdIssues, &issue)
|
||||
}
|
||||
|
||||
// Report failures if any
|
||||
if len(failedIssues) > 0 {
|
||||
fmt.Fprintf(os.Stderr, "\n%s Failed to create %d issues:\n", ui.RenderFail("✗"), len(failedIssues))
|
||||
for _, title := range failedIssues {
|
||||
fmt.Fprintf(os.Stderr, " - %s\n", title)
|
||||
}
|
||||
}
|
||||
|
||||
if jsonOutput {
|
||||
outputJSON(createdIssues)
|
||||
} else {
|
||||
fmt.Printf("%s Created %d issues from %s:\n", ui.RenderPass("✓"), len(createdIssues), filepath)
|
||||
for _, issue := range createdIssues {
|
||||
fmt.Printf(" %s: %s [P%d, %s]\n", issue.ID, issue.Title, issue.Priority, issue.IssueType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user