initial commit
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I79a875e75937ff6b3739ca36bfb0b2836a6a6964
This commit is contained in:
commit
6203ea7f52
13 changed files with 3226 additions and 0 deletions
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
target/
|
||||
|
||||
# Nix
|
||||
result*
|
||||
result-*
|
||||
|
||||
# Misc
|
||||
.direnv
|
||||
2931
Cargo.lock
generated
Normal file
2931
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
31
Cargo.toml
Normal file
31
Cargo.toml
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
[workspace]
|
||||
members = [
|
||||
"crates/server",
|
||||
"crates/evaluator",
|
||||
"crates/queue-runner",
|
||||
"crates/common",
|
||||
]
|
||||
resolver = "3"
|
||||
|
||||
[workspace.package]
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
license = "MPL-2.0"
|
||||
repository = "https://gitub.com/feel-co/fc"
|
||||
authors = ["NotAShelf <raf@notashelf.dev"]
|
||||
|
||||
[workspace.dependencies]
|
||||
tokio = { version = "1.48.0", features = ["full"] }
|
||||
axum = "0.8.6"
|
||||
sqlx = { version = "0.8.6", features = ["runtime-tokio-rustls", "postgres", "chrono", "uuid"] }
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
serde_json = "1.0.145"
|
||||
uuid = { version = "1.18.1", features = ["v4", "serde"] }
|
||||
chrono = { version = "0.4.42", features = ["serde"] }
|
||||
tracing = "0.1.41"
|
||||
tracing-subscriber = "0.3.20"
|
||||
anyhow = "1.0.100"
|
||||
thiserror = "2.0.17"
|
||||
git2 = "0.20.2"
|
||||
clap = { version = "4.5.51", features = ["derive"] }
|
||||
config = "0.15.18"
|
||||
17
crates/common/Cargo.toml
Normal file
17
crates/common/Cargo.toml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
[package]
|
||||
name = "fc-common"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
sqlx.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
uuid.workspace = true
|
||||
chrono.workspace = true
|
||||
anyhow.workspace = true
|
||||
thiserror.workspace = true
|
||||
git2.workspace = true
|
||||
29
crates/common/src/error.rs
Normal file
29
crates/common/src/error.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
//! Error types for FC CI
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum CiError {
|
||||
#[error("Database error: {0}")]
|
||||
Database(#[from] sqlx::Error),
|
||||
|
||||
#[error("Git error: {0}")]
|
||||
Git(#[from] git2::Error),
|
||||
|
||||
#[error("Serialization error: {0}")]
|
||||
Serialization(#[from] serde_json::Error),
|
||||
|
||||
#[error("IO error: {0}")]
|
||||
Io(#[from] std::io::Error),
|
||||
|
||||
#[error("Configuration error: {0}")]
|
||||
Config(String),
|
||||
|
||||
#[error("Build error: {0}")]
|
||||
Build(String),
|
||||
|
||||
#[error("Not found: {0}")]
|
||||
NotFound(String),
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, CiError>;
|
||||
7
crates/common/src/lib.rs
Normal file
7
crates/common/src/lib.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
//! Common types and utilities for CI
|
||||
|
||||
pub mod error;
|
||||
pub mod models;
|
||||
|
||||
pub use error::*;
|
||||
pub use models::*;
|
||||
67
crates/common/src/models.rs
Normal file
67
crates/common/src/models.rs
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
//! Data models for CI
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::FromRow;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||
pub struct Project {
|
||||
pub id: Uuid,
|
||||
pub name: String,
|
||||
pub description: Option<String>,
|
||||
pub repository_url: String,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||
pub struct Jobset {
|
||||
pub id: Uuid,
|
||||
pub project_id: Uuid,
|
||||
pub name: String,
|
||||
pub nix_expression: String,
|
||||
pub enabled: bool,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||
pub struct Evaluation {
|
||||
pub id: Uuid,
|
||||
pub jobset_id: Uuid,
|
||||
pub commit_hash: String,
|
||||
pub evaluation_time: DateTime<Utc>,
|
||||
pub status: EvaluationStatus,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, sqlx::Type)]
|
||||
#[sqlx(type_name = "text", rename_all = "lowercase")]
|
||||
pub enum EvaluationStatus {
|
||||
Pending,
|
||||
Running,
|
||||
Completed,
|
||||
Failed,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||
pub struct Build {
|
||||
pub id: Uuid,
|
||||
pub evaluation_id: Uuid,
|
||||
pub job_name: String,
|
||||
pub drv_path: String,
|
||||
pub status: BuildStatus,
|
||||
pub started_at: Option<DateTime<Utc>>,
|
||||
pub completed_at: Option<DateTime<Utc>>,
|
||||
pub log_path: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, sqlx::Type)]
|
||||
#[sqlx(type_name = "text", rename_all = "lowercase")]
|
||||
pub enum BuildStatus {
|
||||
Pending,
|
||||
Running,
|
||||
Completed,
|
||||
Failed,
|
||||
Cancelled,
|
||||
}
|
||||
23
crates/evaluator/Cargo.toml
Normal file
23
crates/evaluator/Cargo.toml
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
[package]
|
||||
name = "fc-evaluator"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
tokio.workspace = true
|
||||
sqlx.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
uuid.workspace = true
|
||||
chrono.workspace = true
|
||||
tracing.workspace = true
|
||||
tracing-subscriber.workspace = true
|
||||
anyhow.workspace = true
|
||||
thiserror.workspace = true
|
||||
git2.workspace = true
|
||||
clap.workspace = true
|
||||
config.workspace = true
|
||||
fc-common = { path = "../common" }
|
||||
23
crates/evaluator/src/main.rs
Normal file
23
crates/evaluator/src/main.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
use clap::Parser;
|
||||
use tracing_subscriber::fmt::init;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(name = "fc-evaluator")]
|
||||
#[command(about = "CI Evaluator - Git polling and Nix evaluation")]
|
||||
struct Cli {
|
||||
#[arg(short, long)]
|
||||
config: Option<String>,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
#[allow(unused_variables, reason = "Main application logic is TODO")]
|
||||
let cli = Cli::parse();
|
||||
|
||||
tracing::info!("Starting CI Evaluator");
|
||||
init();
|
||||
|
||||
// TODO: Implement evaluator logic
|
||||
|
||||
Ok(())
|
||||
}
|
||||
22
crates/queue-runner/Cargo.toml
Normal file
22
crates/queue-runner/Cargo.toml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
[package]
|
||||
name = "fc-queue-runner"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
tokio.workspace = true
|
||||
sqlx.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
uuid.workspace = true
|
||||
chrono.workspace = true
|
||||
tracing.workspace = true
|
||||
tracing-subscriber.workspace = true
|
||||
anyhow.workspace = true
|
||||
thiserror.workspace = true
|
||||
clap.workspace = true
|
||||
config.workspace = true
|
||||
fc-common = { path = "../common" }
|
||||
23
crates/queue-runner/src/main.rs
Normal file
23
crates/queue-runner/src/main.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
use clap::Parser;
|
||||
use tracing_subscriber::fmt::init;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(name = "fc-queue-runner")]
|
||||
#[command(about = "CI Queue Runner - Build dispatch and execution")]
|
||||
struct Cli {
|
||||
#[arg(short, long)]
|
||||
workers: Option<usize>,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
#[allow(unused_variables, reason = "Main application logic is TODO")]
|
||||
let cli = Cli::parse();
|
||||
|
||||
tracing::info!("Starting CI Queue Runner");
|
||||
init();
|
||||
|
||||
// TODO: Implement queue runner logic
|
||||
|
||||
Ok(())
|
||||
}
|
||||
23
crates/server/Cargo.toml
Normal file
23
crates/server/Cargo.toml
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
[package]
|
||||
name = "fc-server"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
tokio.workspace = true
|
||||
axum.workspace = true
|
||||
sqlx.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
uuid.workspace = true
|
||||
chrono.workspace = true
|
||||
tracing.workspace = true
|
||||
tracing-subscriber.workspace = true
|
||||
anyhow.workspace = true
|
||||
thiserror.workspace = true
|
||||
clap.workspace = true
|
||||
config.workspace = true
|
||||
fc-common = { path = "../common" }
|
||||
22
crates/server/src/main.rs
Normal file
22
crates/server/src/main.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
use clap::Parser;
|
||||
use tracing_subscriber::fmt::init;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(name = "fc-server")]
|
||||
#[command(about = "CI Server - Web API and UI")]
|
||||
struct Cli {
|
||||
#[arg(short, long, default_value = "3000")]
|
||||
port: u16,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
let cli = Cli::parse();
|
||||
|
||||
tracing::info!("Starting CI Server on port {}", cli.port);
|
||||
init();
|
||||
|
||||
// TODO: Implement server logic
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue