Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,7 @@ impl RustwideBuilder {
.runtime
.block_on(self.registry_api.get_release_data(name, version))
{
Ok(data) => Some(data),
Ok(data) => data,
Err(err) => {
error!(%name, %version, ?err, "could not fetch releases-data");
None
Expand Down
7 changes: 5 additions & 2 deletions crates/bin/docs_rs_import_release/src/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{
rustdoc::{download_static_files, find_static_paths, find_successful_build_targets},
rustdoc_status::fetch_rustdoc_status,
};
use anyhow::{Result, bail};
use anyhow::{Result, anyhow, bail};
use docs_rs_cargo_metadata::CargoMetadata;
use docs_rs_database::releases::{
finish_build, finish_release, initialize_build, initialize_crate, initialize_release,
Expand Down Expand Up @@ -117,7 +117,10 @@ async fn import_test_release_inner(
(files_list, source_size)
};

let registry_data = registry_api.get_release_data(name, version).await?;
let registry_data = registry_api
.get_release_data(name, version)
.await?
.ok_or_else(|| anyhow!("release not found in registry"))?;

let rustdoc_dir = {
info!("download & extract rustdoc archive...");
Expand Down
1 change: 1 addition & 0 deletions crates/lib/docs_rs_registry_api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ tracing = { workspace = true }
url = { workspace = true }

[dev-dependencies]
docs_rs_types = { path = "../docs_rs_types", features = ["testing"] }
mime = { workspace = true }
mockito = { workspace = true }
test-case = { workspace = true }
Expand Down
136 changes: 128 additions & 8 deletions crates/lib/docs_rs_registry_api/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ use crate::{
error::{Error, Result},
models::{ApiErrors, CrateData, CrateOwner, OwnerKind, ReleaseData, Search, SearchResponse},
};
use anyhow::{Context, anyhow};
use chrono::{DateTime, Utc};
use docs_rs_types::{KrateName, Version};
use docs_rs_utils::{APP_USER_AGENT, retry_async};
use reqwest::header::{ACCEPT, HeaderValue, USER_AGENT};
use reqwest::{
StatusCode,
header::{ACCEPT, HeaderValue, USER_AGENT},
};
use serde::{Deserialize, de::DeserializeOwned};
use tracing::instrument;
use url::Url;
Expand Down Expand Up @@ -111,7 +113,7 @@ impl RegistryApi {
&self,
name: &KrateName,
version: &Version,
) -> Result<ReleaseData> {
) -> Result<Option<ReleaseData>> {
let url = {
let mut url = self.api_base.clone();
url.path_segments_mut()
Expand All @@ -136,19 +138,25 @@ impl RegistryApi {
downloads: i32,
}

let response: Response = self.request(&url).await?;
let response: Response = match self.request(&url).await {
Ok(response) => response,
Err(err) if err.status() == Some(StatusCode::NOT_FOUND) => return Ok(None),
Err(err) => return Err(err),
};

let version = response
let Some(version) = response
.versions
.into_iter()
.find(|data| data.num == *version)
.with_context(|| anyhow!("Could not find version in response"))?;
else {
return Ok(None);
};

Ok(ReleaseData {
Ok(Some(ReleaseData {
release_time: version.created_at,
yanked: version.yanked,
downloads: version.downloads,
})
}))
}

/// Fetch owners from the registry's API
Expand Down Expand Up @@ -222,6 +230,8 @@ impl RegistryApi {
mod tests {
use super::*;
use crate::models::{ApiError, SearchCrate, SearchMeta};
use anyhow::anyhow;
use docs_rs_types::testing::{KRATE, V1, V2};
use reqwest::{StatusCode, header::CONTENT_TYPE};
use serde::Serialize;
use test_case::test_case;
Expand All @@ -241,6 +251,25 @@ mod tests {
api.search("q=foo").await
}

async fn test_get_release(
status: StatusCode,
body: impl Serialize,
version: &Version,
) -> Result<Option<ReleaseData>> {
let mut crates_io_api = mockito::Server::new_async().await;

let _m = crates_io_api
.mock("GET", "/api/v1/crates/krate/versions")
.with_status(status.as_u16().into())
.with_header(CONTENT_TYPE, mime::APPLICATION_JSON.as_ref())
.with_body(serde_json::to_vec(&body).unwrap())
.create_async()
.await;

let api = RegistryApi::new(crates_io_api.url().parse().unwrap(), 0)?;
api.get_release_data(&KRATE, version).await
}

#[test]
fn test_error_without_status() {
for err in [
Expand Down Expand Up @@ -397,4 +426,95 @@ mod tests {

Ok(())
}

#[tokio::test]
async fn test_get_release_ok() -> Result<()> {
let release_data = test_get_release(
StatusCode::OK,
serde_json::json!({
"versions": [
{
"num": V1.to_string(),
"created_at": "2024-01-01T00:00:00Z",
"yanked": false,
"downloads": 42
},
{
"num": V2.to_string(),
"created_at": "2024-01-02T00:00:00Z",
"yanked": true,
"downloads": 100
}
]
}),
&V1,
)
.await?
.expect("found version");

assert_eq!(
release_data,
ReleaseData {
release_time: DateTime::parse_from_rfc3339("2024-01-01T00:00:00Z")
.unwrap()
.with_timezone(&Utc),
yanked: false,
downloads: 42,
}
);

Ok(())
}

#[tokio::test]
async fn test_get_release_not_found_empty_result() -> Result<()> {
assert!(
test_get_release(
StatusCode::OK,
serde_json::json!({
"versions": []
}),
&V1,
)
.await?
.is_none()
);

Ok(())
}

#[tokio::test]
async fn test_get_release_not_found_other_version() -> Result<()> {
assert!(
test_get_release(
StatusCode::OK,
serde_json::json!({
"versions": [
{
"num": V1.to_string(),
"created_at": "2024-01-01T00:00:00Z",
"yanked": false,
"downloads": 42
}
]
}),
&V2,
)
.await?
.is_none()
);

Ok(())
}

#[tokio::test]
async fn test_get_release_not_found_404() -> Result<()> {
assert!(
test_get_release(StatusCode::NOT_FOUND, "", &V1)
.await?
.is_none()
);

Ok(())
}
}
1 change: 0 additions & 1 deletion crates/lib/docs_rs_registry_api/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ mod tests {
let status = StatusCode::INTERNAL_SERVER_ERROR;

assert!(Error::CrateIoApiError(status, ApiErrors::default()).status() == Some(status));

assert!(Error::CrateIoError(status, "".into()).status() == Some(status));
}

Expand Down
1 change: 1 addition & 0 deletions crates/lib/docs_rs_registry_api/src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub struct CrateData {
}

#[derive(Debug)]
#[cfg_attr(test, derive(PartialEq))]
pub struct ReleaseData {
pub release_time: DateTime<Utc>,
pub yanked: bool,
Expand Down
Loading