diff --git a/src/config.rs b/src/config.rs index ed418eae7..cb43f769b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -419,6 +419,9 @@ pub(crate) struct MajorChangeConfig { pub(crate) zulip_stream: u64, /// Extra text in the opening major change. pub(crate) open_extra_text: Option, + /// Template for a tracking issue to be created when the major change is accepted + #[serde(rename = "tracking-issue-template")] + pub(crate) tracking_issue_template: Option, } impl MajorChangeConfig { @@ -433,6 +436,20 @@ impl MajorChangeConfig { } } +#[derive(PartialEq, Eq, Debug, serde::Deserialize)] +#[serde(rename_all = "kebab-case")] +#[serde(deny_unknown_fields)] +pub(crate) struct MajorChangeTrackingIssueTemplateConfig { + /// Template for the title + pub(crate) title: String, + /// Repository where to create the tracking issue (otherwise the current repository) + pub(crate) repository: Option, + /// List of labels to add to the issue + pub(crate) labels: Vec, + /// Template of the body + pub(crate) body: String, +} + #[derive(PartialEq, Eq, Debug, serde::Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct CloseConfig {} @@ -1030,4 +1047,50 @@ mod tests { }) )); } + + #[test] + fn major_change() { + let config = r#" + [major-change] + enabling_label = "major-change" + meeting_label = "to-announce" + second_label = "final-comment-period" + concerns_label = "has-concerns" + accept_label = "major-change-accepted" + waiting_period = 1 + auto_closing = true + zulip_stream = 224082 + zulip_ping = "Urgau" + + [major-change.tracking-issue-template] + repository = "triagebot" + title = "Tracking issue for MCP#${mcp_number}" + body = """ +Multi text body with ${mcp_issue} and ${mcp_title} +""" + labels = ["C-tracking-issue", "T-compiler"] + "#; + let config = toml::from_str::(&config).unwrap(); + assert_eq!( + config.major_change, + Some(MajorChangeConfig { + zulip_ping: "Urgau".to_string(), + enabling_label: "major-change".to_string(), + second_label: "final-comment-period".to_string(), + accept_label: "major-change-accepted".to_string(), + meeting_label: "to-announce".to_string(), + concerns_label: Some("has-concerns".to_string()), + waiting_period: 1, + auto_closing: true, + zulip_stream: 224082, + open_extra_text: None, + tracking_issue_template: Some(MajorChangeTrackingIssueTemplateConfig { + title: "Tracking issue for MCP#${mcp_number}".to_string(), + repository: Some("triagebot".to_string()), + body: "Multi text body with ${mcp_issue} and ${mcp_title}\n".to_string(), + labels: vec!["C-tracking-issue".to_string(), "T-compiler".to_string()], + }) + }) + ); + } } diff --git a/src/handlers/major_change.rs b/src/handlers/major_change.rs index aef7ae21c..d42f9f73b 100644 --- a/src/handlers/major_change.rs +++ b/src/handlers/major_change.rs @@ -519,7 +519,7 @@ impl Job for MajorChangeAcceptenceJob { let now = Utc::now(); - match process_seconded(ctx, &major_change, now).await { + match try_accept_mcp(ctx, &major_change, now).await { Ok(()) => { tracing::info!( "{}: major change ({:?}) as been accepted", @@ -549,7 +549,7 @@ impl Job for MajorChangeAcceptenceJob { } } -async fn process_seconded( +async fn try_accept_mcp( ctx: &super::Context, major_change: &MajorChangeSeconded, now: DateTime, @@ -581,6 +581,11 @@ async fn process_seconded( .await .context("unable to get the associated issue")?; + let (org, repo) = major_change + .repo + .split_once('/') + .context("unable to split org/repo")?; + { // Static checks against the timeline to block the acceptance if the state changed between // the second and now (like concerns added, issue closed, ...). @@ -588,10 +593,6 @@ async fn process_seconded( // Note that checking the timeline is important as a concern could have been added and // resolved by the time we run, missing that this job should not run. - let (org, repo) = major_change - .repo - .split_once('/') - .context("unable to split org/repo")?; let timeline = ctx .octocrab .issues(org, repo) @@ -665,13 +666,58 @@ async fn process_seconded( } if !issue.labels.iter().any(|l| l.name == config.accept_label) { - // Only post the comment if the accept_label isn't set yet, we may be in a retry + // Only create the tracking issue and post the comment if the accept_label isn't set yet, we may be in a retry. + + let tracking_issue_text = + if let Some(tracking_issue_template) = &config.tracking_issue_template { + let issue_repo = crate::github::IssueRepository { + organization: org.to_string(), + repository: tracking_issue_template + .repository + .as_deref() + .unwrap_or(repo) + .to_string(), + }; + + let fill_out = |input: &str| { + input + .replace("${mcp_number}", &issue.number.to_string()) + .replace("${mcp_title}", &issue.title) + .replace("${mcp_author}", &issue.user.login) + }; + + let title = fill_out(&tracking_issue_template.title); + let body = fill_out(&tracking_issue_template.body); + + let tracking_issue = ctx + .github + .new_issue( + &issue_repo, + &title, + &body, + tracking_issue_template.labels.clone(), + ) + .await + .context("unable to create MCP tracking issue") + .with_context(|| format!("title: {title}")) + .with_context(|| format!("body: {body}"))?; + + format!( + r" +Progress of this major change will be tracked in the tracking issue at {}#{}. +", + &issue_repo, tracking_issue.number + ) + } else { + String::new() + }; + issue .post_comment( &ctx.github, &format!( r"The final comment period is now complete, this major change is now **accepted**. - +{tracking_issue_text} As the automated representative, I would like to thank the author for their work and everyone else who contributed to this major change proposal. *If you think this major change shouldn't have been accepted, feel free to remove the `{}` label and reopen this issue.*",