Skip to content
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
4 changes: 0 additions & 4 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
use crate::config::Config;
use crate::polling::git::GitFetcher;
use crate::repository::SqliteRepository;
use sqlx::SqlitePool;
use std::sync::Arc;
use tokio_util::sync::CancellationToken;

Expand All @@ -16,9 +15,6 @@ pub struct SharedContext {
/// Repository for data access.
pub repository: Arc<SqliteRepository>,

/// SQLx connection pool.
pub db_pool: SqlitePool,

/// Token to signal task cancellation.
pub token: CancellationToken,

Expand Down
4 changes: 0 additions & 4 deletions src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ mod tests {
let state = AppState {
config: std::sync::Arc::new(config),
repository: std::sync::Arc::new(crate::repository::SqliteRepository::new(pool.clone())),
db_pool: pool.clone(),
};
let payload = CreateSubscription {
source_repo_url: RepoUrl::new("https://github.com/org/repo".to_string()).unwrap(),
Expand Down Expand Up @@ -147,7 +146,6 @@ mod tests {
let state = AppState {
config: std::sync::Arc::new(config),
repository: std::sync::Arc::new(crate::repository::SqliteRepository::new(pool.clone())),
db_pool: pool.clone(),
};

// Try getting a non-existent subscription
Expand Down Expand Up @@ -176,7 +174,6 @@ mod tests {
let state = AppState {
config: std::sync::Arc::new(config),
repository: std::sync::Arc::new(crate::repository::SqliteRepository::new(pool.clone())),
db_pool: pool.clone(),
};

// Create 3 subscriptions
Expand Down Expand Up @@ -234,7 +231,6 @@ mod tests {
let state = AppState {
config: std::sync::Arc::new(config),
repository: std::sync::Arc::new(crate::repository::SqliteRepository::new(pool.clone())),
db_pool: pool.clone(),
};
let payload = CreateSubscription {
source_repo_url: RepoUrl::new("https://github.com/org/repo".to_string()).unwrap(),
Expand Down
36 changes: 4 additions & 32 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
)]

use std::fs;
use std::str::FromStr;
use std::time::Duration;

use axum::{
Expand All @@ -26,7 +25,6 @@ use reqwest::Client;
use rovo::Router as RovoRouter;
use rovo::aide::openapi::OpenApi;
use rovo::rovo;
use sqlx::sqlite::SqliteConnectOptions;
use subtle::ConstantTimeEq;
use tokio::signal;
use tokio_util::sync::CancellationToken;
Expand Down Expand Up @@ -74,16 +72,11 @@ type EngineTask = (Box<dyn AsyncEngine>, &'static str);
/// Runs the server, delegating errors to the caller.
pub async fn run_app(tracker: &TaskTracker, token: &CancellationToken) -> Result<(), FatalError> {
let config = Config::load()?;
let pool = init_database(&config).await?;
let repository = std::sync::Arc::new(crate::repository::SqliteRepository::new(pool.clone()));
let repository =
std::sync::Arc::new(crate::repository::SqliteRepository::connect(&config.database).await?);
let http_client = build_http_client(&config)?;

let ctx = init_context(
repository.clone(),
pool.clone(),
config.clone(),
token.clone(),
)?;
let ctx = init_context(repository.clone(), config.clone(), token.clone())?;

crate::trigger::recover_stuck_tasks(&repository, &config)
.await
Expand All @@ -94,7 +87,7 @@ pub async fn run_app(tracker: &TaskTracker, token: &CancellationToken) -> Result
crate::engine::start_engine(engine, message, tracker);
}

let app = build_router(repository, pool, &config);
let app = build_router(repository, &config);

run_server(app, &ctx.config, token.clone()).await?;

Expand All @@ -120,27 +113,9 @@ pub fn log_dotenv_status(loaded: bool) {
);
}

/// Initializes the database pool.
async fn init_database(config: &Config) -> Result<sqlx::SqlitePool, FatalError> {
let options = SqliteConnectOptions::from_str(config.database.url.as_str())?
.foreign_keys(true)
.journal_mode(sqlx::sqlite::SqliteJournalMode::Wal);

let pool = sqlx::sqlite::SqlitePoolOptions::new()
.acquire_timeout(config.database.timeout)
.connect_with(options)
.await?;

// Ensures database schema is up to date in all environments.
sqlx::migrate!().run(&pool).await?;

Ok(pool)
}

/// Initializes the shared application context.
fn init_context(
repository: std::sync::Arc<crate::repository::SqliteRepository>,
pool: sqlx::SqlitePool,
config: Config,
token: CancellationToken,
) -> Result<SharedContext, FatalError> {
Expand All @@ -156,7 +131,6 @@ fn init_context(
Ok(SharedContext {
config,
repository,
db_pool: pool,
token,
git_fetcher: std::sync::Arc::new(git_fetcher),
})
Expand Down Expand Up @@ -333,13 +307,11 @@ impl<B> OnResponse<B> for HttpRequestOnResponse {
/// Builds the application router.
pub fn build_router(
repository: std::sync::Arc<crate::repository::SqliteRepository>,
pool: sqlx::SqlitePool,
config: &Config,
) -> Router {
let state = AppState {
config: std::sync::Arc::new(config.clone()),
repository,
db_pool: pool,
};

let mut api = OpenApi::default();
Expand Down
4 changes: 0 additions & 4 deletions src/polling/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,6 @@ mod tests {
let ctx = SharedContext {
config: crate::test_utils::create_test_config(),
repository: std::sync::Arc::new(crate::repository::SqliteRepository::new(pool.clone())),
db_pool: pool.clone(),
git_fetcher: mock_fetcher,
token: CancellationToken::new(),
};
Expand Down Expand Up @@ -314,7 +313,6 @@ mod tests {
let ctx = SharedContext {
config: crate::test_utils::create_test_config(),
repository: std::sync::Arc::new(crate::repository::SqliteRepository::new(pool.clone())),
db_pool: pool.clone(),
git_fetcher: Arc::new(crate::test_utils::MockGitFetcher {
hash: CommitHash::new("b".repeat(40)).unwrap(),
}),
Expand All @@ -332,7 +330,6 @@ mod tests {
let ctx = SharedContext {
config: ctx.config,
repository: std::sync::Arc::new(crate::repository::SqliteRepository::new(pool.clone())),
db_pool: pool.clone(),
git_fetcher: mock_fetcher,
token: ctx.token,
};
Expand Down Expand Up @@ -402,7 +399,6 @@ mod tests {
let ctx = SharedContext {
config: crate::test_utils::create_test_config(),
repository: std::sync::Arc::new(crate::repository::SqliteRepository::new(pool.clone())),
db_pool: pool.clone(),
git_fetcher: std::sync::Arc::new(crate::test_utils::MockGitFetcher {
hash: CommitHash::new("c".repeat(40)).unwrap(),
}),
Expand Down
22 changes: 22 additions & 0 deletions src/repository/sqlite.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
//! SQLite implementation of the repository.

use std::str::FromStr;

use crate::config::DatabaseConfig;
use crate::domain::{BranchName, EventType, RepoUrl, TargetRepo};
use crate::error::FatalError;
use crate::model::{
Branch, CreateSubscription, Subscription, SubscriptionWithBranch, TriggerQueueItem,
UpdateSubscription,
Expand All @@ -13,6 +17,7 @@ use crate::repository::{
};
use async_trait::async_trait;
use futures::future::BoxFuture;
use sqlx::sqlite::{SqliteConnectOptions, SqliteJournalMode, SqlitePoolOptions};
use sqlx::{SqliteConnection, SqlitePool};

#[derive(Debug)]
Expand All @@ -23,6 +28,23 @@ pub struct SqliteRepository {
}

impl SqliteRepository {
/// Connects to the database described by `config`.
pub async fn connect(config: &DatabaseConfig) -> Result<Self, FatalError> {
let options = SqliteConnectOptions::from_str(config.url.as_str())?
.foreign_keys(true)
.journal_mode(SqliteJournalMode::Wal);

let pool = SqlitePoolOptions::new()
.acquire_timeout(config.timeout)
.connect_with(options)
.await?;

// Ensures database schema is up to date in all environments.
sqlx::migrate!().run(&pool).await?;

Ok(Self { pool })
}

/// Creates a new [`SqliteRepository`] from a [`SqlitePool`].
pub fn new(pool: SqlitePool) -> Self {
Self { pool }
Expand Down
3 changes: 0 additions & 3 deletions src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,4 @@ pub struct AppState {

/// Repository for data access.
pub repository: Arc<SqliteRepository>,

/// SQLx connection pool for the SQLite database.
pub db_pool: sqlx::SqlitePool,
}
2 changes: 1 addition & 1 deletion src/tests/api_routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ async fn test_subscription_api_routes() {
config.auth.allow_unauthenticated = true;
let repository = Arc::new(SqliteRepository::new(pool.clone()));

let app = build_router(repository, pool, &config);
let app = build_router(repository, &config);

// Test List Subscriptions (Empty)
let response = app
Expand Down
10 changes: 5 additions & 5 deletions src/tests/auth_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ async fn test_auth_no_key_configured_fails() {
config.auth.allow_unauthenticated = false;

let repository = Arc::new(SqliteRepository::new(pool.clone()));
let app = build_router(repository, pool, &config);
let app = build_router(repository, &config);

let response = app
.oneshot(
Expand All @@ -40,7 +40,7 @@ async fn test_auth_allowed_unauthenticated_success() {
config.auth.allow_unauthenticated = true;

let repository = Arc::new(SqliteRepository::new(pool.clone()));
let app = build_router(repository, pool, &config);
let app = build_router(repository, &config);

let response = app
.oneshot(
Expand All @@ -63,7 +63,7 @@ async fn test_auth_key_configured_success() {
config.auth.api_key = Some(NonEmptyString::new("secret".to_string()).unwrap());

let repository = Arc::new(SqliteRepository::new(pool.clone()));
let app = build_router(repository, pool, &config);
let app = build_router(repository, &config);

let response = app
.oneshot(
Expand All @@ -87,7 +87,7 @@ async fn test_auth_key_configured_mismatch() {
config.auth.api_key = Some(NonEmptyString::new("secret".to_string()).unwrap());

let repository = Arc::new(SqliteRepository::new(pool.clone()));
let app = build_router(repository, pool, &config);
let app = build_router(repository, &config);

let response = app
.oneshot(
Expand All @@ -111,7 +111,7 @@ async fn test_auth_key_configured_missing() {
config.auth.api_key = Some(NonEmptyString::new("secret".to_string()).unwrap());

let repository = Arc::new(SqliteRepository::new(pool.clone()));
let app = build_router(repository, pool, &config);
let app = build_router(repository, &config);

let response = app
.oneshot(
Expand Down
2 changes: 0 additions & 2 deletions src/trigger/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,6 @@ mod tests {
repository: std::sync::Arc::new(crate::repository::SqliteRepository::new(
pool.clone(),
)),
db_pool: pool.clone(),
token: CancellationToken::new(),
git_fetcher: Arc::new(MockGitFetcher {
hash: CommitHash::new("a".repeat(40)).unwrap(),
Expand Down Expand Up @@ -623,7 +622,6 @@ mod tests {
repository: std::sync::Arc::new(crate::repository::SqliteRepository::new(
pool.clone(),
)),
db_pool: pool.clone(),
token: CancellationToken::new(),
git_fetcher: Arc::new(MockGitFetcher {
hash: CommitHash::new("a".repeat(40)).unwrap(),
Expand Down
Loading