don't
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

test(knot): impl tests for `sh.tangled.repo.tag`

Signed-off-by: tjh <x@tjh.dev>

tjh d91c60de 0ab31a46

+76 -6
+66 -1
crates/gordian-knot/src/public/xrpc/sh_tangled/repo/tag.rs
··· 1 1 use core::error; 2 2 3 3 use axum::Json; 4 + use serde::Deserialize; 4 5 use serde::Serialize; 5 6 6 7 use crate::extract::repository::XrpcRepository; ··· 17 16 /// 18 17 /// This is not defined in the lexicon, but models what knotserver 19 18 /// currently produces. 20 - #[derive(Debug, Serialize)] 19 + #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)] 20 + #[serde(deny_unknown_fields)] 21 21 pub struct Output { 22 22 pub tag: Tag, 23 23 } ··· 45 43 fn from(value: TagNotFound<E>) -> Self { 46 44 use axum::http::StatusCode; 47 45 Self::new(StatusCode::NOT_FOUND, "TagNotFound", value.0.to_string()) 46 + } 47 + } 48 + 49 + #[cfg(test)] 50 + mod tests { 51 + use super::Output; 52 + use crate::public::xrpc::XrpcError; 53 + use crate::test_helpers::Client; 54 + use crate::test_helpers::TestState; 55 + 56 + fn app() -> axum::Router { 57 + axum::Router::new() 58 + .route(super::LXM, axum::routing::get(super::handle)) 59 + .with_state(TestState::default()) 60 + } 61 + 62 + const V1_12_0_ALPHA: &str = r#"{"tag":{"name":"v1.12.0-alpha","hash":"efd0b8592e77867d014b41853729faa0e054e050","tag":{"Hash":[239,208,184,89,46,119,134,125,1,75,65,133,55,41,250,160,224,84,224,80],"Name":"v1.12.0-alpha","Tagger":{"Name":"Akshay","Email":"nerdy@peppe.rs","When":"2026-03-02T09:30:08Z"},"Message":"v1.12.0-alpha\n\n* fix minor patch application discrepancy between merge-check and merge\n* update blob and tree endpoints to include last-commit info\n* add pagination to tags and branches endpoints\n-----BEGIN SSH SIGNATURE-----\nU1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgyPUOf1i4WjYE2v33fKYFrqfPLI\ngoBREioxtS18jz7hcAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5\nAAAAQIR2kUMXdS3xbwAuPNx8PTcWVfBGUqNHErS5oKhY//OINmKTpVd6JYmNhDUNWJWmfG\norMQIL40Lj2lLHhKD8OAQ=\n-----END SSH SIGNATURE-----","PGPSignature":"","TargetType":4,"Target":[143,126,97,191,81,55,60,65,124,111,152,51,159,76,123,236,181,96,210,153]},"message":"v1.12.0-alpha\n\n* fix minor patch application discrepancy between merge-check and merge\n* update blob and tree endpoints to include last-commit info\n* add pagination to tags and branches endpoints\n-----BEGIN SSH SIGNATURE-----\nU1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgyPUOf1i4WjYE2v33fKYFrqfPLI\ngoBREioxtS18jz7hcAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5\nAAAAQIR2kUMXdS3xbwAuPNx8PTcWVfBGUqNHErS5oKhY//OINmKTpVd6JYmNhDUNWJWmfG\norMQIL40Lj2lLHhKD8OAQ=\n-----END SSH SIGNATURE-----"}}"#; 63 + 64 + #[tokio::test] 65 + async fn can_get_tag_with_short_name() { 66 + let client = Client::new(app()); 67 + let output: Output = client 68 + .get( 69 + "/sh.tangled.repo.tag?repo=did:plc:65gha4t3avpfpzmvpbwovss7/core&tag=v1.12.0-alpha", 70 + ) 71 + .await 72 + .ok() 73 + .json() 74 + .await; 75 + 76 + let expected: Output = serde_json::from_str(V1_12_0_ALPHA).unwrap(); 77 + assert_eq!(output, expected); 78 + } 79 + 80 + #[tokio::test] 81 + async fn can_get_tag_with_full_name() { 82 + let client = Client::new(app()); 83 + let output: Output = client 84 + .get( 85 + "/sh.tangled.repo.tag?repo=did:plc:65gha4t3avpfpzmvpbwovss7/core&tag=refs/tags/v1.12.0-alpha", 86 + ) 87 + .await 88 + .ok() 89 + .json() 90 + .await; 91 + 92 + let expected: Output = serde_json::from_str(V1_12_0_ALPHA).unwrap(); 93 + assert_eq!(output, expected); 94 + } 95 + 96 + #[tokio::test] 97 + async fn deny_unknown_tag_with_tag_not_found() { 98 + let client = Client::new(app()); 99 + let XrpcError { error, .. } = client 100 + .get( 101 + "/sh.tangled.repo.tag?repo=did:plc:65gha4t3avpfpzmvpbwovss7/core&tag=hopefully_this_tag_does_not_exist", 102 + ) 103 + .await 104 + .not_found() 105 + .json() 106 + .await; 107 + 108 + assert_eq!(error, "TagNotFound"); 48 109 } 49 110 }
+7 -4
crates/gordian-knot/src/public/xrpc/sh_tangled/repo/tags.rs
··· 1 1 use axum::Json; 2 + use serde::Deserialize; 2 3 use serde::Serialize; 3 4 4 5 use crate::extract::repository::XrpcRepository; ··· 17 16 /// 18 17 /// This is not defined in the lexicon, but models what knotserver 19 18 /// currently produces. 20 - #[derive(Debug, Serialize)] 19 + #[derive(Debug, Deserialize, Serialize)] 20 + #[serde(deny_unknown_fields)] 21 21 pub struct Output { 22 22 pub tags: Vec<Tag>, 23 23 } 24 24 25 - #[derive(Debug, Serialize)] 26 - #[serde(rename_all = "PascalCase")] 25 + #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)] 26 + #[serde(deny_unknown_fields, rename_all = "PascalCase")] 27 27 pub struct TagAnnotation { 28 28 pub hash: ObjectId<Array>, 29 29 pub name: String, ··· 36 34 pub target: ObjectId<Array>, 37 35 } 38 36 39 - #[derive(Debug, Serialize)] 37 + #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)] 38 + #[serde(deny_unknown_fields)] 40 39 pub struct Tag { 41 40 #[serde(flatten)] 42 41 pub r#ref: Reference,
+3 -1
crates/gordian-lexicon/src/sh_tangled/repo.rs
··· 179 179 #[serde(deny_unknown_fields)] 180 180 pub struct Signature { 181 181 /// Author or committer name. 182 + #[serde(alias = "Name")] 182 183 pub name: String, 183 184 184 185 /// Author or committer email. 186 + #[serde(alias = "Email")] 185 187 pub email: String, 186 188 187 189 /// Author or committer timestamp. 188 - #[serde(with = "time::serde::rfc3339")] 190 + #[serde(alias = "When", with = "time::serde::rfc3339")] 189 191 pub when: OffsetDateTime, 190 192 } 191 193