Skip to content

Commit 51001ca

Browse files
committed
code to create issues
1 parent f7c61c5 commit 51001ca

File tree

5 files changed

+120
-33
lines changed

5 files changed

+120
-33
lines changed

Cargo.lock

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mdbook-goals/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ structopt = "0.3.26"
1616
walkdir = "2.5.0"
1717
rust_team_data = { git = "https://github.com/rust-lang/team" }
1818
lazy_static = "1.5.0"
19+
progress_bar = "1.0.5"

mdbook-goals/src/goal.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,14 @@ impl GoalDocument {
145145
.copied()
146146
.collect()
147147
}
148+
149+
/// True if this goal is a candidate (may yet be accepted)
150+
pub(crate) fn is_not_not_accepted(&self) -> bool {
151+
match self.metadata.status {
152+
Status::Flagship | Status::Proposed | Status::Orphaned => true,
153+
Status::NotAccepted => false,
154+
}
155+
}
148156
}
149157

150158
/// Format a set of team asks into a table, with asks separated by team and grouped by kind.

mdbook-goals/src/main.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ enum Command {
4141
Issues {
4242
path: PathBuf,
4343

44+
/// Number of milliseconds to pause between github commands
45+
/// to avoid rate limiting
46+
#[structopt(long, default_value = "500")]
47+
sleep: u64,
48+
4449
/// Without this option, no action is taken.
4550
#[structopt(long)]
4651
commit: bool,
@@ -70,8 +75,12 @@ fn main() -> anyhow::Result<()> {
7075
rfc::generate_rfc(&path)?;
7176
}
7277

73-
Some(Command::Issues { path, commit }) => {
74-
rfc::generate_issues(&opt.repository, path, *commit)?;
78+
Some(Command::Issues {
79+
path,
80+
commit,
81+
sleep,
82+
}) => {
83+
rfc::generate_issues(&opt.repository, path, *commit, *sleep)?;
7584
}
7685

7786
None => {

mdbook-goals/src/rfc.rs

Lines changed: 90 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@ use std::{
44
fmt::Display,
55
path::{Path, PathBuf},
66
process::Command,
7+
time::Duration,
78
};
89

910
use anyhow::Context;
1011
use regex::Regex;
1112
use serde::{Deserialize, Serialize};
1213

1314
use crate::{
14-
goal::{self, GoalDocument, ParsedOwners, PlanItem},
15+
goal::{self, GoalDocument, ParsedOwners, PlanItem, Status},
1516
team::{get_person_data, TeamName},
1617
};
1718

@@ -97,10 +98,17 @@ pub fn generate_rfc(path: &Path) -> anyhow::Result<()> {
9798
Ok(())
9899
}
99100

100-
pub fn generate_issues(repository: &str, path: &Path, commit: bool) -> anyhow::Result<()> {
101+
pub fn generate_issues(
102+
repository: &str,
103+
path: &Path,
104+
commit: bool,
105+
sleep: u64,
106+
) -> anyhow::Result<()> {
101107
let timeframe = validate_path(path)?;
102108

103-
let goal_documents = goal::goals_in_dir(path)?;
109+
let mut goal_documents = goal::goals_in_dir(path)?;
110+
goal_documents.retain(|gd| gd.is_not_not_accepted());
111+
104112
let teams_with_asks = teams_with_asks(&goal_documents);
105113
let mut actions = initialize_labels(repository, &teams_with_asks)?;
106114
actions.extend(initialize_issues(repository, &timeframe, &goal_documents)?);
@@ -110,16 +118,31 @@ pub fn generate_issues(repository: &str, path: &Path, commit: bool) -> anyhow::R
110118
return Ok(());
111119
}
112120

113-
eprintln!("Actions to be executed:");
114-
for action in &actions {
115-
eprintln!("* {action}");
116-
}
117-
118121
if commit {
122+
progress_bar::init_progress_bar(actions.len());
123+
progress_bar::set_progress_bar_action(
124+
"Executing",
125+
progress_bar::Color::Blue,
126+
progress_bar::Style::Bold,
127+
);
119128
for action in actions.into_iter() {
129+
progress_bar::print_progress_bar_info(
130+
"Action",
131+
&format!("{}", action),
132+
progress_bar::Color::Green,
133+
progress_bar::Style::Bold,
134+
);
120135
action.execute(repository, &timeframe)?;
136+
progress_bar::inc_progress_bar();
137+
138+
std::thread::sleep(Duration::from_millis(sleep));
121139
}
140+
progress_bar::finalize_progress_bar();
122141
} else {
142+
eprintln!("Actions to be executed:");
143+
for action in &actions {
144+
eprintln!("* {action}");
145+
}
123146
eprintln!("");
124147
eprintln!("Use `--commit` to execute the actions.");
125148
}
@@ -132,7 +155,7 @@ pub struct GithubIssue {
132155
pub title: String,
133156
pub assignees: Vec<String>,
134157
pub body: String,
135-
pub teams: BTreeSet<&'static TeamName>,
158+
pub labels: Vec<String>,
136159
}
137160

138161
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
@@ -147,6 +170,11 @@ struct GhLabel {
147170
color: String,
148171
}
149172

173+
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
174+
struct ExistingGithubIssue {
175+
title: String,
176+
}
177+
150178
fn list_labels(repository: &str) -> anyhow::Result<Vec<GhLabel>> {
151179
let output = Command::new("gh")
152180
.arg("-R")
@@ -162,6 +190,25 @@ fn list_labels(repository: &str) -> anyhow::Result<Vec<GhLabel>> {
162190
Ok(labels)
163191
}
164192

193+
fn list_issue_titles_in_milestone(
194+
repository: &str,
195+
timeframe: &str,
196+
) -> anyhow::Result<BTreeSet<String>> {
197+
let output = Command::new("gh")
198+
.arg("-R")
199+
.arg(repository)
200+
.arg("issue")
201+
.arg("list")
202+
.arg("-m")
203+
.arg(timeframe)
204+
.arg("--json")
205+
.arg("title")
206+
.output()?;
207+
208+
let existing_issues: Vec<ExistingGithubIssue> = serde_json::from_slice(&output.stdout)?;
209+
210+
Ok(existing_issues.into_iter().map(|e_i| e_i.title).collect())
211+
}
165212
/// Initializes the required `T-<team>` labels on the repository.
166213
/// Warns if the labels are found with wrong color.
167214
fn initialize_labels(
@@ -187,6 +234,11 @@ fn initialize_labels(
187234
color: "f5f1fd".to_string(),
188235
});
189236

237+
desired_labels.insert(GhLabel {
238+
name: "Flagship Goal".to_string(),
239+
color: "5319E7".to_string(),
240+
});
241+
190242
for existing_label in list_labels(repository)? {
191243
desired_labels.remove(&existing_label);
192244
}
@@ -200,18 +252,24 @@ fn initialize_labels(
200252
/// Initializes the required `T-<team>` labels on the repository.
201253
/// Warns if the labels are found with wrong color.
202254
fn initialize_issues(
203-
_repository: &str,
255+
repository: &str,
204256
timeframe: &str,
205257
goal_documents: &[GoalDocument],
206258
) -> anyhow::Result<BTreeSet<GithubAction>> {
207-
goal_documents
259+
// the set of issues we want to exist
260+
let mut desired_issues: BTreeSet<GithubIssue> = goal_documents
208261
.iter()
209-
.map(|goal_document| {
210-
Ok(GithubAction::CreateIssue {
211-
issue: issue(timeframe, goal_document)?,
212-
})
213-
})
214-
.collect()
262+
.map(|goal_document| issue(timeframe, goal_document))
263+
.collect::<anyhow::Result<_>>()?;
264+
265+
// remove any existings that already exist
266+
let existing_issues = list_issue_titles_in_milestone(repository, timeframe)?;
267+
desired_issues.retain(|i| !existing_issues.contains(&i.title));
268+
269+
Ok(desired_issues
270+
.into_iter()
271+
.map(|issue| GithubAction::CreateIssue { issue })
272+
.collect())
215273
}
216274

217275
fn issue(timeframe: &str, document: &GoalDocument) -> anyhow::Result<GithubIssue> {
@@ -222,11 +280,19 @@ fn issue(timeframe: &str, document: &GoalDocument) -> anyhow::Result<GithubIssue
222280
}
223281
}
224282

283+
let mut labels = vec!["C-tracking-issue".to_string()];
284+
if let Status::Flagship = document.metadata.status {
285+
labels.push("Flagship Goal".to_string());
286+
}
287+
for team in document.teams_with_asks() {
288+
labels.push(team.gh_label());
289+
}
290+
225291
Ok(GithubIssue {
226292
title: document.metadata.title.clone(),
227293
assignees,
228-
body: issue_text(timeframe, document)?.replace("@", "%"), // HACK to avoid pings
229-
teams: document.teams_with_asks(),
294+
body: issue_text(timeframe, document)?,
295+
labels,
230296
})
231297
}
232298

@@ -321,7 +387,7 @@ impl Display for GithubAction {
321387
write!(f, "create label `{}` with color `{}`", name, color)
322388
}
323389
GithubAction::CreateIssue { issue } => {
324-
write!(f, "create issue `{}`", issue.title)
390+
write!(f, "create issue \"{}\"", issue.title)
325391
}
326392
}
327393
}
@@ -361,7 +427,7 @@ impl GithubAction {
361427
title,
362428
assignees,
363429
body,
364-
teams,
430+
labels,
365431
},
366432
} => {
367433
let output = Command::new("gh")
@@ -374,16 +440,9 @@ impl GithubAction {
374440
.arg("-t")
375441
.arg(&title)
376442
.arg("-l")
377-
.arg(format!(
378-
"C-tracking-issue,{}",
379-
teams
380-
.iter()
381-
.map(|t| t.gh_label())
382-
.collect::<Vec<_>>()
383-
.join(",")
384-
))
385-
// .arg("-a")
386-
// .arg(assignees.join(","))
443+
.arg(labels.join(","))
444+
.arg("-a")
445+
.arg(assignees.join(","))
387446
.arg("-m")
388447
.arg(&timeframe)
389448
.output()?;

0 commit comments

Comments
 (0)