Skip to content

Commit 7ab1c15

Browse files
authored
Merge pull request #226 from nikomatsakis/autogenerate-owners-and-teams
Autogenerate owners and teams
2 parents 6255bff + 3e997eb commit 7ab1c15

File tree

76 files changed

+417
-138
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+417
-138
lines changed

crates/mdbook-goals/src/mdbook_preprocessor.rs

Lines changed: 90 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ impl<'c> GoalPreprocessorWithContext<'c> {
127127
fn process_book_item(&mut self, book_item: &mut BookItem) -> anyhow::Result<()> {
128128
match book_item {
129129
BookItem::Chapter(chapter) => {
130+
self.replace_metadata_placeholders(chapter)?;
130131
self.replace_team_asks(chapter)?;
131132
self.replace_goal_lists(chapter)?;
132133
self.replace_goal_count(chapter)?;
@@ -173,14 +174,27 @@ impl<'c> GoalPreprocessorWithContext<'c> {
173174
}
174175

175176
fn replace_goal_lists(&mut self, chapter: &mut Chapter) -> anyhow::Result<()> {
176-
self.replace_goal_lists_helper(chapter, &re::FLAGSHIP_GOAL_LIST, |status| status.is_flagship && status.is_not_not_accepted())?;
177-
self.replace_goal_lists_helper(chapter, &re::OTHER_GOAL_LIST, |status| !status.is_flagship && status.is_not_not_accepted())?;
178-
self.replace_goal_lists_helper(chapter, &re::GOAL_LIST, |status| status.is_not_not_accepted())?;
179-
self.replace_goal_lists_helper(chapter, &re::GOAL_NOT_ACCEPTED_LIST, |status| !status.is_not_not_accepted())?;
177+
self.replace_goal_lists_helper(chapter, &re::FLAGSHIP_GOAL_LIST, |status| {
178+
status.is_flagship && status.is_not_not_accepted()
179+
})?;
180+
self.replace_goal_lists_helper(chapter, &re::OTHER_GOAL_LIST, |status| {
181+
!status.is_flagship && status.is_not_not_accepted()
182+
})?;
183+
self.replace_goal_lists_helper(chapter, &re::GOAL_LIST, |status| {
184+
status.is_not_not_accepted()
185+
})?;
186+
self.replace_goal_lists_helper(chapter, &re::GOAL_NOT_ACCEPTED_LIST, |status| {
187+
!status.is_not_not_accepted()
188+
})?;
180189
Ok(())
181190
}
182-
183-
fn replace_goal_lists_helper(&mut self, chapter: &mut Chapter, regex: &Regex, filter: impl Fn(Status) -> bool) -> anyhow::Result<()> {
191+
192+
fn replace_goal_lists_helper(
193+
&mut self,
194+
chapter: &mut Chapter,
195+
regex: &Regex,
196+
filter: impl Fn(Status) -> bool,
197+
) -> anyhow::Result<()> {
184198
loop {
185199
let Some(m) = regex.find(&chapter.content) else {
186200
return Ok(());
@@ -193,7 +207,8 @@ impl<'c> GoalPreprocessorWithContext<'c> {
193207

194208
// Extract out the list of goals with the given status.
195209
let goals = self.goal_documents(chapter_path)?;
196-
let mut goals_with_status: Vec<&GoalDocument> = goals.iter().filter(|g| filter(g.metadata.status)).collect();
210+
let mut goals_with_status: Vec<&GoalDocument> =
211+
goals.iter().filter(|g| filter(g.metadata.status)).collect();
197212

198213
goals_with_status.sort_by_key(|g| &g.metadata.title);
199214

@@ -246,25 +261,22 @@ impl<'c> GoalPreprocessorWithContext<'c> {
246261
Ok(())
247262
}
248263

264+
/// Find the goal documents for the milestone in which this `chapter_path` resides.
265+
/// e.g., if invoked with `2024h2/xxx.md`, will find all goal documents in `2024h2`.
249266
fn goal_documents(&mut self, chapter_path: &Path) -> anyhow::Result<Arc<Vec<GoalDocument>>> {
250-
// let chapter_path = self.ctx.config.book.src.join(chapter_path);
251267

252-
if let Some(goals) = self.goal_document_map.get(chapter_path) {
268+
let Some(milestone_path) = chapter_path.parent() else {
269+
anyhow::bail!("cannot get goal documents from `{chapter_path:?}`")
270+
};
271+
272+
if let Some(goals) = self.goal_document_map.get(milestone_path) {
253273
return Ok(goals.clone());
254274
}
255275

256-
let goal_documents = goal::goals_in_dir(
257-
self.ctx
258-
.config
259-
.book
260-
.src
261-
.join(chapter_path)
262-
.parent()
263-
.unwrap(),
264-
)?;
276+
let goal_documents = goal::goals_in_dir(&self.ctx.config.book.src.join(milestone_path))?;
265277
let goals = Arc::new(goal_documents);
266278
self.goal_document_map
267-
.insert(chapter_path.to_path_buf(), goals.clone());
279+
.insert(milestone_path.to_path_buf(), goals.clone());
268280
Ok(goals)
269281
}
270282

@@ -365,4 +377,63 @@ impl<'c> GoalPreprocessorWithContext<'c> {
365377
}
366378
Ok(())
367379
}
380+
381+
/// Replace placeholders like TASK_OWNERS and TEAMS_WITH_ASKS.
382+
/// All goal documents should have this in their metadata table;
383+
/// that is enforced during goal parsing.
384+
fn replace_metadata_placeholders(&mut self, chapter: &mut Chapter) -> anyhow::Result<()> {
385+
self.replace_metadata_placeholder(chapter, &re::TASK_OWNERS, |goal| {
386+
goal.task_owners.iter().cloned().collect()
387+
})?;
388+
389+
self.replace_metadata_placeholder(chapter, &re::TEAMS_WITH_ASKS, |goal| {
390+
goal.teams_with_asks()
391+
.iter()
392+
.map(|team_name| team_name.name())
393+
.collect()
394+
})?;
395+
396+
Ok(())
397+
}
398+
399+
/// Replace one of the placeholders that occur in the goal document metadata,
400+
/// like [`re::TASK_OWNERS`][].
401+
fn replace_metadata_placeholder(
402+
&mut self,
403+
chapter: &mut Chapter,
404+
regex: &Regex,
405+
op: impl Fn(&GoalDocument) -> Vec<String>,
406+
) -> anyhow::Result<()> {
407+
let Some(m) = regex.find(&chapter.content) else {
408+
return Ok(());
409+
};
410+
let range = m.range();
411+
412+
let Some(chapter_path) = chapter.path.as_ref() else {
413+
anyhow::bail!(
414+
"goal chapter `{}` matches placeholder regex but has no path",
415+
chapter.name
416+
);
417+
};
418+
419+
// Hack: leave this stuff alone in the template
420+
if chapter_path.file_name().unwrap() == "TEMPLATE.md" {
421+
return Ok(());
422+
}
423+
424+
let goals = self.goal_documents(&chapter_path)?;
425+
let chapter_in_context = self.ctx.config.book.src.join(chapter_path);
426+
let Some(goal) = goals.iter().find(|gd| gd.path == chapter_in_context) else {
427+
anyhow::bail!(
428+
"goal chapter `{}` has no goal document at path {:?}",
429+
chapter.name,
430+
chapter_path,
431+
);
432+
};
433+
434+
let replacement = op(goal).join(", ");
435+
chapter.content.replace_range(range, &replacement);
436+
437+
Ok(())
438+
}
368439
}

0 commit comments

Comments
 (0)