From db833b99b58ab35a168c5b8a62d59489bb4413aa Mon Sep 17 00:00:00 2001 From: messense Date: Wed, 9 Aug 2023 08:10:14 +0800 Subject: [PATCH] Add non-interactive mode to `upload` command --- src/ci.rs | 10 +++++----- src/upload.rs | 28 ++++++++++++++++------------ tests/cmd/publish.stdout | 7 +++++++ tests/cmd/upload.stdout | 7 +++++++ 4 files changed, 35 insertions(+), 17 deletions(-) diff --git a/src/ci.rs b/src/ci.rs index 3013e2adb..1de8f56df 100644 --- a/src/ci.rs +++ b/src/ci.rs @@ -479,7 +479,7 @@ jobs:\n", MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }} with: command: upload - args: --skip-existing * + args: --non-interactive --skip-existing * "#, ); if platforms.contains(&Platform::Emscripten) { @@ -645,7 +645,7 @@ mod tests { MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }} with: command: upload - args: --skip-existing * + args: --non-interactive --skip-existing * "#}; assert_eq!(conf, expected.trim()); } @@ -759,7 +759,7 @@ mod tests { MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }} with: command: upload - args: --skip-existing * + args: --non-interactive --skip-existing * "#}; assert_eq!(conf, expected.trim()); } @@ -936,7 +936,7 @@ mod tests { MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }} with: command: upload - args: --skip-existing * + args: --non-interactive --skip-existing * "#}; assert_eq!(conf, expected.trim()); } @@ -1055,7 +1055,7 @@ mod tests { MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }} with: command: upload - args: --skip-existing * + args: --non-interactive --skip-existing * "#}; assert_eq!(conf, expected.trim()); } diff --git a/src/upload.rs b/src/upload.rs index 3eb84b4e8..333c7d729 100644 --- a/src/upload.rs +++ b/src/upload.rs @@ -33,11 +33,7 @@ pub struct PublishOpt { /// The URL of the registry where the wheels are uploaded to. This overrides --repository. /// /// Can also be set via MATURIN_REPOSITORY_URL environment variable. - #[arg( - long = "repository-url", - env = "MATURIN_REPOSITORY_URL", - overrides_with = "repository" - )] + #[arg(long, env = "MATURIN_REPOSITORY_URL", overrides_with = "repository")] repository_url: Option, /// Username for pypi or your custom registry. /// @@ -53,8 +49,13 @@ pub struct PublishOpt { password: Option, /// Continue uploading files if one already exists. /// (Only valid when uploading to PyPI. Other implementations may not support this.) - #[arg(long = "skip-existing")] + #[arg(long)] skip_existing: bool, + /// Do not interactively prompt for username/password if the required credentials are missing. + /// + /// Can also be set via MATURIN_NON_INTERACTIVE environment variable. + #[arg(long, env = "MATURIN_NON_INTERACTIVE")] + non_interactive: bool, } impl PublishOpt { @@ -202,17 +203,17 @@ fn resolve_pypi_cred( config: &Ini, registry_name: Option<&str>, registry_url: &str, -) -> (String, String) { +) -> Result<(String, String)> { // API token from environment variable takes priority if let Ok(token) = env::var("MATURIN_PYPI_TOKEN") { - return ("__token__".to_string(), token); + return Ok(("__token__".to_string(), token)); } // Try to get a token via OIDC exchange match resolve_pypi_token_via_oidc(registry_url) { Ok(Some(token)) => { eprintln!("🔐 Using trusted publisher for upload"); - return ("__token__".to_string(), token); + return Ok(("__token__".to_string(), token)); } Ok(None) => {} Err(e) => eprintln!("⚠️ Warning: Failed to resolve PyPI token via OIDC: {}", e), @@ -222,17 +223,20 @@ fn resolve_pypi_cred( registry_name.and_then(|name| load_pypi_cred_from_config(config, name)) { eprintln!("🔐 Using credential in pypirc for upload"); - return (username, password); + return Ok((username, password)); } // fallback to username and password + if opt.non_interactive { + bail!("Credentials not found and non-interactive mode is enabled"); + } let username = opt.username.clone().unwrap_or_else(get_username); let password = opt .password .clone() .or_else(|| env::var("MATURIN_PASSWORD").ok()) .unwrap_or_else(|| get_password(&username)); - (username, password) + Ok((username, password)) } #[derive(Debug, Deserialize)] @@ -328,7 +332,7 @@ fn complete_registry(opt: &PublishOpt) -> Result { opt.repository ); }; - let (username, password) = resolve_pypi_cred(opt, &pypirc, registry_name, ®istry_url); + let (username, password) = resolve_pypi_cred(opt, &pypirc, registry_name, ®istry_url)?; let registry = Registry::new(username, password, registry_url); Ok(registry) diff --git a/tests/cmd/publish.stdout b/tests/cmd/publish.stdout index 6bb2b1ba7..3329c61a6 100644 --- a/tests/cmd/publish.stdout +++ b/tests/cmd/publish.stdout @@ -50,6 +50,13 @@ Options: Continue uploading files if one already exists. (Only valid when uploading to PyPI. Other implementations may not support this.) + --non-interactive + Do not interactively prompt for username/password if the required credentials are missing. + + Can also be set via MATURIN_NON_INTERACTIVE environment variable. + + [env: MATURIN_NON_INTERACTIVE=] + --compatibility [...] Control the platform tag on linux. diff --git a/tests/cmd/upload.stdout b/tests/cmd/upload.stdout index 14f6248d1..dfbda34ba 100644 --- a/tests/cmd/upload.stdout +++ b/tests/cmd/upload.stdout @@ -43,5 +43,12 @@ Options: Continue uploading files if one already exists. (Only valid when uploading to PyPI. Other implementations may not support this.) + --non-interactive + Do not interactively prompt for username/password if the required credentials are missing. + + Can also be set via MATURIN_NON_INTERACTIVE environment variable. + + [env: MATURIN_NON_INTERACTIVE=] + -h, --help Print help (see a summary with '-h')