diff --git a/src/main/java/be/seeseepuff/webgit/controller/HomeController.java b/src/main/java/be/seeseepuff/webgit/controller/HomeController.java index a3a2c6e..d9118f1 100644 --- a/src/main/java/be/seeseepuff/webgit/controller/HomeController.java +++ b/src/main/java/be/seeseepuff/webgit/controller/HomeController.java @@ -52,8 +52,10 @@ public class HomeController } @PostMapping("/clone") - public String cloneRepo(@RequestParam String url, @RequestParam String name) throws GitAPIException, IOException + public String cloneRepo(@RequestParam String url, @RequestParam(required = false) String name) throws GitAPIException, IOException { + if (name == null || name.isBlank()) + name = gitService.deriveRepositoryName(url); gitService.cloneRepository(url, name); return "redirect:/?repo=" + name; } diff --git a/src/main/java/be/seeseepuff/webgit/service/GitService.java b/src/main/java/be/seeseepuff/webgit/service/GitService.java index 117d61f..09b3d2e 100644 --- a/src/main/java/be/seeseepuff/webgit/service/GitService.java +++ b/src/main/java/be/seeseepuff/webgit/service/GitService.java @@ -22,8 +22,20 @@ public class GitService { private final WebgitProperties properties; + public String deriveRepositoryName(String url) + { + String path = url.replaceAll("[/\\\\]+$", ""); + int lastSep = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\')); + String base = lastSep >= 0 ? path.substring(lastSep + 1) : path; + if (base.endsWith(".git")) + base = base.substring(0, base.length() - 4); + return base; + } + public void cloneRepository(String url, String name) throws GitAPIException, IOException { + if (name == null || name.isBlank()) + name = deriveRepositoryName(url); Path worktree = properties.getWorktreePath().resolve(name); Path gitDir = properties.getGitDirPath().resolve(name); diff --git a/src/main/java/be/seeseepuff/webgit/telnet/TelnetSession.java b/src/main/java/be/seeseepuff/webgit/telnet/TelnetSession.java index df2c21f..f5b1c2b 100644 --- a/src/main/java/be/seeseepuff/webgit/telnet/TelnetSession.java +++ b/src/main/java/be/seeseepuff/webgit/telnet/TelnetSession.java @@ -88,11 +88,12 @@ public class TelnetSession implements Runnable if (url == null || url.isBlank()) return; - out.print("Name: "); + String defaultName = gitService.deriveRepositoryName(url.trim()); + out.print("Name [" + defaultName + "]: "); out.flush(); String name = in.readLine(); if (name == null || name.isBlank()) - return; + name = defaultName; gitService.cloneRepository(url.trim(), name.trim()); out.println("Cloned successfully."); diff --git a/src/test/java/be/seeseepuff/webgit/WebgitApplicationTests.java b/src/test/java/be/seeseepuff/webgit/WebgitApplicationTests.java index 2c38a47..bbf4d16 100644 --- a/src/test/java/be/seeseepuff/webgit/WebgitApplicationTests.java +++ b/src/test/java/be/seeseepuff/webgit/WebgitApplicationTests.java @@ -2,8 +2,10 @@ package be.seeseepuff.webgit; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.TestPropertySource; -@SpringBootTest +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@TestPropertySource(properties = "webgit.telnet.enabled=false") class WebgitApplicationTests { @Test diff --git a/src/test/java/be/seeseepuff/webgit/controller/HomeControllerTest.java b/src/test/java/be/seeseepuff/webgit/controller/HomeControllerTest.java index 2706e6c..b95e0a8 100644 --- a/src/test/java/be/seeseepuff/webgit/controller/HomeControllerTest.java +++ b/src/test/java/be/seeseepuff/webgit/controller/HomeControllerTest.java @@ -115,4 +115,31 @@ class HomeControllerTest verify(gitService).cloneRepository("https://example.com/repo.git", "myrepo"); } + + @Test + void cloneWithEmptyNameDerivesFromUrl() throws Exception + { + when(gitService.deriveRepositoryName("https://example.com/repo.git")).thenReturn("repo"); + + mockMvc.perform(post("/clone") + .param("url", "https://example.com/repo.git") + .param("name", "")) + .andExpect(status().is3xxRedirection()) + .andExpect(redirectedUrl("/?repo=repo")); + + verify(gitService).cloneRepository("https://example.com/repo.git", "repo"); + } + + @Test + void cloneWithNoNameParamDerivesFromUrl() throws Exception + { + when(gitService.deriveRepositoryName("https://example.com/project.git")).thenReturn("project"); + + mockMvc.perform(post("/clone") + .param("url", "https://example.com/project.git")) + .andExpect(status().is3xxRedirection()) + .andExpect(redirectedUrl("/?repo=project")); + + verify(gitService).cloneRepository("https://example.com/project.git", "project"); + } } diff --git a/src/test/java/be/seeseepuff/webgit/service/GitServiceTest.java b/src/test/java/be/seeseepuff/webgit/service/GitServiceTest.java index 88986e3..fe54186 100644 --- a/src/test/java/be/seeseepuff/webgit/service/GitServiceTest.java +++ b/src/test/java/be/seeseepuff/webgit/service/GitServiceTest.java @@ -250,4 +250,53 @@ class GitServiceTest assertDoesNotThrow(() -> gitService.pull("myrepo")); } + + @Test + void deriveNameFromHttpsUrl() + { + assertEquals("my-project", gitService.deriveRepositoryName("https://github.com/user/my-project.git")); + } + + @Test + void deriveNameFromUrlWithoutGitSuffix() + { + assertEquals("repo", gitService.deriveRepositoryName("https://github.com/user/repo")); + } + + @Test + void deriveNameFromUrlWithTrailingSlash() + { + assertEquals("repo", gitService.deriveRepositoryName("https://github.com/user/repo/")); + } + + @Test + void deriveNameFromSshUrl() + { + assertEquals("project", gitService.deriveRepositoryName("git@github.com:user/project.git")); + } + + @Test + void deriveNameFromBareName() + { + assertEquals("foo", gitService.deriveRepositoryName("foo.git")); + } + + @Test + void cloneWithBlankNameDerivesFromUrl() throws GitAPIException, IOException + { + gitService.cloneRepository(bareRemote.toUri().toString(), ""); + + String expectedName = gitService.deriveRepositoryName(bareRemote.toUri().toString()); + assertTrue(Files.exists(worktreePath.resolve(expectedName))); + assertTrue(Files.exists(gitDirPath.resolve(expectedName))); + } + + @Test + void cloneWithNullNameDerivesFromUrl() throws GitAPIException, IOException + { + gitService.cloneRepository(bareRemote.toUri().toString(), null); + + String expectedName = gitService.deriveRepositoryName(bareRemote.toUri().toString()); + assertTrue(Files.exists(worktreePath.resolve(expectedName))); + } } diff --git a/src/test/java/be/seeseepuff/webgit/telnet/TelnetSessionTest.java b/src/test/java/be/seeseepuff/webgit/telnet/TelnetSessionTest.java index bac7330..26ea8c9 100644 --- a/src/test/java/be/seeseepuff/webgit/telnet/TelnetSessionTest.java +++ b/src/test/java/be/seeseepuff/webgit/telnet/TelnetSessionTest.java @@ -72,7 +72,9 @@ class TelnetSessionTest @Test void cloneRepository() throws IOException, GitAPIException { + when(gitService.deriveRepositoryName("https://example.com/repo.git")).thenReturn("repo"); String output = runSession("2\nhttps://example.com/repo.git\nmyrepo\nq\n"); + assertTrue(output.contains("Name [repo]:")); assertTrue(output.contains("Cloned successfully.")); verify(gitService).cloneRepository("https://example.com/repo.git", "myrepo"); } @@ -85,10 +87,13 @@ class TelnetSessionTest } @Test - void cloneRepositoryEmptyName() + void cloneRepositoryEmptyNameUsesDefault() throws IOException, GitAPIException { + when(gitService.deriveRepositoryName("https://example.com/repo.git")).thenReturn("repo"); String output = runSession("2\nhttps://example.com/repo.git\n\nq\n"); - assertFalse(output.contains("Cloned successfully.")); + assertTrue(output.contains("Name [repo]:")); + assertTrue(output.contains("Cloned successfully.")); + verify(gitService).cloneRepository("https://example.com/repo.git", "repo"); } @Test @@ -521,10 +526,12 @@ class TelnetSessionTest } @Test - void cloneNullName() + void cloneNullName() throws IOException, GitAPIException { - // URL is provided but name input stream ends + // URL is provided but name input stream ends — uses default + when(gitService.deriveRepositoryName("https://example.com/repo.git")).thenReturn("repo"); String output = runSession("2\nhttps://example.com/repo.git\n"); - assertTrue(output.contains("Goodbye!")); + assertTrue(output.contains("Cloned successfully.")); + verify(gitService).cloneRepository("https://example.com/repo.git", "repo"); } }