diff --git a/radicle-httpd/src/api/json.rs b/radicle-httpd/src/api/json.rs index 212beaac..60b8e72b 100644 --- a/radicle-httpd/src/api/json.rs +++ b/radicle-httpd/src/api/json.rs @@ -19,7 +19,7 @@ use radicle::prelude::NodeId; use radicle::storage::{git, refs, RemoteRepository}; use radicle_surf::blob::Blob; use radicle_surf::tree::{EntryKind, Tree}; -use radicle_surf::{Commit, Oid, Stats}; +use radicle_surf::{Commit, Oid}; use crate::api::auth::Session; @@ -74,7 +74,7 @@ pub fn blob_content>(blob: &Blob) -> String { } /// Returns JSON for a tree with a given `path` and `stats`. -pub(crate) fn tree(tree: &Tree, path: &str, stats: &Stats) -> Value { +pub(crate) fn tree(tree: &Tree, path: &str) -> Value { let prefix = Path::new(path); let entries = tree .entries() @@ -98,7 +98,6 @@ pub(crate) fn tree(tree: &Tree, path: &str, stats: &Stats) -> Value { "lastCommit": commit(tree.commit()), "name": name_in_path(path), "path": path, - "stats": stats, }) } diff --git a/radicle-httpd/src/api/v1/projects.rs b/radicle-httpd/src/api/v1/projects.rs index d3e97908..4f525683 100644 --- a/radicle-httpd/src/api/v1/projects.rs +++ b/radicle-httpd/src/api/v1/projects.rs @@ -54,6 +54,10 @@ pub fn router(ctx: Context) -> Router { ) .route("/projects/:project/tree/:sha/", get(tree_handler_root)) .route("/projects/:project/tree/:sha/*path", get(tree_handler)) + .route( + "/projects/:project/stats/tree/:sha", + get(stats_tree_handler), + ) .route("/projects/:project/remotes", get(remotes_handler)) .route("/projects/:project/remotes/:peer", get(remote_handler)) .route("/projects/:project/blob/:sha/*path", get(blob_handler)) @@ -230,15 +234,10 @@ async fn history_handler( .take(per_page) .collect::>(); - let response = json!({ - "commits": commits, - "stats": repo.stats_from(&sha)?, - }); - if is_immutable { - Ok::<_, Error>(immutable_response(response).into_response()) + Ok::<_, Error>(immutable_response(commits).into_response()) } else { - Ok::<_, Error>(Json(response).into_response()) + Ok::<_, Error>(Json(commits).into_response()) } } @@ -430,8 +429,7 @@ async fn tree_handler( let repo = Repository::open(repo.path())?; let tree = repo.tree(sha, &path)?; - let stats = repo.stats_from(&sha)?; - let response = api::json::tree(&tree, &path, &stats); + let response = api::json::tree(&tree, &path); if let Some(cache) = &ctx.cache { let cache = &mut cache.tree.lock().await; @@ -441,6 +439,19 @@ async fn tree_handler( Ok::<_, Error>(immutable_response(response)) } +/// Get project source tree stats. +/// `GET /projects/:project/stats/tree/:sha` +async fn stats_tree_handler( + State(ctx): State, + Path((project, sha)): Path<(RepoId, Oid)>, +) -> impl IntoResponse { + let (repo, _) = ctx.repo(project)?; + let repo = Repository::open(repo.path())?; + let stats = repo.stats_from(&sha)?; + + Ok::<_, Error>(immutable_response(stats)) +} + /// Get all project remotes. /// `GET /projects/:project/remotes` async fn remotes_handler( @@ -1101,8 +1112,7 @@ mod routes { assert_eq!(response.status(), StatusCode::OK); assert_eq!( response.json().await, - json!({ - "commits": [ + json!([ { "id": HEAD, "author": { @@ -1152,13 +1162,7 @@ mod routes { "time": 1673001014, }, }, - ], - "stats": { - "commits": 3, - "branches": 1, - "contributors": 1 - } - }) + ]) ); } @@ -1343,6 +1347,25 @@ mod routes { assert_eq!(response.status(), StatusCode::NOT_FOUND); } + #[tokio::test] + async fn test_projects_stats() { + let tmp = tempfile::tempdir().unwrap(); + let app = super::router(seed(tmp.path())); + let response = get(&app, format!("/projects/{RID}/stats/tree/{HEAD}")).await; + + assert_eq!(response.status(), StatusCode::OK); + assert_eq!( + response.json().await, + json!( + { + "commits": 3, + "branches": 1, + "contributors": 1 + } + ) + ); + } + #[tokio::test] async fn test_projects_tree() { let tmp = tempfile::tempdir().unwrap(); @@ -1386,11 +1409,6 @@ mod routes { }, "name": "", "path": "", - "stats": { - "commits": 3, - "branches": 1, - "contributors": 1 - } } ) ); @@ -1428,11 +1446,6 @@ mod routes { }, "name": "dir1", "path": "dir1", - "stats": { - "commits": 3, - "branches": 1, - "contributors": 1 - } }) ); }