Skip to content

Commit

Permalink
Progress on refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
boxbeam committed May 13, 2024
1 parent 490690b commit 8ab2396
Show file tree
Hide file tree
Showing 4 changed files with 274 additions and 6 deletions.
4 changes: 2 additions & 2 deletions ee/tabby-schema/src/schema/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,6 @@ pub trait IntegrationService: Send + Sync {
first: Option<usize>,
last: Option<usize>,
) -> Result<Vec<IntegrationAccessToken>>;

async fn sync_resources(&self, id: ID) -> Result<()>;
async fn get_integration(&self, id: ID) -> Result<IntegrationAccessToken>;
async fn update_integration_error(&self, id: ID, error: Option<String>) -> Result<()>;
}
13 changes: 13 additions & 0 deletions ee/tabby-schema/src/schema/repository/third_party.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,18 @@ pub trait ThirdPartyRepositoryService: Send + Sync {
) -> Result<Vec<ProvidedRepository>>;

async fn update_repository_active(&self, id: ID, active: bool) -> Result<()>;
async fn upsert_repository(
&self,
integration_id: ID,
vendor_id: String,
display_name: String,
git_url: String,
) -> Result<()>;
async fn list_active_git_urls(&self) -> Result<Vec<String>>;
async fn sync_repositories(&self, kind: IntegrationKind) -> Result<()>;
async fn delete_outdated_repositories(
&self,
integration_id: ID,
before: DateTime<Utc>,
) -> Result<usize>;
}
128 changes: 124 additions & 4 deletions ee/tabby-webserver/src/service/repository/third_party.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
use chrono::{DateTime, Utc};
use juniper::ID;
use std::marker::PhantomData;
use strum::IntoEnumIterator;
use std::sync::Arc;
use tabby_schema::{
integration::IntegrationKind, repository::ProvidedRepository, AsRowid, DbEnum, Result,
integration::{IntegrationKind, IntegrationService},
repository::ProvidedRepository,
AsRowid, DbEnum, Result,
};
use tracing::{debug, error};
use url::Url;

use async_trait::async_trait;
use tabby_db::DbConn;
use tabby_schema::repository::{RepositoryProvider, ThirdPartyRepositoryService};
use tabby_schema::repository::ThirdPartyRepositoryService;

use crate::service::graphql_pagination_to_filter;
use fetch::fetch_all_repos;

mod fetch;

struct ThirdPartyRepositoryServiceImpl {
db: DbConn,
integration: Arc<dyn IntegrationService>,
}

#[async_trait]
Expand Down Expand Up @@ -56,7 +63,120 @@ impl ThirdPartyRepositoryService for ThirdPartyRepositoryServiceImpl {

async fn list_active_git_urls(&self) -> Result<Vec<String>> {
let mut urls = vec![];

Check warning on line 65 in ee/tabby-webserver/src/service/repository/third_party.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party.rs#L64-L65

Added lines #L64 - L65 were not covered by tests

let integrations = self
.integration
.list_integrations(None, None, None, None, None, None)
.await?;

Check warning on line 70 in ee/tabby-webserver/src/service/repository/third_party.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party.rs#L67-L70

Added lines #L67 - L70 were not covered by tests

for integration in integrations {
let repositories = self
.list_repositories(
Some(vec![integration.id.clone()]),
None,
Some(true),
None,
None,
None,
None,
)
.await?;

Check warning on line 83 in ee/tabby-webserver/src/service/repository/third_party.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party.rs#L72-L83

Added lines #L72 - L83 were not covered by tests

for repository in repositories {
let url = format_authenticated_url(
&repository.kind,
&repository.git_url,
&integration.access_token,
)?;
urls.push(url);

Check warning on line 91 in ee/tabby-webserver/src/service/repository/third_party.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party.rs#L85-L91

Added lines #L85 - L91 were not covered by tests
}
}

Ok(urls)
}

Check warning on line 96 in ee/tabby-webserver/src/service/repository/third_party.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party.rs#L95-L96

Added lines #L95 - L96 were not covered by tests

async fn sync_repositories(&self, kind: IntegrationKind) -> Result<()> {
todo!("Loop over integrations and call refresh_repositories_for_provider");

Check warning on line 99 in ee/tabby-webserver/src/service/repository/third_party.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party.rs#L98-L99

Added lines #L98 - L99 were not covered by tests
Ok(())
}

Check warning on line 101 in ee/tabby-webserver/src/service/repository/third_party.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party.rs#L101

Added line #L101 was not covered by tests

async fn upsert_repository(
&self,
integration_id: ID,
vendor_id: String,
display_name: String,
git_url: String,
) -> Result<()> {
self.db
.upsert_provided_repository(
integration_id.as_rowid()?,
vendor_id,
display_name,
git_url,

Check warning on line 115 in ee/tabby-webserver/src/service/repository/third_party.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party.rs#L109-L115

Added lines #L109 - L115 were not covered by tests
)
.await?;
Ok(())
}

Check warning on line 119 in ee/tabby-webserver/src/service/repository/third_party.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party.rs#L117-L119

Added lines #L117 - L119 were not covered by tests

async fn delete_outdated_repositories(
&self,
integration_id: ID,
before: DateTime<Utc>,
) -> Result<usize> {
Ok(self
.db
.delete_outdated_provided_repositories(integration_id.as_rowid()?, before.into())
.await?)
}

Check warning on line 130 in ee/tabby-webserver/src/service/repository/third_party.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party.rs#L125-L130

Added lines #L125 - L130 were not covered by tests
}

