From 744d2a7d22cc5a7d57b4792e8247e76abe9b7789 Mon Sep 17 00:00:00 2001 From: beads/crew/emma Date: Wed, 7 Jan 2026 01:04:58 -0800 Subject: [PATCH] feat(create): add --dry-run flag to preview issue creation (bd-0hi7) Adds --dry-run flag that shows what would be created without actually creating the issue. Useful for scripting and validation. - Shows preview in human-readable format by default - Outputs full issue JSON with --json flag (empty ID, not placeholder string) - Skips all side effects (hooks, labels, dependencies) - Works with --rig/--prefix flags (shows target rig) - Errors gracefully with --file flag (not supported) - Includes event fields when --type=event --- cmd/bd/create.go | 81 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/cmd/bd/create.go b/cmd/bd/create.go index 7d1dc38d..074a5f69 100644 --- a/cmd/bd/create.go +++ b/cmd/bd/create.go @@ -36,6 +36,11 @@ var createCmd = &cobra.Command{ if len(args) > 0 { FatalError("cannot specify both title and --file flag") } + // --dry-run not supported with --file (would need to parse and preview multiple issues) + dryRun, _ := cmd.Flags().GetBool("dry-run") + if dryRun { + FatalError("--dry-run is not supported with --file flag") + } createIssuesFromMarkdown(cmd, file) return } @@ -173,6 +178,81 @@ var createCmd = &cobra.Command{ deferUntil = &t } + // Handle --dry-run flag (before --rig to ensure it works with cross-rig creation) + dryRun, _ := cmd.Flags().GetBool("dry-run") + if dryRun { + // Build preview issue + var externalRefPtr *string + if externalRef != "" { + externalRefPtr = &externalRef + } + previewIssue := &types.Issue{ + Title: title, + Description: description, + Design: design, + AcceptanceCriteria: acceptance, + Notes: notes, + Status: types.StatusOpen, + Priority: priority, + IssueType: types.IssueType(issueType), + Assignee: assignee, + ExternalRef: externalRefPtr, + Ephemeral: wisp, + CreatedBy: getActorWithGit(), + MolType: molType, + RoleType: roleType, + Rig: agentRig, + DueAt: dueAt, + DeferUntil: deferUntil, + // Event fields + EventKind: eventCategory, + Actor: eventActor, + Target: eventTarget, + Payload: eventPayload, + } + if explicitID != "" { + previewIssue.ID = explicitID + } + + if jsonOutput { + outputJSON(previewIssue) + } else { + idDisplay := previewIssue.ID + if idDisplay == "" { + idDisplay = "(will be generated)" + } + fmt.Printf("%s [DRY RUN] Would create issue:\n", ui.RenderWarn("⚠")) + fmt.Printf(" ID: %s\n", idDisplay) + fmt.Printf(" Title: %s\n", previewIssue.Title) + fmt.Printf(" Type: %s\n", previewIssue.IssueType) + fmt.Printf(" Priority: P%d\n", previewIssue.Priority) + fmt.Printf(" Status: %s\n", previewIssue.Status) + if previewIssue.Assignee != "" { + fmt.Printf(" Assignee: %s\n", previewIssue.Assignee) + } + if previewIssue.Description != "" { + fmt.Printf(" Description: %s\n", previewIssue.Description) + } + if len(labels) > 0 { + fmt.Printf(" Labels: %s\n", strings.Join(labels, ", ")) + } + if len(deps) > 0 { + fmt.Printf(" Dependencies: %s\n", strings.Join(deps, ", ")) + } + if rigOverride != "" || prefixOverride != "" { + rig := rigOverride + if rig == "" { + rig = prefixOverride + } + fmt.Printf(" Target rig: %s\n", rig) + } + if eventCategory != "" { + fmt.Printf(" Event category: %s\n", eventCategory) + } + } + return + } + // Handle --rig or --prefix flag: create issue in a different rig // Both flags use the same forgiving lookup (accepts rig names or prefixes) targetRig := rigOverride @@ -602,6 +682,7 @@ func init() { createCmd.Flags().StringP("file", "f", "", "Create multiple issues from markdown file") createCmd.Flags().String("title", "", "Issue title (alternative to positional argument)") createCmd.Flags().Bool("silent", false, "Output only the issue ID (for scripting)") + createCmd.Flags().Bool("dry-run", false, "Preview what would be created without actually creating") registerPriorityFlag(createCmd, "2") createCmd.Flags().StringP("type", "t", "task", "Issue type (bug|feature|task|epic|chore|merge-request|molecule|gate|agent|role|rig|convoy|event)") registerCommonIssueFlags(createCmd)