use derive_builder::Builder;
use crate::api::common::NameOrId;
use crate::api::endpoint_prelude::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum PipelineVariableType {
EnvVar,
File,
}
#[allow(clippy::derivable_impls)]
impl Default for PipelineVariableType {
fn default() -> Self {
PipelineVariableType::EnvVar
}
}
impl PipelineVariableType {
fn as_str(self) -> &'static str {
match self {
PipelineVariableType::EnvVar => "env_var",
PipelineVariableType::File => "file",
}
}
}
#[derive(Debug, Clone, Builder)]
pub struct PipelineVariable<'a> {
#[builder(setter(into))]
pub key: Cow<'a, str>,
#[builder(setter(into))]
pub value: Cow<'a, str>,
#[builder(default)]
pub variable_type: PipelineVariableType,
}
impl<'a> PipelineVariable<'a> {
pub fn builder() -> PipelineVariableBuilder<'a> {
PipelineVariableBuilder::default()
}
}
#[derive(Debug, Builder, Clone)]
pub struct CreatePipeline<'a> {
#[builder(setter(into))]
project: NameOrId<'a>,
#[builder(setter(into))]
ref_: Cow<'a, str>,
#[builder(setter(name = "_variables"), default, private)]
variables: Vec<PipelineVariable<'a>>,
}
impl<'a> CreatePipeline<'a> {
pub fn builder() -> CreatePipelineBuilder<'a> {
CreatePipelineBuilder::default()
}
}
impl<'a> CreatePipelineBuilder<'a> {
pub fn variable(&mut self, variable: PipelineVariable<'a>) -> &mut Self {
self.variables.get_or_insert_with(Vec::new).push(variable);
self
}
pub fn variables<I, V>(&mut self, iter: I) -> &mut Self
where
I: Iterator<Item = V>,
V: Into<PipelineVariable<'a>>,
{
self.variables
.get_or_insert_with(Vec::new)
.extend(iter.map(Into::into));
self
}
}
impl<'a> Endpoint for CreatePipeline<'a> {
fn method(&self) -> Method {
Method::POST
}
fn endpoint(&self) -> Cow<'static, str> {
format!("projects/{}/pipeline", self.project).into()
}
fn body(&self) -> Result<Option<(&'static str, Vec<u8>)>, BodyError> {
let mut params = FormParams::default();
params.push("ref", &self.ref_);
self.variables.iter().for_each(|variable| {
params.extend(
[
("variables[][key]", variable.key.as_ref()),
("variables[][value]", variable.value.as_ref()),
(
"variables[][variable_type]",
variable.variable_type.as_str(),
),
]
.iter()
.cloned(),
);
});
params.into_body()
}
}
#[cfg(test)]
mod tests {
use http::Method;
use crate::api::projects::pipelines::{
CreatePipeline, CreatePipelineBuilderError, PipelineVariable, PipelineVariableBuilderError,
PipelineVariableType,
};
use crate::api::{self, Query};
use crate::test::client::{ExpectedUrl, SingleTestClient};
#[test]
fn pipeline_variable_type_default() {
assert_eq!(
PipelineVariableType::default(),
PipelineVariableType::EnvVar,
);
}
#[test]
fn pipeline_variable_type_as_str() {
let items = &[
(PipelineVariableType::EnvVar, "env_var"),
(PipelineVariableType::File, "file"),
];
for (i, s) in items {
assert_eq!(i.as_str(), *s);
}
}
#[test]
fn pipeline_variable_key_and_value_are_necessary() {
let err = PipelineVariable::builder().build().unwrap_err();
crate::test::assert_missing_field!(err, PipelineVariableBuilderError, "key");
}
#[test]
fn pipeline_variable_key_is_necessary() {
let err = PipelineVariable::builder()
.value("value")
.build()
.unwrap_err();
crate::test::assert_missing_field!(err, PipelineVariableBuilderError, "key");
}
#[test]
fn pipeline_variable_value_is_necessary() {
let err = PipelineVariable::builder().key("key").build().unwrap_err();
crate::test::assert_missing_field!(err, PipelineVariableBuilderError, "value");
}
#[test]
fn pipeline_variable_key_and_value_are_sufficient() {
PipelineVariable::builder()
.key("key")
.value("value")
.build()
.unwrap();
}
#[test]
fn project_and_ref_are_needed() {
let err = CreatePipeline::builder().build().unwrap_err();
crate::test::assert_missing_field!(err, CreatePipelineBuilderError, "project");
}
#[test]
fn project_is_needed() {
let err = CreatePipeline::builder()
.ref_("testref")
.build()
.unwrap_err();
crate::test::assert_missing_field!(err, CreatePipelineBuilderError, "project");
}
#[test]
fn ref_is_needed() {
let err = CreatePipeline::builder().project(1).build().unwrap_err();
crate::test::assert_missing_field!(err, CreatePipelineBuilderError, "ref_");
}
#[test]
fn project_and_ref_are_sufficient() {
CreatePipeline::builder()
.project(1)
.ref_("testref")
.build()
.unwrap();
}
#[test]
fn endpoint() {
let endpoint = ExpectedUrl::builder()
.method(Method::POST)
.endpoint("projects/simple%2Fproject/pipeline")
.content_type("application/x-www-form-urlencoded")
.body_str("ref=master")
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = CreatePipeline::builder()
.project("simple/project")
.ref_("master")
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_pipeline_variables() {
let endpoint = ExpectedUrl::builder()
.method(Method::POST)
.endpoint("projects/1/pipeline")
.content_type("application/x-www-form-urlencoded")
.body_str(concat!(
"ref=master",
"&variables%5B%5D%5Bkey%5D=key",
"&variables%5B%5D%5Bvalue%5D=value",
"&variables%5B%5D%5Bvariable_type%5D=env_var",
"&variables%5B%5D%5Bkey%5D=file",
"&variables%5B%5D%5Bvalue%5D=contents",
"&variables%5B%5D%5Bvariable_type%5D=file",
))
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = CreatePipeline::builder()
.project(1)
.ref_("master")
.variable(
PipelineVariable::builder()
.key("key")
.value("value")
.build()
.unwrap(),
)
.variables(
[PipelineVariable::builder()
.key("file")
.value("contents")
.variable_type(PipelineVariableType::File)
.build()
.unwrap()]
.iter()
.cloned(),
)
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
}