Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(webserver): support browsing github / gitlab repositories. #1968

Merged
merged 3 commits into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions ee/tabby-db/src/github_repository_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,20 @@
Ok(())
}

pub async fn get_github_provided_repository(
&self,
id: i64,
) -> Result<GithubProvidedRepositoryDAO> {
let repo = query_as!(
GithubProvidedRepositoryDAO,
"SELECT id, vendor_id, name, git_url, active, github_repository_provider_id FROM github_provided_repositories WHERE id = ?",
id
)
.fetch_one(&self.pool)
.await?;
Ok(repo)
}

Check warning on line 181 in ee/tabby-db/src/github_repository_provider.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-db/src/github_repository_provider.rs#L169-L181

Added lines #L169 - L181 were not covered by tests

pub async fn list_github_provided_repositories(
&self,
provider_ids: Vec<i64>,
Expand Down
14 changes: 14 additions & 0 deletions ee/tabby-db/src/gitlab_repository_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,20 @@
Ok(())
}

pub async fn get_gitlab_provided_repository(
&self,
id: i64,
) -> Result<GitlabProvidedRepositoryDAO> {
let repo = query_as!(
GitlabProvidedRepositoryDAO,
"SELECT id, vendor_id, name, git_url, active, gitlab_repository_provider_id FROM gitlab_provided_repositories WHERE id = ?",
id
)
.fetch_one(&self.pool)
.await?;
Ok(repo)
}

Check warning on line 181 in ee/tabby-db/src/gitlab_repository_provider.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-db/src/gitlab_repository_provider.rs#L169-L181

Added lines #L169 - L181 were not covered by tests

pub async fn list_gitlab_provided_repositories(
&self,
provider_ids: Vec<i64>,
Expand Down
10 changes: 3 additions & 7 deletions ee/tabby-db/src/repositories.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,11 @@
}
}

pub async fn get_repository_by_name(&self, name: &str) -> Result<RepositoryDAO> {
pub async fn get_repository(&self, id: i64) -> Result<RepositoryDAO> {

Check warning on line 70 in ee/tabby-db/src/repositories.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-db/src/repositories.rs#L70

Added line #L70 was not covered by tests
let repository = sqlx::query_as!(
RepositoryDAO,
"SELECT id as 'id!: i64', name, git_url FROM repositories WHERE name = ?",
name
"SELECT id as 'id!: i64', name, git_url FROM repositories WHERE id = ?",
id

Check warning on line 74 in ee/tabby-db/src/repositories.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-db/src/repositories.rs#L73-L74

Added lines #L73 - L74 were not covered by tests
)
.fetch_one(&self.pool)
.await?;
Expand Down Expand Up @@ -112,9 +112,5 @@
.unwrap()[0];
assert_eq!(repository.git_url, "testurl2");
assert_eq!(repository.name, "test2");
assert_eq!(
conn.get_repository_by_name("test2").await.unwrap().git_url,
repository.git_url
);
}
}
15 changes: 14 additions & 1 deletion ee/tabby-webserver/graphql/schema.graphql
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
type Repository {
id: ID!
name: String!
kind: RepositoryKind!
}

