mirror of https://github.com/astral-sh/uv
publish: don't infer check URLs for pyx uploads (#16234)
This commit is contained in:
parent
d45acaebc8
commit
6fb00a9936
|
|
@ -11,7 +11,6 @@ use uv_cache::Cache;
|
||||||
use uv_client::{AuthIntegration, BaseClient, BaseClientBuilder, RegistryClientBuilder};
|
use uv_client::{AuthIntegration, BaseClient, BaseClientBuilder, RegistryClientBuilder};
|
||||||
use uv_configuration::{KeyringProviderType, TrustedPublishing};
|
use uv_configuration::{KeyringProviderType, TrustedPublishing};
|
||||||
use uv_distribution_types::{IndexCapabilities, IndexLocations, IndexUrl};
|
use uv_distribution_types::{IndexCapabilities, IndexLocations, IndexUrl};
|
||||||
use uv_pep508::VerbatimUrl;
|
|
||||||
use uv_publish::{
|
use uv_publish::{
|
||||||
CheckUrlClient, FormMetadata, PublishError, TrustedPublishResult, check_trusted_publishing,
|
CheckUrlClient, FormMetadata, PublishError, TrustedPublishResult, check_trusted_publishing,
|
||||||
files_for_publishing, upload,
|
files_for_publishing, upload,
|
||||||
|
|
@ -75,16 +74,15 @@ pub(crate) async fn publish(
|
||||||
.publish_url
|
.publish_url
|
||||||
.clone()
|
.clone()
|
||||||
.with_context(|| format!("Index is missing a publish URL: `{index_name}`"))?;
|
.with_context(|| format!("Index is missing a publish URL: `{index_name}`"))?;
|
||||||
let check_url = index.url.clone();
|
|
||||||
(publish_url, Some(check_url))
|
// pyx has the same behavior as PyPI where uploads of identical
|
||||||
} else if token_store.is_known_url(&publish_url) {
|
// files + contents are idempotent, so we don't need to pre-check.
|
||||||
// If the user is publishing to a known index, construct the check URL from the publish
|
if token_store.is_known_url(&publish_url) {
|
||||||
// URL.
|
(publish_url, None)
|
||||||
let check_url = check_url.or_else(|| {
|
} else {
|
||||||
infer_check_url(&publish_url)
|
let check_url = index.url.clone();
|
||||||
.inspect(|check_url| debug!("Inferred check URL: {check_url}"))
|
(publish_url, Some(check_url))
|
||||||
});
|
}
|
||||||
(publish_url, check_url)
|
|
||||||
} else {
|
} else {
|
||||||
(publish_url, check_url)
|
(publish_url, check_url)
|
||||||
};
|
};
|
||||||
|
|
@ -439,50 +437,6 @@ fn prompt_username_and_password() -> Result<(Option<String>, Option<String>)> {
|
||||||
Ok((Some(username), Some(password)))
|
Ok((Some(username), Some(password)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a Simple Index URL from a publish URL, if possible.
|
|
||||||
///
|
|
||||||
/// Matches against a publish URL of the form `/v1/upload/{workspace}/{registry}` and returns
|
|
||||||
/// `/simple/{workspace}/{registry}`.
|
|
||||||
fn infer_check_url(publish_url: &DisplaySafeUrl) -> Option<IndexUrl> {
|
|
||||||
let mut segments = publish_url.path_segments()?;
|
|
||||||
|
|
||||||
let v1 = segments.next()?;
|
|
||||||
if v1 != "v1" {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let upload = segments.next()?;
|
|
||||||
if upload != "upload" {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let workspace = segments.next()?;
|
|
||||||
if workspace.is_empty() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let registry = segments.next()?;
|
|
||||||
if registry.is_empty() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip any empty segments (trailing slash handling)
|
|
||||||
for remaining in segments {
|
|
||||||
if !remaining.is_empty() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reconstruct the URL with `/simple/{workspace}/{registry}`.
|
|
||||||
let mut check_url = publish_url.clone();
|
|
||||||
{
|
|
||||||
let mut segments = check_url.path_segments_mut().ok()?;
|
|
||||||
segments.clear();
|
|
||||||
segments.push("simple").push(workspace).push(registry);
|
|
||||||
}
|
|
||||||
Some(IndexUrl::from(VerbatimUrl::from(check_url)))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
@ -595,33 +549,4 @@ mod tests {
|
||||||
@"The password can't be set both in the publish URL and in the CLI"
|
@"The password can't be set both in the publish URL and in the CLI"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_infer_check_url() {
|
|
||||||
let url =
|
|
||||||
DisplaySafeUrl::from_str("https://example.com/v1/upload/workspace/registry").unwrap();
|
|
||||||
let check_url = infer_check_url(&url);
|
|
||||||
assert_eq!(
|
|
||||||
check_url,
|
|
||||||
Some(IndexUrl::from_str("https://example.com/simple/workspace/registry").unwrap())
|
|
||||||
);
|
|
||||||
|
|
||||||
let url =
|
|
||||||
DisplaySafeUrl::from_str("https://example.com/v1/upload/workspace/registry/").unwrap();
|
|
||||||
let check_url = infer_check_url(&url);
|
|
||||||
assert_eq!(
|
|
||||||
check_url,
|
|
||||||
Some(IndexUrl::from_str("https://example.com/simple/workspace/registry").unwrap())
|
|
||||||
);
|
|
||||||
|
|
||||||
let url =
|
|
||||||
DisplaySafeUrl::from_str("https://example.com/upload/workspace/registry").unwrap();
|
|
||||||
let check_url = infer_check_url(&url);
|
|
||||||
assert_eq!(check_url, None);
|
|
||||||
|
|
||||||
let url = DisplaySafeUrl::from_str("https://example.com/upload/workspace/registry/package")
|
|
||||||
.unwrap();
|
|
||||||
let check_url = infer_check_url(&url);
|
|
||||||
assert_eq!(check_url, None);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue