Skip to content

Commit 0243c6f

Browse files
authored
feat: search for git repos two levels deep (#133)
1 parent 218d747 commit 0243c6f

File tree

2 files changed

+163
-1
lines changed

2 files changed

+163
-1
lines changed

src/commands/init.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ impl Command for InitCommand {
4141
let current_dir = std::env::current_dir()?;
4242

4343
for entry in WalkDir::new(&current_dir)
44-
.max_depth(3)
44+
.max_depth(4)
4545
.into_iter()
4646
.filter_map(|e| e.ok())
4747
{

tests/init_command_tests.rs

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,3 +470,165 @@ async fn test_init_command_integration_flow() {
470470
// Note: Config file may not be created if repositories don't have remote URLs
471471
// This is expected behavior in test scenarios
472472
}
473+
474+
#[tokio::test]
475+
#[serial]
476+
async fn test_init_command_discovers_repos_two_levels_deep() {
477+
let temp_dir = TempDir::new().unwrap();
478+
479+
// Create a repository 2 levels deep: ./cloned_repos/level_1/repo
480+
let repo_dir = temp_dir
481+
.path()
482+
.join("cloned_repos")
483+
.join("level_1")
484+
.join("test-repo");
485+
fs::create_dir_all(&repo_dir).unwrap();
486+
fs::create_dir_all(repo_dir.join(".git")).unwrap();
487+
create_git_repo(&repo_dir).unwrap();
488+
489+
// Add a remote URL so the repo will be included in the config
490+
std::process::Command::new("git")
491+
.args([
492+
"remote",
493+
"add",
494+
"origin",
495+
"git@github.com:test/test-repo.git",
496+
])
497+
.current_dir(&repo_dir)
498+
.output()
499+
.unwrap();
500+
501+
let output_path = temp_dir.path().join("two-levels-config.yaml");
502+
let command = InitCommand {
503+
output: output_path.to_string_lossy().to_string(),
504+
overwrite: false,
505+
supplement: false,
506+
};
507+
508+
let context = CommandContext {
509+
config: Config::new(),
510+
tag: vec![],
511+
exclude_tag: vec![],
512+
repos: None,
513+
parallel: false,
514+
};
515+
516+
let original_dir = std::env::current_dir().unwrap();
517+
std::env::set_current_dir(temp_dir.path()).unwrap();
518+
519+
let result = command.execute(&context).await;
520+
521+
std::env::set_current_dir(original_dir).unwrap();
522+
523+
// Should succeed
524+
assert!(result.is_ok());
525+
526+
// Config file should exist with the discovered repo
527+
assert!(output_path.exists());
528+
529+
// Load and verify the config contains the discovered repo
530+
let config = Config::load(&output_path.to_string_lossy()).unwrap();
531+
assert_eq!(config.repositories.len(), 1);
532+
assert_eq!(config.repositories[0].name, "test-repo");
533+
assert_eq!(
534+
config.repositories[0].url,
535+
"git@github.com:test/test-repo.git"
536+
);
537+
assert_eq!(
538+
config.repositories[0].path.as_ref().unwrap(),
539+
"cloned_repos/level_1/test-repo"
540+
);
541+
}
542+
543+
#[tokio::test]
544+
#[serial]
545+
async fn test_init_command_depth_boundary() {
546+
let temp_dir = TempDir::new().unwrap();
547+
548+
// Create repos at different depths to test the boundary
549+
// Level 1: ./repo1 - should be discovered
550+
let repo1_dir = temp_dir.path().join("repo1");
551+
fs::create_dir_all(&repo1_dir).unwrap();
552+
create_git_repo(&repo1_dir).unwrap();
553+
std::process::Command::new("git")
554+
.args(["remote", "add", "origin", "git@github.com:test/repo1.git"])
555+
.current_dir(&repo1_dir)
556+
.output()
557+
.unwrap();
558+
559+
// Level 2: ./dir1/repo2 - should be discovered
560+
let repo2_dir = temp_dir.path().join("dir1").join("repo2");
561+
fs::create_dir_all(&repo2_dir).unwrap();
562+
create_git_repo(&repo2_dir).unwrap();
563+
std::process::Command::new("git")
564+
.args(["remote", "add", "origin", "git@github.com:test/repo2.git"])
565+
.current_dir(&repo2_dir)
566+
.output()
567+
.unwrap();
568+
569+
// Level 3: ./dir1/dir2/repo3 - should be discovered (2 levels deep)
570+
let repo3_dir = temp_dir.path().join("dir1").join("dir2").join("repo3");
571+
fs::create_dir_all(&repo3_dir).unwrap();
572+
create_git_repo(&repo3_dir).unwrap();
573+
std::process::Command::new("git")
574+
.args(["remote", "add", "origin", "git@github.com:test/repo3.git"])
575+
.current_dir(&repo3_dir)
576+
.output()
577+
.unwrap();
578+
579+
// Level 4: ./dir1/dir2/dir3/repo4 - should NOT be discovered (3 levels deep, too deep)
580+
let repo4_dir = temp_dir
581+
.path()
582+
.join("dir1")
583+
.join("dir2")
584+
.join("dir3")
585+
.join("repo4");
586+
fs::create_dir_all(&repo4_dir).unwrap();
587+
create_git_repo(&repo4_dir).unwrap();
588+
std::process::Command::new("git")
589+
.args(["remote", "add", "origin", "git@github.com:test/repo4.git"])
590+
.current_dir(&repo4_dir)
591+
.output()
592+
.unwrap();
593+
594+
let output_path = temp_dir.path().join("depth-boundary-config.yaml");
595+
let command = InitCommand {
596+
output: output_path.to_string_lossy().to_string(),
597+
overwrite: false,
598+
supplement: false,
599+
};
600+
601+
let context = CommandContext {
602+
config: Config::new(),
603+
tag: vec![],
604+
exclude_tag: vec![],
605+
repos: None,
606+
parallel: false,
607+
};
608+
609+
let original_dir = std::env::current_dir().unwrap();
610+
std::env::set_current_dir(temp_dir.path()).unwrap();
611+
612+
let result = command.execute(&context).await;
613+
614+
std::env::set_current_dir(original_dir).unwrap();
615+
616+
// Should succeed
617+
assert!(result.is_ok());
618+
assert!(output_path.exists());
619+
620+
// Load and verify only repos 1, 2, and 3 are discovered (not repo4 which is too deep)
621+
let config = Config::load(&output_path.to_string_lossy()).unwrap();
622+
assert_eq!(config.repositories.len(), 3);
623+
624+
// Verify the discovered repos
625+
let repo_names: Vec<&str> = config
626+
.repositories
627+
.iter()
628+
.map(|r| r.name.as_str())
629+
.collect();
630+
assert!(repo_names.contains(&"repo1"));
631+
assert!(repo_names.contains(&"repo2"));
632+
assert!(repo_names.contains(&"repo3"));
633+
assert!(!repo_names.contains(&"repo4")); // Should not be discovered
634+
}

0 commit comments

Comments
 (0)