cargolifter-backend-gitlab 0.2.0

CargoLifter Gitlab backend
Documentation
mod api;
mod models;

use async_trait::async_trait;
use cargolifter_core::models::PublishedVersion;
use cargolifter_core::Backend;

pub struct Gitlab {
    cargolifter_token: Option<String>,
    project_id: usize,
    host: Option<String>,
    default_branch: String,
}

impl Gitlab {
    pub fn from(config: cargolifter_core::config::GitlabConfig) -> Self {
        Self {
            cargolifter_token: config.cargolifter_token,
            project_id: config.project_id,
            host: config.host.clone(),
            default_branch: config
                .default_branch
                .unwrap_or_else(|| String::from("main")),
        }
    }

    fn host(&self) -> String {
        let default_host = String::from("https://gitlab.com");
        self.host.as_ref().unwrap_or(&default_host).into()
    }
}

#[async_trait]
impl Backend for Gitlab {
    async fn get_file(
        &self,
        token: &str,
        crate_path: &str,
    ) -> Result<(String, String, String), reqwest::Error> {
        let host = self.host();

        match api::get_file(
            &host,
            token,
            self.project_id,
            &crate_path,
            &self.default_branch,
        )
        .await
        {
            Ok(response) => Ok((
                response.content, 
                response.encoding,
                response.content_sha256,
            )),
            Err(e) => Err(e),
        }
    }

    async fn create_file(
        &self,
        token: &str,
        crate_path: &str,
        branch_name: &str,
        initial_version: &PublishedVersion,
    ) -> Result<(), reqwest::Error> {
        let host = self.host();

        let json = serde_json::to_string(&initial_version).unwrap();
        let encoded_content = base64::encode(json);
        let create_request = crate::models::create_file::Request {
            branch: branch_name.into(),
            start_branch: Some(self.default_branch.clone()),
            content: encoded_content,
            encoding: Some("base64".into()),
            commit_message: format!("Adding {} {}", initial_version.name, initial_version.vers),
            ..Default::default()
        };

        match api::create_file(&host, token, self.project_id, &crate_path, &create_request).await {
            Ok(_) => Ok(()),
            Err(e) => Err(e),
        }
    }

    async fn update_file(
        &self,
        token: &str,
        crate_path: &str,
        branch_name: &str,
        versions: &[PublishedVersion],
        _current_sha: &str,
    ) -> Result<(), reqwest::Error> {
        let host = self.host();

        let new_content = versions
            .iter()
            .map(|v| serde_json::to_string(v).unwrap())
            .collect::<Vec<String>>()
            .join("\n");

        let update_request = crate::models::update_file::Request {
            branch: branch_name.into(),
            start_branch: Some(self.default_branch.clone()),
            content: base64::encode(new_content),
            encoding: Some("base64".into()),
            commit_message: format!("Adding {} {}", versions[0].name, versions[0].vers),
            ..Default::default()
        };
        match api::update_file(&host, token, self.project_id, &crate_path, &update_request).await {
            Ok(_) => Ok(()),
            Err(e) => Err(e),
        }
    }

    async fn delete_branch(
        &self,
        token: &str,
        branch_name: &str,
    ) -> Result<(), reqwest::Error>
    {
        let host = self.host();

        match api::delete_branch(&host, token, self.project_id, &branch_name.clone()).await {
            Ok(_) => Ok(()),
            Err(e) => Err(e),
        }
    }

    async fn create_pull_request(
        &self,
        token: &str,
        title: &str,
        branch_name: &str,
    ) -> Result<u64, reqwest::Error> {
        let host = self.host();

        let merge_request = models::create_merge_request::Request {
            source_branch: branch_name.into(),
            target_branch: self.default_branch.clone(),
            title: title.into(),
            remove_source_branch: Some(false),
            ..Default::default()
        };
        match api::create_merge_request(&host, token, self.project_id, &merge_request).await {
            Ok(response) => {
                Ok(response.iid)
            },
            Err(e) => Err(e),
        }
    }

    async fn merge_pull_request(
        &self,
        token: &str,
        id: u64,
    ) -> Result<(), reqwest::Error> {
        let host = self.host();

        let owned_token = token.to_owned();
        let merge_token = self.cargolifter_token.as_ref().unwrap_or(&owned_token);

        let accept_request = models::accept_merge_request::Request {
            should_remove_source_branch: Some(false),
            ..Default::default()
        };

        match api::accept_merge_request(
            &host,
            merge_token,
            self.project_id,
            id,
            &accept_request,
        )
        .await
        {
            Ok(_) => Ok(()),
            Err(e) => Err(e),
        }
    }

    async fn delete_pull_request(
        &self,
        _token: &str,
        _id: u64,
    ) -> Result<(), reqwest::Error> {
        Ok(())
    }
}