From 066aa378ae9f99d360886ff352bd0e5a47394e69 Mon Sep 17 00:00:00 2001
From: Denis Cornehl <denis@cornehl.org>
Date: Wed, 21 Feb 2024 16:51:47 +0100
Subject: [PATCH] introduce aggregated build status on release & start using it

---
 ...695c7a88206171881f2d9951eb2f40125b244.json |  28 ---
 ...10ecf32505d1dad95e7d05bc310e9deb47411.json |  32 ---
 ...781ea30207795b833c4951f3c8303c49e699e.json |  12 +
 ...4741c42f9476ed8573511fe141883b86482d.json} |   8 +-
 ...7087ffc214cdaf08feb7bd25fa2b3ec7618b0.json |  22 ++
 ...76af53e2e45f860edd6b2bb42ed5b45ae4efa.json |  34 +++
 ...015344ee7f1d6add8cdeb3b71aee4dfd95eba.json |  32 +++
 ...f63660684cdb61af270631fe29dfca2ed466c.json |  71 ------
 ...958d5cee193e28ec6532bc1b1fbb98cfc3f16.json |  69 ++++++
 ...f892efba0a451bb14fff77876ca250b0fab1.json} |   6 +-
 ...309082057_release_status_view.sql.down.sql |   1 +
 ...40309082057_release_status_view.sql.up.sql |  22 ++
 src/db/add_package.rs                         |  23 +-
 src/db/types.rs                               |  25 ++
 src/web/crate_details.rs                      | 231 ++++++++++++++----
 src/web/releases.rs                           |  28 +--
 src/web/rustdoc.rs                            |   4 +-
 17 files changed, 448 insertions(+), 200 deletions(-)
 delete mode 100644 .sqlx/query-0f51891df12ccdbecbdffef1588695c7a88206171881f2d9951eb2f40125b244.json
 delete mode 100644 .sqlx/query-1379f2cb71474de2ce28373283210ecf32505d1dad95e7d05bc310e9deb47411.json
 create mode 100644 .sqlx/query-192d91c85fff00d311fa28dd7f5781ea30207795b833c4951f3c8303c49e699e.json
 rename .sqlx/{query-19123a7751cdf06658d0341289fb4d63bacdfb30ea9addededd2a55fb5638ad7.json => query-2e8ab3494453908d26decae9f9f64741c42f9476ed8573511fe141883b86482d.json} (63%)
 create mode 100644 .sqlx/query-42b5d5684d3813768048b4770997087ffc214cdaf08feb7bd25fa2b3ec7618b0.json
 create mode 100644 .sqlx/query-5ecd90db215d7bf3178869a320176af53e2e45f860edd6b2bb42ed5b45ae4efa.json
 create mode 100644 .sqlx/query-b823051d59855fc332ad37ecbcd015344ee7f1d6add8cdeb3b71aee4dfd95eba.json
 delete mode 100644 .sqlx/query-d672be5ae066efe9678be495580f63660684cdb61af270631fe29dfca2ed466c.json
 create mode 100644 .sqlx/query-d896b69c6f6061b0652862e2baa958d5cee193e28ec6532bc1b1fbb98cfc3f16.json
 rename .sqlx/{query-9a6a50ddbc1d07ef5648726f135eeca83ec922c4e9da07516b5f963b3551f4ee.json => query-e8f8c3649576bcba99393a2e78c9f892efba0a451bb14fff77876ca250b0fab1.json} (66%)
 create mode 100644 migrations/20240309082057_release_status_view.sql.down.sql
 create mode 100644 migrations/20240309082057_release_status_view.sql.up.sql

