1
0
Fork 0

Merge pull request 'feat: implement ssh_url deserialization to url::Url instead of String' (#53) from Aviac/forgejo-api:feat/parse-ssh-url into main

Reviewed-on: https://codeberg.org/Cyborus/forgejo-api/pulls/53
Reviewed-by: Cyborus <cyborus@noreply.codeberg.org>
This commit is contained in:
Cyborus 2024-05-11 15:56:37 +00:00
commit 80cba9a6c3
5 changed files with 148 additions and 5 deletions

View file

@ -63,7 +63,7 @@ pub fn create_struct_for_definition(
crate::schema_subtype_name(spec, name, prop_name, value, &mut field_ty)?;
crate::schema_subtypes(spec, name, prop_name, value, &mut subtypes)?;
}
if field_name.ends_with("url") && field_name != "ssh_url" && field_ty == "String" {
if field_name.ends_with("url") && field_ty == "String" {
field_ty = "url::Url".into()
}
if field_ty == name {
@ -73,8 +73,17 @@ pub fn create_struct_for_definition(
field_ty = format!("Option<{field_ty}>")
}
if field_ty == "Option<url::Url>" {
if field_name == "ssh_url" {
fields.push_str(
"#[serde(deserialize_with = \"crate::deserialize_optional_ssh_url\")]\n",
);
} else {
fields.push_str("#[serde(deserialize_with = \"crate::none_if_blank_url\")]\n");
}
}
if field_ty == "url::Url" && field_name == "ssh_url" {
fields.push_str("#[serde(deserialize_with = \"crate::deserialize_ssh_url\")]\n");
}
if field_ty == "time::OffsetDateTime" {
fields.push_str("#[serde(with = \"time::serde::rfc3339\")]\n");
}
@ -106,8 +115,8 @@ pub fn create_struct_for_definition(
}
}
if let Some(additonal_schema) = &schema.additional_properties {
let prop_ty = crate::schema_ref_type_name(spec, additonal_schema)?;
if let Some(additional_schema) = &schema.additional_properties {
let prop_ty = crate::schema_ref_type_name(spec, additional_schema)?;
fields.push_str("#[serde(flatten)]\n");
fields.push_str("pub additional: BTreeMap<String, ");
fields.push_str(&prop_ty);

View file

@ -2278,7 +2278,8 @@ pub struct Repository {
pub release_counter: Option<u64>,
pub repo_transfer: Option<RepoTransfer>,
pub size: Option<u64>,
pub ssh_url: Option<String>,
#[serde(deserialize_with = "crate::deserialize_optional_ssh_url")]
pub ssh_url: Option<url::Url>,
pub stars_count: Option<u64>,
pub template: Option<bool>,
#[serde(with = "time::serde::rfc3339::option")]

View file

@ -1,4 +1,5 @@
use reqwest::{Client, Request, StatusCode};
use serde::{Deserialize, Deserializer};
use soft_assert::*;
use url::Url;
use zeroize::Zeroize;
@ -254,6 +255,41 @@ fn none_if_blank_url<'de, D: serde::Deserializer<'de>>(
deserializer.deserialize_str(EmptyUrlVisitor)
}
#[allow(dead_code)] // not used yet, but it might appear in the future
fn deserialize_ssh_url<'de, D, DE>(deserializer: D) -> Result<Url, DE>
where
D: Deserializer<'de>,
DE: serde::de::Error,
{
let raw_url: String = String::deserialize(deserializer).map_err(DE::custom)?;
parse_ssh_url(&raw_url).map_err(DE::custom)
}
fn deserialize_optional_ssh_url<'de, D, DE>(deserializer: D) -> Result<Option<Url>, DE>
where
D: Deserializer<'de>,
DE: serde::de::Error,
{
let raw_url: Option<String> = Option::deserialize(deserializer).map_err(DE::custom)?;
raw_url
.as_ref()
.map(parse_ssh_url)
.map(|res| res.map_err(DE::custom))
.transpose()
.or(Ok(None))
}
fn parse_ssh_url(raw_url: &String) -> Result<Url, url::ParseError> {
// in case of a non-standard ssh-port (not 22), the ssh url coming from the forgejo API
// is actually parseable by the url crate, so try to do that first
Url::parse(raw_url).or_else(|_| {
// otherwise the ssh url is not parseable by the url crate and we try again after some
// pre-processing
let url = format!("ssh://{url}", url = raw_url.replace(":", "/"));
Url::parse(url.as_str())
})
}
impl From<structs::DefaultMergeStyle> for structs::MergePullRequestOptionDo {
fn from(value: structs::DefaultMergeStyle) -> Self {
match value {

View file

@ -430,3 +430,9 @@ async fn admin() {
.await
.expect("failed to delete hook");
}
#[test]
fn ssh_url_deserialization() {
let data = include_str!("./repo_data.json");
assert!(serde_json::from_str::<Repository>(data).is_ok());
}

91
tests/repo_data.json Normal file
View file

@ -0,0 +1,91 @@
{
"id": 160106,
"owner": {
"id": 94809,
"login": "Cyborus",
"login_name": "",
"full_name": "",
"email": "cyborus@noreply.codeberg.org",
"avatar_url": "https://codeberg.org/avatars/53e78f627539c6a0b96854028529779133724a5df2d2c229e5d0eb48aaa3d1fa",
"language": "",
"is_admin": false,
"last_login": "0001-01-01T00:00:00Z",
"created": "2023-04-30T00:54:15Z",
"restricted": false,
"active": false,
"prohibit_login": false,
"location": "",
"pronouns": "",
"website": "https://cyborus.xyz",
"description": "I host my own Forgejo instance at https://code.cartoon-aa.xyz/",
"visibility": "public",
"followers_count": 4,
"following_count": 4,
"starred_repos_count": 8,
"username": "Cyborus"
},
"name": "forgejo-api",
"full_name": "Cyborus/forgejo-api",
"description": "Rust crate to interact with the Forgejo API",
"empty": false,
"private": false,
"fork": false,
"template": false,
"parent": null,
"mirror": false,
"size": 1481,
"language": "Rust",
"languages_url": "https://codeberg.org/api/v1/repos/Cyborus/forgejo-api/languages",
"html_url": "https://codeberg.org/Cyborus/forgejo-api",
"url": "https://codeberg.org/api/v1/repos/Cyborus/forgejo-api",
"link": "",
"ssh_url": "git@codeberg.org:Cyborus/forgejo-api.git",
"clone_url": "https://codeberg.org/Cyborus/forgejo-api.git",
"original_url": "",
"website": "",
"stars_count": 4,
"forks_count": 1,
"watchers_count": 2,
"open_issues_count": 2,
"open_pr_counter": 0,
"release_counter": 2,
"default_branch": "main",
"archived": false,
"created_at": "2023-11-09T17:42:18Z",
"updated_at": "2024-04-27T22:42:52Z",
"archived_at": "1970-01-01T00:00:00Z",
"permissions": {
"admin": false,
"push": false,
"pull": true
},
"has_issues": true,
"internal_tracker": {
"enable_time_tracker": true,
"allow_only_contributors_to_track_time": true,
"enable_issue_dependencies": true
},
"has_wiki": false,
"wiki_branch": "master",
"has_pull_requests": true,
"has_projects": true,
"has_releases": true,
"has_packages": false,
"has_actions": false,
"ignore_whitespace_conflicts": false,
"allow_merge_commits": true,
"allow_rebase": true,
"allow_rebase_explicit": true,
"allow_squash_merge": true,
"allow_fast_forward_only_merge": false,
"allow_rebase_update": true,
"default_delete_branch_after_merge": true,
"default_merge_style": "merge",
"default_allow_maintainer_edit": true,
"avatar_url": "",
"internal": false,
"mirror_interval": "",
"object_format_name": "sha1",
"mirror_updated": "0001-01-01T00:00:00Z",
"repo_transfer": null
}