Skip to content

Commit b8d10a2

Browse files
authored
Merge pull request #1860 from Urgau/warn_default_branch-exceptions
Add support for exceptions in non default branch warning
2 parents 1300896 + 56928c7 commit b8d10a2

File tree

2 files changed

+125
-10
lines changed

2 files changed

+125
-10
lines changed

src/config.rs

+103-3
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,10 @@ pub(crate) struct PingTeamConfig {
9191
#[derive(PartialEq, Eq, Debug, serde::Deserialize)]
9292
#[serde(deny_unknown_fields)]
9393
pub(crate) struct AssignConfig {
94-
/// If `true`, then posts a warning comment if the PR is opened against a
94+
/// If enabled, then posts a warning comment if the PR is opened against a
9595
/// different branch than the default (usually master or main).
9696
#[serde(default)]
97-
pub(crate) warn_non_default_branch: bool,
97+
pub(crate) warn_non_default_branch: WarnNonDefaultBranchConfig,
9898
/// A URL to include in the welcome message.
9999
pub(crate) contributing_url: Option<String>,
100100
/// Ad-hoc groups that can be referred to in `owners`.
@@ -118,6 +118,45 @@ impl AssignConfig {
118118
}
119119
}
120120

121+
#[derive(PartialEq, Eq, Debug, serde::Deserialize)]
122+
#[serde(deny_unknown_fields)]
123+
#[serde(untagged)]
124+
pub(crate) enum WarnNonDefaultBranchConfig {
125+
Simple(bool),
126+
Extended {
127+
enable: bool,
128+
/// List of exceptions that have a different default branch
129+
#[serde(default)]
130+
exceptions: Vec<WarnNonDefaultBranchException>,
131+
},
132+
}
133+
134+
#[derive(PartialEq, Eq, Debug, serde::Deserialize)]
135+
#[serde(deny_unknown_fields)]
136+
pub(crate) struct WarnNonDefaultBranchException {
137+
/// Substring in the title that match this exception
138+
pub(crate) title: String,
139+
/// The actual branch that should be associated with the issue
140+
pub(crate) branch: String,
141+
}
142+
143+
impl Default for WarnNonDefaultBranchConfig {
144+
fn default() -> WarnNonDefaultBranchConfig {
145+
WarnNonDefaultBranchConfig::Simple(false)
146+
}
147+
}
148+
149+
impl WarnNonDefaultBranchConfig {
150+
pub(crate) fn enabled_and_exceptions(&self) -> Option<&[WarnNonDefaultBranchException]> {
151+
match self {
152+
WarnNonDefaultBranchConfig::Simple(enable) => enable.then(|| &[] as &[_]),
153+
WarnNonDefaultBranchConfig::Extended { enable, exceptions } => {
154+
enable.then(|| exceptions.as_slice())
155+
}
156+
}
157+
}
158+
}
159+
121160
#[derive(PartialEq, Eq, Debug, serde::Deserialize)]
122161
#[serde(deny_unknown_fields)]
123162
pub(crate) struct NoMergesConfig {
@@ -514,7 +553,7 @@ mod tests {
514553
allow_unauthenticated: vec!["C-*".into()],
515554
}),
516555
assign: Some(AssignConfig {
517-
warn_non_default_branch: false,
556+
warn_non_default_branch: WarnNonDefaultBranchConfig::Simple(false),
518557
contributing_url: None,
519558
adhoc_groups: HashMap::new(),
520559
owners: HashMap::new(),
@@ -544,4 +583,65 @@ mod tests {
544583
}
545584
);
546585
}
586+
587+
#[test]
588+
fn warn_non_default_branch() {
589+
let config = r#"
590+
[assign]
591+
warn_non_default_branch.enable = true
592+
593+
[[assign.warn_non_default_branch.exceptions]]
594+
title = "[beta"
595+
branch = "beta"
596+
597+
[[assign.warn_non_default_branch.exceptions]]
598+
title = "[stable"
599+
branch = "stable"
600+
"#;
601+
let config = toml::from_str::<Config>(&config).unwrap();
602+
assert_eq!(
603+
config,
604+
Config {
605+
relabel: None,
606+
assign: Some(AssignConfig {
607+
warn_non_default_branch: WarnNonDefaultBranchConfig::Extended {
608+
enable: true,
609+
exceptions: vec![
610+
WarnNonDefaultBranchException {
611+
title: "[beta".to_string(),
612+
branch: "beta".to_string()
613+
},
614+
WarnNonDefaultBranchException {
615+
title: "[stable".to_string(),
616+
branch: "stable".to_string()
617+
},
618+
],
619+
},
620+
contributing_url: None,
621+
adhoc_groups: HashMap::new(),
622+
owners: HashMap::new(),
623+
users_on_vacation: HashSet::new(),
624+
}),
625+
note: None,
626+
ping: None,
627+
nominate: None,
628+
shortcut: None,
629+
prioritize: None,
630+
major_change: None,
631+
glacier: None,
632+
close: None,
633+
autolabel: None,
634+
notify_zulip: None,
635+
github_releases: None,
636+
review_submitted: None,
637+
review_requested: None,
638+
mentions: None,
639+
no_merges: None,
640+
validate_config: Some(ValidateConfig {}),
641+
pr_tracking: None,
642+
transfer: None,
643+
merge_conflicts: None,
644+
}
645+
);
646+
}
547647
}

src/handlers/assign.rs

+22-7
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)