3 Commits

Author SHA1 Message Date
2b37c5b18c Add Gitea Action support for issue-to-work conversion
Implemented Gitea actions to support converting Gitea issues into work packages in OpenProject. Modified various modules to include necessary structs, functions, and tests to handle Gitea issues, ensure URL validation, and adapt work package creation based on Gitea issues.
2024-10-25 00:29:34 +02:00
9ef98e5044 Refactor the issue2work action
- separation the logic to handle issues from gitlab into the gitlab mod
- create a kind of visitor pattern to check between the different providers
2024-10-24 23:14:14 +02:00
9aec267e0a WIP on integrate gitea 2024-05-20 19:16:21 +02:00
11 changed files with 39 additions and 62 deletions

View File

@@ -0,0 +1,4 @@
kind: Added
body: Add an option `--assign-to-me` to automatically assign the openproject's user
to the newly created work package
time: 2024-03-17T21:35:42.724855046+01:00

View File

@@ -0,0 +1,3 @@
kind: Added
body: Allow to configure multiple gitlab instances
time: 2024-03-17T21:35:56.447907065+01:00

View File

@@ -1,5 +0,0 @@
## v0.2.0 - 2024-11-14
### Added
* Add an option `--assign-to-me` to automatically assign the openproject's user to the newly created work package
* Allow to configure multiple gitlab instances
* Create work pakcage from gitea

View File

