1use std::collections::HashMap;
8
9use serde::{Deserialize, Serialize};
10
11#[derive(Debug, Clone, Serialize)]
18pub struct JiraIssue {
19 pub key: String,
21
22 pub summary: String,
24
25 pub description_adf: Option<serde_json::Value>,
27
28 pub status: Option<String>,
30
31 pub issue_type: Option<String>,
33
34 pub assignee: Option<String>,
36
37 pub priority: Option<String>,
39
40 pub labels: Vec<String>,
42
43 #[serde(default, skip_serializing_if = "Vec::is_empty")]
46 pub custom_fields: Vec<JiraCustomField>,
47}
48
49#[derive(Debug, Clone, Default)]
56pub enum FieldSelection {
57 #[default]
60 Standard,
61
62 Named(Vec<String>),
66
67 All,
69}
70
71#[derive(Debug, Clone, Serialize)]
76pub struct JiraCustomField {
77 pub id: String,
79
80 pub name: String,
83
84 pub value: serde_json::Value,
87}
88
89#[derive(Debug, Clone, Default)]
95pub struct EditMeta {
96 pub fields: std::collections::BTreeMap<String, EditMetaField>,
98}
99
100#[derive(Debug, Clone)]
102pub struct EditMetaField {
103 pub name: String,
105
106 pub schema: EditMetaSchema,
108
109 pub allowed_values: Vec<String>,
117}
118
119#[derive(Debug, Clone, Default)]
121pub struct EditMetaSchema {
122 pub kind: String,
124
125 pub custom: Option<String>,
128
129 pub items: Option<String>,
132
133 pub system: Option<String>,
136}
137
138impl EditMetaField {
139 pub fn is_adf_rich_text(&self) -> bool {
143 self.schema.custom.as_deref() == Some(TEXTAREA_CUSTOM_TYPE)
144 || matches!(
145 self.schema.system.as_deref(),
146 Some("description" | "environment")
147 )
148 }
149}
150
151#[derive(Debug, Clone, Serialize)]
159pub struct CreateMeta {
160 pub project: String,
162
163 pub issue_type: String,
165
166 pub fields: Vec<CreateMetaField>,
168}
169
170#[derive(Debug, Clone, Serialize)]
172pub struct CreateMetaField {
173 pub field_id: String,
175
176 pub name: String,
178
179 pub required: bool,
181
182 pub schema_type: String,
184
185 #[serde(skip_serializing_if = "Option::is_none")]
187 pub items: Option<String>,
188
189 #[serde(skip_serializing_if = "Option::is_none")]
192 pub custom: Option<String>,
193
194 #[serde(skip_serializing_if = "Vec::is_empty")]
197 pub allowed_values: Vec<CreateMetaAllowedValue>,
198
199 #[serde(skip_serializing_if = "Option::is_none")]
201 pub default_value: Option<serde_json::Value>,
202}
203
204#[derive(Debug, Clone, Serialize)]
207pub struct CreateMetaAllowedValue {
208 #[serde(skip_serializing_if = "Option::is_none")]
210 pub id: Option<String>,
211
212 #[serde(skip_serializing_if = "Option::is_none")]
214 pub value: Option<String>,
215
216 #[serde(skip_serializing_if = "Vec::is_empty")]
218 pub children: Vec<Self>,
219}
220
221#[derive(Debug, Clone, Serialize, Deserialize)]
224pub struct JiraUser {
225 #[serde(rename = "displayName")]
227 pub display_name: String,
228
229 #[serde(rename = "emailAddress")]
231 pub email_address: Option<String>,
232
233 #[serde(rename = "accountId")]
235 pub account_id: String,
236}
237
238#[derive(Debug, Clone, Serialize)]
240pub struct JiraWatcherList {
241 pub watchers: Vec<JiraUser>,
243
244 pub watch_count: u32,
246}
247
248#[derive(Debug, Clone, Serialize)]
250pub struct JiraCreatedIssue {
251 pub key: String,
253 pub id: String,
255 pub self_url: String,
257}
258
259#[derive(Debug, Clone, Serialize)]
264pub struct JiraSearchResult {
265 pub issues: Vec<JiraIssue>,
267
268 pub total: u32,
270}
271
272#[derive(Debug, Clone, Serialize)]
281pub struct JiraUserSearchResult {
282 pub account_id: String,
284 #[serde(skip_serializing_if = "Option::is_none")]
286 pub display_name: Option<String>,
287 #[serde(skip_serializing_if = "Option::is_none")]
289 pub email_address: Option<String>,
290 pub active: bool,
292 #[serde(skip_serializing_if = "Option::is_none")]
294 pub account_type: Option<String>,
295}
296
297#[derive(Debug, Clone, Serialize)]
303pub struct JiraUserSearchResults {
304 pub users: Vec<JiraUserSearchResult>,
306 pub count: u32,
309}
310
311#[derive(Debug, Clone, Serialize)]
321pub struct JiraUserRecord {
322 pub account_id: String,
324 #[serde(skip_serializing_if = "Option::is_none")]
326 pub display_name: Option<String>,
327 #[serde(skip_serializing_if = "Option::is_none")]
329 pub email_address: Option<String>,
330 #[serde(skip_serializing_if = "Option::is_none")]
332 pub active: Option<bool>,
333 #[serde(skip_serializing_if = "Option::is_none")]
335 pub account_type: Option<String>,
336 #[serde(skip_serializing_if = "Option::is_none")]
339 pub error: Option<String>,
340}
341
342#[derive(Debug, Clone, Serialize)]
345pub struct JiraUserGetResults {
346 pub users: Vec<JiraUserRecord>,
348}
349
350#[derive(Debug, Clone, Serialize)]
352pub struct JiraComment {
353 pub id: String,
355 pub author: String,
357 pub body_adf: Option<serde_json::Value>,
359 pub created: String,
361 #[serde(skip_serializing_if = "Option::is_none")]
363 pub updated: Option<String>,
364}
365
366#[derive(Debug, Clone, Copy, Serialize)]
372#[serde(rename_all = "lowercase")]
373pub enum JiraVisibilityType {
374 Group,
376 Role,
378}
379
380#[derive(Debug, Clone)]
385pub struct JiraVisibility {
386 pub ty: JiraVisibilityType,
388 pub value: String,
390}
391
392impl Serialize for JiraVisibility {
393 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
394 use serde::ser::SerializeStruct;
395 let mut s = serializer.serialize_struct("JiraVisibility", 2)?;
396 s.serialize_field("type", &self.ty)?;
397 s.serialize_field("identifier", &self.value)?;
398 s.end()
399 }
400}
401
402#[derive(Debug, Clone, Serialize)]
406pub struct JiraProject {
407 pub id: String,
409 pub key: String,
411 pub name: String,
413 pub project_type: Option<String>,
415 pub lead: Option<String>,
417}
418
419#[derive(Debug, Clone, Serialize)]
422pub struct JiraProjectList {
423 pub projects: Vec<JiraProject>,
425 pub total: u32,
427}
428
429pub(crate) const TEXTAREA_CUSTOM_TYPE: &str =
432 "com.atlassian.jira.plugin.system.customfieldtypes:textarea";
433
434#[derive(Debug, Clone, Serialize)]
436pub struct JiraField {
437 pub id: String,
439 pub name: String,
441 pub custom: bool,
443 pub schema_type: Option<String>,
448 #[serde(skip_serializing_if = "Option::is_none")]
452 pub schema_custom: Option<String>,
453}
454
455#[derive(Debug, Clone, Serialize)]
458pub struct JiraFieldOption {
459 pub id: String,
461 pub value: String,
463}
464
465#[derive(Debug, Clone, Serialize)]
469pub struct AgileBoard {
470 pub id: u64,
472 pub name: String,
474 pub board_type: String,
476 pub project_key: Option<String>,
478}
479
480#[derive(Debug, Clone, Serialize)]
483pub struct AgileBoardList {
484 pub boards: Vec<AgileBoard>,
486 pub total: u32,
488}
489
490#[derive(Debug, Clone, Serialize)]
494pub struct AgileSprint {
495 pub id: u64,
497 pub name: String,
499 pub state: String,
501 pub start_date: Option<String>,
503 pub end_date: Option<String>,
505 pub goal: Option<String>,
507}
508
509#[derive(Debug, Clone, Serialize)]
512pub struct AgileSprintList {
513 pub sprints: Vec<AgileSprint>,
515 pub total: u32,
517}
518
519#[derive(Debug, Clone, Serialize)]
525pub struct JiraProjectVersion {
526 pub id: String,
528 pub name: String,
530 pub description: Option<String>,
532 pub project_key: String,
534 pub released: bool,
536 pub archived: bool,
538 pub release_date: Option<String>,
540 pub start_date: Option<String>,
542}
543
544#[derive(Debug, Clone, Serialize)]
547pub struct JiraProjectVersionList {
548 pub versions: Vec<JiraProjectVersion>,
550 pub total: u32,
552}
553
554#[derive(Debug, Clone, Serialize)]
557pub struct JiraComponent {
558 pub id: String,
560 pub name: String,
562 #[serde(skip_serializing_if = "Option::is_none")]
564 pub description: Option<String>,
565}
566
567#[derive(Deserialize)]
569pub(crate) struct JiraComponentEntry {
570 pub(crate) id: String,
571 #[serde(default)]
572 pub(crate) name: String,
573 #[serde(default)]
574 pub(crate) description: Option<String>,
575}
576
577#[derive(Debug, Clone, Serialize)]
580pub struct JiraChangelogEntry {
581 pub id: String,
583 pub author: String,
585 pub created: String,
587 pub items: Vec<JiraChangelogItem>,
589}
590
591#[derive(Debug, Clone, Serialize)]
593pub struct JiraChangelogItem {
594 pub field: String,
596 pub from_string: Option<String>,
598 pub to_string: Option<String>,
600}
601
602#[derive(Debug, Clone, Serialize)]
604pub struct JiraLinkType {
605 pub id: String,
607 pub name: String,
609 pub inward: String,
611 pub outward: String,
613}
614
615#[derive(Debug, Clone, Serialize)]
619pub struct JiraIssueLink {
620 pub id: String,
622 pub link_type: String,
624 pub direction: String,
626 pub linked_issue_key: String,
628 pub linked_issue_summary: String,
630}
631
632#[derive(Debug, Clone, Serialize)]
638pub struct JiraRemoteIssueLink {
639 pub id: String,
641 #[serde(skip_serializing_if = "Option::is_none")]
644 pub global_id: Option<String>,
645 #[serde(skip_serializing_if = "Option::is_none")]
648 pub relationship: Option<String>,
649 pub object: JiraRemoteIssueLinkObject,
651}
652
653#[derive(Debug, Clone, Serialize)]
655pub struct JiraRemoteIssueLinkObject {
656 pub url: String,
658 #[serde(skip_serializing_if = "Option::is_none")]
660 pub title: Option<String>,
661 #[serde(skip_serializing_if = "Option::is_none")]
663 pub summary: Option<String>,
664 #[serde(skip_serializing_if = "Option::is_none")]
667 pub icon: Option<JiraRemoteIssueLinkIcon>,
668}
669
670#[derive(Debug, Clone, Serialize)]
673pub struct JiraRemoteIssueLinkIcon {
674 #[serde(skip_serializing_if = "Option::is_none")]
676 pub url: Option<String>,
677 #[serde(skip_serializing_if = "Option::is_none")]
679 pub title: Option<String>,
680}
681
682#[derive(Debug, Clone, Serialize)]
688pub struct JiraAttachment {
689 pub id: String,
691 pub filename: String,
693 pub mime_type: String,
695 pub size: u64,
697 pub content_url: String,
699}
700
701impl From<JiraAttachmentEntry> for JiraAttachment {
702 fn from(entry: JiraAttachmentEntry) -> Self {
703 Self {
704 id: entry.id,
705 filename: entry.filename,
706 mime_type: entry.mime_type,
707 size: entry.size,
708 content_url: entry.content,
709 }
710 }
711}
712
713#[derive(Debug, Clone, Serialize)]
717pub struct JiraTransition {
718 pub id: String,
720 pub name: String,
722 #[serde(skip_serializing_if = "Option::is_none")]
724 pub to_status: Option<JiraTransitionToStatus>,
725 #[serde(skip_serializing_if = "Option::is_none")]
727 pub has_screen: Option<bool>,
728}
729
730#[derive(Debug, Clone, Serialize)]
733pub struct JiraTransitionToStatus {
734 pub id: String,
736 pub name: String,
738 #[serde(skip_serializing_if = "Option::is_none")]
740 pub category: Option<String>,
741}
742
743#[derive(Debug, Clone, Serialize)]
746pub struct JiraDevPullRequest {
747 pub id: String,
749 pub name: String,
751 pub status: String,
753 pub url: String,
755 pub repository_name: String,
757 pub source_branch: String,
759 pub destination_branch: String,
761 #[serde(skip_serializing_if = "Option::is_none")]
763 pub author: Option<String>,
764 #[serde(skip_serializing_if = "Vec::is_empty")]
766 pub reviewers: Vec<String>,
767 #[serde(skip_serializing_if = "Option::is_none")]
769 pub comment_count: Option<u32>,
770 #[serde(skip_serializing_if = "Option::is_none")]
772 pub last_update: Option<String>,
773}
774
775#[derive(Debug, Clone, Serialize)]
779pub struct JiraDevCommit {
780 pub id: String,
782 pub display_id: String,
784 pub message: String,
786 #[serde(skip_serializing_if = "Option::is_none")]
788 pub author: Option<String>,
789 #[serde(skip_serializing_if = "Option::is_none")]
791 pub timestamp: Option<String>,
792 pub url: String,
794 pub file_count: u32,
796 pub merge: bool,
798}
799
800#[derive(Debug, Clone, Serialize)]
803pub struct JiraDevBranch {
804 pub name: String,
806 pub url: String,
808 pub repository_name: String,
810 #[serde(skip_serializing_if = "Option::is_none")]
812 pub create_pr_url: Option<String>,
813 #[serde(skip_serializing_if = "Option::is_none")]
815 pub last_commit: Option<JiraDevCommit>,
816}
817
818#[derive(Debug, Clone, Serialize)]
821pub struct JiraDevRepository {
822 pub name: String,
824 pub url: String,
826 #[serde(skip_serializing_if = "Vec::is_empty")]
828 pub commits: Vec<JiraDevCommit>,
829}
830
831#[derive(Debug, Clone, Serialize)]
837pub struct JiraDevStatus {
838 #[serde(skip_serializing_if = "Vec::is_empty")]
840 pub pull_requests: Vec<JiraDevPullRequest>,
841 #[serde(skip_serializing_if = "Vec::is_empty")]
843 pub branches: Vec<JiraDevBranch>,
844 #[serde(skip_serializing_if = "Vec::is_empty")]
846 pub repositories: Vec<JiraDevRepository>,
847}
848
849#[derive(Debug, Clone, Serialize)]
853pub struct JiraDevStatusCount {
854 pub count: u32,
856 pub providers: Vec<JiraDevProvider>,
858}
859
860#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
863pub struct JiraDevProvider {
864 pub instance_type: String,
868 pub name: String,
870}
871
872#[derive(Debug, Clone, Serialize)]
876pub struct JiraDevStatusSummary {
877 pub pullrequest: JiraDevStatusCount,
879 pub branch: JiraDevStatusCount,
881 pub repository: JiraDevStatusCount,
883}
884
885#[derive(Debug, Clone, Serialize)]
888pub struct JiraWorklog {
889 pub id: String,
891 pub author: String,
893 pub time_spent: String,
895 pub time_spent_seconds: u64,
897 pub started: String,
899 #[serde(skip_serializing_if = "Option::is_none")]
901 pub comment: Option<String>,
902}
903
904#[derive(Debug, Clone, Serialize)]
907pub struct JiraWorklogList {
908 pub worklogs: Vec<JiraWorklog>,
910 pub total: u32,
912}
913
914#[derive(Deserialize)]
917pub(crate) struct JiraIssueResponse {
918 pub(crate) key: String,
919 pub(crate) fields: JiraIssueFields,
920}
921
922#[derive(Deserialize)]
925pub(crate) struct JiraIssueEnvelope {
926 pub(crate) key: String,
927 #[serde(default)]
928 pub(crate) fields: std::collections::BTreeMap<String, serde_json::Value>,
929 #[serde(default)]
930 pub(crate) names: std::collections::BTreeMap<String, String>,
931}
932
933impl JiraIssueEnvelope {
934 pub(crate) fn into_issue(self, selection: &FieldSelection) -> JiraIssue {
935 let Self {
936 key,
937 mut fields,
938 names,
939 } = self;
940
941 let description_adf = fields.remove("description").filter(|v| !v.is_null());
942 let summary = fields
943 .remove("summary")
944 .and_then(|v| v.as_str().map(str::to_string))
945 .unwrap_or_default();
946 let status = extract_named_field(fields.remove("status"));
947 let issue_type = extract_named_field(fields.remove("issuetype"));
948 let assignee = extract_display_name(fields.remove("assignee"));
949 let priority = extract_named_field(fields.remove("priority"));
950 let labels = fields
951 .remove("labels")
952 .and_then(|v| serde_json::from_value::<Vec<String>>(v).ok())
953 .unwrap_or_default();
954
955 let collect_customs = !matches!(selection, FieldSelection::Standard);
956 let custom_fields = if collect_customs {
957 fields
958 .into_iter()
959 .filter(|(_, value)| !value.is_null())
960 .map(|(id, value)| {
961 let name = names.get(&id).cloned().unwrap_or_else(|| id.clone());
962 JiraCustomField { id, name, value }
963 })
964 .collect()
965 } else {
966 Vec::new()
967 };
968
969 JiraIssue {
970 key,
971 summary,
972 description_adf,
973 status,
974 issue_type,
975 assignee,
976 priority,
977 labels,
978 custom_fields,
979 }
980 }
981}
982
983fn extract_named_field(value: Option<serde_json::Value>) -> Option<String> {
984 value
985 .and_then(|v| v.get("name").cloned())
986 .and_then(|n| n.as_str().map(str::to_string))
987}
988
989fn extract_display_name(value: Option<serde_json::Value>) -> Option<String> {
990 value
991 .and_then(|v| v.get("displayName").cloned())
992 .and_then(|n| n.as_str().map(str::to_string))
993}
994
995#[derive(Deserialize)]
996pub(crate) struct JiraEditMetaResponse {
997 #[serde(default)]
998 pub(crate) fields: std::collections::BTreeMap<String, JiraEditMetaField>,
999}
1000
1001#[derive(Deserialize)]
1002pub(crate) struct JiraEditMetaField {
1003 #[serde(default)]
1004 pub(crate) name: Option<String>,
1005 #[serde(default)]
1006 pub(crate) schema: Option<JiraEditMetaSchemaRaw>,
1007 #[serde(rename = "allowedValues", default)]
1008 pub(crate) allowed_values: Vec<JiraAllowedValueRaw>,
1009}
1010
1011impl JiraEditMetaField {
1012 pub(crate) fn allowed_value_strings(&self) -> Vec<String> {
1016 self.allowed_values
1017 .iter()
1018 .filter_map(|v| v.value.clone().or_else(|| v.name.clone()))
1019 .collect()
1020 }
1021}
1022
1023#[derive(Deserialize)]
1024pub(crate) struct JiraEditMetaSchemaRaw {
1025 #[serde(rename = "type", default)]
1026 pub(crate) kind: Option<String>,
1027 #[serde(default)]
1028 pub(crate) custom: Option<String>,
1029 #[serde(default)]
1030 pub(crate) items: Option<String>,
1031 #[serde(default)]
1032 pub(crate) system: Option<String>,
1033}
1034
1035impl From<Option<JiraEditMetaSchemaRaw>> for EditMetaSchema {
1036 fn from(raw: Option<JiraEditMetaSchemaRaw>) -> Self {
1037 raw.map_or_else(Self::default, |s| Self {
1038 kind: s.kind.unwrap_or_default(),
1039 custom: s.custom,
1040 items: s.items,
1041 system: s.system,
1042 })
1043 }
1044}
1045
1046#[derive(Deserialize)]
1047pub(crate) struct JiraCreateMetaResponse {
1048 #[serde(default)]
1049 pub(crate) projects: Vec<JiraCreateMetaProject>,
1050}
1051
1052#[derive(Deserialize)]
1053pub(crate) struct JiraCreateMetaProject {
1054 #[serde(default)]
1055 pub(crate) issuetypes: Vec<JiraCreateMetaIssueType>,
1056}
1057
1058#[derive(Deserialize)]
1059pub(crate) struct JiraCreateMetaIssueType {
1060 #[serde(default)]
1061 pub(crate) fields: std::collections::BTreeMap<String, JiraEditMetaField>,
1062}
1063
1064#[derive(Deserialize)]
1068pub(crate) struct JiraCreateMetaFullResponse {
1069 #[serde(default)]
1070 pub(crate) projects: Vec<JiraCreateMetaFullProject>,
1071}
1072
1073#[derive(Deserialize)]
1074pub(crate) struct JiraCreateMetaFullProject {
1075 #[serde(default)]
1076 pub(crate) issuetypes: Vec<JiraCreateMetaFullIssueType>,
1077}
1078
1079#[derive(Deserialize)]
1080pub(crate) struct JiraCreateMetaFullIssueType {
1081 #[serde(default)]
1082 pub(crate) fields: std::collections::BTreeMap<String, JiraCreateMetaFieldRaw>,
1083}
1084
1085#[derive(Deserialize)]
1086pub(crate) struct JiraCreateMetaFieldRaw {
1087 #[serde(default)]
1088 pub(crate) name: Option<String>,
1089 #[serde(default)]
1090 pub(crate) required: bool,
1091 #[serde(default)]
1092 pub(crate) schema: Option<JiraCreateMetaSchemaRaw>,
1093 #[serde(rename = "allowedValues", default)]
1094 pub(crate) allowed_values: Vec<JiraAllowedValueRaw>,
1095 #[serde(rename = "defaultValue", default)]
1096 pub(crate) default_value: Option<serde_json::Value>,
1097}
1098
1099#[derive(Deserialize)]
1100pub(crate) struct JiraCreateMetaSchemaRaw {
1101 #[serde(rename = "type", default)]
1102 pub(crate) kind: Option<String>,
1103 #[serde(default)]
1104 pub(crate) items: Option<String>,
1105 #[serde(default)]
1106 pub(crate) custom: Option<String>,
1107}
1108
1109#[derive(Deserialize)]
1110pub(crate) struct JiraAllowedValueRaw {
1111 #[serde(default)]
1112 pub(crate) id: Option<String>,
1113 #[serde(default)]
1114 pub(crate) value: Option<String>,
1115 #[serde(default)]
1116 pub(crate) name: Option<String>,
1117 #[serde(default)]
1118 pub(crate) children: Vec<Self>,
1119}
1120
1121impl JiraAllowedValueRaw {
1122 pub(crate) fn into_allowed_value(self) -> CreateMetaAllowedValue {
1125 CreateMetaAllowedValue {
1126 id: self.id,
1127 value: self.value.or(self.name),
1128 children: self
1129 .children
1130 .into_iter()
1131 .map(Self::into_allowed_value)
1132 .collect(),
1133 }
1134 }
1135}
1136
1137#[derive(Deserialize)]
1138pub(crate) struct JiraIssueFields {
1139 pub(crate) summary: Option<String>,
1140 pub(crate) description: Option<serde_json::Value>,
1141 pub(crate) status: Option<JiraNameField>,
1142 pub(crate) issuetype: Option<JiraNameField>,
1143 pub(crate) assignee: Option<JiraAssigneeField>,
1144 pub(crate) priority: Option<JiraNameField>,
1145 #[serde(default)]
1146 pub(crate) labels: Vec<String>,
1147}
1148
1149#[derive(Deserialize)]
1150pub(crate) struct JiraNameField {
1151 pub(crate) name: Option<String>,
1152}
1153
1154#[derive(Deserialize)]
1155pub(crate) struct JiraAssigneeField {
1156 #[serde(rename = "displayName")]
1157 pub(crate) display_name: Option<String>,
1158}
1159
1160#[derive(Deserialize)]
1161#[allow(dead_code)]
1162pub(crate) struct JiraSearchResponse {
1163 pub(crate) issues: Vec<JiraIssueResponse>,
1164 #[serde(default)]
1165 pub(crate) total: u32,
1166 #[serde(rename = "nextPageToken", default)]
1167 pub(crate) next_page_token: Option<String>,
1168}
1169
1170#[derive(Deserialize)]
1171pub(crate) struct JiraTransitionsResponse {
1172 pub(crate) transitions: Vec<JiraTransitionEntry>,
1173}
1174
1175#[derive(Deserialize)]
1176pub(crate) struct JiraTransitionEntry {
1177 pub(crate) id: String,
1178 pub(crate) name: String,
1179 #[serde(default)]
1180 pub(crate) to: Option<JiraTransitionToEntry>,
1181 #[serde(rename = "hasScreen", default)]
1182 pub(crate) has_screen: Option<bool>,
1183 #[serde(default)]
1187 pub(crate) fields: std::collections::BTreeMap<String, JiraEditMetaField>,
1188}
1189
1190#[derive(Deserialize)]
1191pub(crate) struct JiraTransitionToEntry {
1192 pub(crate) id: String,
1193 pub(crate) name: String,
1194 #[serde(rename = "statusCategory", default)]
1195 pub(crate) status_category: Option<JiraStatusCategoryEntry>,
1196}
1197
1198#[derive(Deserialize)]
1199pub(crate) struct JiraStatusCategoryEntry {
1200 #[serde(default)]
1201 pub(crate) key: Option<String>,
1202}
1203
1204#[derive(Deserialize)]
1205pub(crate) struct JiraCommentsResponse {
1206 #[serde(default)]
1207 pub(crate) comments: Vec<JiraCommentEntry>,
1208 #[serde(default)]
1209 pub(crate) total: u32,
1210 #[serde(rename = "startAt", default)]
1211 pub(crate) start_at: u32,
1212 #[serde(rename = "maxResults", default)]
1213 #[allow(dead_code)]
1214 pub(crate) max_results: u32,
1215}
1216
1217#[derive(Deserialize)]
1218pub(crate) struct JiraCommentEntry {
1219 pub(crate) id: String,
1220 pub(crate) author: Option<JiraCommentAuthor>,
1221 pub(crate) body: Option<serde_json::Value>,
1222 pub(crate) created: Option<String>,
1223 #[serde(default)]
1224 pub(crate) updated: Option<String>,
1225}
1226
1227#[derive(Deserialize)]
1228pub(crate) struct JiraCommentAuthor {
1229 #[serde(rename = "displayName")]
1230 pub(crate) display_name: Option<String>,
1231}
1232
1233#[derive(Deserialize)]
1234pub(crate) struct JiraWorklogResponse {
1235 #[serde(default)]
1236 pub(crate) worklogs: Vec<JiraWorklogEntry>,
1237 #[serde(default)]
1238 pub(crate) total: u32,
1239}
1240
1241#[derive(Deserialize)]
1242pub(crate) struct JiraWorklogEntry {
1243 pub(crate) id: String,
1244 pub(crate) author: Option<JiraCommentAuthor>,
1245 #[serde(rename = "timeSpent")]
1246 pub(crate) time_spent: Option<String>,
1247 #[serde(rename = "timeSpentSeconds", default)]
1248 pub(crate) time_spent_seconds: u64,
1249 pub(crate) started: Option<String>,
1250 pub(crate) comment: Option<serde_json::Value>,
1251}
1252
1253#[derive(Deserialize)]
1256pub(crate) struct JiraUserSearchEntry {
1257 #[serde(rename = "accountId")]
1258 pub(crate) account_id: String,
1259 #[serde(rename = "displayName", default)]
1260 pub(crate) display_name: Option<String>,
1261 #[serde(rename = "emailAddress", default)]
1262 pub(crate) email_address: Option<String>,
1263 #[serde(default)]
1264 pub(crate) active: bool,
1265 #[serde(rename = "accountType", default)]
1266 pub(crate) account_type: Option<String>,
1267}
1268
1269#[derive(Deserialize)]
1272#[allow(dead_code)]
1273pub(crate) struct AgileBoardListResponse {
1274 pub(crate) values: Vec<AgileBoardEntry>,
1275 #[serde(default)]
1276 pub(crate) total: u32,
1277 #[serde(rename = "isLast", default)]
1278 pub(crate) is_last: bool,
1279}
1280
1281#[derive(Deserialize)]
1282pub(crate) struct AgileBoardEntry {
1283 pub(crate) id: u64,
1284 pub(crate) name: String,
1285 #[serde(rename = "type")]
1286 pub(crate) board_type: String,
1287 pub(crate) location: Option<AgileBoardLocation>,
1288}
1289
1290#[derive(Deserialize)]
1291pub(crate) struct AgileBoardLocation {
1292 #[serde(rename = "projectKey")]
1293 pub(crate) project_key: Option<String>,
1294}
1295
1296#[derive(Deserialize)]
1297#[allow(dead_code)]
1298pub(crate) struct AgileIssueListResponse {
1299 pub(crate) issues: Vec<JiraIssueResponse>,
1300 #[serde(default)]
1301 pub(crate) total: u32,
1302 #[serde(rename = "isLast", default)]
1303 pub(crate) is_last: bool,
1304}
1305
1306#[derive(Deserialize)]
1307#[allow(dead_code)]
1308pub(crate) struct AgileSprintListResponse {
1309 pub(crate) values: Vec<AgileSprintEntry>,
1310 #[serde(default)]
1311 pub(crate) total: u32,
1312 #[serde(rename = "isLast", default)]
1313 pub(crate) is_last: bool,
1314}
1315
1316#[derive(Deserialize)]
1317pub(crate) struct AgileSprintEntry {
1318 pub(crate) id: u64,
1319 pub(crate) name: String,
1320 pub(crate) state: String,
1321 #[serde(rename = "startDate")]
1322 pub(crate) start_date: Option<String>,
1323 #[serde(rename = "endDate")]
1324 pub(crate) end_date: Option<String>,
1325 pub(crate) goal: Option<String>,
1326}
1327
1328#[derive(Deserialize)]
1329pub(crate) struct JiraProjectVersionEntry {
1330 pub(crate) id: String,
1331 pub(crate) name: String,
1332 #[serde(default)]
1333 pub(crate) description: Option<String>,
1334 #[serde(default)]
1335 pub(crate) released: bool,
1336 #[serde(default)]
1337 pub(crate) archived: bool,
1338 #[serde(rename = "releaseDate", default)]
1339 pub(crate) release_date: Option<String>,
1340 #[serde(rename = "startDate", default)]
1341 pub(crate) start_date: Option<String>,
1342}
1343
1344#[derive(Deserialize)]
1345pub(crate) struct JiraIssueLinksResponse {
1346 pub(crate) fields: JiraIssueLinksFields,
1347}
1348
1349#[derive(Deserialize)]
1350pub(crate) struct JiraIssueLinksFields {
1351 #[serde(default)]
1352 pub(crate) issuelinks: Vec<JiraIssueLinkEntry>,
1353}
1354
1355#[derive(Deserialize)]
1356pub(crate) struct JiraIssueLinkEntry {
1357 pub(crate) id: String,
1358 #[serde(rename = "type")]
1359 pub(crate) link_type: JiraIssueLinkType,
1360 #[serde(rename = "inwardIssue")]
1361 pub(crate) inward_issue: Option<JiraIssueLinkIssue>,
1362 #[serde(rename = "outwardIssue")]
1363 pub(crate) outward_issue: Option<JiraIssueLinkIssue>,
1364}
1365
1366#[derive(Deserialize)]
1367pub(crate) struct JiraIssueLinkType {
1368 pub(crate) name: String,
1369}
1370
1371#[derive(Deserialize)]
1372pub(crate) struct JiraIssueLinkIssue {
1373 pub(crate) key: String,
1374 pub(crate) fields: Option<JiraIssueLinkIssueFields>,
1375}
1376
1377#[derive(Deserialize)]
1378pub(crate) struct JiraIssueLinkIssueFields {
1379 pub(crate) summary: Option<String>,
1380}
1381
1382#[derive(Deserialize)]
1383pub(crate) struct JiraRemoteIssueLinkEntry {
1384 pub(crate) id: serde_json::Value,
1385 #[serde(rename = "globalId", default)]
1386 pub(crate) global_id: Option<String>,
1387 #[serde(default)]
1388 pub(crate) relationship: Option<String>,
1389 pub(crate) object: JiraRemoteIssueLinkObjectEntry,
1390}
1391
1392#[derive(Deserialize)]
1393pub(crate) struct JiraRemoteIssueLinkObjectEntry {
1394 pub(crate) url: String,
1395 #[serde(default)]
1396 pub(crate) title: Option<String>,
1397 #[serde(default)]
1398 pub(crate) summary: Option<String>,
1399 #[serde(default)]
1400 pub(crate) icon: Option<JiraRemoteIssueLinkIconEntry>,
1401}
1402
1403#[derive(Deserialize)]
1404pub(crate) struct JiraRemoteIssueLinkIconEntry {
1405 #[serde(rename = "url16x16", default)]
1406 pub(crate) url: Option<String>,
1407 #[serde(default)]
1408 pub(crate) title: Option<String>,
1409}
1410
1411#[derive(Deserialize)]
1414pub(crate) struct JiraRemoteLinkCreateResponse {
1415 pub(crate) id: serde_json::Value,
1416}
1417
1418#[derive(Deserialize)]
1419pub(crate) struct JiraLinkTypesResponse {
1420 #[serde(rename = "issueLinkTypes")]
1421 pub(crate) issue_link_types: Vec<JiraLinkTypeEntry>,
1422}
1423
1424#[derive(Deserialize)]
1425pub(crate) struct JiraLinkTypeEntry {
1426 pub(crate) id: String,
1427 pub(crate) name: String,
1428 pub(crate) inward: String,
1429 pub(crate) outward: String,
1430}
1431
1432#[derive(Deserialize)]
1433pub(crate) struct JiraAttachmentIssueResponse {
1434 pub(crate) fields: JiraAttachmentFields,
1435}
1436
1437#[derive(Deserialize)]
1438pub(crate) struct JiraAttachmentFields {
1439 #[serde(default)]
1440 pub(crate) attachment: Vec<JiraAttachmentEntry>,
1441}
1442
1443#[derive(Deserialize)]
1444pub(crate) struct JiraAttachmentEntry {
1445 pub(crate) id: String,
1446 pub(crate) filename: String,
1447 #[serde(rename = "mimeType")]
1448 pub(crate) mime_type: String,
1449 pub(crate) size: u64,
1450 pub(crate) content: String,
1451}
1452
1453#[derive(Deserialize)]
1454#[allow(dead_code)]
1455pub(crate) struct JiraChangelogResponse {
1456 pub(crate) values: Vec<JiraChangelogEntryResponse>,
1457 #[serde(default)]
1458 pub(crate) total: u32,
1459 #[serde(rename = "isLast", default)]
1460 pub(crate) is_last: bool,
1461}
1462
1463#[derive(Deserialize)]
1464pub(crate) struct JiraChangelogEntryResponse {
1465 pub(crate) id: String,
1466 pub(crate) author: Option<JiraCommentAuthor>,
1467 pub(crate) created: Option<String>,
1468 #[serde(default)]
1469 pub(crate) items: Vec<JiraChangelogItemResponse>,
1470}
1471
1472#[derive(Deserialize)]
1473pub(crate) struct JiraChangelogItemResponse {
1474 pub(crate) field: String,
1475 #[serde(rename = "fromString")]
1476 pub(crate) from_string: Option<String>,
1477 #[serde(rename = "toString")]
1478 pub(crate) to_string: Option<String>,
1479}
1480
1481#[derive(Deserialize)]
1482pub(crate) struct JiraFieldEntry {
1483 pub(crate) id: String,
1484 pub(crate) name: String,
1485 #[serde(default)]
1486 pub(crate) custom: bool,
1487 pub(crate) schema: Option<JiraFieldSchema>,
1488}
1489
1490#[derive(Deserialize)]
1491pub(crate) struct JiraFieldSchema {
1492 #[serde(rename = "type")]
1493 pub(crate) schema_type: Option<String>,
1494 pub(crate) custom: Option<String>,
1495}
1496
1497#[derive(Deserialize)]
1498pub(crate) struct JiraFieldContextsResponse {
1499 pub(crate) values: Vec<JiraFieldContextEntry>,
1500}
1501
1502#[derive(Deserialize)]
1503pub(crate) struct JiraFieldContextEntry {
1504 pub(crate) id: String,
1505}
1506
1507#[derive(Deserialize)]
1508pub(crate) struct JiraFieldOptionsResponse {
1509 pub(crate) values: Vec<JiraFieldOptionEntry>,
1510}
1511
1512#[derive(Deserialize)]
1513pub(crate) struct JiraFieldOptionEntry {
1514 pub(crate) id: String,
1515 pub(crate) value: String,
1516}
1517
1518#[derive(Deserialize)]
1519#[allow(dead_code)]
1520pub(crate) struct JiraProjectSearchResponse {
1521 pub(crate) values: Vec<JiraProjectEntry>,
1522 pub(crate) total: u32,
1523 #[serde(rename = "isLast", default)]
1524 pub(crate) is_last: bool,
1525}
1526
1527#[derive(Deserialize)]
1528pub(crate) struct JiraProjectEntry {
1529 pub(crate) id: String,
1530 pub(crate) key: String,
1531 pub(crate) name: String,
1532 #[serde(rename = "projectTypeKey")]
1533 pub(crate) project_type_key: Option<String>,
1534 pub(crate) lead: Option<JiraProjectLead>,
1535}
1536
1537#[derive(Deserialize)]
1538pub(crate) struct JiraProjectLead {
1539 #[serde(rename = "displayName")]
1540 pub(crate) display_name: Option<String>,
1541}
1542
1543#[derive(Deserialize)]
1544pub(crate) struct JiraCreateResponse {
1545 pub(crate) key: String,
1546 pub(crate) id: String,
1547 #[serde(rename = "self")]
1548 pub(crate) self_url: String,
1549}
1550
1551#[derive(Deserialize)]
1555pub(crate) struct JiraIssueIdResponse {
1556 pub(crate) id: String,
1557}
1558
1559#[derive(Deserialize)]
1560pub(crate) struct DevStatusResponse {
1561 #[serde(default)]
1562 pub(crate) detail: Vec<DevStatusDetail>,
1563}
1564
1565#[derive(Deserialize)]
1566pub(crate) struct DevStatusDetail {
1567 #[serde(rename = "pullRequests", default)]
1568 pub(crate) pull_requests: Vec<DevStatusPullRequest>,
1569 #[serde(default)]
1570 pub(crate) branches: Vec<DevStatusBranch>,
1571 #[serde(default)]
1572 pub(crate) repositories: Vec<DevStatusRepositoryEntry>,
1573}
1574
1575#[derive(Deserialize)]
1576pub(crate) struct DevStatusPullRequest {
1577 #[serde(default)]
1578 pub(crate) id: String,
1579 #[serde(default)]
1580 pub(crate) name: String,
1581 #[serde(default)]
1582 pub(crate) status: String,
1583 #[serde(default)]
1584 pub(crate) url: String,
1585 #[serde(rename = "repositoryName", default)]
1586 pub(crate) repository_name: String,
1587 #[serde(default)]
1588 pub(crate) source: Option<DevStatusBranchRef>,
1589 #[serde(default)]
1590 pub(crate) destination: Option<DevStatusBranchRef>,
1591 #[serde(default)]
1592 pub(crate) author: Option<DevStatusAuthor>,
1593 #[serde(default)]
1594 pub(crate) reviewers: Vec<DevStatusReviewer>,
1595 #[serde(rename = "commentCount", default)]
1596 pub(crate) comment_count: Option<u32>,
1597 #[serde(rename = "lastUpdate", default)]
1598 pub(crate) last_update: Option<String>,
1599}
1600
1601#[derive(Deserialize)]
1602pub(crate) struct DevStatusBranchRef {
1603 #[serde(default)]
1604 pub(crate) branch: String,
1605}
1606
1607#[derive(Deserialize)]
1608pub(crate) struct DevStatusAuthor {
1609 #[serde(default)]
1610 pub(crate) name: String,
1611}
1612
1613#[derive(Deserialize)]
1614pub(crate) struct DevStatusReviewer {
1615 #[serde(default)]
1616 pub(crate) name: String,
1617}
1618
1619#[derive(Deserialize)]
1620pub(crate) struct DevStatusCommit {
1621 #[serde(default)]
1622 pub(crate) id: String,
1623 #[serde(rename = "displayId", default)]
1624 pub(crate) display_id: String,
1625 #[serde(default)]
1626 pub(crate) message: String,
1627 #[serde(default)]
1628 pub(crate) author: Option<DevStatusAuthor>,
1629 #[serde(rename = "authorTimestamp", default)]
1630 pub(crate) author_timestamp: Option<String>,
1631 #[serde(default)]
1632 pub(crate) url: String,
1633 #[serde(rename = "fileCount", default)]
1634 pub(crate) file_count: u32,
1635 #[serde(default)]
1636 pub(crate) merge: bool,
1637}
1638
1639#[derive(Deserialize)]
1640pub(crate) struct DevStatusBranch {
1641 #[serde(default)]
1642 pub(crate) name: String,
1643 #[serde(default)]
1644 pub(crate) url: String,
1645 #[serde(rename = "repositoryName", default)]
1646 pub(crate) repository_name: String,
1647 #[serde(rename = "createPullRequestUrl", default)]
1648 pub(crate) create_pr_url: Option<String>,
1649 #[serde(rename = "lastCommit", default)]
1650 pub(crate) last_commit: Option<DevStatusCommit>,
1651}
1652
1653#[derive(Deserialize)]
1654pub(crate) struct DevStatusRepositoryEntry {
1655 #[serde(default)]
1656 pub(crate) name: String,
1657 #[serde(default)]
1658 pub(crate) url: String,
1659 #[serde(default)]
1660 pub(crate) commits: Vec<DevStatusCommit>,
1661}
1662
1663#[derive(Deserialize)]
1666pub(crate) struct DevStatusSummaryResponse {
1667 #[serde(default)]
1668 pub(crate) summary: DevStatusSummaryData,
1669}
1670
1671#[derive(Deserialize, Default)]
1672pub(crate) struct DevStatusSummaryData {
1673 #[serde(default)]
1674 pub(crate) pullrequest: Option<DevStatusSummaryCategory>,
1675 #[serde(default)]
1676 pub(crate) branch: Option<DevStatusSummaryCategory>,
1677 #[serde(default)]
1678 pub(crate) repository: Option<DevStatusSummaryCategory>,
1679}
1680
1681#[derive(Deserialize)]
1682pub(crate) struct DevStatusSummaryCategory {
1683 pub(crate) overall: Option<DevStatusSummaryOverall>,
1684 #[serde(rename = "byInstanceType", default)]
1687 pub(crate) by_instance_type: HashMap<String, serde_json::Value>,
1688}
1689
1690#[derive(Deserialize)]
1691pub(crate) struct DevStatusSummaryOverall {
1692 #[serde(default)]
1693 pub(crate) count: u32,
1694}