Skip to content
Draft
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
48 changes: 42 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ permissions:

jobs:
lint:
runs-on: ubuntu-latest
runs-on: [self-hosted, node-b, linux, x64]
steps:
- uses: actions/checkout@v7
- uses: Swatinem/rust-cache@v2
Expand All @@ -36,7 +36,24 @@ jobs:
- run: cargo clippy --workspace --all-features --locked -- -D warnings

test:
runs-on: ubuntu-latest
runs-on: [self-hosted, node-b, linux, x64]
services:
mariadb:
image: mariadb:11.4
env:
MARIADB_ROOT_PASSWORD: stackarr
ports:
- 3306:3306
options: >-
--health-cmd="healthcheck.sh --connect --innodb_initialized"
--health-interval=5s
--health-timeout=5s
--health-retries=20
env:
# The TestDb harness creates and drops a database per test, so this
# account needs server-wide CREATE/DROP. root is scoped to the throwaway
# service container and never leaves the job.
TEST_DATABASE_URL: mysql://root:stackarr@127.0.0.1:3306/mysql
steps:
- uses: actions/checkout@v7
- uses: Swatinem/rust-cache@v2
Expand All @@ -50,9 +67,15 @@ jobs:
npm --prefix client ci --no-audit --no-fund
npm --prefix client run build
- run: cargo test --workspace --all-features --locked
# The database-backed tests are #[ignore]d so they can be skipped on a
# machine with no server. They are the only thing that proves the
# MariaDB swap against a real server, so CI must opt into them
# explicitly now that the service container above exists.
- name: Database-backed tests
run: cargo test --workspace --all-features --locked -- --ignored

build:
runs-on: ubuntu-latest
runs-on: [self-hosted, node-b, linux, x64]
steps:
- uses: actions/checkout@v7
- uses: Swatinem/rust-cache@v2
Expand All @@ -68,7 +91,7 @@ jobs:
- run: cargo build --workspace --all-features --locked

ui:
runs-on: ubuntu-latest
runs-on: [self-hosted, node-b, linux, x64]
strategy:
matrix:
project: [ui, client]
Expand All @@ -85,7 +108,7 @@ jobs:
run: npm run build

ui-e2e:
runs-on: ubuntu-latest
runs-on: [self-hosted, node-b, linux, x64]
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
Expand All @@ -100,16 +123,28 @@ jobs:
- working-directory: ui
run: npm run test:e2e

conformance:
runs-on: [self-hosted, node-b, linux, x64]
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@master
with:
toolchain: "1.95.0"
- uses: Swatinem/rust-cache@v2
- name: Run compatibility/conformance gate
run: just conformance

container:
if: github.event_name == 'push'
needs: [lint, test, build, ui, ui-e2e]
needs: [lint, test, build, ui, ui-e2e, conformance]
runs-on: [self-hosted, node-b, linux, x64, publish, docker]
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v7
- uses: docker/setup-buildx-action@v4
- uses: docker/setup-qemu-action@v4
- uses: docker/login-action@v4
if: github.event_name == 'push'
with:
Expand All @@ -121,6 +156,7 @@ jobs:
context: .
file: docker/Dockerfile
push: ${{ github.event_name == 'push' }}
platforms: linux/amd64,linux/arm64
tags: |
ghcr.io/thedancingdeveloper-org/ngms:latest
ghcr.io/thedancingdeveloper-org/ngms:sha-${{ github.sha }}
Expand Down
5 changes: 2 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,10 @@ The following list is checked against `Cargo.toml` in CI.
- `crates/stackarr-cardigann`
- `crates/stackarr-cardigann-parity`
- `crates/stackarr-stream`
- `crates/stackarr-postgres`
- `crates/stackarr-mariadb`
<!-- workspace-members:end -->

The final entry is renamed to `stackarr-mariadb` during P1. Update this list in
the same commit as any workspace-member change.
Update this list in the same commit as any workspace-member change.

The torrent engine is consumed from crates.io through the `swarmforge` package
family and historical `librtbit` dependency aliases. The Usenet engine is the
Expand Down
29 changes: 10 additions & 19 deletions Cargo.lock

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

9 changes: 3 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ members = [
"crates/stackarr-cardigann",
"crates/stackarr-cardigann-parity",
"crates/stackarr-stream",
"crates/stackarr-postgres",
"crates/stackarr-mariadb",
]

