forked from github-starred/komodo
build monthly stats and build versions
This commit is contained in:
@@ -1,13 +1,17 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::Context;
|
||||
use async_timing_util::unix_timestamp_ms;
|
||||
use async_trait::async_trait;
|
||||
use futures::TryStreamExt;
|
||||
use monitor_types::{
|
||||
entities::{
|
||||
build::{Build, BuildActionState},
|
||||
PermissionLevel,
|
||||
Operation, PermissionLevel, update::UpdateStatus,
|
||||
},
|
||||
requests::read::*,
|
||||
};
|
||||
use mungos::mongodb::bson::doc;
|
||||
use mungos::mongodb::{bson::doc, options::FindOptions};
|
||||
use resolver_api::Resolve;
|
||||
|
||||
use crate::{auth::RequestUser, resource::Resource, state::State};
|
||||
@@ -87,3 +91,130 @@ impl Resolve<GetBuildsSummary, RequestUser> for State {
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
const ONE_DAY_MS: i64 = 86400000;
|
||||
|
||||
#[async_trait]
|
||||
impl Resolve<GetBuildMonthlyStats, RequestUser> for State {
|
||||
async fn resolve(
|
||||
&self,
|
||||
GetBuildMonthlyStats { page }: GetBuildMonthlyStats,
|
||||
_: RequestUser,
|
||||
) -> anyhow::Result<GetBuildMonthlyStatsResponse> {
|
||||
let curr_ts = unix_timestamp_ms() as i64;
|
||||
let next_day = curr_ts - curr_ts % ONE_DAY_MS + ONE_DAY_MS;
|
||||
|
||||
let close_ts = next_day - page as i64 * 30 * ONE_DAY_MS;
|
||||
let open_ts = close_ts - 30 * ONE_DAY_MS;
|
||||
|
||||
let mut build_updates = self
|
||||
.db
|
||||
.updates
|
||||
.collection
|
||||
.find(
|
||||
doc! {
|
||||
"start_ts": {
|
||||
"$gte": open_ts,
|
||||
"$lt": close_ts
|
||||
},
|
||||
"operation": Operation::RunBuild.to_string(),
|
||||
},
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.context("failed to get updates cursor")?;
|
||||
|
||||
let mut days = HashMap::<i64, BuildStatsDay>::with_capacity(32);
|
||||
|
||||
let mut curr = open_ts;
|
||||
|
||||
while curr < close_ts {
|
||||
let stats = BuildStatsDay {
|
||||
ts: curr as f64,
|
||||
..Default::default()
|
||||
};
|
||||
days.insert(curr, stats);
|
||||
curr += ONE_DAY_MS;
|
||||
}
|
||||
|
||||
while let Some(update) = build_updates.try_next().await? {
|
||||
if let Some(end_ts) = update.end_ts {
|
||||
let day = update.start_ts - update.start_ts % ONE_DAY_MS;
|
||||
let mut entry = days.entry(day).or_default();
|
||||
entry.count += 1.0;
|
||||
entry.time += ms_to_hour(end_ts - update.start_ts);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(GetBuildMonthlyStatsResponse::new(
|
||||
days.into_values().collect(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
const MS_TO_HOUR_DIVISOR: f64 = 1000.0 * 60.0 * 60.0;
|
||||
fn ms_to_hour(duration: i64) -> f64 {
|
||||
duration as f64 / MS_TO_HOUR_DIVISOR
|
||||
}
|
||||
|
||||
const NUM_VERSIONS_PER_PAGE: u64 = 10;
|
||||
|
||||
#[async_trait]
|
||||
impl Resolve<GetBuildVersions, RequestUser> for State {
|
||||
async fn resolve(
|
||||
&self,
|
||||
GetBuildVersions {
|
||||
id,
|
||||
page,
|
||||
major,
|
||||
minor,
|
||||
patch,
|
||||
}: GetBuildVersions,
|
||||
user: RequestUser,
|
||||
) -> anyhow::Result<Vec<BuildVersionResponseItem>> {
|
||||
let _: Build = self
|
||||
.get_resource_check_permissions(&id, &user, PermissionLevel::Read)
|
||||
.await?;
|
||||
|
||||
let mut filter = doc! {
|
||||
"target": {
|
||||
"type": "Build",
|
||||
"id": id
|
||||
},
|
||||
"operation": Operation::RunBuild.to_string(),
|
||||
"status": UpdateStatus::Complete.to_string(),
|
||||
"success": true
|
||||
};
|
||||
if let Some(major) = major {
|
||||
filter.insert("version.major", major);
|
||||
}
|
||||
if let Some(minor) = minor {
|
||||
filter.insert("version.minor", minor);
|
||||
}
|
||||
if let Some(patch) = patch {
|
||||
filter.insert("version.patch", patch);
|
||||
}
|
||||
let versions = self
|
||||
.db
|
||||
.updates
|
||||
.get_some(
|
||||
filter,
|
||||
FindOptions::builder()
|
||||
.sort(doc! { "_id": -1 })
|
||||
.limit(NUM_VERSIONS_PER_PAGE as i64)
|
||||
.skip(page as u64 * NUM_VERSIONS_PER_PAGE)
|
||||
.build(),
|
||||
)
|
||||
.await
|
||||
.context("failed to pull versions from mongo")?
|
||||
.into_iter()
|
||||
.map(|u| (u.version, u.start_ts))
|
||||
.filter(|(v, _)| !v.is_none())
|
||||
.map(|(version, ts)| BuildVersionResponseItem {
|
||||
version,
|
||||
ts,
|
||||
})
|
||||
.collect();
|
||||
Ok(versions)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,6 +67,8 @@ enum ReadRequest {
|
||||
GetBuild(GetBuild),
|
||||
ListBuilds(ListBuilds),
|
||||
GetBuildActionState(GetBuildActionState),
|
||||
GetBuildMonthlyStats(GetBuildMonthlyStats),
|
||||
GetBuildVersions(GetBuildVersions),
|
||||
|
||||
// ==== REPO ====
|
||||
GetReposSummary(GetReposSummary),
|
||||
|
||||
Reference in New Issue
Block a user