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
This commit is contained in:
beads/crew/emma
2026-01-07 01:04:58 -08:00
committed by Steve Yegge
parent 81a2af9598
commit 744d2a7d22

View File

@@ -36,6 +36,11 @@ var createCmd = &cobra.Command{
if len(args) > 0 { if len(args) > 0 {
FatalError("cannot specify both title and --file flag") 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) createIssuesFromMarkdown(cmd, file)
return return
} }
@@ -173,6 +178,81 @@ var createCmd = &cobra.Command{
deferUntil = &t 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 // Handle --rig or --prefix flag: create issue in a different rig
// Both flags use the same forgiving lookup (accepts rig names or prefixes) // Both flags use the same forgiving lookup (accepts rig names or prefixes)
targetRig := rigOverride targetRig := rigOverride
@@ -602,6 +682,7 @@ func init() {
createCmd.Flags().StringP("file", "f", "", "Create multiple issues from markdown file") createCmd.Flags().StringP("file", "f", "", "Create multiple issues from markdown file")
createCmd.Flags().String("title", "", "Issue title (alternative to positional argument)") 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("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") 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)") createCmd.Flags().StringP("type", "t", "task", "Issue type (bug|feature|task|epic|chore|merge-request|molecule|gate|agent|role|rig|convoy|event)")
registerCommonIssueFlags(createCmd) registerCommonIssueFlags(createCmd)