Skip to content

Commit d016fd0

Browse files
sypharGuillaumeGomez
authored andcommitted
don't overwrite release information on failed builds
1 parent ab5e2c1 commit d016fd0

5 files changed

+196
-30
lines changed

.sqlx/query-e00a426fa250609748b3013a2a4f80844b1091964e8bdb0f55e55209077d15b1.json

+22
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.sqlx/query-e3216009b040994f88958082b518e2bbdb89147a2ef8b29e85bb9695c4bc8374.json

+33
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/db/add_package.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ fn get_readme(pkg: &MetadataPackage, source_dir: &Path) -> Result<Option<String>
447447
}
448448

449449
fn get_rustdoc(pkg: &MetadataPackage, source_dir: &Path) -> Result<Option<String>> {
450-
if let Some(src_path) = &pkg.targets[0].src_path {
450+
if let Some(src_path) = &pkg.targets.first().and_then(|t| t.src_path.clone()) {
451451
let src_path = Path::new(src_path);
452452
if src_path.is_absolute() {
453453
read_rust_doc(src_path)

src/docbuilder/rustwide_builder.rs

+134-27
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,32 @@ impl RustwideBuilder {
581581
None
582582
};
583583

584-
let has_examples = build.host_source_dir().join("examples").is_dir();
584+
let mut async_conn = self.runtime.block_on(self.db.get_async())?;
585+
586+
self.runtime.block_on(finish_build(
587+
&mut async_conn,
588+
build_id,
589+
&res.result.rustc_version,
590+
&res.result.docsrs_version,
591+
if res.result.successful {
592+
BuildStatus::Success
593+
} else {
594+
BuildStatus::Failure
595+
},
596+
documentation_size,
597+
None,
598+
))?;
599+
600+
{
601+
let _span = info_span!("store_build_logs").entered();
602+
let build_log_path = format!("build-logs/{build_id}/{default_target}.txt");
603+
self.storage.store_one(build_log_path, res.build_log)?;
604+
for (target, log) in target_build_logs {
605+
let build_log_path = format!("build-logs/{build_id}/{target}.txt");
606+
self.storage.store_one(build_log_path, log)?;
607+
}
608+
}
609+
585610
if res.result.successful {
586611
self.metrics.successful_builds.inc();
587612
} else if res.cargo_metadata.root().is_library() {
@@ -611,8 +636,26 @@ impl RustwideBuilder {
611636
let cargo_metadata = res.cargo_metadata.root();
612637
let repository = self.get_repo(cargo_metadata)?;
613638

614-
let mut async_conn = self.runtime.block_on(self.db.get_async())?;
639+
// when we have an unsuccessful build, but the release was already successfullly
640+
// built in the past, don't touch the release record so the docs stay intact.
641+
// This mainly happens with manually triggered or automated rebuilds.
642+
// The `release_build_status` table is already updated with the information from
643+
// the current build via `finish_build`.
644+
let current_release_build_status = self.runtime.block_on(sqlx::query_scalar!(
645+
r#"
646+
SELECT build_status AS "build_status: BuildStatus"
647+
FROM release_build_status
648+
WHERE rid = $1
649+
"#,
650+
release_id.0,
651+
).fetch_optional(&mut *async_conn))?;
652+
653+
if !res.result.successful && current_release_build_status == Some(BuildStatus::Success) {
654+
info!("build was unsuccessful, but the release was already successfully built in the past. Skipping release record update.");
655+
return Ok(false);
656+
}
615657

658+
let has_examples = build.host_source_dir().join("examples").is_dir();
616659
self.runtime.block_on(finish_release(
617660
&mut async_conn,
618661
crate_id,
@@ -639,31 +682,6 @@ impl RustwideBuilder {
639682
))?;
640683
}
641684

642-
let build_status = if res.result.successful {
643-
BuildStatus::Success
644-
} else {
645-
BuildStatus::Failure
646-
};
647-
self.runtime.block_on(finish_build(
648-
&mut async_conn,
649-
build_id,
650-
&res.result.rustc_version,
651-
&res.result.docsrs_version,
652-
build_status,
653-
documentation_size,
654-
None,
655-
))?;
656-
657-
{
658-
let _span = info_span!("store_build_logs").entered();
659-
let build_log_path = format!("build-logs/{build_id}/{default_target}.txt");
660-
self.storage.store_one(build_log_path, res.build_log)?;
661-
for (target, log) in target_build_logs {
662-
let build_log_path = format!("build-logs/{build_id}/{target}.txt");
663-
self.storage.store_one(build_log_path, log)?;
664-
}
665-
}
666-
667685
// Some crates.io crate data is mutable, so we proactively update it during a release
668686
if !is_local {
669687
match self
@@ -1023,8 +1041,12 @@ impl Default for BuildPackageSummary {
10231041

10241042
#[cfg(test)]
10251043
mod tests {
1044+
use std::iter;
1045+
10261046
use super::*;
10271047
use crate::db::types::Feature;
1048+
use crate::registry_api::ReleaseData;
1049+
use crate::storage::CompressionAlgorithm;
10281050
use crate::test::{wrapper, AxumRouterTestExt, TestEnvironment};
10291051

10301052
fn get_features(
@@ -1297,6 +1319,91 @@ mod tests {
12971319
})
12981320
}
12991321

1322+
#[test]
1323+
#[ignore]
1324+
fn test_failed_build_with_existing_successful_release() {
1325+
wrapper(|env| {
1326+
// rand 0.8.5 fails to build with recent nightly versions
1327+
// https://github.com/rust-lang/docs.rs/issues/26750
1328+
let crate_ = "rand";
1329+
let version = "0.8.5";
1330+
1331+
// create a successful release & build in the database
1332+
let release_id = env.runtime().block_on(async {
1333+
let mut conn = env.async_db().await.async_conn().await;
1334+
let crate_id = initialize_crate(&mut conn, crate_).await?;
1335+
let release_id = initialize_release(&mut conn, crate_id, version).await?;
1336+
let build_id = initialize_build(&mut conn, release_id).await?;
1337+
finish_build(
1338+
&mut conn,
1339+
build_id,
1340+
"some-version",
1341+
"other-version",
1342+
BuildStatus::Success,
1343+
None,
1344+
None,
1345+
)
1346+
.await?;
1347+
finish_release(
1348+
&mut conn,
1349+
crate_id,
1350+
release_id,
1351+
&MetadataPackage::default(),
1352+
Path::new("/unknown/"),
1353+
"x86_64-unknown-linux-gnu",
1354+
serde_json::Value::Array(vec![]),
1355+
vec![
1356+
"i686-pc-windows-msvc".into(),
1357+
"i686-unknown-linux-gnu".into(),
1358+
"x86_64-apple-darwin".into(),
1359+
"x86_64-pc-windows-msvc".into(),
1360+
"x86_64-unknown-linux-gnu".into(),
1361+
],
1362+
&ReleaseData::default(),
1363+
true,
1364+
false,
1365+
iter::once(CompressionAlgorithm::Bzip2),
1366+
None,
1367+
true,
1368+
42,
1369+
)
1370+
.await?;
1371+
1372+
Ok::<_, anyhow::Error>(release_id)
1373+
})?;
1374+
1375+
fn check_rustdoc_status(env: &TestEnvironment, rid: ReleaseId) -> Result<()> {
1376+
assert_eq!(
1377+
env.runtime().block_on(async {
1378+
let mut conn = env.async_db().await.async_conn().await;
1379+
sqlx::query_scalar!(
1380+
"SELECT rustdoc_status FROM releases WHERE id = $1",
1381+
rid.0
1382+
)
1383+
.fetch_one(&mut *conn)
1384+
.await
1385+
})?,
1386+
Some(true)
1387+
);
1388+
Ok(())
1389+
}
1390+
1391+
check_rustdoc_status(env, release_id)?;
1392+
1393+
let mut builder = RustwideBuilder::init(env).unwrap();
1394+
builder.update_toolchain()?;
1395+
assert!(
1396+
// not successful build
1397+
!builder
1398+
.build_package(crate_, version, PackageKind::CratesIo)?
1399+
.successful
1400+
);
1401+
1402+
check_rustdoc_status(env, release_id)?;
1403+
Ok(())
1404+
});
1405+
}
1406+
13001407
#[test]
13011408
#[ignore]
13021409
fn test_proc_macro() {

src/utils/cargo_metadata.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,12 @@ impl Package {
9090
}
9191

9292
pub(crate) fn package_name(&self) -> String {
93-
self.library_name()
94-
.unwrap_or_else(|| self.normalize_package_name(&self.targets[0].name))
93+
self.library_name().unwrap_or_else(|| {
94+
self.targets
95+
.first()
96+
.map(|t| self.normalize_package_name(&t.name))
97+
.unwrap_or_default()
98+
})
9599
}
96100

97101
pub(crate) fn library_name(&self) -> Option<String> {

0 commit comments

Comments
 (0)