feat: replace dependencies and enable build on macos
Some checks failed
Release / release (push) Failing after 1m47s

Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
2026-03-20 17:29:11 +01:00
parent f0b8ffdb9b
commit 772aa1ea42
3 changed files with 436 additions and 834 deletions

1078
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -24,9 +24,7 @@ uuid = { version = "1.7.0", features = ["v4"] }
async-trait = "0.1.82" async-trait = "0.1.82"
toml = "0.8.19" toml = "0.8.19"
gitea-client = { git = "https://git.kjuulh.io/kjuulh/gitea-rs.git", default-features = false, features = ["rustls-ring"] } reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "json"] }
reqwest = { version = "0.13", default-features = false, features = ["__rustls", "json", "webpki-roots"] }
rustls = { version = "0.23", default-features = false, features = ["ring", "logging", "std", "tls12"] }
url = "2.5.2" url = "2.5.2"
dirs = "6.0.0" dirs = "6.0.0"
prost = "0.13.2" prost = "0.13.2"
@@ -40,7 +38,7 @@ termwiz = "0.23.0"
regex = "1.11.1" regex = "1.11.1"
minijinja = "2" minijinja = "2"
shell-words = "1" shell-words = "1"
chrono = { version = "0.4", features = ["serde"] } chrono = { version = "0.4", default-features = false, features = ["std", "now", "serde"] }
serde_json = "1" serde_json = "1"
[dev-dependencies] [dev-dependencies]

View File