@@ -6,12 +6,6 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
and is generated by [Changie](https://github.com/miniscruff/changie).
## v0.2.0 - 2024-11-14
### Added
* Add an option `--assign-to-me` to automatically assign the openproject's user to the newly created work package
* Allow to configure multiple gitlab instances
* Create work pakcage from gitea
## v0.1.0 - 2024-01-08
### Added
* Initiate changie versioning

View File

@@ -1,6 +1,9 @@
use crate::config::Config;
use crate::error::GeneralError;
use crate::gitea::issue::Issue;
use crate::openproject::client::Client;
use crate::openproject::root::RootClient;
use crate::openproject::user::GetMe;
use url::Url;
pub(crate) async fn debug(config: Config) -> Result<(), GeneralError> {
@@ -16,9 +19,8 @@ pub(crate) async fn debug(config: Config) -> Result<(), GeneralError> {
println!("issue: {:?}", issue);
Ok(())
return Ok(());
/*
let open_project_client = Client::from_config(&config.openproject);
println!("base_url: {}", open_project_client.base_url);
println!("base_url: will get root");
@@ -28,6 +30,4 @@ pub(crate) async fn debug(config: Config) -> Result<(), GeneralError> {
println!("me: {:?}", u);
Ok(())
*/
}

View File

@@ -1,21 +1,22 @@
use url::Url;
use crate::cli::Issue2Work;
use crate::config::Config;
use crate::error::GeneralError;
use crate::gitea::client::has_client_for_url;
use crate::gitea::issue::{issue_html_url_to_api, Issue};
use crate::gitea::client::has_client_for_url;
use crate::openproject::user::{GetMe, User};
use crate::openproject::work::WorkPackageWriter;
use crate::openproject::work::{WorkPackage, WorkPackageWriter, WorkPackageWriterAssignee};
use crate::planning::Issue2WorkActionTrait;
use url::Url;
pub(crate) struct GiteaAction {}
impl Issue2WorkActionTrait for GiteaAction {
async fn run(&self, url: &Url, config: &Config, args: &Issue2Work) -> Result<(), GeneralError> {
let gitea_client = crate::gitea::client::Client::from_config(config.gitea.first().unwrap());
let issue: Issue = gitea_client.get(issue_html_url_to_api(url)?).await?;
let open_project_client =
crate::openproject::client::Client::from_config(&config.openproject);
let issue: Issue = gitea_client
.get(issue_html_url_to_api(url)?)
.await?;
let open_project_client = crate::openproject::client::Client::from_config(&config.openproject);
let work_package = create_work_package_from_issue(
&issue,
@@ -25,7 +26,7 @@ impl Issue2WorkActionTrait for GiteaAction {
Some(u)
}
false => None,
},
}
);
let work_package = open_project_client
@@ -47,12 +48,16 @@ impl Issue2WorkActionTrait for GiteaAction {
fn create_work_package_from_issue(issue: &Issue, assignee: Option<User>) -> WorkPackageWriter {
WorkPackageWriter {
subject: format!("{} ({}/{})", issue.title, issue.repository.full_name, issue.number),
subject: format!(
"{} ({})",
issue.title,
issue.repository.full_name
),
work_type: "TASK".into(),
description: crate::openproject::work::DescriptionWriter {
format: "markdown".into(),
raw: format!("From Gitea issue: {} \n\n{}", issue.html_url, issue.body),
},
assignee: assignee.into(),
assignee: assignee.into()
}
}
}

View File

@@ -1,4 +1,4 @@
use crate::config::{Config, GiteaConfig};
use crate::config::{Config, GiteaConfig, GitlabConfig};
use crate::error::GeneralError;
use reqwest::header::{HeaderMap, ACCEPT, AUTHORIZATION};
use reqwest::{ClientBuilder, StatusCode};
@@ -54,7 +54,7 @@ impl Client {
pub async fn get<T: DeserializeOwned>(&self, url: Url) -> Result<T, GeneralError> {
let mut headers = HeaderMap::new();
headers.append(AUTHORIZATION, format!("token {}", self.token).parse()?);
headers.append(AUTHORIZATION, self.token.parse()?);
headers.append(ACCEPT, "application/json".parse()?);
let client = ClientBuilder::new()
@@ -92,19 +92,7 @@ mod test {
token: "<PASSWORD>".into(),
};
assert_eq!(
is_client_for_url(
&Url::parse("https://gitea.champs-libres.be/something/somewhere").unwrap(),
&config
),
true
);
assert_eq!(
is_client_for_url(
&Url::parse("https://somewhere.else/something/somewhere").unwrap(),
&config
),
false
);
assert_eq!(is_client_for_url(&Url::parse("https://gitea.champs-libres.be/something/somewhere").unwrap(), &config), true);
assert_eq!(is_client_for_url(&Url::parse("https://somewhere.else/something/somewhere").unwrap(), &config), false);
}
}

View File

@@ -1,13 +1,13 @@
use crate::error::GeneralError;
use crate::gitea::client::Client;
use crate::gitea::repository::Repository;
use serde::Deserialize;
use url::Url;
use crate::error::GeneralError;
#[derive(Debug, Deserialize)]
pub struct Issue {
pub id: u64,
pub number: u64,
number: u64,
pub title: String,
pub body: String,
pub repository: Repository,
@@ -31,24 +31,13 @@ pub fn issue_html_url_to_api(url: &Url) -> Result<Url, GeneralError> {
let issue = parts.next().unwrap();
let iid = parts.next().unwrap();
if !issue.eq("issues") {
if (!issue.eq("issues")) {
return Err(GeneralError {
description: format!("Issue url is not valid: {}", url),
});
}
let url = Url::parse(
format!(
"{}://{}/api/v1/repos/{}/{}/issues/{}",
url.scheme(),
url.host().unwrap(),
domain,
repo,
iid
)
.as_str(),
)
.unwrap();
let url = Url::parse(format!("{}://{}/api/v1/repos/{}/{}/issues/{}", url.scheme(), url.host().unwrap(), domain, repo, iid).as_str()).unwrap();
Ok(url)
}
@@ -62,9 +51,6 @@ mod tests {
let url = Url::parse("https://gitea.champs-libres.be/champs-libres/test/issues/1").unwrap();
let result = issue_html_url_to_api(&url).unwrap();
assert_eq!(
result.as_str(),
"https://gitea.champs-libres.be/api/v1/repos/champs-libres/test/issues/1"
);
assert_eq!(result.as_str(), "https://gitea.champs-libres.be/api/v1/repos/champs-libres/test/issues/1");
}
}

View File

@@ -1,4 +1,4 @@
pub(crate) mod action;
pub mod client;
pub mod issue;
pub mod repository;
pub(crate) mod action;

View File

@@ -1,5 +1,5 @@
use crate::openproject::user::User;
use serde::{Deserialize, Serialize};
use crate::openproject::user::User;
#[derive(Serialize, Debug)]
pub struct WorkPackageWriterAssignee {

View File

@@ -1,6 +1,8 @@
use crate::cli::Issue2Work;
use crate::config::Config;
use crate::error::GeneralError;
use crate::gitlab::client::ClientProvider;
use gitlab::{AsyncGitlab, GitlabBuilder};
use url::Url;
pub(crate) mod issue2work;