Skip to content

Commit

Permalink
feat(webserver): list config repositories from the repository_list en…
Browse files Browse the repository at this point in the history
…dpoint (TabbyML#2379)

* feat(webserver): list config repositories from the repository_list endpoint

* [autofix.ci] apply automated fixes

* [autofix.ci] apply automated fixes (attempt 2/3)

* Fix

* Resolve repositories from config

* Use sanitized repository name

* Remove reference to anyhow

* Resolve comments

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
  • Loading branch information
boxbeam and autofix-ci[bot] authored Jun 18, 2024
1 parent 04de905 commit 3ef1bc4
Show file tree
Hide file tree
Showing 11 changed files with 81 additions and 10 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/tabby-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ async-trait.workspace = true
thiserror.workspace = true
url.workspace = true
derive_builder.workspace = true
hash-ids.workspace = true

[dev-dependencies]
temp_testdir = { workspace = true }
Expand Down
32 changes: 31 additions & 1 deletion crates/tabby-common/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use std::{collections::HashSet, path::PathBuf};
use anyhow::{anyhow, Context, Result};
use async_trait::async_trait;
use derive_builder::Builder;
use hash_ids::HashIds;
use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};

use crate::{
Expand Down Expand Up @@ -71,6 +73,30 @@ impl Config {
}
}

lazy_static! {
static ref HASHER: HashIds = HashIds::builder()
.with_salt("tabby-config-id-serializer")
.with_min_length(6)
.finish();
}

pub fn config_index_to_id(index: usize) -> String {
let id = HASHER.encode(&[index as u64]);
format!("config:{id}")
}

