diff --git a/Cargo.lock b/Cargo.lock
index c195423d8..35c76430b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4972,6 +4972,7 @@ dependencies = [
"thiserror 2.0.11",
"tokio",
"tokio-util",
+ "toml",
"tracing",
"url",
"uv-cache",
diff --git a/crates/uv-distribution/Cargo.toml b/crates/uv-distribution/Cargo.toml
index b0fdefb96..06bd9e5c5 100644
--- a/crates/uv-distribution/Cargo.toml
+++ b/crates/uv-distribution/Cargo.toml
@@ -51,6 +51,7 @@ tempfile = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true }
tokio-util = { workspace = true, features = ["compat"] }
+toml = { workspace = true }
tracing = { workspace = true }
url = { workspace = true }
walkdir = { workspace = true }
diff --git a/crates/uv-distribution/src/source/mod.rs b/crates/uv-distribution/src/source/mod.rs
index f68b9a9bf..4a784fbf4 100644
--- a/crates/uv-distribution/src/source/mod.rs
+++ b/crates/uv-distribution/src/source/mod.rs
@@ -22,7 +22,7 @@ use crate::source::revision::Revision;
use crate::{Reporter, RequiresDist};
use fs_err::tokio as fs;
use futures::{FutureExt, TryStreamExt};
-use reqwest::Response;
+use reqwest::{Response, StatusCode};
use tokio_util::compat::FuturesAsyncReadCompatExt;
use tracing::{debug, info_span, instrument, warn, Instrument};
use url::Url;
@@ -40,12 +40,14 @@ use uv_distribution_types::{
};
use uv_extract::hash::Hasher;
use uv_fs::{rename_with_retry, write_atomic, LockedFile};
+use uv_git::{GitHubRepository, GitSha};
use uv_metadata::read_archive_metadata;
use uv_normalize::PackageName;
use uv_pep440::{release_specifiers_to_ranges, Version};
use uv_platform_tags::Tags;
use uv_pypi_types::{HashAlgorithm, HashDigest, Metadata12, RequiresTxt, ResolutionMetadata};
use uv_types::{BuildContext, BuildStack, SourceBuildTrait};
+use uv_workspace::pyproject::ToolUvSources;
use zip::ZipArchive;
mod built_wheel_metadata;
@@ -1496,6 +1498,34 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
return Err(Error::HashesNotSupportedGit(source.to_string()));
}
+ // If this is GitHub URL, attempt to resolve to a precise commit using the GitHub API.
+ if let Some(precise) = self
+ .build_context
+ .git()
+ .github_fast_path(
+ resource.git,
+ client.unmanaged.uncached_client(resource.url).clone(),
+ )
+ .await?
+ {
+ // There's no need to check the cache, since we can't use cached metadata if there are
+ // sources, and we can't know if there are sources without fetching the
+ // `pyproject.toml`.
+ //
+ // For the same reason, there's no need to write to the cache, since we won't be able to
+ // use it on subsequent runs.
+ if let Some(metadata) = self
+ .github_metadata(precise, source, resource, client)
+ .await?
+ {
+ debug!("Found static metadata via GitHub fast path for: {source}");
+ return Ok(ArchiveMetadata {
+ metadata: Metadata::from_metadata23(metadata),
+ hashes: vec![],
+ });
+ }
+ }
+
// Fetch the Git repository.
let fetch = self
.build_context
@@ -1698,38 +1728,139 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
source: &BuildableSource<'_>,
client: &ManagedClient<'_>,
) -> Result<(), Error> {
- match source {
- BuildableSource::Dist(SourceDist::Git(source)) => {
- self.build_context
- .git()
- .fetch(
- &source.git,
- client.unmanaged.uncached_client(&source.url).clone(),
- self.build_context.cache().bucket(CacheBucket::Git),
- self.reporter
- .clone()
- .map(|reporter| reporter.into_git_reporter()),
- )
- .await?;
+ let git = match source {
+ BuildableSource::Dist(SourceDist::Git(source)) => &*source.git,
+ BuildableSource::Url(SourceUrl::Git(source)) => source.git,
+ _ => {
+ return Ok(());
}
- BuildableSource::Url(SourceUrl::Git(source)) => {
- self.build_context
- .git()
- .fetch(
- source.git,
- client.unmanaged.uncached_client(source.url).clone(),
- self.build_context.cache().bucket(CacheBucket::Git),
- self.reporter
- .clone()
- .map(|reporter| reporter.into_git_reporter()),
- )
- .await?;
- }
- _ => {}
+ };
+
+ // If this is GitHub URL, attempt to resolve to a precise commit using the GitHub API.
+ if self
+ .build_context
+ .git()
+ .github_fast_path(
+ git,
+ client.unmanaged.uncached_client(git.repository()).clone(),
+ )
+ .await?
+ .is_some()
+ {
+ debug!("Resolved to precise commit via GitHub fast path: {source}");
+ return Ok(());
}
+
+ // Otherwise, fetch the Git repository.
+ self.build_context
+ .git()
+ .fetch(
+ git,
+ client.unmanaged.uncached_client(git.repository()).clone(),
+ self.build_context.cache().bucket(CacheBucket::Git),
+ self.reporter
+ .clone()
+ .map(|reporter| reporter.into_git_reporter()),
+ )
+ .await?;
+
Ok(())
}
+ /// Fetch static [`ResolutionMetadata`] from a GitHub repository, if possible.
+ ///
+ /// Attempts to fetch the `pyproject.toml` from the resolved commit using the GitHub API.
+ async fn github_metadata(
+ &self,
+ commit: GitSha,
+ source: &BuildableSource<'_>,
+ resource: &GitSourceUrl<'_>,
+ client: &ManagedClient<'_>,
+ ) -> Result