Skip to content

Commit 3c3006b

Browse files
author
Niko Matsakis
committed
rework to flat lists of goals
1 parent 7b77f9b commit 3c3006b

32 files changed

+670
-508
lines changed

crates/rust-project-goals-cli/src/rfc.rs

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use rust_project_goals::{
1818
},
1919
labels::GhLabel,
2020
},
21-
goal::{self, GoalDocument, ParsedOwners, PlanItem, Status},
21+
goal::{self, GoalDocument, GoalPlan, ParsedOwners, Status},
2222
team::{get_person_data, TeamName},
2323
};
2424

@@ -324,8 +324,8 @@ fn issue<'doc>(timeframe: &str, document: &'doc GoalDocument) -> anyhow::Result<
324324

325325
fn issue_text(timeframe: &str, document: &GoalDocument) -> anyhow::Result<String> {
326326
let mut tasks = vec![];
327-
for plan_item in &document.plan_items {
328-
tasks.extend(task_items(plan_item)?);
327+
for goal_plan in &document.goal_plans {
328+
tasks.extend(task_items(goal_plan)?);
329329
}
330330

331331
let teams = document
@@ -361,35 +361,38 @@ fn issue_text(timeframe: &str, document: &GoalDocument) -> anyhow::Result<String
361361
))
362362
}
363363

364-
fn task_items(plan_item: &PlanItem) -> anyhow::Result<Vec<String>> {
364+
fn task_items(goal_plan: &GoalPlan) -> anyhow::Result<Vec<String>> {
365365
use std::fmt::Write;
366366

367+
367368
let mut tasks = vec![];
368369

369-
let mut description = format!(
370-
"* {box} {text}",
371-
box = if plan_item.is_complete() { "[x]" } else { "[ ]" },
372-
text = plan_item.text
373-
);
370+
if let Some(title) = &goal_plan.subgoal {
371+
tasks.push(format!("### {title}"));
372+
}
374373

375-
if let Some(parsed_owners) = plan_item.parse_owners()? {
376-
match parsed_owners {
377-
ParsedOwners::TeamAsks(asks) => {
378-
let teams: Vec<String> = asks.iter().map(|ask| ask.name_and_link()).collect();
374+
for plan_item in &goal_plan.plan_items {
375+
let mut description = format!(
376+
"* {box} {text}",
377+
box = if plan_item.is_complete() { "[x]" } else { "[ ]" },
378+
text = plan_item.text
379+
);
379380

380-
write!(description, " ({} ![Team][])", teams.join(", "))?;
381-
}
381+
if let Some(parsed_owners) = plan_item.parse_owners()? {
382+
match parsed_owners {
383+
ParsedOwners::TeamAsks(asks) => {
384+
let teams: Vec<String> = asks.iter().map(|ask| ask.name_and_link()).collect();
382385

383-
ParsedOwners::Usernames(usernames) => {
384-
write!(description, " ({})", usernames.join(", "))?;
386+
write!(description, " ({} ![Team][])", teams.join(", "))?;
387+
}
388+
389+
ParsedOwners::Usernames(usernames) => {
390+
write!(description, " ({})", usernames.join(", "))?;
391+
}
385392
}
386393
}
387-
}
388-
389-
tasks.push(description);
390394

391-
for task in &plan_item.children {
392-
tasks.extend(task_items(task)?.into_iter().map(|t| format!(" {}", &t)));
395+
tasks.push(description);
393396
}
394397

395398
Ok(tasks)

crates/rust-project-goals/src/goal.rs

Lines changed: 64 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pub struct GoalDocument {
3030
pub summary: String,
3131

3232
/// 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>,
3434

3535
/// List of team asks extracted from the goal
3636
pub team_asks: Vec<TeamAsk>,
@@ -50,13 +50,22 @@ pub struct Metadata {
5050

5151
pub const TRACKING_ISSUE_ROW: &str = "Tracking issue";
5252

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+
5363
/// Identifies a particular ask for a set of Rust teams
5464
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
5565
pub struct PlanItem {
5666
pub text: String,
5767
pub owners: String,
5868
pub notes: String,
59-
pub children: Vec<PlanItem>,
6069
}
6170

6271
/// Returns the "owner(s)" of a plan-item, which can be
@@ -116,20 +125,23 @@ impl GoalDocument {
116125

117126
let link_path = Arc::new(link_path.to_path_buf());
118127

119-
let plan_items = match metadata.status {
128+
let goal_plans = match metadata.status {
120129
Status::Flagship | Status::Accepted | Status::Proposed => {
121130
extract_plan_items(&sections)?
122131
}
123132
Status::NotAccepted => vec![],
124133
};
125134

126135
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+
}
133145
}
134146

135147
Ok(Some(GoalDocument {
@@ -138,7 +150,7 @@ impl GoalDocument {
138150
summary: summary.unwrap_or_else(|| metadata.title.clone()),
139151
metadata,
140152
team_asks,
141-
plan_items,
153+
goal_plans,
142154
}))
143155
}
144156

@@ -201,7 +213,7 @@ pub fn format_team_asks(asks_of_any_team: &[&TeamAsk]) -> anyhow::Result<String>
201213

202214
for subgoal in subgoals {
203215
table.push(vec![
204-
format!("*{}*", subgoal),
216+
format!("**{}**", subgoal),
205217
"".to_string(),
206218
"".to_string(),
207219
]);
@@ -390,29 +402,52 @@ fn extract_summary(sections: &[Section]) -> anyhow::Result<Option<String>> {
390402
Ok(Some(ownership_section.text.trim().to_string()))
391403
}
392404

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
395407
.iter()
396-
.find(|section| section.title == "Ownership and team asks")
408+
.position(|section| section.title == "Ownership and team asks")
397409
else {
398410
anyhow::bail!("no `Ownership and team asks` section found")
399411
};
400412

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+
}
407422

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+
}
409429

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),
414449
}
415-
Ok(plan_items)
450+
416451
}
417452

418453
fn extract_plan_item(
@@ -422,33 +457,11 @@ fn extract_plan_item(
422457
anyhow::bail!("unexpected end of table");
423458
};
424459

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(),
436462
owners: row[1].to_string(),
437463
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+
})
452465
}
453466

454467
impl PlanItem {
@@ -543,16 +556,6 @@ impl PlanItem {
543556
});
544557
}
545558

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-
556559
Ok(asks)
557560
}
558561
}

