@@ -30,7 +30,7 @@ pub struct GoalDocument {
30
30
pub summary : String ,
31
31
32
32
/// The "plan" for completing the goal (includes things owners will do as well as team asks)
33
- pub plan_items : Vec < PlanItem > ,
33
+ pub goal_plans : Vec < GoalPlan > ,
34
34
35
35
/// List of team asks extracted from the goal
36
36
pub team_asks : Vec < TeamAsk > ,
@@ -50,13 +50,22 @@ pub struct Metadata {
50
50
51
51
pub const TRACKING_ISSUE_ROW : & str = "Tracking issue" ;
52
52
53
+ /// Items required to complete the goal.
54
+ #[ derive( Debug , PartialEq , Eq , PartialOrd , Ord ) ]
55
+ pub struct GoalPlan {
56
+ /// If `Some`, title of the subsection in which these items were found.
57
+ pub subgoal : Option < String > ,
58
+
59
+ /// List of items found in the table.
60
+ pub plan_items : Vec < PlanItem > ,
61
+ }
62
+
53
63
/// Identifies a particular ask for a set of Rust teams
54
64
#[ derive( Debug , PartialEq , Eq , PartialOrd , Ord ) ]
55
65
pub struct PlanItem {
56
66
pub text : String ,
57
67
pub owners : String ,
58
68
pub notes : String ,
59
- pub children : Vec < PlanItem > ,
60
69
}
61
70
62
71
/// Returns the "owner(s)" of a plan-item, which can be
@@ -116,20 +125,23 @@ impl GoalDocument {
116
125
117
126
let link_path = Arc :: new ( link_path. to_path_buf ( ) ) ;
118
127
119
- let plan_items = match metadata. status {
128
+ let goal_plans = match metadata. status {
120
129
Status :: Flagship | Status :: Accepted | Status :: Proposed => {
121
130
extract_plan_items ( & sections) ?
122
131
}
123
132
Status :: NotAccepted => vec ! [ ] ,
124
133
} ;
125
134
126
135
let mut team_asks = vec ! [ ] ;
127
- for plan_item in & plan_items {
128
- team_asks. extend ( plan_item. team_asks (
129
- & link_path,
130
- & metadata. short_title ,
131
- & metadata. owners ,
132
- ) ?) ;
136
+ for goal_plan in & goal_plans {
137
+ let goal_title = goal_plan. subgoal . as_deref ( ) . unwrap_or ( & metadata. short_title ) ;
138
+ for plan_item in & goal_plan. plan_items {
139
+ team_asks. extend ( plan_item. team_asks (
140
+ & link_path,
141
+ goal_title,
142
+ & metadata. owners ,
143
+ ) ?) ;
144
+ }
133
145
}
134
146
135
147
Ok ( Some ( GoalDocument {
@@ -138,7 +150,7 @@ impl GoalDocument {
138
150
summary : summary. unwrap_or_else ( || metadata. title . clone ( ) ) ,
139
151
metadata,
140
152
team_asks,
141
- plan_items ,
153
+ goal_plans ,
142
154
} ) )
143
155
}
144
156
@@ -201,7 +213,7 @@ pub fn format_team_asks(asks_of_any_team: &[&TeamAsk]) -> anyhow::Result<String>
201
213
202
214
for subgoal in subgoals {
203
215
table. push ( vec ! [
204
- format!( "*{} *" , subgoal) ,
216
+ format!( "**{}* *" , subgoal) ,
205
217
"" . to_string( ) ,
206
218
"" . to_string( ) ,
207
219
] ) ;
@@ -390,29 +402,52 @@ fn extract_summary(sections: &[Section]) -> anyhow::Result<Option<String>> {
390
402
Ok ( Some ( ownership_section. text . trim ( ) . to_string ( ) ) )
391
403
}
392
404
393
- fn extract_plan_items < ' i > ( sections : & [ Section ] ) -> anyhow:: Result < Vec < PlanItem > > {
394
- let Some ( ownership_section ) = sections
405
+ fn extract_plan_items < ' i > ( sections : & [ Section ] ) -> anyhow:: Result < Vec < GoalPlan > > {
406
+ let Some ( ownership_index ) = sections
395
407
. iter ( )
396
- . find ( |section| section. title == "Ownership and team asks" )
408
+ . position ( |section| section. title == "Ownership and team asks" )
397
409
else {
398
410
anyhow:: bail!( "no `Ownership and team asks` section found" )
399
411
} ;
400
412
401
- let Some ( table) = ownership_section. tables . first ( ) else {
402
- anyhow:: bail!(
403
- "on line {}, no table found in `Ownership and team asks` section" ,
404
- ownership_section. line_num
405
- )
406
- } ;
413
+ // Extract the plan items from the main section (if any)
414
+ let level= sections[ ownership_index] . level ;
415
+
416
+ let mut goal_plans = vec ! [ ] ;
417
+ goal_plans. extend ( goal_plan ( None , & sections[ ownership_index] ) ?) ;
418
+
419
+ for subsection in sections. iter ( ) . skip ( ownership_index + 1 ) . take_while ( |s| s. level > level) {
420
+ goal_plans. extend ( goal_plan ( Some ( subsection. title . clone ( ) ) , subsection) ?) ;
421
+ }
407
422
408
- expect_headers ( table, & [ "Subgoal" , "Owner(s) or team(s)" , "Notes" ] ) ?;
423
+ if goal_plans. is_empty ( ) {
424
+ anyhow:: bail!( "no goal table items found in the `Ownership and team asks` section or subsections" )
425
+ }
426
+
427
+ Ok ( goal_plans)
428
+ }
409
429
410
- let mut rows = table. rows . iter ( ) . peekable ( ) ;
411
- let mut plan_items = vec ! [ ] ;
412
- while rows. peek ( ) . is_some ( ) {
413
- plan_items. push ( extract_plan_item ( & mut rows) ?) ;
430
+ fn goal_plan ( subgoal : Option < String > , section : & Section ) -> anyhow:: Result < Option < GoalPlan > > {
431
+ match section. tables . len ( ) {
432
+ 0 => Ok ( None ) ,
433
+ 1 => {
434
+ let table = & section. tables [ 0 ] ;
435
+ expect_headers ( table, & [ "Subgoal" , "Owner(s) or team(s)" , "Notes" ] ) ?;
436
+
437
+ let mut rows = table. rows . iter ( ) . peekable ( ) ;
438
+ let mut plan_items = vec ! [ ] ;
439
+ while rows. peek ( ) . is_some ( ) {
440
+ plan_items. push ( extract_plan_item ( & mut rows) ?) ;
441
+ }
442
+
443
+ Ok ( Some ( GoalPlan {
444
+ subgoal,
445
+ plan_items,
446
+ } ) )
447
+ }
448
+ _ => anyhow:: bail!( "multiple goal tables found in section `{}`" , section. title) ,
414
449
}
415
- Ok ( plan_items )
450
+
416
451
}
417
452
418
453
fn extract_plan_item (
@@ -422,33 +457,11 @@ fn extract_plan_item(
422
457
anyhow:: bail!( "unexpected end of table" ) ;
423
458
} ;
424
459
425
- let mut subgoal = row[ 0 ] . trim ( ) ;
426
- let mut is_child = false ;
427
-
428
- if subgoal. starts_with ( ARROW ) {
429
- // e.g., "↳ stabilization" is a subtask of the metagoal
430
- subgoal = row[ 0 ] [ ARROW . len ( ) ..] . trim ( ) ;
431
- is_child = true ;
432
- }
433
-
434
- let mut item = PlanItem {
435
- text : subgoal. to_string ( ) ,
460
+ Ok ( PlanItem {
461
+ text : row[ 0 ] . to_string ( ) ,
436
462
owners : row[ 1 ] . to_string ( ) ,
437
463
notes : row[ 2 ] . to_string ( ) ,
438
- children : vec ! [ ] ,
439
- } ;
440
-
441
- if !is_child {
442
- while let Some ( row) = rows. peek ( ) {
443
- if !row[ 0 ] . starts_with ( ARROW ) {
444
- break ;
445
- }
446
-
447
- item. children . push ( extract_plan_item ( rows) ?) ;
448
- }
449
- }
450
-
451
- Ok ( item)
464
+ } )
452
465
}
453
466
454
467
impl PlanItem {
@@ -543,16 +556,6 @@ impl PlanItem {
543
556
} ) ;
544
557
}
545
558
546
- for child in & self . children {
547
- // If this item has owners listed, they take precedence, otherwise use the owners in scope.
548
- let owners = if self . owners . is_empty ( ) {
549
- goal_owners
550
- } else {
551
- & self . owners
552
- } ;
553
- asks. extend ( child. team_asks ( link_path, & self . text , owners) ?) ;
554
- }
555
-
556
559
Ok ( asks)
557
560
}
558
561
}
0 commit comments