diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs index 71b9166e6b1e8..ef1c7964fa508 100644 --- a/crates/uv-cli/src/lib.rs +++ b/crates/uv-cli/src/lib.rs @@ -2314,6 +2314,17 @@ impl ExternalCommand { } } +#[derive(Debug, Default, Copy, Clone, clap::ValueEnum)] +pub enum AuthorFrom { + /// Fetch the author information from some sources (e.g., Git) automatically. + #[default] + Auto, + /// Fetch the author information for Git configuration only. + Git, + /// Do not infer the author information. + None, +} + #[derive(Args)] #[allow(clippy::struct_excessive_bools)] pub struct InitArgs { @@ -2400,13 +2411,13 @@ pub struct InitArgs { #[arg(long)] pub no_readme: bool, - /// Do not fill in the `authors` field in the `pyproject.toml`. - #[arg(long)] - pub no_authors: bool, - /// Fill in the `authors` field in the `pyproject.toml`. - #[arg(long, overrides_with = "no_authors", hide = true)] - pub authors: bool, + /// + /// By default, uv will attempt to infer the author information from some sources (e.g., Git) (`auto`). + /// Use `--author-from git` to only infer from Git. + /// Use `--author-from none` to avoid inferring the author information. + #[arg(long, value_enum)] + pub author_from: Option, /// Do not create a `.python-version` file for the project. /// diff --git a/crates/uv/src/commands/project/init.rs b/crates/uv/src/commands/project/init.rs index 0bfc29309f716..d3d2aab1ae48c 100644 --- a/crates/uv/src/commands/project/init.rs +++ b/crates/uv/src/commands/project/init.rs @@ -9,6 +9,7 @@ use pep440_rs::Version; use pep508_rs::PackageName; use tracing::{debug, warn}; use uv_cache::Cache; +use uv_cli::AuthorFrom; use uv_client::{BaseClientBuilder, Connectivity}; use uv_configuration::{VersionControlError, VersionControlSystem}; use uv_fs::{Simplified, CWD}; @@ -37,7 +38,7 @@ pub(crate) async fn init( init_kind: InitKind, vcs: Option, no_readme: bool, - with_authors: Option, + author_from: Option, no_pin_python: bool, python: Option, no_workspace: bool, @@ -64,7 +65,7 @@ pub(crate) async fn init( printer, no_workspace, no_readme, - with_authors, + author_from, no_pin_python, package, native_tls, @@ -114,7 +115,7 @@ pub(crate) async fn init( project_kind, vcs, no_readme, - with_authors, + author_from, no_pin_python, python, no_workspace, @@ -169,7 +170,7 @@ async fn init_script( printer: Printer, no_workspace: bool, no_readme: bool, - with_authors: Option, + author_from: Option, no_pin_python: bool, package: bool, native_tls: bool, @@ -180,8 +181,8 @@ async fn init_script( if no_readme { warn_user_once!("`--no_readme` is a no-op for Python scripts, which are standalone"); } - if with_authors.is_some() { - warn_user_once!("`--no_authors` is a no-op for Python scripts, which are standalone"); + if author_from.is_some() { + warn_user_once!("`--author-from` is a no-op for Python scripts, which are standalone"); } if package { warn_user_once!("`--package` is a no-op for Python scripts, which are standalone"); @@ -245,7 +246,7 @@ async fn init_project( project_kind: InitProjectKind, vcs: Option, no_readme: bool, - with_authors: Option, + author_from: Option, no_pin_python: bool, python: Option, no_workspace: bool, @@ -470,7 +471,7 @@ async fn init_project( &requires_python, python_request.as_ref(), vcs, - with_authors, + author_from, no_readme, package, ) @@ -560,7 +561,7 @@ impl InitProjectKind { requires_python: &RequiresPython, python_request: Option<&PythonRequest>, vcs: Option, - with_authors: Option, + author_from: Option, no_readme: bool, package: bool, ) -> Result<()> { @@ -572,7 +573,7 @@ impl InitProjectKind { requires_python, python_request, vcs, - with_authors, + author_from, no_readme, package, ) @@ -585,7 +586,7 @@ impl InitProjectKind { requires_python, python_request, vcs, - with_authors, + author_from, no_readme, package, ) @@ -602,18 +603,24 @@ impl InitProjectKind { requires_python: &RequiresPython, python_request: Option<&PythonRequest>, vcs: Option, - with_authors: Option, + author_from: Option, no_readme: bool, package: bool, ) -> Result<()> { fs_err::create_dir_all(path)?; // Do no fill in `authors` for non-packaged applications unless explicitly requested. - let author = if with_authors.unwrap_or(package) { - get_author_info(path) - } else { - None + let author_from = match author_from { + None => { + if package { + AuthorFrom::default() + } else { + AuthorFrom::None + } + } + Some(author_from) => author_from, }; + let author = get_author_info(path, author_from); // Create the `pyproject.toml` let mut pyproject = pyproject_project(name, requires_python, author.as_ref(), no_readme); @@ -691,7 +698,7 @@ impl InitProjectKind { requires_python: &RequiresPython, python_request: Option<&PythonRequest>, vcs: Option, - with_authors: Option, + author_from: Option, no_readme: bool, package: bool, ) -> Result<()> { @@ -701,11 +708,7 @@ impl InitProjectKind { fs_err::create_dir_all(path)?; - let author = if with_authors.unwrap_or(true) { - get_author_info(path) - } else { - None - }; + let author = get_author_info(path, author_from.unwrap_or_default()); // Create the `pyproject.toml` let mut pyproject = pyproject_project(name, requires_python, author.as_ref(), no_readme); @@ -866,10 +869,15 @@ fn init_vcs(path: &Path, vcs: Option) -> Result<()> { /// Try to get the author information. /// /// Currently, this only tries to get the author information from git. -fn get_author_info(path: &Path) -> Option { - match get_author_from_git(path) { - Ok(author) => return Some(author), - Err(err) => warn!("Failed to get author from git: {err}"), +fn get_author_info(path: &Path, author_from: AuthorFrom) -> Option { + if matches!(author_from, AuthorFrom::None) { + return None; + } + if matches!(author_from, AuthorFrom::Auto | AuthorFrom::Git) { + match get_author_from_git(path) { + Ok(author) => return Some(author), + Err(err) => warn!("Failed to get author from git: {err}"), + } } None diff --git a/crates/uv/src/lib.rs b/crates/uv/src/lib.rs index 48dea3dcb54c8..32d865e5358ff 100644 --- a/crates/uv/src/lib.rs +++ b/crates/uv/src/lib.rs @@ -1189,7 +1189,7 @@ async fn run_project( args.kind, args.vcs, args.no_readme, - args.with_authors, + args.author_from, args.no_pin_python, args.python, args.no_workspace, diff --git a/crates/uv/src/settings.rs b/crates/uv/src/settings.rs index 9dc4e8e8c7f87..34373b9bdc029 100644 --- a/crates/uv/src/settings.rs +++ b/crates/uv/src/settings.rs @@ -12,7 +12,7 @@ use url::Url; use uv_cache::{CacheArgs, Refresh}; use uv_cli::{ options::{flag, resolver_installer_options, resolver_options}, - BuildArgs, ExportArgs, PublishArgs, ToolUpgradeArgs, + AuthorFrom, BuildArgs, ExportArgs, PublishArgs, ToolUpgradeArgs, }; use uv_cli::{ AddArgs, ColorChoice, ExternalCommand, GlobalArgs, InitArgs, ListFormat, LockArgs, Maybe, @@ -164,7 +164,7 @@ pub(crate) struct InitSettings { pub(crate) kind: InitKind, pub(crate) vcs: Option, pub(crate) no_readme: bool, - pub(crate) with_authors: Option, + pub(crate) author_from: Option, pub(crate) no_pin_python: bool, pub(crate) no_workspace: bool, pub(crate) python: Option, @@ -185,8 +185,7 @@ impl InitSettings { script, vcs, no_readme, - no_authors, - authors, + author_from, no_pin_python, no_workspace, python, @@ -209,7 +208,7 @@ impl InitSettings { kind, vcs, no_readme, - with_authors: flag(authors, no_authors), + author_from, no_pin_python, no_workspace, python, diff --git a/crates/uv/tests/init.rs b/crates/uv/tests/init.rs index ef41883187c99..627228840781a 100644 --- a/crates/uv/tests/init.rs +++ b/crates/uv/tests/init.rs @@ -2307,11 +2307,12 @@ fn init_with_author() -> Result<()> { ); }); - // use `--authors` to explicitly fill it. + // use `--author-from auto` to explicitly fill it. context .init() .arg("bar") - .arg("--authors") + .arg("--author-from") + .arg("auto") .assert() .success(); let pyproject = fs_err::read_to_string(context.temp_dir.join("bar/pyproject.toml"))?; @@ -2360,12 +2361,13 @@ fn init_with_author() -> Result<()> { ); }); - // use `--no-authors` to prevent it. + // use `--authors-from none` to prevent it. context .init() .arg("qux") .arg("--lib") - .arg("--no-authors") + .arg("--author-from") + .arg("none") .assert() .success(); let pyproject = fs_err::read_to_string(context.temp_dir.join("qux/pyproject.toml"))?;