use crates::chrono::{DateTime, NaiveDate, Utc};
use crates::serde::{Deserialize, Deserializer, Serialize, Serializer};
use crates::serde::de::{DeserializeOwned, Error, Unexpected};
use crates::serde_json::{self, Value};
use std::fmt::{self, Display, Formatter};
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub struct UserId(u64);
impl_id!(UserId);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UserState {
Active,
Blocked,
LdapBlocked,
}
enum_serialize!(UserState -> "user state",
Active => "active",
Blocked => "blocked",
LdapBlocked => "ldap_blocked",
);
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct UserBasic {
pub username: String,
pub name: String,
pub id: UserId,
pub state: UserState,
pub avatar_url: String,
pub web_url: String,
}
pub trait UserResult: DeserializeOwned {}
impl<T: DeserializeOwned + Into<UserBasic>> UserResult for T {}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct User {
pub username: String,
pub name: String,
pub id: UserId,
pub state: UserState,
pub avatar_url: String,
pub web_url: String,
pub created_at: DateTime<Utc>,
pub is_admin: Option<bool>,
pub bio: Option<String>,
pub location: Option<String>,
pub skype: String,
pub linkedin: String,
pub twitter: String,
pub website_url: String,
pub organization: Option<String>,
}
impl From<User> for UserBasic {
fn from(user: User) -> Self {
UserBasic {
username: user.username,
name: user.name,
id: user.id,
state: user.state,
avatar_url: user.avatar_url,
web_url: user.web_url,
}
}
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Identity {
pub provider: String,
pub extern_uid: String,
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub struct ThemeId(u64);
impl_id!(ThemeId);
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub struct ColorSchemeId(u64);
impl_id!(ColorSchemeId);
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct UserPublic {
pub username: String,
pub name: String,
pub id: UserId,
pub state: UserState,
pub avatar_url: String,
pub web_url: String,
pub created_at: DateTime<Utc>,
pub is_admin: Option<bool>,
pub bio: Option<String>,
pub location: Option<String>,
pub skype: String,
pub linkedin: String,
pub twitter: String,
pub website_url: String,
pub organization: Option<String>,
pub last_sign_in_at: Option<DateTime<Utc>>,
pub last_activity_on: Option<NaiveDate>,
pub confirmed_at: Option<DateTime<Utc>>,
pub email: String,
pub theme_id: Option<ThemeId>,
pub color_scheme_id: ColorSchemeId,
pub projects_limit: u64,
pub current_sign_in_at: Option<DateTime<Utc>>,
pub identities: Vec<Identity>,
pub can_create_group: bool,
pub can_create_project: bool,
pub two_factor_enabled: bool,
pub external: bool,
}
impl From<UserPublic> for UserBasic {
fn from(user: UserPublic) -> Self {
UserBasic {
username: user.username,
name: user.name,
id: user.id,
state: user.state,
avatar_url: user.avatar_url,
web_url: user.web_url,
}
}
}
impl From<UserPublic> for User {
fn from(user: UserPublic) -> Self {
User {
username: user.username,
name: user.name,
id: user.id,
state: user.state,
avatar_url: user.avatar_url,
web_url: user.web_url,
created_at: user.created_at,
is_admin: user.is_admin,
bio: user.bio,
location: user.location,
skype: user.skype,
linkedin: user.linkedin,
twitter: user.twitter,
website_url: user.website_url,
organization: user.organization,
}
}
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub struct EmailId(u64);
impl_id!(EmailId);
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Email {
pub id: EmailId,
pub email: String,
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub struct HookId(u64);
impl_id!(HookId);
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Hook {
pub id: HookId,
pub url: String,
pub created_at: DateTime<Utc>,
pub push_events: bool,
pub tag_push_events: bool,
pub enable_ssl_verification: bool,
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ProjectHook {
pub id: HookId,
pub url: String,
pub created_at: DateTime<Utc>,
pub project_id: ProjectId,
pub push_events: bool,
pub tag_push_events: bool,
pub issues_events: bool,
pub merge_requests_events: bool,
pub note_events: bool,
pub repository_update_events: bool,
pub enable_ssl_verification: bool,
pub job_events: bool,
pub pipeline_events: bool,
pub wiki_page_events: bool,
}
impl From<ProjectHook> for Hook {
fn from(hook: ProjectHook) -> Self {
Hook {
id: hook.id,
url: hook.url,
created_at: hook.created_at,
push_events: hook.push_events,
tag_push_events: hook.tag_push_events,
enable_ssl_verification: hook.enable_ssl_verification,
}
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct WebhookEvents {
job: bool,
issues: bool,
confidential_issues: bool,
merge_requests: bool,
note: bool,
pipeline: bool,
push: bool,
wiki_page: bool,
}
impl WebhookEvents {
pub fn new() -> Self {
WebhookEvents {
job: false,
issues: false,
confidential_issues: false,
merge_requests: false,
note: false,
pipeline: false,
push: false,
wiki_page: false,
}
}
with_event!{with_job, job}
with_event!{with_issues, issues}
with_event!{with_confidential_issues, issues}
with_event!{with_merge_requests, merge_requests}
with_event!{with_note, note}
with_event!{with_pipeline, pipeline}
with_event!{with_push, push}
with_event!{with_wiki_page, wiki_page}
get_event!{job}
get_event!{issues}
get_event!{confidential_issues}
get_event!{merge_requests}
get_event!{note}
get_event!{pipeline}
get_event!{push}
get_event!{wiki_page}
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub struct ProjectId(u64);
impl_id!(ProjectId);
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct BasicProjectDetails {
pub id: ProjectId,
pub name: String,
pub name_with_namespace: String,
pub path: String,
pub path_with_namespace: String,
pub http_url_to_repo: String,
pub web_url: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum VisibilityLevel {
Public,
Internal,
Private,
}
enum_serialize!(VisibilityLevel -> "visibility level",
Public => "public",
Internal => "internal",
Private => "private",
);
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct SharedGroup {
pub group_id: GroupId,
pub group_name: String,
pub group_access_level: u64,
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
pub struct MemberAccess {
pub access_level: u64,
pub notification_level: Option<u64>,
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
pub struct Permissions {
pub project_access: Option<MemberAccess>,
pub group_access: Option<MemberAccess>,
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ProjectNamespaceAvatar {
pub url: Option<String>,
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
struct ProjectLinks {
#[serde(rename="self")]
self_: String,
issues: Option<String>,
merge_requests: Option<String>,
repo_branches: String,
labels: String,
events: String,
members: String,
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Project {
pub id: ProjectId,
pub description: Option<String>,
pub default_branch: Option<String>,
pub tag_list: Vec<String>,
pub archived: bool,
pub visibility: VisibilityLevel,
pub ssh_url_to_repo: String,
pub http_url_to_repo: String,
pub web_url: String,
pub owner: Option<UserBasic>,
pub name: String,
pub name_with_namespace: String,
pub path: String,
pub path_with_namespace: String,
pub container_registry_enabled: Option<bool>,
pub created_at: DateTime<Utc>,
pub last_activity_at: DateTime<Utc>,
pub shared_runners_enabled: bool,
pub lfs_enabled: bool,
pub creator_id: UserId,
pub namespace: Namespace,
pub forked_from_project: Option<BasicProjectDetails>,
pub avatar_url: Option<String>,
pub ci_config_path: Option<String>,
pub import_error: Option<String>,
pub star_count: u64,
pub forks_count: u64,
pub open_issues_count: Option<u64>,
pub runners_token: Option<String>,
pub public_jobs: bool,
pub shared_with_groups: Vec<SharedGroup>,
pub only_allow_merge_if_pipeline_succeeds: Option<bool>,
pub only_allow_merge_if_all_discussions_are_resolved: Option<bool>,
pub printing_merge_request_link_enabled: Option<bool>,
pub request_access_enabled: bool,
pub jobs_enabled: bool,
pub resolve_outdated_diff_discussions: Option<bool>,
pub issues_enabled: bool,
pub merge_requests_enabled: bool,
pub snippets_enabled: bool,
pub wiki_enabled: bool,
pub statistics: Option<ProjectStatistics>,
pub permissions: Option<Permissions>,
_links: Option<ProjectLinks>,
}
#[cfg(test)]
impl Project {
pub fn has_links(&self) -> bool {
self._links.is_some()
}
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
pub struct ProjectStatistics {
pub commit_count: u64,
pub storage_size: u64,
pub repository_size: u64,
pub lfs_objects_size: u64,
pub job_artifacts_size: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum AccessLevel {
Anonymous,
Guest,
Reporter,
Developer,
Master,
Owner,
}
impl From<AccessLevel> for u64 {
fn from(access: AccessLevel) -> Self {
match access {
AccessLevel::Anonymous => 0,
AccessLevel::Guest => 10,
AccessLevel::Reporter => 20,
AccessLevel::Developer => 30,
AccessLevel::Master => 40,
AccessLevel::Owner => 50,
}
}
}
impl From<u64> for AccessLevel {
fn from(access: u64) -> Self {
if access >= 50 {
AccessLevel::Owner
} else if access >= 40 {
AccessLevel::Master
} else if access >= 30 {
AccessLevel::Developer
} else if access >= 20 {
AccessLevel::Reporter
} else if access >= 10 {
AccessLevel::Guest
} else {
AccessLevel::Anonymous
}
}
}
impl Display for AccessLevel {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}", Into::<u64>::into(self.clone()))
}
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Member {
pub username: String,
pub name: String,
pub id: UserId,
pub state: UserState,
pub avatar_url: String,
pub web_url: String,
pub access_level: u64,
pub expires_at: Option<NaiveDate>,
}
impl From<Member> for UserBasic {
fn from(member: Member) -> Self {
UserBasic {
username: member.username,
name: member.name,
id: member.id,
state: member.state,
avatar_url: member.avatar_url,
web_url: member.web_url,
}
}
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct AccessRequester {
pub username: String,
pub name: String,
pub id: UserId,
pub state: UserState,
pub avatar_url: String,
pub web_url: String,
pub requested_at: DateTime<Utc>,
}
impl From<AccessRequester> for UserBasic {
fn from(member: AccessRequester) -> Self {
UserBasic {
username: member.username,
name: member.name,
id: member.id,
state: member.state,
avatar_url: member.avatar_url,
web_url: member.web_url,
}
}
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub struct GroupId(u64);
impl_id!(GroupId);
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Group {
pub id: GroupId,
pub name: String,
pub path: String,
pub description: Option<String>,
pub visibility: VisibilityLevel,
pub lfs_enabled: bool,
pub avatar_url: String,
pub web_url: String,
pub request_access_enabled: bool,
pub full_name: String,
pub full_path: String,
pub parent_id: Option<GroupId>,
pub statistics: Option<GroupStatistics>,
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
pub struct GroupStatistics {
pub storage_size: u64,
pub repository_size: u64,
pub lfs_objects_size: u64,
pub job_artifacts_size: u64,
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct GroupDetail {
pub id: GroupId,
pub name: String,
pub path: String,
pub description: Option<String>,
pub visibility: VisibilityLevel,
pub lfs_enabled: bool,
pub avatar_url: String,
pub web_url: String,
pub projects: Vec<Project>,
pub shared_projects: Vec<Project>,
pub request_access_enabled: bool,
pub full_name: String,
pub full_path: String,
pub parent_id: Option<GroupId>,
pub statistics: Option<GroupStatistics>,
}
impl From<GroupDetail> for Group {
fn from(detail: GroupDetail) -> Self {
Group {
id: detail.id,
name: detail.name,
path: detail.path,
description: detail.description,
visibility: detail.visibility,
lfs_enabled: detail.lfs_enabled,
avatar_url: detail.avatar_url,
web_url: detail.web_url,
request_access_enabled: detail.request_access_enabled,
full_name: detail.full_name,
full_path: detail.full_path,
parent_id: detail.parent_id,
statistics: detail.statistics,
}
}
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RepoBranch {
pub name: String,
pub commit: Option<RepoCommit>,
pub merged: Option<bool>,
pub protected: Option<bool>,
pub developers_can_push: Option<bool>,
pub developers_can_merge: Option<bool>,
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct ObjectId(String);
impl ObjectId {
pub fn new<O: ToString>(oid: O) -> Self {
ObjectId(oid.to_string())
}
pub fn value(&self) -> &String {
&self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ObjectType {
Tree,
Blob,
}
enum_serialize!(ObjectType -> "object type",
Tree => "tree",
Blob => "blob",
);
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RepoTreeObject {
pub id: ObjectId,
pub name: String,
#[serde(rename="type")]
pub type_: ObjectType,
pub path: String,
pub mode: String,
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RepoCommit {
pub id: ObjectId,
pub short_id: ObjectId,
pub title: String,
pub parent_ids: Vec<ObjectId>,
pub author_name: String,
pub author_email: String,
pub authored_date: DateTime<Utc>,
pub committer_name: String,
pub committer_email: String,
pub committed_date: DateTime<Utc>,
pub created_at: DateTime<Utc>,
pub message: String,
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
pub struct RepoCommitStats {
pub additions: u64,
pub deletions: u64,
pub total: u64,
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RepoCommitDetail {
pub id: ObjectId,
pub short_id: ObjectId,
pub title: String,
pub parent_ids: Vec<ObjectId>,
pub author_name: String,
pub author_email: String,
pub authored_date: DateTime<Utc>,
pub committer_name: String,
pub committer_email: String,
pub committed_date: DateTime<Utc>,
pub created_at: DateTime<Utc>,
pub message: String,
pub stats: Option<RepoCommitStats>,
pub last_pipeline: Option<PipelineBasic>,
pub project_id: ProjectId,
status: Value,
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub struct SnippetId(u64);
impl_id!(SnippetId);
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ProjectSnippet {
pub id: SnippetId,
pub title: String,
pub file_name: String,
pub author: UserBasic,
pub updated_at: DateTime<Utc>,
pub created_at: DateTime<Utc>,
pub expires_at: Option<DateTime<Utc>>,
pub web_url: String,
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RepoDiff {
pub old_path: String,
pub new_path: String,
pub a_mode: String,
pub b_mode: String,
pub diff: String,
pub new_file: bool,
pub renamed_file: bool,
pub deleted_file: bool,
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub struct MilestoneId(u64);
impl_id!(MilestoneId);
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub struct MilestoneInternalId(u64);
impl_id!(MilestoneInternalId);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MilestoneState {
Active,
Closed,
}
enum_serialize!(MilestoneState -> "milestone type",
Active => "active",
Closed => "closed",
);
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Milestone {
pub id: MilestoneId,
pub iid: MilestoneInternalId,
pub project_id: ProjectId,
pub title: String,
pub description: String,
pub state: MilestoneState,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub due_date: Option<NaiveDate>,
pub start_date: Option<NaiveDate>,
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub struct IssueId(u64);
impl_id!(IssueId);
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub struct IssueInternalId(u64);
impl_id!(IssueInternalId);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IssueState {
Opened,
Closed,
Reopened,
}
enum_serialize!(IssueState -> "issue type",
Opened => "opened",
Closed => "closed",
Reopened => "reopened",
);
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
struct IssueLinks {
#[serde(rename="self")]
self_: String,
notes: String,
award_emoji: String,
project: String,
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Issue {
pub id: IssueId,
pub iid: IssueInternalId,
pub project_id: ProjectId,
pub title: String,
pub description: Option<String>,
pub state: IssueState,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub closed_at: Option<DateTime<Utc>>,
pub labels: Vec<String>,
pub milestone: Option<Milestone>,
pub author: UserBasic,
pub assignee: Option<UserBasic>,
pub assignees: Option<Vec<UserBasic>>,
pub subscribed: Option<bool>,
pub time_stats: IssuableTimeStats,
pub user_notes_count: u64,
pub upvotes: u64,
pub downvotes: u64,
pub due_date: Option<NaiveDate>,
pub confidential: bool,
pub discussion_locked: Option<bool>,
pub web_url: String,
_links: Option<IssueLinks>,
}
#[cfg(test)]
impl Issue {
pub fn has_links(&self) -> bool {
self._links.is_some()
}
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct IssuableTimeStats {
pub time_estimate: u64,
pub total_time_spent: u64,
pub human_time_estimate: Option<String>,
pub human_total_time_spent: Option<String>,
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub struct ExternalIssueId(u64);
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ExternalIssue {
pub id: ExternalIssueId,
pub title: String,
}
#[derive(Debug, Clone)]
pub enum IssueReference {
Internal(Issue),
External(ExternalIssue),
}
impl Serialize for IssueReference {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match *self {
IssueReference::Internal(ref issue) => issue.serialize(serializer),
IssueReference::External(ref issue) => issue.serialize(serializer),
}
}
}
impl<'de> Deserialize<'de> for IssueReference {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>,
{
let val = <Value as Deserialize>::deserialize(deserializer)?;
serde_json::from_value::<Issue>(val.clone())
.map(IssueReference::Internal)
.or_else(|_| serde_json::from_value::<ExternalIssue>(val).map(IssueReference::External))
.map_err(|err| D::Error::custom(format!("invalid issue reference: {:?}", err)))
}
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub struct MergeRequestId(u64);
impl_id!(MergeRequestId);
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub struct MergeRequestInternalId(u64);
impl_id!(MergeRequestInternalId);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MergeStatus {
Unchecked,
CanBeMerged,
CannotBeMerged,
}
enum_serialize!(MergeStatus -> "merge status",
Unchecked => "unchecked",
CanBeMerged => "can_be_merged",
CannotBeMerged => "cannot_be_merged",
);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MergeRequestState {
Opened,
Closed,
Reopened,
Merged,
Locked,
}
enum_serialize!(MergeRequestState -> "merge request state",
Opened => "opened",
Closed => "closed",
Reopened => "reopened",
Merged => "merged",
Locked => "locked",
);
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct MergeRequest {
pub id: MergeRequestId,
pub iid: MergeRequestInternalId,
pub project_id: ProjectId,
pub title: String,
pub description: Option<String>,
pub state: MergeRequestState,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub target_branch: String,
pub source_branch: String,
pub upvotes: u64,
pub downvotes: u64,
pub author: UserBasic,
pub assignee: Option<UserBasic>,
pub assignees: Option<Vec<UserBasic>>,
pub source_project_id: ProjectId,
pub target_project_id: ProjectId,
pub labels: Vec<String>,
pub work_in_progress: bool,
pub milestone: Option<Milestone>,
pub merge_when_pipeline_succeeds: bool,
pub merge_status: MergeStatus,
pub sha: Option<ObjectId>,
pub merge_commit_sha: Option<ObjectId>,
pub subscribed: Option<bool>,
pub time_stats: IssuableTimeStats,
pub changes_count: Option<String>,
pub user_notes_count: u64,
pub discussion_locked: Option<bool>,
pub should_remove_source_branch: Option<bool>,
pub force_remove_source_branch: Option<bool>,
pub web_url: String,
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct MergeRequestChanges {
pub id: MergeRequestId,
pub iid: MergeRequestInternalId,
pub project_id: ProjectId,
pub title: String,
pub description: Option<String>,
pub state: MergeRequestState,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub target_branch: String,
pub source_branch: String,
pub upvotes: u64,
pub downvotes: u64,
pub author: UserBasic,
pub assignee: Option<UserBasic>,
pub assignees: Option<Vec<UserBasic>>,
pub source_project_id: ProjectId,
pub target_project_id: ProjectId,
pub labels: Vec<String>,
pub work_in_progress: bool,
pub milestone: Option<Milestone>,
pub merge_when_pipeline_succeeds: bool,
pub merge_status: MergeStatus,
pub sha: Option<ObjectId>,
pub merge_commit_sha: Option<ObjectId>,
pub subscribed: Option<bool>,
pub time_stats: IssuableTimeStats,
pub changes_count: Option<String>,
pub user_notes_count: u64,
pub discussion_locked: Option<bool>,
pub should_remove_source_branch: Option<bool>,
pub force_remove_source_branch: Option<bool>,
pub web_url: String,
pub changes: Vec<RepoDiff>,
}
impl From<MergeRequestChanges> for MergeRequest {
fn from(mr: MergeRequestChanges) -> Self {
MergeRequest {
id: mr.id,
iid: mr.iid,
project_id: mr.project_id,
title: mr.title,
description: mr.description,
state: mr.state,
created_at: mr.created_at,
updated_at: mr.updated_at,
target_branch: mr.target_branch,
source_branch: mr.source_branch,
upvotes: mr.upvotes,
downvotes: mr.downvotes,
author: mr.author,
assignee: mr.assignee,
assignees: mr.assignees,
source_project_id: mr.source_project_id,
target_project_id: mr.target_project_id,
labels: mr.labels,
work_in_progress: mr.work_in_progress,
milestone: mr.milestone,
merge_when_pipeline_succeeds: mr.merge_when_pipeline_succeeds,
merge_status: mr.merge_status,
sha: mr.sha,
merge_commit_sha: mr.merge_commit_sha,
subscribed: mr.subscribed,
time_stats: mr.time_stats,
changes_count: mr.changes_count,
user_notes_count: mr.user_notes_count,
discussion_locked: mr.discussion_locked,
should_remove_source_branch: mr.should_remove_source_branch,
force_remove_source_branch: mr.force_remove_source_branch,
web_url: mr.web_url,
}
}
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub struct SshKeyId(u64);
impl_id!(SshKeyId);
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct SshKey {
pub id: SshKeyId,
pub title: String,
pub key: String,
pub created_at: DateTime<Utc>,
pub can_push: bool,
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct SshKeyWithUser {
pub id: SshKeyId,
pub title: String,
pub key: String,
pub created_at: DateTime<Utc>,
pub user: UserPublic,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NoteType {
Commit,
Issue,
MergeRequest,
Snippet,
}
enum_serialize!(NoteType -> "note type",
Commit => "Commit",
Issue => "Issue",
MergeRequest => "MergeRequest",
Snippet => "Snippet",
);
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum NoteableId {
Commit(ObjectId),
Issue(IssueId),
MergeRequest(MergeRequestId),
Snippet(SnippetId),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum NoteableInternalId {
Issue(IssueInternalId),
MergeRequest(MergeRequestInternalId),
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub struct NoteId(u64);
impl_id!(NoteId);
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Note {
pub id: NoteId,
pub body: String,
pub attachment: Option<String>,
pub author: UserBasic,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub system: bool,
noteable_id: Value,
noteable_iid: Option<Value>,
pub noteable_type: NoteType,
}
impl Note {
pub fn noteable_id(&self) -> Option<NoteableId> {
match self.noteable_type {
NoteType::Commit => {
self.noteable_id
.as_str()
.map(|id| NoteableId::Commit(ObjectId::new(id)))
},
NoteType::Issue => {
self.noteable_id
.as_u64()
.map(|id| NoteableId::Issue(IssueId::new(id)))
},
NoteType::MergeRequest => {
self.noteable_id
.as_u64()
.map(|id| NoteableId::MergeRequest(MergeRequestId::new(id)))
},
NoteType::Snippet => {
self.noteable_id
.as_u64()
.map(|id| NoteableId::Snippet(SnippetId::new(id)))
},
}
}
pub fn noteable_iid(&self) -> Option<NoteableInternalId> {
match self.noteable_type {
NoteType::Commit => {
None
},
NoteType::Issue => {
self.noteable_iid
.as_ref()
.and_then(|value| value.as_u64())
.map(|id| NoteableInternalId::Issue(IssueInternalId::new(id)))
},
NoteType::MergeRequest => {
self.noteable_iid
.as_ref()
.and_then(|value| value.as_u64())
.map(|id| NoteableInternalId::MergeRequest(MergeRequestInternalId::new(id)))
},
NoteType::Snippet => {
None
},
}
}
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub struct AwardId(u64);
impl_id!(AwardId);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AwardableId {
Issue(IssueId),
MergeRequest(MergeRequestId),
Snippet(SnippetId),
Note(NoteId),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AwardableType {
Issue,
MergeRequest,
Snippet,
Note,
}
enum_serialize!(AwardableType -> "awardable type",
Issue => "Issue",
MergeRequest => "MergeRequest",
Snippet => "Snippet",
Note => "Note",
);
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct AwardEmoji {
pub id: AwardId,
pub name: String,
pub user: UserBasic,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
awardable_id: u64,
pub awardable_type: AwardableType,
}
impl AwardEmoji {
pub fn awardable_id(&self) -> AwardableId {
match self.awardable_type {
AwardableType::Issue => AwardableId::Issue(IssueId::new(self.awardable_id)),
AwardableType::MergeRequest => {
AwardableId::MergeRequest(MergeRequestId::new(self.awardable_id))
},
AwardableType::Snippet => AwardableId::Snippet(SnippetId::new(self.awardable_id)),
AwardableType::Note => AwardableId::Note(NoteId::new(self.awardable_id)),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LineType {
New,
Old,
}
enum_serialize!(LineType -> "line type",
New => "new",
Old => "old",
);
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct CommitNote {
pub note: String,
pub path: Option<String>,
pub line: Option<u64>,
pub line_type: Option<LineType>,
pub author: UserBasic,
pub created_at: DateTime<Utc>,
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub struct CommitStatusId(u64);
impl_id!(CommitStatusId);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StatusState {
Pending,
Running,
Success,
Failed,
Canceled,
}
enum_serialize!(StatusState -> "status state",
Pending => "pending",
Running => "running",
Success => "success",
Failed => "failed",
Canceled => "canceled",
);
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct CommitStatus {
pub id: CommitStatusId,
pub sha: ObjectId,
#[serde(rename="ref")]
pub ref_: Option<String>,
pub status: StatusState,
pub name: String,
pub target_url: Option<String>,
pub description: Option<String>,
pub created_at: DateTime<Utc>,
pub started_at: Option<DateTime<Utc>>,
pub finished_at: Option<DateTime<Utc>>,
pub allow_failure: bool,
pub coverage: Option<u64>,
pub author: UserBasic,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EventTargetType {
Commit,
Issue,
MergeRequest,
Snippet,
ProjectSnippet,
}
enum_serialize!(EventTargetType -> "event target type",
Commit => "commit",
Issue => "issue",
MergeRequest => "merge_request",
Snippet => "snippet",
ProjectSnippet => "project_snippet",
);
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EventTargetId {
Commit(ObjectId),
Issue(IssueId),
MergeRequest(MergeRequestId),
Snippet(SnippetId),
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Event {
pub title: Option<String>,
pub project_id: ProjectId,
pub action_name: String,
target_id: Value,
pub target_type: EventTargetType,
pub author_id: UserId,
pub data: Option<Value>,
pub target_title: String,
pub created_at: DateTime<Utc>,
pub note: Option<Note>,
pub author: Option<UserBasic>,
pub author_username: Option<String>,
}
impl Event {
pub fn target_id(&self) -> Option<EventTargetId> {
match self.target_type {
EventTargetType::Commit => {
self.target_id
.as_str()
.map(|id| EventTargetId::Commit(ObjectId(id.to_string())))
},
EventTargetType::Issue => {
self.target_id
.as_u64()
.map(|id| EventTargetId::Issue(IssueId(id)))
},
EventTargetType::MergeRequest => {
self.target_id
.as_u64()
.map(|id| EventTargetId::MergeRequest(MergeRequestId(id)))
},
EventTargetType::Snippet => {
self.target_id
.as_u64()
.map(|id| EventTargetId::Snippet(SnippetId(id)))
},
EventTargetType::ProjectSnippet => {
self.target_id
.as_u64()
.map(|id| EventTargetId::Snippet(SnippetId(id)))
},
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NamespaceKind {
User,
Group,
}
enum_serialize!(NamespaceKind -> "namespace kind",
User => "user",
Group => "group",
);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NamespaceId {
User(UserId),
Group(GroupId),
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Namespace {
id: u64,
pub path: String,
pub name: String,
pub kind: NamespaceKind,
pub full_path: String,
pub members_count_with_descendants: Option<u64>,
}
impl Namespace {
pub fn id(&self) -> NamespaceId {
match self.kind {
NamespaceKind::User => NamespaceId::User(UserId(self.id)),
NamespaceKind::Group => NamespaceId::Group(GroupId(self.id)),
}
}
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub struct RunnerId(u64);
impl_id!(RunnerId);
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Runner {
pub id: RunnerId,
pub description: Option<String>,
pub active: bool,
pub is_shared: bool,
pub name: Option<String>,
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct JobArtifactFile {
pub filename: String,
pub size: usize,
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub struct JobId(u64);
impl_id!(JobId);
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Job {
pub id: JobId,
pub status: StatusState,
pub stage: String,
pub name: String,
#[serde(rename="ref")]
pub ref_: Option<String>,
pub tag: bool,
pub coverage: Option<f32>,
pub created_at: DateTime<Utc>,
pub started_at: Option<DateTime<Utc>>,
pub finished_at: Option<DateTime<Utc>>,
pub user: Option<User>,
pub artifacts_file: Option<JobArtifactFile>,
pub commit: RepoCommit,
pub runner: Option<Runner>,
pub pipeline: PipelineBasic,
}
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub struct PipelineId(u64);
impl_id!(PipelineId);
#[cfg_attr(feature="strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct PipelineBasic {
pub id: PipelineId,
#[serde(rename="ref")]
pub ref_: Option<String>,
pub sha: ObjectId,
pub status: StatusState,
}