@@ -1,18 +1,34 @@
use anyhow::Context; use anyhow::Context;
use gitea_client::apis::configuration::Configuration; use serde::Deserialize;
use url::Url; use url::Url;
use crate::{app::App, config::GiteaAccessToken}; use crate::{app::App, config::GiteaAccessToken};
#[derive(Debug, Deserialize)]
struct GiteaRepo {
name: Option<String>,
ssh_url: Option<String>,
owner: Option<GiteaUser>,
}
#[derive(Debug, Deserialize)]
struct GiteaUser {
login: Option<String>,
}
#[derive(Debug)] #[derive(Debug)]
pub struct GiteaProvider { pub struct GiteaProvider {
#[allow(dead_code)] #[allow(dead_code)]
app: &'static App, app: &'static App,
client: reqwest::Client,
} }
impl GiteaProvider { impl GiteaProvider {
pub fn new(app: &'static App) -> GiteaProvider { pub fn new(app: &'static App) -> GiteaProvider {
GiteaProvider { app } GiteaProvider {
app,
client: reqwest::Client::new(),
}
} }
pub async fn list_repositories_for_current_user( pub async fn list_repositories_for_current_user(
@@ -22,39 +38,23 @@ impl GiteaProvider {
) -> anyhow::Result<Vec<super::Repository>> { ) -> anyhow::Result<Vec<super::Repository>> {
tracing::debug!("fetching gitea repositories for current user"); tracing::debug!("fetching gitea repositories for current user");
let config = self.get_config(api, access_token)?;
let mut repositories = Vec::new(); let mut repositories = Vec::new();
let mut page = 1; let mut page = 1;
loop { loop {
let mut repos = self let repos: Vec<GiteaRepo> = self
.list_repositories_for_current_user_with_page(&config, page) .request(&format!("{api}/user/repos"), access_token, page)
.await?; .await?;
if repos.is_empty() { if repos.is_empty() {
break; break;
} }
repositories.append(&mut repos); repositories.extend(repos);
page += 1; page += 1;
} }
let provider = &Self::get_domain(api)?; let provider = &Self::get_domain(api)?;
Ok(to_repositories(provider, repositories))
Ok(repositories
.into_iter()
.map(|repo| super::Repository {
provider: provider.into(),
owner: repo
.owner
.map(|user| user.login.unwrap_or_default())
.unwrap_or_default(),
repo_name: repo.name.unwrap_or_default(),
ssh_url: repo
.ssh_url
.expect("ssh url to be set for a gitea repository"),
})
.collect())
} }
fn get_domain(api: &str) -> anyhow::Result<String> { fn get_domain(api: &str) -> anyhow::Result<String> {
@@ -64,19 +64,6 @@ impl GiteaProvider {
Ok(provider.into()) Ok(provider.into())
} }
async fn list_repositories_for_current_user_with_page(
&self,
config: &Configuration,
page: usize,
) -> anyhow::Result<Vec<gitea_client::models::Repository>> {
let repos =
gitea_client::apis::user_api::user_current_list_repos(config, Some(page as i32), None)
.await
.context("failed to fetch repos for users")?;
Ok(repos)
}
pub async fn list_repositories_for_user( pub async fn list_repositories_for_user(
&self, &self,
user: &str, user: &str,
@@ -85,53 +72,27 @@ impl GiteaProvider {
) -> anyhow::Result<Vec<super::Repository>> { ) -> anyhow::Result<Vec<super::Repository>> {
tracing::debug!(user = user, "fetching gitea repositories for user"); tracing::debug!(user = user, "fetching gitea repositories for user");
let config = self.get_config(api, access_token)?;
let mut repositories = Vec::new(); let mut repositories = Vec::new();
let mut page = 1; let mut page = 1;
loop { loop {
let mut repos = self let repos: Vec<GiteaRepo> = self
.list_repositories_for_user_with_page(user, &config, page) .request(
&format!("{api}/users/{user}/repos"),
access_token,
page,
)
.await?; .await?;
if repos.is_empty() { if repos.is_empty() {
break; break;
} }
repositories.append(&mut repos); repositories.extend(repos);
page += 1; page += 1;
} }
let provider = &Self::get_domain(api)?; let provider = &Self::get_domain(api)?;
Ok(to_repositories(provider, repositories))
Ok(repositories
.into_iter()
.map(|repo| super::Repository {
provider: provider.into(),
owner: repo
.owner
.map(|user| user.login.unwrap_or_default())
.unwrap_or_default(),
repo_name: repo.name.unwrap_or_default(),
ssh_url: repo
.ssh_url
.expect("ssh url to be set for gitea repository"),
})
.collect())
}
pub async fn list_repositories_for_user_with_page(
&self,
user: &str,
config: &Configuration,
page: usize,
) -> anyhow::Result<Vec<gitea_client::models::Repository>> {
let repos =
gitea_client::apis::user_api::user_list_repos(config, user, Some(page as i32), None)
.await
.context("failed to fetch repos for users")?;
Ok(repos)
} }
pub async fn list_repositories_for_organisation( pub async fn list_repositories_for_organisation(
@@ -144,83 +105,78 @@ impl GiteaProvider {
organisation = organisation, organisation = organisation,
"fetching gitea repositories for organisation" "fetching gitea repositories for organisation"
); );
let config = self.get_config(api, access_token)?;
let mut repositories = Vec::new(); let mut repositories = Vec::new();
let mut page = 1; let mut page = 1;
loop { loop {
let mut repos = self let repos: Vec<GiteaRepo> = self
.list_repositories_for_organisation_with_page(organisation, &config, page) .request(
&format!("{api}/orgs/{organisation}/repos"),
access_token,
page,
)
.await?; .await?;
if repos.is_empty() { if repos.is_empty() {
break; break;
} }
repositories.append(&mut repos); repositories.extend(repos);
page += 1; page += 1;
} }
let provider = &Self::get_domain(api)?; let provider = &Self::get_domain(api)?;
Ok(to_repositories(provider, repositories))
Ok(repositories
.into_iter()
.map(|repo| super::Repository {
provider: provider.into(),
owner: repo
.owner
.map(|user| user.login.unwrap_or_default())
.unwrap_or_default(),
repo_name: repo.name.unwrap_or_default(),
ssh_url: repo
.ssh_url
.expect("ssh url to be set for gitea repository"),
})
.collect())
} }
pub async fn list_repositories_for_organisation_with_page( async fn request<T: serde::de::DeserializeOwned>(
&self, &self,
organisation: &str, url: &str,
config: &Configuration,
page: usize,
) -> anyhow::Result<Vec<gitea_client::models::Repository>> {
let repos = gitea_client::apis::organization_api::org_list_repos(
config,
organisation,
Some(page as i32),
None,
)
.await
.context("failed to fetch repos for users")?;
Ok(repos)
}
fn get_config(
&self,
api: &str,
access_token: Option<&GiteaAccessToken>, access_token: Option<&GiteaAccessToken>,
) -> anyhow::Result<Configuration> { page: usize,
let mut config = gitea_client::apis::configuration::Configuration::new(); ) -> anyhow::Result<T> {
config.base_path = api.into(); let mut req = self.client.get(url).query(&[("page", page.to_string())]);
match access_token { match access_token {
Some(GiteaAccessToken::Env { env }) => { Some(GiteaAccessToken::Env { env }) => {
let token = let token =
std::env::var(env).context(format!("{env} didn't have a valid value"))?; std::env::var(env).context(format!("{env} didn't have a valid value"))?;
req = req.basic_auth("", Some(token));
config.basic_auth = Some(("".into(), Some(token)));
} }
Some(GiteaAccessToken::Direct(var)) => { Some(GiteaAccessToken::Direct(var)) => {
config.bearer_access_token = Some(var.to_owned()); req = req.bearer_auth(var);
} }
None => {} None => {}
} }
Ok(config) req.send()
.await
.context("failed to send request")?
.error_for_status()
.context("request failed")?
.json()
.await
.context("failed to parse response")
} }
} }
fn to_repositories(provider: &str, repos: Vec<GiteaRepo>) -> Vec<super::Repository> {
repos
.into_iter()
.map(|repo| super::Repository {
provider: provider.into(),
owner: repo
.owner
.map(|user| user.login.unwrap_or_default())
.unwrap_or_default(),
repo_name: repo.name.unwrap_or_default(),
ssh_url: repo
.ssh_url
.expect("ssh url to be set for a gitea repository"),
})
.collect()
}
pub trait GiteaProviderApp { pub trait GiteaProviderApp {
fn gitea_provider(&self) -> GiteaProvider; fn gitea_provider(&self) -> GiteaProvider;
} }