async fn refresh_repositories_for_provider(
repository: Arc<dyn ThirdPartyRepositoryService>,
integration: Arc<dyn IntegrationService>,
provider_id: ID,
) -> Result<()> {
let provider = integration.get_integration(provider_id.clone()).await?;
debug!(
"Refreshing repositories for provider: {}",
provider.display_name
);

Check warning on line 142 in ee/tabby-webserver/src/service/repository/third_party.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party.rs#L133-L142

Added lines #L133 - L142 were not covered by tests

let start = Utc::now();
let repos = match fetch_all_repos(provider.kind.clone(), &provider.access_token).await {
Ok(repos) => repos,
Err((e, true)) => {
integration
.update_integration_error(provider.id.clone(), Some("".into()))
.await?;
error!(
"Credentials for integration {} are expired or invalid",
provider.display_name
);
return Err(e.into());

Check warning on line 155 in ee/tabby-webserver/src/service/repository/third_party.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party.rs#L144-L155

Added lines #L144 - L155 were not covered by tests
}
Err((e, false)) => {
error!("Failed to fetch repositories from github: {e}");
return Err(e.into());

Check warning on line 159 in ee/tabby-webserver/src/service/repository/third_party.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party.rs#L157-L159

Added lines #L157 - L159 were not covered by tests
}
};
for repo in repos {
debug!("importing: {}", repo.name);

Check warning on line 163 in ee/tabby-webserver/src/service/repository/third_party.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party.rs#L162-L163

Added lines #L162 - L163 were not covered by tests

let id = repo.vendor_id;

repository
.upsert_repository(provider_id.clone(), id, repo.name, repo.git_url)
.await?;

Check warning on line 169 in ee/tabby-webserver/src/service/repository/third_party.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party.rs#L165-L169

Added lines #L165 - L169 were not covered by tests
}

integration
.update_integration_error(provider_id.clone(), None)
.await?;
let num_removed = repository
.delete_outdated_repositories(provider_id, start.into())
.await?;
debug!("Removed {} outdated repositories", num_removed);
Ok(())
}

Check warning on line 180 in ee/tabby-webserver/src/service/repository/third_party.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party.rs#L172-L180

Added lines #L172 - L180 were not covered by tests

