fix(events): Handle nullable label and milestone in resource events
GitLab returns null for the label/milestone fields on resource_label_events and resource_milestone_events when the referenced label or milestone has been deleted. This caused deserialization failures during sync. - Add migration 012 to recreate both event tables with nullable label_name, milestone_title, and milestone_id columns (SQLite requires table recreation to alter NOT NULL constraints) - Change GitLabLabelEvent.label and GitLabMilestoneEvent.milestone to Option<> in the Rust types - Update upsert functions to pass through None values correctly - Add tests for null label and null milestone deserialization Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -729,10 +729,11 @@ fn deserializes_label_event_add() {
|
||||
|
||||
assert_eq!(event.id, 2001);
|
||||
assert_eq!(event.action, "add");
|
||||
assert_eq!(event.label.id, 100);
|
||||
assert_eq!(event.label.name, "bug");
|
||||
assert_eq!(event.label.color, Some("#FF0000".to_string()));
|
||||
assert_eq!(event.label.description, Some("Bug label".to_string()));
|
||||
let label = event.label.expect("label should be Some");
|
||||
assert_eq!(label.id, 100);
|
||||
assert_eq!(label.name, "bug");
|
||||
assert_eq!(label.color, Some("#FF0000".to_string()));
|
||||
assert_eq!(label.description, Some("Bug label".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -760,8 +761,57 @@ fn deserializes_label_event_remove_null_color() {
|
||||
serde_json::from_str(json).expect("Failed to deserialize label remove event");
|
||||
|
||||
assert_eq!(event.action, "remove");
|
||||
assert!(event.label.color.is_none());
|
||||
assert!(event.label.description.is_none());
|
||||
let label = event.label.expect("label should be Some");
|
||||
assert!(label.color.is_none());
|
||||
assert!(label.description.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserializes_label_event_null_label() {
|
||||
let json = r#"{
|
||||
"id": 2003,
|
||||
"user": {
|
||||
"id": 42,
|
||||
"username": "developer",
|
||||
"name": "Dev User"
|
||||
},
|
||||
"created_at": "2024-03-15T10:30:00.000Z",
|
||||
"resource_type": "Issue",
|
||||
"resource_id": 999,
|
||||
"label": null,
|
||||
"action": "remove"
|
||||
}"#;
|
||||
|
||||
let event: GitLabLabelEvent =
|
||||
serde_json::from_str(json).expect("Failed to deserialize label event with null label");
|
||||
|
||||
assert_eq!(event.id, 2003);
|
||||
assert_eq!(event.action, "remove");
|
||||
assert!(event.label.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserializes_milestone_event_null_milestone() {
|
||||
let json = r#"{
|
||||
"id": 3002,
|
||||
"user": {
|
||||
"id": 42,
|
||||
"username": "developer",
|
||||
"name": "Dev User"
|
||||
},
|
||||
"created_at": "2024-03-15T10:30:00.000Z",
|
||||
"resource_type": "Issue",
|
||||
"resource_id": 999,
|
||||
"milestone": null,
|
||||
"action": "remove"
|
||||
}"#;
|
||||
|
||||
let event: GitLabMilestoneEvent = serde_json::from_str(json)
|
||||
.expect("Failed to deserialize milestone event with null milestone");
|
||||
|
||||
assert_eq!(event.id, 3002);
|
||||
assert_eq!(event.action, "remove");
|
||||
assert!(event.milestone.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -789,9 +839,10 @@ fn deserializes_milestone_event() {
|
||||
|
||||
assert_eq!(event.id, 3001);
|
||||
assert_eq!(event.action, "add");
|
||||
assert_eq!(event.milestone.id, 200);
|
||||
assert_eq!(event.milestone.iid, 5);
|
||||
assert_eq!(event.milestone.title, "v1.0");
|
||||
let milestone = event.milestone.expect("milestone should be Some");
|
||||
assert_eq!(milestone.id, 200);
|
||||
assert_eq!(milestone.iid, 5);
|
||||
assert_eq!(milestone.title, "v1.0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user