diff --git a/gradle/changelog/repo_information_page.yaml b/gradle/changelog/repo_information_page.yaml new file mode 100644 index 0000000000..5ae408085f --- /dev/null +++ b/gradle/changelog/repo_information_page.yaml @@ -0,0 +1,2 @@ +- type: changed + description: Show only relevant information on repository information page ([#1636](https://github.com/scm-manager/scm-manager/pull/1636)) diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigResource.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigResource.java index 69f8815dda..40170a56dd 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigResource.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigResource.java @@ -24,16 +24,19 @@ package sonia.scm.api.v2.resources; +import com.google.common.base.Strings; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.ExampleObject; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.parameters.RequestBody; import io.swagger.v3.oas.annotations.responses.ApiResponse; +import lombok.AllArgsConstructor; import lombok.Getter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.repository.GitRepositoryConfig; +import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryManager; @@ -61,12 +64,14 @@ public class GitRepositoryConfigResource { private final GitRepositoryConfigMapper repositoryConfigMapper; private final RepositoryManager repositoryManager; private final GitRepositoryConfigStoreProvider gitRepositoryConfigStoreProvider; + private final GitRepositoryHandler repositoryHandler; @Inject - public GitRepositoryConfigResource(GitRepositoryConfigMapper repositoryConfigMapper, RepositoryManager repositoryManager, GitRepositoryConfigStoreProvider gitRepositoryConfigStoreProvider) { + public GitRepositoryConfigResource(GitRepositoryConfigMapper repositoryConfigMapper, RepositoryManager repositoryManager, GitRepositoryConfigStoreProvider gitRepositoryConfigStoreProvider, GitRepositoryHandler repositoryHandler) { this.repositoryConfigMapper = repositoryConfigMapper; this.repositoryManager = repositoryManager; this.gitRepositoryConfigStoreProvider = gitRepositoryConfigStoreProvider; + this.repositoryHandler = repositoryHandler; } @GET @@ -100,12 +105,55 @@ public class GitRepositoryConfigResource { public Response getRepositoryConfig(@PathParam("namespace") String namespace, @PathParam("name") String name) { Repository repository = getRepository(namespace, name); RepositoryPermissions.read(repository).check(); - ConfigurationStore repositoryConfigStore = getStore(repository); - GitRepositoryConfig config = repositoryConfigStore.get(); + GitRepositoryConfig config = getStore(repository).get(); GitRepositoryConfigDto dto = repositoryConfigMapper.map(config, repository); return Response.ok(dto).build(); } + @GET + @Path("default-branch") + @Produces(GitVndMediaType.GIT_REPOSITORY_DEFAULT_BRANCH) + @Operation(summary = "Git repository default branch", description = "Returns the default branch for the repository.", tags = "Git") + @ApiResponse( + responseCode = "200", + description = "success", + content = @Content( + mediaType = GitVndMediaType.GIT_REPOSITORY_CONFIG, + schema = @Schema(implementation = GitRepositoryConfigDto.class) + ) + ) + @ApiResponse(responseCode = "401", description = "not authenticated / invalid credentials") + @ApiResponse(responseCode = "403", description = "not authorized, the current user has no privileges to read the repository config") + @ApiResponse( + responseCode = "404", + description = "not found, no repository with the specified namespace and name available", + content = @Content( + mediaType = VndMediaType.ERROR_TYPE, + schema = @Schema(implementation = ErrorDto.class) + )) + @ApiResponse( + responseCode = "500", + description = "internal server error", + content = @Content( + mediaType = VndMediaType.ERROR_TYPE, + schema = @Schema(implementation = ErrorDto.class) + )) + public Response getDefaultBranch(@PathParam("namespace") String namespace, @PathParam("name") String name) { + Repository repository = getRepository(namespace, name); + RepositoryPermissions.read(repository).check(); + GitRepositoryConfig config = getStore(repository).get(); + + String defaultBranch = "main"; + + if (!Strings.isNullOrEmpty(config.getDefaultBranch())) { + defaultBranch = config.getDefaultBranch(); + } else if (!Strings.isNullOrEmpty(repositoryHandler.getConfig().getDefaultBranch())) { + defaultBranch = repositoryHandler.getConfig().getDefaultBranch(); + } + + return Response.ok(new DefaultBranchDto(defaultBranch)).build(); + } + @PUT @Path("/") @Consumes(GitVndMediaType.GIT_REPOSITORY_CONFIG) @@ -167,4 +215,10 @@ public class GitRepositoryConfigResource { private ConfigurationStore getStore(Repository repository) { return gitRepositoryConfigStoreProvider.get(repository); } + + @Getter + @AllArgsConstructor + public static class DefaultBranchDto { + private final String defaultBranch; + } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/RepositoryLinkEnricher.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/RepositoryLinkEnricher.java new file mode 100644 index 0000000000..1fd927abc5 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/RepositoryLinkEnricher.java @@ -0,0 +1,62 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sonia.scm.api.v2.resources; + +import sonia.scm.plugin.Extension; +import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryPermissions; + +import javax.inject.Inject; +import javax.inject.Provider; + +@Extension +@Enrich(Repository.class) +public class RepositoryLinkEnricher implements HalEnricher { + + private final Provider scmPathInfoStore; + + @Inject + public RepositoryLinkEnricher(Provider scmPathInfoStore) { + this.scmPathInfoStore = scmPathInfoStore; + } + + @Override + public void enrich(HalEnricherContext context, HalAppender appender) { + Repository repository = context.oneRequireByType(Repository.class); + + LinkBuilder linkBuilder = new LinkBuilder(scmPathInfoStore.get().get(), GitConfigResource.class, GitRepositoryConfigResource.class); + + if (RepositoryPermissions.read(repository).isPermitted()) { + appender.appendLink("defaultBranch", getDefaultBranchLink(repository, linkBuilder)); + } + } + + private String getDefaultBranchLink(Repository repository, LinkBuilder linkBuilder) { + return linkBuilder + .method("getRepositoryConfig").parameters(repository.getNamespace(), repository.getName()) + .method("getDefaultBranch").parameters() + .href(); + } +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitVndMediaType.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitVndMediaType.java index 61053e61a3..5a8ef15588 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitVndMediaType.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitVndMediaType.java @@ -27,6 +27,7 @@ package sonia.scm.web; public class GitVndMediaType { public static final String GIT_CONFIG = VndMediaType.PREFIX + "gitConfig" + VndMediaType.SUFFIX; public static final String GIT_REPOSITORY_CONFIG = VndMediaType.PREFIX + "gitConfig" + VndMediaType.SUFFIX; + public static final String GIT_REPOSITORY_DEFAULT_BRANCH = VndMediaType.PREFIX + "gitDefaultBranch" + VndMediaType.SUFFIX; private GitVndMediaType() { } diff --git a/scm-plugins/scm-git-plugin/src/main/js/CloneInformation.tsx b/scm-plugins/scm-git-plugin/src/main/js/CloneInformation.tsx index c3b1c5b36f..b0cf16a55a 100644 --- a/scm-plugins/scm-git-plugin/src/main/js/CloneInformation.tsx +++ b/scm-plugins/scm-git-plugin/src/main/js/CloneInformation.tsx @@ -21,57 +21,93 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -import React from "react"; -import { WithTranslation, withTranslation } from "react-i18next"; -import { Repository } from "@scm-manager/ui-types"; +import React, { FC, useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { Link, Repository } from "@scm-manager/ui-types"; +import { apiClient } from "@scm-manager/ui-components"; -type Props = WithTranslation & { +type Props = { url: string; repository: Repository; }; -class CloneInformation extends React.Component { - render() { - const { url, repository, t } = this.props; +const CloneInformation: FC = ({ url, repository }) => { + const [t] = useTranslation("plugins"); + const [defaultBranch, setDefaultBranch] = useState("main"); + const [emptyRepository, setEmptyRepository] = useState(); - return ( -
-

{t("scm-git-plugin.information.clone")}

-
-          git clone {url}
-        
-

{t("scm-git-plugin.information.create")}

-
-          
-            git init {repository.name}
-            
- cd {repository.name} -
- echo "# {repository.name} - " > README.md -
- git add README.md -
- git commit -m "Add readme" -
- git remote add origin {url} -
- git push -u origin master -
-
-
-

{t("scm-git-plugin.information.replace")}

-
-          
-            git remote add origin {url}
-            
- git push -u origin master -
-
-
-
- ); - } -} + useEffect(() => { + if (repository) { + apiClient + .get((repository._links.changesets as Link).href + "?limit=1") + .then(r => r.json()) + .then(result => { + const empty = result._embedded.changesets.length === 0; + setEmptyRepository(empty); + }); + } + }, [repository]); -export default withTranslation("plugins")(CloneInformation); + useEffect(() => { + if (repository) { + apiClient + .get((repository._links.defaultBranch as Link).href) + .then(r => r.json()) + .then(r => r.defaultBranch && setDefaultBranch(r.defaultBranch)); + } + }, [repository]); + + return ( +
+

{t("scm-git-plugin.information.clone")}

+
+        
+          git clone {url}
+          
+ cd {repository.name} + {emptyRepository && ( + <> +
+ git checkout -b {defaultBranch} + + )} +
+
+ {emptyRepository && ( + <> +

{t("scm-git-plugin.information.create")}

+
+            
+              git init {repository.name}
+              
+ cd {repository.name} +
+ git checkout -b {defaultBranch} +
+ echo "# {repository.name} + " > README.md +
+ git add README.md +
+ git commit -m "Add readme" +
+ git remote add origin {url} +
+ git push -u origin {defaultBranch} +
+
+
+ + )} +

{t("scm-git-plugin.information.replace")}

+
+        
+          git remote add origin {url}
+          
+
+
+
+ ); +}; + +export default CloneInformation; diff --git a/scm-plugins/scm-git-plugin/src/main/js/index.ts b/scm-plugins/scm-git-plugin/src/main/js/index.ts index 49d85cb8bb..c8108c84dd 100644 --- a/scm-plugins/scm-git-plugin/src/main/js/index.ts +++ b/scm-plugins/scm-git-plugin/src/main/js/index.ts @@ -22,7 +22,6 @@ * SOFTWARE. */ -import React from "react"; import { binder } from "@scm-manager/ui-extensions"; import ProtocolInformation from "./ProtocolInformation"; import GitAvatar from "./GitAvatar"; diff --git a/scm-plugins/scm-git-plugin/src/main/resources/locales/de/plugins.json b/scm-plugins/scm-git-plugin/src/main/resources/locales/de/plugins.json index 05aa65485b..1b667398b3 100644 --- a/scm-plugins/scm-git-plugin/src/main/resources/locales/de/plugins.json +++ b/scm-plugins/scm-git-plugin/src/main/resources/locales/de/plugins.json @@ -3,7 +3,7 @@ "information": { "clone": "Repository klonen", "create": "Neues Repository erstellen", - "replace": "Ein bestehendes Repository aktualisieren", + "replace": "Quelle zum bestehenden Repository hinzufügen", "fetch": "Remote-Änderungen herunterladen", "checkout": "Branch wechseln", "checkoutTag": "Tag als neuen Branch auschecken", diff --git a/scm-plugins/scm-git-plugin/src/main/resources/locales/en/plugins.json b/scm-plugins/scm-git-plugin/src/main/resources/locales/en/plugins.json index c28cb82e0c..74e2f1be47 100644 --- a/scm-plugins/scm-git-plugin/src/main/resources/locales/en/plugins.json +++ b/scm-plugins/scm-git-plugin/src/main/resources/locales/en/plugins.json @@ -3,7 +3,7 @@ "information": { "clone": "Clone the Repository", "create": "Create a New Repository", - "replace": "Push an Existing Repository", + "replace": "Add Remote Origin to an Existing Repository", "fetch": "Get Remote Changes", "checkout": "Switch Branch", "checkoutTag": "Checkout Tag as New Branch", diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigResourceTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigResourceTest.java index e3041dd447..c861674175 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigResourceTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigResourceTest.java @@ -74,7 +74,7 @@ public class GitConfigResourceTest { @Rule public ShiroRule shiro = new ShiroRule(); - private RestDispatcher dispatcher = new RestDispatcher(); + private final RestDispatcher dispatcher = new RestDispatcher(); private final URI baseUri = URI.create("/"); @@ -106,7 +106,7 @@ public class GitConfigResourceTest { public void prepareEnvironment() { GitConfig gitConfig = createConfiguration(); when(repositoryHandler.getConfig()).thenReturn(gitConfig); - GitRepositoryConfigResource gitRepositoryConfigResource = new GitRepositoryConfigResource(repositoryConfigMapper, repositoryManager, new GitRepositoryConfigStoreProvider(configurationStoreFactory)); + GitRepositoryConfigResource gitRepositoryConfigResource = new GitRepositoryConfigResource(repositoryConfigMapper, repositoryManager, new GitRepositoryConfigStoreProvider(configurationStoreFactory), repositoryHandler); GitConfigResource gitConfigResource = new GitConfigResource(dtoToConfigMapper, configToDtoMapper, repositoryHandler, of(gitRepositoryConfigResource)); dispatcher.addSingletonResource(gitConfigResource); when(scmPathInfoStore.get().getApiRestUri()).thenReturn(baseUri); @@ -251,6 +251,71 @@ public class GitConfigResourceTest { .isEqualTo("new"); } + @Test + @SubjectAware(username = "readOnly") + public void shouldGetDefaultBranchFromRepoConfig() throws URISyntaxException, UnsupportedEncodingException { + when(repositoryManager.get(new NamespaceAndName("space", "X"))).thenReturn(new Repository("id", "git", "space", "X")); + when(configurationStore.get()).thenReturn(new GitRepositoryConfig("default")); + MockHttpRequest request = MockHttpRequest + .get("/" + GitConfigResource.GIT_CONFIG_PATH_V2 + "/space/X/default-branch") + .contentType(GitVndMediaType.GIT_REPOSITORY_CONFIG); + MockHttpResponse response = new MockHttpResponse(); + + dispatcher.invoke(request, response); + + assertEquals(HttpServletResponse.SC_OK, response.getStatus()); + assertEquals("{\"defaultBranch\":\"default\"}", response.getContentAsString()); + } + + @Test + @SubjectAware(username = "readOnly") + public void shouldGetDefaultBranchFromGlobalConfig() throws URISyntaxException, UnsupportedEncodingException { + when(repositoryManager.get(new NamespaceAndName("space", "X"))).thenReturn(new Repository("id", "git", "space", "X")); + when(configurationStore.get()).thenReturn(new GitRepositoryConfig()); + GitConfig globalGitConfig = createConfiguration(); + globalGitConfig.setDefaultBranch("global-default"); + when(repositoryHandler.getConfig()).thenReturn(globalGitConfig); + MockHttpRequest request = MockHttpRequest + .get("/" + GitConfigResource.GIT_CONFIG_PATH_V2 + "/space/X/default-branch") + .contentType(GitVndMediaType.GIT_REPOSITORY_CONFIG); + MockHttpResponse response = new MockHttpResponse(); + + dispatcher.invoke(request, response); + + assertEquals(HttpServletResponse.SC_OK, response.getStatus()); + assertEquals("{\"defaultBranch\":\"global-default\"}", response.getContentAsString()); + } + + @Test + @SubjectAware(username = "readOnly") + public void shouldGetFallbackDefaultBranchIfBothConfigsEmpty() throws URISyntaxException, UnsupportedEncodingException { + when(repositoryManager.get(new NamespaceAndName("space", "X"))).thenReturn(new Repository("id", "git", "space", "X")); + when(configurationStore.get()).thenReturn(new GitRepositoryConfig()); + when(repositoryHandler.getConfig()).thenReturn(createConfiguration()); + MockHttpRequest request = MockHttpRequest + .get("/" + GitConfigResource.GIT_CONFIG_PATH_V2 + "/space/X/default-branch") + .contentType(GitVndMediaType.GIT_REPOSITORY_CONFIG); + MockHttpResponse response = new MockHttpResponse(); + + dispatcher.invoke(request, response); + + assertEquals(HttpServletResponse.SC_OK, response.getStatus()); + assertEquals("{\"defaultBranch\":\"main\"}", response.getContentAsString()); + } + + @Test + public void shouldThrowAuthorizationExceptionIfNotPermittedToGetDefaultBranch() throws URISyntaxException { + when(repositoryManager.get(new NamespaceAndName("space", "X"))).thenReturn(new Repository("id", "git", "space", "X")); + MockHttpRequest request = MockHttpRequest + .get("/" + GitConfigResource.GIT_CONFIG_PATH_V2 + "/space/X/default-branch") + .contentType(GitVndMediaType.GIT_REPOSITORY_CONFIG); + MockHttpResponse response = new MockHttpResponse(); + + dispatcher.invoke(request, response); + + assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus()); + } + private MockHttpResponse get() throws URISyntaxException { MockHttpRequest request = MockHttpRequest.get("/" + GitConfigResource.GIT_CONFIG_PATH_V2); MockHttpResponse response = new MockHttpResponse(); diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/RepositoryLinkEnricherTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/RepositoryLinkEnricherTest.java new file mode 100644 index 0000000000..501afedb92 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/RepositoryLinkEnricherTest.java @@ -0,0 +1,90 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sonia.scm.api.v2.resources; + +import com.google.inject.util.Providers; +import org.github.sdorra.jse.ShiroExtension; +import org.github.sdorra.jse.SubjectAware; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryTestData; + +import javax.inject.Provider; +import java.net.URI; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +@ExtendWith(ShiroExtension.class) +@ExtendWith(MockitoExtension.class) +@SubjectAware( + value = "trillian" +) +class RepositoryLinkEnricherTest { + + private static final Repository REPOSITORY = RepositoryTestData.create42Puzzle(); + + private RepositoryLinkEnricher repositoryLinkEnricher; + + @Mock + private HalAppender appender; + + @BeforeEach + void initEnricher() { + ScmPathInfoStore scmPathInfoStore = new ScmPathInfoStore(); + scmPathInfoStore.set(() -> URI.create("/api/")); + Provider scmPathInfoStoreProvider = Providers.of(scmPathInfoStore); + repositoryLinkEnricher = new RepositoryLinkEnricher(scmPathInfoStoreProvider); + REPOSITORY.setId("id-1"); + } + + @Test + void shouldNotAppendLinkIfNotPermitted() { + HalEnricherContext context = HalEnricherContext.of(REPOSITORY); + + repositoryLinkEnricher.enrich(context, appender); + + verify(appender, never()).appendLink(eq("defaultBranch"), any(String.class)); + } + + @Test + @SubjectAware( + permissions = "repository:read:id-1" + ) + void shouldAppendDefaultBranchLink() { + HalEnricherContext context = HalEnricherContext.of(REPOSITORY); + + repositoryLinkEnricher.enrich(context, appender); + + verify(appender).appendLink("defaultBranch", "/api/v2/config/git/hitchhiker/42Puzzle/default-branch"); + } + +} diff --git a/scm-plugins/scm-hg-plugin/src/main/js/ProtocolInformation.tsx b/scm-plugins/scm-hg-plugin/src/main/js/ProtocolInformation.tsx index 5d964336ee..9a5a7e68ff 100644 --- a/scm-plugins/scm-hg-plugin/src/main/js/ProtocolInformation.tsx +++ b/scm-plugins/scm-hg-plugin/src/main/js/ProtocolInformation.tsx @@ -21,67 +21,84 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -import React from "react"; -import { WithTranslation, withTranslation } from "react-i18next"; -import { Repository } from "@scm-manager/ui-types"; -import { repositories } from "@scm-manager/ui-components"; +import React, { FC, useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { Link, Repository } from "@scm-manager/ui-types"; +import { apiClient, repositories } from "@scm-manager/ui-components"; -type Props = WithTranslation & { +type Props = { repository: Repository; }; -class ProtocolInformation extends React.Component { - render() { - const { repository, t } = this.props; - const href = repositories.getProtocolLinkByType(repository, "http"); - if (!href) { - return null; - } - return ( -
-

{t("scm-hg-plugin.information.clone")}

-
-          hg clone {href}
-        
-

{t("scm-hg-plugin.information.create")}

-
-          
-            hg init {repository.name}
-            
- cd {repository.name} -
- echo "[paths]" > .hg/hgrc -
- echo "default = {href} - " >> .hg/hgrc -
- echo "# {repository.name} - " > README.md -
- hg add README.md -
- hg commit -m "added readme" -
-
- hg push -
-
-
-

{t("scm-hg-plugin.information.replace")}

-
-          
-            # add the repository url as default to your .hg/hgrc e.g:
-            
- default = {href} -
- # push to remote repository -
- hg push -
-
-
- ); - } -} +const ProtocolInformation: FC = ({ repository }) => { + const [t] = useTranslation("plugins"); + const [emptyRepository, setEmptyRepository] = useState(); -export default withTranslation("plugins")(ProtocolInformation); + const href = repositories.getProtocolLinkByType(repository, "http"); + + useEffect(() => { + if (repository) { + apiClient + .get((repository._links.changesets as Link).href) + .then(r => r.json()) + .then(result => { + const empty = result._embedded.changesets.length === 0; + setEmptyRepository(empty); + }); + } + }, [repository]); + + if (!href) { + return null; + } + return ( +
+

{t("scm-hg-plugin.information.clone")}

+
+        hg clone {href}
+      
+ {emptyRepository && ( + <> +

{t("scm-hg-plugin.information.create")}

+
+            
+              hg init {repository.name}
+              
+ cd {repository.name} +
+ echo "[paths]" > .hg/hgrc +
+ echo "default = {href} + " >> .hg/hgrc +
+ echo "# {repository.name} + " > README.md +
+ hg add README.md +
+ hg commit -m "added readme" +
+
+ hg push +
+
+
+ + )} +

{t("scm-hg-plugin.information.replace")}

+
+        
+          # add the repository url as default to your .hg/hgrc e.g:
+          
+ default = {href} +
+ # push to remote repository +
+ hg push +
+
+
+ ); +}; + +export default ProtocolInformation; diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/locales/de/plugins.json b/scm-plugins/scm-hg-plugin/src/main/resources/locales/de/plugins.json index 0fed88a8f3..0ced68fa2c 100644 --- a/scm-plugins/scm-hg-plugin/src/main/resources/locales/de/plugins.json +++ b/scm-plugins/scm-hg-plugin/src/main/resources/locales/de/plugins.json @@ -3,7 +3,7 @@ "information": { "clone" : "Repository klonen", "create" : "Neues Repository erstellen", - "replace" : "Ein bestehendes Repository aktualisieren", + "replace" : "Quelle zum bestehenden Repository hinzufügen", "fetch": "Remote-Änderungen herunterladen", "checkout": "Branch wechseln", "checkoutTag": "Tag auschecken" diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/locales/en/plugins.json b/scm-plugins/scm-hg-plugin/src/main/resources/locales/en/plugins.json index 4eff635133..75e2f0b582 100644 --- a/scm-plugins/scm-hg-plugin/src/main/resources/locales/en/plugins.json +++ b/scm-plugins/scm-hg-plugin/src/main/resources/locales/en/plugins.json @@ -3,7 +3,7 @@ "information": { "clone" : "Clone the repository", "create" : "Create a New Repository", - "replace" : "Push an Existing Repository", + "replace" : "Add Remote Origin to an Existing Repository", "fetch": "Get Remote Changes", "checkout": "Switch Branch", "checkoutTag": "Checkout Tag"