input UpdateRepositoryProviderInput {
id: ID!
displayName: String!
Expand Down Expand Up @@ -283,7 +289,7 @@ type Query {
networkSetting: NetworkSetting!
securitySetting: SecuritySetting!
gitRepositories(after: String, before: String, first: Int, last: Int): RepositoryConnection!
repositorySearch(repositoryName: String!, pattern: String!): [FileEntrySearchResult!]!
repositorySearch(kind: RepositoryKind!, id: ID!, pattern: String!): [FileEntrySearchResult!]!
oauthCredential(provider: OAuthProvider!): OAuthCredential
oauthCallbackUrl(provider: OAuthProvider!): String!
serverInfo: ServerInfo!
Expand All @@ -293,6 +299,7 @@ type Query {
dailyStats(start: DateTimeUtc!, end: DateTimeUtc!, users: [ID!], languages: [Language!]): [CompletionStats!]!
userEvents(after: String, before: String, first: Int, last: Int, users: [ID!], start: DateTimeUtc!, end: DateTimeUtc!): UserEventConnection!
diskUsageStats: DiskUsageStats!
repositoryList: [Repository!]!
}

input NetworkSettingInput {
Expand Down Expand Up @@ -336,6 +343,12 @@ type RepositoryConnection {
pageInfo: PageInfo!
}

enum RepositoryKind {
GIT
GITHUB
GITLAB
}

input EmailSettingInput {
smtpUsername: String!
fromAddress: String!
Expand Down
3 changes: 1 addition & 2 deletions ee/tabby-webserver/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,7 @@
)
.nest(
"/repositories",
// FIXME(boxbeam): repositories routes should support both git / github repositories, but currently only git repositories are supported.
repositories::routes(ctx.repository().git(), ctx.auth()),
repositories::routes(ctx.repository(), ctx.auth()),

Check warning on line 121 in ee/tabby-webserver/src/handler.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/handler.rs#L121

Added line #L121 was not covered by tests
)
.route(
"/avatar/:id",
Expand Down
24 changes: 9 additions & 15 deletions ee/tabby-webserver/src/repositories/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,18 @@
use crate::{
handler::require_login_middleware,
repositories::resolve::ResolveParams,
schema::{auth::AuthenticationService, git_repository::GitRepositoryService},
schema::{auth::AuthenticationService, repository::RepositoryService},
};

pub fn routes(
repository: Arc<dyn GitRepositoryService>,
repository: Arc<dyn RepositoryService>,

Check warning on line 23 in ee/tabby-webserver/src/repositories/mod.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/repositories/mod.rs#L23

Added line #L23 was not covered by tests
auth: Arc<dyn AuthenticationService>,
) -> Router {
Router::new()
.route("/resolve", routing::get(resolve))
.route("/resolve/", routing::get(resolve))
.route("/:name/resolve/.git/", routing::get(not_found))
.route("/:name/resolve/.git/*path", routing::get(not_found))
.route("/:name/resolve/", routing::get(resolve_path))
.route("/:name/resolve/*path", routing::get(resolve_path))
.route("/:kind/:id/resolve/.git/", routing::get(not_found))
.route("/:kind/:id/resolve/.git/*path", routing::get(not_found))
.route("/:kind/:id/resolve/", routing::get(resolve_path))
.route("/:kind/:id/resolve/*path", routing::get(resolve_path))

Check warning on line 30 in ee/tabby-webserver/src/repositories/mod.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/repositories/mod.rs#L27-L30

Added lines #L27 - L30 were not covered by tests
.with_state(Arc::new(ResolveState::new(repository)))
.fallback(not_found)
.layer(from_fn_with_state(auth, require_login_middleware))
Expand All @@ -44,11 +42,11 @@
State(rs): State<Arc<ResolveState>>,
Path(repo): Path<ResolveParams>,
) -> Result<Response, StatusCode> {
let Some(conf) = rs.find_repository(repo.name_str()).await else {
let relpath = repo.os_path();
let Some(root) = rs.find_repository(&repo).await else {
return Err(StatusCode::NOT_FOUND);
};
let root = conf.dir();
let full_path = root.join(repo.os_path());
let full_path = root.join(relpath);
let is_dir = tokio::fs::metadata(full_path.clone())
.await
.map(|m| m.is_dir())
Expand All @@ -72,7 +70,3 @@
}
}
}

async fn resolve(State(rs): State<Arc<ResolveState>>) -> Result<Response, StatusCode> {
rs.resolve_all().await.map_err(|_| StatusCode::NOT_FOUND)
}
44 changes: 13 additions & 31 deletions ee/tabby-webserver/src/repositories/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,23 @@
Json,
};
use hyper::Body;
use juniper::ID;
use serde::{Deserialize, Serialize};
use tabby_common::config::RepositoryConfig;
use tower::ServiceExt;
use tower_http::services::ServeDir;

use crate::schema::git_repository::GitRepositoryService;
use crate::schema::repository::{RepositoryKind, RepositoryService};

const DIRECTORY_MIME_TYPE: &str = "application/vnd.directory+json";

#[derive(Deserialize, Debug)]
pub struct ResolveParams {
name: String,
pub kind: RepositoryKind,
pub id: ID,
path: Option<String>,
}

impl ResolveParams {
pub fn name_str(&self) -> &str {
self.name.as_str()
}

pub fn path_str(&self) -> &str {
self.path.as_deref().unwrap_or("")
}
Expand Down Expand Up @@ -60,11 +57,11 @@
}

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

impl ResolveState {
pub fn new(service: Arc<dyn GitRepositoryService>) -> Self {
pub fn new(service: Arc<dyn RepositoryService>) -> Self {

Check warning on line 64 in ee/tabby-webserver/src/repositories/resolve.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/repositories/resolve.rs#L64

Added line #L64 was not covered by tests
Self { service }
}

Expand Down Expand Up @@ -128,27 +125,12 @@
Ok(resp.map(boxed))
}

pub async fn resolve_all(&self) -> Result<Response> {
let repositories = self.service.list(None, None, None, None).await?;

let entries = repositories
.into_iter()
.map(|repo| DirEntry {
kind: DirEntryKind::Dir,
basename: repo.name.clone(),
})
.collect();

let body = Json(ListDir { entries }).into_response();
let resp = Response::builder()
.header(header::CONTENT_TYPE, DIRECTORY_MIME_TYPE)
.body(body.into_body())?;

Ok(resp)
}

pub async fn find_repository(&self, name: &str) -> Option<RepositoryConfig> {
let repository = self.service.get_by_name(name).await.ok()?;
Some(RepositoryConfig::new(repository.git_url.clone()))
pub async fn find_repository(&self, params: &ResolveParams) -> Option<PathBuf> {
let repository = self
.service
.resolve_repository(&params.kind, &params.id)
.await
.ok()?;
Some(repository.dir)

Check warning on line 134 in ee/tabby-webserver/src/repositories/resolve.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/repositories/resolve.rs#L128-L134

Added lines #L128 - L134 were not covered by tests
}
}
12 changes: 2 additions & 10 deletions ee/tabby-webserver/src/schema/git_repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use async_trait::async_trait;
use juniper::{GraphQLObject, ID};
use validator::Validate;

use super::{repository::FileEntrySearchResult, Context, Result};
use super::{repository::RepositoryProvider, Context, Result};
use crate::juniper::relay::NodeType;

#[derive(Validate)]
Expand Down Expand Up @@ -42,7 +42,7 @@ impl NodeType for GitRepository {
}

#[async_trait]
pub trait GitRepositoryService: Send + Sync {
pub trait GitRepositoryService: Send + Sync + RepositoryProvider {
async fn list(
&self,
after: Option<String>,
Expand All @@ -52,14 +52,6 @@ pub trait GitRepositoryService: Send + Sync {
) -> Result<Vec<GitRepository>>;

async fn create(&self, name: String, git_url: String) -> Result<ID>;
async fn get_by_name(&self, name: &str) -> Result<GitRepository>;
async fn delete(&self, id: &ID) -> Result<bool>;
async fn update(&self, id: &ID, name: String, git_url: String) -> Result<bool>;

async fn search_files(
&self,
name: &str,
pattern: &str,
top_n: usize,
) -> Result<Vec<FileEntrySearchResult>>;
}
4 changes: 2 additions & 2 deletions ee/tabby-webserver/src/schema/github_repository_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use async_trait::async_trait;
use chrono::{DateTime, Utc};
use juniper::{GraphQLObject, ID};

use super::Context;
use super::{repository::RepositoryProvider, Context};
use crate::{juniper::relay::NodeType, schema::Result};

#[derive(GraphQLObject, Debug, PartialEq)]
Expand Down Expand Up @@ -61,7 +61,7 @@ impl NodeType for GithubProvidedRepository {
}

#[async_trait]
pub trait GithubRepositoryProviderService: Send + Sync {
pub trait GithubRepositoryProviderService: Send + Sync + RepositoryProvider {
async fn create_github_repository_provider(
&self,
display_name: String,
Expand Down
4 changes: 2 additions & 2 deletions ee/tabby-webserver/src/schema/gitlab_repository_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use async_trait::async_trait;
use chrono::{DateTime, Utc};
use juniper::{GraphQLObject, ID};

use super::Context;
use super::{repository::RepositoryProvider, Context};
use crate::{juniper::relay::NodeType, schema::Result};

#[derive(GraphQLObject, Debug, PartialEq)]
Expand Down Expand Up @@ -61,7 +61,7 @@ impl NodeType for GitlabProvidedRepository {
}

#[async_trait]
pub trait GitlabRepositoryProviderService: Send + Sync {
pub trait GitlabRepositoryProviderService: Send + Sync + RepositoryProvider {
async fn create_gitlab_repository_provider(
&self,
display_name: String,
Expand Down
23 changes: 12 additions & 11 deletions ee/tabby-webserver/src/schema/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,22 +40,19 @@ use self::{
email::{EmailService, EmailSetting, EmailSettingInput},
git_repository::GitRepository,
github_repository_provider::{GithubProvidedRepository, GithubRepositoryProvider},
gitlab_repository_provider::{GitlabProvidedRepository, GitlabRepositoryProvider},
job::JobStats,
license::{IsLicenseValid, LicenseInfo, LicenseService, LicenseType},
repository::RepositoryService,
repository::{FileEntrySearchResult, Repository, RepositoryKind, RepositoryService},
setting::{
NetworkSetting, NetworkSettingInput, SecuritySetting, SecuritySettingInput, SettingService,
},
types::{CreateRepositoryProviderInput, UpdateRepositoryProviderInput},
user_event::{UserEvent, UserEventService},
};
use crate::{
axum::FromAuth,
juniper::relay::{self, Connection},
schema::{
gitlab_repository_provider::{GitlabProvidedRepository, GitlabRepositoryProvider},
repository::FileEntrySearchResult,
types::{CreateRepositoryProviderInput, UpdateRepositoryProviderInput},
},
};

pub trait ServiceLocator: Send + Sync {
Expand Down Expand Up @@ -421,14 +418,14 @@ impl Query {

async fn repository_search(
ctx: &Context,
repository_name: String,
kind: RepositoryKind,
id: ID,
pattern: String,
) -> Result<Vec<FileEntrySearchResult>> {
check_claims(ctx)?;
ctx.locator
.repository()
.git()
.search_files(&repository_name, &pattern, 40)
.search_files(&kind, &id, &pattern, 40)
.await
}

Expand Down Expand Up @@ -526,8 +523,12 @@ impl Query {

async fn disk_usage_stats(ctx: &Context) -> Result<DiskUsageStats> {
check_admin(ctx).await?;
let storage_stats = ctx.locator.analytic().disk_usage_stats().await?;
Ok(storage_stats)
ctx.locator.analytic().disk_usage_stats().await
}

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

Expand Down
Loading
Loading