Skip to content

Commit fba3e53

Browse files
committed
load data properly for the edition
1 parent 2a7491b commit fba3e53

File tree

6 files changed

+242
-90
lines changed

6 files changed

+242
-90
lines changed

mdbook-goals/src/gh/issues.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,47 @@ impl std::fmt::Display for ExistingIssueState {
7777
}
7878
}
7979

80+
pub struct CountIssues {
81+
pub open: u32,
82+
pub closed: u32,
83+
}
84+
85+
pub fn count_issues_matching_search(
86+
repository: &Repository,
87+
search: &str,
88+
) -> anyhow::Result<CountIssues> {
89+
#[derive(Deserialize)]
90+
struct JustState {
91+
state: ExistingIssueState,
92+
}
93+
94+
let output = Command::new("gh")
95+
.arg("-R")
96+
.arg(&repository.to_string())
97+
.arg("issue")
98+
.arg("list")
99+
.arg("-S")
100+
.arg(search)
101+
.arg("-s")
102+
.arg("all")
103+
.arg("--json")
104+
.arg("state")
105+
.output()?;
106+
107+
let existing_issues: Vec<JustState> = serde_json::from_slice(&output.stdout)?;
108+
109+
let mut count_issues = CountIssues { open: 0, closed: 0 };
110+
111+
for issue in &existing_issues {
112+
match issue.state {
113+
ExistingIssueState::Open => count_issues.open += 1,
114+
ExistingIssueState::Closed => count_issues.closed += 1,
115+
}
116+
}
117+
118+
Ok(count_issues)
119+
}
120+
80121
pub fn list_issue_titles_in_milestone(
81122
repository: &Repository,
82123
timeframe: &str,

mdbook-goals/src/goal.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ pub fn format_goal_table(goals: &[&GoalDocument]) -> anyhow::Result<String> {
258258

259259
let progress_bar = match &goal.metadata.tracking_issue {
260260
Some(issue_id @ IssueId { repository: Repository { org, repo }, number }) => format!(
261-
"<a href='{url}' alt='Tracking issue'><progress id='{milestone}:{org}:{repo}:{number}' value='0' max='100'></progress></a>",
261+
"<a href='{url}' alt='Tracking issue'><div class='tracking-issue-progress' id='{milestone}:{org}:{repo}:{number}'></div></a>",
262262
url = issue_id.url(),
263263
),
264264
None => format!("(no tracking issue)"),

mdbook-goals/src/json.rs

Lines changed: 64 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@
66
//! to the types in `gh` and so forth but because they represent
77
//! a versioned API, we copy them over here to insulate them from incidental changes.
88
9-
use std::path::PathBuf;
9+
use std::{path::PathBuf, str::FromStr};
1010

1111
use serde::Serialize;
1212

1313
use crate::{
1414
gh::{
1515
issue_id::Repository,
1616
issues::{
17-
list_issue_titles_in_milestone, ExistingGithubComment, ExistingGithubIssue,
18-
ExistingIssueState,
17+
count_issues_matching_search, list_issue_titles_in_milestone, CountIssues,
18+
ExistingGithubComment, ExistingGithubIssue, ExistingIssueState,
1919
},
2020
},
2121
re,
@@ -32,13 +32,17 @@ pub(super) fn generate_json(
3232
issues: issues
3333
.into_iter()
3434
.map(|(title, issue)| {
35-
let (total_checkboxes, checked_checkboxes) = checkboxes(&issue);
35+
let progress = match checkboxes(&issue) {
36+
Ok(pair) => pair,
37+
Err(e) => Progress::Error {
38+
message: e.to_string(),
39+
},
40+
};
3641
TrackingIssue {
3742
number: issue.number,
3843
title,
3944
flagship: is_flagship(&issue),
40-
total_checkboxes,
41-
checked_checkboxes,
45+
progress,
4246
assignees: issue.assignees.into_iter().collect(),
4347
updates: updates(issue.comments),
4448
state: issue.state,
@@ -80,11 +84,8 @@ struct TrackingIssue {
8084
/// True if this is a flagship goal
8185
flagship: bool,
8286

83-
/// Total checkboxes appearing in the body (i.e., `* [ ]` or `* [x]`)
84-
total_checkboxes: u32,
85-
86-
/// Checked checkboxes appearing in the body (i.e., `* [x]`)
87-
checked_checkboxes: u32,
87+
/// State of progress
88+
progress: Progress,
8889

8990
/// Set of assigned people
9091
assignees: Vec<String>,
@@ -96,6 +97,23 @@ struct TrackingIssue {
9697
state: ExistingIssueState,
9798
}
9899

100+
#[derive(Serialize)]
101+
enum Progress {
102+
/// We could not find any checkboxes or other deatils on the tracking issue.
103+
/// So all we have is "open" or "closed".
104+
Binary,
105+
106+
/// We found checkboxes or issue listing.
107+
Tracked {
108+
completed: u32,
109+
total: u32,
110+
},
111+
112+
Error {
113+
message: String,
114+
},
115+
}
116+
99117
#[derive(Serialize)]
100118
struct TrackingIssueUpdate {
101119
pub author: String,
@@ -105,21 +123,49 @@ struct TrackingIssueUpdate {
105123
pub url: String,
106124
}
107125

108-
fn checkboxes(issue: &ExistingGithubIssue) -> (u32, u32) {
109-
let mut total = 0;
110-
let mut checked = 0;
126+
/// Identify how many sub-items have been completed.
127+
/// These can be encoded in two different ways:
128+
///
129+
/// * Option A, the most common, is to have checkboxes in the issue. We just count the number that are checked.
130+
/// * Option B is to include a metadata line called "Tracked issues" that lists a search query. We count the number of open vs closed issues in that query.
131+
///
132+
/// Returns a tuple (completed, total) with the number of completed items and the total number of items.
133+
fn checkboxes(issue: &ExistingGithubIssue) -> anyhow::Result<Progress> {
134+
let mut checkboxes = None;
135+
let mut issues = None;
111136

112137
for line in issue.body.lines() {
113-
if re::CHECKBOX.is_match(line) {
114-
total += 1;
138+
// Does this match TRACKED_ISSUES?
139+
if let Some(c) = re::TRACKED_ISSUES_QUERY.captures(line) {
140+
let repo = Repository::from_str(&c[1])?;
141+
let query = &c[2];
142+
143+
if issues.is_some() {
144+
anyhow::bail!("found multiple search queries for Tracked Issues");
145+
}
146+
147+
let CountIssues { open, closed } = count_issues_matching_search(&repo, query)?;
148+
issues = Some((closed, open + closed));
115149
}
116150

151+
let (checked, total) = checkboxes.unwrap_or((0, 0));
152+
117153
if re::CHECKED_CHECKBOX.is_match(line) {
118-
checked += 1;
154+
checkboxes = Some((checked + 1, total + 1));
155+
} else if re::CHECKBOX.is_match(line) {
156+
checkboxes = Some((checked, total + 1));
119157
}
120158
}
121159

122-
(total, checked)
160+
eprintln!("#{}: {checkboxes:?}, {issues:?}", issue.number);
161+
162+
match (checkboxes, issues) {
163+
(Some((completed, total)), None) | (None, Some((completed, total))) => {
164+
Ok(Progress::Tracked { completed, total })
165+
}
166+
(None, None) => Ok(Progress::Binary),
167+
(Some(_), Some(_)) => anyhow::bail!("found both Tracked Issues and checkboxes"),
168+
}
123169
}
124170

125171
fn is_flagship(issue: &ExistingGithubIssue) -> bool {

mdbook-goals/src/re.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,8 @@ lazy_static! {
3232
lazy_static! {
3333
pub static ref CHECKED_CHECKBOX: Regex = Regex::new(r"\s*[-*] \[x\] ").unwrap();
3434
}
35+
36+
lazy_static! {
37+
pub static ref TRACKED_ISSUES_QUERY: Regex =
38+
Regex::new(r"^\| *Tracked +issues *\| *\[([^ ]*) ([^]]*)\]\(.*\) *\| *$").unwrap();
39+
}

src/how_to/report_status.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@ Every accepted project goal has an associated tracking issue.
44

55
Owners are expected to provide regular status updates in the form of a comment indicating how things are going.
66

7+
## Documenting your plan and your progress
8+
9+
To help users
10+
11+
### Checkboxes
12+
13+
The deafult
14+
15+
### Search queries
16+
717
## Status updates are reported out
818

919
The status updates from the tracking issues are used to author a blog post for Inside Rust on a monthly basis.

0 commit comments

Comments
 (0)