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)]
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.
///
/// 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,
list: bool,
build_logs: bool,
gitignore: bool,
force_pep517: bool,
clear: bool,
build_constraints: Vec<RequirementsSource>,
@ -134,6 +135,7 @@ pub(crate) async fn build_frontend(
wheel,
list,
build_logs,
gitignore,
force_pep517,
clear,
&build_constraints,
@ -178,6 +180,7 @@ async fn build_impl(
wheel: bool,
list: bool,
build_logs: bool,
gitignore: bool,
force_pep517: bool,
clear: bool,
build_constraints: &[RequirementsSource],
@ -344,6 +347,7 @@ async fn build_impl(
client_builder.clone(),
hash_checking,
build_logs,
gitignore,
force_pep517,
clear,
build_constraints,
@ -452,6 +456,7 @@ async fn build_package(
client_builder: BaseClientBuilder<'_>,
hash_checking: Option<HashCheckingMode>,
build_logs: bool,
gitignore: bool,
force_pep517: bool,
clear: bool,
build_constraints: &[RequirementsSource],
@ -627,7 +632,7 @@ async fn build_package(
preview,
);
prepare_output_directory(&output_dir).await?;
prepare_output_directory(&output_dir, gitignore).await?;
// Determine the build plan.
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`.
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.
fs_err::tokio::create_dir_all(&output_dir).await?;
// Add a .gitignore.
match fs_err::OpenOptions::new()
.write(true)
.create_new(true)
.open(output_dir.join(".gitignore"))
{
Ok(mut file) => file.write_all(b"*")?,
Err(err) if err.kind() == io::ErrorKind::AlreadyExists => (),
Err(err) => return Err(err.into()),
if gitignore {
match fs_err::OpenOptions::new()
.write(true)
.create_new(true)
.open(output_dir.join(".gitignore"))
{
Ok(mut file) => file.write_all(b"*")?,
Err(err) if err.kind() == io::ErrorKind::AlreadyExists => (),
Err(err) => return Err(err.into()),
}
}
Ok(())
}

View file

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

View file

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

View file

@ -2213,3 +2213,53 @@ fn build_clear() -> Result<()> {
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_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>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>
<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>