Skip to content

Commit

Permalink
Add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
j178 committed Jul 27, 2024
1 parent 727428f commit 85280e4
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 24 deletions.
4 changes: 2 additions & 2 deletions crates/uv-configuration/src/vcs_options.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use serde::Deserialize;
use std::str::FromStr;

///
/// The version control system to use.
#[derive(Clone, Copy, Debug, PartialEq, Default, Deserialize)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
Expand All @@ -22,7 +22,7 @@ impl FromStr for VersionControl {
match s {
"git" => Ok(VersionControl::Git),
"none" => Ok(VersionControl::None),
other => Err(format!("unknown vcs specification: `{}`", other)),
other => Err(format!("unknown vcs specification: `{other}`")),
}
}
}
Expand Down
50 changes: 28 additions & 22 deletions crates/uv/src/commands/project/init.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use anyhow::{Context, Result};
use owo_colors::OwoColorize;
use pep440_rs::Version;
use pep508_rs::PackageName;
use std::fmt::Write;
use std::path::Path;
use std::process::{Command, Stdio};

use anyhow::{Context, Result};
use owo_colors::OwoColorize;
use tracing::debug;

use pep440_rs::Version;
use pep508_rs::PackageName;
use uv_cache::Cache;
use uv_client::{BaseClientBuilder, Connectivity};
use uv_configuration::{PreviewMode, VersionControl};
Expand Down Expand Up @@ -108,8 +110,8 @@ pub(crate) async fn init(
let in_existing_vcs = existing_vcs_repo(path.parent().unwrap_or(&path));
let vcs = match (version_control, in_existing_vcs) {
(None, false) => VersionControl::default(),
(Some(vcs), false) => vcs,
(None, true) => VersionControl::None,
(Some(vcs), false) => vcs,
(Some(vcs), true) => {
warn_user!(
"The project is already in a version control system, `--vcs {vcs}` is ignored",
Expand Down Expand Up @@ -349,15 +351,21 @@ async fn init_project(
fn init_vcs(path: &Path, vcs: VersionControl) -> Result<()> {
match vcs {
VersionControl::Git => {
if !path.join(".git").exists() {
if path.join(".git").try_exists()? {
warn_user!(
"Git repository already exists at `{}`",
path.simplified_display()
);
} else {
init_git_repo(path)?;
}

// Create the `.gitignore` if it does not already exist.
let gitignore = path.join(".gitignore");
if !gitignore.exists() {
fs_err::write(
gitignore,
indoc::indoc! {r"
// Create the `.gitignore` if it does not already exist.
let gitignore = path.join(".gitignore");
if !gitignore.try_exists()? {
fs_err::write(
gitignore,
indoc::indoc! {r"
# Python generated files
__pycache__/
*.py[oc]
Expand All @@ -369,8 +377,7 @@ fn init_vcs(path: &Path, vcs: VersionControl) -> Result<()> {
# venv
.venv
"},
)?;
}
)?;
}
}
VersionControl::None => {}
Expand All @@ -379,9 +386,10 @@ fn init_vcs(path: &Path, vcs: VersionControl) -> Result<()> {
Ok(())
}

// Check if we are in an existing repo.
/// Check if the path is inside a VCS repository.
///
/// Currently only supports Git.
fn existing_vcs_repo(dir: &Path) -> bool {
// Check git repo only for now.
is_inside_git_work_tree(dir)
}

Expand All @@ -402,16 +410,14 @@ fn is_inside_git_work_tree(dir: &Path) -> bool {
fn init_git_repo(dir: &Path) -> Result<()> {
if !Command::new("git")
.arg("init")
.current_dir(&dir)
.current_dir(dir)
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()?
.status()
.context("failed to run `git init`")?
.success()
{
anyhow::bail!(
"Run `git init` failed at `{}`",
dir.simplified_display()
);
anyhow::bail!("`git init` failed at `{}`", dir.simplified_display());
}

Ok(())
Expand Down
149 changes: 149 additions & 0 deletions crates/uv/tests/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use anyhow::Result;
use assert_fs::prelude::*;
use indoc::indoc;
use insta::assert_snapshot;
use predicates::prelude::predicate;
use std::process::Command;

use common::{uv_snapshot, TestContext};

Expand Down Expand Up @@ -1129,3 +1131,150 @@ fn init_hidden() {
error: Not a valid package or extra name: ".foo". Names must start and end with a letter or digit and may only contain -, _, ., and alphanumeric characters.
"###);
}

#[test]
fn init_git() -> Result<()> {
let context = TestContext::new("3.12");

let child = context.temp_dir.child("foo");

uv_snapshot!(context.filters(), context.init().arg(child.as_ref()), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: `uv init` is experimental and may change without warning
Initialized project `foo` at `[TEMP_DIR]/foo`
"###);

let gitignore = fs_err::read_to_string(child.join(".gitignore"))?;
insta::with_settings!({
filters => context.filters(),
}, {
assert_snapshot!(
gitignore, @r###"
# Python generated files
__pycache__/
*.py[oc]
build/
dist/
wheels/
*.egg-info
# venv
.venv
"###
);
});

child.child(".git").assert(predicate::path::is_dir());

Ok(())
}

#[test]
fn init_vcs_none() {
let context = TestContext::new("3.12");

let child = context.temp_dir.child("foo");

uv_snapshot!(context.filters(), context.init().arg(child.as_ref()).arg("--vcs").arg("none"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: `uv init` is experimental and may change without warning
Initialized project `foo` at `[TEMP_DIR]/foo`
"###);

child.child(".gitignore").assert(predicate::path::missing());
child.child(".git").assert(predicate::path::missing());
}

/// Run `uv init` from within a Git repository. Do not try to reinitialize one.
#[test]
fn init_inside_git_repo() -> Result<()> {
let context = TestContext::new("3.12");

Command::new("git")
.arg("init")
.current_dir(&context.temp_dir)
.status()?;

let child = context.temp_dir.child("foo");

uv_snapshot!(context.filters(), context.init().arg(child.as_ref()).arg("--vcs").arg("git"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: `uv init` is experimental and may change without warning
warning: The project is already in a version control system, `--vcs git` is ignored
Initialized project `foo` at `[TEMP_DIR]/foo`
"###);

child.child(".gitignore").assert(predicate::path::missing());

let child = context.temp_dir.child("bar");
uv_snapshot!(context.filters(), context.init().arg(child.as_ref()), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: `uv init` is experimental and may change without warning
Initialized project `bar` at `[TEMP_DIR]/bar`
"###);

child.child(".gitignore").assert(predicate::path::missing());

Ok(())
}

#[test]
fn init_git_not_installed() {
let context = TestContext::new("3.12");

let child = context.temp_dir.child("foo");

// Without explicit `--vcs git`, `uv init` succeeds without initializing a Git repository.
uv_snapshot!(context.filters(), context.init().env("PATH", &*child).arg(child.as_ref()), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: `uv init` is experimental and may change without warning
Initialized project `foo` at `[TEMP_DIR]/foo`
"###);

// With explicit `--vcs git`, `uv init` will fail.
let child = context.temp_dir.child("bar");
if cfg!(windows) {
// Set `PATH` to child to make `git` command fail.
uv_snapshot!(context.filters(), context.init().env("PATH", &*child).arg(child.as_ref()).arg("--vcs").arg("git"), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
warning: `uv init` is experimental and may change without warning
error: failed to run `git init`
Caused by: program not found
"###);
} else {
uv_snapshot!(context.filters(), context.init().env("PATH", &*child).arg(child.as_ref()).arg("--vcs").arg("git"), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
warning: `uv init` is experimental and may change without warning
error: failed to run `git init`
Caused by: No such file or directory (os error 2)
"###);
}
}

0 comments on commit 85280e4

Please sign in to comment.