src/2024h2/annotate-snippets.md

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Use annotate-snippets for rustc diagnostic output
22

33
| Metadata | |
4-
| --- | --- |
4+
|----------------|------------------------------------|
55
| Owner(s) | @estebank, @Muscraft |
66
| Teams | [compiler] |
77
| Status | Accepted |
@@ -61,24 +61,36 @@ This section defines the specific work items that are planned and who is expecte
6161

6262
*Adjust the table below; some common examples are shown below.*
6363

64-
| Subgoal | Owner(s) or team(s) | Notes |
65-
| ----------------------------------------------- | ------------------------------ | ------------------------------ |
66-
| Reach output parity of rustc/annotate-snippets | | |
67-
| ↳ Port a subset of rustc's UI tests | @Muscraft | |
68-
| ↳ Make list of current unnaddressed divergences | @Muscraft | |
69-
| ↳ address divergences | @Muscraft | |
70-
| Initial use of annotate-snippets | | |
71-
| ↳ update annotate-snippets to latest version | | |
72-
| ↳ teach cargo to pass annotate-snippets flag | @estebank | |
73-
| ↳ add ui test mode comparing new output | | |
74-
| ↳ switch default nightly rustc output | | |
75-
| Production use of annotate-snippets | | |
76-
| ↳ switch default rustc output | | |
77-
| ↳ release notes | | |
78-
| ↳ switch ui tests to only check new output | | |
79-
| ↳ Dedicated reviewer | ![Team][] [compiler] | @estebank will be the reviewer |
80-
| Standard reviews | ![Team][] [compiler] | |
81-
| Top-level Rust blog post inviting feedback |
64+
| Subgoal | Owner(s) or team(s) | Notes |
65+
|--------------------------------------------|----------------------|-------|
66+
| Standard reviews | ![Team][] [compiler] | |
67+
| Top-level Rust blog post inviting feedback | | |
68+
69+
### Reach output parity for rustc/annotation-snippets
70+
71+
| Subgoal | Owner(s) or team(s) | Notes |
72+
|-----------------------------------------------|---------------------|-------|
73+
| Port a subset of rustc's UI tests | @Muscraft | |
74+
| Make list of current unnaddressed divergences | @Muscraft | |
75+
| address divergences | @Muscraft | |
76+
77+
### Initial use of annotate-snippets
78+
79+
| Subgoal | Owner(s) or team(s) | Notes |
80+
|--------------------------------------------|---------------------|-------|
81+
| update annotate-snippets to latest version | | |
82+
| teach cargo to pass annotate-snippets flag | @estebank | |
83+
| add ui test mode comparing new output | | |
84+
| switch default nightly rustc output | | |
85+
86+
### Production use of annotate-snippets
87+
88+
| Subgoal | Owner(s) or team(s) | Notes |
89+
|------------------------------------------|----------------------|--------------------------------|
90+
| switch default rustc output | | |
91+
| release notes | | |
92+
| switch ui tests to only check new output | | |
93+
| Dedicated reviewer | ![Team][] [compiler] | @estebank will be the reviewer |
8294

8395
## Frequently asked questions
8496

0 commit comments

Comments
 (0)