feat: with release manager
All checks were successful
continuous-integration/drone/push Build is passing

Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
Kasper Juul Hermansen 2024-02-11 16:56:22 +01:00
parent 8bab1a1df3
commit ab3d1d9817
Signed by: kjuulh
GPG Key ID: 57B6E1465221F912
12 changed files with 192 additions and 38 deletions

35
Cargo.lock generated
View File

@ -90,15 +90,21 @@ dependencies = [
[[package]] [[package]]
name = "async-trait" name = "async-trait"
version = "0.1.68" version = "0.1.77"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn",
] ]
[[package]]
name = "atomic"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba"
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.1.0" version = "1.1.0"
@ -334,16 +340,19 @@ name = "flux-releaser"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait",
"axum 0.7.4", "axum 0.7.4",
"clap", "clap",
"dotenv", "dotenv",
"mockall", "mockall",
"mockall_double",
"prost", "prost",
"tokio", "tokio",
"tonic", "tonic",
"tonic-build", "tonic-build",
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
"uuid",
] ]
[[package]] [[package]]
@ -790,6 +799,18 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "mockall_double"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1ca96e5ac35256ae3e13536edd39b172b88f41615e1d7b653c8ad24524113e8"
dependencies = [
"cfg-if",
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "multimap" name = "multimap"
version = "0.8.3" version = "0.8.3"
@ -1482,6 +1503,16 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "uuid"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a"
dependencies = [
"atomic",
"getrandom",
]
[[package]] [[package]]
name = "valuable" name = "valuable"
version = "0.1.0" version = "0.1.0"

View File

@ -13,6 +13,9 @@ dotenv.workspace = true
axum.workspace = true axum.workspace = true
prost = "0.12.3" prost = "0.12.3"
tonic = "0.11.0" tonic = "0.11.0"
uuid = { version = "1.7.0", features = ["v7", "v4"] }
async-trait = "0.1.77"
mockall_double = "0.3.1"
[build-dependencies] [build-dependencies]
tonic-build = "0.11.0" tonic-build = "0.11.0"

View File

@ -32,10 +32,10 @@ impl Command {
let app = SharedApp::new(); let app = SharedApp::new();
tokio::select! { tokio::select! {
res = axum_serve(host, app) => { res = axum_serve(host, app.clone()) => {
res?; res?;
}, },
res = tonic_serve(grpc_host) => { res = tonic_serve(grpc_host, app.clone()) => {
res?; res?;
}, },
}; };

View File

@ -2,32 +2,57 @@ use std::net::SocketAddr;
use tonic::transport::Server; use tonic::transport::Server;
use crate::{
app::SharedApp,
services::release_manager::{
extensions::ReleaseManagerExt, models::CommitArtifact, ReleaseManager,
},
};
use self::gen::{greeter_server, HelloReply, HelloRequest}; use self::gen::{greeter_server, HelloReply, HelloRequest};
mod gen { mod gen {
tonic::include_proto!("flux_releaser"); tonic::include_proto!("flux_releaser");
} }
#[derive(Debug, Default)] pub struct FluxReleaserGrpc {
pub struct FluxReleaserGrpc {} release_manager: ReleaseManager,
}
impl FluxReleaserGrpc {
pub fn new(app: SharedApp) -> Self {
Self {
release_manager: app.release_manager(),
}
}
}
#[tonic::async_trait] #[tonic::async_trait]
impl greeter_server::Greeter for FluxReleaserGrpc { impl greeter_server::Greeter for FluxReleaserGrpc {
async fn say_hello( async fn say_hello(
&self, &self,
request: tonic::Request<HelloRequest>, request: tonic::Request<HelloRequest>,
) -> std::result::Result<tonic::Response<HelloReply>, tonic::Status> { ) -> std::result::Result<tonic::Response<HelloReply>, tonic::Status> {
self.release_manager
.commit_artifact(CommitArtifact {
app: "some-app".into(),
branch: "some-branch".into(),
})
.await
.unwrap();
Ok(tonic::Response::new(HelloReply { Ok(tonic::Response::new(HelloReply {
message: "something".into(), message: "something".into(),
})) }))
} }
} }
pub async fn tonic_serve(host: SocketAddr) -> anyhow::Result<()> { pub async fn tonic_serve(host: SocketAddr, app: SharedApp) -> anyhow::Result<()> {
tracing::info!("grpc listening on: {}", host); tracing::info!("grpc listening on: {}", host);
Server::builder() Server::builder()
.add_service(greeter_server::GreeterServer::new( .add_service(greeter_server::GreeterServer::new(FluxReleaserGrpc::new(
FluxReleaserGrpc::default(), app,
)) )))
.serve(host) .serve(host)
.await?; .await?;

View File

@ -1 +1,2 @@
mod file_store;
pub mod release_manager; pub mod release_manager;

View File

@ -0,0 +1,28 @@
use std::{path::PathBuf, sync::Arc};
use super::release_manager::models::ArtifactID;
pub mod extensions;
#[derive(Clone)]
pub struct FileStore {}
#[cfg(test)]
use mockall::{automock, mock, predicate::*};
#[cfg_attr(test, automock)]
impl FileStore {
pub fn new() -> Self {
Self {}
}
pub async fn upload_files(
&self,
artifact_id: ArtifactID,
files: Vec<PathBuf>,
) -> anyhow::Result<()> {
tracing::trace!("uploading files: {}", artifact_id.to_string());
Ok(())
}
}

View File

@ -0,0 +1,14 @@
use crate::app::SharedApp;
#[mockall_double::double]
use super::FileStore;
pub trait FileStoreExt {
fn file_store(&self) -> FileStore;
}
impl FileStoreExt for SharedApp {
fn file_store(&self) -> FileStore {
FileStore::new()
}
}

View File

@ -1,25 +1,57 @@
mod default; #[mockall_double::double]
pub mod traits; use crate::services::file_store::FileStore;
use std::sync::Arc; use self::models::{ArtifactID, CommitArtifact};
#[derive(Clone)]
pub struct ReleaseManager { pub struct ReleaseManager {
inner: Arc<dyn traits::ReleaseManager>, file_store: FileStore,
} }
impl ReleaseManager { impl ReleaseManager {
pub fn get_default() -> Self { pub fn new(file_store: FileStore) -> Self {
Self { Self { file_store }
inner: Arc::new(default::ReleaseManager::new()), }
}
pub async fn commit_artifact(&self, request: CommitArtifact) -> anyhow::Result<ArtifactID> {
tracing::debug!("committing artifact: {:?}", request);
let artifact_id = ArtifactID::new();
self.file_store
.upload_files(artifact_id.clone(), Vec::new())
.await?;
// publish domain event that it has been published
Ok(artifact_id)
} }
} }
impl std::ops::Deref for ReleaseManager { pub mod extensions;
type Target = Arc<dyn traits::ReleaseManager>; pub mod models;
fn deref(&self) -> &Self::Target { #[cfg(test)]
&self.inner mod test {
use crate::services::file_store::MockFileStore;
use super::*;
#[tokio::test]
async fn generated_artifact_id() -> anyhow::Result<()> {
let mut file_store = MockFileStore::new();
file_store
.expect_upload_files()
.times(1)
.returning(|_, _| Ok(()));
let releaser_manager = ReleaseManager::new(file_store);
releaser_manager
.commit_artifact(CommitArtifact {
app: "app".into(),
branch: "branch".into(),
})
.await?;
Ok(())
} }
} }

View File

@ -1,11 +0,0 @@
use super::traits;
pub struct ReleaseManager {}
impl ReleaseManager {
pub fn new() -> Self {
Self {}
}
}
impl traits::ReleaseManager for ReleaseManager {}

View File

@ -0,0 +1,13 @@
use crate::{app::SharedApp, services::file_store::extensions::FileStoreExt};
use super::ReleaseManager;
pub trait ReleaseManagerExt {
fn release_manager(&self) -> ReleaseManager;
}
impl ReleaseManagerExt for SharedApp {
fn release_manager(&self) -> ReleaseManager {
ReleaseManager::new(self.file_store())
}
}

View File

@ -0,0 +1,22 @@
#[derive(Clone, Debug)]
pub struct CommitArtifact {
pub app: String,
pub branch: String,
}
#[derive(Debug, Clone)]
pub struct ArtifactID(uuid::Uuid);
impl ArtifactID {
pub fn new() -> Self {
Self(uuid::Uuid::now_v7())
}
}
impl std::ops::Deref for ArtifactID {
type Target = uuid::Uuid;
fn deref(&self) -> &Self::Target {
&self.0
}
}

View File

@ -1,4 +0,0 @@
#[cfg(test)]
use mockall::{automock, mock, predicate::*};
#[cfg_attr(test, automock)]
pub trait ReleaseManager {}