Use anyhow more idiomatically (#31052)

https://github.com/zed-industries/zed/issues/30972 brought up another
case where our context is not enough to track the actual source of the
issue: we get a general top-level error without inner error.

The reason for this was `.ok_or_else(|| anyhow!("failed to read HEAD
SHA"))?; ` on the top level.

The PR finally reworks the way we use anyhow to reduce such issues (or
at least make it simpler to bubble them up later in a fix).
On top of that, uses a few more anyhow methods for better readability.

* `.ok_or_else(|| anyhow!("..."))`, `map_err` and other similar error
conversion/option reporting cases are replaced with `context` and
`with_context` calls
* in addition to that, various `anyhow!("failed to do ...")` are
stripped with `.context("Doing ...")` messages instead to remove the
parasitic `failed to` text
* `anyhow::ensure!` is used instead of `if ... { return Err(...); }`
calls
* `anyhow::bail!` is used instead of `return Err(anyhow!(...));`

Release Notes:

- N/A
This commit is contained in:
Kirill Bulatov 2025-05-21 02:06:07 +03:00 committed by GitHub
parent 1e51a7ac44
commit 16366cf9f2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
294 changed files with 2037 additions and 2610 deletions

View file

@ -1,4 +1,4 @@
use anyhow::{Context, anyhow, bail};
use anyhow::{Context as _, bail};
use axum::{
Extension, Json, Router,
extract::{self, Query},
@ -89,7 +89,7 @@ async fn get_billing_preferences(
.db
.get_user_by_github_user_id(params.github_user_id)
.await?
.ok_or_else(|| anyhow!("user not found"))?;
.context("user not found")?;
let billing_customer = app.db.get_billing_customer_by_user_id(user.id).await?;
let preferences = app.db.get_billing_preferences(user.id).await?;
@ -138,7 +138,7 @@ async fn update_billing_preferences(
.db
.get_user_by_github_user_id(body.github_user_id)
.await?
.ok_or_else(|| anyhow!("user not found"))?;
.context("user not found")?;
let billing_customer = app.db.get_billing_customer_by_user_id(user.id).await?;
@ -241,7 +241,7 @@ async fn list_billing_subscriptions(
.db
.get_user_by_github_user_id(params.github_user_id)
.await?
.ok_or_else(|| anyhow!("user not found"))?;
.context("user not found")?;
let subscriptions = app.db.get_billing_subscriptions(user.id).await?;
@ -307,7 +307,7 @@ async fn create_billing_subscription(
.db
.get_user_by_github_user_id(body.github_user_id)
.await?
.ok_or_else(|| anyhow!("user not found"))?;
.context("user not found")?;
let Some(stripe_billing) = app.stripe_billing.clone() else {
log::error!("failed to retrieve Stripe billing object");
@ -432,7 +432,7 @@ async fn manage_billing_subscription(
.db
.get_user_by_github_user_id(body.github_user_id)
.await?
.ok_or_else(|| anyhow!("user not found"))?;
.context("user not found")?;
let Some(stripe_client) = app.stripe_client.clone() else {
log::error!("failed to retrieve Stripe client");
@ -454,7 +454,7 @@ async fn manage_billing_subscription(
.db
.get_billing_customer_by_user_id(user.id)
.await?
.ok_or_else(|| anyhow!("billing customer not found"))?;
.context("billing customer not found")?;
let customer_id = CustomerId::from_str(&customer.stripe_customer_id)
.context("failed to parse customer ID")?;
@ -462,7 +462,7 @@ async fn manage_billing_subscription(
.db
.get_billing_subscription_by_id(body.subscription_id)
.await?
.ok_or_else(|| anyhow!("subscription not found"))?;
.context("subscription not found")?;
let subscription_id = SubscriptionId::from_str(&subscription.stripe_subscription_id)
.context("failed to parse subscription ID")?;
@ -559,7 +559,7 @@ async fn manage_billing_subscription(
None
}
})
.ok_or_else(|| anyhow!("No subscription item to update"))?;
.context("No subscription item to update")?;
Some(CreateBillingPortalSessionFlowData {
type_: CreateBillingPortalSessionFlowDataType::SubscriptionUpdateConfirm,
@ -653,7 +653,7 @@ async fn migrate_to_new_billing(
.db
.get_user_by_github_user_id(body.github_user_id)
.await?
.ok_or_else(|| anyhow!("user not found"))?;
.context("user not found")?;
let old_billing_subscriptions_by_user = app
.db
@ -732,13 +732,13 @@ async fn sync_billing_subscription(
.db
.get_user_by_github_user_id(body.github_user_id)
.await?
.ok_or_else(|| anyhow!("user not found"))?;
.context("user not found")?;
let billing_customer = app
.db
.get_billing_customer_by_user_id(user.id)
.await?
.ok_or_else(|| anyhow!("billing customer not found"))?;
.context("billing customer not found")?;
let stripe_customer_id = billing_customer
.stripe_customer_id
.parse::<stripe::CustomerId>()
@ -1031,13 +1031,13 @@ async fn sync_subscription(
let billing_customer =
find_or_create_billing_customer(app, stripe_client, subscription.customer)
.await?
.ok_or_else(|| anyhow!("billing customer not found"))?;
.context("billing customer not found")?;
if let Some(SubscriptionKind::ZedProTrial) = subscription_kind {
if subscription.status == SubscriptionStatus::Trialing {
let current_period_start =
DateTime::from_timestamp(subscription.current_period_start, 0)
.ok_or_else(|| anyhow!("No trial subscription period start"))?;
.context("No trial subscription period start")?;
app.db
.update_billing_customer(
@ -1243,7 +1243,7 @@ async fn get_monthly_spend(
.db
.get_user_by_github_user_id(params.github_user_id)
.await?
.ok_or_else(|| anyhow!("user not found"))?;
.context("user not found")?;
let Some(llm_db) = app.llm_db.clone() else {
return Err(Error::http(
@ -1311,7 +1311,7 @@ async fn get_current_usage(
.db
.get_user_by_github_user_id(params.github_user_id)
.await?
.ok_or_else(|| anyhow!("user not found"))?;
.context("user not found")?;
let feature_flags = app.db.get_user_flags(user.id).await?;
let has_extended_trial = feature_flags

View file

@ -1,6 +1,5 @@
use std::sync::{Arc, OnceLock};
use anyhow::anyhow;
use axum::{
Extension, Json, Router,
extract::{self, Query},
@ -39,7 +38,7 @@ impl CheckIsContributorParams {
return Ok(ContributorSelector::GitHubLogin { github_login });
}
Err(anyhow!(
Err(anyhow::anyhow!(
"must be one of `github_user_id` or `github_login`."
))?
}

View file

@ -1,6 +1,6 @@
use crate::db::ExtensionVersionConstraints;
use crate::{AppState, Error, Result, db::NewExtensionVersion};
use anyhow::{Context as _, anyhow};
use anyhow::Context as _;
use aws_sdk_s3::presigning::PresigningConfig;
use axum::{
Extension, Json, Router,
@ -181,7 +181,7 @@ async fn download_latest_extension(
.db
.get_extension(&params.extension_id, constraints.as_ref())
.await?
.ok_or_else(|| anyhow!("unknown extension"))?;
.context("unknown extension")?;
download_extension(
Extension(app),
Path(DownloadExtensionParams {
@ -238,7 +238,7 @@ async fn download_extension(
))
.presigned(PresigningConfig::expires_in(EXTENSION_DOWNLOAD_URL_LIFETIME).unwrap())
.await
.map_err(|e| anyhow!("failed to create presigned extension download url {e}"))?;
.context("creating presigned extension download url")?;
Ok(Redirect::temporary(url.uri()))
}
@ -374,7 +374,7 @@ async fn fetch_extension_manifest(
blob_store_bucket: &String,
extension_id: &str,
version: &str,
) -> Result<NewExtensionVersion, anyhow::Error> {
) -> anyhow::Result<NewExtensionVersion> {
let object = blob_store_client
.get_object()
.bucket(blob_store_bucket)
@ -397,8 +397,8 @@ async fn fetch_extension_manifest(
String::from_utf8_lossy(&manifest_bytes)
)
})?;
let published_at = object.last_modified.ok_or_else(|| {
anyhow!("missing last modified timestamp for extension {extension_id} version {version}")
let published_at = object.last_modified.with_context(|| {
format!("missing last modified timestamp for extension {extension_id} version {version}")
})?;
let published_at = time::OffsetDateTime::from_unix_timestamp_nanos(published_at.as_nanos())?;
let published_at = PrimitiveDateTime::new(published_at.date(), published_at.time());

View file

@ -1,3 +1,4 @@
use anyhow::Context as _;
use collections::HashMap;
use semantic_version::SemanticVersion;
@ -13,18 +14,12 @@ pub struct IpsFile {
impl IpsFile {
pub fn parse(bytes: &[u8]) -> anyhow::Result<IpsFile> {
let mut split = bytes.splitn(2, |&b| b == b'\n');
let header_bytes = split
.next()
.ok_or_else(|| anyhow::anyhow!("No header found"))?;
let header: Header = serde_json::from_slice(header_bytes)
.map_err(|e| anyhow::anyhow!("Failed to parse header: {}", e))?;
let header_bytes = split.next().context("No header found")?;
let header: Header = serde_json::from_slice(header_bytes).context("parsing header")?;
let body_bytes = split
.next()
.ok_or_else(|| anyhow::anyhow!("No body found"))?;
let body_bytes = split.next().context("No body found")?;
let body: Body = serde_json::from_slice(body_bytes)
.map_err(|e| anyhow::anyhow!("Failed to parse body: {}", e))?;
let body: Body = serde_json::from_slice(body_bytes).context("parsing body")?;
Ok(IpsFile { header, body })
}