use crate::cli::Issue2Work; use crate::config::Config; use crate::error::GeneralError; use crate::gitlab::client::{client_for_url, has_client_for_url}; use crate::gitlab::issue::IssueBundle; use crate::openproject::client::Client; use crate::openproject::user::{GetMe, User}; use crate::openproject::work::WorkPackageWriterAssignee; use crate::planning::Issue2WorkActionTrait; use gitlab::api::{issues, projects, AsyncQuery}; use gitlab::{Issue, Project}; use url::Url; #[derive(Debug)] struct IssueInfo { project: String, iid: u64, } /// details on how to create a work package from various informations #[derive(Debug)] struct Issue2WorkPackageDTO { pub issue: IssueBundle, pub assign_to: Option, } pub(crate) struct GitlabAction {} impl Issue2WorkActionTrait for GitlabAction { async fn run(&self, url: &Url, config: &Config, args: &Issue2Work) -> Result<(), GeneralError> { let client = client_for_url(&url, &config).await?; let data = extract_issue_info(&url).unwrap(); let endpoint = issues::ProjectIssues::builder() .iid(data.iid) .project(String::from(data.project)) .build() .unwrap(); let issues: Vec = endpoint.query_async(&client).await.unwrap(); let issue = issues.first().unwrap(); let project_endpoint = projects::Project::builder() .project(issue.project_id.value()) .build() .unwrap(); let project: Project = project_endpoint.query_async(&client).await.unwrap(); let issue_bundle = IssueBundle::new(&issue, &project); let open_project_client = Client::from_config(&config.openproject); let dto = Issue2WorkPackageDTO { issue: issue_bundle, assign_to: match args.assign_to_me { true => { let u = open_project_client.me().await?; Some(u) } false => None, }, }; let work_package = open_project_client .create_work_package(&(&dto).into(), &args.project_id) .await?; println!( "new work package created: {:?}, edit at {}/projects/{}/work_packages/{}", work_package.subject, config.openproject.base_url, args.project_id, work_package.id ); Ok(()) } fn supports(&self, url: &Url, config: &Config, _args: &Issue2Work) -> bool { has_client_for_url(&url, &config) } } fn extract_issue_info(url: &Url) -> Option { let parts = url .path_segments() .expect("Could not parse path segment of given url"); let mut project_url: Vec = Vec::with_capacity(3); let mut iid: Option = None; let mut project_found = false; for el in parts { if el == "-" { project_found = true; continue; } if el == "issues" { continue; } if !project_found { project_url.push(String::from(el)); } else { // must be the id iid = Some(String::from(el)); break; } } Some(IssueInfo { project: project_url.join("/"), iid: iid .expect("iid of the issue not found") .parse() .expect("could not transform issue id to u64"), }) } impl From<&Issue2WorkPackageDTO> for crate::openproject::work::WorkPackageWriter { fn from(value: &Issue2WorkPackageDTO) -> Self { crate::openproject::work::WorkPackageWriter { subject: format!( "{} ({}/{})", value.issue.issue.title, value.issue.project.name_with_namespace, value.issue.issue.iid ), work_type: "TASK".into(), description: crate::openproject::work::DescriptionWriter { format: "markdown".into(), raw: format!("From gitlab: {}", value.issue.issue.web_url), }, assignee: WorkPackageWriterAssignee { href: match &value.assign_to { None => None, Some(w) => Some(w.clone().d_links.d_self.href), }, }, } } }