|
90 | 90 | pub(crate) struct Release {
|
91 | 91 | pub id: i32,
|
92 | 92 | pub version: semver::Version,
|
| 93 | + /// Aggregated build status of the release. |
| 94 | + /// * no builds -> build In progress |
| 95 | + /// * any build is successful -> Success |
| 96 | + /// -> even with failed or in-progress builds we have docs to show |
| 97 | + /// * any build is failed -> Failure |
| 98 | + /// -> we can only have Failure or InProgress here, so the Failure is the |
| 99 | + /// important part on this aggregation level. |
| 100 | + /// * the rest is all builds are in-progress -> InProgress |
| 101 | + /// -> if we have any builds, and the previous conditions don't match, we end |
| 102 | + /// up here, but we still check. |
93 | 103 | pub build_status: BuildStatus,
|
94 | 104 | pub yanked: bool,
|
95 | 105 | pub is_library: bool,
|
@@ -352,46 +362,60 @@ pub(crate) async fn releases_for_crate(
|
352 | 362 | r#"SELECT
|
353 | 363 | releases.id,
|
354 | 364 | releases.version,
|
355 |
| - COALESCE(builds.build_status, 'failure') as "build_status!: BuildStatus", |
| 365 | + ( |
| 366 | + SELECT ARRAY_AGG(builds.build_status ORDER BY builds.id) |
| 367 | + FROM builds |
| 368 | + WHERE builds.rid = releases.id |
| 369 | + ) as "build_status?: Vec<BuildStatus>", |
356 | 370 | releases.yanked,
|
357 | 371 | releases.is_library,
|
358 | 372 | releases.rustdoc_status,
|
359 | 373 | releases.target_name
|
360 | 374 | FROM releases
|
361 |
| - LEFT JOIN LATERAL ( |
362 |
| - SELECT build_status FROM builds |
363 |
| - WHERE builds.rid = releases.id |
364 |
| - ORDER BY builds.build_time |
365 |
| - DESC LIMIT 1 |
366 |
| - ) AS builds ON true |
367 | 375 | WHERE
|
368 | 376 | releases.crate_id = $1"#,
|
369 | 377 | crate_id,
|
370 | 378 | )
|
371 | 379 | .fetch(&mut *conn)
|
372 | 380 | .try_filter_map(|row| async move {
|
373 |
| - Ok( |
374 |
| - match semver::Version::parse(&row.version).with_context(|| { |
375 |
| - format!( |
376 |
| - "invalid semver in database for crate {crate_id}: {}", |
377 |
| - row.version |
378 |
| - ) |
379 |
| - }) { |
380 |
| - Ok(semversion) => Some(Release { |
381 |
| - id: row.id, |
382 |
| - version: semversion, |
383 |
| - build_status: row.build_status, |
384 |
| - yanked: row.yanked, |
385 |
| - is_library: row.is_library, |
386 |
| - rustdoc_status: row.rustdoc_status, |
387 |
| - target_name: row.target_name, |
388 |
| - }), |
389 |
| - Err(err) => { |
390 |
| - report_error(&err); |
391 |
| - None |
392 |
| - } |
393 |
| - }, |
394 |
| - ) |
| 381 | + let semversion = match semver::Version::parse(&row.version).with_context(|| { |
| 382 | + format!( |
| 383 | + "invalid semver in database for crate {crate_id}: {}", |
| 384 | + row.version |
| 385 | + ) |
| 386 | + }) { |
| 387 | + Ok(semver) => semver, |
| 388 | + Err(err) => { |
| 389 | + report_error(&err); |
| 390 | + return Ok(None); |
| 391 | + } |
| 392 | + }; |
| 393 | + |
| 394 | + Ok(Some(Release { |
| 395 | + id: row.id, |
| 396 | + version: semversion, |
| 397 | + build_status: row |
| 398 | + .build_status |
| 399 | + .map(|build_status| { |
| 400 | + if build_status.contains(&BuildStatus::Success) { |
| 401 | + BuildStatus::Success |
| 402 | + } else if build_status.contains(&BuildStatus::Failure) { |
| 403 | + BuildStatus::Failure |
| 404 | + } else if build_status |
| 405 | + .iter() |
| 406 | + .all(|status| *status == BuildStatus::InProgress) |
| 407 | + { |
| 408 | + BuildStatus::InProgress |
| 409 | + } else { |
| 410 | + unreachable!() |
| 411 | + } |
| 412 | + }) |
| 413 | + .unwrap_or(BuildStatus::InProgress), |
| 414 | + yanked: row.yanked, |
| 415 | + is_library: row.is_library, |
| 416 | + rustdoc_status: row.rustdoc_status, |
| 417 | + target_name: row.target_name, |
| 418 | + })) |
395 | 419 | })
|
396 | 420 | .try_collect()
|
397 | 421 | .await?;
|
|
0 commit comments