gitlab 0.1810.0

Gitlab API client.
Documentation
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use derive_builder::Builder;

use crate::api::common::NameOrId;
use crate::api::endpoint_prelude::*;
use crate::api::projects::labels::{LabelColor, LabelPriority};

/// Edit a label within a project.
#[derive(Debug, Builder, Clone)]
#[builder(setter(strip_option), build_fn(validate = "Self::validate"))]
pub struct EditLabel<'a> {
    /// The project to edit a label within.
    #[builder(setter(into))]
    project: NameOrId<'a>,
    /// The ID or title of the label.
    #[builder(setter(into))]
    label: NameOrId<'a>,
    /// The name of the label.
    #[builder(setter(into), default)]
    new_name: Option<Cow<'a, str>>,
    /// The color of the label.
    #[builder(setter(into), default)]
    color: Option<LabelColor>,

    /// The description of the label.
    #[builder(setter(into), default)]
    description: Option<Cow<'a, str>>,
    /// The priority of the label.
    #[builder(setter(into), default)]
    priority: Option<LabelPriority>,
}

impl<'a> EditLabel<'a> {
    /// Create a builder for the endpoint.
    pub fn builder() -> EditLabelBuilder<'a> {
        EditLabelBuilder::default()
    }
}

static NEED_COLOR_OR_NEW_NAME: &str = "at least one of `new_name` and `color` is required";

#[non_exhaustive]
enum EditLabelBuilderValidationError {
    NeedColorOrNewName,
}

impl From<EditLabelBuilderValidationError> for EditLabelBuilderError {
    fn from(validation_error: EditLabelBuilderValidationError) -> Self {
        match validation_error {
            EditLabelBuilderValidationError::NeedColorOrNewName => {
                EditLabelBuilderError::ValidationError(NEED_COLOR_OR_NEW_NAME.into())
            },
        }
    }
}

impl EditLabelBuilder<'_> {
    fn validate(&self) -> Result<(), EditLabelBuilderValidationError> {
        if self.new_name.is_none() && self.color.is_none() {
            return Err(EditLabelBuilderValidationError::NeedColorOrNewName);
        }

        Ok(())
    }
}

impl Endpoint for EditLabel<'_> {
    fn method(&self) -> Method {
        Method::PUT
    }

    fn endpoint(&self) -> Cow<'static, str> {
        format!("projects/{}/labels/{}", self.project, self.label).into()
    }

    fn body(&self) -> Result<Option<(&'static str, Vec<u8>)>, BodyError> {
        let mut params = FormParams::default();

        params
            .push_opt("new_name", self.new_name.as_ref())
            .push_opt("color", self.color.as_ref())
            .push_opt("description", self.description.as_ref())
            .push_opt("priority", self.priority);

        params.into_body()
    }
}

#[cfg(test)]
mod tests {
    use crate::api::projects::labels::{
        EditLabel, EditLabelBuilderError, GitlabDefaultColor, LabelPriority,
    };
    use crate::api::{self, Query};
    use crate::test::client::{ExpectedUrl, SingleTestClient};
    use http::Method;

    use super::NEED_COLOR_OR_NEW_NAME;

    #[test]
    fn project_is_necessary() {
        let err = EditLabel::builder()
            .label(1)
            .new_name("label")
            .build()
            .unwrap_err();
        crate::test::assert_missing_field!(err, EditLabelBuilderError, "project");
    }

    #[test]
    fn label_is_necessary() {
        let err = EditLabel::builder()
            .project(1)
            .new_name("label")
            .build()
            .unwrap_err();
        crate::test::assert_missing_field!(err, EditLabelBuilderError, "label");
    }

    #[test]
    fn new_name_or_color_is_necessary() {
        let err = EditLabel::builder()
            .project(1)
            .label("label")
            .build()
            .unwrap_err();
        assert_eq!(err.to_string(), NEED_COLOR_OR_NEW_NAME);
    }

    #[test]
    fn project_label_and_new_name_are_sufficient() {
        EditLabel::builder()
            .project(1)
            .label("label")
            .new_name("label_new")
            .build()
            .unwrap();
    }

