Skip to content

Commit 943b9d1

Browse files
committed
Merge branch 'master' into accept-backports-from-zulip
2 parents 93156bd + c6b8549 commit 943b9d1

23 files changed

+245
-367
lines changed

parser/src/command/relabel.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ fn delta_empty() {
102102
}
103103

104104
impl RelabelCommand {
105-
/// Parse and validate command tokens
106105
pub fn parse<'a>(input: &mut Tokenizer<'a>) -> Result<Option<Self>, Error<'a>> {
107106
let mut toks = input.clone();
108107

src/agenda.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use axum::response::Html;
22

33
use crate::actions::{Action, Query, QueryKind, QueryMap, Step};
4+
use crate::errors::AppError;
45
use crate::github;
5-
use crate::utils::AppError;
66
use std::sync::Arc;
77

88
pub async fn lang_http() -> axum::response::Result<Html<String>, AppError> {

src/bors.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::sync::Arc;
22

33
use axum::{Json, extract::State};
44

5-
use crate::{db, handlers::Context, utils::AppError};
5+
use crate::{db, errors::AppError, handlers::Context};
66

77
pub async fn bors_commit_list(
88
State(ctx): State<Arc<Context>>,

src/config.rs

Lines changed: 3 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use crate::changelogs::ChangelogFormat;
22
use crate::github::{GithubClient, Repository};
3-
use parser::command::relabel::{Label, LabelDelta, RelabelCommand};
43
use std::collections::{HashMap, HashSet};
54
use std::fmt;
65
use std::sync::{Arc, LazyLock, RwLock};
@@ -251,64 +250,10 @@ pub(crate) struct MentionsEntryConfig {
251250

252251
#[derive(PartialEq, Eq, Debug, serde::Deserialize)]
253252
#[serde(rename_all = "kebab-case")]
253+
#[serde(deny_unknown_fields)]
254254
pub(crate) struct RelabelConfig {
255255
#[serde(default)]
256256
pub(crate) allow_unauthenticated: Vec<String>,
257-
// alias identifier -> labels
258-
#[serde(flatten)]
259-
pub(crate) aliases: HashMap<String, RelabelAliasConfig>,
260-
}
261-
262-
impl RelabelConfig {
263-
pub(crate) fn retrieve_command_from_alias(&self, input: RelabelCommand) -> RelabelCommand {
264-
let mut deltas = vec![];
265-
if !self.aliases.is_empty() {
266-
// parse all tokens: if one matches an alias, extract the labels
267-
// else, it will assumed to be a valid label
268-
for tk in input.0.into_iter() {
269-
let name = tk.label() as &str;
270-
if let Some(alias) = self.aliases.get(name) {
271-
let cmd = alias.to_command(matches!(tk, LabelDelta::Remove(_)));
272-
deltas.extend(cmd.0);
273-
} else {
274-
deltas.push(tk);
275-
}
276-
}
277-
}
278-
RelabelCommand(deltas)
279-
}
280-
}
281-
282-
#[derive(Default, PartialEq, Eq, Debug, serde::Deserialize)]
283-
#[serde(rename_all = "kebab-case")]
284-
#[serde(deny_unknown_fields)]
285-
pub(crate) struct RelabelAliasConfig {
286-
/// Labels to be added
287-
pub(crate) add_labels: Vec<String>,
288-
/// Labels to be removed
289-
pub(crate) rem_labels: Vec<String>,
290-
}
291-
292-
impl RelabelAliasConfig {
293-
/// Translate a RelabelAliasConfig into a RelabelCommand for GitHub consumption
294-
fn to_command(&self, inverted: bool) -> RelabelCommand {
295-
let mut deltas = Vec::new();
296-
let mut add_labels = &self.add_labels;
297-
let mut rem_labels = &self.rem_labels;
298-
299-
// if the polarity of the alias is inverted, swap labels before parsing the command
300-
if inverted {
301-
std::mem::swap(&mut add_labels, &mut rem_labels);
302-
}
303-
304-
for l in add_labels.iter() {
305-
deltas.push(LabelDelta::Add(Label(l.into())));
306-
}
307-
for l in rem_labels.iter() {
308-
deltas.push(LabelDelta::Remove(Label(l.into())));
309-
}
310-
RelabelCommand(deltas)
311-
}
312257
}
313258

314259
#[derive(PartialEq, Eq, Debug, serde::Deserialize)]
@@ -816,11 +761,11 @@ mod tests {
816761
817762
[mentions."src/"]
818763
cc = ["@someone"]
819-
764+
820765
[mentions."target/"]
821766
message = "This is a message."
822767
cc = ["@someone"]
823-
768+
824769
[mentions."#[rustc_attr]"]
825770
type = "content"
826771
message = "This is a message."
@@ -890,7 +835,6 @@ mod tests {
890835
Config {
891836
relabel: Some(RelabelConfig {
892837
allow_unauthenticated: vec!["C-*".into()],
893-
aliases: HashMap::new()
894838
}),
895839
assign: Some(AssignConfig {
896840
warn_non_default_branch: WarnNonDefaultBranchConfig::Simple(false),
@@ -1089,76 +1033,6 @@ mod tests {
10891033
);
10901034
}
10911035

1092-
#[test]
1093-
fn relabel_alias_config() {
1094-
let config = r#"
1095-
[relabel.to-stable]
1096-
add-labels = ["regression-from-stable-to-stable"]
1097-
rem-labels = ["regression-from-stable-to-beta", "regression-from-stable-to-nightly"]
1098-
"#;
1099-
let config = toml::from_str::<Config>(&config).unwrap();
1100-
1101-
let mut relabel_configs = HashMap::new();
1102-
relabel_configs.insert(
1103-
"to-stable".into(),
1104-
RelabelAliasConfig {
1105-
add_labels: vec!["regression-from-stable-to-stable".to_string()],
1106-
rem_labels: vec![
1107-
"regression-from-stable-to-beta".to_string(),
1108-
"regression-from-stable-to-nightly".to_string(),
1109-
],
1110-
},
1111-
);
1112-
1113-
let expected_cfg = RelabelConfig {
1114-
allow_unauthenticated: vec![],
1115-
aliases: relabel_configs,
1116-
};
1117-
1118-
assert_eq!(config.relabel, Some(expected_cfg));
1119-
}
1120-
1121-
#[test]
1122-
fn relabel_alias() {
1123-
// [relabel.my-alias]
1124-
// add-labels = ["Alpha"]
1125-
// rem-labels = ["Bravo", "Charlie"]
1126-
let relabel_cfg = RelabelConfig {
1127-
allow_unauthenticated: vec![],
1128-
aliases: HashMap::from([(
1129-
"my-alias".to_string(),
1130-
RelabelAliasConfig {
1131-
add_labels: vec!["Alpha".to_string()],
1132-
rem_labels: vec!["Bravo".to_string(), "Charlie".to_string()],
1133-
},
1134-
)]),
1135-
};
1136-
1137-
// @triagebot label my-alias
1138-
let deltas = vec![LabelDelta::Add(Label("my-alias".into()))];
1139-
let new_input = relabel_cfg.retrieve_command_from_alias(RelabelCommand(deltas));
1140-
assert_eq!(
1141-
new_input,
1142-
RelabelCommand(vec![
1143-
LabelDelta::Add(Label("Alpha".into())),
1144-
LabelDelta::Remove(Label("Bravo".into())),
1145-
LabelDelta::Remove(Label("Charlie".into())),
1146-
])
1147-
);
1148-
1149-
// @triagebot label -my-alias
1150-
let deltas = vec![LabelDelta::Remove(Label("my-alias".into()))];
1151-
let new_input = relabel_cfg.retrieve_command_from_alias(RelabelCommand(deltas));
1152-
assert_eq!(
1153-
new_input,
1154-
RelabelCommand(vec![
1155-
LabelDelta::Add(Label("Bravo".into())),
1156-
LabelDelta::Add(Label("Charlie".into())),
1157-
LabelDelta::Remove(Label("Alpha".into())),
1158-
])
1159-
);
1160-
}
1161-
11621036
#[test]
11631037
fn issue_links_uncanonicalized() {
11641038
let config = r#"
@@ -1219,36 +1093,4 @@ Multi text body with ${mcp_issue} and ${mcp_title}
12191093
})
12201094
);
12211095
}
1222-
1223-
#[test]
1224-
fn relabel_new_config() {
1225-
let config = r#"
1226-
[relabel]
1227-
allow-unauthenticated = ["ABCD-*"]
1228-
1229-
[relabel.to-stable]
1230-
add-labels = ["regression-from-stable-to-stable"]
1231-
rem-labels = ["regression-from-stable-to-beta", "regression-from-stable-to-nightly"]
1232-
"#;
1233-
let config = toml::from_str::<Config>(&config).unwrap();
1234-
1235-
let mut relabel_configs = HashMap::new();
1236-
relabel_configs.insert(
1237-
"to-stable".into(),
1238-
RelabelAliasConfig {
1239-
add_labels: vec!["regression-from-stable-to-stable".to_string()],
1240-
rem_labels: vec![
1241-
"regression-from-stable-to-beta".to_string(),
1242-
"regression-from-stable-to-nightly".to_string(),
1243-
],
1244-
},
1245-
);
1246-
1247-
let expected_cfg = RelabelConfig {
1248-
allow_unauthenticated: vec!["ABCD-*".to_string()],
1249-
aliases: relabel_configs,
1250-
};
1251-
1252-
assert_eq!(config.relabel, Some(expected_cfg));
1253-
}
12541096
}

src/errors.rs

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
//! Errors handling
2+
3+
use std::fmt;
4+
5+
use crate::interactions::REPORT_TO;
6+
7+
use axum::{
8+
http::StatusCode,
9+
response::{IntoResponse, Response},
10+
};
11+
12+
/// Represent a user error.
13+
///
14+
/// The message will be shown to the user via comment posted by this bot.
15+
#[derive(Debug)]
16+
pub enum UserError {
17+
/// Simple message
18+
Message(String),
19+
/// Unknown labels
20+
UnknownLabels { labels: Vec<String> },
21+
/// Invalid assignee
22+
InvalidAssignee,
23+
}
24+
25+
impl std::error::Error for UserError {}
26+
27+
// NOTE: This is used to post the Github comment; make sure it's valid markdown.
28+
impl fmt::Display for UserError {
29+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
30+
match self {
31+
UserError::Message(msg) => f.write_str(msg),
32+
UserError::UnknownLabels { labels } => {
33+
write!(f, "Unknown labels: {}", labels.join(", "))
34+
}
35+
UserError::InvalidAssignee => write!(f, "invalid assignee"),
36+
}
37+
}
38+
}
39+
40+
/// Creates a [`UserError`] with message.
41+
///
42+
/// Should be used when an handler is in error due to the user action's (not a PR,
43+
/// not a issue, not authorized, ...).
44+
///
45+
/// Should be used like this `return user_error!("My error message.");`.
46+
macro_rules! user_error {
47+
($err:expr $(,)?) => {
48+
anyhow::Result::Err(anyhow::anyhow!(crate::errors::UserError::Message(
49+
$err.into()
50+
)))
51+
};
52+
}
53+
54+
// export the macro
55+
pub(crate) use user_error;
56+
57+
/// Represent a application error.
58+
///
59+
/// Useful for returning a error via the API
60+
pub struct AppError(anyhow::Error);
61+
62+
impl IntoResponse for AppError {
63+
fn into_response(self) -> Response {
64+
tracing::error!("{:?}", &self.0);
65+
(
66+
StatusCode::INTERNAL_SERVER_ERROR,
67+
format!("Something went wrong: {}\n\n{REPORT_TO}", self.0),
68+
)
69+
.into_response()
70+
}
71+
}
72+
73+
impl<E> From<E> for AppError
74+
where
75+
E: Into<anyhow::Error>,
76+
{
77+
fn from(err: E) -> Self {
78+
AppError(err.into())
79+
}
80+
}
81+
82+
/// Represent an error when trying to assign someone
83+
#[derive(Debug)]
84+
pub enum AssignmentError {
85+
InvalidAssignee,
86+
Other(anyhow::Error),
87+
}
88+
89+
// NOTE: This is used to post the Github comment; make sure it's valid markdown.
90+
impl fmt::Display for AssignmentError {
91+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
92+
match self {
93+
AssignmentError::InvalidAssignee => write!(f, "invalid assignee"),
94+
AssignmentError::Other(err) => write!(f, "{err}"),
95+
}
96+
}
97+
}
98+
99+
impl From<AssignmentError> for anyhow::Error {
100+
fn from(a: AssignmentError) -> Self {
101+
match a {
102+
AssignmentError::InvalidAssignee => UserError::InvalidAssignee.into(),
103+
AssignmentError::Other(err) => err.context("assignment error"),
104+
}
105+
}
106+
}
107+
108+
#[cfg(test)]
109+
mod tests {
110+
use super::*;
111+
112+
#[test]
113+
fn display_labels() {
114+
let x = UserError::UnknownLabels {
115+
labels: vec!["A-bootstrap".into(), "xxx".into()],
116+
};
117+
assert_eq!(x.to_string(), "Unknown labels: A-bootstrap, xxx");
118+
}
119+
}

src/gh_changes_since.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,7 @@ use axum::{
77
};
88
use hyper::StatusCode;
99

10-
use crate::{
11-
github,
12-
handlers::Context,
13-
utils::{AppError, is_repo_autorized},
14-
};
10+
use crate::{errors::AppError, github, handlers::Context, utils::is_repo_autorized};
1511

1612
/// Redirects to either `/gh-range-diff` (when the base changed) or to GitHub's compare
1713
/// page (when the base is the same).

src/gh_range_diff.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use unicode_segmentation::UnicodeSegmentation;
2323

2424
use crate::github::GithubCompare;
2525
use crate::utils::is_repo_autorized;
26-
use crate::{github, handlers::Context, utils::AppError};
26+
use crate::{errors::AppError, github, handlers::Context};
2727

2828
static MARKER_RE: LazyLock<Regex> =
2929
LazyLock::new(|| Regex::new(r"@@ -[\d]+,[\d]+ [+][\d]+,[\d]+ @@").unwrap());

src/gha_logs.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
use crate::errors::AppError;
12
use crate::github::{self, WorkflowRunJob};
23
use crate::handlers::Context;
34
use crate::interactions::REPORT_TO;
4-
use crate::utils::{AppError, is_repo_autorized};
5+
use crate::utils::is_repo_autorized;
56
use anyhow::Context as _;
67
use axum::extract::{Path, State};
78
use axum::http::HeaderValue;

0 commit comments

Comments
 (0)