diff --git a/.sqlx/query-0f51891df12ccdbecbdffef1588695c7a88206171881f2d9951eb2f40125b244.json b/.sqlx/query-0f51891df12ccdbecbdffef1588695c7a88206171881f2d9951eb2f40125b244.json
deleted file mode 100644
index f7341988f..000000000
--- a/.sqlx/query-0f51891df12ccdbecbdffef1588695c7a88206171881f2d9951eb2f40125b244.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
-  "db_name": "PostgreSQL",
-  "query": "SELECT\n                 target_name,\n                 rustdoc_status\n             FROM releases\n             WHERE releases.id = $1",
-  "describe": {
-    "columns": [
-      {
-        "ordinal": 0,
-        "name": "target_name",
-        "type_info": "Varchar"
-      },
-      {
-        "ordinal": 1,
-        "name": "rustdoc_status",
-        "type_info": "Bool"
-      }
-    ],
-    "parameters": {
-      "Left": [
-        "Int4"
-      ]
-    },
-    "nullable": [
-      false,
-      false
-    ]
-  },
-  "hash": "0f51891df12ccdbecbdffef1588695c7a88206171881f2d9951eb2f40125b244"
-}
diff --git a/.sqlx/query-1379f2cb71474de2ce28373283210ecf32505d1dad95e7d05bc310e9deb47411.json b/.sqlx/query-1379f2cb71474de2ce28373283210ecf32505d1dad95e7d05bc310e9deb47411.json
deleted file mode 100644
index f1fbb008c..000000000
--- a/.sqlx/query-1379f2cb71474de2ce28373283210ecf32505d1dad95e7d05bc310e9deb47411.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
-  "db_name": "PostgreSQL",
-  "query": "WITH dates AS (\n               -- we need this series so that days in the statistic that don't have any releases are included\n               SELECT generate_series(\n                       CURRENT_DATE - INTERVAL '30 days',\n                       CURRENT_DATE - INTERVAL '1 day',\n                       '1 day'::interval\n                   )::date AS date_\n           ),\n           release_stats AS (\n               SELECT\n                   release_time::date AS date_,\n                   COUNT(*) AS counts,\n                   SUM(CAST((\n                       is_library = TRUE AND (\n                           SELECT builds.build_status\n                           FROM builds\n                           WHERE builds.rid = releases.id\n                           ORDER BY builds.build_time DESC\n                           LIMIT 1\n                       ) != 'success'\n                   ) AS INT)) AS failures\n               FROM\n                   releases\n               WHERE\n                   release_time >= CURRENT_DATE - INTERVAL '30 days' AND\n                   release_time < CURRENT_DATE\n               GROUP BY\n                   release_time::date\n           )\n           SELECT\n               dates.date_ AS \"date!\",\n               COALESCE(rs.counts, 0) AS \"counts!\",\n               COALESCE(rs.failures, 0) AS \"failures!\"\n           FROM\n               dates\n               LEFT OUTER JOIN Release_stats AS rs ON dates.date_ = rs.date_\n\n               ORDER BY\n                   dates.date_\n        ",
-  "describe": {
-    "columns": [
-      {
-        "ordinal": 0,
-        "name": "date!",
-        "type_info": "Date"
-      },
-      {
-        "ordinal": 1,
-        "name": "counts!",
-        "type_info": "Int8"
-      },
-      {
-        "ordinal": 2,
-        "name": "failures!",
-        "type_info": "Int8"
-      }
-    ],
-    "parameters": {
-      "Left": []
-    },
-    "nullable": [
-      null,
-      null,
-      null
-    ]
-  },
-  "hash": "1379f2cb71474de2ce28373283210ecf32505d1dad95e7d05bc310e9deb47411"
-}
diff --git a/.sqlx/query-192d91c85fff00d311fa28dd7f5781ea30207795b833c4951f3c8303c49e699e.json b/.sqlx/query-192d91c85fff00d311fa28dd7f5781ea30207795b833c4951f3c8303c49e699e.json
new file mode 100644
index 000000000..1cb245393
--- /dev/null
+++ b/.sqlx/query-192d91c85fff00d311fa28dd7f5781ea30207795b833c4951f3c8303c49e699e.json
@@ -0,0 +1,12 @@
+{
+  "db_name": "PostgreSQL",
+  "query": "DELETE FROM builds",
+  "describe": {
+    "columns": [],
+    "parameters": {
+      "Left": []
+    },
+    "nullable": []
+  },
+  "hash": "192d91c85fff00d311fa28dd7f5781ea30207795b833c4951f3c8303c49e699e"
+}
diff --git a/.sqlx/query-19123a7751cdf06658d0341289fb4d63bacdfb30ea9addededd2a55fb5638ad7.json b/.sqlx/query-2e8ab3494453908d26decae9f9f64741c42f9476ed8573511fe141883b86482d.json
similarity index 63%
rename from .sqlx/query-19123a7751cdf06658d0341289fb4d63bacdfb30ea9addededd2a55fb5638ad7.json
rename to .sqlx/query-2e8ab3494453908d26decae9f9f64741c42f9476ed8573511fe141883b86482d.json
index 509731d88..201281b82 100644
--- a/.sqlx/query-19123a7751cdf06658d0341289fb4d63bacdfb30ea9addededd2a55fb5638ad7.json
+++ b/.sqlx/query-2e8ab3494453908d26decae9f9f64741c42f9476ed8573511fe141883b86482d.json
@@ -1,6 +1,6 @@
 {
   "db_name": "PostgreSQL",
-  "query": "SELECT\n                crates.id AS crate_id,\n                releases.id AS release_id,\n                crates.name,\n                releases.version,\n                releases.description,\n                releases.dependencies,\n                releases.readme,\n                releases.description_long,\n                releases.release_time,\n                COALESCE(builds.build_status, 'failure') as \"build_status!: BuildStatus\",\n                (\n                    SELECT id\n                    FROM builds\n                    WHERE\n                        builds.rid = releases.id AND\n                        builds.build_status = 'success'\n                    ORDER BY build_time DESC\n                    LIMIT 1\n                ) AS latest_build_id,\n                releases.rustdoc_status,\n                releases.archive_storage,\n                releases.repository_url,\n                releases.homepage_url,\n                releases.keywords,\n                releases.have_examples,\n                releases.target_name,\n                repositories.host as \"repo_host?\",\n                repositories.stars as \"repo_stars?\",\n                repositories.forks as \"repo_forks?\",\n                repositories.issues as \"repo_issues?\",\n                repositories.name as \"repo_name?\",\n                releases.is_library,\n                releases.yanked,\n                releases.doc_targets,\n                releases.license,\n                releases.documentation_url,\n                releases.default_target,\n                builds.rustc_version as \"rustc_version?\",\n                doc_coverage.total_items,\n                doc_coverage.documented_items,\n                doc_coverage.total_items_needing_examples,\n                doc_coverage.items_with_examples\n            FROM releases\n            INNER JOIN crates ON releases.crate_id = crates.id\n            LEFT JOIN doc_coverage ON doc_coverage.release_id = releases.id\n            LEFT JOIN repositories ON releases.repository_id = repositories.id\n            LEFT JOIN LATERAL (\n                SELECT * FROM builds\n                WHERE builds.rid = releases.id\n                ORDER BY builds.build_time\n                DESC LIMIT 1\n            ) AS builds ON true\n            WHERE crates.name = $1 AND releases.version = $2;",
+  "query": "SELECT\n                crates.id AS crate_id,\n                releases.id AS release_id,\n                crates.name,\n                releases.version,\n                releases.description,\n                releases.dependencies,\n                releases.readme,\n                releases.description_long,\n                releases.release_time,\n                release_build_status.build_status as \"build_status!: BuildStatus\",\n                (\n                    -- this is the latest build ID that generated content\n                    -- it's used to invalidate some blob storage related caches.\n                    SELECT id\n                    FROM builds\n                    WHERE\n                        builds.rid = releases.id AND\n                        builds.build_status = 'success'\n                    ORDER BY build_time DESC\n                    LIMIT 1\n                ) AS latest_build_id,\n                releases.rustdoc_status,\n                releases.archive_storage,\n                releases.repository_url,\n                releases.homepage_url,\n                releases.keywords,\n                releases.have_examples,\n                releases.target_name,\n                repositories.host as \"repo_host?\",\n                repositories.stars as \"repo_stars?\",\n                repositories.forks as \"repo_forks?\",\n                repositories.issues as \"repo_issues?\",\n                repositories.name as \"repo_name?\",\n                releases.is_library,\n                releases.yanked,\n                releases.doc_targets,\n                releases.license,\n                releases.documentation_url,\n                releases.default_target,\n                (\n                    -- we're using the rustc version here to set the correct CSS file\n                    -- in the metadata.\n                    -- So we're only interested in successful builds here.\n                    SELECT rustc_version\n                    FROM builds\n                    WHERE\n                        builds.rid = releases.id AND\n                        builds.build_status = 'success'\n                    ORDER BY builds.build_time\n                    DESC LIMIT 1\n                ) as \"rustc_version?\",\n                doc_coverage.total_items,\n                doc_coverage.documented_items,\n                doc_coverage.total_items_needing_examples,\n                doc_coverage.items_with_examples\n            FROM releases\n            INNER JOIN release_build_status ON releases.id = release_build_status.id\n            INNER JOIN crates ON releases.crate_id = crates.id\n            LEFT JOIN doc_coverage ON doc_coverage.release_id = releases.id\n            LEFT JOIN repositories ON releases.repository_id = repositories.id\n            WHERE crates.name = $1 AND releases.version = $2;",
   "describe": {
     "columns": [
       {
@@ -201,7 +201,7 @@
       true,
       true,
       false,
-      null,
+      true,
       null,
       false,
       false,
@@ -221,12 +221,12 @@
       true,
       true,
       false,
-      false,
+      null,
       true,
       true,
       true,
       true
     ]
   },
-  "hash": "19123a7751cdf06658d0341289fb4d63bacdfb30ea9addededd2a55fb5638ad7"
+  "hash": "2e8ab3494453908d26decae9f9f64741c42f9476ed8573511fe141883b86482d"
 }
diff --git a/.sqlx/query-42b5d5684d3813768048b4770997087ffc214cdaf08feb7bd25fa2b3ec7618b0.json b/.sqlx/query-42b5d5684d3813768048b4770997087ffc214cdaf08feb7bd25fa2b3ec7618b0.json
new file mode 100644
index 000000000..552902659
--- /dev/null
+++ b/.sqlx/query-42b5d5684d3813768048b4770997087ffc214cdaf08feb7bd25fa2b3ec7618b0.json
@@ -0,0 +1,22 @@
+{
+  "db_name": "PostgreSQL",
+  "query": "SELECT crate_id\n         FROM releases\n         WHERE id = $1",
+  "describe": {
+    "columns": [
+      {
+        "ordinal": 0,
+        "name": "crate_id",
+        "type_info": "Int4"
+      }
+    ],
+    "parameters": {
+      "Left": [
+        "Int4"
+      ]
+    },
+    "nullable": [
+      false
+    ]
+  },
+  "hash": "42b5d5684d3813768048b4770997087ffc214cdaf08feb7bd25fa2b3ec7618b0"
+}
diff --git a/.sqlx/query-5ecd90db215d7bf3178869a320176af53e2e45f860edd6b2bb42ed5b45ae4efa.json b/.sqlx/query-5ecd90db215d7bf3178869a320176af53e2e45f860edd6b2bb42ed5b45ae4efa.json
new file mode 100644
index 000000000..3641dd849
--- /dev/null
+++ b/.sqlx/query-5ecd90db215d7bf3178869a320176af53e2e45f860edd6b2bb42ed5b45ae4efa.json
@@ -0,0 +1,34 @@
+{
+  "db_name": "PostgreSQL",
+  "query": "\n            SELECT build_status as \"build_status!: BuildStatus\"\n            FROM crates\n            INNER JOIN releases ON crates.id = releases.crate_id\n            INNER JOIN release_build_status ON releases.id = release_build_status.id\n            WHERE crates.name = $1 AND releases.version = $2",
+  "describe": {
+    "columns": [
+      {
+        "ordinal": 0,
+        "name": "build_status!: BuildStatus",
+        "type_info": {
+          "Custom": {
+            "name": "build_status",
+            "kind": {
+              "Enum": [
+                "in_progress",
+                "success",
+                "failure"
+              ]
+            }
+          }
+        }
+      }
+    ],
+    "parameters": {
+      "Left": [
+        "Text",
+        "Text"
+      ]
+    },
+    "nullable": [
+      true
+    ]
+  },
+  "hash": "5ecd90db215d7bf3178869a320176af53e2e45f860edd6b2bb42ed5b45ae4efa"
+}
diff --git a/.sqlx/query-b823051d59855fc332ad37ecbcd015344ee7f1d6add8cdeb3b71aee4dfd95eba.json b/.sqlx/query-b823051d59855fc332ad37ecbcd015344ee7f1d6add8cdeb3b71aee4dfd95eba.json
new file mode 100644
index 000000000..728b0b892
--- /dev/null
+++ b/.sqlx/query-b823051d59855fc332ad37ecbcd015344ee7f1d6add8cdeb3b71aee4dfd95eba.json
@@ -0,0 +1,32 @@
+{
+  "db_name": "PostgreSQL",
+  "query": "WITH dates AS (\n               -- we need this series so that days in the statistic that don't have any releases are included\n               SELECT generate_series(\n                       CURRENT_DATE - INTERVAL '30 days',\n                       CURRENT_DATE - INTERVAL '1 day',\n                       '1 day'::interval\n                   )::date AS date_\n           ),\n           release_stats AS (\n               SELECT\n                   release_time::date AS date_,\n                   SUM(CAST(\n                       release_build_status.build_status != 'in_progress' AS INT\n                   )) AS counts,\n                   SUM(CAST((\n                       is_library = TRUE AND\n                       release_build_status.build_status = 'failure'\n                   ) AS INT)) AS failures\n               FROM releases\n               INNER JOIN release_build_status ON releases.id = release_build_status.id\n\n               WHERE\n                   release_time >= CURRENT_DATE - INTERVAL '30 days' AND\n                   release_time < CURRENT_DATE\n               GROUP BY\n                   release_time::date\n           )\n           SELECT\n               dates.date_ AS \"date!\",\n               COALESCE(rs.counts, 0) AS \"counts!\",\n               COALESCE(rs.failures, 0) AS \"failures!\"\n           FROM\n               dates\n               LEFT OUTER JOIN Release_stats AS rs ON dates.date_ = rs.date_\n\n               ORDER BY\n                   dates.date_\n        ",
+  "describe": {
+    "columns": [
+      {
+        "ordinal": 0,
+        "name": "date!",
+        "type_info": "Date"
+      },
+      {
+        "ordinal": 1,
+        "name": "counts!",
+        "type_info": "Int8"
+      },
+      {
+        "ordinal": 2,
+        "name": "failures!",
+        "type_info": "Int8"
+      }
+    ],
+    "parameters": {
+      "Left": []
+    },
+    "nullable": [
+      null,
+      null,
+      null
+    ]
+  },
+  "hash": "b823051d59855fc332ad37ecbcd015344ee7f1d6add8cdeb3b71aee4dfd95eba"
+}
diff --git a/.sqlx/query-d672be5ae066efe9678be495580f63660684cdb61af270631fe29dfca2ed466c.json b/.sqlx/query-d672be5ae066efe9678be495580f63660684cdb61af270631fe29dfca2ed466c.json
deleted file mode 100644
index 5a4059bfb..000000000
--- a/.sqlx/query-d672be5ae066efe9678be495580f63660684cdb61af270631fe29dfca2ed466c.json
+++ /dev/null
@@ -1,71 +0,0 @@
-{
-  "db_name": "PostgreSQL",
-  "query": "INSERT INTO releases (\n            crate_id, version, release_time,\n            dependencies, target_name, yanked, build_status,\n            rustdoc_status, test_status, license, repository_url,\n            homepage_url, description, description_long, readme,\n            keywords, have_examples, downloads, files,\n            doc_targets, is_library, doc_rustc_version,\n            documentation_url, default_target, features,\n            repository_id, archive_storage\n         )\n         VALUES (\n            $1,  $2,  $3,  $4,  $5,  $6,  $7,  $8,  $9,\n            $10, $11, $12, $13, $14, $15, $16, $17, $18,\n            $19, $20, $21, $22, $23, $24, $25, $26, $27\n         )\n         ON CONFLICT (crate_id, version) DO UPDATE\n            SET release_time = $3,\n                dependencies = $4,\n                target_name = $5,\n                yanked = $6,\n                build_status = $7,\n                rustdoc_status = $8,\n                test_status = $9,\n                license = $10,\n                repository_url = $11,\n                homepage_url = $12,\n                description = $13,\n                description_long = $14,\n                readme = $15,\n                keywords = $16,\n                have_examples = $17,\n                downloads = $18,\n                files = $19,\n                doc_targets = $20,\n                is_library = $21,\n                doc_rustc_version = $22,\n                documentation_url = $23,\n                default_target = $24,\n                features = $25,\n                repository_id = $26,\n                archive_storage = $27\n         RETURNING id",
-  "describe": {
-    "columns": [
-      {
-        "ordinal": 0,
-        "name": "id",
-        "type_info": "Int4"
-      }
-    ],
-    "parameters": {
-      "Left": [
-        "Int4",
-        "Varchar",
-        "Timestamptz",
-        "Json",
-        "Varchar",
-        "Bool",
-        "Bool",
-        "Bool",
-        "Bool",
-        "Varchar",
-        "Varchar",
-        "Varchar",
-        "Varchar",
-        "Varchar",
-        "Varchar",
-        "Json",
-        "Bool",
-        "Int4",
-        "Json",
-        "Json",
-        "Bool",
-        "Varchar",
-        "Varchar",
-        "Varchar",
-        {
-          "Custom": {
-            "name": "_feature",
-            "kind": {
-              "Array": {
-                "Custom": {
-                  "name": "feature",
-                  "kind": {
-                    "Composite": [
-                      [
-                        "name",
-                        "Text"
-                      ],
-                      [
-                        "subfeatures",
-                        "TextArray"
-                      ]
-                    ]
-                  }
-                }
-              }
-            }
-          }
-        },
-        "Int4",
-        "Bool"
-      ]
-    },
-    "nullable": [
-      false
-    ]
-  },
-  "hash": "d672be5ae066efe9678be495580f63660684cdb61af270631fe29dfca2ed466c"
-}
diff --git a/.sqlx/query-d896b69c6f6061b0652862e2baa958d5cee193e28ec6532bc1b1fbb98cfc3f16.json b/.sqlx/query-d896b69c6f6061b0652862e2baa958d5cee193e28ec6532bc1b1fbb98cfc3f16.json
new file mode 100644
index 000000000..35d0d9706
--- /dev/null
+++ b/.sqlx/query-d896b69c6f6061b0652862e2baa958d5cee193e28ec6532bc1b1fbb98cfc3f16.json
@@ -0,0 +1,69 @@
+{
+  "db_name": "PostgreSQL",
+  "query": "INSERT INTO releases (\n            crate_id, version, release_time,\n            dependencies, target_name, yanked,\n            rustdoc_status, test_status, license, repository_url,\n            homepage_url, description, description_long, readme,\n            keywords, have_examples, downloads, files,\n            doc_targets, is_library,\n            documentation_url, default_target, features,\n            repository_id, archive_storage\n         )\n         VALUES (\n            $1,  $2,  $3,  $4,  $5,  $6,  $7,  $8,  $9,\n            $10, $11, $12, $13, $14, $15, $16, $17, $18,\n            $19, $20, $21, $22, $23, $24, $25\n         )\n         ON CONFLICT (crate_id, version) DO UPDATE\n            SET release_time = $3,\n                dependencies = $4,\n                target_name = $5,\n                yanked = $6,\n                rustdoc_status = $7,\n                test_status = $8,\n                license = $9,\n                repository_url = $10,\n                homepage_url = $11,\n                description = $12,\n                description_long = $13,\n                readme = $14,\n                keywords = $15,\n                have_examples = $16,\n                downloads = $17,\n                files = $18,\n                doc_targets = $19,\n                is_library = $20,\n                documentation_url = $21,\n                default_target = $22,\n                features = $23,\n                repository_id = $24,\n                archive_storage = $25\n         RETURNING id",
+  "describe": {
+    "columns": [
+      {
+        "ordinal": 0,
+        "name": "id",
+        "type_info": "Int4"
+      }
+    ],
+    "parameters": {
+      "Left": [
+        "Int4",
+        "Varchar",
+        "Timestamptz",
+        "Json",
+        "Varchar",
+        "Bool",
+        "Bool",
+        "Bool",
+        "Varchar",
+        "Varchar",
+        "Varchar",
+        "Varchar",
+        "Varchar",
+        "Varchar",
+        "Json",
+        "Bool",
+        "Int4",
+        "Json",
+        "Json",
+        "Bool",
+        "Varchar",
+        "Varchar",
+        {
+          "Custom": {
+            "name": "_feature",
+            "kind": {
+              "Array": {
+                "Custom": {
+                  "name": "feature",
+                  "kind": {
+                    "Composite": [
+                      [
+                        "name",
+                        "Text"
+                      ],
+                      [
+                        "subfeatures",
+                        "TextArray"
+                      ]
+                    ]
+                  }
+                }
+              }
+            }
+          }
+        },
+        "Int4",
+        "Bool"
+      ]
+    },
+    "nullable": [
+      false
+    ]
+  },
+  "hash": "d896b69c6f6061b0652862e2baa958d5cee193e28ec6532bc1b1fbb98cfc3f16"
+}
diff --git a/.sqlx/query-9a6a50ddbc1d07ef5648726f135eeca83ec922c4e9da07516b5f963b3551f4ee.json b/.sqlx/query-e8f8c3649576bcba99393a2e78c9f892efba0a451bb14fff77876ca250b0fab1.json
similarity index 66%
rename from .sqlx/query-9a6a50ddbc1d07ef5648726f135eeca83ec922c4e9da07516b5f963b3551f4ee.json
rename to .sqlx/query-e8f8c3649576bcba99393a2e78c9f892efba0a451bb14fff77876ca250b0fab1.json
index 6f2eaf532..319634d31 100644
--- a/.sqlx/query-9a6a50ddbc1d07ef5648726f135eeca83ec922c4e9da07516b5f963b3551f4ee.json
+++ b/.sqlx/query-e8f8c3649576bcba99393a2e78c9f892efba0a451bb14fff77876ca250b0fab1.json
@@ -1,6 +1,6 @@
 {
   "db_name": "PostgreSQL",
-  "query": "SELECT\n             releases.id,\n             releases.version,\n             COALESCE(builds.build_status, 'failure') as \"build_status!: BuildStatus\",\n             releases.yanked,\n             releases.is_library,\n             releases.rustdoc_status,\n             releases.target_name\n         FROM releases\n         LEFT JOIN LATERAL (\n            SELECT build_status FROM builds\n            WHERE builds.rid = releases.id\n            ORDER BY builds.build_time\n            DESC LIMIT 1\n         ) AS builds ON true\n         WHERE\n             releases.crate_id = $1",
+  "query": "SELECT\n             releases.id,\n             releases.version,\n             release_build_status.build_status as \"build_status!: BuildStatus\",\n             releases.yanked,\n             releases.is_library,\n             releases.rustdoc_status,\n             releases.target_name\n         FROM releases\n         INNER JOIN release_build_status ON releases.id = release_build_status.id\n         WHERE\n             releases.crate_id = $1",
   "describe": {
     "columns": [
       {
@@ -58,12 +58,12 @@
     "nullable": [
       false,
       false,
-      null,
+      true,
       false,
       false,
       false,
       false
     ]
   },
-  "hash": "9a6a50ddbc1d07ef5648726f135eeca83ec922c4e9da07516b5f963b3551f4ee"
+  "hash": "e8f8c3649576bcba99393a2e78c9f892efba0a451bb14fff77876ca250b0fab1"
 }
diff --git a/migrations/20240309082057_release_status_view.sql.down.sql b/migrations/20240309082057_release_status_view.sql.down.sql
new file mode 100644
index 000000000..ff27e9eef
--- /dev/null
+++ b/migrations/20240309082057_release_status_view.sql.down.sql
@@ -0,0 +1 @@
+DROP VIEW release_build_status;
diff --git a/migrations/20240309082057_release_status_view.sql.up.sql b/migrations/20240309082057_release_status_view.sql.up.sql
new file mode 100644
index 000000000..ac2ceb025
--- /dev/null
+++ b/migrations/20240309082057_release_status_view.sql.up.sql
@@ -0,0 +1,22 @@
+CREATE OR REPLACE VIEW release_build_status AS (
+  SELECT 
+    summary.id,
+    summary.last_build_time,
+    CASE 
+      WHEN summary.success_count > 0 THEN 'success'::build_status
+      WHEN summary.failure_count > 0 THEN 'failure'::build_status
+      ELSE 'in_progress'::build_status
+    END as build_status
+      
+  FROM (
+    SELECT
+      r.id,
+      MAX(b.build_time) as last_build_time,
+      SUM(CASE WHEN b.build_status = 'success' THEN 1 ELSE 0 END) as success_count,
+      SUM(CASE WHEN b.build_status = 'failure' THEN 1 ELSE 0 END) as failure_count
+    FROM 
+      releases as r
+      LEFT OUTER JOIN builds AS b on b.rid = r.id 
+    GROUP BY r.id
+  ) as summary
+);
diff --git a/src/db/add_package.rs b/src/db/add_package.rs
index 03a860cbe..6fcfaaacf 100644
--- a/src/db/add_package.rs
+++ b/src/db/add_package.rs
@@ -144,6 +144,17 @@ pub async fn update_latest_version_id(conn: &mut sqlx::PgConnection, crate_id: i
     Ok(())
 }
 
+async fn crate_id_from_release_id(conn: &mut sqlx::PgConnection, release_id: i32) -> Result<i32> {
+    Ok(sqlx::query_scalar!(
+        "SELECT crate_id
+         FROM releases
+         WHERE id = $1",
+        release_id,
+    )
+    .fetch_one(&mut *conn)
+    .await?)
+}
+
 pub(crate) async fn add_doc_coverage(
     conn: &mut sqlx::PgConnection,
     release_id: i32,
@@ -183,7 +194,8 @@ pub(crate) async fn add_build_into_database(
 ) -> Result<i32> {
     debug!("Adding build into database");
     let hostname = hostname::get()?;
-    Ok(sqlx::query_scalar!(
+
+    let build_id = sqlx::query_scalar!(
         "INSERT INTO builds (rid, rustc_version, docsrs_version, build_status, build_server)
         VALUES ($1, $2, $3, $4, $5)
         RETURNING id",
@@ -194,7 +206,14 @@ pub(crate) async fn add_build_into_database(
         hostname.to_str().unwrap_or(""),
     )
     .fetch_one(&mut *conn)
-    .await?)
+    .await?;
+
+    let crate_id = crate_id_from_release_id(&mut *conn, release_id).await?;
+    update_latest_version_id(&mut *conn, crate_id)
+        .await
+        .context("couldn't update latest version id")?;
+
+    Ok(build_id)
 }
 
 async fn initialize_package_in_database(
diff --git a/src/db/types.rs b/src/db/types.rs
index ddf89d79f..17140c595 100644
--- a/src/db/types.rs
+++ b/src/db/types.rs
@@ -26,6 +26,7 @@ impl sqlx::postgres::PgHasArrayType for Feature {
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, sqlx::Type)]
 #[sqlx(type_name = "build_status", rename_all = "snake_case")]
+#[serde(rename_all = "snake_case")]
 pub(crate) enum BuildStatus {
     Success,
     Failure,
@@ -37,3 +38,27 @@ impl BuildStatus {
         matches!(self, BuildStatus::Success)
     }
 }
+
+impl sqlx::postgres::PgHasArrayType for BuildStatus {
+    fn array_type_info() -> sqlx::postgres::PgTypeInfo {
+        sqlx::postgres::PgTypeInfo::with_name("_build_status")
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use test_case::test_case;
+
+    #[test_case(BuildStatus::Success, "success")]
+    #[test_case(BuildStatus::Failure, "failure")]
+    #[test_case(BuildStatus::InProgress, "in_progress")]
+    fn test_build_status_serialization(status: BuildStatus, expected: &str) {
+        let serialized = serde_json::to_string(&status).unwrap();
+        assert_eq!(serialized, format!("\"{}\"", expected));
+        assert_eq!(
+            serde_json::from_str::<BuildStatus>(&serialized).unwrap(),
+            status
+        );
+    }
+}
diff --git a/src/web/crate_details.rs b/src/web/crate_details.rs
index babe3ebad..7e896a01e 100644
--- a/src/web/crate_details.rs
+++ b/src/web/crate_details.rs
@@ -90,6 +90,17 @@ where
 pub(crate) struct Release {
     pub id: i32,
     pub version: semver::Version,
+    /// Aggregated build status of the release.
+    /// * no builds -> build In progress
+    /// * any build is successful -> Success
+    ///   -> even with failed or in-progress builds we have docs to show
+    /// * any build is failed -> Failure
+    ///   -> we can only have Failure or InProgress here, so the Failure is the
+    ///      important part on this aggregation level.
+    /// * the rest is all builds are in-progress -> InProgress
+    ///   -> if we have any builds, and the previous conditions don't match, we end
+    ///      up here, but we still check.
+    /// calculated in a database view : `release_build_status`
     pub build_status: BuildStatus,
     pub yanked: bool,
     pub is_library: bool,
@@ -132,8 +143,10 @@ impl CrateDetails {
                 releases.readme,
                 releases.description_long,
                 releases.release_time,
-                COALESCE(builds.build_status, 'failure') as "build_status!: BuildStatus",
+                release_build_status.build_status as "build_status!: BuildStatus",
                 (
+                    -- this is the latest build ID that generated content
+                    -- it's used to invalidate some blob storage related caches.
                     SELECT id
                     FROM builds
                     WHERE
@@ -160,21 +173,27 @@ impl CrateDetails {
                 releases.license,
                 releases.documentation_url,
                 releases.default_target,
-                builds.rustc_version as "rustc_version?",
+                (
+                    -- we're using the rustc version here to set the correct CSS file
+                    -- in the metadata.
+                    -- So we're only interested in successful builds here.
+                    SELECT rustc_version
+                    FROM builds
+                    WHERE
+                        builds.rid = releases.id AND
+                        builds.build_status = 'success'
+                    ORDER BY builds.build_time
+                    DESC LIMIT 1
+                ) as "rustc_version?",
                 doc_coverage.total_items,
                 doc_coverage.documented_items,
                 doc_coverage.total_items_needing_examples,
                 doc_coverage.items_with_examples
             FROM releases
+            INNER JOIN release_build_status ON releases.id = release_build_status.id
             INNER JOIN crates ON releases.crate_id = crates.id
             LEFT JOIN doc_coverage ON doc_coverage.release_id = releases.id
             LEFT JOIN repositories ON releases.repository_id = repositories.id
-            LEFT JOIN LATERAL (
-                SELECT * FROM builds
-                WHERE builds.rid = releases.id
-                ORDER BY builds.build_time
-                DESC LIMIT 1
-            ) AS builds ON true
             WHERE crates.name = $1 AND releases.version = $2;"#,
             name,
             version.to_string(),
@@ -333,13 +352,16 @@ impl CrateDetails {
 }
 
 pub(crate) fn latest_release(releases: &[Release]) -> Option<&Release> {
-    if let Some(release) = releases
-        .iter()
-        .find(|release| release.version.pre.is_empty() && !release.yanked)
-    {
+    if let Some(release) = releases.iter().find(|release| {
+        release.version.pre.is_empty()
+            && !release.yanked
+            && release.build_status != BuildStatus::InProgress
+    }) {
         Some(release)
     } else {
-        releases.first()
+        releases
+            .iter()
+            .find(|release| release.build_status != BuildStatus::InProgress)
     }
 }
 
@@ -352,46 +374,41 @@ pub(crate) async fn releases_for_crate(
         r#"SELECT
              releases.id,
              releases.version,
-             COALESCE(builds.build_status, 'failure') as "build_status!: BuildStatus",
+             release_build_status.build_status as "build_status!: BuildStatus",
              releases.yanked,
              releases.is_library,
              releases.rustdoc_status,
              releases.target_name
          FROM releases
-         LEFT JOIN LATERAL (
-            SELECT build_status FROM builds
-            WHERE builds.rid = releases.id
-            ORDER BY builds.build_time
-            DESC LIMIT 1
-         ) AS builds ON true
+         INNER JOIN release_build_status ON releases.id = release_build_status.id
          WHERE
              releases.crate_id = $1"#,
         crate_id,
     )
     .fetch(&mut *conn)
     .try_filter_map(|row| async move {
-        Ok(
-            match semver::Version::parse(&row.version).with_context(|| {
-                format!(
-                    "invalid semver in database for crate {crate_id}: {}",
-                    row.version
-                )
-            }) {
-                Ok(semversion) => Some(Release {
-                    id: row.id,
-                    version: semversion,
-                    build_status: row.build_status,
-                    yanked: row.yanked,
-                    is_library: row.is_library,
-                    rustdoc_status: row.rustdoc_status,
-                    target_name: row.target_name,
-                }),
-                Err(err) => {
-                    report_error(&err);
-                    None
-                }
-            },
-        )
+        let semversion = match semver::Version::parse(&row.version).with_context(|| {
+            format!(
+                "invalid semver in database for crate {crate_id}: {}",
+                row.version
+            )
+        }) {
+            Ok(semver) => semver,
+            Err(err) => {
+                report_error(&err);
+                return Ok(None);
+            }
+        };
+
+        Ok(Some(Release {
+            id: row.id,
+            version: semversion,
+            build_status: row.build_status,
+            yanked: row.yanked,
+            is_library: row.is_library,
+            rustdoc_status: row.rustdoc_status,
+            target_name: row.target_name,
+        }))
     })
     .try_collect()
     .await?;
@@ -691,17 +708,46 @@ pub(crate) async fn get_all_platforms(
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::registry_api::CrateOwner;
     use crate::test::{
         assert_cache_control, assert_redirect, assert_redirect_cached, async_wrapper, wrapper,
         FakeBuild, TestDatabase, TestEnvironment,
     };
+    use crate::{db::types::BuildStatus, registry_api::CrateOwner};
     use anyhow::Error;
     use kuchikiki::traits::TendrilSink;
     use reqwest::StatusCode;
     use semver::Version;
     use std::collections::HashMap;
 
+    async fn release_build_status(
+        conn: &mut sqlx::PgConnection,
+        name: &str,
+        version: &str,
+    ) -> BuildStatus {
+        let status = sqlx::query_scalar!(
+            r#"
+            SELECT build_status as "build_status!: BuildStatus"
+            FROM crates
+            INNER JOIN releases ON crates.id = releases.crate_id
+            INNER JOIN release_build_status ON releases.id = release_build_status.id
+            WHERE crates.name = $1 AND releases.version = $2"#,
+            name,
+            version
+        )
+        .fetch_one(&mut *conn)
+        .await
+        .unwrap();
+
+        assert_eq!(
+            crate_details(&mut *conn, name, version, None)
+                .await
+                .build_status,
+            status
+        );
+
+        status
+    }
+
     async fn crate_details(
         conn: &mut sqlx::PgConnection,
         name: &str,
@@ -1767,4 +1813,103 @@ mod tests {
             Ok(())
         })
     }
+
+    #[test]
+    fn test_build_status_no_builds() {
+        async_wrapper(|env| async move {
+            env.async_fake_release()
+                .await
+                .name("dummy")
+                .version("0.1.0")
+                .create_async()
+                .await?;
+
+            let mut conn = env.async_db().await.async_conn().await;
+            sqlx::query!("DELETE FROM builds")
+                .execute(&mut *conn)
+                .await?;
+
+            assert_eq!(
+                release_build_status(&mut conn, "dummy", "0.1.0").await,
+                BuildStatus::InProgress
+            );
+
+            Ok(())
+        })
+    }
+
+    #[test]
+    fn test_build_status_successful() {
+        async_wrapper(|env| async move {
+            env.async_fake_release()
+                .await
+                .name("dummy")
+                .version("0.1.0")
+                .builds(vec![
+                    FakeBuild::default().build_status(BuildStatus::Success),
+                    FakeBuild::default().build_status(BuildStatus::Failure),
+                    FakeBuild::default().build_status(BuildStatus::InProgress),
+                ])
+                .create_async()
+                .await?;
+
+            let mut conn = env.async_db().await.async_conn().await;
+
+            assert_eq!(
+                release_build_status(&mut conn, "dummy", "0.1.0").await,
+                BuildStatus::Success
+            );
+
+            Ok(())
+        })
+    }
+
+    #[test]
+    fn test_build_status_failed() {
+        async_wrapper(|env| async move {
+            env.async_fake_release()
+                .await
+                .name("dummy")
+                .version("0.1.0")
+                .builds(vec![
+                    FakeBuild::default().build_status(BuildStatus::Failure),
+                    FakeBuild::default().build_status(BuildStatus::InProgress),
+                ])
+                .create_async()
+                .await?;
+
+            let mut conn = env.async_db().await.async_conn().await;
+
+            assert_eq!(
+                release_build_status(&mut conn, "dummy", "0.1.0").await,
+                BuildStatus::Failure
+            );
+
+            Ok(())
+        })
+    }
+
+    #[test]
+    fn test_build_status_in_progress() {
+        async_wrapper(|env| async move {
+            env.async_fake_release()
+                .await
+                .name("dummy")
+                .version("0.1.0")
+                .builds(vec![
+                    FakeBuild::default().build_status(BuildStatus::InProgress)
+                ])
+                .create_async()
+                .await?;
+
+            let mut conn = env.async_db().await.async_conn().await;
+
+            assert_eq!(
+                release_build_status(&mut conn, "dummy", "0.1.0").await,
+                BuildStatus::InProgress
+            );
+
+            Ok(())
+        })
+    }
 }
diff --git a/src/web/releases.rs b/src/web/releases.rs
index 139e2ecf6..36f179e2e 100644
--- a/src/web/releases.rs
+++ b/src/web/releases.rs
@@ -77,9 +77,9 @@ pub(crate) async fn get_releases(
 
     // WARNING: it is _crucial_ that this always be hard-coded and NEVER be user input
     let (ordering, filter_failed): (&'static str, _) = match order {
-        Order::ReleaseTime => ("builds.build_time", false),
+        Order::ReleaseTime => ("release_build_status.last_build_time", false),
         Order::GithubStars => ("repositories.stars", false),
-        Order::RecentFailures => ("builds.build_time", true),
+        Order::RecentFailures => ("release_build_status.last_build_time", true),
         Order::FailuresByGithubStars => ("repositories.stars", true),
     };
 
@@ -89,14 +89,14 @@ pub(crate) async fn get_releases(
             releases.description,
             releases.target_name,
             releases.rustdoc_status,
-            builds.build_time,
+            release_build_status.last_build_time AS build_time,
             repositories.stars
         FROM crates
         {1}
-        INNER JOIN builds ON releases.id = builds.rid
+        INNER JOIN release_build_status ON releases.id = release_build_status.id
         LEFT JOIN repositories ON releases.repository_id = repositories.id
         WHERE
-            ((NOT $3) OR (builds.build_status != 'success' AND releases.is_library = TRUE))
+            ((NOT $3) OR (release_build_status.build_status = 'failure' AND releases.is_library = TRUE))
             AND {0} IS NOT NULL
 
         ORDER BY {0} DESC
@@ -686,18 +686,16 @@ pub(crate) async fn activity_handler(mut conn: DbConnection) -> AxumResult<impl
            release_stats AS (
                SELECT
                    release_time::date AS date_,
-                   COUNT(*) AS counts,
+                   SUM(CAST(
+                       release_build_status.build_status != 'in_progress' AS INT
+                   )) AS counts,
                    SUM(CAST((
-                       is_library = TRUE AND (
-                           SELECT builds.build_status
-                           FROM builds
-                           WHERE builds.rid = releases.id
-                           ORDER BY builds.build_time DESC
-                           LIMIT 1
-                       ) != 'success'
+                       is_library = TRUE AND
+                       release_build_status.build_status = 'failure'
                    ) AS INT)) AS failures
-               FROM
-                   releases
+               FROM releases
+               INNER JOIN release_build_status ON releases.id = release_build_status.id
+
                WHERE
                    release_time >= CURRENT_DATE - INTERVAL '30 days' AND
                    release_time < CURRENT_DATE
diff --git a/src/web/rustdoc.rs b/src/web/rustdoc.rs
index 2a9d6e44e..56a0986e5 100644
--- a/src/web/rustdoc.rs
+++ b/src/web/rustdoc.rs
@@ -1,7 +1,7 @@
 //! rustdoc handler
 
 use crate::{
-    db::{types::BuildStatus, Pool},
+    db::Pool,
     storage::rustdoc_archive_path,
     utils,
     web::{
@@ -550,7 +550,7 @@ pub(crate) async fn rustdoc_html_server_handler(
 
     // Find the path of the latest version for the `Go to latest` and `Permalink` links
     let mut current_target = String::new();
-    let target_redirect = if latest_release.build_status == BuildStatus::Success {
+    let target_redirect = if latest_release.build_status.is_success() {
         let target = if target.is_empty() {
             current_target = krate.metadata.default_target.clone();
             &krate.metadata.default_target