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