pub fn config_id_to_index(id: &str) -> Result<usize, anyhow::Error> {
let id = id
.strip_prefix("config:")
.ok_or_else(|| anyhow!("Invalid config ID"))?;

HASHER
.decode(id)
.first()
.map(|i| *i as usize)
.ok_or_else(|| anyhow!("Invalid config ID"))
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct RepositoryConfig {
pub git_url: String,
Expand Down Expand Up @@ -103,10 +129,14 @@ impl RepositoryConfig {
let path = self.git_url.strip_prefix("file://").unwrap();
path.into()
} else {
repositories_dir().join(sanitize_name(&self.canonical_git_url()))
repositories_dir().join(self.dir_name())
}
}

pub fn dir_name(&self) -> String {
sanitize_name(&self.canonical_git_url())
}

pub fn is_local_dir(&self) -> bool {
self.git_url.starts_with("file://")
}
Expand Down
1 change: 1 addition & 0 deletions ee/tabby-schema/src/schema/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ impl Query {

async fn repository_list(ctx: &Context) -> Result<Vec<Repository>> {
check_user(ctx).await?;

ctx.locator.repository().repository_list().await
}

Expand Down
3 changes: 2 additions & 1 deletion ee/tabby-schema/src/schema/repository/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,5 +288,6 @@ pub trait RepositoryService: Send + Sync {
fn git(&self) -> Arc<dyn GitRepositoryService>;
fn third_party(&self) -> Arc<dyn ThirdPartyRepositoryService>;

async fn list_repositories(&self) -> Result<Vec<RepositoryConfig>>;
async fn list_all_repository_urls(&self) -> Result<Vec<RepositoryConfig>>;
fn configured_repositories(&self) -> Vec<RepositoryConfig>;
}
6 changes: 5 additions & 1 deletion ee/tabby-webserver/src/routes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,11 @@ pub fn create(ctx: Arc<dyn ServiceLocator>, api: Router, ui: Router) -> (Router,
)
.nest(
"/repositories",
repositories::routes(ctx.repository(), ctx.auth()),
repositories::routes(
ctx.repository(),
ctx.auth(),
ctx.repository().configured_repositories(),
),
)
.route(
"/avatar/:id",
Expand Down
4 changes: 3 additions & 1 deletion ee/tabby-webserver/src/routes/repositories/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use axum::{
routing, Router,
};
use resolve::{ResolveParams, ResolveState};
use tabby_common::config::RepositoryConfig;
use tabby_schema::{auth::AuthenticationService, repository::RepositoryService};
use tracing::instrument;

Expand All @@ -19,14 +20,15 @@ use super::require_login_middleware;
pub fn routes(
repository: Arc<dyn RepositoryService>,
auth: Arc<dyn AuthenticationService>,
config: Vec<RepositoryConfig>,
) -> Router {
Router::new()
.route("/:kind/:id/resolve/", routing::get(resolve_path))
.route("/:kind/:id/resolve/*path", routing::get(resolve_path))
// Routes support viewing a specific revision of a repository
.route("/:kind/:id/rev/:rev/", routing::get(resolve_path))
.route("/:kind/:id/rev/:rev/*path", routing::get(resolve_path))
.with_state(Arc::new(ResolveState::new(repository)))
.with_state(Arc::new(ResolveState::new(repository, config)))
.fallback(not_found)
.layer(from_fn_with_state(auth, require_login_middleware))
}
Expand Down
10 changes: 8 additions & 2 deletions ee/tabby-webserver/src/routes/repositories/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use axum::{body::Body, response::Response};
use hyper::StatusCode;
use juniper::ID;
use serde::Deserialize;
use tabby_common::config::{config_id_to_index, RepositoryConfig};
use tabby_schema::repository::{RepositoryKind, RepositoryService};

#[derive(Deserialize, Debug)]
Expand All @@ -17,14 +18,19 @@ pub struct ResolveParams {

pub(super) struct ResolveState {
service: Arc<dyn RepositoryService>,
config: Vec<RepositoryConfig>,
}

impl ResolveState {
pub fn new(service: Arc<dyn RepositoryService>) -> Self {
Self { service }
pub fn new(service: Arc<dyn RepositoryService>, config: Vec<RepositoryConfig>) -> Self {
Self { service, config }
}

async fn find_repository(&self, params: &ResolveParams) -> Option<PathBuf> {
if let Ok(index) = config_id_to_index(&params.id) {
return Some(self.config.get(index)?.dir());
}

let repository = self
.service
.resolve_repository(&params.kind, &params.id)
Expand Down
1 change: 1 addition & 0 deletions ee/tabby-webserver/src/service/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ impl ServerContext {
let user_event = Arc::new(user_event::create(db_conn.clone()));
let job = Arc::new(job::create(db_conn.clone()).await);
let setting = Arc::new(setting::create(db_conn.clone()));

Self {
mail: mail.clone(),
auth: Arc::new(auth::create(
Expand Down
30 changes: 27 additions & 3 deletions ee/tabby-webserver/src/service/repository/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::sync::Arc;
use async_trait::async_trait;
use futures::StreamExt;
use juniper::ID;
use tabby_common::config::RepositoryConfig;
use tabby_common::config::{config_index_to_id, Config, RepositoryConfig};
use tabby_db::DbConn;
use tabby_schema::{
integration::IntegrationService,
Expand All @@ -23,6 +23,7 @@ use crate::service::background_job::BackgroundJobEvent;
struct RepositoryServiceImpl {
git: Arc<dyn GitRepositoryService>,
third_party: Arc<dyn ThirdPartyRepositoryService>,
config: Vec<RepositoryConfig>,
}

pub fn create(
Expand All @@ -33,12 +34,15 @@ pub fn create(
Arc::new(RepositoryServiceImpl {
git: Arc::new(git::create(db.clone(), background.clone())),
third_party: Arc::new(third_party::create(db, integration, background.clone())),
config: Config::load()
.map(|config| config.repositories)
.unwrap_or_default(),
})
}

#[async_trait]
impl RepositoryService for RepositoryServiceImpl {
async fn list_repositories(&self) -> Result<Vec<RepositoryConfig>> {
async fn list_all_repository_urls(&self) -> Result<Vec<RepositoryConfig>> {
let mut repos: Vec<RepositoryConfig> = self
.git
.list(None, None, None, None)
Expand Down Expand Up @@ -69,6 +73,22 @@ impl RepositoryService for RepositoryServiceImpl {
let mut all = vec![];
all.extend(self.git().repository_list().await?);
all.extend(self.third_party().repository_list().await?);
all.extend(
self.config
.iter()
.enumerate()
.map(|(index, repo)| {
Ok(Repository {
id: ID::new(config_index_to_id(index)),
name: repo.dir_name(),
kind: RepositoryKind::Git,
dir: repo.dir(),
refs: tabby_git::list_refs(&repo.dir())?,
git_url: repo.git_url.clone(),
})
})
.collect::<Result<Vec<_>>>()?,
);

Ok(all)
}
Expand Down Expand Up @@ -140,6 +160,10 @@ impl RepositoryService for RepositoryServiceImpl {

Ok(ret)
}

fn configured_repositories(&self) -> Vec<RepositoryConfig> {
self.config.clone()
}
}

fn to_grep_file(file: tabby_git::GrepFile) -> tabby_schema::repository::GrepFile {
Expand Down Expand Up @@ -213,7 +237,7 @@ mod tests {
.unwrap();

// FIXME(boxbeam): add repo with github service once there's syncing logic.
let repos = service.list_repositories().await.unwrap();
let repos = service.list_all_repository_urls().await.unwrap();
assert_eq!(repos.len(), 1);
}
}
2 changes: 1 addition & 1 deletion ee/tabby-webserver/src/webserver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub struct Webserver {
impl ConfigAccess for Webserver {
async fn repositories(&self) -> anyhow::Result<Vec<RepositoryConfig>> {
let mut repos = Config::load().map(|x| x.repositories).unwrap_or_default();
repos.extend(self.repository.list_repositories().await?);
repos.extend(self.repository.list_all_repository_urls().await?);
Ok(repos)
}
}
Expand Down

0 comments on commit 3ef1bc4

Please sign in to comment.