an agent gets one todo when its pr starts conflicting with the target branch
This commit is contained in:
parent
32155f70aa
commit
11eb7dac9c
1 changed files with 963 additions and 21 deletions
|
|
@ -13,6 +13,8 @@ use std::collections::BTreeSet;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value as Json;
|
||||
|
||||
use swarm_wire::forge_events::MERGEABILITY_EVENT;
|
||||
|
||||
use crate::flow::{Fields, Value};
|
||||
|
||||
/// The parts of an `issues` or `pull_request` family delivery the router
|
||||
|
|
@ -165,6 +167,41 @@ pub struct Snapshot {
|
|||
/// and tells nobody anything.
|
||||
#[serde(default)]
|
||||
pub head: Option<String>,
|
||||
/// Whether the last mergeability event for this PR found it conflicting
|
||||
/// with its target branch, or `None` before the first.
|
||||
#[serde(default)]
|
||||
pub conflicting: Option<bool>,
|
||||
}
|
||||
|
||||
/// Whether a mergeability event moves the PR into or out of conflict: a
|
||||
/// `conflicting` finding for a PR not already conflicting, or a `mergeable`
|
||||
/// one for a PR that was.
|
||||
fn mergeability_changed(event_type: &str, action: &str, snapshot: &Snapshot) -> bool {
|
||||
if event_type != MERGEABILITY_EVENT {
|
||||
return false;
|
||||
}
|
||||
match action {
|
||||
"conflicting" => snapshot.conflicting != Some(true),
|
||||
"mergeable" => snapshot.conflicting == Some(true),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// The PR's conflict state after `event_type`, or `snapshot`'s when the event
|
||||
/// says nothing about it. A closed PR forgets it: the `closed` flow clears the
|
||||
/// conflict todo, so a reopened PR that still conflicts is told again.
|
||||
pub fn conflicting_after(event_type: &str, action: &str, snapshot: &Snapshot) -> Option<bool> {
|
||||
if event_type == "pull_request" && action == "closed" {
|
||||
return None;
|
||||
}
|
||||
if event_type != MERGEABILITY_EVENT {
|
||||
return snapshot.conflicting;
|
||||
}
|
||||
match action {
|
||||
"conflicting" => Some(true),
|
||||
"mergeable" => Some(false),
|
||||
_ => snapshot.conflicting,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether `event_type` is an assign delivery, whose assignee list is the
|
||||
|
|
@ -199,6 +236,14 @@ pub fn fields(event_type: &str, delivery: &Delivery, snapshot: &Snapshot) -> Fie
|
|||
("author", text(&delivery.author)),
|
||||
("draft", text(bool_text(delivery.draft))),
|
||||
("undrafted", text(bool_text(delivery.undrafted))),
|
||||
(
|
||||
"mergeability_changed",
|
||||
text(bool_text(mergeability_changed(
|
||||
event_type,
|
||||
&delivery.action,
|
||||
snapshot,
|
||||
))),
|
||||
),
|
||||
(
|
||||
"assignees",
|
||||
Value::List(delivery.assignees.iter().cloned().collect()),
|
||||
|
|
@ -428,6 +473,60 @@ mod tests {
|
|||
assert_eq!(f.get("undrafted"), Some(&Value::Text("true".to_owned())));
|
||||
}
|
||||
|
||||
/// The body swarm-controller publishes for a mergeability finding reads as
|
||||
/// a PR, and `mergeability_changed` is true only for a change.
|
||||
#[test]
|
||||
fn a_mergeability_event_reads_as_a_pull_request_and_flags_only_a_change() {
|
||||
let body = |action: &str| {
|
||||
serde_json::to_vec(&serde_json::json!({
|
||||
"action": action,
|
||||
"number": 9,
|
||||
"pull_request": {
|
||||
"number": 9,
|
||||
"title": "t",
|
||||
"html_url": "https://forge/pulls/9",
|
||||
"user": { "login": "atlas" },
|
||||
"assignees": [{ "login": "iris" }],
|
||||
"head": { "sha": "abc" },
|
||||
"base": { "ref": "main" },
|
||||
"draft": false,
|
||||
},
|
||||
"repository": { "id": 42, "full_name": "o/r" },
|
||||
}))
|
||||
.expect("encodes")
|
||||
};
|
||||
let d = Delivery::from_event(MERGEABILITY_EVENT, &body("conflicting")).expect("parses");
|
||||
assert!(d.is_pull);
|
||||
assert_eq!(
|
||||
(d.author.as_str(), d.number, d.action.as_str()),
|
||||
("atlas", 9, "conflicting")
|
||||
);
|
||||
assert_eq!(d.assignees, BTreeSet::from(["iris".to_owned()]));
|
||||
|
||||
let changed = |action: &str, before: Option<bool>, event: &str| {
|
||||
let d = Delivery::from_event(event, &body(action)).expect("parses");
|
||||
let snapshot = Snapshot {
|
||||
conflicting: before,
|
||||
..Snapshot::default()
|
||||
};
|
||||
fields(event, &d, &snapshot)
|
||||
.get("mergeability_changed")
|
||||
.cloned()
|
||||
};
|
||||
let yes = Some(Value::Text("true".to_owned()));
|
||||
let no = Some(Value::Text("false".to_owned()));
|
||||
assert_eq!(changed("conflicting", None, MERGEABILITY_EVENT), yes);
|
||||
assert_eq!(changed("conflicting", Some(false), MERGEABILITY_EVENT), yes);
|
||||
assert_eq!(changed("conflicting", Some(true), MERGEABILITY_EVENT), no);
|
||||
assert_eq!(changed("mergeable", Some(true), MERGEABILITY_EVENT), yes);
|
||||
assert_eq!(changed("mergeable", Some(false), MERGEABILITY_EVENT), no);
|
||||
assert_eq!(changed("mergeable", None, MERGEABILITY_EVENT), no);
|
||||
assert_eq!(
|
||||
changed("conflicting", None, "pull_request"),
|
||||
no,
|
||||
"another event type never changes it"
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn the_snapshot_turns_the_after_list_into_added_and_removed() {
|
||||
let d = Delivery::parse(&issue_assign("unassigned", &["iris"])).expect("parses");
|
||||
|
|
|
|||
Loading…
Reference in a new issue