fn format_authenticated_url(
Expand Down
135 changes: 135 additions & 0 deletions ee/tabby-webserver/src/service/repository/third_party/fetch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
use gitlab::{
api::{projects::Projects, AsyncQuery, Pagination},
GitlabBuilder,
};
use octocrab::{GitHubError, Octocrab};
use tabby_schema::integration::IntegrationKind;

pub struct RepositoryInfo {
pub name: String,
pub git_url: String,
pub vendor_id: String,
}

mod gitlab_types {
use gitlab::api::ApiError;
use serde::Deserialize;

#[derive(Deserialize)]

Check warning on line 18 in ee/tabby-webserver/src/service/repository/third_party/fetch.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party/fetch.rs#L18

Added line #L18 was not covered by tests
pub struct GitlabRepository {
pub id: u128,
pub path_with_namespace: String,
pub http_url_to_repo: String,
}

#[derive(thiserror::Error, Debug)]

Check warning on line 25 in ee/tabby-webserver/src/service/repository/third_party/fetch.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party/fetch.rs#L25

Added line #L25 was not covered by tests
pub enum GitlabError {
#[error(transparent)]
Rest(#[from] gitlab::api::ApiError<gitlab::RestError>),
#[error(transparent)]
Gitlab(#[from] gitlab::GitlabError),
#[error(transparent)]
Projects(#[from] gitlab::api::projects::ProjectsBuilderError),
}

impl GitlabError {
pub fn is_client_error(&self) -> bool {
match self {
GitlabError::Rest(source)
| GitlabError::Gitlab(gitlab::GitlabError::Api { source }) => {
matches!(
source,

Check warning on line 41 in ee/tabby-webserver/src/service/repository/third_party/fetch.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party/fetch.rs#L36-L41

Added lines #L36 - L41 were not covered by tests
ApiError::Auth { .. }
| ApiError::Client {
source: gitlab::RestError::AuthError { .. }
}
| ApiError::Gitlab { .. }
)
}
_ => false,

Check warning on line 49 in ee/tabby-webserver/src/service/repository/third_party/fetch.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party/fetch.rs#L49

Added line #L49 was not covered by tests
}
}

Check warning on line 51 in ee/tabby-webserver/src/service/repository/third_party/fetch.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party/fetch.rs#L51

Added line #L51 was not covered by tests
}
}

pub async fn fetch_all_repos(
kind: IntegrationKind,
access_token: &str,
) -> Result<Vec<RepositoryInfo>, (anyhow::Error, bool)> {
match kind {
IntegrationKind::Github => match fetch_all_github_repos(access_token).await {
Ok(repos) => Ok(repos),

Check warning on line 61 in ee/tabby-webserver/src/service/repository/third_party/fetch.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party/fetch.rs#L55-L61

Added lines #L55 - L61 were not covered by tests
Err(octocrab::Error::GitHub {
source: source @ GitHubError { .. },

Check warning on line 63 in ee/tabby-webserver/src/service/repository/third_party/fetch.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party/fetch.rs#L63

Added line #L63 was not covered by tests
..
}) if source.status_code.is_client_error() => Err((source.into(), true)),
Err(e) => Err((e.into(), false)),

Check warning on line 66 in ee/tabby-webserver/src/service/repository/third_party/fetch.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party/fetch.rs#L65-L66

Added lines #L65 - L66 were not covered by tests
},
IntegrationKind::Gitlab => match fetch_all_gitlab_repos(access_token).await {
Ok(repos) => Ok(repos),
Err(e) => {
let client_error = e.is_client_error();
Err((e.into(), client_error))

Check warning on line 72 in ee/tabby-webserver/src/service/repository/third_party/fetch.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party/fetch.rs#L68-L72

Added lines #L68 - L72 were not covered by tests
}
},
}
}

Check warning on line 76 in ee/tabby-webserver/src/service/repository/third_party/fetch.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party/fetch.rs#L76

Added line #L76 was not covered by tests

async fn fetch_all_gitlab_repos(
access_token: &str,
) -> Result<Vec<RepositoryInfo>, gitlab_types::GitlabError> {
let gitlab = GitlabBuilder::new("gitlab.com", access_token)
.build_async()
.await?;
let repos: Vec<gitlab_types::GitlabRepository> = gitlab::api::paged(
Projects::builder().membership(true).build()?,
Pagination::All,
)
.query_async(&gitlab)
.await?;

Check warning on line 89 in ee/tabby-webserver/src/service/repository/third_party/fetch.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party/fetch.rs#L78-L89

Added lines #L78 - L89 were not covered by tests

Ok(repos
.into_iter()
.map(|repo| RepositoryInfo {
name: repo.path_with_namespace,
git_url: repo.http_url_to_repo,
vendor_id: repo.id.to_string(),
})
.collect())
}

Check warning on line 99 in ee/tabby-webserver/src/service/repository/third_party/fetch.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party/fetch.rs#L91-L99

Added lines #L91 - L99 were not covered by tests

async fn fetch_all_github_repos(
access_token: &str,
) -> Result<Vec<RepositoryInfo>, octocrab::Error> {
let octocrab = Octocrab::builder()
.user_access_token(access_token.to_string())
.build()?;

Check warning on line 106 in ee/tabby-webserver/src/service/repository/third_party/fetch.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party/fetch.rs#L101-L106

Added lines #L101 - L106 were not covered by tests

let mut page = 1;
let mut repos = vec![];

Check warning on line 109 in ee/tabby-webserver/src/service/repository/third_party/fetch.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party/fetch.rs#L108-L109

Added lines #L108 - L109 were not covered by tests

loop {
let response = octocrab
.current()
.list_repos_for_authenticated_user()
.visibility("all")
.page(page)
.send()
.await?;

Check warning on line 118 in ee/tabby-webserver/src/service/repository/third_party/fetch.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party/fetch.rs#L112-L118

Added lines #L112 - L118 were not covered by tests

let pages = response.number_of_pages().unwrap_or_default() as u8;
repos.extend(response.items.into_iter().filter_map(|repo| {
Some(RepositoryInfo {
name: repo.full_name.unwrap_or(repo.name),
git_url: repo.html_url?.to_string(),
vendor_id: repo.id.to_string(),

Check warning on line 125 in ee/tabby-webserver/src/service/repository/third_party/fetch.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party/fetch.rs#L120-L125

Added lines #L120 - L125 were not covered by tests
})
}));

page += 1;
if page > pages {
break;
}

Check warning on line 132 in ee/tabby-webserver/src/service/repository/third_party/fetch.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party/fetch.rs#L127-L132

Added lines #L127 - L132 were not covered by tests
}
Ok(repos)
}

Check warning on line 135 in ee/tabby-webserver/src/service/repository/third_party/fetch.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/repository/third_party/fetch.rs#L134-L135

Added lines #L134 - L135 were not covered by tests

0 comments on commit 8ab2396

Please sign in to comment.