Skip to main content

llm_optimizer_integrations/jira/
types.rs

1//! Jira API type definitions
2//!
3//! This module provides comprehensive type definitions for Jira REST API v3.
4//! All types include Serde serialization/deserialization support.
5
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8
9/// Jira authentication configuration
10#[derive(Debug, Clone, Serialize, Deserialize)]
11#[serde(tag = "type")]
12pub enum JiraAuth {
13    /// OAuth 2.0 authentication
14    OAuth2 {
15        /// OAuth client ID
16        client_id: String,
17        /// OAuth client secret
18        client_secret: String,
19        /// OAuth access token
20        access_token: String,
21        /// OAuth refresh token
22        refresh_token: Option<String>,
23    },
24    /// Basic authentication with email and API token
25    Basic {
26        /// User email address
27        email: String,
28        /// API token
29        api_token: String,
30    },
31    /// Personal Access Token (PAT)
32    PersonalAccessToken {
33        /// PAT token
34        token: String,
35    },
36}
37
38/// Jira client configuration
39#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct JiraConfig {
41    /// Jira instance base URL (e.g., https://your-domain.atlassian.net)
42    pub base_url: String,
43    /// Authentication configuration
44    pub auth: JiraAuth,
45    /// Request timeout in seconds
46    #[serde(default = "default_timeout")]
47    pub timeout_secs: u64,
48    /// Maximum retry attempts
49    #[serde(default = "default_max_retries")]
50    pub max_retries: u32,
51    /// Rate limit: requests per minute
52    #[serde(default = "default_rate_limit")]
53    pub rate_limit_per_minute: u32,
54}
55
56fn default_timeout() -> u64 {
57    30
58}
59
60fn default_max_retries() -> u32 {
61    3
62}
63
64fn default_rate_limit() -> u32 {
65    100
66}
67
68/// Jira issue representation
69#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct Issue {
71    /// Issue ID
72    pub id: String,
73    /// Issue key (e.g., PROJ-123)
74    pub key: String,
75    /// Issue fields
76    pub fields: IssueFields,
77    /// Issue self URL
78    #[serde(rename = "self")]
79    pub self_url: String,
80}
81
82/// Jira issue fields
83#[derive(Debug, Clone, Serialize, Deserialize)]
84pub struct IssueFields {
85    /// Issue summary
86    pub summary: String,
87    /// Issue description
88    pub description: Option<String>,
89    /// Issue type
90    #[serde(rename = "issuetype")]
91    pub issue_type: IssueType,
92    /// Issue status
93    pub status: Status,
94    /// Issue priority
95    pub priority: Option<Priority>,
96    /// Assignee
97    pub assignee: Option<User>,
98    /// Reporter
99    pub reporter: Option<User>,
100    /// Project
101    pub project: Project,
102    /// Labels
103    #[serde(default)]
104    pub labels: Vec<String>,
105    /// Components
106    #[serde(default)]
107    pub components: Vec<Component>,
108    /// Created timestamp
109    pub created: String,
110    /// Updated timestamp
111    pub updated: String,
112    /// Custom fields
113    #[serde(flatten)]
114    pub custom_fields: HashMap<String, serde_json::Value>,
115}
116
117/// Issue type
118#[derive(Debug, Clone, Serialize, Deserialize)]
119pub struct IssueType {
120    pub id: String,
121    pub name: String,
122    pub description: Option<String>,
123}
124
125/// Issue status
126#[derive(Debug, Clone, Serialize, Deserialize)]
127pub struct Status {
128    pub id: String,
129    pub name: String,
130    pub description: Option<String>,
131    #[serde(rename = "statusCategory")]
132    pub status_category: StatusCategory,
133}
134
135/// Status category
136#[derive(Debug, Clone, Serialize, Deserialize)]
137pub struct StatusCategory {
138    pub id: i32,
139    pub key: String,
140    pub name: String,
141    #[serde(rename = "colorName")]
142    pub color_name: String,
143}
144
145/// Issue priority
146#[derive(Debug, Clone, Serialize, Deserialize)]
147pub struct Priority {
148    pub id: String,
149    pub name: String,
150    #[serde(rename = "iconUrl")]
151    pub icon_url: Option<String>,
152}
153
154/// Jira user
155#[derive(Debug, Clone, Serialize, Deserialize)]
156pub struct User {
157    #[serde(rename = "accountId")]
158    pub account_id: String,
159    #[serde(rename = "displayName")]
160    pub display_name: String,
161    #[serde(rename = "emailAddress")]
162    pub email_address: Option<String>,
163    pub active: bool,
164}
165
166/// Jira project
167#[derive(Debug, Clone, Serialize, Deserialize)]
168pub struct Project {
169    pub id: String,
170    pub key: String,
171    pub name: String,
172    pub description: Option<String>,
173    #[serde(rename = "projectTypeKey")]
174    pub project_type_key: String,
175}
176
177/// Jira component
178#[derive(Debug, Clone, Serialize, Deserialize)]
179pub struct Component {
180    pub id: String,
181    pub name: String,
182    pub description: Option<String>,
183}
184
185/// Create issue request
186#[derive(Debug, Clone, Serialize, Deserialize)]
187pub struct CreateIssueRequest {
188    pub fields: CreateIssueFields,
189}
190
191/// Create issue fields
192#[derive(Debug, Clone, Serialize, Deserialize)]
193pub struct CreateIssueFields {
194    pub project: ProjectRef,
195    pub summary: String,
196    pub description: Option<String>,
197    #[serde(rename = "issuetype")]
198    pub issue_type: IssueTypeRef,
199    #[serde(skip_serializing_if = "Option::is_none")]
200    pub assignee: Option<UserRef>,
201    #[serde(skip_serializing_if = "Option::is_none")]
202    pub priority: Option<PriorityRef>,
203    #[serde(default, skip_serializing_if = "Vec::is_empty")]
204    pub labels: Vec<String>,
205    #[serde(default, skip_serializing_if = "Vec::is_empty")]
206    pub components: Vec<ComponentRef>,
207}
208
209/// Project reference (for creating issues)
210#[derive(Debug, Clone, Serialize, Deserialize)]
211pub struct ProjectRef {
212    pub key: String,
213}
214
215/// Issue type reference
216#[derive(Debug, Clone, Serialize, Deserialize)]
217pub struct IssueTypeRef {
218    pub name: String,
219}
220
221/// User reference
222#[derive(Debug, Clone, Serialize, Deserialize)]
223pub struct UserRef {
224    #[serde(rename = "accountId")]
225    pub account_id: String,
226}
227
228/// Priority reference
229#[derive(Debug, Clone, Serialize, Deserialize)]
230pub struct PriorityRef {
231    pub name: String,
232}
233
234/// Component reference
235#[derive(Debug, Clone, Serialize, Deserialize)]
236pub struct ComponentRef {
237    pub name: String,
238}
239
240/// Update issue request
241#[derive(Debug, Clone, Serialize, Deserialize)]
242pub struct UpdateIssueRequest {
243    #[serde(skip_serializing_if = "Option::is_none")]
244    pub fields: Option<HashMap<String, serde_json::Value>>,
245    #[serde(skip_serializing_if = "Option::is_none")]
246    pub update: Option<HashMap<String, Vec<UpdateOperation>>>,
247}
248
249/// Update operation
250#[derive(Debug, Clone, Serialize, Deserialize)]
251#[serde(tag = "operation", content = "value")]
252pub enum UpdateOperation {
253    #[serde(rename = "add")]
254    Add(serde_json::Value),
255    #[serde(rename = "set")]
256    Set(serde_json::Value),
257    #[serde(rename = "remove")]
258    Remove(serde_json::Value),
259}
260
261/// JQL search request
262#[derive(Debug, Clone, Serialize, Deserialize)]
263pub struct JqlSearchRequest {
264    /// JQL query string
265    pub jql: String,
266    /// Starting index (pagination)
267    #[serde(skip_serializing_if = "Option::is_none")]
268    #[serde(rename = "startAt")]
269    pub start_at: Option<u32>,
270    /// Maximum results per page
271    #[serde(skip_serializing_if = "Option::is_none")]
272    #[serde(rename = "maxResults")]
273    pub max_results: Option<u32>,
274    /// Fields to include in response
275    #[serde(skip_serializing_if = "Option::is_none")]
276    pub fields: Option<Vec<String>>,
277}
278
279/// JQL search response
280#[derive(Debug, Clone, Serialize, Deserialize)]
281pub struct JqlSearchResponse {
282    /// Total number of issues matching the query
283    pub total: u32,
284    /// Starting index
285    #[serde(rename = "startAt")]
286    pub start_at: u32,
287    /// Maximum results
288    #[serde(rename = "maxResults")]
289    pub max_results: u32,
290    /// Issues in this page
291    pub issues: Vec<Issue>,
292}
293
294/// Board information
295#[derive(Debug, Clone, Serialize, Deserialize)]
296pub struct Board {
297    pub id: u64,
298    pub name: String,
299    #[serde(rename = "type")]
300    pub board_type: String,
301    #[serde(rename = "self")]
302    pub self_url: String,
303}
304
305/// Sprint information
306#[derive(Debug, Clone, Serialize, Deserialize)]
307pub struct Sprint {
308    pub id: u64,
309    pub name: String,
310    pub state: String,
311    #[serde(rename = "startDate")]
312    pub start_date: Option<String>,
313    #[serde(rename = "endDate")]
314    pub end_date: Option<String>,
315    #[serde(rename = "originBoardId")]
316    pub origin_board_id: u64,
317}
318
319/// Webhook event
320#[derive(Debug, Clone, Serialize, Deserialize)]
321pub struct WebhookEvent {
322    /// Event timestamp
323    pub timestamp: i64,
324    /// Event type (e.g., "jira:issue_created", "jira:issue_updated")
325    #[serde(rename = "webhookEvent")]
326    pub webhook_event: String,
327    /// Issue event type for issue events
328    #[serde(rename = "issue_event_type_name")]
329    pub issue_event_type_name: Option<String>,
330    /// User who triggered the event
331    pub user: Option<User>,
332    /// Issue data
333    pub issue: Option<Issue>,
334    /// Changelog for update events
335    pub changelog: Option<Changelog>,
336}
337
338/// Changelog
339#[derive(Debug, Clone, Serialize, Deserialize)]
340pub struct Changelog {
341    pub id: String,
342    pub items: Vec<ChangelogItem>,
343}
344
345/// Changelog item
346#[derive(Debug, Clone, Serialize, Deserialize)]
347pub struct ChangelogItem {
348    pub field: String,
349    #[serde(rename = "fieldtype")]
350    pub field_type: String,
351    #[serde(rename = "fieldId")]
352    pub field_id: Option<String>,
353    pub from: Option<String>,
354    #[serde(rename = "fromString")]
355    pub from_string: Option<String>,
356    pub to: Option<String>,
357    #[serde(rename = "toString")]
358    pub to_string: Option<String>,
359}
360
361/// API error response
362#[derive(Debug, Clone, Serialize, Deserialize)]
363pub struct ErrorResponse {
364    #[serde(rename = "errorMessages")]
365    pub error_messages: Vec<String>,
366    pub errors: HashMap<String, String>,
367}
368
369/// Rate limit info
370#[derive(Debug, Clone)]
371pub struct RateLimitInfo {
372    /// Remaining requests in current window
373    pub remaining: u32,
374    /// Total requests allowed per window
375    pub limit: u32,
376    /// Time when rate limit resets (Unix timestamp)
377    pub reset_at: i64,
378}