diff --git a/src/main/java/be/seeseepuff/webgit/controller/RepoController.java b/src/main/java/be/seeseepuff/webgit/controller/RepoController.java index a45a173..4d2b13a 100644 --- a/src/main/java/be/seeseepuff/webgit/controller/RepoController.java +++ b/src/main/java/be/seeseepuff/webgit/controller/RepoController.java @@ -44,9 +44,10 @@ public class RepoController } @GetMapping("/repo/{name}/remote") - public String remote(@PathVariable String name, Model model) + public String remote(@PathVariable String name, Model model) throws IOException { model.addAttribute("name", name); + model.addAttribute("remotes", gitService.listRemotes(name)); return "remote"; } @@ -106,6 +107,13 @@ public class RepoController return "redirect:/repo/" + name + "/remote"; } + @PostMapping("/repo/{name}/update-remote") + public String updateRemote(@PathVariable String name, @RequestParam String remote, @RequestParam String url) throws IOException + { + gitService.updateRemoteUrl(name, remote, url); + return "redirect:/repo/" + name + "/remote"; + } + @PostMapping("/repo/{name}/delete") public String delete(@PathVariable String name) throws IOException { diff --git a/src/main/java/be/seeseepuff/webgit/service/GitService.java b/src/main/java/be/seeseepuff/webgit/service/GitService.java index 37481fd..414f78c 100644 --- a/src/main/java/be/seeseepuff/webgit/service/GitService.java +++ b/src/main/java/be/seeseepuff/webgit/service/GitService.java @@ -13,7 +13,9 @@ import org.springframework.stereotype.Service; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.stream.Stream; @Service @@ -216,6 +218,32 @@ public class GitService } } + public Map listRemotes(String name) throws IOException + { + try (Git git = openRepository(name)) + { + StoredConfig config = git.getRepository().getConfig(); + var remoteNames = config.getSubsections("remote"); + Map remotes = new LinkedHashMap<>(); + for (String remote : remoteNames) + { + String url = config.getString("remote", remote, "url"); + remotes.put(remote, url != null ? url : ""); + } + return remotes; + } + } + + public void updateRemoteUrl(String name, String remote, String url) throws IOException + { + try (Git git = openRepository(name)) + { + StoredConfig config = git.getRepository().getConfig(); + config.setString("remote", remote, "url", url); + config.save(); + } + } + public void push(String name) throws IOException, GitAPIException { try (Git git = openRepository(name)) diff --git a/src/main/resources/templates/remote.html b/src/main/resources/templates/remote.html index ac6b0ad..b84538e 100644 --- a/src/main/resources/templates/remote.html +++ b/src/main/resources/templates/remote.html @@ -4,10 +4,24 @@ Remote -

Remote

+

Remotes

- +
+ + + + + + + +
NameURL
+
+ + + +
+
@@ -21,5 +35,7 @@
+

No remotes configured.

+ diff --git a/src/test/java/be/seeseepuff/webgit/controller/RepoControllerTest.java b/src/test/java/be/seeseepuff/webgit/controller/RepoControllerTest.java index 059b4ab..6401e41 100644 --- a/src/test/java/be/seeseepuff/webgit/controller/RepoControllerTest.java +++ b/src/test/java/be/seeseepuff/webgit/controller/RepoControllerTest.java @@ -74,12 +74,26 @@ class RepoControllerTest } @Test - void remotePageLoads() throws Exception + void remotePageShowsRemotes() throws Exception { + when(gitService.listRemotes("myrepo")).thenReturn(java.util.Map.of("origin", "https://example.com/repo.git")); + mockMvc.perform(get("/repo/myrepo/remote")) .andExpect(status().isOk()) .andExpect(view().name("remote")) - .andExpect(model().attribute("name", "myrepo")); + .andExpect(model().attribute("name", "myrepo")) + .andExpect(content().string(org.hamcrest.Matchers.containsString("origin"))) + .andExpect(content().string(org.hamcrest.Matchers.containsString("https://example.com/repo.git"))); + } + + @Test + void remotePageShowsNoRemotes() throws Exception + { + when(gitService.listRemotes("myrepo")).thenReturn(java.util.Map.of()); + + mockMvc.perform(get("/repo/myrepo/remote")) + .andExpect(status().isOk()) + .andExpect(content().string(org.hamcrest.Matchers.containsString("No remotes configured."))); } @Test @@ -168,6 +182,18 @@ class RepoControllerTest verify(gitService).pull("myrepo"); } + @Test + void updateRemoteRedirectsToRemote() throws Exception + { + mockMvc.perform(post("/repo/myrepo/update-remote") + .param("remote", "origin") + .param("url", "https://new-url.com/repo.git")) + .andExpect(status().is3xxRedirection()) + .andExpect(redirectedUrl("/repo/myrepo/remote")); + + verify(gitService).updateRemoteUrl("myrepo", "origin", "https://new-url.com/repo.git"); + } + @Test void deleteRedirectsToRoot() throws Exception { diff --git a/src/test/java/be/seeseepuff/webgit/service/GitServiceTest.java b/src/test/java/be/seeseepuff/webgit/service/GitServiceTest.java index d97fa89..8adb733 100644 --- a/src/test/java/be/seeseepuff/webgit/service/GitServiceTest.java +++ b/src/test/java/be/seeseepuff/webgit/service/GitServiceTest.java @@ -311,4 +311,26 @@ class GitServiceTest { assertThrows(IllegalArgumentException.class, () -> gitService.cloneRepository(".git", null)); } + + @Test + void listRemotesReturnsConfiguredRemotes() throws GitAPIException, IOException + { + gitService.cloneRepository(bareRemote.toUri().toString(), "myrepo"); + + var remotes = gitService.listRemotes("myrepo"); + assertEquals(1, remotes.size()); + assertTrue(remotes.containsKey("origin")); + assertEquals(bareRemote.toUri().toString(), remotes.get("origin")); + } + + @Test + void updateRemoteUrlChangesUrl() throws GitAPIException, IOException + { + gitService.cloneRepository(bareRemote.toUri().toString(), "myrepo"); + + gitService.updateRemoteUrl("myrepo", "origin", "https://new-url.com/repo.git"); + + var remotes = gitService.listRemotes("myrepo"); + assertEquals("https://new-url.com/repo.git", remotes.get("origin")); + } }