tix/cli/cli_initiative.rs
1#[allow(clippy::wildcard_imports)]
2use super::*;
3
4/// The `tix initiative` subcommands (mission `roadmap-initiatives-01M3C8SX`, WP04).
5///
6/// A **required** subcommand, like `tix project` and `tix epic`. Selection is by the
7/// stable id (the registry key); a name resolves to the same initiative as a
8/// convenience. A rename through `edit --name` changes the label only: the id is not
9/// re-keyed, so every association and derived value survives.
10#[derive(Subcommand)]
11pub enum InitiativeCommand {
12 /// Create an initiative and allocate a stable id
13 ///
14 /// The name is a display label, not the identity: `tix initiative edit --name`
15 /// changes it and every association survives, because the record is keyed by id.
16 Create {
17 /// Display name (unique within the registry, case-insensitively)
18 #[arg(value_name = "NAME")]
19 name: String,
20 /// Optional strategic outcome
21 #[arg(long)]
22 outcome: Option<String>,
23 /// Owner identity string; no lookup, never inferred
24 #[arg(long)]
25 owner: Option<String>,
26 /// Free-form initiative status (not a board column)
27 #[arg(long)]
28 status: Option<String>,
29 /// Initiative priority (a known spelling is normalized; an unknown one is kept)
30 #[arg(long)]
31 priority: Option<String>,
32 /// Filterable labels, comma-separated
33 #[arg(long)]
34 labels: Option<String>,
35 /// Target date (`YYYY-MM-DD`)
36 #[arg(long = "target-date")]
37 target_date: Option<String>,
38 /// Project ids this initiative concerns, comma-separated
39 ///
40 /// Shape-checked only, never resolved: a well-formed id the registry does not
41 /// hold is stored and diagnosed by `tix roadmap`/`tix lint`, so it is
42 /// repairable.
43 #[arg(long, value_name = "ID")]
44 projects: Option<String>,
45 /// Epic ids this initiative concerns, comma-separated
46 #[arg(long, value_name = "ID")]
47 epics: Option<String>,
48 /// Milestone names this initiative concerns, comma-separated
49 #[arg(long, value_name = "NAME")]
50 milestones: Option<String>,
51 },
52 /// Edit an initiative's fields; a rename changes the label only
53 ///
54 /// Nothing is re-keyed, so every association and derived value stays intact. An
55 /// optional value with a blank spelling clears the field (`--owner ""`), and a
56 /// blank reference list clears it (`--projects ""`).
57 Edit {
58 /// Initiative id (a name is accepted as a convenience)
59 #[arg(value_name = "ID")]
60 reference: String,
61 /// New display name
62 #[arg(long)]
63 name: Option<String>,
64 /// New strategic outcome (`--outcome ""` clears)
65 #[arg(long)]
66 outcome: Option<String>,
67 /// New owner identity string (`--owner ""` clears)
68 #[arg(long)]
69 owner: Option<String>,
70 /// New free-form status (`--status ""` clears)
71 #[arg(long)]
72 status: Option<String>,
73 /// New priority (`--priority ""` clears)
74 #[arg(long)]
75 priority: Option<String>,
76 /// Replace the label list, comma-separated (`--labels ""` clears)
77 #[arg(long)]
78 labels: Option<String>,
79 /// New target date (`YYYY-MM-DD`; `--target-date ""` clears)
80 #[arg(long = "target-date")]
81 target_date: Option<String>,
82 /// Replace the project ids, comma-separated (`--projects ""` clears)
83 #[arg(long, value_name = "ID")]
84 projects: Option<String>,
85 /// Replace the epic ids, comma-separated (`--epics ""` clears)
86 #[arg(long, value_name = "ID")]
87 epics: Option<String>,
88 /// Replace the milestone names, comma-separated (`--milestones ""` clears)
89 #[arg(long, value_name = "NAME")]
90 milestones: Option<String>,
91 },
92 /// List initiatives in declaration order, with ids, target dates and status
93 List,
94 /// Show one initiative's record, metadata and references
95 Show {
96 /// Initiative id (a name is accepted as a convenience)
97 #[arg(value_name = "ID")]
98 reference: String,
99 },
100 /// Delete an initiative's registry entry (nothing else is ever deleted)
101 ///
102 /// The record's own references are reported and nothing cascades: no project,
103 /// epic, milestone or issue is touched, and no association is silently repaired.
104 Delete {
105 /// Initiative id (a name is accepted as a convenience)
106 #[arg(value_name = "ID")]
107 reference: String,
108 /// Confirm without prompting
109 #[arg(long)]
110 yes: bool,
111 },
112 /// Associate an initiative with exactly one project, epic or milestone
113 ///
114 /// Name exactly one of `--project`, `--epic`, `--milestone`; the kind is part of
115 /// the record, so guessing is worse than asking. A well-formed reference that
116 /// names nothing is stored and stays diagnosable, and a repeated association is
117 /// an idempotent no-op that writes no bytes.
118 Associate {
119 /// Initiative id (a name is accepted as a convenience)
120 #[arg(value_name = "ID")]
121 reference: String,
122 /// Project **id** to associate
123 #[arg(long, value_name = "ID")]
124 project: Option<String>,
125 /// Epic **id** to associate
126 #[arg(long, value_name = "ID")]
127 epic: Option<String>,
128 /// Milestone **name** to associate
129 #[arg(long, value_name = "NAME")]
130 milestone: Option<String>,
131 },
132 /// Drop an explicit association from an initiative
133 ///
134 /// Name exactly one of `--project`, `--epic`, `--milestone`. Dropping an
135 /// association that is not recorded is an idempotent no-op that writes no bytes.
136 Dereference {
137 /// Initiative id (a name is accepted as a convenience)
138 #[arg(value_name = "ID")]
139 reference: String,
140 /// Project **id** to drop
141 #[arg(long, value_name = "ID")]
142 project: Option<String>,
143 /// Epic **id** to drop
144 #[arg(long, value_name = "ID")]
145 epic: Option<String>,
146 /// Milestone **name** to drop
147 #[arg(long, value_name = "NAME")]
148 milestone: Option<String>,
149 },
150}