Compare commits

..

3 Commits

Author SHA1 Message Date
julienfastre 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
julienfastre 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
julienfastre 9aec267e0a WIP on integrate gitea 2024-05-20 19:16:21 +02:00
15 changed files with 40 additions and 121 deletions
@@ -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
@@ -0,0 +1,3 @@
kind: Added
body: Allow to configure multiple gitlab instances
time: 2024-03-17T21:35:56.447907065+01:00
-5
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
-3
View File
@@ -1,3 +0,0 @@
## v0.3.0 - 2024-11-17
### Added
* Open the newly create work package after the wp has been created
-6
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
Generated
-37
View File
@@ -111,7 +111,6 @@ dependencies = [
"clap",
"gitlab",
"log",
"open",
"reqwest",
"serde",
"simple-home-dir",
@@ -739,15 +738,6 @@ version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146"
[[package]]
name = "is-docker"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3"
dependencies = [
"once_cell",
]
[[package]]
name = "is-terminal"
version = "0.4.5"
@@ -760,16 +750,6 @@ dependencies = [
"windows-sys 0.45.0",
]
[[package]]
name = "is-wsl"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5"
dependencies = [
"is-docker",
"once_cell",
]
[[package]]
name = "itertools"
version = "0.10.5"
@@ -929,17 +909,6 @@ version = "1.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
[[package]]
name = "open"
version = "5.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ecd52f0b8d15c40ce4820aa251ed5de032e5d91fab27f7db2f40d42a8bdf69c"
dependencies = [
"is-wsl",
"libc",
"pathdiff",
]
[[package]]
name = "openssl"
version = "0.10.62"
@@ -990,12 +959,6 @@ version = "6.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267"
[[package]]
name = "pathdiff"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361"
[[package]]
name = "percent-encoding"
version = "2.2.0"
-1
View File
@@ -15,4 +15,3 @@ url = "2.3.1"
tokio = { version = "1.0.0", features = ["rt", "rt-multi-thread", "macros"] }
simple-home-dir = "0.2.1"
log = "0.4.17"
open = "5.3.1"
+1 -6
View File
@@ -1,11 +1,6 @@
[[gitlab]]
[gitlab]
# generate from https://gitlab.com/-/user_settings/personal_access_tokens
token = "glpat-example"
domain = "gitlab.com"
[[gitea]]
token = "abcdexempletoken"
domain = "gitea.champs-libres.be"
[openproject]
# generate api token from https://champs-libres.openproject.com/my/access_token
+4 -4
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(())
*/
}
+15 -22
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,27 +26,18 @@ impl Issue2WorkActionTrait for GiteaAction {
Some(u)
}
false => None,
},
}
);
let work_package = open_project_client
.create_work_package(&work_package, &args.project_id)
.await?;
let url = format!(
"{}/projects/{}/work_packages/{}",
config.openproject.base_url, args.project_id, work_package.id
);
println!(
"new work package created: {:?}, edit at {}",
work_package.subject, url
"new work package created: {:?}, edit at {}/projects/{}/work_packages/{}",
work_package.subject, config.openproject.base_url, args.project_id, work_package.id
);
if let Err(e) = open::that(url) {
println!("failed to open work package in browser: {}", e);
};
Ok(())
}
@@ -57,14 +49,15 @@ 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
"{} ({})",
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()
}
}
}
+4 -16
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);
}
}
+5 -19
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");
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
pub(crate) mod action;
pub mod client;
pub mod issue;
pub mod repository;
pub(crate) mod action;
+1 -1
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 {
+2
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;