Commit 559f5f4a authored by Brad King's avatar Brad King 💬 Committed by Kitware Robot
Browse files

Merge topic 'review-sweep'

cd75bde3 traits: derive sensible traits
adece3e7 rustfmt: apply suggestions
e7162e07 cargo: pin the version of the log crate
43f8c8ec clippy: apply suggestions
8837cf1c webhooks: another nullable field
7e230e31 types: remove deprecated fields
212a6c46 gitlab: simplify construction
9cb1ba9b

 types: hide bits which have safer versions
...
Acked-by: Kitware Robot's avatarKitware Robot <kwrobot@kitware.com>
Reviewed-by: Brad King's avatarBrad King <brad.king@kitware.com>
Merge-request: !45
parents 3338b2de cd75bde3
......@@ -18,7 +18,7 @@ serde_codegen = "~0.8"
chrono = { version = "~0.2", features = ["serde"] }
ease = "~0.6"
hyper = "~0.9"
log = "*"
log = "~0.3"
quick-error = "~1.1"
serde = "~0.8"
serde_json = "~0.8"
......
......@@ -3,6 +3,7 @@ fn_args_density = "Compressed"
fn_args_layout = "Visual"
match_block_trailing_comma = true
match_wildcard_trailing_comma = true
reorder_imported_names = true
struct_lit_multiline_style = "ForceMulti"
struct_lit_trailing_comma = "Always"
struct_trailing_comma = "Always"
......
......@@ -14,7 +14,6 @@ extern crate serde;
use self::serde::Deserialize;
extern crate serde_json;
use self::serde_json::from_value;
extern crate url;
use self::url::percent_encoding::{PATH_SEGMENT_ENCODE_SET, percent_encode};
......@@ -22,6 +21,8 @@ use self::url::percent_encoding::{PATH_SEGMENT_ENCODE_SET, percent_encode};
use super::error::Error;
use super::types::*;
use std::fmt::{self, Debug};
// TODO: Add system hook APIs
// TODO: Add webhook APIs
......@@ -34,12 +35,19 @@ pub struct Gitlab {
token: String,
}
impl Debug for Gitlab {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "Gitlab {{ {} }}", self.base_url)
}
}
// The header Gitlab uses to authenticate the user.
header!{ (GitlabPrivateToken, "PRIVATE-TOKEN") => [String] }
/// A JSON value return from Gitlab.
pub type GitlabResult<T: Deserialize> = Result<T, Error>;
#[derive(Debug)]
/// Optional information for commit statuses.
pub struct CommitStatusInfo<'a> {
/// The refname of the commit being tested.
......@@ -57,21 +65,19 @@ impl Gitlab {
///
/// Errors out if `token` is invalid.
pub fn new<T: ToString>(host: &str, token: T) -> GitlabResult<Self> {
let base_url = try!(Url::parse(&format!("https://{}/api/v3/", host)));
Self::_new(host, token.to_string(), base_url)
Self::_new("https", host, token.to_string())
}
/// Create a new non-SSL Gitlab API representation.
///
/// Errors out if `token` is invalid.
pub fn new_insecure<T: ToString>(host: &str, token: T) -> GitlabResult<Self> {
let base_url = try!(Url::parse(&format!("http://{}/api/v3/", host)));
Self::_new(host, token.to_string(), base_url)
Self::_new("http", host, token.to_string())
}
fn _new(host: &str, token: String, base_url: Url) -> GitlabResult<Self> {
fn _new(protocol: &str, host: &str, token: String) -> GitlabResult<Self> {
let base_url = try!(Url::parse(&format!("{}://{}/api/v3/", protocol, host)));
let api = Gitlab {
base_url: base_url,
token: token,
......@@ -160,15 +166,18 @@ impl Gitlab {
request
.param("build_events", Self::bool_param_value(events.build()))
.param("issues_events", Self::bool_param_value(events.issues()))
.param("merge_requests_events", Self::bool_param_value(events.merge_requests()))
.param("merge_requests_events",
Self::bool_param_value(events.merge_requests()))
.param("note_events", Self::bool_param_value(events.note()))
.param("pipeline_events", Self::bool_param_value(events.pipeline()))
.param("push_events", Self::bool_param_value(events.push()))
.param("wiki_page_events", Self::bool_param_value(events.wiki_page()));
.param("wiki_page_events",
Self::bool_param_value(events.wiki_page()));
}
/// Add a project hook.
pub fn add_hook(&self, project: ProjectId, url: &str, events: WebhookEvents) -> GitlabResult<Hook> {
pub fn add_hook(&self, project: ProjectId, url: &str, events: WebhookEvents)
-> GitlabResult<Hook> {
let mut req = try!(self._mkrequest(&format!("projects/{}/hooks", project)));
Self::set_event_flags(&mut req, events);
......@@ -231,7 +240,9 @@ impl Gitlab {
/// Get comments on a commit.
pub fn commit_comments(&self, project: ProjectId, commit: &str)
-> GitlabResult<Vec<CommitNote>> {
self._get_paged(&format!("projects/{}/repository/commits/{}/comments", project, commit))
self._get_paged(&format!("projects/{}/repository/commits/{}/comments",
project,
commit))
}
/// Get comments on a commit.
......@@ -268,7 +279,9 @@ impl Gitlab {
/// Get the statuses of a commit.
pub fn commit_statuses(&self, project: ProjectId, commit: &str)
-> GitlabResult<Vec<CommitStatus>> {
self._get_paged(&format!("projects/{}/repository/commits/{}/statuses", project, commit))
self._get_paged(&format!("projects/{}/repository/commits/{}/statuses",
project,
commit))
}
/// Get the statuses of a commit.
......@@ -356,9 +369,12 @@ impl Gitlab {
/// Award a merge request note with an award.
pub fn award_merge_request_note(&self, project: ProjectId, merge_request: MergeRequestId,
note: NoteId, award: &str) -> GitlabResult<AwardEmoji> {
note: NoteId, award: &str)
-> GitlabResult<AwardEmoji> {
let path = &format!("projects/{}/merge_requests/{}/notes/{}/award_emoji",
project, merge_request, note);
project,
merge_request,
note);
let mut req = try!(self._mkrequest(path));
req.param("name", award);
......@@ -368,7 +384,8 @@ impl Gitlab {
/// Get the awards for a merge request note.
pub fn merge_request_note_awards(&self, project: ProjectId, merge_request: MergeRequestId,
note: NoteId) -> GitlabResult<Vec<AwardEmoji>> {
note: NoteId)
-> GitlabResult<Vec<AwardEmoji>> {
self._get_paged(&format!("projects/{}/merge_requests/{}/notes/{}/award_emoji",
project,
merge_request,
......@@ -420,7 +437,7 @@ impl Gitlab {
Ok(rsp) => {
let v = try!(rsp.from_json().map_err(Error::Ease));
Ok(try!(from_value::<T>(v)))
Ok(try!(serde_json::from_value::<T>(v)))
},
Err(err) => {
if let EaseError::UnsuccessfulResponse(rsp) = err {
......
......@@ -11,7 +11,7 @@ use self::serde::{Deserialize, Deserializer};
use self::serde::de::Error;
extern crate serde_json;
use self::serde_json::{from_value, Value};
use self::serde_json::Value;
use super::systemhooks::SystemHook;
use super::webhooks::WebHook;
......@@ -28,13 +28,13 @@ impl Deserialize for GitlabHook {
// Look for `object_kind` first because some web hooks also have `event_name` which would
// cause a false match here.
let hook_res = if let Some(_) = val.pointer("/object_kind") {
from_value(val).map(GitlabHook::Web)
} else if let Some(_) = val.pointer("/event_name") {
from_value(val).map(GitlabHook::System)
} else {
return Err(D::Error::missing_field("either object_kind or event_name"));
};
let hook_res = if val.pointer("/object_kind").is_some() {
serde_json::from_value(val).map(GitlabHook::Web)
} else if val.pointer("/event_name").is_some() {
serde_json::from_value(val).map(GitlabHook::System)
} else {
return Err(D::Error::missing_field("either object_kind or event_name"));
};
hook_res.map_err(|err| D::Error::invalid_value(&format!("{:?}", err)))
}
......
......@@ -14,10 +14,10 @@ use self::serde::{Deserialize, Deserializer, Serialize, Serializer};
use self::serde::de::{Error, Type};
extern crate serde_json;
use self::serde_json::{from_value, Value};
use self::serde_json::Value;
use super::types::{AccessLevel, GroupId, ObjectId, ProjectId, SshKeyId, UserId};
use super::webhooks::{BuildProjectHookAttrs, CommitHookAttrs, ProjectHookAttrs};
use super::webhooks::{CommitHookAttrs, ProjectHookAttrs};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProjectEvent {
......@@ -239,10 +239,6 @@ pub struct PushSystemHook {
pub project: ProjectHookAttrs,
pub commits: Vec<CommitHookAttrs>, // limited to 20 commits
pub total_commits_count: u64,
// Deprecated.
pub repository: BuildProjectHookAttrs,
pub object_kind: String,
}
#[derive(Debug)]
......@@ -264,7 +260,7 @@ impl Deserialize for SystemHook {
Some(&Value::String(ref name)) => name,
Some(_) => {
return Err(D::Error::invalid_type(Type::String));
}
},
None => {
return Err(D::Error::missing_field("event_name"));
},
......@@ -272,30 +268,30 @@ impl Deserialize for SystemHook {
.to_string();
let hook_res = match event_name.as_str() {
"project_create" |
"project_destroy" |
"project_rename" |
"project_transfer" => from_value(val).map(SystemHook::Project),
"project_create" |
"project_destroy" |
"project_rename" |
"project_transfer" => serde_json::from_value(val).map(SystemHook::Project),
"user_add_to_team" |
"user_remove_from_team" => from_value(val).map(SystemHook::ProjectMember),
"user_add_to_team" |
"user_remove_from_team" => serde_json::from_value(val).map(SystemHook::ProjectMember),
"user_create" | "user_destroy" => from_value(val).map(SystemHook::User),
"user_create" | "user_destroy" => serde_json::from_value(val).map(SystemHook::User),
"key_create" | "key_destroy" => from_value(val).map(SystemHook::Key),
"key_create" | "key_destroy" => serde_json::from_value(val).map(SystemHook::Key),
"group_create" | "group_destroy" => from_value(val).map(SystemHook::Group),
"group_create" | "group_destroy" => serde_json::from_value(val).map(SystemHook::Group),
"user_add_to_group" |
"user_remove_from_group" => from_value(val).map(SystemHook::GroupMember),
"user_add_to_group" |
"user_remove_from_group" => serde_json::from_value(val).map(SystemHook::GroupMember),
"push" | "tag_push" => from_value(val).map(SystemHook::Push),
"push" | "tag_push" => serde_json::from_value(val).map(SystemHook::Push),
_ => {
return Err(D::Error::invalid_value(&format!("unrecognized system event name: {}",
event_name)));
},
};
_ => {
return Err(D::Error::invalid_value(&format!("unrecognized system event name: {}",
event_name)));
},
};
hook_res.map_err(|err| D::Error::invalid_value(&format!("{:?}", err)))
}
......
......@@ -14,7 +14,7 @@ use self::serde::{Deserialize, Deserializer, Serialize, Serializer};
use self::serde::de::Error;
extern crate serde_json;
use self::serde_json::{from_value, Value};
use self::serde_json::Value;
use std::fmt::{self, Display, Formatter};
......@@ -297,7 +297,7 @@ impl From<ProjectHook> for Hook {
}
}
#[derive(Default)]
#[derive(Debug, Default, Clone, Copy)]
pub struct WebhookEvents {
build: bool,
issues: bool,
......@@ -393,7 +393,7 @@ pub struct SharedGroup {
pub group_access_level: u64,
}
#[derive(Serialize, Deserialize, Debug)]
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
// Called `MemberAccess` in entities.rb, but it is just a base class for `ProjectAccess` and
// `GroupAccess`. Combine them here.
pub struct MemberAccess {
......@@ -401,7 +401,7 @@ pub struct MemberAccess {
pub notification_level: Option<u64>,
}
#[derive(Serialize, Deserialize, Debug)]
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
pub struct Permissions {
pub project_access: Option<MemberAccess>,
pub group_access: Option<MemberAccess>,
......@@ -418,7 +418,7 @@ pub struct ProjectNamespace {
pub path: String,
pub description: String,
pub id: u64,
pub owner_id: Option<UserId>,
owner_id: Option<u64>,
pub created_at: DateTime<UTC>,
pub updated_at: DateTime<UTC>,
pub deleted_at: Option<DateTime<UTC>>,
......@@ -430,7 +430,7 @@ pub struct ProjectNamespace {
}
impl ProjectNamespace {
pub fn namespace_id(&self) -> NamespaceId {
pub fn owner_id(&self) -> NamespaceId {
match self.owner_id {
Some(_) => NamespaceId::User(UserId(self.id)),
None => NamespaceId::Group(GroupId(self.id)),
......@@ -506,18 +506,6 @@ pub struct Project {
pub only_allow_merge_if_build_succeeds: bool,
pub request_access_enabled: bool,
// Deprecated.
/// Whether issues are enabled.
pub issues_enabled: bool,
/// Whether merge requests are enabled.
pub merge_requests_enabled: bool,
/// Whether project wiki is enabled.
pub wiki_enabled: bool,
/// Whether continuous integration is enabled.
pub builds_enabled: bool,
/// Whether project snippets is enabled.
pub snippets_enabled: bool,
/// If this is present, it is `ProjectWithAccess`, but since it is so similar, just have it be
/// optional here.
pub permissions: Option<Permissions>,
......@@ -775,7 +763,7 @@ pub struct RepoCommit {
pub message: String,
}
#[derive(Serialize, Deserialize, Debug)]
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
pub struct RepoCommitStats {
pub additions: u64,
pub deletions: u64,
......@@ -913,6 +901,7 @@ pub struct ExternalIssue {
pub title: String,
}
#[derive(Debug)]
pub enum IssueReference {
Internal(Issue),
External(ExternalIssue),
......@@ -931,9 +920,9 @@ impl Deserialize for IssueReference {
fn deserialize<D: Deserializer>(deserializer: &mut D) -> Result<Self, D::Error> {
let val = try!(Value::deserialize(deserializer));
from_value::<Issue>(val.clone())
serde_json::from_value::<Issue>(val.clone())
.map(IssueReference::Internal)
.or_else(|_| from_value::<ExternalIssue>(val).map(IssueReference::External))
.or_else(|_| serde_json::from_value::<ExternalIssue>(val).map(IssueReference::External))
.map_err(|err| D::Error::invalid_value(&format!("{:?}", err)))
}
}
......@@ -1105,7 +1094,7 @@ enum_serialize!(NoteType -> "note type",
Snippet => "Snippet",
);
#[derive(Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum NoteableId {
Commit(ObjectId),
Issue(IssueId),
......@@ -1126,7 +1115,7 @@ pub struct Note {
pub created_at: DateTime<UTC>,
pub updated_at: DateTime<UTC>,
pub system: bool,
pub noteable_id: Value, // Keep as JSON because its type depends on what `noteable_type` is.
noteable_id: Value, // Keep as JSON because its type depends on what `noteable_type` is.
pub noteable_type: NoteType,
}
......@@ -1162,7 +1151,7 @@ impl Note {
pub struct AwardId(u64);
impl_id!(AwardId);
#[derive(Clone, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AwardableId {
Issue(IssueId),
MergeRequest(MergeRequestId),
......@@ -1191,7 +1180,7 @@ pub struct AwardEmoji {
pub user: UserBasic,
pub created_at: DateTime<UTC>,
pub updated_at: DateTime<UTC>,
pub awardable_id: u64,
awardable_id: u64,
pub awardable_type: AwardableType,
}
......@@ -1199,7 +1188,9 @@ 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::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)),
}
......@@ -1285,7 +1276,7 @@ enum_serialize!(EventTargetType -> "event target type",
ProjectSnippet => "project_snippet",
);
#[derive(Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EventTargetId {
Commit(ObjectId),
Issue(IssueId),
......@@ -1298,7 +1289,7 @@ pub struct Event {
pub title: Option<String>,
pub project_id: ProjectId,
pub action_name: String,
pub target_id: Value,
target_id: Value,
pub target_type: EventTargetType,
pub author_id: UserId,
pub data: Option<Value>,
......@@ -1310,7 +1301,7 @@ pub struct Event {
}
impl Event {
pub fn event_target_id(&self) -> Option<EventTargetId> {
pub fn target_id(&self) -> Option<EventTargetId> {
match self.target_type {
EventTargetType::Commit => {
self.target_id
......@@ -1355,7 +1346,7 @@ enum_serialize!(NamespaceKind -> "namespace kind",
Group => "group",
);
#[derive(Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NamespaceId {
User(UserId),
Group(GroupId),
......@@ -1363,13 +1354,13 @@ pub enum NamespaceId {
#[derive(Serialize, Deserialize, Debug)]
pub struct Namespace {
pub id: u64,
id: u64,
pub path: String,
pub kind: NamespaceKind,
}
impl Namespace {
pub fn namespace_id(&self) -> NamespaceId {
pub fn id(&self) -> NamespaceId {
match self.kind {
NamespaceKind::User => NamespaceId::User(UserId(self.id)),
NamespaceKind::Group => NamespaceId::Group(GroupId(self.id)),
......
......@@ -14,13 +14,13 @@ use self::serde::{Deserialize, Deserializer, Serialize, Serializer};
use self::serde::de::{Error, Type};
extern crate serde_json;
use self::serde_json::{from_value, Value};
use self::serde_json::Value;
use super::types::{BuildId, IssueId, IssueState, MergeRequestId, MergeRequestState, MergeStatus,
MilestoneId, NoteableId, NoteId, NoteType, ObjectId, ProjectId, SnippetId,
MilestoneId, NoteId, NoteType, NoteableId, ObjectId, ProjectId, SnippetId,
UserId};
#[derive(Debug)]
#[derive(Debug, Clone, Copy)]
pub struct HookDate(DateTime<UTC>);
impl Serialize for HookDate {
......@@ -72,20 +72,6 @@ pub struct ProjectHookAttrs {
pub path_with_namespace: String,
/// The default branch for the project.
pub default_branch: String,
// Deprecated.
pub http_url: String,
pub ssh_url: String,
pub url: String,
pub homepage: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct RepositoryHookAttrs {
pub description: Option<String>,
pub homepage: String,
pub name: String,
pub url: String,
}
#[derive(Serialize, Deserialize, Debug)]
......@@ -145,10 +131,6 @@ pub struct PushHook {
pub project: ProjectHookAttrs,
pub commits: Vec<CommitHookAttrs>, // limited to 20 commits
pub total_commits_count: u64,
// Deprecated.
pub repository: BuildProjectHookAttrs,
pub event_name: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
......@@ -291,9 +273,6 @@ pub struct MergeRequestHook {
pub project: ProjectHookAttrs,
pub object_attributes: MergeRequestHookAttrs,
pub assignee: Option<UserHookAttrs>,
// Deprecated.
pub repository: RepositoryHookAttrs,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
......@@ -388,7 +367,7 @@ pub struct NoteHookAttrs {
pub commit_id: Option<ObjectId>, // XXX(8.11): apparently can be an empty string?
pub discussion_id: ObjectId,
pub original_discussion_id: Option<ObjectId>,
pub noteable_id: Value, // Keep as JSON because its type depends on what `noteable_type` is.
noteable_id: Value, // Keep as JSON because its type depends on what `noteable_type` is.
pub system: bool,
pub st_diff: Option<DiffHookAttrs>,
pub url: String,
......@@ -398,6 +377,34 @@ pub struct NoteHookAttrs {
//pub is_award: bool, // seems to have been removed?
}
impl NoteHookAttrs {
/// The ID of the object the note is for.
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)))
},
}
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct NoteHook {
pub object_kind: String,
......@@ -409,9 +416,6 @@ pub struct NoteHook {
pub issue: Option<IssueHookAttrs>,
pub merge_request: Option<MergeRequestHookAttrs>,
pub snippet: Option<SnippetHookAttrs>,
// Deprecated.
pub repository: RepositoryHookAttrs,
}
#[derive(Serialize, Deserialize, Debug)]
......@@ -440,7 +444,7 @@ pub struct BuildProjectHookAttrs {
/// The display name of the project.
pub name: String,
/// The description of the project.
pub description: String,
pub description: Option<String>,
/// The URL for the project's homepage.
pub homepage: String,
/// The URL to clone the repository over HTTPS.
......@@ -449,9 +453,6 @@ pub struct BuildProjectHookAttrs {
pub git_ssh_url: String,
/// Integral value for the project's visibility.
pub visibility_level: u64,
// Deprecated.
pub url: String,
}
#[derive(Serialize, Deserialize, Debug)]
......@@ -510,21 +511,21 @@ impl Deserialize for WebHook {
.to_string();
let hook_res = match object_kind.as_str() {
"push" | "tag_push" => from_value(val).map(WebHook::Push),
"push" | "tag_push" => serde_json::from_value(val).map(WebHook::Push),
"issue" => from_value(val).map(WebHook::Issue),
"issue" => serde_json::from_value(val).map(WebHook::Issue),
"merge_request" => from_value(val).map(WebHook::MergeRequest),
"merge_request" => serde_json::from_value(val).map(WebHook::MergeRequest),
"note" => from_value(val).map(WebHook::Note),
"note" => serde_json::from_value(val).map(WebHook::Note),
"build" => from_value(val).map(WebHook::Build),
"build" => serde_json::from_value(val).map(WebHook::Build),
_ => {
return Err(D::Error::invalid_value(&format!("unrecognized webhook object kind: {}",
object_kind)));
},
};
_ => {
return Err(D::Error::invalid_value(&format!("unrecognized webhook object kind: {}",
object_kind)));
},
};
hook_res.map_err(|err| D::Error::invalid_value(&format!("{:?}", err)))
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment