Skip to content

Commit 2d95522

Browse files
committed
Add support for exceptions in non default branch warning
1 parent 742b66b commit 2d95522

File tree

2 files changed

+124
-10
lines changed

2 files changed

+124
-10
lines changed

src/config.rs

Lines changed: 102 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,10 @@ pub(crate) struct PingTeamConfig {
9090
#[derive(PartialEq, Eq, Debug, serde::Deserialize)]
9191
#[serde(deny_unknown_fields)]
9292
pub(crate) struct AssignConfig {
93-
/// If `true`, then posts a warning comment if the PR is opened against a
93+
/// If enabled, then posts a warning comment if the PR is opened against a
9494
/// different branch than the default (usually master or main).
9595
#[serde(default)]
96-
pub(crate) warn_non_default_branch: bool,
96+
pub(crate) warn_non_default_branch: WarnNonDefaultBranchConfig,
9797
/// A URL to include in the welcome message.
9898
pub(crate) contributing_url: Option<String>,
9999
/// Ad-hoc groups that can be referred to in `owners`.
@@ -117,6 +117,45 @@ impl AssignConfig {
117117
}
118118
}
119119

120+
#[derive(PartialEq, Eq, Debug, serde::Deserialize)]
121+
#[serde(deny_unknown_fields)]
122+
#[serde(untagged)]
123+
pub(crate) enum WarnNonDefaultBranchConfig {
124+
Simple(bool),
125+
Extended {
126+
enable: bool,
127+
/// List of exceptions that have a different default branch
128+
#[serde(default)]
129+
exceptions: Vec<WarnNonDefaultBranchException>,
130+
},
131+
}
132+
133+
#[derive(PartialEq, Eq, Debug, serde::Deserialize)]
134+
#[serde(deny_unknown_fields)]
135+
pub(crate) struct WarnNonDefaultBranchException {
136+
/// Substring in the title that match this exception
137+
pub(crate) title: String,
138+
/// The actual branch that should be associated with the issue
139+
pub(crate) branch: String,
140+
}
141+
142+
impl Default for WarnNonDefaultBranchConfig {
143+
fn default() -> WarnNonDefaultBranchConfig {
144+
WarnNonDefaultBranchConfig::Simple(false)
145+
}
146+
}
147+
148+
impl WarnNonDefaultBranchConfig {
149+
pub(crate) fn enabled_and_exceptions(&self) -> Option<&[WarnNonDefaultBranchException]> {
150+
match self {
151+
WarnNonDefaultBranchConfig::Simple(enable) => enable.then(|| &[] as &[_]),
152+
WarnNonDefaultBranchConfig::Extended { enable, exceptions } => {
153+
enable.then(|| exceptions.as_slice())
154+
}
155+
}
156+
}
157+
}
158+
120159
#[derive(PartialEq, Eq, Debug, serde::Deserialize)]
121160
#[serde(deny_unknown_fields)]
122161
pub(crate) struct NoMergesConfig {
@@ -501,7 +540,7 @@ mod tests {
501540
allow_unauthenticated: vec!["C-*".into()],
502541
}),
503542
assign: Some(AssignConfig {
504-
warn_non_default_branch: false,
543+
warn_non_default_branch: WarnNonDefaultBranchConfig::Simple(false),
505544
contributing_url: None,
506545
adhoc_groups: HashMap::new(),
507546
owners: HashMap::new(),
@@ -530,4 +569,64 @@ mod tests {
530569
}
531570
);
532571
}
572+
573+
#[test]
574+
fn warn_non_default_branch() {
575+
let config = r#"
576+
[assign]
577+
warn_non_default_branch.enable = true
578+
579+
[[assign.warn_non_default_branch.exceptions]]
580+
title = "[beta"
581+
branch = "beta"
582+
583+
[[assign.warn_non_default_branch.exceptions]]
584+
title = "[stable"
585+
branch = "stable"
586+
"#;
587+
let config = toml::from_str::<Config>(&config).unwrap();
588+
assert_eq!(
589+
config,
590+
Config {
591+
relabel: None,
592+
assign: Some(AssignConfig {
593+
warn_non_default_branch: WarnNonDefaultBranchConfig::Extended {
594+
enable: true,
595+
exceptions: vec![
596+
WarnNonDefaultBranchException {
597+
title: "[beta".to_string(),
598+
branch: "beta".to_string()
599+
},
600+
WarnNonDefaultBranchException {
601+
title: "[stable".to_string(),
602+
branch: "stable".to_string()
603+
},
604+
],
605+
},
606+
contributing_url: None,
607+
adhoc_groups: HashMap::new(),
608+
owners: HashMap::new(),
609+
users_on_vacation: HashSet::new(),
610+
}),
611+
note: None,
612+
ping: None,
613+
nominate: None,
614+
shortcut: None,
615+
prioritize: None,
616+
major_change: None,
617+
glacier: None,
618+
close: None,
619+
autolabel: None,
620+
notify_zulip: None,
621+
github_releases: None,
622+
review_submitted: None,
623+
review_requested: None,
624+
mentions: None,
625+
no_merges: None,
626+
validate_config: Some(ValidateConfig {}),
627+
pr_tracking: None,
628+
transfer: None,
629+
}
630+
);
631+
}
533632
}