[workspace.package]
Expand Down Expand Up @@ -50,7 +50,7 @@ tower-http = { version = "0.6", features = ["cors", "trace", "fs", "set-header",
http = "1"

# Database
sqlx = { version = "0.8.6", default-features = false, features = ["runtime-tokio", "postgres", "chrono", "json", "uuid", "derive", "macros", "migrate"] }
sqlx = { version = "0.8.6", default-features = false, features = ["runtime-tokio", "mysql", "chrono", "json", "uuid", "derive", "macros", "migrate"] }
rusqlite = { version = "0.32", features = ["bundled"] }

# HTTP client
Expand Down Expand Up @@ -193,7 +193,7 @@ stackarr-migrate = { path = "crates/stackarr-migrate" }
stackarr-plex = { path = "crates/stackarr-plex" }
stackarr-cardigann = { path = "crates/stackarr-cardigann" }
stackarr-stream = { path = "crates/stackarr-stream" }
stackarr-postgres = { path = "crates/stackarr-postgres" }
stackarr-mariadb = { path = "crates/stackarr-mariadb" }

# SwarmForge 0.1.0, published by rustTorrent. Cargo aliases preserve the
# existing librtbit API names while the canonical crates.io package names make
Expand Down Expand Up @@ -236,8 +236,6 @@ license.workspace = true
[features]
default = ["ui"]
ui = []
managed-postgres = ["dep:stackarr-postgres"]
embed-postgres = ["stackarr-postgres/embed", "managed-postgres"]
embed-ui = ["stackarr-web/embed-ui"]

[dependencies]
Expand Down Expand Up @@ -269,7 +267,6 @@ network-interface = { workspace = true }
librtbit-upnp = { workspace = true }
serde = { workspace = true }
rustls = { workspace = true }
stackarr-postgres = { workspace = true, optional = true }

[dev-dependencies]
# Select the otherwise optional twelfth SwarmForge crate so the lockfile and
Expand Down
4 changes: 2 additions & 2 deletions config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ data_dir = "/config"
log_level = "info"

[database]
# PostgreSQL connection string
url = "postgresql://stackarr:stackarr@localhost:5432/stackarr"
# MariaDB connection string
url = "mysql://stackarr:stackarr@localhost:3306/stackarr"
# Maximum number of connections in the pool
max_connections = 20

Expand Down
1 change: 1 addition & 0 deletions crates/stackarr-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ default = []
testing = []

[dependencies]
stackarr-mariadb = { workspace = true }
sqlx = { workspace = true }
nzbdav-core = { workspace = true }
async-trait = { workspace = true }
Expand Down
28 changes: 4 additions & 24 deletions crates/stackarr-core/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,9 @@ pub struct GeneralConfig {

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DatabaseConfig {
/// Database mode: "external" (default), "managed", or "embedded".
#[serde(default = "default_db_mode")]
pub mode: String,
pub url: String,
#[serde(default = "default_max_connections")]
pub max_connections: u32,
/// Where managed PostgreSQL stores its data. Defaults to `{data_dir}/postgres`.
#[serde(default)]
pub data_dir: Option<std::path::PathBuf>,
/// Port for managed PostgreSQL (default 5433, avoids conflict with system PG).
#[serde(default = "default_pg_port")]
pub port: u16,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
Expand Down Expand Up @@ -417,12 +408,6 @@ fn default_log_level() -> String {
fn default_max_connections() -> u32 {
20
}
fn default_db_mode() -> String {
"external".to_string()
}
fn default_pg_port() -> u16 {
5433
}
fn default_auth_method() -> String {
"forms".to_string()
}
Expand Down Expand Up @@ -570,11 +555,8 @@ impl Default for GeneralConfig {
impl Default for DatabaseConfig {
fn default() -> Self {
Self {
mode: default_db_mode(),
url: "postgresql://stackarr:stackarr@localhost:5432/stackarr".to_string(),
url: "mysql://stackarr:stackarr@localhost:3306/stackarr".to_string(),
max_connections: default_max_connections(),
data_dir: None,
port: default_pg_port(),
}
}
}
Expand Down Expand Up @@ -609,11 +591,9 @@ impl AppConfig {
/// Validate config values and emit warnings for common misconfigurations.
/// Returns an error only for values that will definitely break at runtime.
pub fn validate(&self) -> crate::Result<()> {
// Database URL is required for external mode
if self.database.mode == "external" && self.database.url.is_empty() {
if self.database.url.is_empty() {
return Err(crate::Error::Config(
"database.url is required when database.mode = \"external\". \
Set it in your config file or pass --database-url."
"database.url is required. Set it in your config file or pass --database-url."
.to_string(),
));
}
Expand Down Expand Up @@ -722,7 +702,7 @@ mod tests {
port = 9090

[database]
url = "postgresql://test:test@localhost:5432/test"
url = "mysql://test:test@localhost:3306/test"

[auth]
method = "none"
Expand Down
Loading