rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5 heartwoodef52e15bdf39939ed7e276b960efd46f9d325681
{
"request": "trigger",
"version": 1,
"event_type": "patch",
"repository": {
"id": "rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5",
"name": "heartwood",
"description": "Radicle Heartwood Protocol & Stack",
"private": false,
"default_branch": "master",
"delegates": [
"did:key:z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT",
"did:key:z6MktaNvN1KVFMkSRAiN4qK5yvX1zuEEaseeX5sffhzPZRZW",
"did:key:z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM",
"did:key:z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz",
"did:key:z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz"
]
},
"action": "Created",
"patch": {
"id": "f2659b3488965a4d2f4f67beb2f2317b9bb62f02",
"author": {
"id": "did:key:z6MkkfM3tPXNPrPevKr3uSiQtHPuwnNhu2yUVjgd2jXVsVz5",
"alias": "sebastinez"
},
"title": "httpd: Decouple repo stats from tree endpoint",
"state": {
"status": "merged",
"conflicts": []
},
"before": "abf89438ea3e3b61dda68677761ba43772eac27d",
"after": "ef52e15bdf39939ed7e276b960efd46f9d325681",
"commits": [
"ef52e15bdf39939ed7e276b960efd46f9d325681"
],
"target": "6cfed884bf37cba1e0d8e97fa8b0e94df4a04b1f",
"labels": [],
"assignees": [],
"revisions": [
{
"id": "f2659b3488965a4d2f4f67beb2f2317b9bb62f02",
"author": {
"id": "did:key:z6MkkfM3tPXNPrPevKr3uSiQtHPuwnNhu2yUVjgd2jXVsVz5",
"alias": "sebastinez"
},
"description": "",
"base": "bb5355fcb1a47e6a6ac3e441e2b807906d7ef135",
"oid": "23d592b3e4156917f934c4b20b406e1c3984e5db",
"timestamp": 1714481200
},
{
"id": "ff268203e1aa0243733a80cf658e42c021cd9a7b",
"author": {
"id": "did:key:z6MkkfM3tPXNPrPevKr3uSiQtHPuwnNhu2yUVjgd2jXVsVz5",
"alias": "sebastinez"
},
"description": "Fix tests",
"base": "bb5355fcb1a47e6a6ac3e441e2b807906d7ef135",
"oid": "f0a42c5b768de04560d794d85c3608b643f913c7",
"timestamp": 1714481634
},
{
"id": "4260aecaaa53f475fc7bd0c81ab28d384dd63690",
"author": {
"id": "did:key:z6MkkfM3tPXNPrPevKr3uSiQtHPuwnNhu2yUVjgd2jXVsVz5",
"alias": "sebastinez"
},
"description": "Update `/stats/:sha` endpoint to `/stats/tree/:sha`",
"base": "bb5355fcb1a47e6a6ac3e441e2b807906d7ef135",
"oid": "766c1e250d87ab1ee2645a75002ebf9226b03b45",
"timestamp": 1714485152
},
{
"id": "e5720c3871c3c2fe2dbc90b83710c57949c8ab9b",
"author": {
"id": "did:key:z6MkkfM3tPXNPrPevKr3uSiQtHPuwnNhu2yUVjgd2jXVsVz5",
"alias": "sebastinez"
},
"description": "Rebase and use `/tree/stats/:oid` as new endpoint for tree stats",
"base": "abf89438ea3e3b61dda68677761ba43772eac27d",
"oid": "ef52e15bdf39939ed7e276b960efd46f9d325681",
"timestamp": 1714638708
},
{
"id": "75c83ab973c5092225b0b239dd0b9b6a58821f8f",
"author": {
"id": "did:key:z6MkkfM3tPXNPrPevKr3uSiQtHPuwnNhu2yUVjgd2jXVsVz5",
"alias": "sebastinez"
},
"description": "Rebase.",
"base": "a9b94b0ad671e4d8e3129b1e2da86325a114896f",
"oid": "854fc9af8ebad0a3323f34ba78e4b328e8027ddd",
"timestamp": 1714653692
}
]
}
}
{
"response": "triggered",
"run_id": {
"id": "d240a4d0-997e-4e68-9bc3-79ce1f3ab495"
},
"info_url": "https://cci.rad.levitte.org//d240a4d0-997e-4e68-9bc3-79ce1f3ab495.html"
}
Started at: 2025-10-21 18:59:01.700761+02:00
Commands:
$ rad clone rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5 .
✓ Creating checkout in ./...
✓ Remote cloudhead@z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT added
✓ Remote-tracking branch cloudhead@z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT/master created for z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT
✓ Remote cloudhead@z6MktaNvN1KVFMkSRAiN4qK5yvX1zuEEaseeX5sffhzPZRZW added
✓ Remote-tracking branch cloudhead@z6MktaNvN1KVFMkSRAiN4qK5yvX1zuEEaseeX5sffhzPZRZW/master created for z6MktaNvN1KVFMkSRAiN4qK5yvX1zuEEaseeX5sffhzPZRZW
✓ Remote fintohaps@z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM added
✓ Remote-tracking branch fintohaps@z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM/master created for z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM
✓ Remote erikli@z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz added
✓ Remote-tracking branch erikli@z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz/master created for z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz
✓ Remote lorenz@z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz added
✓ Remote-tracking branch lorenz@z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz/master created for z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz
✓ Repository successfully cloned under /opt/radcis/ci.rad.levitte.org/cci/state/d240a4d0-997e-4e68-9bc3-79ce1f3ab495/w/
╭────────────────────────────────────╮
│ heartwood │
│ Radicle Heartwood Protocol & Stack │
│ 125 issues · 15 patches │
╰────────────────────────────────────╯
Run `cd ./.` to go to the repository directory.
Exit code: 0
$ rad patch checkout f2659b3488965a4d2f4f67beb2f2317b9bb62f02
✓ Switched to branch patch/f2659b3 at revision e5720c3
✓ Branch patch/f2659b3 setup to track rad/patches/f2659b3488965a4d2f4f67beb2f2317b9bb62f02
Exit code: 0
$ git config advice.detachedHead false
Exit code: 0
$ git checkout ef52e15bdf39939ed7e276b960efd46f9d325681
HEAD is now at ef52e15b httpd: Decouple repo stats from tree endpoint
Exit code: 0
$ git show ef52e15bdf39939ed7e276b960efd46f9d325681
commit ef52e15bdf39939ed7e276b960efd46f9d325681
Author: Sebastian Martinez <me@sebastinez.dev>
Date: Tue Apr 30 14:46:38 2024 +0200
httpd: Decouple repo stats from tree endpoint
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<T: AsRef<[u8]>>(blob: &Blob<T>) -> 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..dbace963 100644
--- a/radicle-httpd/src/api/v1/projects.rs
+++ b/radicle-httpd/src/api/v1/projects.rs
@@ -54,6 +54,7 @@ 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/tree/stats/:sha", get(tree_stats_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 +231,10 @@ async fn history_handler(
.take(per_page)
.collect::<Vec<_>>();
- 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 +426,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 +436,19 @@ async fn tree_handler(
Ok::<_, Error>(immutable_response(response))
}
+/// Get project source tree stats.
+/// `GET /projects/:project/tree/stats/:sha`
+async fn tree_stats_handler(
+ State(ctx): State<Context>,
+ 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 +1109,7 @@ mod routes {
assert_eq!(response.status(), StatusCode::OK);
assert_eq!(
response.json().await,
- json!({
- "commits": [
+ json!([
{
"id": HEAD,
"author": {
@@ -1152,13 +1159,7 @@ mod routes {
"time": 1673001014,
},
},
- ],
- "stats": {
- "commits": 3,
- "branches": 1,
- "contributors": 1
- }
- })
+ ])
);
}
@@ -1343,6 +1344,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}/tree/stats/{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 +1406,6 @@ mod routes {
},
"name": "",
"path": "",
- "stats": {
- "commits": 3,
- "branches": 1,
- "contributors": 1
- }
}
)
);
@@ -1428,11 +1443,6 @@ mod routes {
},
"name": "dir1",
"path": "dir1",
- "stats": {
- "commits": 3,
- "branches": 1,
- "contributors": 1
- }
})
);
}
Exit code: 0
shell: 'cargo --version rustc --version cargo fmt --check cargo clippy --all-targets --workspace -- --deny clippy::all cargo build --all-targets --workspace cargo doc --workspace cargo test --workspace --no-fail-fast '
Commands:
$ podman run --name d240a4d0-997e-4e68-9bc3-79ce1f3ab495 -v /opt/radcis/ci.rad.levitte.org/cci/state/d240a4d0-997e-4e68-9bc3-79ce1f3ab495/s:/d240a4d0-997e-4e68-9bc3-79ce1f3ab495/s:ro -v /opt/radcis/ci.rad.levitte.org/cci/state/d240a4d0-997e-4e68-9bc3-79ce1f3ab495/w:/d240a4d0-997e-4e68-9bc3-79ce1f3ab495/w -w /d240a4d0-997e-4e68-9bc3-79ce1f3ab495/w -v /opt/radcis/ci.rad.levitte.org/.radicle:/${id}/.radicle:ro -e RAD_HOME=/${id}/.radicle rust:bookworm bash /d240a4d0-997e-4e68-9bc3-79ce1f3ab495/s/script.sh
+ cargo --version
info: syncing channel updates for '1.77-x86_64-unknown-linux-gnu'
info: latest update on 2024-04-09, rust version 1.77.2 (25ef9e3d8 2024-04-09)
info: downloading component 'cargo'
info: downloading component 'rust-std'
info: downloading component 'rustc'
info: installing component 'cargo'
info: installing component 'rust-std'
info: installing component 'rustc'
cargo 1.77.2 (e52e36006 2024-03-26)
+ rustc --version
rustc 1.77.2 (25ef9e3d8 2024-04-09)
+ cargo fmt --check
error: 'cargo-fmt' is not installed for the toolchain '1.77-x86_64-unknown-linux-gnu'.
To install, run `rustup component add --toolchain 1.77-x86_64-unknown-linux-gnu rustfmt`
Exit code: 1
{
"response": "finished",
"result": "failure"
}