use std::collections::HashMap;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize)]
pub struct JiraIssue {
pub key: String,
pub summary: String,
pub description_adf: Option<serde_json::Value>,
pub status: Option<String>,
pub issue_type: Option<String>,
pub assignee: Option<String>,
pub priority: Option<String>,
pub labels: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub custom_fields: Vec<JiraCustomField>,
}
#[derive(Debug, Clone, Default)]
pub enum FieldSelection {
#[default]
Standard,
Named(Vec<String>),
All,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraCustomField {
pub id: String,
pub name: String,
pub value: serde_json::Value,
}
#[derive(Debug, Clone, Default)]
pub struct EditMeta {
pub fields: std::collections::BTreeMap<String, EditMetaField>,
}
#[derive(Debug, Clone)]
pub struct EditMetaField {
pub name: String,
pub schema: EditMetaSchema,
pub allowed_values: Vec<String>,
}
#[derive(Debug, Clone, Default)]
pub struct EditMetaSchema {
pub kind: String,
pub custom: Option<String>,
pub items: Option<String>,
pub system: Option<String>,
}
impl EditMetaField {
pub fn is_adf_rich_text(&self) -> bool {
self.schema.custom.as_deref() == Some(TEXTAREA_CUSTOM_TYPE)
|| matches!(
self.schema.system.as_deref(),
Some("description" | "environment")
)
}
}
#[derive(Debug, Clone, Serialize)]
pub struct CreateMeta {
pub project: String,
pub issue_type: String,
pub fields: Vec<CreateMetaField>,
}
#[derive(Debug, Clone, Serialize)]
pub struct CreateMetaField {
pub field_id: String,
pub name: String,
pub required: bool,
pub schema_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub items: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub custom: Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub allowed_values: Vec<CreateMetaAllowedValue>,
#[serde(skip_serializing_if = "Option::is_none")]
pub default_value: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize)]
pub struct CreateMetaAllowedValue {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub children: Vec<Self>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JiraUser {
#[serde(rename = "displayName")]
pub display_name: String,
#[serde(rename = "emailAddress")]
pub email_address: Option<String>,
#[serde(rename = "accountId")]
pub account_id: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraWatcherList {
pub watchers: Vec<JiraUser>,
pub watch_count: u32,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraCreatedIssue {
pub key: String,
pub id: String,
pub self_url: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraSearchResult {
pub issues: Vec<JiraIssue>,
pub total: u32,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraUserSearchResult {
pub account_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub display_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub email_address: Option<String>,
pub active: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub account_type: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraUserSearchResults {
pub users: Vec<JiraUserSearchResult>,
pub count: u32,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraUserRecord {
pub account_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub display_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub email_address: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub active: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub account_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraUserGetResults {
pub users: Vec<JiraUserRecord>,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraComment {
pub id: String,
pub author: String,
pub body_adf: Option<serde_json::Value>,
pub created: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub updated: Option<String>,
}
#[derive(Debug, Clone, Copy, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum JiraVisibilityType {
Group,
Role,
}
#[derive(Debug, Clone)]
pub struct JiraVisibility {
pub ty: JiraVisibilityType,
pub value: String,
}
impl Serialize for JiraVisibility {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
use serde::ser::SerializeStruct;
let mut s = serializer.serialize_struct("JiraVisibility", 2)?;
s.serialize_field("type", &self.ty)?;
s.serialize_field("identifier", &self.value)?;
s.end()
}
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraProject {
pub id: String,
pub key: String,
pub name: String,
pub project_type: Option<String>,
pub lead: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraProjectList {
pub projects: Vec<JiraProject>,
pub total: u32,
}
pub(crate) const TEXTAREA_CUSTOM_TYPE: &str =
"com.atlassian.jira.plugin.system.customfieldtypes:textarea";
#[derive(Debug, Clone, Serialize)]
pub struct JiraField {
pub id: String,
pub name: String,
pub custom: bool,
pub schema_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub schema_custom: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraFieldOption {
pub id: String,
pub value: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct AgileBoard {
pub id: u64,
pub name: String,
pub board_type: String,
pub project_key: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct AgileBoardList {
pub boards: Vec<AgileBoard>,
pub total: u32,
}
#[derive(Debug, Clone, Serialize)]
pub struct AgileSprint {
pub id: u64,
pub name: String,
pub state: String,
pub start_date: Option<String>,
pub end_date: Option<String>,
pub goal: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct AgileSprintList {
pub sprints: Vec<AgileSprint>,
pub total: u32,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraProjectVersion {
pub id: String,
pub name: String,
pub description: Option<String>,
pub project_key: String,
pub released: bool,
pub archived: bool,
pub release_date: Option<String>,
pub start_date: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraProjectVersionList {
pub versions: Vec<JiraProjectVersion>,
pub total: u32,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraChangelogEntry {
pub id: String,
pub author: String,
pub created: String,
pub items: Vec<JiraChangelogItem>,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraChangelogItem {
pub field: String,
pub from_string: Option<String>,
pub to_string: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraLinkType {
pub id: String,
pub name: String,
pub inward: String,
pub outward: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraIssueLink {
pub id: String,
pub link_type: String,
pub direction: String,
pub linked_issue_key: String,
pub linked_issue_summary: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraRemoteIssueLink {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub global_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub relationship: Option<String>,
pub object: JiraRemoteIssueLinkObject,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraRemoteIssueLinkObject {
pub url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub summary: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub icon: Option<JiraRemoteIssueLinkIcon>,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraRemoteIssueLinkIcon {
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraAttachment {
pub id: String,
pub filename: String,
pub mime_type: String,
pub size: u64,
pub content_url: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraTransition {
pub id: String,
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub to_status: Option<JiraTransitionToStatus>,
#[serde(skip_serializing_if = "Option::is_none")]
pub has_screen: Option<bool>,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraTransitionToStatus {
pub id: String,
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub category: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraDevPullRequest {
pub id: String,
pub name: String,
pub status: String,
pub url: String,
pub repository_name: String,
pub source_branch: String,
pub destination_branch: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub author: Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub reviewers: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub comment_count: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub last_update: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraDevCommit {
pub id: String,
pub display_id: String,
pub message: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub author: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub timestamp: Option<String>,
pub url: String,
pub file_count: u32,
pub merge: bool,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraDevBranch {
pub name: String,
pub url: String,
pub repository_name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub create_pr_url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub last_commit: Option<JiraDevCommit>,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraDevRepository {
pub name: String,
pub url: String,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub commits: Vec<JiraDevCommit>,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraDevStatus {
#[serde(skip_serializing_if = "Vec::is_empty")]
pub pull_requests: Vec<JiraDevPullRequest>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub branches: Vec<JiraDevBranch>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub repositories: Vec<JiraDevRepository>,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraDevStatusCount {
pub count: u32,
pub providers: Vec<JiraDevProvider>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct JiraDevProvider {
pub instance_type: String,
pub name: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraDevStatusSummary {
pub pullrequest: JiraDevStatusCount,
pub branch: JiraDevStatusCount,
pub repository: JiraDevStatusCount,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraWorklog {
pub id: String,
pub author: String,
pub time_spent: String,
pub time_spent_seconds: u64,
pub started: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub comment: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct JiraWorklogList {
pub worklogs: Vec<JiraWorklog>,
pub total: u32,
}
#[derive(Deserialize)]
pub(crate) struct JiraIssueResponse {
pub(crate) key: String,
pub(crate) fields: JiraIssueFields,
}
#[derive(Deserialize)]
pub(crate) struct JiraIssueEnvelope {
pub(crate) key: String,
#[serde(default)]
pub(crate) fields: std::collections::BTreeMap<String, serde_json::Value>,
#[serde(default)]
pub(crate) names: std::collections::BTreeMap<String, String>,
}
impl JiraIssueEnvelope {
pub(crate) fn into_issue(self, selection: &FieldSelection) -> JiraIssue {
let Self {
key,
mut fields,
names,
} = self;
let description_adf = fields.remove("description").filter(|v| !v.is_null());
let summary = fields
.remove("summary")
.and_then(|v| v.as_str().map(str::to_string))
.unwrap_or_default();
let status = extract_named_field(fields.remove("status"));
let issue_type = extract_named_field(fields.remove("issuetype"));
let assignee = extract_display_name(fields.remove("assignee"));
let priority = extract_named_field(fields.remove("priority"));
let labels = fields
.remove("labels")
.and_then(|v| serde_json::from_value::<Vec<String>>(v).ok())
.unwrap_or_default();
let collect_customs = !matches!(selection, FieldSelection::Standard);
let custom_fields = if collect_customs {
fields
.into_iter()
.filter(|(_, value)| !value.is_null())
.map(|(id, value)| {
let name = names.get(&id).cloned().unwrap_or_else(|| id.clone());
JiraCustomField { id, name, value }
})
.collect()
} else {
Vec::new()
};
JiraIssue {
key,
summary,
description_adf,
status,
issue_type,
assignee,
priority,
labels,
custom_fields,
}
}
}
fn extract_named_field(value: Option<serde_json::Value>) -> Option<String> {
value
.and_then(|v| v.get("name").cloned())
.and_then(|n| n.as_str().map(str::to_string))
}
fn extract_display_name(value: Option<serde_json::Value>) -> Option<String> {
value
.and_then(|v| v.get("displayName").cloned())
.and_then(|n| n.as_str().map(str::to_string))
}
#[derive(Deserialize)]
pub(crate) struct JiraEditMetaResponse {
#[serde(default)]
pub(crate) fields: std::collections::BTreeMap<String, JiraEditMetaField>,
}
#[derive(Deserialize)]
pub(crate) struct JiraEditMetaField {
#[serde(default)]
pub(crate) name: Option<String>,
#[serde(default)]
pub(crate) schema: Option<JiraEditMetaSchemaRaw>,
#[serde(rename = "allowedValues", default)]
pub(crate) allowed_values: Vec<JiraAllowedValueRaw>,
}
impl JiraEditMetaField {
pub(crate) fn allowed_value_strings(&self) -> Vec<String> {
self.allowed_values
.iter()
.filter_map(|v| v.value.clone().or_else(|| v.name.clone()))
.collect()
}
}
#[derive(Deserialize)]
pub(crate) struct JiraEditMetaSchemaRaw {
#[serde(rename = "type", default)]
pub(crate) kind: Option<String>,
#[serde(default)]
pub(crate) custom: Option<String>,
#[serde(default)]
pub(crate) items: Option<String>,
#[serde(default)]
pub(crate) system: Option<String>,
}
impl From<Option<JiraEditMetaSchemaRaw>> for EditMetaSchema {
fn from(raw: Option<JiraEditMetaSchemaRaw>) -> Self {
raw.map_or_else(Self::default, |s| Self {
kind: s.kind.unwrap_or_default(),
custom: s.custom,
items: s.items,
system: s.system,
})
}
}
#[derive(Deserialize)]
pub(crate) struct JiraCreateMetaResponse {
#[serde(default)]
pub(crate) projects: Vec<JiraCreateMetaProject>,
}
#[derive(Deserialize)]
pub(crate) struct JiraCreateMetaProject {
#[serde(default)]
pub(crate) issuetypes: Vec<JiraCreateMetaIssueType>,
}
#[derive(Deserialize)]
pub(crate) struct JiraCreateMetaIssueType {
#[serde(default)]
pub(crate) fields: std::collections::BTreeMap<String, JiraEditMetaField>,
}
#[derive(Deserialize)]
pub(crate) struct JiraCreateMetaFullResponse {
#[serde(default)]
pub(crate) projects: Vec<JiraCreateMetaFullProject>,
}
#[derive(Deserialize)]
pub(crate) struct JiraCreateMetaFullProject {
#[serde(default)]
pub(crate) issuetypes: Vec<JiraCreateMetaFullIssueType>,
}
#[derive(Deserialize)]
pub(crate) struct JiraCreateMetaFullIssueType {
#[serde(default)]
pub(crate) fields: std::collections::BTreeMap<String, JiraCreateMetaFieldRaw>,
}
#[derive(Deserialize)]
pub(crate) struct JiraCreateMetaFieldRaw {
#[serde(default)]
pub(crate) name: Option<String>,
#[serde(default)]
pub(crate) required: bool,
#[serde(default)]
pub(crate) schema: Option<JiraCreateMetaSchemaRaw>,
#[serde(rename = "allowedValues", default)]
pub(crate) allowed_values: Vec<JiraAllowedValueRaw>,
#[serde(rename = "defaultValue", default)]
pub(crate) default_value: Option<serde_json::Value>,
}
#[derive(Deserialize)]
pub(crate) struct JiraCreateMetaSchemaRaw {
#[serde(rename = "type", default)]
pub(crate) kind: Option<String>,
#[serde(default)]
pub(crate) items: Option<String>,
#[serde(default)]
pub(crate) custom: Option<String>,
}
#[derive(Deserialize)]
pub(crate) struct JiraAllowedValueRaw {
#[serde(default)]
pub(crate) id: Option<String>,
#[serde(default)]
pub(crate) value: Option<String>,
#[serde(default)]
pub(crate) name: Option<String>,
#[serde(default)]
pub(crate) children: Vec<Self>,
}
impl JiraAllowedValueRaw {
pub(crate) fn into_allowed_value(self) -> CreateMetaAllowedValue {
CreateMetaAllowedValue {
id: self.id,
value: self.value.or(self.name),
children: self
.children
.into_iter()
.map(Self::into_allowed_value)
.collect(),
}
}
}
#[derive(Deserialize)]
pub(crate) struct JiraIssueFields {
pub(crate) summary: Option<String>,
pub(crate) description: Option<serde_json::Value>,
pub(crate) status: Option<JiraNameField>,
pub(crate) issuetype: Option<JiraNameField>,
pub(crate) assignee: Option<JiraAssigneeField>,
pub(crate) priority: Option<JiraNameField>,
#[serde(default)]
pub(crate) labels: Vec<String>,
}
#[derive(Deserialize)]
pub(crate) struct JiraNameField {
pub(crate) name: Option<String>,
}
#[derive(Deserialize)]
pub(crate) struct JiraAssigneeField {
#[serde(rename = "displayName")]
pub(crate) display_name: Option<String>,
}
#[derive(Deserialize)]
#[allow(dead_code)]
pub(crate) struct JiraSearchResponse {
pub(crate) issues: Vec<JiraIssueResponse>,
#[serde(default)]
pub(crate) total: u32,
#[serde(rename = "nextPageToken", default)]
pub(crate) next_page_token: Option<String>,
}
#[derive(Deserialize)]
pub(crate) struct JiraTransitionsResponse {
pub(crate) transitions: Vec<JiraTransitionEntry>,
}
#[derive(Deserialize)]
pub(crate) struct JiraTransitionEntry {
pub(crate) id: String,
pub(crate) name: String,
#[serde(default)]
pub(crate) to: Option<JiraTransitionToEntry>,
#[serde(rename = "hasScreen", default)]
pub(crate) has_screen: Option<bool>,
}
#[derive(Deserialize)]
pub(crate) struct JiraTransitionToEntry {
pub(crate) id: String,
pub(crate) name: String,
#[serde(rename = "statusCategory", default)]
pub(crate) status_category: Option<JiraStatusCategoryEntry>,
}
#[derive(Deserialize)]
pub(crate) struct JiraStatusCategoryEntry {
#[serde(default)]
pub(crate) key: Option<String>,
}
#[derive(Deserialize)]
pub(crate) struct JiraCommentsResponse {
#[serde(default)]
pub(crate) comments: Vec<JiraCommentEntry>,
#[serde(default)]
pub(crate) total: u32,
#[serde(rename = "startAt", default)]
pub(crate) start_at: u32,
#[serde(rename = "maxResults", default)]
#[allow(dead_code)]
pub(crate) max_results: u32,
}
#[derive(Deserialize)]
pub(crate) struct JiraCommentEntry {
pub(crate) id: String,
pub(crate) author: Option<JiraCommentAuthor>,
pub(crate) body: Option<serde_json::Value>,
pub(crate) created: Option<String>,
#[serde(default)]
pub(crate) updated: Option<String>,
}
#[derive(Deserialize)]
pub(crate) struct JiraCommentAuthor {
#[serde(rename = "displayName")]
pub(crate) display_name: Option<String>,
}
#[derive(Deserialize)]
pub(crate) struct JiraWorklogResponse {
#[serde(default)]
pub(crate) worklogs: Vec<JiraWorklogEntry>,
#[serde(default)]
pub(crate) total: u32,
}
#[derive(Deserialize)]
pub(crate) struct JiraWorklogEntry {
pub(crate) id: String,
pub(crate) author: Option<JiraCommentAuthor>,
#[serde(rename = "timeSpent")]
pub(crate) time_spent: Option<String>,
#[serde(rename = "timeSpentSeconds", default)]
pub(crate) time_spent_seconds: u64,
pub(crate) started: Option<String>,
pub(crate) comment: Option<serde_json::Value>,
}
#[derive(Deserialize)]
pub(crate) struct JiraUserSearchEntry {
#[serde(rename = "accountId")]
pub(crate) account_id: String,
#[serde(rename = "displayName", default)]
pub(crate) display_name: Option<String>,
#[serde(rename = "emailAddress", default)]
pub(crate) email_address: Option<String>,
#[serde(default)]
pub(crate) active: bool,
#[serde(rename = "accountType", default)]
pub(crate) account_type: Option<String>,
}
#[derive(Deserialize)]
#[allow(dead_code)]
pub(crate) struct AgileBoardListResponse {
pub(crate) values: Vec<AgileBoardEntry>,
#[serde(default)]
pub(crate) total: u32,
#[serde(rename = "isLast", default)]
pub(crate) is_last: bool,
}
#[derive(Deserialize)]
pub(crate) struct AgileBoardEntry {
pub(crate) id: u64,
pub(crate) name: String,
#[serde(rename = "type")]
pub(crate) board_type: String,
pub(crate) location: Option<AgileBoardLocation>,
}
#[derive(Deserialize)]
pub(crate) struct AgileBoardLocation {
#[serde(rename = "projectKey")]
pub(crate) project_key: Option<String>,
}
#[derive(Deserialize)]
#[allow(dead_code)]
pub(crate) struct AgileIssueListResponse {
pub(crate) issues: Vec<JiraIssueResponse>,
#[serde(default)]
pub(crate) total: u32,
#[serde(rename = "isLast", default)]
pub(crate) is_last: bool,
}
#[derive(Deserialize)]
#[allow(dead_code)]
pub(crate) struct AgileSprintListResponse {
pub(crate) values: Vec<AgileSprintEntry>,
#[serde(default)]
pub(crate) total: u32,
#[serde(rename = "isLast", default)]
pub(crate) is_last: bool,
}
#[derive(Deserialize)]
pub(crate) struct AgileSprintEntry {
pub(crate) id: u64,
pub(crate) name: String,
pub(crate) state: String,
#[serde(rename = "startDate")]
pub(crate) start_date: Option<String>,
#[serde(rename = "endDate")]
pub(crate) end_date: Option<String>,
pub(crate) goal: Option<String>,
}
#[derive(Deserialize)]
pub(crate) struct JiraProjectVersionEntry {
pub(crate) id: String,
pub(crate) name: String,
#[serde(default)]
pub(crate) description: Option<String>,
#[serde(default)]
pub(crate) released: bool,
#[serde(default)]
pub(crate) archived: bool,
#[serde(rename = "releaseDate", default)]
pub(crate) release_date: Option<String>,
#[serde(rename = "startDate", default)]
pub(crate) start_date: Option<String>,
}
#[derive(Deserialize)]
pub(crate) struct JiraIssueLinksResponse {
pub(crate) fields: JiraIssueLinksFields,
}
#[derive(Deserialize)]
pub(crate) struct JiraIssueLinksFields {
#[serde(default)]
pub(crate) issuelinks: Vec<JiraIssueLinkEntry>,
}
#[derive(Deserialize)]
pub(crate) struct JiraIssueLinkEntry {
pub(crate) id: String,
#[serde(rename = "type")]
pub(crate) link_type: JiraIssueLinkType,
#[serde(rename = "inwardIssue")]
pub(crate) inward_issue: Option<JiraIssueLinkIssue>,
#[serde(rename = "outwardIssue")]
pub(crate) outward_issue: Option<JiraIssueLinkIssue>,
}
#[derive(Deserialize)]
pub(crate) struct JiraIssueLinkType {
pub(crate) name: String,
}
#[derive(Deserialize)]
pub(crate) struct JiraIssueLinkIssue {
pub(crate) key: String,
pub(crate) fields: Option<JiraIssueLinkIssueFields>,
}
#[derive(Deserialize)]
pub(crate) struct JiraIssueLinkIssueFields {
pub(crate) summary: Option<String>,
}
#[derive(Deserialize)]
pub(crate) struct JiraRemoteIssueLinkEntry {
pub(crate) id: serde_json::Value,
#[serde(rename = "globalId", default)]
pub(crate) global_id: Option<String>,
#[serde(default)]
pub(crate) relationship: Option<String>,
pub(crate) object: JiraRemoteIssueLinkObjectEntry,
}
#[derive(Deserialize)]
pub(crate) struct JiraRemoteIssueLinkObjectEntry {
pub(crate) url: String,
#[serde(default)]
pub(crate) title: Option<String>,
#[serde(default)]
pub(crate) summary: Option<String>,
#[serde(default)]
pub(crate) icon: Option<JiraRemoteIssueLinkIconEntry>,
}
#[derive(Deserialize)]
pub(crate) struct JiraRemoteIssueLinkIconEntry {
#[serde(rename = "url16x16", default)]
pub(crate) url: Option<String>,
#[serde(default)]
pub(crate) title: Option<String>,
}
#[derive(Deserialize)]
pub(crate) struct JiraLinkTypesResponse {
#[serde(rename = "issueLinkTypes")]
pub(crate) issue_link_types: Vec<JiraLinkTypeEntry>,
}
#[derive(Deserialize)]
pub(crate) struct JiraLinkTypeEntry {
pub(crate) id: String,
pub(crate) name: String,
pub(crate) inward: String,
pub(crate) outward: String,
}
#[derive(Deserialize)]
pub(crate) struct JiraAttachmentIssueResponse {
pub(crate) fields: JiraAttachmentFields,
}
#[derive(Deserialize)]
pub(crate) struct JiraAttachmentFields {
#[serde(default)]
pub(crate) attachment: Vec<JiraAttachmentEntry>,
}
#[derive(Deserialize)]
pub(crate) struct JiraAttachmentEntry {
pub(crate) id: String,
pub(crate) filename: String,
#[serde(rename = "mimeType")]
pub(crate) mime_type: String,
pub(crate) size: u64,
pub(crate) content: String,
}
#[derive(Deserialize)]
#[allow(dead_code)]
pub(crate) struct JiraChangelogResponse {
pub(crate) values: Vec<JiraChangelogEntryResponse>,
#[serde(default)]
pub(crate) total: u32,
#[serde(rename = "isLast", default)]
pub(crate) is_last: bool,
}
#[derive(Deserialize)]
pub(crate) struct JiraChangelogEntryResponse {
pub(crate) id: String,
pub(crate) author: Option<JiraCommentAuthor>,
pub(crate) created: Option<String>,
#[serde(default)]
pub(crate) items: Vec<JiraChangelogItemResponse>,
}
#[derive(Deserialize)]
pub(crate) struct JiraChangelogItemResponse {
pub(crate) field: String,
#[serde(rename = "fromString")]
pub(crate) from_string: Option<String>,
#[serde(rename = "toString")]
pub(crate) to_string: Option<String>,
}
#[derive(Deserialize)]
pub(crate) struct JiraFieldEntry {
pub(crate) id: String,
pub(crate) name: String,
#[serde(default)]
pub(crate) custom: bool,
pub(crate) schema: Option<JiraFieldSchema>,
}
#[derive(Deserialize)]
pub(crate) struct JiraFieldSchema {
#[serde(rename = "type")]
pub(crate) schema_type: Option<String>,
pub(crate) custom: Option<String>,
}
#[derive(Deserialize)]
pub(crate) struct JiraFieldContextsResponse {
pub(crate) values: Vec<JiraFieldContextEntry>,
}
#[derive(Deserialize)]
pub(crate) struct JiraFieldContextEntry {
pub(crate) id: String,
}
#[derive(Deserialize)]
pub(crate) struct JiraFieldOptionsResponse {
pub(crate) values: Vec<JiraFieldOptionEntry>,
}
#[derive(Deserialize)]
pub(crate) struct JiraFieldOptionEntry {
pub(crate) id: String,
pub(crate) value: String,
}
#[derive(Deserialize)]
#[allow(dead_code)]
pub(crate) struct JiraProjectSearchResponse {
pub(crate) values: Vec<JiraProjectEntry>,
pub(crate) total: u32,
#[serde(rename = "isLast", default)]
pub(crate) is_last: bool,
}
#[derive(Deserialize)]
pub(crate) struct JiraProjectEntry {
pub(crate) id: String,
pub(crate) key: String,
pub(crate) name: String,
#[serde(rename = "projectTypeKey")]
pub(crate) project_type_key: Option<String>,
pub(crate) lead: Option<JiraProjectLead>,
}
#[derive(Deserialize)]
pub(crate) struct JiraProjectLead {
#[serde(rename = "displayName")]
pub(crate) display_name: Option<String>,
}
#[derive(Deserialize)]
pub(crate) struct JiraCreateResponse {
pub(crate) key: String,
pub(crate) id: String,
#[serde(rename = "self")]
pub(crate) self_url: String,
}
#[derive(Deserialize)]
pub(crate) struct JiraIssueIdResponse {
pub(crate) id: String,
}
#[derive(Deserialize)]
pub(crate) struct DevStatusResponse {
#[serde(default)]
pub(crate) detail: Vec<DevStatusDetail>,
}
#[derive(Deserialize)]
pub(crate) struct DevStatusDetail {
#[serde(rename = "pullRequests", default)]
pub(crate) pull_requests: Vec<DevStatusPullRequest>,
#[serde(default)]
pub(crate) branches: Vec<DevStatusBranch>,
#[serde(default)]
pub(crate) repositories: Vec<DevStatusRepositoryEntry>,
}
#[derive(Deserialize)]
pub(crate) struct DevStatusPullRequest {
#[serde(default)]
pub(crate) id: String,
#[serde(default)]
pub(crate) name: String,
#[serde(default)]
pub(crate) status: String,
#[serde(default)]
pub(crate) url: String,
#[serde(rename = "repositoryName", default)]
pub(crate) repository_name: String,
#[serde(default)]
pub(crate) source: Option<DevStatusBranchRef>,
#[serde(default)]
pub(crate) destination: Option<DevStatusBranchRef>,
#[serde(default)]
pub(crate) author: Option<DevStatusAuthor>,
#[serde(default)]
pub(crate) reviewers: Vec<DevStatusReviewer>,
#[serde(rename = "commentCount", default)]
pub(crate) comment_count: Option<u32>,
#[serde(rename = "lastUpdate", default)]
pub(crate) last_update: Option<String>,
}
#[derive(Deserialize)]
pub(crate) struct DevStatusBranchRef {
#[serde(default)]
pub(crate) branch: String,
}
#[derive(Deserialize)]
pub(crate) struct DevStatusAuthor {
#[serde(default)]
pub(crate) name: String,
}
#[derive(Deserialize)]
pub(crate) struct DevStatusReviewer {
#[serde(default)]
pub(crate) name: String,
}
#[derive(Deserialize)]
pub(crate) struct DevStatusCommit {
#[serde(default)]
pub(crate) id: String,
#[serde(rename = "displayId", default)]
pub(crate) display_id: String,
#[serde(default)]
pub(crate) message: String,
#[serde(default)]
pub(crate) author: Option<DevStatusAuthor>,
#[serde(rename = "authorTimestamp", default)]
pub(crate) author_timestamp: Option<String>,
#[serde(default)]
pub(crate) url: String,
#[serde(rename = "fileCount", default)]
pub(crate) file_count: u32,
#[serde(default)]
pub(crate) merge: bool,
}
#[derive(Deserialize)]
pub(crate) struct DevStatusBranch {
#[serde(default)]
pub(crate) name: String,
#[serde(default)]
pub(crate) url: String,
#[serde(rename = "repositoryName", default)]
pub(crate) repository_name: String,
#[serde(rename = "createPullRequestUrl", default)]
pub(crate) create_pr_url: Option<String>,
#[serde(rename = "lastCommit", default)]
pub(crate) last_commit: Option<DevStatusCommit>,
}
#[derive(Deserialize)]
pub(crate) struct DevStatusRepositoryEntry {
#[serde(default)]
pub(crate) name: String,
#[serde(default)]
pub(crate) url: String,
#[serde(default)]
pub(crate) commits: Vec<DevStatusCommit>,
}
#[derive(Deserialize)]
pub(crate) struct DevStatusSummaryResponse {
#[serde(default)]
pub(crate) summary: DevStatusSummaryData,
}
#[derive(Deserialize, Default)]
pub(crate) struct DevStatusSummaryData {
#[serde(default)]
pub(crate) pullrequest: Option<DevStatusSummaryCategory>,
#[serde(default)]
pub(crate) branch: Option<DevStatusSummaryCategory>,
#[serde(default)]
pub(crate) repository: Option<DevStatusSummaryCategory>,
}
#[derive(Deserialize)]
pub(crate) struct DevStatusSummaryCategory {
pub(crate) overall: Option<DevStatusSummaryOverall>,
#[serde(rename = "byInstanceType", default)]
pub(crate) by_instance_type: HashMap<String, serde_json::Value>,
}
#[derive(Deserialize)]
pub(crate) struct DevStatusSummaryOverall {
#[serde(default)]
pub(crate) count: u32,
}