Skip to content

Commit 640eaee

Browse files
Add support for adding labels based on files changed
```toml [autolabel."A-rustdoc"] preexisting: trigger_labels = [ ... ] exclude_labels = [ ... ] new: trigger_files = [ "src/librustdoc", "src/tools/rustdoc", "src/rustdoc-json-types", ] ``` Co-authored-by: Joshua Nelson <[email protected]>
1 parent 76216e5 commit 640eaee

File tree

6 files changed

+97
-5
lines changed

6 files changed

+97
-5
lines changed

src/config.rs

+2
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ pub(crate) struct AutolabelLabelConfig {
117117
pub(crate) trigger_labels: Vec<String>,
118118
#[serde(default)]
119119
pub(crate) exclude_labels: Vec<String>,
120+
#[serde(default)]
121+
pub(crate) trigger_files: Vec<String>,
120122
}
121123

122124
#[derive(PartialEq, Eq, Debug, serde::Deserialize)]

src/github.rs

+46
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,52 @@ pub struct IssuesEvent {
753753
pub repository: Repository,
754754
/// Some if action is IssuesAction::Labeled, for example
755755
pub label: Option<Label>,
756+
757+
// These fields are the sha fields before/after a synchronize operation,
758+
// used to compute the diff between these two commits.
759+
#[serde(default)]
760+
before: Option<String>,
761+
#[serde(default)]
762+
after: Option<String>,
763+
764+
#[serde(default)]
765+
base: Option<CommitBase>,
766+
#[serde(default)]
767+
head: Option<CommitBase>,
768+
}
769+
770+
#[derive(Default, Clone, Debug, serde::Deserialize)]
771+
pub struct CommitBase {
772+
sha: String,
773+
}
774+
775+
impl IssuesEvent {
776+
/// Returns the diff in this event, for Open and Synchronize events for now.
777+
pub async fn diff_between(&self, client: &GithubClient) -> anyhow::Result<Option<String>> {
778+
let (before, after) = if self.action == IssuesAction::Synchronize {
779+
(
780+
self.before.clone().unwrap_or_default(),
781+
self.after.clone().unwrap_or_default(),
782+
)
783+
} else if self.action == IssuesAction::Opened {
784+
(
785+
self.base.clone().unwrap_or_default().sha,
786+
self.head.clone().unwrap_or_default().sha,
787+
)
788+
} else {
789+
return Ok(None);
790+
};
791+
792+
let mut req = client.get(&format!(
793+
"{}/compare/{}...{}",
794+
self.issue.repository().url(),
795+
before,
796+
after
797+
));
798+
req = req.header("Accept", "application/vnd.github.v3.diff");
799+
let diff = client.send_req(req).await?;
800+
Ok(Some(String::from(String::from_utf8_lossy(&diff))))
801+
}
756802
}
757803

758804
#[derive(Debug, serde::Deserialize)]

src/handlers.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ macro_rules! issue_handlers {
115115
errors: &mut Vec<HandlerError>,
116116
) {
117117
$(
118-
match $name::parse_input(ctx, event, config.$name.as_ref()) {
118+
match $name::parse_input(ctx, event, config.$name.as_ref()).await {
119119
Err(err) => errors.push(HandlerError::Message(err)),
120120
Ok(Some(input)) => {
121121
if let Some(config) = &config.$name {

src/handlers/autolabel.rs

+46-2
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,55 @@ pub(super) struct AutolabelInput {
77
labels: Vec<Label>,
88
}
99

10-
pub(super) fn parse_input(
11-
_ctx: &Context,
10+
pub(super) async fn parse_input(
11+
ctx: &Context,
1212
event: &IssuesEvent,
1313
config: Option<&AutolabelConfig>,
1414
) -> Result<Option<AutolabelInput>, String> {
15+
if let Some(diff) = event
16+
.diff_between(&ctx.github)
17+
.await
18+
.map_err(|e| {
19+
log::error!("failed to fetch diff: {:?}", e);
20+
})
21+
.unwrap_or_default()
22+
{
23+
if let Some(config) = config {
24+
let mut files = Vec::new();
25+
for line in diff.lines() {
26+
// mostly copied from highfive
27+
if line.starts_with("diff --git ") {
28+
let parts = line[line.find(" b/").unwrap() + " b/".len()..].split("/");
29+
let path = parts.collect::<Vec<_>>().join("/");
30+
if !path.is_empty() {
31+
files.push(path);
32+
}
33+
}
34+
}
35+
let mut autolabels = Vec::new();
36+
for trigger_file in files {
37+
if trigger_file.is_empty() {
38+
// TODO: when would this be true?
39+
continue;
40+
}
41+
for (label, cfg) in config.labels.iter() {
42+
if cfg
43+
.trigger_files
44+
.iter()
45+
.any(|f| trigger_file.starts_with(f))
46+
{
47+
autolabels.push(Label {
48+
name: label.to_owned(),
49+
});
50+
}
51+
}
52+
if !autolabels.is_empty() {
53+
return Ok(Some(AutolabelInput { labels: autolabels }));
54+
}
55+
}
56+
}
57+
}
58+
1559
if event.action == IssuesAction::Labeled {
1660
if let Some(config) = config {
1761
let mut autolabels = Vec::new();

src/handlers/major_change.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub enum Invocation {
1414
Rename { prev_issue: ZulipGitHubReference },
1515
}
1616

17-
pub(super) fn parse_input(
17+
pub(super) async fn parse_input(
1818
_ctx: &Context,
1919
event: &IssuesEvent,
2020
_config: Option<&MajorChangeConfig>,

src/handlers/notify_zulip.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub(super) enum NotificationType {
2020
Reopened,
2121
}
2222

23-
pub(super) fn parse_input(
23+
pub(super) async fn parse_input(
2424
_ctx: &Context,
2525
event: &IssuesEvent,
2626
config: Option<&NotifyZulipConfig>,

0 commit comments

Comments
 (0)