Skip to main content

plan_issue_cli/commands/
plan.rs

1use std::path::PathBuf;
2
3use clap::{ArgGroup, Args, ValueEnum};
4use serde::Serialize;
5
6use super::{CommentModeArgs, CommentTextArgs, GroupingArgs, PrefixArgs, SummaryArgs};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, ValueEnum)]
9pub enum CloseReason {
10    Completed,
11    #[value(name = "not-planned")]
12    NotPlanned,
13}
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, ValueEnum)]
16pub enum LinkPrStatus {
17    #[value(name = "planned")]
18    Planned,
19    #[value(name = "in-progress")]
20    InProgress,
21    #[value(name = "blocked")]
22    Blocked,
23}
24
25#[derive(Debug, Clone, Args, Serialize)]
26pub struct StartPlanArgs {
27    /// Plan markdown path.
28    #[arg(long, value_name = "path")]
29    pub plan: PathBuf,
30
31    /// Override plan issue title.
32    #[arg(long, value_name = "text")]
33    pub title: Option<String>,
34
35    /// Plan task-spec output path override.
36    #[arg(long, value_name = "path")]
37    pub task_spec_out: Option<PathBuf>,
38
39    /// Rendered plan issue body output path override.
40    #[arg(long, value_name = "path")]
41    pub issue_body_out: Option<PathBuf>,
42
43    #[command(flatten)]
44    pub prefixes: PrefixArgs,
45
46    #[command(flatten)]
47    pub grouping: GroupingArgs,
48
49    /// Labels to add at issue creation time.
50    #[arg(long = "label", value_name = "name", default_values = ["issue", "plan"])]
51    pub label: Vec<String>,
52}
53
54#[derive(Debug, Clone, Args, Serialize)]
55#[command(group(
56    ArgGroup::new("issue_source")
57        .required(true)
58        .args(["issue", "body_file"])
59))]
60#[command(group(
61    ArgGroup::new("target_scope")
62        .required(true)
63        .args(["task", "sprint"])
64))]
65pub struct LinkPrArgs {
66    /// Plan issue number (live `plan-issue` path only).
67    #[arg(long, value_name = "number")]
68    pub issue: Option<u64>,
69
70    /// Offline issue body path.
71    #[arg(long, value_name = "path")]
72    pub body_file: Option<PathBuf>,
73
74    /// Target task row id (for example `S2T3`). Shared-lane rows sync automatically.
75    #[arg(long, value_name = "task-id")]
76    pub task: Option<String>,
77
78    /// Target sprint rows. If multiple shared lanes exist, use `--pr-group`.
79    #[arg(long, value_parser = clap::value_parser!(u16).range(1..), value_name = "number")]
80    pub sprint: Option<u16>,
81
82    /// Target PR group within the sprint (`pr-shared` lane selector).
83    #[arg(
84        long = "pr-group",
85        value_name = "group",
86        requires = "sprint",
87        conflicts_with = "task"
88    )]
89    pub pr_group: Option<String>,
90
91    /// PR reference (`#123`, `123`, or GitHub pull URL).
92    #[arg(long, value_name = "pr")]
93    pub pr: String,
94
95    /// Row status to apply after linking PR (default: `in-progress`).
96    #[arg(long, value_enum, default_value_t = LinkPrStatus::InProgress)]
97    pub status: LinkPrStatus,
98}
99
100#[derive(Debug, Clone, Args, Serialize)]
101#[command(group(
102    ArgGroup::new("issue_source")
103        .required(true)
104        .args(["issue", "body_file"])
105))]
106pub struct StatusPlanArgs {
107    /// Plan issue number (live `plan-issue` path only).
108    #[arg(long, value_name = "number")]
109    pub issue: Option<u64>,
110
111    /// Offline issue body path.
112    #[arg(long, value_name = "path")]
113    pub body_file: Option<PathBuf>,
114
115    #[command(flatten)]
116    pub comment_mode: CommentModeArgs,
117}
118
119#[derive(Debug, Clone, Args, Serialize)]
120#[command(group(
121    ArgGroup::new("issue_source")
122        .required(true)
123        .args(["issue", "body_file"])
124))]
125pub struct ReadyPlanArgs {
126    /// Plan issue number (live `plan-issue` path only).
127    #[arg(long, value_name = "number")]
128    pub issue: Option<u64>,
129
130    /// Offline issue body path.
131    #[arg(long, value_name = "path")]
132    pub body_file: Option<PathBuf>,
133
134    #[command(flatten)]
135    pub summary: SummaryArgs,
136
137    /// Apply label updates in live mode.
138    #[arg(long)]
139    pub label_update: bool,
140
141    /// Review label to add when `--label-update` is set.
142    #[arg(long = "label", value_name = "name", requires = "label_update")]
143    pub label: Option<String>,
144
145    /// Labels to remove when `--label-update` is set.
146    #[arg(long = "remove-label", value_name = "name", requires = "label_update")]
147    pub remove_label: Vec<String>,
148
149    #[command(flatten)]
150    pub comment_mode: CommentModeArgs,
151}
152
153#[derive(Debug, Clone, Args, Serialize)]
154pub struct ClosePlanArgs {
155    /// Plan issue number (`--issue`-only path is live `plan-issue` only).
156    #[arg(long, value_name = "number")]
157    pub issue: Option<u64>,
158
159    /// Local issue body path (dry-run mode).
160    #[arg(long, value_name = "path")]
161    pub body_file: Option<PathBuf>,
162
163    /// Final approval comment URL.
164    #[arg(long = "approved-comment-url", value_name = "url")]
165    pub approved_comment_url: String,
166
167    /// Close reason.
168    #[arg(long, value_enum, default_value_t = CloseReason::Completed)]
169    pub reason: CloseReason,
170
171    #[command(flatten)]
172    pub close_comment: CommentTextArgs,
173
174    /// Allow closing when some tasks are not done.
175    #[arg(long)]
176    pub allow_not_done: bool,
177}
178
179#[derive(Debug, Clone, Args, Serialize)]
180pub struct CleanupWorktreesArgs {
181    /// Plan issue number (live `plan-issue` only).
182    #[arg(long, value_name = "number")]
183    pub issue: u64,
184}