Skip to content

Commit dfb7c80

Browse files
authored
Merge pull request #1917 from Urgau/no_mentions
Add no GitHub mentions in commits handler
2 parents cc054e0 + 88dff54 commit dfb7c80

File tree

4 files changed

+106
-8
lines changed

4 files changed

+106
-8
lines changed

Diff for: src/config.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ pub(crate) struct Config {
4747
pub(crate) bot_pull_requests: Option<BotPullRequests>,
4848
pub(crate) rendered_link: Option<RenderedLinkConfig>,
4949
pub(crate) canonicalize_issue_links: Option<CanonicalizeIssueLinksConfig>,
50+
pub(crate) no_mentions: Option<NoMentionsConfig>,
5051
}
5152

5253
#[derive(PartialEq, Eq, Debug, serde::Deserialize)]
@@ -420,6 +421,11 @@ pub(crate) struct RenderedLinkConfig {
420421
#[serde(deny_unknown_fields)]
421422
pub(crate) struct CanonicalizeIssueLinksConfig {}
422423

424+
#[derive(PartialEq, Eq, Debug, serde::Deserialize)]
425+
#[serde(rename_all = "kebab-case")]
426+
#[serde(deny_unknown_fields)]
427+
pub(crate) struct NoMentionsConfig {}
428+
423429
fn get_cached_config(repo: &str) -> Option<Result<Arc<Config>, ConfigurationError>> {
424430
let cache = CONFIG_CACHE.read().unwrap();
425431
cache.get(repo).and_then(|(config, fetch_time)| {
@@ -545,6 +551,8 @@ mod tests {
545551
546552
[rendered-link]
547553
trigger-files = ["posts/"]
554+
555+
[no-mentions]
548556
"#;
549557
let config = toml::from_str::<Config>(&config).unwrap();
550558
let mut ping_teams = HashMap::new();
@@ -608,6 +616,7 @@ mod tests {
608616
trigger_files: vec!["posts/".to_string()]
609617
}),
610618
canonicalize_issue_links: Some(CanonicalizeIssueLinksConfig {}),
619+
no_mentions: Some(NoMentionsConfig {}),
611620
}
612621
);
613622
}
@@ -671,7 +680,8 @@ mod tests {
671680
merge_conflicts: None,
672681
bot_pull_requests: None,
673682
rendered_link: None,
674-
canonicalize_issue_links: None
683+
canonicalize_issue_links: None,
684+
no_mentions: None,
675685
}
676686
);
677687
}

Diff for: src/handlers/check_commits.rs

+16-6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::{
88
};
99

1010
mod modified_submodule;
11+
mod no_mentions;
1112
mod non_default_branch;
1213

1314
/// Key for the state in the database
@@ -41,6 +42,7 @@ pub(super) async fn handle(ctx: &Context, event: &Event, config: &Config) -> any
4142
event.issue.number
4243
)
4344
};
45+
let commits = event.issue.commits(&ctx.github).await?;
4446

4547
let mut warnings = Vec::new();
4648

@@ -58,6 +60,10 @@ pub(super) async fn handle(ctx: &Context, event: &Event, config: &Config) -> any
5860
warnings.extend(modified_submodule::modifies_submodule(diff));
5961
}
6062

63+
if let Some(no_mentions) = &config.no_mentions {
64+
warnings.extend(no_mentions::mentions_in_commits(no_mentions, &commits));
65+
}
66+
6167
handle_warnings(ctx, event, warnings).await
6268
}
6369

@@ -88,12 +94,7 @@ async fn handle_warnings(
8894
.await?;
8995
}
9096

91-
// Format the warnings for user consumption on Github
92-
let warnings: Vec<_> = warnings
93-
.iter()
94-
.map(|warning| format!("* {warning}"))
95-
.collect();
96-
let warning = format!(":warning: **Warning** :warning:\n\n{}", warnings.join("\n"));
97+
let warning = warning_from_warnings(&warnings);
9798
let comment = event.issue.post_comment(&ctx.github, &warning).await?;
9899

