rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5 heartwood881fe0251902ced0de517af9685f9e61054e9192
{
"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": "e855cbf7171ef5c4e42f5b8ba1c9d624f1b517e4",
"author": {
"id": "did:key:z6MkkfM3tPXNPrPevKr3uSiQtHPuwnNhu2yUVjgd2jXVsVz5",
"alias": "sebastinez"
},
"title": "httpd: Add /raw route to get file at canonical head",
"state": {
"status": "merged",
"conflicts": []
},
"before": "db98daeccaa08d2dbf2982beec599519be24f6af",
"after": "881fe0251902ced0de517af9685f9e61054e9192",
"commits": [
"881fe0251902ced0de517af9685f9e61054e9192"
],
"target": "6cfed884bf37cba1e0d8e97fa8b0e94df4a04b1f",
"labels": [],
"assignees": [],
"revisions": [
{
"id": "e855cbf7171ef5c4e42f5b8ba1c9d624f1b517e4",
"author": {
"id": "did:key:z6MkkfM3tPXNPrPevKr3uSiQtHPuwnNhu2yUVjgd2jXVsVz5",
"alias": "sebastinez"
},
"description": "Instead of requiring to specify a commit to obtain a file through the\n/raw route, this commit allows to prefix `/head` to get the file at the\ncurrent canonical head commit.",
"base": "db98daeccaa08d2dbf2982beec599519be24f6af",
"oid": "981682240364aface75295f5bbcfa96d08c422fa",
"timestamp": 1717153461
},
{
"id": "0ae09a1378522739453b5f0b2e9dc91d344bebb5",
"author": {
"id": "did:key:z6MkkfM3tPXNPrPevKr3uSiQtHPuwnNhu2yUVjgd2jXVsVz5",
"alias": "sebastinez"
},
"description": "Use `head()` instead of `canonical_head()`",
"base": "db98daeccaa08d2dbf2982beec599519be24f6af",
"oid": "881fe0251902ced0de517af9685f9e61054e9192",
"timestamp": 1717502581
},
{
"id": "8d187be6ea3fc47fa60cd588d537bf065c2968ce",
"author": {
"id": "did:key:z6MkkfM3tPXNPrPevKr3uSiQtHPuwnNhu2yUVjgd2jXVsVz5",
"alias": "sebastinez"
},
"description": "Rebase.",
"base": "3ae7e305bd6d93f3e92167285e2fe00c4cdef50d",
"oid": "dff6df10fb3837093014da692dcd3263cd0f3d31",
"timestamp": 1717503589
}
]
}
}
{
"response": "triggered",
"run_id": {
"id": "91b5a645-3283-410d-b15d-fd5b132df2fb"
},
"info_url": "https://cci.rad.levitte.org//91b5a645-3283-410d-b15d-fd5b132df2fb.html"
}
Started at: 2025-10-21 18:58:49.356805+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/91b5a645-3283-410d-b15d-fd5b132df2fb/w/
╭────────────────────────────────────╮
│ heartwood │
│ Radicle Heartwood Protocol & Stack │
│ 125 issues · 15 patches │
╰────────────────────────────────────╯
Run `cd ./.` to go to the repository directory.
Exit code: 0
$ rad patch checkout e855cbf7171ef5c4e42f5b8ba1c9d624f1b517e4
✓ Switched to branch patch/e855cbf at revision 0ae09a1
✓ Branch patch/e855cbf setup to track rad/patches/e855cbf7171ef5c4e42f5b8ba1c9d624f1b517e4
Exit code: 0
$ git config advice.detachedHead false
Exit code: 0
$ git checkout 881fe0251902ced0de517af9685f9e61054e9192
HEAD is now at 881fe025 httpd: Add /raw route to get file at canonical head
Exit code: 0
$ git show 881fe0251902ced0de517af9685f9e61054e9192
commit 881fe0251902ced0de517af9685f9e61054e9192
Author: Sebastian Martinez <me@sebastinez.dev>
Date: Fri May 31 13:04:15 2024 +0200
httpd: Add /raw route to get file at canonical head
Instead of requiring to specify a commit to obtain a file through the
/raw route, this commit allows to prefix `/head` to get the file at the
current canonical head commit.
diff --git a/radicle-httpd/src/raw.rs b/radicle-httpd/src/raw.rs
index 3aa2dad6..cce1f337 100644
--- a/radicle-httpd/src/raw.rs
+++ b/radicle-httpd/src/raw.rs
@@ -7,6 +7,7 @@ use axum::response::IntoResponse;
use axum::routing::get;
use axum::Router;
use hyper::HeaderMap;
+use radicle_surf::blob::{Blob, BlobRef};
use tower_http::cors;
use radicle::prelude::RepoId;
@@ -94,8 +95,9 @@ static MIMES: &[(&str, &str)] = &[
pub fn router(profile: Arc<Profile>) -> Router {
Router::new()
- .route("/:project/:sha/*path", get(file_by_path_handler))
- .route("/:project/blobs/:oid", get(file_by_oid_handler))
+ .route("/:rid/:sha/*path", get(file_by_commit_handler))
+ .route("/:rid/head/*path", get(file_by_canonical_head_handler))
+ .route("/:rid/blobs/:oid", get(file_by_oid_handler))
.with_state(profile)
.layer(
cors::CorsLayer::new()
@@ -106,7 +108,7 @@ pub fn router(profile: Arc<Profile>) -> Router {
)
}
-async fn file_by_path_handler(
+async fn file_by_commit_handler(
Path((rid, sha, path)): Path<(RepoId, Oid, String)>,
State(profile): State<Arc<Profile>>,
) -> impl IntoResponse {
@@ -118,10 +120,36 @@ async fn file_by_path_handler(
return Err(Error::NotFound);
}
- let mut response_headers = HeaderMap::new();
let repo: Repository = repo.backend.into();
let blob = repo.blob(sha, &path)?;
+ blob_response(blob, path)
+}
+
+async fn file_by_canonical_head_handler(
+ Path((rid, path)): Path<(RepoId, String)>,
+ State(profile): State<Arc<Profile>>,
+) -> impl IntoResponse {
+ let storage = &profile.storage;
+ let repo = storage.repository(rid)?;
+
+ // Don't allow downloading raw files for private repos.
+ if repo.identity_doc()?.visibility.is_private() {
+ return Err(Error::NotFound);
+ }
+
+ let (_, sha) = repo.head()?;
+ let repo: Repository = repo.backend.into();
+ let blob = repo.blob(sha, &path)?;
+
+ blob_response(blob, path)
+}
+
+fn blob_response(
+ blob: Blob<BlobRef>,
+ path: String,
+) -> Result<(StatusCode, HeaderMap, Vec<u8>), Error> {
+ let mut response_headers = HeaderMap::new();
if blob.size() > MAX_BLOB_SIZE {
return Ok::<_, Error>((StatusCode::PAYLOAD_TOO_LARGE, response_headers, vec![]));
}
@@ -171,8 +199,8 @@ async fn file_by_oid_handler(
mod routes {
use axum::http::StatusCode;
- use crate::test::{self, get, HEAD, RID, RID_PRIVATE};
- use radicle::storage::{ReadRepository, ReadStorage};
+ use crate::test::{self, get, RID, RID_PRIVATE};
+ use radicle::storage::ReadStorage;
#[tokio::test]
async fn test_file_handler() {
@@ -180,20 +208,18 @@ mod routes {
let ctx = test::seed(tmp.path());
let app = super::router(ctx.profile().to_owned());
- let response = get(&app, format!("/{RID}/{HEAD}/dir1/README")).await;
+ let response = get(&app, format!("/{RID}/head/dir1/README")).await;
assert_eq!(response.status(), StatusCode::OK);
assert_eq!(response.body().await, "Hello World from dir1!\n");
// Make sure the repo exists in storage.
- let repo = ctx
- .profile()
+ ctx.profile()
.storage
.repository(RID_PRIVATE.parse().unwrap())
.unwrap();
- let (_, head) = repo.head().unwrap();
- let response = get(&app, format!("/{RID_PRIVATE}/{head}/README")).await;
+ let response = get(&app, format!("/{RID_PRIVATE}/head/README")).await;
assert_eq!(response.status(), StatusCode::NOT_FOUND);
}
}
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 91b5a645-3283-410d-b15d-fd5b132df2fb -v /opt/radcis/ci.rad.levitte.org/cci/state/91b5a645-3283-410d-b15d-fd5b132df2fb/s:/91b5a645-3283-410d-b15d-fd5b132df2fb/s:ro -v /opt/radcis/ci.rad.levitte.org/cci/state/91b5a645-3283-410d-b15d-fd5b132df2fb/w:/91b5a645-3283-410d-b15d-fd5b132df2fb/w -w /91b5a645-3283-410d-b15d-fd5b132df2fb/w -v /opt/radcis/ci.rad.levitte.org/.radicle:/${id}/.radicle:ro -e RAD_HOME=/${id}/.radicle rust:bookworm bash /91b5a645-3283-410d-b15d-fd5b132df2fb/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"
}