Skip to content

Commit

Permalink
fix(forge): init a git repo at root during init unless explicitely st…
Browse files Browse the repository at this point in the history
…ated
  • Loading branch information
0xvv committed Jan 17, 2025
1 parent 55badd4 commit 19cd229
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 5 deletions.
4 changes: 4 additions & 0 deletions crates/cli/src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,10 @@ impl<'a> Git<'a> {
self.cmd().args(["rev-parse", "--is-inside-work-tree"]).status().map(|s| s.success())
}

pub fn is_repo_root(self) -> Result<bool> {
self.cmd().args(["rev-parse", "--show-cdup"]).exec().map(|out| out.stdout.is_empty())
}

pub fn is_clean(self) -> Result<bool> {
self.cmd().args(["status", "--porcelain"]).exec().map(|out| out.stdout.is_empty())
}
Expand Down
22 changes: 17 additions & 5 deletions crates/forge/bin/cmd/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,18 @@ pub struct InitArgs {
#[arg(long, conflicts_with = "template")]
pub vscode: bool,

/// Use the parent git repository instead of initializing a new one.
/// Only valid if the target is in a git repository.
#[arg(long, conflicts_with = "template")]
pub use_parent_git: bool,

#[command(flatten)]
pub install: DependencyInstallOpts,
}

impl InitArgs {
pub fn run(self) -> Result<()> {
let Self { root, template, branch, install, offline, force, vscode } = self;
let Self { root, template, branch, install, offline, force, vscode, use_parent_git } = self;
let DependencyInstallOpts { shallow, no_git, no_commit } = install;

// create the root dir if it does not exist
Expand Down Expand Up @@ -138,7 +143,7 @@ impl InitArgs {

// set up the repo
if !no_git {
init_git_repo(git, no_commit)?;
init_git_repo(git, no_commit, use_parent_git)?;
}

// install forge-std
Expand All @@ -163,15 +168,22 @@ impl InitArgs {
}
}

/// Initialises `root` as a git repository, if it isn't one already.
/// Initialises `root` as a git repository, if it isn't one already, unless 'use_parent_git' is
/// true.
///
/// Creates `.gitignore` and `.github/workflows/test.yml`, if they don't exist already.
///
/// Commits everything in `root` if `no_commit` is false.
fn init_git_repo(git: Git<'_>, no_commit: bool) -> Result<()> {
/// Commits everything if `no_commit` is false.
fn init_git_repo(git: Git<'_>, no_commit: bool, use_parent_git: bool) -> Result<()> {
// git init
// if not in a git repo, initialize one
if !git.is_in_repo()? {
git.init()?;
} else {
// if target is not the repo root init a new one unless `use_parent_git` is true
if !git.is_repo_root()? && !use_parent_git {
git.init()?;
}
}

// .gitignore
Expand Down
47 changes: 47 additions & 0 deletions crates/forge/tests/cli/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,53 @@ Warning: Target directory is not empty, but `--force` was specified
assert_eq!(gitignore, "not foundry .gitignore");
});

// `forge init --use-parent-git` works on already initialized git repository
forgetest!(can_init_using_parent_repo, |prj, cmd| {
let root = prj.root();

// initialize new git repo
let status = Command::new("git")
.arg("init")
.current_dir(root)
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.expect("could not run git init");
assert!(status.success());
assert!(root.join(".git").exists());

prj.create_file("README.md", "non-empty dir");
prj.create_file(".gitignore", "not foundry .gitignore");

let folder = "foundry-folder";
cmd.arg("init").arg(folder).arg("--force").arg("--use-parent-git").assert_success().stdout_eq(
str![[r#"
Initializing [..]...
Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None)
Installed forge-std[..]
Initialized forge project
"#]],
);

assert!(root.join(folder).join("lib/forge-std").exists());

// not overwritten
let gitignore = root.join(".gitignore");
let gitignore = fs::read_to_string(gitignore).unwrap();
assert_eq!(gitignore, "not foundry .gitignore");

// submodules are registered at root
let gitmodules = root.join(".gitmodules");
let gitmodules = fs::read_to_string(gitmodules).unwrap();
assert!(gitmodules.contains(
"
path = foundry-folder/lib/forge-std
url = https://github.com/foundry-rs/forge-std
"
));
});

// Checks that remappings.txt and .vscode/settings.json is generated
forgetest!(can_init_vscode, |prj, cmd| {
prj.wipe();
Expand Down

0 comments on commit 19cd229

Please sign in to comment.