99100
// Save new state in the database
@@ -120,3 +121,12 @@ async fn handle_warnings(
120121

121122
Ok(())
122123
}
124+
125+
// Format the warnings for user consumption on Github
126+
fn warning_from_warnings(warnings: &[String]) -> String {
127+
let warnings: Vec<_> = warnings
128+
.iter()
129+
.map(|warning| format!("* {warning}"))
130+
.collect();
131+
format!(":warning: **Warning** :warning:\n\n{}", warnings.join("\n"))
132+
}

Diff for: src/handlers/check_commits/modified_submodule.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::github::FileDiff;
22

3-
const SUBMODULE_WARNING_MSG: &str = "These commits modify **submodules**.";
3+
const SUBMODULE_WARNING_MSG: &str = "Some commits in this PR modify **submodules**.";
44

55
/// Returns a message if the PR modifies a git submodule.
66
pub(super) fn modifies_submodule(diff: &[FileDiff]) -> Option<String> {

Diff for: src/handlers/check_commits/no_mentions.rs

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
//! Purpose: When opening a PR, or pushing new changes, check for github mentions
2+
//! in commits and notify the user of our no-mentions in commits policy.
3+
4+
use std::fmt::Write;
5+
6+
use crate::{config::NoMentionsConfig, github::GithubCommit};
7+
8+
pub(super) fn mentions_in_commits(
9+
_conf: &NoMentionsConfig,
10+
commits: &[GithubCommit],
11+
) -> Option<String> {
12+
let mut mentions_commits = Vec::new();
13+
14+
for commit in commits {
15+
if !parser::get_mentions(&commit.commit.message).is_empty() {
16+
mentions_commits.push(&*commit.sha);
17+
}
18+
}
19+
20+
if mentions_commits.is_empty() {
21+
None
22+
} else {
23+
Some(mentions_in_commits_warn(mentions_commits))
24+
}
25+
}
26+
27+
fn mentions_in_commits_warn(commits: Vec<&str>) -> String {
28+
let mut warning = format!("There are username mentions (such as `@user`) in the commit messages of the following commits.\n *Please remove the mentions to avoid spamming these users.*\n");
29+
30+
for commit in commits {
31+
let _ = writeln!(warning, " - {commit}");
32+
}
33+
34+
warning
35+
}
36+
37+
#[test]
38+
fn test_mentions_in_commits() {
39+
fn dummy_commit_from_body(sha: &str, body: &str) -> GithubCommit {
40+
use chrono::{DateTime, FixedOffset};
41+
42+
GithubCommit {
43+
sha: sha.to_string(),
44+
commit: crate::github::GithubCommitCommitField {
45+
author: crate::github::GitUser {
46+
date: DateTime::<FixedOffset>::MIN_UTC.into(),
47+
},
48+
message: body.to_string(),
49+
tree: crate::github::GitCommitTree {
50+
sha: "60ff73dfdd81aa1e6737eb3dacdfd4a141f6e14d".to_string(),
51+
},
52+
},
53+
parents: vec![],
54+
}
55+
}
56+
57+
let mut commits = vec![dummy_commit_from_body(
58+
"d1992a392617dfb10518c3e56446b6c9efae38b0",
59+
"This is simple without mentions!",
60+
)];
61+
62+
assert_eq!(mentions_in_commits(&NoMentionsConfig {}, &commits), None);
63+
64+
commits.push(dummy_commit_from_body(
65+
"d7daa17bc97df9377640b0d33cbd0bbeed703c3a",
66+
"This is a body with a @mention!",
67+
));
68+
69+
assert_eq!(
70+
mentions_in_commits(&NoMentionsConfig {}, &commits),
71+
Some(
72+
r#"There are username mentions (such as `@user`) in the commit messages of the following commits.
73+
*Please remove the mentions to avoid spamming these users.*
74+
- d7daa17bc97df9377640b0d33cbd0bbeed703c3a
75+
"#.to_string()
76+
)
77+
);
78+
}

0 commit comments

Comments
 (0)