Add --no-create-gitignore to uv build (#16369)

Fixes #16332
This commit is contained in:
konsti 2025-10-28 13:25:31 +01:00 committed by GitHub
parent c279b4ab54
commit cfa1de311e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 86 additions and 11 deletions

View file

@ -2639,6 +2639,16 @@ pub struct BuildArgs {
#[arg(long)] #[arg(long)]
pub clear: bool, pub clear: bool,
#[arg(long, overrides_with("no_create_gitignore"), hide = true)]
pub create_gitignore: bool,
/// Do not create a `.gitignore` file in the output directory.
///
/// By default, uv creates a `.gitignore` file in the output directory to exclude build
/// artifacts from version control. When this flag is used, the file will be omitted.
#[arg(long, overrides_with("create_gitignore"))]
pub no_create_gitignore: bool,
/// Constrain build dependencies using the given requirements files when building distributions. /// Constrain build dependencies using the given requirements files when building distributions.
/// ///
/// Constraints files are `requirements.txt`-like files that only control the _version_ of a /// Constraints files are `requirements.txt`-like files that only control the _version_ of a

View file

@ -108,6 +108,7 @@ pub(crate) async fn build_frontend(
wheel: bool, wheel: bool,
list: bool, list: bool,
build_logs: bool, build_logs: bool,
gitignore: bool,
force_pep517: bool, force_pep517: bool,
clear: bool, clear: bool,
build_constraints: Vec<RequirementsSource>, build_constraints: Vec<RequirementsSource>,
@ -134,6 +135,7 @@ pub(crate) async fn build_frontend(
wheel, wheel,
list, list,
build_logs, build_logs,
gitignore,
force_pep517, force_pep517,
clear, clear,
&build_constraints, &build_constraints,
@ -178,6 +180,7 @@ async fn build_impl(
wheel: bool, wheel: bool,
list: bool, list: bool,
build_logs: bool, build_logs: bool,
gitignore: bool,
force_pep517: bool, force_pep517: bool,
clear: bool, clear: bool,
build_constraints: &[RequirementsSource], build_constraints: &[RequirementsSource],
@ -344,6 +347,7 @@ async fn build_impl(
client_builder.clone(), client_builder.clone(),
hash_checking, hash_checking,
build_logs, build_logs,
gitignore,
force_pep517, force_pep517,
clear, clear,
build_constraints, build_constraints,
@ -452,6 +456,7 @@ async fn build_package(
client_builder: BaseClientBuilder<'_>, client_builder: BaseClientBuilder<'_>,
hash_checking: Option<HashCheckingMode>, hash_checking: Option<HashCheckingMode>,
build_logs: bool, build_logs: bool,
gitignore: bool,
force_pep517: bool, force_pep517: bool,
clear: bool, clear: bool,
build_constraints: &[RequirementsSource], build_constraints: &[RequirementsSource],
@ -627,7 +632,7 @@ async fn build_package(
preview, preview,
); );
prepare_output_directory(&output_dir).await?; prepare_output_directory(&output_dir, gitignore).await?;
// Determine the build plan. // Determine the build plan.
let plan = BuildPlan::determine(&source, sdist, wheel).map_err(Error::BuildPlan)?; let plan = BuildPlan::determine(&source, sdist, wheel).map_err(Error::BuildPlan)?;
@ -1094,19 +1099,21 @@ async fn build_wheel(
} }
/// Create the output directory and add a `.gitignore`. /// Create the output directory and add a `.gitignore`.
async fn prepare_output_directory(output_dir: &Path) -> Result<(), Error> { async fn prepare_output_directory(output_dir: &Path, gitignore: bool) -> Result<(), Error> {
// Create the output directory. // Create the output directory.
fs_err::tokio::create_dir_all(&output_dir).await?; fs_err::tokio::create_dir_all(&output_dir).await?;
// Add a .gitignore. // Add a .gitignore.
match fs_err::OpenOptions::new() if gitignore {
.write(true) match fs_err::OpenOptions::new()
.create_new(true) .write(true)
.open(output_dir.join(".gitignore")) .create_new(true)
{ .open(output_dir.join(".gitignore"))
Ok(mut file) => file.write_all(b"*")?, {
Err(err) if err.kind() == io::ErrorKind::AlreadyExists => (), Ok(mut file) => file.write_all(b"*")?,
Err(err) => return Err(err.into()), Err(err) if err.kind() == io::ErrorKind::AlreadyExists => (),
Err(err) => return Err(err.into()),
}
} }
Ok(()) Ok(())
} }

View file

@ -1072,6 +1072,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
args.wheel, args.wheel,
args.list, args.list,
args.build_logs, args.build_logs,
args.gitignore,
args.force_pep517, args.force_pep517,
args.clear, args.clear,
build_constraints, build_constraints,

View file

@ -2872,6 +2872,7 @@ pub(crate) struct BuildSettings {
pub(crate) wheel: bool, pub(crate) wheel: bool,
pub(crate) list: bool, pub(crate) list: bool,
pub(crate) build_logs: bool, pub(crate) build_logs: bool,
pub(crate) gitignore: bool,
pub(crate) force_pep517: bool, pub(crate) force_pep517: bool,
pub(crate) clear: bool, pub(crate) clear: bool,
pub(crate) build_constraints: Vec<PathBuf>, pub(crate) build_constraints: Vec<PathBuf>,
@ -2906,6 +2907,8 @@ impl BuildSettings {
no_verify_hashes, no_verify_hashes,
build_logs, build_logs,
no_build_logs, no_build_logs,
create_gitignore,
no_create_gitignore,
python, python,
build, build,
refresh, refresh,
@ -2927,6 +2930,8 @@ impl BuildSettings {
build_logs: flag(build_logs, no_build_logs, "build-logs").unwrap_or(true), build_logs: flag(build_logs, no_build_logs, "build-logs").unwrap_or(true),
force_pep517, force_pep517,
clear, clear,
gitignore: flag(create_gitignore, no_create_gitignore, "create-gitignore")
.unwrap_or(true),
build_constraints: build_constraints build_constraints: build_constraints
.into_iter() .into_iter()
.filter_map(Maybe::into_option) .filter_map(Maybe::into_option)

View file

@ -2213,3 +2213,53 @@ fn build_clear() -> Result<()> {
Ok(()) Ok(())
} }
/// Test `uv build --no-create-gitignore`.
#[test]
fn build_no_gitignore() -> Result<()> {
let context = TestContext::new("3.12");
let project = context.temp_dir.child("project");
context.init().arg(project.path()).assert().success();
// Default build with `.gitignore`
uv_snapshot!(&context.filters(), context.build().arg("project").arg("--no-build-logs"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Building source distribution...
Building wheel from source distribution...
Successfully built project/dist/project-0.1.0.tar.gz
Successfully built project/dist/project-0.1.0-py3-none-any.whl
"###);
project
.child("dist")
.child(".gitignore")
.assert(predicate::path::is_file());
fs_err::remove_dir_all(project.child("dist"))?;
// Build with `--no-create-gitignore` that does not create `.gitignore`
uv_snapshot!(&context.filters(), context.build().arg("project").arg("--no-create-gitignore").arg("--no-build-logs"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Building source distribution...
Building wheel from source distribution...
Successfully built project/dist/project-0.1.0.tar.gz
Successfully built project/dist/project-0.1.0-py3-none-any.whl
"###);
project
.child("dist")
.child(".gitignore")
.assert(predicate::path::missing());
Ok(())
}

View file

@ -5730,7 +5730,9 @@ uv build [OPTIONS] [SRC]
<p>May also be set with the <code>UV_NO_BUILD_PACKAGE</code> environment variable.</p></dd><dt id="uv-build--no-cache"><a href="#uv-build--no-cache"><code>--no-cache</code></a>, <code>--no-cache-dir</code>, <code>-n</code></dt><dd><p>Avoid reading from or writing to the cache, instead using a temporary directory for the duration of the operation</p> <p>May also be set with the <code>UV_NO_BUILD_PACKAGE</code> environment variable.</p></dd><dt id="uv-build--no-cache"><a href="#uv-build--no-cache"><code>--no-cache</code></a>, <code>--no-cache-dir</code>, <code>-n</code></dt><dd><p>Avoid reading from or writing to the cache, instead using a temporary directory for the duration of the operation</p>
<p>May also be set with the <code>UV_NO_CACHE</code> environment variable.</p></dd><dt id="uv-build--no-config"><a href="#uv-build--no-config"><code>--no-config</code></a></dt><dd><p>Avoid discovering configuration files (<code>pyproject.toml</code>, <code>uv.toml</code>).</p> <p>May also be set with the <code>UV_NO_CACHE</code> environment variable.</p></dd><dt id="uv-build--no-config"><a href="#uv-build--no-config"><code>--no-config</code></a></dt><dd><p>Avoid discovering configuration files (<code>pyproject.toml</code>, <code>uv.toml</code>).</p>
<p>Normally, configuration files are discovered in the current directory, parent directories, or user configuration directories.</p> <p>Normally, configuration files are discovered in the current directory, parent directories, or user configuration directories.</p>
<p>May also be set with the <code>UV_NO_CONFIG</code> environment variable.</p></dd><dt id="uv-build--no-index"><a href="#uv-build--no-index"><code>--no-index</code></a></dt><dd><p>Ignore the registry index (e.g., PyPI), instead relying on direct URL dependencies and those provided via <code>--find-links</code></p> <p>May also be set with the <code>UV_NO_CONFIG</code> environment variable.</p></dd><dt id="uv-build--no-create-gitignore"><a href="#uv-build--no-create-gitignore"><code>--no-create-gitignore</code></a></dt><dd><p>Do not create a <code>.gitignore</code> file in the output directory.</p>
<p>By default, uv creates a <code>.gitignore</code> file in the output directory to exclude build artifacts from version control. When this flag is used, the file will be omitted.</p>
</dd><dt id="uv-build--no-index"><a href="#uv-build--no-index"><code>--no-index</code></a></dt><dd><p>Ignore the registry index (e.g., PyPI), instead relying on direct URL dependencies and those provided via <code>--find-links</code></p>
</dd><dt id="uv-build--no-managed-python"><a href="#uv-build--no-managed-python"><code>--no-managed-python</code></a></dt><dd><p>Disable use of uv-managed Python versions.</p> </dd><dt id="uv-build--no-managed-python"><a href="#uv-build--no-managed-python"><code>--no-managed-python</code></a></dt><dd><p>Disable use of uv-managed Python versions.</p>
<p>Instead, uv will search for a suitable Python version on the system.</p> <p>Instead, uv will search for a suitable Python version on the system.</p>
<p>May also be set with the <code>UV_NO_MANAGED_PYTHON</code> environment variable.</p></dd><dt id="uv-build--no-progress"><a href="#uv-build--no-progress"><code>--no-progress</code></a></dt><dd><p>Hide all progress outputs.</p> <p>May also be set with the <code>UV_NO_MANAGED_PYTHON</code> environment variable.</p></dd><dt id="uv-build--no-progress"><a href="#uv-build--no-progress"><code>--no-progress</code></a></dt><dd><p>Hide all progress outputs.</p>