feat: gitea able to pull repositories
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
parent
d969f799b0
commit
ca989486d4
968
Cargo.lock
generated
968
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -16,3 +16,6 @@ serde = { version = "1.0.197", features = ["derive"] }
|
|||||||
uuid = { version = "1.7.0", features = ["v4"] }
|
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-rs = { git = "https://git.front.kjuulh.io/kjuulh/gitea-rs", ref = "main", version = "1.22.1" }
|
||||||
|
url = "2.5.2"
|
||||||
|
@ -0,0 +1,188 @@
|
|||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use anyhow::Context;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
pub struct Config {
|
||||||
|
#[serde(default)]
|
||||||
|
pub providers: Providers,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Serialize, Deserialize, PartialEq)]
|
||||||
|
pub struct Providers {
|
||||||
|
#[serde(default)]
|
||||||
|
pub github: Vec<GitHub>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub gitea: Vec<Gitea>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
pub struct GitHub {
|
||||||
|
#[serde(default)]
|
||||||
|
pub users: Vec<GitHubUser>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub organisations: Vec<GitHubOrganisation>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
pub struct GitHubUser(String);
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
pub struct GitHubOrganisation(String);
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
pub struct Gitea {
|
||||||
|
pub url: String,
|
||||||
|
pub access_token: Option<GiteaAccessToken>,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub current_user: Option<String>,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub users: Vec<GiteaUser>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub organisations: Vec<GiteaOrganisation>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum GiteaAccessToken {
|
||||||
|
Direct(String),
|
||||||
|
Env { env: String },
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
pub struct GiteaUser(String);
|
||||||
|
|
||||||
|
impl From<GiteaUser> for String {
|
||||||
|
fn from(value: GiteaUser) -> Self {
|
||||||
|
value.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a GiteaUser> for &'a str {
|
||||||
|
fn from(value: &'a GiteaUser) -> Self {
|
||||||
|
value.0.as_str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
pub struct GiteaOrganisation(String);
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
pub async fn from_file(file_path: &Path) -> anyhow::Result<Config> {
|
||||||
|
if !file_path.exists() {
|
||||||
|
if let Some(parent) = file_path.parent() {
|
||||||
|
tokio::fs::create_dir_all(parent).await?;
|
||||||
|
}
|
||||||
|
tokio::fs::File::create(file_path).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let file_content = tokio::fs::read_to_string(file_path).await?;
|
||||||
|
|
||||||
|
Self::from_string(&file_content)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_string(content: &str) -> anyhow::Result<Config> {
|
||||||
|
toml::from_str(content).context("failed to deserialize config file")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_can_parse_config() -> anyhow::Result<()> {
|
||||||
|
let content = r#"
|
||||||
|
[[providers.github]]
|
||||||
|
users = ["kjuulh"]
|
||||||
|
organisations = ["lunarway"]
|
||||||
|
|
||||||
|
[[providers.github]]
|
||||||
|
users = ["other"]
|
||||||
|
organisations = ["org"]
|
||||||
|
|
||||||
|
[[providers.gitea]]
|
||||||
|
url = "https://git.front.kjuulh.io/api/v1"
|
||||||
|
current_user = "kjuulh"
|
||||||
|
users = ["kjuulh"]
|
||||||
|
organisations = ["lunarway"]
|
||||||
|
|
||||||
|
[[providers.gitea]]
|
||||||
|
url = "https://git.front.kjuulh.io/api/v1"
|
||||||
|
users = ["other"]
|
||||||
|
organisations = ["org"]
|
||||||
|
|
||||||
|
[[providers.gitea]]
|
||||||
|
url = "https://git.front.kjuulh.io/api/v1"
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let config = Config::from_string(content)?;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Config {
|
||||||
|
providers: Providers {
|
||||||
|
github: vec![
|
||||||
|
GitHub {
|
||||||
|
users: vec![GitHubUser("kjuulh".into())],
|
||||||
|
organisations: vec![GitHubOrganisation("lunarway".into())]
|
||||||
|
},
|
||||||
|
GitHub {
|
||||||
|
users: vec![GitHubUser("other".into())],
|
||||||
|
organisations: vec![GitHubOrganisation("org".into())]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
gitea: vec![
|
||||||
|
Gitea {
|
||||||
|
url: "https://git.front.kjuulh.io/api/v1".into(),
|
||||||
|
users: vec![GiteaUser("kjuulh".into())],
|
||||||
|
organisations: vec![GiteaOrganisation("lunarway".into())],
|
||||||
|
access_token: None,
|
||||||
|
current_user: Some("kjuulh".into())
|
||||||
|
},
|
||||||
|
Gitea {
|
||||||
|
url: "https://git.front.kjuulh.io/api/v1".into(),
|
||||||
|
users: vec![GiteaUser("other".into())],
|
||||||
|
organisations: vec![GiteaOrganisation("org".into())],
|
||||||
|
access_token: None,
|
||||||
|
current_user: None
|
||||||
|
},
|
||||||
|
Gitea {
|
||||||
|
url: "https://git.front.kjuulh.io/api/v1".into(),
|
||||||
|
users: vec![],
|
||||||
|
organisations: vec![],
|
||||||
|
access_token: None,
|
||||||
|
current_user: None
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
config
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_can_parse_empty_config() -> anyhow::Result<()> {
|
||||||
|
let content = r#"
|
||||||
|
# empty file
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let config = Config::from_string(content)?;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Config {
|
||||||
|
providers: Providers {
|
||||||
|
github: vec![],
|
||||||
|
gitea: vec![]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
config
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
44
crates/gitnow/src/git_provider.rs
Normal file
44
crates/gitnow/src/git_provider.rs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
use std::{collections::HashMap, path::PathBuf, str::FromStr};
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||||
|
pub struct Repository {
|
||||||
|
pub provider: String,
|
||||||
|
pub owner: String,
|
||||||
|
pub repo_name: String,
|
||||||
|
pub ssh_url: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Repository {
|
||||||
|
pub fn to_rel_path(&self) -> PathBuf {
|
||||||
|
PathBuf::from(&self.provider)
|
||||||
|
.join(&self.owner)
|
||||||
|
.join(&self.repo_name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait VecRepositoryExt {
|
||||||
|
fn collect_unique(&mut self) -> &mut Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VecRepositoryExt for Vec<Repository> {
|
||||||
|
fn collect_unique(&mut self) -> &mut Self {
|
||||||
|
self.sort_by_key(|a| a.to_rel_path());
|
||||||
|
self.dedup_by_key(|a| a.to_rel_path());
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
pub trait GitProvider {
|
||||||
|
async fn list_repositories_for_user(&self, user: &str) -> anyhow::Result<Vec<Repository>>;
|
||||||
|
async fn list_repositories_for_organisation(
|
||||||
|
&self,
|
||||||
|
organisation: &str,
|
||||||
|
) -> anyhow::Result<Vec<Repository>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod gitea;
|
||||||
|
pub mod github;
|
185
crates/gitnow/src/git_provider/gitea.rs
Normal file
185
crates/gitnow/src/git_provider/gitea.rs
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
use anyhow::Context;
|
||||||
|
use gitea_rs::apis::configuration::{ApiKey, Configuration};
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
use crate::{app::App, config::GiteaAccessToken};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GiteaProvider {
|
||||||
|
app: &'static App,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GiteaProvider {
|
||||||
|
pub fn new(app: &'static App) -> GiteaProvider {
|
||||||
|
GiteaProvider { app }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip(self))]
|
||||||
|
pub async fn list_repositories_for_current_user(
|
||||||
|
&self,
|
||||||
|
user: &str,
|
||||||
|
api: &str,
|
||||||
|
access_token: Option<&GiteaAccessToken>,
|
||||||
|
) -> anyhow::Result<Vec<super::Repository>> {
|
||||||
|
tracing::debug!("fetching gitea repositories for user");
|
||||||
|
|
||||||
|
let mut config = gitea_rs::apis::configuration::Configuration::new();
|
||||||
|
config.base_path = api.into();
|
||||||
|
match access_token {
|
||||||
|
Some(GiteaAccessToken::Env { env }) => {
|
||||||
|
let token =
|
||||||
|
std::env::var(env).context(format!("{env} didn't have a valid value"))?;
|
||||||
|
|
||||||
|
config.basic_auth = Some((user.into(), Some(token)));
|
||||||
|
}
|
||||||
|
Some(GiteaAccessToken::Direct(var)) => {
|
||||||
|
config.bearer_access_token = Some(var.to_owned());
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut repositories = Vec::new();
|
||||||
|
let mut page = 1;
|
||||||
|
loop {
|
||||||
|
let mut repos = self
|
||||||
|
.list_repositories_for_current_user_with_page(user, &config, page)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if repos.is_empty() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories.append(&mut repos);
|
||||||
|
page += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let provider = &Self::get_domain(api)?;
|
||||||
|
|
||||||
|
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> {
|
||||||
|
let url = Url::parse(api)?;
|
||||||
|
let provider = url.domain().unwrap_or("gitea");
|
||||||
|
|
||||||
|
Ok(provider.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip(self))]
|
||||||
|
async fn list_repositories_for_current_user_with_page(
|
||||||
|
&self,
|
||||||
|
user: &str,
|
||||||
|
config: &Configuration,
|
||||||
|
page: usize,
|
||||||
|
) -> anyhow::Result<Vec<gitea_rs::models::Repository>> {
|
||||||
|
let repos =
|
||||||
|
gitea_rs::apis::user_api::user_current_list_repos(config, Some(page as i32), None)
|
||||||
|
.await
|
||||||
|
.context("failed to fetch repos for users")?;
|
||||||
|
|
||||||
|
Ok(repos)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip(self))]
|
||||||
|
pub async fn list_repositories_for_user(
|
||||||
|
&self,
|
||||||
|
user: &str,
|
||||||
|
api: &str,
|
||||||
|
access_token: Option<&GiteaAccessToken>,
|
||||||
|
) -> anyhow::Result<Vec<super::Repository>> {
|
||||||
|
tracing::debug!("fetching gitea repositories for user");
|
||||||
|
|
||||||
|
let mut config = gitea_rs::apis::configuration::Configuration::new();
|
||||||
|
config.base_path = api.into();
|
||||||
|
match access_token {
|
||||||
|
Some(GiteaAccessToken::Env { env }) => {
|
||||||
|
let token =
|
||||||
|
std::env::var(env).context(format!("{env} didn't have a valid value"))?;
|
||||||
|
|
||||||
|
config.basic_auth = Some((user.into(), Some(token)));
|
||||||
|
}
|
||||||
|
Some(GiteaAccessToken::Direct(var)) => {
|
||||||
|
config.bearer_access_token = Some(var.to_owned());
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut repositories = Vec::new();
|
||||||
|
let mut page = 1;
|
||||||
|
loop {
|
||||||
|
let mut repos = self
|
||||||
|
.list_repositories_for_user_with_page(user, &config, page)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if repos.is_empty() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories.append(&mut repos);
|
||||||
|
page += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let provider = &Self::get_domain(api)?;
|
||||||
|
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip(self))]
|
||||||
|
pub async fn list_repositories_for_user_with_page(
|
||||||
|
&self,
|
||||||
|
user: &str,
|
||||||
|
config: &Configuration,
|
||||||
|
page: usize,
|
||||||
|
) -> anyhow::Result<Vec<gitea_rs::models::Repository>> {
|
||||||
|
let repos =
|
||||||
|
gitea_rs::apis::user_api::user_list_repos(config, user, Some(page as i32), None)
|
||||||
|
.await
|
||||||
|
.context("failed to fetch repos for users")?;
|
||||||
|
|
||||||
|
Ok(repos)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument]
|
||||||
|
pub async fn list_repositories_for_organisation(
|
||||||
|
&self,
|
||||||
|
organisation: &str,
|
||||||
|
) -> anyhow::Result<Vec<super::Repository>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait GiteaProviderApp {
|
||||||
|
fn gitea_provider(&self) -> GiteaProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GiteaProviderApp for &'static App {
|
||||||
|
fn gitea_provider(&self) -> GiteaProvider {
|
||||||
|
GiteaProvider::new(self)
|
||||||
|
}
|
||||||
|
}
|
42
crates/gitnow/src/git_provider/github.rs
Normal file
42
crates/gitnow/src/git_provider/github.rs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
use async_trait::async_trait;
|
||||||
|
|
||||||
|
use crate::app::App;
|
||||||
|
|
||||||
|
use super::GitProvider;
|
||||||
|
|
||||||
|
pub struct GitHubProvider {
|
||||||
|
app: &'static App,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GitHubProvider {
|
||||||
|
pub fn new(app: &'static App) -> GitHubProvider {
|
||||||
|
GitHubProvider { app }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl GitProvider for GitHubProvider {
|
||||||
|
async fn list_repositories_for_user(
|
||||||
|
&self,
|
||||||
|
user: &str,
|
||||||
|
) -> anyhow::Result<Vec<super::Repository>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn list_repositories_for_organisation(
|
||||||
|
&self,
|
||||||
|
organisation: &str,
|
||||||
|
) -> anyhow::Result<Vec<super::Repository>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait GitHubProviderApp {
|
||||||
|
fn github_provider(&self) -> GitHubProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GitHubProviderApp for &'static App {
|
||||||
|
fn github_provider(&self) -> GitHubProvider {
|
||||||
|
GitHubProvider::new(self)
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,12 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use commands::root::RootCommand;
|
use commands::root::RootCommand;
|
||||||
|
use config::Config;
|
||||||
|
|
||||||
|
mod config;
|
||||||
|
mod git_provider;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(author, version, about, long_about = Some("Navigate git projects at the speed of thought"))]
|
#[command(author, version, about, long_about = Some("Navigate git projects at the speed of thought"))]
|
||||||
@ -14,11 +20,23 @@ enum Commands {
|
|||||||
Hello {},
|
Hello {},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DEFAULT_CONFIG_PATH: &str = ".config/gitnow/gitnow.toml";
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> anyhow::Result<()> {
|
async fn main() -> anyhow::Result<()> {
|
||||||
dotenv::dotenv().ok();
|
dotenv::dotenv().ok();
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
let app = app::App::new_static();
|
|
||||||
|
let home =
|
||||||
|
std::env::var("HOME").context("HOME was not found, are you using a proper shell?")?;
|
||||||
|
let default_config_path = PathBuf::from(home).join(DEFAULT_CONFIG_PATH);
|
||||||
|
let config_path = std::env::var("GITNOW_CONFIG")
|
||||||
|
.map(PathBuf::from)
|
||||||
|
.unwrap_or(default_config_path);
|
||||||
|
|
||||||
|
let config = Config::from_file(&config_path).await?;
|
||||||
|
|
||||||
|
let app = app::App::new_static(config).await?;
|
||||||
|
|
||||||
let cli = Command::parse();
|
let cli = Command::parse();
|
||||||
tracing::debug!("Starting cli");
|
tracing::debug!("Starting cli");
|
||||||
@ -33,33 +51,29 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
mod config;
|
|
||||||
|
|
||||||
mod git_provider {
|
|
||||||
use async_trait::async_trait;
|
|
||||||
|
|
||||||
pub struct Repository {}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
pub trait GitProvider {
|
|
||||||
async fn list_repositories(&self) -> anyhow::Result<Vec<Repository>>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod app {
|
mod app {
|
||||||
|
use crate::config::Config;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct App {}
|
pub struct App {
|
||||||
|
pub config: Config,
|
||||||
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
pub fn new_static() -> &'static App {
|
pub async fn new_static(config: Config) -> anyhow::Result<&'static App> {
|
||||||
Box::leak(Box::new(App {}))
|
Ok(Box::leak(Box::new(App { config })))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod commands {
|
mod commands {
|
||||||
pub mod root {
|
pub mod root {
|
||||||
use crate::app::App;
|
use crate::{
|
||||||
|
app::App,
|
||||||
|
git_provider::{
|
||||||
|
gitea::GiteaProviderApp, github::GitHubProviderApp, GitProvider, VecRepositoryExt,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct RootCommand {
|
pub struct RootCommand {
|
||||||
@ -71,10 +85,48 @@ mod commands {
|
|||||||
Self { app }
|
Self { app }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument]
|
#[tracing::instrument(skip(self))]
|
||||||
pub async fn execute(&mut self) -> anyhow::Result<()> {
|
pub async fn execute(&mut self) -> anyhow::Result<()> {
|
||||||
tracing::debug!("executing");
|
tracing::debug!("executing");
|
||||||
|
|
||||||
|
//let github_provider = self.app.github_provider();
|
||||||
|
let gitea_provider = self.app.gitea_provider();
|
||||||
|
|
||||||
|
let mut repositories = Vec::new();
|
||||||
|
for gitea in self.app.config.providers.gitea.iter() {
|
||||||
|
if let Some(user) = &gitea.current_user {
|
||||||
|
let mut repos = gitea_provider
|
||||||
|
.list_repositories_for_current_user(
|
||||||
|
user,
|
||||||
|
&gitea.url,
|
||||||
|
gitea.access_token.as_ref(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
repositories.append(&mut repos);
|
||||||
|
}
|
||||||
|
|
||||||
|
for gitea_user in gitea.users.iter() {
|
||||||
|
let mut repos = gitea_provider
|
||||||
|
.list_repositories_for_user(
|
||||||
|
gitea_user.into(),
|
||||||
|
&gitea.url,
|
||||||
|
gitea.access_token.as_ref(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
repositories.append(&mut repos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories.collect_unique();
|
||||||
|
|
||||||
|
for repo in &repositories {
|
||||||
|
tracing::info!("repo: {}", repo.to_rel_path().display());
|
||||||
|
}
|
||||||
|
|
||||||
|
tracing::info!("amount of repos fetched {}", repositories.len());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user