    #[test]
    fn project_label_and_color_are_sufficient() {
        EditLabel::builder()
            .project(1)
            .label("label")
            .color((0xf1, 0x00, 0xfe))
            .build()
            .unwrap();
    }

    #[test]
    fn endpoint() {
        let endpoint = ExpectedUrl::builder()
            .method(Method::PUT)
            .endpoint("projects/simple%2Fproject/labels/label%25with%25percent")
            .content_type("application/x-www-form-urlencoded")
            .body_str(concat!("new_name=label", "&color=%23ffffff"))
            .build()
            .unwrap();
        let client = SingleTestClient::new_raw(endpoint, "");

        let endpoint = EditLabel::builder()
            .project("simple/project")
            .label("label%with%percent")
            .new_name("label")
            .color((0xff, 0xff, 0xff))
            .build()
            .unwrap();
        api::ignore(endpoint).query(&client).unwrap();
    }

    #[test]
    fn endpoint_new_name() {
        let endpoint = ExpectedUrl::builder()
            .method(Method::PUT)
            .endpoint("projects/simple%2Fproject/labels/label")
            .content_type("application/x-www-form-urlencoded")
            .body_str("new_name=label")
            .build()
            .unwrap();
        let client = SingleTestClient::new_raw(endpoint, "");

        let endpoint = EditLabel::builder()
            .project("simple/project")
            .label("label")
            .new_name("label")
            .build()
            .unwrap();
        api::ignore(endpoint).query(&client).unwrap();
    }

    #[test]
    fn endpoint_color() {
        let endpoint = ExpectedUrl::builder()
            .method(Method::PUT)
            .endpoint("projects/simple%2Fproject/labels/label")
            .content_type("application/x-www-form-urlencoded")
            .body_str("color=%23ffffff")
            .build()
            .unwrap();
        let client = SingleTestClient::new_raw(endpoint, "");

        let endpoint = EditLabel::builder()
            .project("simple/project")
            .label("label")
            .color((0xff, 0xff, 0xff))
            .build()
            .unwrap();
        api::ignore(endpoint).query(&client).unwrap();
    }

    #[test]
    fn endpoint_description() {
        let endpoint = ExpectedUrl::builder()
            .method(Method::PUT)
            .endpoint("projects/simple%2Fproject/labels/label")
            .content_type("application/x-www-form-urlencoded")
            .body_str(concat!("new_name=new_label", "&description=description"))
            .build()
            .unwrap();
        let client = SingleTestClient::new_raw(endpoint, "");

        let endpoint = EditLabel::builder()
            .project("simple/project")
            .label("label")
            .new_name("new_label")
            .description("description")
            .build()
            .unwrap();
        api::ignore(endpoint).query(&client).unwrap();
    }

    #[test]
    fn endpoint_priority() {
        let endpoint = ExpectedUrl::builder()
            .method(Method::PUT)
            .endpoint("projects/simple%2Fproject/labels/label")
            .content_type("application/x-www-form-urlencoded")
            .body_str(concat!("new_name=new_label", "&priority=1"))
            .build()
            .unwrap();
        let client = SingleTestClient::new_raw(endpoint, "");

        let endpoint = EditLabel::builder()
            .project("simple/project")
            .label("label")
            .new_name("new_label")
            .priority(1)
            .build()
            .unwrap();
        api::ignore(endpoint).query(&client).unwrap();
    }

    #[test]
    fn endpoint_priority_null() {
        let endpoint = ExpectedUrl::builder()
            .method(Method::PUT)
            .endpoint("projects/simple%2Fproject/labels/label")
            .content_type("application/x-www-form-urlencoded")
            .body_str(concat!("color=%23808080", "&priority=null"))
            .build()
            .unwrap();
        let client = SingleTestClient::new_raw(endpoint, "");

        let endpoint = EditLabel::builder()
            .project("simple/project")
            .label("label")
            .color(GitlabDefaultColor::Gray)
            .priority(LabelPriority::Null)
            .build()
            .unwrap();
        api::ignore(endpoint).query(&client).unwrap();
    }
}