src/handlers/assign.rs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
//! the PR modifies.
1919
2020
use crate::{
21-
config::AssignConfig,
21+
config::{AssignConfig, WarnNonDefaultBranchException},
2222
github::{self, Event, FileDiff, Issue, IssuesAction, Selection},
2323
handlers::{Context, GithubClient, IssuesEvent},
2424
interactions::EditIssueBody,
@@ -73,6 +73,11 @@ const NON_DEFAULT_BRANCH: &str =
7373
but this one is against {target}. \
7474
Please double check that you specified the right target!";
7575

76+
const NON_DEFAULT_BRANCH_EXCEPTION: &str =
77+
"Pull requests targetting the {default} branch are usually filed against the {default} \
78+
branch, but this one is against {target}. \
79+
Please double check that you specified the right target!";
80+
7681
const SUBMODULE_WARNING_MSG: &str = "These commits modify **submodules**.";
7782

7883
fn on_vacation_msg(user: &str) -> String {
@@ -179,8 +184,8 @@ pub(super) async fn handle_input(
179184

180185
// Compute some warning messages to post to new PRs.
181186
let mut warnings = Vec::new();
182-
if config.warn_non_default_branch {
183-
warnings.extend(non_default_branch(event));
187+
if let Some(exceptions) = config.warn_non_default_branch.enabled_and_exceptions() {
188+
warnings.extend(non_default_branch(exceptions, event));
184189
}
185190
warnings.extend(modifies_submodule(diff));
186191
if !warnings.is_empty() {
@@ -209,15 +214,25 @@ fn is_self_assign(assignee: &str, pr_author: &str) -> bool {
209214
assignee.to_lowercase() == pr_author.to_lowercase()
210215
}
211216

212-
/// Returns a message if the PR is opened against the non-default branch.
213-
fn non_default_branch(event: &IssuesEvent) -> Option<String> {
217+
/// Returns a message if the PR is opened against the non-default branch (or the exception branch
218+
/// if it's an exception).
219+
fn non_default_branch(
220+
exceptions: &[WarnNonDefaultBranchException],
221+
event: &IssuesEvent,
222+
) -> Option<String> {
214223
let target_branch = &event.issue.base.as_ref().unwrap().git_ref;
215-
let default_branch = &event.repository.default_branch;
224+
let (default_branch, warn_msg) = exceptions
225+
.iter()
226+
.find(|e| event.issue.title.contains(&e.title))
227+
.map_or_else(
228+
|| (&event.repository.default_branch, NON_DEFAULT_BRANCH),
229+
|e| (&e.branch, NON_DEFAULT_BRANCH_EXCEPTION),
230+
);
216231
if target_branch == default_branch {
217232
return None;
218233
}
219234
Some(
220-
NON_DEFAULT_BRANCH
235+
warn_msg
221236
.replace("{default}", default_branch)
222237
.replace("{target}", target_branch),
223238
)

0 commit comments

Comments
 (0)