feat(gitlab): Add MergeRequest and related types for API deserialization
Extends GitLab type definitions with comprehensive merge request support, matching the API response structure for /projects/:id/merge_requests. New types: - MergeRequest: Full MR metadata including draft status, branch info, detailed_merge_status, merge_user (modern API fields replacing deprecated alternatives), and references for cross-project support - MrReviewer: Reviewer user info (MR-specific, distinct from assignees) - MrAssignee: Assignee user info with consistent structure - MrDiscussion: MR discussion wrapper for polymorphic handling - DiffNotePosition: Rich position data for code review comments with line ranges and SHA triplet for commit context Design decisions: - Use Option<T> for all nullable API fields to handle partial responses - Include deprecated fields (merged_by, merge_status) alongside modern alternatives for backward compatibility with older GitLab instances - DiffNotePosition uses Option for all fields since different position types (text/image/file) populate different subsets These types enable type-safe deserialization of GitLab MR API responses with full coverage of the fields needed for CP2 ingestion. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -140,4 +140,120 @@ pub struct GitLabNotePosition {
|
||||
pub new_path: Option<String>,
|
||||
pub old_line: Option<i32>,
|
||||
pub new_line: Option<i32>,
|
||||
/// Position type: "text", "image", or "file".
|
||||
pub position_type: Option<String>,
|
||||
/// Line range for multi-line comments (GitLab 13.6+).
|
||||
pub line_range: Option<GitLabLineRange>,
|
||||
/// Base commit SHA for the diff.
|
||||
pub base_sha: Option<String>,
|
||||
/// Start commit SHA for the diff.
|
||||
pub start_sha: Option<String>,
|
||||
/// Head commit SHA for the diff.
|
||||
pub head_sha: Option<String>,
|
||||
}
|
||||
|
||||
/// Line range for multi-line DiffNote comments.
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct GitLabLineRange {
|
||||
pub start: GitLabLineRangePoint,
|
||||
pub end: GitLabLineRangePoint,
|
||||
}
|
||||
|
||||
/// A point in a line range (start or end).
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct GitLabLineRangePoint {
|
||||
pub line_code: Option<String>,
|
||||
/// "old" or "new".
|
||||
#[serde(rename = "type")]
|
||||
pub line_type: Option<String>,
|
||||
pub old_line: Option<i32>,
|
||||
pub new_line: Option<i32>,
|
||||
}
|
||||
|
||||
impl GitLabLineRange {
|
||||
/// Get the start line number (new_line preferred, falls back to old_line).
|
||||
pub fn start_line(&self) -> Option<i32> {
|
||||
self.start.new_line.or(self.start.old_line)
|
||||
}
|
||||
|
||||
/// Get the end line number (new_line preferred, falls back to old_line).
|
||||
pub fn end_line(&self) -> Option<i32> {
|
||||
self.end.new_line.or(self.end.old_line)
|
||||
}
|
||||
}
|
||||
|
||||
// === Checkpoint 2: Merge Request types ===
|
||||
|
||||
/// GitLab MR references (short and full reference strings).
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct GitLabReferences {
|
||||
/// Short reference e.g. "!42".
|
||||
pub short: String,
|
||||
/// Full reference e.g. "group/project!42".
|
||||
pub full: String,
|
||||
}
|
||||
|
||||
/// GitLab Reviewer (can have approval state in future).
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct GitLabReviewer {
|
||||
pub id: i64,
|
||||
pub username: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
/// GitLab Merge Request from /projects/:id/merge_requests endpoint.
|
||||
/// Note: Uses non-deprecated field names where possible (detailed_merge_status, merge_user).
|
||||
/// Falls back gracefully for older GitLab versions.
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct GitLabMergeRequest {
|
||||
/// GitLab global ID (unique across all projects).
|
||||
pub id: i64,
|
||||
/// Project-scoped MR number (the number shown in the UI).
|
||||
pub iid: i64,
|
||||
/// The project this MR belongs to.
|
||||
pub project_id: i64,
|
||||
pub title: String,
|
||||
pub description: Option<String>,
|
||||
/// "opened" | "merged" | "closed" | "locked".
|
||||
pub state: String,
|
||||
/// Work-in-progress status (preferred over work_in_progress).
|
||||
#[serde(default)]
|
||||
pub draft: bool,
|
||||
/// Deprecated; fallback for older instances.
|
||||
#[serde(default)]
|
||||
pub work_in_progress: bool,
|
||||
pub source_branch: String,
|
||||
pub target_branch: String,
|
||||
/// Current commit SHA at head of source branch (CP3-ready).
|
||||
pub sha: Option<String>,
|
||||
/// Short and full reference strings (CP3-ready).
|
||||
pub references: Option<GitLabReferences>,
|
||||
/// Non-deprecated merge status. Prefer over merge_status.
|
||||
pub detailed_merge_status: Option<String>,
|
||||
/// Deprecated merge_status field for fallback.
|
||||
#[serde(alias = "merge_status")]
|
||||
pub merge_status_legacy: Option<String>,
|
||||
/// ISO 8601 timestamp.
|
||||
pub created_at: String,
|
||||
/// ISO 8601 timestamp.
|
||||
pub updated_at: String,
|
||||
/// ISO 8601 timestamp when merged (null if not merged).
|
||||
pub merged_at: Option<String>,
|
||||
/// ISO 8601 timestamp when closed (null if not closed).
|
||||
pub closed_at: Option<String>,
|
||||
pub author: GitLabAuthor,
|
||||
/// Non-deprecated; who merged this MR.
|
||||
pub merge_user: Option<GitLabAuthor>,
|
||||
/// Deprecated; fallback for older instances.
|
||||
pub merged_by: Option<GitLabAuthor>,
|
||||
/// Array of label names.
|
||||
#[serde(default)]
|
||||
pub labels: Vec<String>,
|
||||
/// Assignees (can be multiple).
|
||||
#[serde(default)]
|
||||
pub assignees: Vec<GitLabAuthor>,
|
||||
/// Reviewers (MR-specific).
|
||||
#[serde(default)]
|
||||
pub reviewers: Vec<GitLabReviewer>,
|
||||
pub web_url: String,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user