From 8927d56b5cf16e35973d57c69548d58cbd6ecbf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maren=20S=C3=BCwer?= Date: Wed, 12 Dec 2018 09:40:37 +0100 Subject: [PATCH 01/76] do not create new error when error is catched --- scm-ui/src/config/modules/config.js | 14 ++---- scm-ui/src/groups/modules/groups.js | 25 +++++------ scm-ui/src/repos/modules/repos.js | 5 +-- .../repos/permissions/modules/permissions.js | 44 +++++++------------ scm-ui/src/repos/sources/modules/sources.js | 3 +- scm-ui/src/users/modules/users.js | 27 +++--------- 6 files changed, 39 insertions(+), 79 deletions(-) diff --git a/scm-ui/src/config/modules/config.js b/scm-ui/src/config/modules/config.js index 352afefb70..2d14fcfea6 100644 --- a/scm-ui/src/config/modules/config.js +++ b/scm-ui/src/config/modules/config.js @@ -32,9 +32,8 @@ export function fetchConfig(link: string) { .then(data => { dispatch(fetchConfigSuccess(data)); }) - .catch(cause => { - const error = new Error(`could not fetch config: ${cause.message}`); - dispatch(fetchConfigFailure(error)); + .catch(err => { + dispatch(fetchConfigFailure(err)); }); }; } @@ -73,13 +72,8 @@ export function modifyConfig(config: Config, callback?: () => void) { callback(); } }) - .catch(cause => { - dispatch( - modifyConfigFailure( - config, - new Error(`could not modify config: ${cause.message}`) - ) - ); + .catch(err => { + dispatch(modifyConfigFailure(config, err)); }); }; } diff --git a/scm-ui/src/groups/modules/groups.js b/scm-ui/src/groups/modules/groups.js index 165648edaa..483b5b3798 100644 --- a/scm-ui/src/groups/modules/groups.js +++ b/scm-ui/src/groups/modules/groups.js @@ -54,9 +54,8 @@ export function fetchGroupsByLink(link: string) { .then(data => { dispatch(fetchGroupsSuccess(data)); }) - .catch(cause => { - const error = new Error(`could not fetch groups: ${cause.message}`); - dispatch(fetchGroupsFailure(link, error)); + .catch(err => { + dispatch(fetchGroupsFailure(link, err)); }); }; } @@ -105,9 +104,8 @@ function fetchGroup(link: string, name: string) { .then(data => { dispatch(fetchGroupSuccess(data)); }) - .catch(cause => { - const error = new Error(`could not fetch group: ${cause.message}`); - dispatch(fetchGroupFailure(name, error)); + .catch(err => { + dispatch(fetchGroupFailure(name, err)); }); }; } @@ -151,10 +149,10 @@ export function createGroup(link: string, group: Group, callback?: () => void) { callback(); } }) - .catch(error => { + .catch(err => { dispatch( createGroupFailure( - new Error(`Failed to create group ${group.name}: ${error.message}`) + err ) ); }); @@ -201,11 +199,11 @@ export function modifyGroup(group: Group, callback?: () => void) { .then(() => { dispatch(fetchGroupByLink(group)); }) - .catch(cause => { + .catch(err => { dispatch( modifyGroupFailure( group, - new Error(`could not modify group ${group.name}: ${cause.message}`) + err ) ); }); @@ -259,11 +257,8 @@ export function deleteGroup(group: Group, callback?: () => void) { callback(); } }) - .catch(cause => { - const error = new Error( - `could not delete group ${group.name}: ${cause.message}` - ); - dispatch(deleteGroupFailure(group, error)); + .catch(err => { + dispatch(deleteGroupFailure(group, err)); }); }; } diff --git a/scm-ui/src/repos/modules/repos.js b/scm-ui/src/repos/modules/repos.js index 642f6cf395..3e574aa938 100644 --- a/scm-ui/src/repos/modules/repos.js +++ b/scm-ui/src/repos/modules/repos.js @@ -224,9 +224,8 @@ export function modifyRepo(repository: Repository, callback?: () => void) { .then(() => { dispatch(fetchRepoByLink(repository)); }) - .catch(cause => { - const error = new Error(`failed to modify repo: ${cause.message}`); - dispatch(modifyRepoFailure(repository, error)); + .catch(err => { + dispatch(modifyRepoFailure(repository, err)); }); }; } diff --git a/scm-ui/src/repos/permissions/modules/permissions.js b/scm-ui/src/repos/permissions/modules/permissions.js index 154ee8123f..9f5330bbcd 100644 --- a/scm-ui/src/repos/permissions/modules/permissions.js +++ b/scm-ui/src/repos/permissions/modules/permissions.js @@ -1,12 +1,16 @@ // @flow -import type {Action} from "@scm-manager/ui-components"; -import {apiClient} from "@scm-manager/ui-components"; +import type { Action } from "@scm-manager/ui-components"; +import { apiClient } from "@scm-manager/ui-components"; import * as types from "../../../modules/types"; -import type {Permission, PermissionCollection, PermissionCreateEntry} from "@scm-manager/ui-types"; -import {isPending} from "../../../modules/pending"; -import {getFailure} from "../../../modules/failure"; -import {Dispatch} from "redux"; +import type { + Permission, + PermissionCollection, + PermissionCreateEntry +} from "@scm-manager/ui-types"; +import { isPending } from "../../../modules/pending"; +import { getFailure } from "../../../modules/failure"; +import { Dispatch } from "redux"; export const FETCH_PERMISSIONS = "scm/permissions/FETCH_PERMISSIONS"; export const FETCH_PERMISSIONS_PENDING = `${FETCH_PERMISSIONS}_${ @@ -141,13 +145,8 @@ export function modifyPermission( callback(); } }) - .catch(cause => { - const error = new Error( - `failed to modify permission: ${cause.message}` - ); - dispatch( - modifyPermissionFailure(permission, error, namespace, repoName) - ); + .catch(err => { + dispatch(modifyPermissionFailure(permission, err, namespace, repoName)); }); }; } @@ -241,15 +240,7 @@ export function createPermission( } }) .catch(err => - dispatch( - createPermissionFailure( - new Error( - `failed to add permission ${permission.name}: ${err.message}` - ), - namespace, - repoName - ) - ) + dispatch(createPermissionFailure(err, namespace, repoName)) ); }; } @@ -318,13 +309,8 @@ export function deletePermission( callback(); } }) - .catch(cause => { - const error = new Error( - `could not delete permission ${permission.name}: ${cause.message}` - ); - dispatch( - deletePermissionFailure(permission, namespace, repoName, error) - ); + .catch(err => { + dispatch(deletePermissionFailure(permission, namespace, repoName, err)); }); }; } diff --git a/scm-ui/src/repos/sources/modules/sources.js b/scm-ui/src/repos/sources/modules/sources.js index 5868c56df3..c6d86d38ee 100644 --- a/scm-ui/src/repos/sources/modules/sources.js +++ b/scm-ui/src/repos/sources/modules/sources.js @@ -25,8 +25,7 @@ export function fetchSources( dispatch(fetchSourcesSuccess(repository, revision, path, sources)); }) .catch(err => { - const error = new Error(`failed to fetch sources: ${err.message}`); - dispatch(fetchSourcesFailure(repository, revision, path, error)); + dispatch(fetchSourcesFailure(repository, revision, path, err)); }); }; } diff --git a/scm-ui/src/users/modules/users.js b/scm-ui/src/users/modules/users.js index fe751d13d4..ab330d9ffd 100644 --- a/scm-ui/src/users/modules/users.js +++ b/scm-ui/src/users/modules/users.js @@ -35,8 +35,6 @@ export const DELETE_USER_FAILURE = `${DELETE_USER}_${types.FAILURE_SUFFIX}`; const CONTENT_TYPE_USER = "application/vnd.scmm-user+json;v=2"; -// TODO i18n for error messages - // fetch users export function fetchUsers(link: string) { @@ -57,9 +55,8 @@ export function fetchUsersByLink(link: string) { .then(data => { dispatch(fetchUsersSuccess(data)); }) - .catch(cause => { - const error = new Error(`could not fetch users: ${cause.message}`); - dispatch(fetchUsersFailure(link, error)); + .catch(err => { + dispatch(fetchUsersFailure(link, err)); }); }; } @@ -108,9 +105,8 @@ function fetchUser(link: string, name: string) { .then(data => { dispatch(fetchUserSuccess(data)); }) - .catch(cause => { - const error = new Error(`could not fetch user: ${cause.message}`); - dispatch(fetchUserFailure(name, error)); + .catch(err => { + dispatch(fetchUserFailure(name, err)); }); }; } @@ -155,13 +151,7 @@ export function createUser(link: string, user: User, callback?: () => void) { callback(); } }) - .catch(err => - dispatch( - createUserFailure( - new Error(`failed to add user ${user.name}: ${err.message}`) - ) - ) - ); + .catch(err => dispatch(createUserFailure(err))); }; } @@ -260,11 +250,8 @@ export function deleteUser(user: User, callback?: () => void) { callback(); } }) - .catch(cause => { - const error = new Error( - `could not delete user ${user.name}: ${cause.message}` - ); - dispatch(deleteUserFailure(user, error)); + .catch(err => { + dispatch(deleteUserFailure(user, err)); }); }; } From c3a8ef99861a17c6ff7e73d2176fd5387966b308 Mon Sep 17 00:00:00 2001 From: Florian Scholdei Date: Wed, 12 Dec 2018 13:29:37 +0100 Subject: [PATCH 02/76] implemented unauthorized error message and link to reload page --- .../ui-components/src/ErrorNotification.js | 19 ++++++++++++++----- scm-ui/public/locales/en/commons.json | 3 ++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/scm-ui-components/packages/ui-components/src/ErrorNotification.js b/scm-ui-components/packages/ui-components/src/ErrorNotification.js index 5600d81799..8225c0914a 100644 --- a/scm-ui-components/packages/ui-components/src/ErrorNotification.js +++ b/scm-ui-components/packages/ui-components/src/ErrorNotification.js @@ -2,6 +2,7 @@ import React from "react"; import { translate } from "react-i18next"; import Notification from "./Notification"; +import { UNAUTHORIZED_ERROR } from "./apiclient"; type Props = { t: string => string, @@ -12,11 +13,19 @@ class ErrorNotification extends React.Component { render() { const { t, error } = this.props; if (error) { - return ( - - {t("error-notification.prefix")}: {error.message} - - ); + if (error == UNAUTHORIZED_ERROR) { + return ( + + {t("error-notification.prefix")}: {t("error-notification.timeout")} Login + + ); + } else { + return ( + + {t("error-notification.prefix")}: {error.message} + + ); + } } return null; } diff --git a/scm-ui/public/locales/en/commons.json b/scm-ui/public/locales/en/commons.json index 47a8735e5b..fe1062e789 100644 --- a/scm-ui/public/locales/en/commons.json +++ b/scm-ui/public/locales/en/commons.json @@ -20,7 +20,8 @@ } }, "error-notification": { - "prefix": "Error" + "prefix": "Error", + "timeout": "The session has expired. Please login again." }, "loading": { "alt": "Loading ..." From b27e3d26007ba0c547e33beee121aa46e6319807 Mon Sep 17 00:00:00 2001 From: Florian Scholdei Date: Wed, 12 Dec 2018 13:35:58 +0100 Subject: [PATCH 03/76] added translation --- .../ui-components/src/ErrorNotification.js | 23 +++++++++++++++---- scm-ui/public/locales/en/commons.json | 4 +++- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/scm-ui-components/packages/ui-components/src/ErrorNotification.js b/scm-ui-components/packages/ui-components/src/ErrorNotification.js index 5600d81799..7856f29789 100644 --- a/scm-ui-components/packages/ui-components/src/ErrorNotification.js +++ b/scm-ui-components/packages/ui-components/src/ErrorNotification.js @@ -2,6 +2,7 @@ import React from "react"; import { translate } from "react-i18next"; import Notification from "./Notification"; +import {UNAUTHORIZED_ERROR} from "./apiclient"; type Props = { t: string => string, @@ -9,14 +10,26 @@ type Props = { }; class ErrorNotification extends React.Component { + render() { const { t, error } = this.props; if (error) { - return ( - - {t("error-notification.prefix")}: {error.message} - - ); + if (error === UNAUTHORIZED_ERROR) { + return ( + + {t("error-notification.prefix")}: {t("error-notification.timeout")} + {" "} + {t("error-notification.loginLink")} + + ); + } else { + return ( + + {t("error-notification.prefix")}: {error.message} + + ); + } + } return null; } diff --git a/scm-ui/public/locales/en/commons.json b/scm-ui/public/locales/en/commons.json index 47a8735e5b..2908a38a4f 100644 --- a/scm-ui/public/locales/en/commons.json +++ b/scm-ui/public/locales/en/commons.json @@ -20,7 +20,9 @@ } }, "error-notification": { - "prefix": "Error" + "prefix": "Error", + "loginLink": "You can login here again.", + "timeout": "The session has expired." }, "loading": { "alt": "Loading ..." From bc8c77682142515c9a54edfb0a8b03d7c10a5c1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 12 Dec 2018 14:12:55 +0100 Subject: [PATCH 04/76] Introduce config rest endpoint for default git branch --- .../api/v2/resources/GitConfigResource.java | 13 ++- .../v2/resources/GitRepositoryConfigDto.java | 24 +++++ .../GitRepositoryConfigEnricher.java | 43 +++++++++ .../GitRepositoryConfigResource.java | 52 +++++++++++ ...yConfigToGitRepositoryConfigDtoMapper.java | 45 +++++++++ .../scm/repository/GitRepositoryConfig.java | 14 +++ .../java/sonia/scm/web/GitServletModule.java | 2 + .../java/sonia/scm/web/GitVndMediaType.java | 1 + .../v2/resources/GitConfigResourceTest.java | 92 ++++++++++++++++--- .../sonia/scm/configuration/shiro.ini | 6 +- 10 files changed, 278 insertions(+), 14 deletions(-) create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigDto.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigEnricher.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigResource.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigToGitRepositoryConfigDtoMapper.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryConfig.java diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitConfigResource.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitConfigResource.java index 1384d73d9c..e078b04b08 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitConfigResource.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitConfigResource.java @@ -9,13 +9,17 @@ import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.web.GitVndMediaType; import javax.inject.Inject; +import javax.inject.Provider; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.PUT; import javax.ws.rs.Path; +import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.Response; +import static sonia.scm.ContextEntry.ContextBuilder.entity; + /** * RESTful Web Service Resource to manage the configuration of the git plugin. */ @@ -26,13 +30,15 @@ public class GitConfigResource { private final GitConfigDtoToGitConfigMapper dtoToConfigMapper; private final GitConfigToGitConfigDtoMapper configToDtoMapper; private final GitRepositoryHandler repositoryHandler; + private final Provider gitRepositoryConfigResource; @Inject public GitConfigResource(GitConfigDtoToGitConfigMapper dtoToConfigMapper, GitConfigToGitConfigDtoMapper configToDtoMapper, - GitRepositoryHandler repositoryHandler) { + GitRepositoryHandler repositoryHandler, Provider gitRepositoryConfigResource) { this.dtoToConfigMapper = dtoToConfigMapper; this.configToDtoMapper = configToDtoMapper; this.repositoryHandler = repositoryHandler; + this.gitRepositoryConfigResource = gitRepositoryConfigResource; } /** @@ -88,4 +94,9 @@ public class GitConfigResource { return Response.noContent().build(); } + + @Path("{namespace}/{name}") + public GitRepositoryConfigResource getRepositoryConfig(@PathParam("namespace") String namespace, @PathParam("name") String name) { + return gitRepositoryConfigResource.get(); + } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigDto.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigDto.java new file mode 100644 index 0000000000..d22d6c194e --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigDto.java @@ -0,0 +1,24 @@ +package sonia.scm.api.v2.resources; + +import de.otto.edison.hal.HalRepresentation; +import de.otto.edison.hal.Links; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@SuppressWarnings("squid:S2160") // there is no proper semantic for equals on this dto +public class GitRepositoryConfigDto extends HalRepresentation { + + private String defaultBranch; + + @Override + @SuppressWarnings("squid:S1185") // We want to have this method available in this package + protected HalRepresentation add(Links links) { + return super.add(links); + } +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigEnricher.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigEnricher.java new file mode 100644 index 0000000000..55c565f162 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigEnricher.java @@ -0,0 +1,43 @@ +package sonia.scm.api.v2.resources; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import sonia.scm.plugin.Extension; +import sonia.scm.web.JsonEnricherBase; +import sonia.scm.web.JsonEnricherContext; + +import javax.inject.Inject; +import javax.inject.Provider; + +import static java.util.Collections.singletonMap; +import static sonia.scm.web.VndMediaType.REPOSITORY; + +@Extension +public class GitRepositoryConfigEnricher extends JsonEnricherBase { + + private final Provider scmPathInfoStore; + + @Inject + public GitRepositoryConfigEnricher(Provider scmPathInfoStore, ObjectMapper objectMapper) { + super(objectMapper); + this.scmPathInfoStore = scmPathInfoStore; + } + + @Override + public void enrich(JsonEnricherContext context) { + if (resultHasMediaType(REPOSITORY, context)) { + JsonNode repositoryNode = context.getResponseEntity(); + String namespace = repositoryNode.get("namespace").asText(); + String name = repositoryNode.get("name").asText(); + + String newPullRequest = new LinkBuilder(scmPathInfoStore.get().get(), GitConfigResource.class) + .method("getRepositoryConfig") + .parameters(namespace, name) + .href(); + + JsonNode newPullRequestNode = createObject(singletonMap("href", value(newPullRequest))); + + addPropertyNode(repositoryNode.get("_links"), "configuration", newPullRequestNode); + } + } +} 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 new file mode 100644 index 0000000000..2ff637031b --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigResource.java @@ -0,0 +1,52 @@ +package sonia.scm.api.v2.resources; + +import sonia.scm.repository.GitRepositoryConfig; +import sonia.scm.repository.NamespaceAndName; +import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryManager; +import sonia.scm.store.ConfigurationStore; +import sonia.scm.store.ConfigurationStoreFactory; +import sonia.scm.web.GitVndMediaType; + +import javax.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Response; + +import static sonia.scm.ContextEntry.ContextBuilder.entity; +import static sonia.scm.NotFoundException.notFound; + +public class GitRepositoryConfigResource { + + private final GitRepositoryConfigToGitRepositoryConfigDtoMapper repositoryConfigToDtoMapper; + private final RepositoryManager repositoryManager; + private final ConfigurationStoreFactory configurationStoreFactory; + + @Inject + public GitRepositoryConfigResource(GitRepositoryConfigToGitRepositoryConfigDtoMapper repositoryConfigToDtoMapper, RepositoryManager repositoryManager, ConfigurationStoreFactory configurationStoreFactory) { + this.repositoryConfigToDtoMapper = repositoryConfigToDtoMapper; + this.repositoryManager = repositoryManager; + this.configurationStoreFactory = configurationStoreFactory; + } + + @GET + @Path("/") + @Produces(GitVndMediaType.GIT_REPOSITORY_CONFIG) + public Response getRepositoryConfig(@PathParam("namespace") String namespace, @PathParam("name") String name) { + NamespaceAndName namespaceAndName = new NamespaceAndName(namespace, name); + Repository repository = repositoryManager.get(namespaceAndName); + if (repository == null) { + throw notFound(entity(namespaceAndName)); + } + + ConfigurationStore repositoryConfigStore = configurationStoreFactory.withType(GitRepositoryConfig.class).withName("gitConfig").forRepository(repository).build(); + GitRepositoryConfig config = repositoryConfigStore.get(); + if (config == null) { + config = new GitRepositoryConfig(); + } + GitRepositoryConfigDto dto = repositoryConfigToDtoMapper.map(config, repository); + return Response.ok(dto).build(); + } +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigToGitRepositoryConfigDtoMapper.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigToGitRepositoryConfigDtoMapper.java new file mode 100644 index 0000000000..07fd83b700 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigToGitRepositoryConfigDtoMapper.java @@ -0,0 +1,45 @@ +package sonia.scm.api.v2.resources; + +import de.otto.edison.hal.Links; +import org.mapstruct.AfterMapping; +import org.mapstruct.Context; +import org.mapstruct.Mapper; +import org.mapstruct.MappingTarget; +import sonia.scm.repository.GitRepositoryConfig; +import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryPermissions; + +import javax.inject.Inject; + +import static de.otto.edison.hal.Link.link; +import static de.otto.edison.hal.Links.linkingTo; + +// Mapstruct does not support parameterized (i.e. non-default) constructors. Thus, we need to use field injection. +@SuppressWarnings("squid:S3306") +@Mapper +public abstract class GitRepositoryConfigToGitRepositoryConfigDtoMapper { + + @Inject + private ScmPathInfoStore scmPathInfoStore; + + public abstract GitRepositoryConfigDto map(GitRepositoryConfig config, @Context Repository repository); + + @AfterMapping + void appendLinks(GitRepositoryConfig config, @MappingTarget GitRepositoryConfigDto target, @Context Repository repository) { + Links.Builder linksBuilder = linkingTo().self(self()); + if (RepositoryPermissions.modify(repository).isPermitted()) { + linksBuilder.single(link("update", update())); + } + target.add(linksBuilder.build()); + } + + private String self() { + LinkBuilder linkBuilder = new LinkBuilder(scmPathInfoStore.get(), GitConfigResource.class); + return linkBuilder.method("get").parameters().href(); + } + + private String update() { + LinkBuilder linkBuilder = new LinkBuilder(scmPathInfoStore.get(), GitConfigResource.class); + return linkBuilder.method("update").parameters().href(); + } +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryConfig.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryConfig.java new file mode 100644 index 0000000000..ae41987247 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryConfig.java @@ -0,0 +1,14 @@ +package sonia.scm.repository; + +public class GitRepositoryConfig { + + private String defaultBranch; + + public String getDefaultBranch() { + return defaultBranch; + } + + public void setDefaultBranch(String defaultBranch) { + this.defaultBranch = defaultBranch; + } +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java index a3dac0e7d1..609ee6cb0b 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java @@ -40,6 +40,7 @@ import org.eclipse.jgit.transport.ScmTransportProtocol; import org.mapstruct.factory.Mappers; import sonia.scm.api.v2.resources.GitConfigDtoToGitConfigMapper; import sonia.scm.api.v2.resources.GitConfigToGitConfigDtoMapper; +import sonia.scm.api.v2.resources.GitRepositoryConfigToGitRepositoryConfigDtoMapper; import sonia.scm.plugin.Extension; import sonia.scm.repository.GitWorkdirFactory; import sonia.scm.repository.spi.SimpleGitWorkdirFactory; @@ -65,6 +66,7 @@ public class GitServletModule extends ServletModule bind(GitConfigDtoToGitConfigMapper.class).to(Mappers.getMapper(GitConfigDtoToGitConfigMapper.class).getClass()); bind(GitConfigToGitConfigDtoMapper.class).to(Mappers.getMapper(GitConfigToGitConfigDtoMapper.class).getClass()); + bind(GitRepositoryConfigToGitRepositoryConfigDtoMapper.class).to(Mappers.getMapper(GitRepositoryConfigToGitRepositoryConfigDtoMapper.class).getClass()); bind(GitWorkdirFactory.class).to(SimpleGitWorkdirFactory.class); } 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 8c81c6eefa..9bfa9fe63e 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 @@ -2,6 +2,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; private GitVndMediaType() { } 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 5bf68d3827..7bc0e5fe02 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 @@ -1,7 +1,5 @@ package sonia.scm.api.v2.resources; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.SubjectAware; import org.jboss.resteasy.core.Dispatcher; @@ -18,18 +16,25 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import sonia.scm.repository.GitConfig; +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; +import sonia.scm.store.ConfigurationStore; +import sonia.scm.store.ConfigurationStoreFactory; import sonia.scm.web.GitVndMediaType; import javax.servlet.http.HttpServletResponse; -import java.io.File; -import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; +import static com.google.inject.util.Providers.of; import static junit.framework.TestCase.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; @SubjectAware( @@ -55,30 +60,45 @@ public class GitConfigResourceTest { @Mock(answer = Answers.RETURNS_DEEP_STUBS) private ScmPathInfoStore scmPathInfoStore; + @Mock + private RepositoryManager repositoryManager; + @InjectMocks private GitConfigToGitConfigDtoMapperImpl configToDtoMapper; + @InjectMocks + private GitRepositoryConfigToGitRepositoryConfigDtoMapperImpl repositoryConfigToDtoMapper; @Mock private GitRepositoryHandler repositoryHandler; + @Mock(answer = Answers.CALLS_REAL_METHODS) + private ConfigurationStoreFactory configurationStoreFactory; + @Mock + private ConfigurationStore configurationStore; + @Before public void prepareEnvironment() { GitConfig gitConfig = createConfiguration(); when(repositoryHandler.getConfig()).thenReturn(gitConfig); - GitConfigResource gitConfigResource = new GitConfigResource(dtoToConfigMapper, configToDtoMapper, repositoryHandler); + GitRepositoryConfigResource gitRepositoryConfigResource = new GitRepositoryConfigResource(repositoryConfigToDtoMapper, repositoryManager, configurationStoreFactory); + GitConfigResource gitConfigResource = new GitConfigResource(dtoToConfigMapper, configToDtoMapper, repositoryHandler, of(gitRepositoryConfigResource)); dispatcher.getRegistry().addSingletonResource(gitConfigResource); when(scmPathInfoStore.get().getApiRestUri()).thenReturn(baseUri); } + @Before + public void initConfigStore() { + when(configurationStoreFactory.getStore(any())).thenReturn(configurationStore); + } + @Test @SubjectAware(username = "readWrite") - public void shouldGetGitConfig() throws URISyntaxException, IOException { + public void shouldGetGitConfig() throws URISyntaxException { MockHttpResponse response = get(); assertEquals(HttpServletResponse.SC_OK, response.getStatus()); String responseString = response.getContentAsString(); - ObjectNode responseJson = new ObjectMapper().readValue(responseString, ObjectNode.class); assertTrue(responseString.contains("\"disabled\":false")); assertTrue(responseString.contains("\"gcExpression\":\"valid Git GC Cron Expression\"")); @@ -88,7 +108,7 @@ public class GitConfigResourceTest { @Test @SubjectAware(username = "readWrite") - public void shouldGetGitConfigEvenWhenItsEmpty() throws URISyntaxException, IOException { + public void shouldGetGitConfigEvenWhenItsEmpty() throws URISyntaxException { when(repositoryHandler.getConfig()).thenReturn(null); MockHttpResponse response = get(); @@ -124,12 +144,64 @@ public class GitConfigResourceTest { @Test @SubjectAware(username = "readOnly") - public void shouldNotUpdateConfigWhenNotAuthorized() throws URISyntaxException, IOException { + public void shouldNotUpdateConfigWhenNotAuthorized() throws URISyntaxException { thrown.expectMessage("Subject does not have permission [configuration:write:git]"); put(); } + @Test + @SubjectAware(username = "writeOnly") + public void shouldReadDefaultRepositoryConfig() 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"); + MockHttpResponse response = new MockHttpResponse(); + + dispatcher.invoke(request, response); + + assertEquals(HttpServletResponse.SC_OK, response.getStatus()); + assertThat(response.getContentAsString()) + .contains("\"defaultBranch\":null") + .contains("self") + .contains("update"); + } + + @Test + @SubjectAware(username = "readOnly") + public void shouldNotHaveUpdateLinkForReadOnlyUser() 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"); + MockHttpResponse response = new MockHttpResponse(); + + dispatcher.invoke(request, response); + + assertEquals(HttpServletResponse.SC_OK, response.getStatus()); + assertThat(response.getContentAsString()) + .contains("\"defaultBranch\":null") + .contains("self") + .doesNotContain("update"); + } + + @Test + @SubjectAware(username = "writeOnly") + public void shouldReadStoredRepositoryConfig() throws URISyntaxException { + when(repositoryManager.get(new NamespaceAndName("space", "X"))).thenReturn(new Repository("id", "git", "space", "X")); + GitRepositoryConfig gitRepositoryConfig = new GitRepositoryConfig(); + gitRepositoryConfig.setDefaultBranch("test"); + when(configurationStore.get()).thenReturn(gitRepositoryConfig); + + MockHttpRequest request = MockHttpRequest.get("/" + GitConfigResource.GIT_CONFIG_PATH_V2 + "/space/X"); + MockHttpResponse response = new MockHttpResponse(); + + dispatcher.invoke(request, response); + + assertEquals(HttpServletResponse.SC_OK, response.getStatus()); + assertThat(response.getContentAsString()) + .contains("\"defaultBranch\":\"test\""); + } + private MockHttpResponse get() throws URISyntaxException { MockHttpRequest request = MockHttpRequest.get("/" + GitConfigResource.GIT_CONFIG_PATH_V2); MockHttpResponse response = new MockHttpResponse(); @@ -153,6 +225,4 @@ public class GitConfigResourceTest { config.setDisabled(false); return config; } - } - diff --git a/scm-plugins/scm-git-plugin/src/test/resources/sonia/scm/configuration/shiro.ini b/scm-plugins/scm-git-plugin/src/test/resources/sonia/scm/configuration/shiro.ini index 5d30a000f2..8a8ff98c2f 100644 --- a/scm-plugins/scm-git-plugin/src/test/resources/sonia/scm/configuration/shiro.ini +++ b/scm-plugins/scm-git-plugin/src/test/resources/sonia/scm/configuration/shiro.ini @@ -1,6 +1,6 @@ [users] -readOnly = secret, reader -writeOnly = secret, writer +readOnly = secret, reader, repoRead +writeOnly = secret, writer, repoWrite readWrite = secret, readerWriter admin = secret, admin @@ -9,3 +9,5 @@ reader = configuration:read:git writer = configuration:write:git readerWriter = configuration:*:git admin = * +repoRead = repository:read:* +repoWrite = repository:modify:* From b4081aaa99bfad0a5ac8726b68a8382b4a9b21da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 12 Dec 2018 15:04:56 +0100 Subject: [PATCH 05/76] Add endpoint to set default branch --- ...er.java => GitRepositoryConfigMapper.java} | 5 ++- .../GitRepositoryConfigResource.java | 41 ++++++++++++++----- .../scm/repository/GitRepositoryConfig.java | 6 +++ .../java/sonia/scm/web/GitServletModule.java | 4 +- .../v2/resources/GitConfigResourceTest.java | 35 ++++++++++++++-- 5 files changed, 73 insertions(+), 18 deletions(-) rename scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/{GitRepositoryConfigToGitRepositoryConfigDtoMapper.java => GitRepositoryConfigMapper.java} (86%) diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigToGitRepositoryConfigDtoMapper.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigMapper.java similarity index 86% rename from scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigToGitRepositoryConfigDtoMapper.java rename to scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigMapper.java index 07fd83b700..6480e526b1 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigToGitRepositoryConfigDtoMapper.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigMapper.java @@ -17,15 +17,16 @@ import static de.otto.edison.hal.Links.linkingTo; // Mapstruct does not support parameterized (i.e. non-default) constructors. Thus, we need to use field injection. @SuppressWarnings("squid:S3306") @Mapper -public abstract class GitRepositoryConfigToGitRepositoryConfigDtoMapper { +public abstract class GitRepositoryConfigMapper { @Inject private ScmPathInfoStore scmPathInfoStore; public abstract GitRepositoryConfigDto map(GitRepositoryConfig config, @Context Repository repository); + public abstract GitRepositoryConfig map(GitRepositoryConfigDto dto); @AfterMapping - void appendLinks(GitRepositoryConfig config, @MappingTarget GitRepositoryConfigDto target, @Context Repository repository) { + void appendLinks(@MappingTarget GitRepositoryConfigDto target, @Context Repository repository) { Links.Builder linksBuilder = linkingTo().self(self()); if (RepositoryPermissions.modify(repository).isPermitted()) { linksBuilder.single(link("update", update())); 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 2ff637031b..af3501ae9a 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 @@ -9,7 +9,9 @@ import sonia.scm.store.ConfigurationStoreFactory; import sonia.scm.web.GitVndMediaType; import javax.inject.Inject; +import javax.ws.rs.Consumes; import javax.ws.rs.GET; +import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; @@ -20,13 +22,13 @@ import static sonia.scm.NotFoundException.notFound; public class GitRepositoryConfigResource { - private final GitRepositoryConfigToGitRepositoryConfigDtoMapper repositoryConfigToDtoMapper; + private final GitRepositoryConfigMapper repositoryConfigMapper; private final RepositoryManager repositoryManager; private final ConfigurationStoreFactory configurationStoreFactory; @Inject - public GitRepositoryConfigResource(GitRepositoryConfigToGitRepositoryConfigDtoMapper repositoryConfigToDtoMapper, RepositoryManager repositoryManager, ConfigurationStoreFactory configurationStoreFactory) { - this.repositoryConfigToDtoMapper = repositoryConfigToDtoMapper; + public GitRepositoryConfigResource(GitRepositoryConfigMapper repositoryConfigMapper, RepositoryManager repositoryManager, ConfigurationStoreFactory configurationStoreFactory) { + this.repositoryConfigMapper = repositoryConfigMapper; this.repositoryManager = repositoryManager; this.configurationStoreFactory = configurationStoreFactory; } @@ -35,18 +37,37 @@ public class GitRepositoryConfigResource { @Path("/") @Produces(GitVndMediaType.GIT_REPOSITORY_CONFIG) public Response getRepositoryConfig(@PathParam("namespace") String namespace, @PathParam("name") String name) { + Repository repository = getRepository(namespace, name); + ConfigurationStore repositoryConfigStore = getStore(repository); + GitRepositoryConfig config = repositoryConfigStore.get(); + if (config == null) { + config = new GitRepositoryConfig(); + } + GitRepositoryConfigDto dto = repositoryConfigMapper.map(config, repository); + return Response.ok(dto).build(); + } + + @PUT + @Path("/") + @Consumes(GitVndMediaType.GIT_REPOSITORY_CONFIG) + public Response setRepositoryConfig(@PathParam("namespace") String namespace, @PathParam("name") String name, GitRepositoryConfigDto dto) { + Repository repository = getRepository(namespace, name); + ConfigurationStore repositoryConfigStore = getStore(repository); + GitRepositoryConfig config = repositoryConfigMapper.map(dto); + repositoryConfigStore.set(config); + return Response.noContent().build(); + } + + private Repository getRepository(@PathParam("namespace") String namespace, @PathParam("name") String name) { NamespaceAndName namespaceAndName = new NamespaceAndName(namespace, name); Repository repository = repositoryManager.get(namespaceAndName); if (repository == null) { throw notFound(entity(namespaceAndName)); } + return repository; + } - ConfigurationStore repositoryConfigStore = configurationStoreFactory.withType(GitRepositoryConfig.class).withName("gitConfig").forRepository(repository).build(); - GitRepositoryConfig config = repositoryConfigStore.get(); - if (config == null) { - config = new GitRepositoryConfig(); - } - GitRepositoryConfigDto dto = repositoryConfigToDtoMapper.map(config, repository); - return Response.ok(dto).build(); + private ConfigurationStore getStore(Repository repository) { + return configurationStoreFactory.withType(GitRepositoryConfig.class).withName("gitConfig").forRepository(repository).build(); } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryConfig.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryConfig.java index ae41987247..a548d82153 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryConfig.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryConfig.java @@ -1,5 +1,11 @@ package sonia.scm.repository; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(name = "config") +@XmlAccessorType(XmlAccessType.FIELD) public class GitRepositoryConfig { private String defaultBranch; diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java index 609ee6cb0b..0bbb993cc6 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java @@ -40,7 +40,7 @@ import org.eclipse.jgit.transport.ScmTransportProtocol; import org.mapstruct.factory.Mappers; import sonia.scm.api.v2.resources.GitConfigDtoToGitConfigMapper; import sonia.scm.api.v2.resources.GitConfigToGitConfigDtoMapper; -import sonia.scm.api.v2.resources.GitRepositoryConfigToGitRepositoryConfigDtoMapper; +import sonia.scm.api.v2.resources.GitRepositoryConfigMapper; import sonia.scm.plugin.Extension; import sonia.scm.repository.GitWorkdirFactory; import sonia.scm.repository.spi.SimpleGitWorkdirFactory; @@ -66,7 +66,7 @@ public class GitServletModule extends ServletModule bind(GitConfigDtoToGitConfigMapper.class).to(Mappers.getMapper(GitConfigDtoToGitConfigMapper.class).getClass()); bind(GitConfigToGitConfigDtoMapper.class).to(Mappers.getMapper(GitConfigToGitConfigDtoMapper.class).getClass()); - bind(GitRepositoryConfigToGitRepositoryConfigDtoMapper.class).to(Mappers.getMapper(GitRepositoryConfigToGitRepositoryConfigDtoMapper.class).getClass()); + bind(GitRepositoryConfigMapper.class).to(Mappers.getMapper(GitRepositoryConfigMapper.class).getClass()); bind(GitWorkdirFactory.class).to(SimpleGitWorkdirFactory.class); } 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 7bc0e5fe02..f4de22b2b5 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 @@ -12,8 +12,11 @@ import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.mockito.Answers; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Spy; import org.mockito.runners.MockitoJUnitRunner; import sonia.scm.repository.GitConfig; import sonia.scm.repository.GitRepositoryConfig; @@ -35,6 +38,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.when; @SubjectAware( @@ -66,21 +70,23 @@ public class GitConfigResourceTest { @InjectMocks private GitConfigToGitConfigDtoMapperImpl configToDtoMapper; @InjectMocks - private GitRepositoryConfigToGitRepositoryConfigDtoMapperImpl repositoryConfigToDtoMapper; + private GitRepositoryConfigMapperImpl repositoryConfigMapper; @Mock private GitRepositoryHandler repositoryHandler; @Mock(answer = Answers.CALLS_REAL_METHODS) private ConfigurationStoreFactory configurationStoreFactory; - @Mock - private ConfigurationStore configurationStore; + @Spy + private ConfigurationStore configurationStore; + @Captor + private ArgumentCaptor configurationStoreCaptor; @Before public void prepareEnvironment() { GitConfig gitConfig = createConfiguration(); when(repositoryHandler.getConfig()).thenReturn(gitConfig); - GitRepositoryConfigResource gitRepositoryConfigResource = new GitRepositoryConfigResource(repositoryConfigToDtoMapper, repositoryManager, configurationStoreFactory); + GitRepositoryConfigResource gitRepositoryConfigResource = new GitRepositoryConfigResource(repositoryConfigMapper, repositoryManager, configurationStoreFactory); GitConfigResource gitConfigResource = new GitConfigResource(dtoToConfigMapper, configToDtoMapper, repositoryHandler, of(gitRepositoryConfigResource)); dispatcher.getRegistry().addSingletonResource(gitConfigResource); when(scmPathInfoStore.get().getApiRestUri()).thenReturn(baseUri); @@ -89,6 +95,7 @@ public class GitConfigResourceTest { @Before public void initConfigStore() { when(configurationStoreFactory.getStore(any())).thenReturn(configurationStore); + doNothing().when(configurationStore).set(configurationStoreCaptor.capture()); } @Test @@ -202,6 +209,26 @@ public class GitConfigResourceTest { .contains("\"defaultBranch\":\"test\""); } + @Test + @SubjectAware(username = "writeOnly") + public void shouldStoreChangedRepositoryConfig() throws URISyntaxException { + when(repositoryManager.get(new NamespaceAndName("space", "X"))).thenReturn(new Repository("id", "git", "space", "X")); + + MockHttpRequest request = MockHttpRequest + .put("/" + GitConfigResource.GIT_CONFIG_PATH_V2 + "/space/X") + .contentType(GitVndMediaType.GIT_REPOSITORY_CONFIG) + .content("{\"defaultBranch\": \"new\"}".getBytes()); + MockHttpResponse response = new MockHttpResponse(); + + dispatcher.invoke(request, response); + + assertEquals(HttpServletResponse.SC_NO_CONTENT, response.getStatus()); + assertThat(configurationStoreCaptor.getValue()) + .isInstanceOfSatisfying(GitRepositoryConfig.class, x -> { }) + .extracting("defaultBranch") + .containsExactly("new"); + } + private MockHttpResponse get() throws URISyntaxException { MockHttpRequest request = MockHttpRequest.get("/" + GitConfigResource.GIT_CONFIG_PATH_V2); MockHttpResponse response = new MockHttpResponse(); From cab797fd83244025494ba5dfeab047c95a978297 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maren=20S=C3=BCwer?= Date: Wed, 12 Dec 2018 15:40:24 +0100 Subject: [PATCH 06/76] show nothing if no diff is there --- .../packages/ui-components/src/repos/LoadingDiff.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scm-ui-components/packages/ui-components/src/repos/LoadingDiff.js b/scm-ui-components/packages/ui-components/src/repos/LoadingDiff.js index 5f6330f0e5..3abf971168 100644 --- a/scm-ui-components/packages/ui-components/src/repos/LoadingDiff.js +++ b/scm-ui-components/packages/ui-components/src/repos/LoadingDiff.js @@ -52,9 +52,12 @@ class LoadingDiff extends React.Component { const { diff, loading, error } = this.state; if (error) { return ; - } else if (loading || !diff) { + } else if (loading) { return ; - } else { + } else if(!diff){ + return null; + } + else { return ; } } From ddc2cbbfab959eb97dde19faacb34a0ac737b13c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 12 Dec 2018 15:59:53 +0100 Subject: [PATCH 07/76] Fix directory for file based stores --- .../scm/store/FileBasedStoreFactory.java | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/scm-dao-xml/src/main/java/sonia/scm/store/FileBasedStoreFactory.java b/scm-dao-xml/src/main/java/sonia/scm/store/FileBasedStoreFactory.java index 099ab53baa..d37a150723 100644 --- a/scm-dao-xml/src/main/java/sonia/scm/store/FileBasedStoreFactory.java +++ b/scm-dao-xml/src/main/java/sonia/scm/store/FileBasedStoreFactory.java @@ -58,8 +58,6 @@ public abstract class FileBasedStoreFactory { private RepositoryLocationResolver repositoryLocationResolver; private Store store; - private File storeDirectory; - protected FileBasedStoreFactory(SCMContextProvider contextProvider , RepositoryLocationResolver repositoryLocationResolver, Store store) { this.contextProvider = contextProvider; this.repositoryLocationResolver = repositoryLocationResolver; @@ -75,17 +73,16 @@ public abstract class FileBasedStoreFactory { } protected File getStoreLocation(String name, Class type, Repository repository) { - if (storeDirectory == null) { - if (repository != null) { - LOG.debug("create store with type: {}, name: {} and repository: {}", type, name, repository.getNamespaceAndName()); - storeDirectory = this.getStoreDirectory(store, repository); - } else { - LOG.debug("create store with type: {} and name: {} ", type, name); - storeDirectory = this.getStoreDirectory(store); - } - IOUtil.mkdirs(storeDirectory); + File storeDirectory; + if (repository != null) { + LOG.debug("create store with type: {}, name: {} and repository: {}", type, name, repository.getNamespaceAndName()); + storeDirectory = this.getStoreDirectory(store, repository); + } else { + LOG.debug("create store with type: {} and name: {} ", type, name); + storeDirectory = this.getStoreDirectory(store); } - return new File(this.storeDirectory, name); + IOUtil.mkdirs(storeDirectory); + return new File(storeDirectory, name); } /** From 9b1de3cfb4a73fd176daa7ae794d11ff9809e33f Mon Sep 17 00:00:00 2001 From: Florian Scholdei Date: Wed, 12 Dec 2018 17:14:21 +0100 Subject: [PATCH 08/76] started impementation of wordbreak for table --- scm-ui/src/repos/sources/components/FileTreeLeaf.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/scm-ui/src/repos/sources/components/FileTreeLeaf.js b/scm-ui/src/repos/sources/components/FileTreeLeaf.js index b4e2ad59ea..36bd734d11 100644 --- a/scm-ui/src/repos/sources/components/FileTreeLeaf.js +++ b/scm-ui/src/repos/sources/components/FileTreeLeaf.js @@ -10,6 +10,13 @@ import type { File } from "@scm-manager/ui-types"; const styles = { iconColumn: { width: "16px" + }, + wordBreakTable: { + WebkitHyphens: "auto", + MozHyphens: "auto", + MsHyphens: "auto", + hyphens: "auto", + wordBreak: "auto" } }; @@ -71,7 +78,7 @@ class FileTreeLeaf extends React.Component { return ( {this.createFileIcon(file)} - {this.createFileName(file)} + {this.createFileName(file)} {fileSize} From dbbe467479f9b2068d8f99b400734def0f7d71e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 12 Dec 2018 17:30:23 +0100 Subject: [PATCH 09/76] Remove old property for default branch --- .../GitRepositoryConfigResource.java | 20 ++- .../GitRepositoryConfigStoreProvider.java | 22 +++ .../sonia/scm/repository/GitConstants.java | 49 ------ .../scm/repository/GitRepositoryConfig.java | 7 + .../GitRepositoryModifyListener.java | 97 ----------- .../repository/spi/AbstractGitCommand.java | 3 +- .../sonia/scm/repository/spi/GitContext.java | 19 +- .../spi/GitRepositoryServiceProvider.java | 5 +- .../spi/GitRepositoryServiceResolver.java | 7 +- .../v2/resources/GitConfigResourceTest.java | 2 +- .../repository/GitRepositoryHandlerTest.java | 2 +- .../GitRepositoryModifyListenerTest.java | 163 ------------------ .../spi/AbstractGitCommandTestBase.java | 6 +- .../repository/spi/GitBlameCommandTest.java | 6 +- .../repository/spi/GitBrowseCommandTest.java | 6 +- .../scm/repository/spi/GitCatCommandTest.java | 4 +- .../spi/GitIncomingCommandTest.java | 6 +- .../scm/repository/spi/GitLogCommandTest.java | 6 +- .../spi/GitModificationsCommandTest.java | 8 +- .../spi/GitOutgoingCommandTest.java | 6 +- .../repository/spi/GitPushCommandTest.java | 2 +- .../InMemoryConfigurationStoreFactory.java | 44 ++++- 22 files changed, 148 insertions(+), 342 deletions(-) create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigStoreProvider.java delete mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitConstants.java delete mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryModifyListener.java delete mode 100644 scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryModifyListenerTest.java 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 af3501ae9a..031c324908 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 @@ -1,5 +1,9 @@ package sonia.scm.api.v2.resources; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import sonia.scm.event.ScmEventBus; +import sonia.scm.repository.ClearRepositoryCacheEvent; import sonia.scm.repository.GitRepositoryConfig; import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.Repository; @@ -22,15 +26,17 @@ import static sonia.scm.NotFoundException.notFound; public class GitRepositoryConfigResource { + private static final Logger LOG = LoggerFactory.getLogger(GitRepositoryConfigResource.class); + private final GitRepositoryConfigMapper repositoryConfigMapper; private final RepositoryManager repositoryManager; - private final ConfigurationStoreFactory configurationStoreFactory; + private final GitRepositoryConfigStoreProvider gitRepositoryConfigStoreProvider; @Inject - public GitRepositoryConfigResource(GitRepositoryConfigMapper repositoryConfigMapper, RepositoryManager repositoryManager, ConfigurationStoreFactory configurationStoreFactory) { + public GitRepositoryConfigResource(GitRepositoryConfigMapper repositoryConfigMapper, RepositoryManager repositoryManager, GitRepositoryConfigStoreProvider gitRepositoryConfigStoreProvider) { this.repositoryConfigMapper = repositoryConfigMapper; this.repositoryManager = repositoryManager; - this.configurationStoreFactory = configurationStoreFactory; + this.gitRepositoryConfigStoreProvider = gitRepositoryConfigStoreProvider; } @GET @@ -55,9 +61,15 @@ public class GitRepositoryConfigResource { ConfigurationStore repositoryConfigStore = getStore(repository); GitRepositoryConfig config = repositoryConfigMapper.map(dto); repositoryConfigStore.set(config); + LOG.info("git default branch of repository {} has changed, sending clear cache event", repository.getNamespaceAndName()); + sendClearRepositoryCacheEvent(repository); return Response.noContent().build(); } + private void sendClearRepositoryCacheEvent(Repository repository) { + ScmEventBus.getInstance().post(new ClearRepositoryCacheEvent(repository)); + } + private Repository getRepository(@PathParam("namespace") String namespace, @PathParam("name") String name) { NamespaceAndName namespaceAndName = new NamespaceAndName(namespace, name); Repository repository = repositoryManager.get(namespaceAndName); @@ -68,6 +80,6 @@ public class GitRepositoryConfigResource { } private ConfigurationStore getStore(Repository repository) { - return configurationStoreFactory.withType(GitRepositoryConfig.class).withName("gitConfig").forRepository(repository).build(); + return gitRepositoryConfigStoreProvider.get(repository); } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigStoreProvider.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigStoreProvider.java new file mode 100644 index 0000000000..917892968f --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigStoreProvider.java @@ -0,0 +1,22 @@ +package sonia.scm.api.v2.resources; + +import sonia.scm.repository.GitRepositoryConfig; +import sonia.scm.repository.Repository; +import sonia.scm.store.ConfigurationStore; +import sonia.scm.store.ConfigurationStoreFactory; + +import javax.inject.Inject; + +public class GitRepositoryConfigStoreProvider { + + private final ConfigurationStoreFactory configurationStoreFactory; + + @Inject + public GitRepositoryConfigStoreProvider(ConfigurationStoreFactory configurationStoreFactory) { + this.configurationStoreFactory = configurationStoreFactory; + } + + public ConfigurationStore get(Repository repository) { + return configurationStoreFactory.withType(GitRepositoryConfig.class).withName("gitConfig").forRepository(repository).build(); + } +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitConstants.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitConstants.java deleted file mode 100644 index 6d833577e1..0000000000 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitConstants.java +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) 2014, Sebastian Sdorra - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of SCM-Manager; nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * http://bitbucket.org/sdorra/scm-manager - * - */ -package sonia.scm.repository; - -/** - * Constants for Git. - * - * @author Sebastian Sdorra - * @since 1.50 - */ -public final class GitConstants { - - /** - * Default branch repository property. - */ - public static final String PROPERTY_DEFAULT_BRANCH = "git.default-branch"; - - private GitConstants() { - } - -} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryConfig.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryConfig.java index a548d82153..a0136c8ea6 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryConfig.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryConfig.java @@ -8,6 +8,13 @@ import javax.xml.bind.annotation.XmlRootElement; @XmlAccessorType(XmlAccessType.FIELD) public class GitRepositoryConfig { + public GitRepositoryConfig() { + } + + public GitRepositoryConfig(String defaultBranch) { + this.defaultBranch = defaultBranch; + } + private String defaultBranch; public String getDefaultBranch() { diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryModifyListener.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryModifyListener.java deleted file mode 100644 index 1cbcdc35bf..0000000000 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryModifyListener.java +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Copyright (c) 2014, Sebastian Sdorra - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of SCM-Manager; nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * http://bitbucket.org/sdorra/scm-manager - * - */ -package sonia.scm.repository; - -import com.github.legman.Subscribe; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Objects; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import sonia.scm.EagerSingleton; -import sonia.scm.HandlerEventType; -import sonia.scm.event.ScmEventBus; -import sonia.scm.plugin.Extension; - -/** - * Repository listener which handles git related repository events. - * - * @author Sebastian Sdorra - * @since 1.50 - */ -@Extension -@EagerSingleton -public class GitRepositoryModifyListener { - - /** - * the logger for GitRepositoryModifyListener - */ - private static final Logger logger = LoggerFactory.getLogger(GitRepositoryModifyListener.class); - - /** - * Receives {@link RepositoryModificationEvent} and fires a {@link ClearRepositoryCacheEvent} if - * the default branch of a git repository was modified. - * - * @param event repository modification event - */ - @Subscribe - public void handleEvent(RepositoryModificationEvent event){ - Repository repository = event.getItem(); - - if ( isModifyEvent(event) && - isGitRepository(event.getItem()) && - hasDefaultBranchChanged(event.getItemBeforeModification(), repository)) - { - logger.info("git default branch of repository {} has changed, sending clear cache event", repository.getId()); - sendClearRepositoryCacheEvent(repository); - } - } - - @VisibleForTesting - protected void sendClearRepositoryCacheEvent(Repository repository) { - ScmEventBus.getInstance().post(new ClearRepositoryCacheEvent(repository)); - } - - private boolean isModifyEvent(RepositoryEvent event) { - return event.getEventType() == HandlerEventType.MODIFY; - } - - private boolean isGitRepository(Repository repository) { - return GitRepositoryHandler.TYPE_NAME.equals(repository.getType()); - } - - private boolean hasDefaultBranchChanged(Repository old, Repository current) { - return !Objects.equal( - old.getProperty(GitConstants.PROPERTY_DEFAULT_BRANCH), - current.getProperty(GitConstants.PROPERTY_DEFAULT_BRANCH) - ); - } - -} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/AbstractGitCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/AbstractGitCommand.java index 2970bbd627..f94ccd59f6 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/AbstractGitCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/AbstractGitCommand.java @@ -40,7 +40,6 @@ import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import sonia.scm.repository.GitConstants; import sonia.scm.repository.GitUtil; import java.io.IOException; @@ -110,7 +109,7 @@ public class AbstractGitCommand protected Ref getBranchOrDefault(Repository gitRepository, String requestedBranch) throws IOException { if ( Strings.isNullOrEmpty(requestedBranch) ) { - String defaultBranchName = repository.getProperty(GitConstants.PROPERTY_DEFAULT_BRANCH); + String defaultBranchName = context.getConfig().getDefaultBranch(); if (!Strings.isNullOrEmpty(defaultBranchName)) { return GitUtil.getBranchId(gitRepository, defaultBranchName); } else { diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitContext.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitContext.java index b0dd8f1fd6..0b93f9cf2b 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitContext.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitContext.java @@ -37,6 +37,8 @@ package sonia.scm.repository.spi; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import sonia.scm.api.v2.resources.GitRepositoryConfigStoreProvider; +import sonia.scm.repository.GitRepositoryConfig; import sonia.scm.repository.GitUtil; import sonia.scm.repository.Repository; @@ -68,10 +70,11 @@ public class GitContext implements Closeable * @param directory * @param repository */ - public GitContext(File directory, Repository repository) + public GitContext(File directory, Repository repository, GitRepositoryConfigStoreProvider storeProvider) { this.directory = directory; this.repository = repository; + this.storeProvider = storeProvider; } //~--- methods -------------------------------------------------------------- @@ -117,11 +120,25 @@ public class GitContext implements Closeable return directory; } + GitRepositoryConfig getConfig() { + GitRepositoryConfig config = storeProvider.get(repository).get(); + if (config == null) { + return new GitRepositoryConfig(); + } else { + return config; + } + } + + void setConfig(GitRepositoryConfig newConfig) { + storeProvider.get(repository).set(newConfig); + } + //~--- fields --------------------------------------------------------------- /** Field description */ private final File directory; private final Repository repository; + private final GitRepositoryConfigStoreProvider storeProvider; /** Field description */ private org.eclipse.jgit.lib.Repository gitRepository; diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java index 936962eaba..ef3d96d5cb 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java @@ -34,6 +34,7 @@ package sonia.scm.repository.spi; import com.google.common.collect.ImmutableSet; +import sonia.scm.api.v2.resources.GitRepositoryConfigStoreProvider; import sonia.scm.repository.Feature; import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.repository.Repository; @@ -73,10 +74,10 @@ public class GitRepositoryServiceProvider extends RepositoryServiceProvider //~--- constructors --------------------------------------------------------- - public GitRepositoryServiceProvider(GitRepositoryHandler handler, Repository repository) { + public GitRepositoryServiceProvider(GitRepositoryHandler handler, Repository repository, GitRepositoryConfigStoreProvider storeProvider) { this.handler = handler; this.repository = repository; - this.context = new GitContext(handler.getDirectory(repository.getId()), repository); + this.context = new GitContext(handler.getDirectory(repository.getId()), repository, storeProvider); } //~--- methods -------------------------------------------------------------- diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java index deca141556..0730ffc9cf 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java @@ -35,6 +35,7 @@ package sonia.scm.repository.spi; //~--- non-JDK imports -------------------------------------------------------- import com.google.inject.Inject; +import sonia.scm.api.v2.resources.GitRepositoryConfigStoreProvider; import sonia.scm.plugin.Extension; import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.repository.Repository; @@ -47,10 +48,12 @@ import sonia.scm.repository.Repository; public class GitRepositoryServiceResolver implements RepositoryServiceResolver { private final GitRepositoryHandler handler; + private final GitRepositoryConfigStoreProvider storeProvider; @Inject - public GitRepositoryServiceResolver(GitRepositoryHandler handler) { + public GitRepositoryServiceResolver(GitRepositoryHandler handler, GitRepositoryConfigStoreProvider storeProvider) { this.handler = handler; + this.storeProvider = storeProvider; } @Override @@ -58,7 +61,7 @@ public class GitRepositoryServiceResolver implements RepositoryServiceResolver { GitRepositoryServiceProvider provider = null; if (GitRepositoryHandler.TYPE_NAME.equalsIgnoreCase(repository.getType())) { - provider = new GitRepositoryServiceProvider(handler, repository); + provider = new GitRepositoryServiceProvider(handler, repository, storeProvider); } return provider; 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 f4de22b2b5..0c28a28e59 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 @@ -86,7 +86,7 @@ public class GitConfigResourceTest { public void prepareEnvironment() { GitConfig gitConfig = createConfiguration(); when(repositoryHandler.getConfig()).thenReturn(gitConfig); - GitRepositoryConfigResource gitRepositoryConfigResource = new GitRepositoryConfigResource(repositoryConfigMapper, repositoryManager, configurationStoreFactory); + GitRepositoryConfigResource gitRepositoryConfigResource = new GitRepositoryConfigResource(repositoryConfigMapper, repositoryManager, new GitRepositoryConfigStoreProvider(configurationStoreFactory)); GitConfigResource gitConfigResource = new GitConfigResource(dtoToConfigMapper, configToDtoMapper, repositoryHandler, of(gitRepositoryConfigResource)); dispatcher.getRegistry().addSingletonResource(gitConfigResource); when(scmPathInfoStore.get().getApiRestUri()).thenReturn(baseUri); diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryHandlerTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryHandlerTest.java index dbd67a7f8e..cb10e15271 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryHandlerTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryHandlerTest.java @@ -53,7 +53,7 @@ import static org.mockito.Mockito.when; /** * @author Sebastian Sdorra */ -@RunWith(MockitoJUnitRunner.class) +@RunWith(MockitoJUnitRunner.Silent.class) public class GitRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase { @Mock diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryModifyListenerTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryModifyListenerTest.java deleted file mode 100644 index a542674484..0000000000 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryModifyListenerTest.java +++ /dev/null @@ -1,163 +0,0 @@ -/** - * Copyright (c) 2014, Sebastian Sdorra - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of SCM-Manager; nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * http://bitbucket.org/sdorra/scm-manager - * - */ - -package sonia.scm.repository; - -import org.junit.Test; -import static org.junit.Assert.*; -import org.junit.Before; -import sonia.scm.HandlerEventType; - -/** - * Unit tests for {@link GitRepositoryModifyListener}. - * - * @author Sebastian Sdorra - */ -public class GitRepositoryModifyListenerTest { - - private GitRepositoryModifyTestListener repositoryModifyListener; - - /** - * Set up test object. - */ - @Before - public void setUpObjectUnderTest(){ - repositoryModifyListener = new GitRepositoryModifyTestListener(); - } - - /** - * Tests happy path. - */ - @Test - public void testHandleEvent() { - Repository old = RepositoryTestData.createHeartOfGold("git"); - old.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "master"); - Repository current = RepositoryTestData.createHeartOfGold("git"); - current.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "develop"); - - RepositoryModificationEvent event = new RepositoryModificationEvent(HandlerEventType.MODIFY, current, old); - repositoryModifyListener.handleEvent(event); - - assertNotNull(repositoryModifyListener.repository); - assertSame(current, repositoryModifyListener.repository); - } - - /** - * Tests with new default branch. - */ - @Test - public void testWithNewDefaultBranch() { - Repository old = RepositoryTestData.createHeartOfGold("git"); - Repository current = RepositoryTestData.createHeartOfGold("git"); - current.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "develop"); - - RepositoryModificationEvent event = new RepositoryModificationEvent(HandlerEventType.MODIFY, current, old); - repositoryModifyListener.handleEvent(event); - - assertNotNull(repositoryModifyListener.repository); - assertSame(current, repositoryModifyListener.repository); - } - - /** - * Tests with non git repositories. - */ - @Test - public void testNonGitRepository(){ - Repository old = RepositoryTestData.createHeartOfGold("hg"); - old.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "master"); - Repository current = RepositoryTestData.createHeartOfGold("hg"); - current.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "develop"); - - RepositoryModificationEvent event = new RepositoryModificationEvent(HandlerEventType.MODIFY, current, old); - repositoryModifyListener.handleEvent(event); - - assertNull(repositoryModifyListener.repository); - } - - /** - * Tests without default branch. - */ - @Test - public void testWithoutDefaultBranch(){ - Repository old = RepositoryTestData.createHeartOfGold("git"); - Repository current = RepositoryTestData.createHeartOfGold("git"); - - RepositoryModificationEvent event = new RepositoryModificationEvent(HandlerEventType.MODIFY, current, old); - repositoryModifyListener.handleEvent(event); - - assertNull(repositoryModifyListener.repository); - } - - /** - * Tests with non modify event. - */ - @Test - public void testNonModifyEvent(){ - Repository old = RepositoryTestData.createHeartOfGold("git"); - old.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "master"); - Repository current = RepositoryTestData.createHeartOfGold("git"); - current.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "develop"); - - RepositoryModificationEvent event = new RepositoryModificationEvent(HandlerEventType.CREATE, current, old); - repositoryModifyListener.handleEvent(event); - - assertNull(repositoryModifyListener.repository); - } - - /** - * Tests with non git repositories. - */ - @Test - public void testNoModification(){ - Repository old = RepositoryTestData.createHeartOfGold("git"); - old.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "master"); - Repository current = RepositoryTestData.createHeartOfGold("git"); - current.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "master"); - - RepositoryModificationEvent event = new RepositoryModificationEvent(HandlerEventType.MODIFY, current, old); - repositoryModifyListener.handleEvent(event); - - assertNull(repositoryModifyListener.repository); - } - - private static class GitRepositoryModifyTestListener extends GitRepositoryModifyListener { - - private Repository repository; - - @Override - protected void sendClearRepositoryCacheEvent(Repository repository) { - this.repository = repository; - } - - } - - -} \ No newline at end of file diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/AbstractGitCommandTestBase.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/AbstractGitCommandTestBase.java index 0b3c1d6e9d..d6820bad06 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/AbstractGitCommandTestBase.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/AbstractGitCommandTestBase.java @@ -35,6 +35,9 @@ package sonia.scm.repository.spi; //~--- non-JDK imports -------------------------------------------------------- import org.junit.After; +import sonia.scm.api.v2.resources.GitRepositoryConfigStoreProvider; +import sonia.scm.repository.GitRepositoryConfig; +import sonia.scm.store.InMemoryConfigurationStoreFactory; /** * @@ -51,6 +54,7 @@ public class AbstractGitCommandTestBase extends ZippedRepositoryTestBase public void close() { if (context != null) { + context.setConfig(new GitRepositoryConfig()); context.close(); } } @@ -65,7 +69,7 @@ public class AbstractGitCommandTestBase extends ZippedRepositoryTestBase { if (context == null) { - context = new GitContext(repositoryDirectory, repository); + context = new GitContext(repositoryDirectory, repository, new GitRepositoryConfigStoreProvider(new InMemoryConfigurationStoreFactory())); } return context; diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitBlameCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitBlameCommandTest.java index 5757cd5d5e..817e4641dd 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitBlameCommandTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitBlameCommandTest.java @@ -35,9 +35,11 @@ package sonia.scm.repository.spi; //~--- non-JDK imports -------------------------------------------------------- import org.junit.Test; +import sonia.scm.api.v2.resources.GitRepositoryConfigStoreProvider; import sonia.scm.repository.BlameLine; import sonia.scm.repository.BlameResult; -import sonia.scm.repository.GitConstants; +import sonia.scm.repository.GitRepositoryConfig; +import sonia.scm.store.InMemoryConfigurationStoreFactory; import java.io.IOException; @@ -73,7 +75,7 @@ public class GitBlameCommandTest extends AbstractGitCommandTestBase assertEquals("fcd0ef1831e4002ac43ea539f4094334c79ea9ec", result.getLine(1).getRevision()); // set default branch and test again - repository.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "test-branch"); + createContext().setConfig(new GitRepositoryConfig("test-branch")); result = createCommand().getBlameResult(request); assertNotNull(result); assertEquals(1, result.getTotal()); diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitBrowseCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitBrowseCommandTest.java index 5e63adfb70..2ff3c73420 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitBrowseCommandTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitBrowseCommandTest.java @@ -32,9 +32,11 @@ package sonia.scm.repository.spi; import org.junit.Test; +import sonia.scm.api.v2.resources.GitRepositoryConfigStoreProvider; import sonia.scm.repository.BrowserResult; import sonia.scm.repository.FileObject; -import sonia.scm.repository.GitConstants; +import sonia.scm.repository.GitRepositoryConfig; +import sonia.scm.store.InMemoryConfigurationStoreFactory; import java.io.IOException; import java.util.Collection; @@ -78,7 +80,7 @@ public class GitBrowseCommandTest extends AbstractGitCommandTestBase { @Test public void testExplicitDefaultBranch() throws IOException { - repository.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "test-branch"); + createContext().setConfig(new GitRepositoryConfig("test-branch")); FileObject root = createCommand().getBrowserResult(new BrowseCommandRequest()).getFile(); assertNotNull(root); diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitCatCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitCatCommandTest.java index 079fcac1da..0418bc3e61 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitCatCommandTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitCatCommandTest.java @@ -38,7 +38,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import sonia.scm.NotFoundException; -import sonia.scm.repository.GitConstants; +import sonia.scm.repository.GitRepositoryConfig; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -67,7 +67,7 @@ public class GitCatCommandTest extends AbstractGitCommandTestBase { assertEquals("a\nline for blame", execute(request)); // set default branch for repository and check again - repository.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "test-branch"); + createContext().setConfig(new GitRepositoryConfig("test-branch")); assertEquals("a and b", execute(request)); } diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitIncomingCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitIncomingCommandTest.java index acf0b0f820..376d7cdf7a 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitIncomingCommandTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitIncomingCommandTest.java @@ -38,7 +38,9 @@ import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.revwalk.RevCommit; import org.junit.Ignore; import org.junit.Test; +import sonia.scm.api.v2.resources.GitRepositoryConfigStoreProvider; import sonia.scm.repository.ChangesetPagingResult; +import sonia.scm.store.InMemoryConfigurationStoreFactory; import java.io.IOException; @@ -103,7 +105,7 @@ public class GitIncomingCommandTest commit(outgoing, "added a"); - GitPullCommand pull = new GitPullCommand(handler, new GitContext(incomingDirectory, null), incomingRepository); + GitPullCommand pull = new GitPullCommand(handler, new GitContext(incomingDirectory, null, new GitRepositoryConfigStoreProvider(new InMemoryConfigurationStoreFactory())), incomingRepository); PullCommandRequest req = new PullCommandRequest(); req.setRemoteRepository(outgoingRepository); pull.pull(req); @@ -187,7 +189,7 @@ public class GitIncomingCommandTest */ private GitIncomingCommand createCommand() { - return new GitIncomingCommand(handler, new GitContext(incomingDirectory, null), + return new GitIncomingCommand(handler, new GitContext(incomingDirectory, null, new GitRepositoryConfigStoreProvider(new InMemoryConfigurationStoreFactory())), incomingRepository); } } diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitLogCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitLogCommandTest.java index 4afaf09c67..e2ab85d9a7 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitLogCommandTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitLogCommandTest.java @@ -36,9 +36,11 @@ package sonia.scm.repository.spi; import com.google.common.io.Files; import org.junit.Test; +import sonia.scm.event.ScmEventBus; import sonia.scm.repository.Changeset; import sonia.scm.repository.ChangesetPagingResult; -import sonia.scm.repository.GitConstants; +import sonia.scm.repository.ClearRepositoryCacheEvent; +import sonia.scm.repository.GitRepositoryConfig; import sonia.scm.repository.Modifications; import java.io.File; @@ -78,7 +80,7 @@ public class GitLogCommandTest extends AbstractGitCommandTestBase assertTrue(result.getChangesets().stream().allMatch(r -> r.getBranches().isEmpty())); // set default branch and fetch again - repository.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "test-branch"); + createContext().setConfig(new GitRepositoryConfig("test-branch")); result = createCommand().getChangesets(new LogCommandRequest()); diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModificationsCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModificationsCommandTest.java index 41a516a124..dbb510fb7e 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModificationsCommandTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModificationsCommandTest.java @@ -18,8 +18,8 @@ public class GitModificationsCommandTest extends AbstractRemoteCommandTestBase { @Before public void init() { - incomingModificationsCommand = new GitModificationsCommand(new GitContext(incomingDirectory, null), incomingRepository); - outgoingModificationsCommand = new GitModificationsCommand(new GitContext(outgoingDirectory, null), outgoingRepository); + incomingModificationsCommand = new GitModificationsCommand(new GitContext(incomingDirectory, null, null), incomingRepository); + outgoingModificationsCommand = new GitModificationsCommand(new GitContext(outgoingDirectory, null, null), outgoingRepository); } @Test @@ -63,12 +63,12 @@ public class GitModificationsCommandTest extends AbstractRemoteCommandTestBase { } void pushOutgoingAndPullIncoming() throws IOException { - GitPushCommand cmd = new GitPushCommand(handler, new GitContext(outgoingDirectory, null), + GitPushCommand cmd = new GitPushCommand(handler, new GitContext(outgoingDirectory, null, null), outgoingRepository); PushCommandRequest request = new PushCommandRequest(); request.setRemoteRepository(incomingRepository); cmd.push(request); - GitPullCommand pullCommand = new GitPullCommand(handler, new GitContext(incomingDirectory, null), + GitPullCommand pullCommand = new GitPullCommand(handler, new GitContext(incomingDirectory, null, null), incomingRepository); PullCommandRequest pullRequest = new PullCommandRequest(); pullRequest.setRemoteRepository(incomingRepository); diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitOutgoingCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitOutgoingCommandTest.java index 65592cf7e4..2525a6fa38 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitOutgoingCommandTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitOutgoingCommandTest.java @@ -38,7 +38,9 @@ package sonia.scm.repository.spi; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.revwalk.RevCommit; import org.junit.Test; +import sonia.scm.api.v2.resources.GitRepositoryConfigStoreProvider; import sonia.scm.repository.ChangesetPagingResult; +import sonia.scm.store.InMemoryConfigurationStoreFactory; import java.io.IOException; @@ -104,7 +106,7 @@ public class GitOutgoingCommandTest extends AbstractRemoteCommandTestBase commit(outgoing, "added a"); GitPushCommand push = new GitPushCommand(handler, - new GitContext(outgoingDirectory, null), + new GitContext(outgoingDirectory, null, null), outgoingRepository); PushCommandRequest req = new PushCommandRequest(); @@ -158,7 +160,7 @@ public class GitOutgoingCommandTest extends AbstractRemoteCommandTestBase */ private GitOutgoingCommand createCommand() { - return new GitOutgoingCommand(handler, new GitContext(outgoingDirectory, null), + return new GitOutgoingCommand(handler, new GitContext(outgoingDirectory, null, new GitRepositoryConfigStoreProvider(new InMemoryConfigurationStoreFactory())), outgoingRepository); } } diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitPushCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitPushCommandTest.java index 70212ba233..6aa831ec60 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitPushCommandTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitPushCommandTest.java @@ -98,7 +98,7 @@ public class GitPushCommandTest extends AbstractRemoteCommandTestBase */ private GitPushCommand createCommand() { - return new GitPushCommand(handler, new GitContext(outgoingDirectory, null), + return new GitPushCommand(handler, new GitContext(outgoingDirectory, null, null), outgoingRepository); } } diff --git a/scm-test/src/main/java/sonia/scm/store/InMemoryConfigurationStoreFactory.java b/scm-test/src/main/java/sonia/scm/store/InMemoryConfigurationStoreFactory.java index 2c5641bfd1..99ef942ebc 100644 --- a/scm-test/src/main/java/sonia/scm/store/InMemoryConfigurationStoreFactory.java +++ b/scm-test/src/main/java/sonia/scm/store/InMemoryConfigurationStoreFactory.java @@ -35,15 +35,55 @@ package sonia.scm.store; //~--- non-JDK imports -------------------------------------------------------- +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + /** * In memory configuration store factory for testing purposes. - * + * * @author Sebastian Sdorra */ public class InMemoryConfigurationStoreFactory implements ConfigurationStoreFactory { + private static final Map STORES = new HashMap<>(); + @Override public ConfigurationStore getStore(TypedStoreParameters storeParameters) { - return new InMemoryConfigurationStore<>(); + Key key = new Key(storeParameters.getType(), storeParameters.getName(), storeParameters.getRepository() == null? "-": storeParameters.getRepository().getId()); + if (STORES.containsKey(key)) { + return STORES.get(key); + } else { + InMemoryConfigurationStore store = new InMemoryConfigurationStore<>(); + STORES.put(key, store); + return store; + } + } + + private static class Key { + private final Class type; + private final String name; + private final String id; + + public Key(Class type, String name, String id) { + this.type = type; + this.name = name; + this.id = id; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Key key = (Key) o; + return Objects.equals(type, key.type) && + Objects.equals(name, key.name) && + Objects.equals(id, key.id); + } + + @Override + public int hashCode() { + return Objects.hash(type, name, id); + } } } From db092e57e741307e3a2b1d5494ed771e9710c084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 12 Dec 2018 18:49:38 +0100 Subject: [PATCH 10/76] Move cache event to central position --- .../GitRepositoryConfigResource.java | 8 ----- .../GitRepositoryConfigStoreProvider.java | 30 ++++++++++++++++++- 2 files changed, 29 insertions(+), 9 deletions(-) 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 031c324908..9a85fdf1f3 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 @@ -2,14 +2,11 @@ package sonia.scm.api.v2.resources; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import sonia.scm.event.ScmEventBus; -import sonia.scm.repository.ClearRepositoryCacheEvent; import sonia.scm.repository.GitRepositoryConfig; import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryManager; import sonia.scm.store.ConfigurationStore; -import sonia.scm.store.ConfigurationStoreFactory; import sonia.scm.web.GitVndMediaType; import javax.inject.Inject; @@ -62,14 +59,9 @@ public class GitRepositoryConfigResource { GitRepositoryConfig config = repositoryConfigMapper.map(dto); repositoryConfigStore.set(config); LOG.info("git default branch of repository {} has changed, sending clear cache event", repository.getNamespaceAndName()); - sendClearRepositoryCacheEvent(repository); return Response.noContent().build(); } - private void sendClearRepositoryCacheEvent(Repository repository) { - ScmEventBus.getInstance().post(new ClearRepositoryCacheEvent(repository)); - } - private Repository getRepository(@PathParam("namespace") String namespace, @PathParam("name") String name) { NamespaceAndName namespaceAndName = new NamespaceAndName(namespace, name); Repository repository = repositoryManager.get(namespaceAndName); diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigStoreProvider.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigStoreProvider.java index 917892968f..d7ab5707d5 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigStoreProvider.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigStoreProvider.java @@ -1,5 +1,7 @@ package sonia.scm.api.v2.resources; +import sonia.scm.event.ScmEventBus; +import sonia.scm.repository.ClearRepositoryCacheEvent; import sonia.scm.repository.GitRepositoryConfig; import sonia.scm.repository.Repository; import sonia.scm.store.ConfigurationStore; @@ -17,6 +19,32 @@ public class GitRepositoryConfigStoreProvider { } public ConfigurationStore get(Repository repository) { - return configurationStoreFactory.withType(GitRepositoryConfig.class).withName("gitConfig").forRepository(repository).build(); + return new StoreWrapper(configurationStoreFactory.withType(GitRepositoryConfig.class).withName("gitConfig").forRepository(repository).build(), repository); + } + + private static class StoreWrapper implements ConfigurationStore { + + private final ConfigurationStore delegate; + private final Repository repository; + + private StoreWrapper(ConfigurationStore delegate, Repository repository) { + this.delegate = delegate; + this.repository = repository; + } + + @Override + public GitRepositoryConfig get() { + return delegate.get(); + } + + @Override + public void set(GitRepositoryConfig object) { + delegate.set(object); + sendClearRepositoryCacheEvent(); + } + + private void sendClearRepositoryCacheEvent() { + ScmEventBus.getInstance().post(new ClearRepositoryCacheEvent(repository)); + } } } From c3e6e28262ee1725a719a99093638d862b1a10a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 13 Dec 2018 08:18:04 +0100 Subject: [PATCH 11/76] Fix type --- .../src/main/java/sonia/scm/store/ConfigurationStore.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/store/ConfigurationStore.java b/scm-core/src/main/java/sonia/scm/store/ConfigurationStore.java index a7f21dd304..1e14b848b0 100644 --- a/scm-core/src/main/java/sonia/scm/store/ConfigurationStore.java +++ b/scm-core/src/main/java/sonia/scm/store/ConfigurationStore.java @@ -58,7 +58,7 @@ public interface ConfigurationStore * Stores the given configuration object to the store. * * - * @param obejct configuration object to store + * @param object configuration object to store */ - public void set(T obejct); + public void set(T object); } From 24cd9c3f8c6b3b96183dd7a25a777b5c281ec12f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 13 Dec 2018 09:22:10 +0100 Subject: [PATCH 12/76] Introduce repository config change event to clear caches --- ...figChangeClearRepositoryCacheListener.java | 19 ++++++++++++ .../GitRepositoryConfigChangedEvent.java | 30 +++++++++++++++++++ .../GitRepositoryConfigResource.java | 3 -- .../GitRepositoryConfigStoreProvider.java | 18 +++++------ 4 files changed, 58 insertions(+), 12 deletions(-) create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigChangeClearRepositoryCacheListener.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigChangedEvent.java diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigChangeClearRepositoryCacheListener.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigChangeClearRepositoryCacheListener.java new file mode 100644 index 0000000000..df93fa4886 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigChangeClearRepositoryCacheListener.java @@ -0,0 +1,19 @@ +package sonia.scm.api.v2.resources; + +import com.github.legman.Subscribe; +import sonia.scm.EagerSingleton; +import sonia.scm.event.ScmEventBus; +import sonia.scm.plugin.Extension; +import sonia.scm.repository.ClearRepositoryCacheEvent; + +import java.util.Objects; + +@EagerSingleton @Extension +public class GitRepositoryConfigChangeClearRepositoryCacheListener { + @Subscribe + public void sendClearRepositoryCacheEvent(GitRepositoryConfigChangedEvent event) { + if (!Objects.equals(event.getOldConfig().getDefaultBranch(), event.getNewConfig().getDefaultBranch())) { + ScmEventBus.getInstance().post(new ClearRepositoryCacheEvent(event.getRepository())); + } + } +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigChangedEvent.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigChangedEvent.java new file mode 100644 index 0000000000..eaf575a610 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigChangedEvent.java @@ -0,0 +1,30 @@ +package sonia.scm.api.v2.resources; + +import sonia.scm.event.Event; +import sonia.scm.repository.GitRepositoryConfig; +import sonia.scm.repository.Repository; + +@Event +public class GitRepositoryConfigChangedEvent { + private final Repository repository; + private final GitRepositoryConfig oldConfig; + private final GitRepositoryConfig newConfig; + + public GitRepositoryConfigChangedEvent(Repository repository, GitRepositoryConfig oldConfig, GitRepositoryConfig newConfig) { + this.repository = repository; + this.oldConfig = oldConfig; + this.newConfig = newConfig; + } + + public Repository getRepository() { + return repository; + } + + public GitRepositoryConfig getOldConfig() { + return oldConfig; + } + + public GitRepositoryConfig getNewConfig() { + return newConfig; + } +} 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 9a85fdf1f3..277e712b92 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 @@ -43,9 +43,6 @@ public class GitRepositoryConfigResource { Repository repository = getRepository(namespace, name); ConfigurationStore repositoryConfigStore = getStore(repository); GitRepositoryConfig config = repositoryConfigStore.get(); - if (config == null) { - config = new GitRepositoryConfig(); - } GitRepositoryConfigDto dto = repositoryConfigMapper.map(config, repository); return Response.ok(dto).build(); } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigStoreProvider.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigStoreProvider.java index d7ab5707d5..ce37fb65f4 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigStoreProvider.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigStoreProvider.java @@ -1,7 +1,6 @@ package sonia.scm.api.v2.resources; import sonia.scm.event.ScmEventBus; -import sonia.scm.repository.ClearRepositoryCacheEvent; import sonia.scm.repository.GitRepositoryConfig; import sonia.scm.repository.Repository; import sonia.scm.store.ConfigurationStore; @@ -34,17 +33,18 @@ public class GitRepositoryConfigStoreProvider { @Override public GitRepositoryConfig get() { - return delegate.get(); + GitRepositoryConfig config = delegate.get(); + if (config == null) { + return new GitRepositoryConfig(); + } + return config; } @Override - public void set(GitRepositoryConfig object) { - delegate.set(object); - sendClearRepositoryCacheEvent(); - } - - private void sendClearRepositoryCacheEvent() { - ScmEventBus.getInstance().post(new ClearRepositoryCacheEvent(repository)); + public void set(GitRepositoryConfig newConfig) { + GitRepositoryConfig oldConfig = get(); + delegate.set(newConfig); + ScmEventBus.getInstance().post(new GitRepositoryConfigChangedEvent(repository, oldConfig, newConfig)); } } } From b392e3f9d2608feee32ae4a80a80313e12f96848 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 13 Dec 2018 09:38:41 +0100 Subject: [PATCH 13/76] Fix content type for simple exception mappers --- .../src/main/java/sonia/scm/api/rest/StatusExceptionMapper.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/StatusExceptionMapper.java b/scm-webapp/src/main/java/sonia/scm/api/rest/StatusExceptionMapper.java index 6f4978637e..1590154369 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/StatusExceptionMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/StatusExceptionMapper.java @@ -36,6 +36,7 @@ package sonia.scm.api.rest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.ext.ExceptionMapper; @@ -92,6 +93,7 @@ public class StatusExceptionMapper return Response.status(status) .entity(exception.getMessage()) + .type(MediaType.TEXT_PLAIN_TYPE) .build(); } } From 9e963b6aeb0786fa7f60377aefbe2ec5d0e0f3a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 13 Dec 2018 10:00:03 +0100 Subject: [PATCH 14/76] Enrich repository collection, too --- .../GitRepositoryConfigEnricher.java | 24 ++- .../GitRepositoryConfigEnricherTest.java | 152 ++++++++++++++++++ .../sonia/scm/repository/repository-001.json | 42 +++++ .../repository/repository-collection-001.json | 106 ++++++++++++ 4 files changed, 319 insertions(+), 5 deletions(-) create mode 100644 scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitRepositoryConfigEnricherTest.java create mode 100644 scm-plugins/scm-git-plugin/src/test/resources/sonia/scm/repository/repository-001.json create mode 100644 scm-plugins/scm-git-plugin/src/test/resources/sonia/scm/repository/repository-collection-001.json diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigEnricher.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigEnricher.java index 55c565f162..58634464ec 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigEnricher.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigEnricher.java @@ -3,6 +3,8 @@ package sonia.scm.api.v2.resources; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import sonia.scm.plugin.Extension; +import sonia.scm.repository.NamespaceAndName; +import sonia.scm.repository.RepositoryManager; import sonia.scm.web.JsonEnricherBase; import sonia.scm.web.JsonEnricherContext; @@ -11,31 +13,43 @@ import javax.inject.Provider; import static java.util.Collections.singletonMap; import static sonia.scm.web.VndMediaType.REPOSITORY; +import static sonia.scm.web.VndMediaType.REPOSITORY_COLLECTION; @Extension public class GitRepositoryConfigEnricher extends JsonEnricherBase { private final Provider scmPathInfoStore; + private final RepositoryManager manager; @Inject - public GitRepositoryConfigEnricher(Provider scmPathInfoStore, ObjectMapper objectMapper) { + public GitRepositoryConfigEnricher(Provider scmPathInfoStore, ObjectMapper objectMapper, RepositoryManager manager) { super(objectMapper); this.scmPathInfoStore = scmPathInfoStore; + this.manager = manager; } @Override public void enrich(JsonEnricherContext context) { if (resultHasMediaType(REPOSITORY, context)) { JsonNode repositoryNode = context.getResponseEntity(); - String namespace = repositoryNode.get("namespace").asText(); - String name = repositoryNode.get("name").asText(); + enrichRepositoryNode(repositoryNode); + } else if (resultHasMediaType(REPOSITORY_COLLECTION, context)) { + JsonNode repositoryCollectionNode = context.getResponseEntity().get("_embedded").withArray("repositories"); + repositoryCollectionNode.elements().forEachRemaining(this::enrichRepositoryNode); + } + } - String newPullRequest = new LinkBuilder(scmPathInfoStore.get().get(), GitConfigResource.class) + private void enrichRepositoryNode(JsonNode repositoryNode) { + String namespace = repositoryNode.get("namespace").asText(); + String name = repositoryNode.get("name").asText(); + + if ("git".equals(manager.get(new NamespaceAndName(namespace, name)).getType())) { + String repositoryConfigLink = new LinkBuilder(scmPathInfoStore.get().get(), GitConfigResource.class) .method("getRepositoryConfig") .parameters(namespace, name) .href(); - JsonNode newPullRequestNode = createObject(singletonMap("href", value(newPullRequest))); + JsonNode newPullRequestNode = createObject(singletonMap("href", value(repositoryConfigLink))); addPropertyNode(repositoryNode.get("_links"), "configuration", newPullRequestNode); } diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitRepositoryConfigEnricherTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitRepositoryConfigEnricherTest.java new file mode 100644 index 0000000000..d2942d08a3 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitRepositoryConfigEnricherTest.java @@ -0,0 +1,152 @@ +package sonia.scm.api.v2.resources; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.io.Resources; +import com.google.inject.Provider; +import com.google.inject.util.Providers; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +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.NamespaceAndName; +import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryManager; +import sonia.scm.repository.api.Command; +import sonia.scm.repository.api.RepositoryService; +import sonia.scm.repository.api.RepositoryServiceFactory; +import sonia.scm.web.JsonEnricherContext; +import sonia.scm.web.VndMediaType; + +import javax.ws.rs.core.MediaType; +import java.io.IOException; +import java.net.URI; +import java.net.URL; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class GitRepositoryConfigEnricherTest { + + private final ObjectMapper objectMapper = new ObjectMapper(); + private GitRepositoryConfigEnricher linkEnricher; + private JsonNode rootNode; + @Mock + private RepositoryManager manager; + + @BeforeEach + void globalSetUp() { + ScmPathInfoStore pathInfoStore = new ScmPathInfoStore(); + pathInfoStore.set(() -> URI.create("/")); + Provider pathInfoStoreProvider = Providers.of(pathInfoStore); + + linkEnricher = new GitRepositoryConfigEnricher(pathInfoStoreProvider, objectMapper, manager); + } + + @Nested + class ForSingleRepository { + @BeforeEach + void setUp() throws IOException { + URL resource = Resources.getResource("sonia/scm/repository/repository-001.json"); + rootNode = objectMapper.readTree(resource); + + when(manager.get(new NamespaceAndName("scmadmin", "web-resources"))).thenReturn(new Repository("id", "git", "scmadmin", "web-resources")); + } + + @Test + void shouldEnrichGitRepositories() { + JsonEnricherContext context = new JsonEnricherContext( + URI.create("/"), + MediaType.valueOf(VndMediaType.REPOSITORY), + rootNode + ); + + linkEnricher.enrich(context); + + String configLink = context.getResponseEntity() + .get("_links") + .get("configuration") + .get("href") + .asText(); + + assertThat(configLink).isEqualTo("/v2/config/git/scmadmin/web-resources"); + } + + @Test + void shouldNotEnrichOtherRepositories() { + when(manager.get(new NamespaceAndName("scmadmin", "web-resources"))).thenReturn(new Repository("id", "hg", "scmadmin", "web-resources")); + + JsonEnricherContext context = new JsonEnricherContext( + URI.create("/"), + MediaType.valueOf(VndMediaType.REPOSITORY), + rootNode + ); + + linkEnricher.enrich(context); + + JsonNode configLink = context.getResponseEntity() + .get("_links") + .get("configuration"); + + assertThat(configLink).isNull(); + } + } + + @Nested + class ForRepositoryCollection { + @BeforeEach + void setUp() throws IOException { + URL resource = Resources.getResource("sonia/scm/repository/repository-collection-001.json"); + rootNode = objectMapper.readTree(resource); + + when(manager.get(new NamespaceAndName("scmadmin", "web-resources"))).thenReturn(new Repository("id", "git", "scmadmin", "web-resources")); + } + + @Test + void shouldEnrichAllRepositories() { + JsonEnricherContext context = new JsonEnricherContext( + URI.create("/"), + MediaType.valueOf(VndMediaType.REPOSITORY_COLLECTION), + rootNode + ); + + linkEnricher.enrich(context); + + context.getResponseEntity() + .get("_embedded") + .withArray("repositories") + .elements() + .forEachRemaining(node -> { + String configLink = node + .get("_links") + .get("configuration") + .get("href") + .asText(); + + assertThat(configLink).isEqualTo("/v2/config/git/scmadmin/web-resources"); + }); + } + } + + @Test + void shouldNotModifyObjectsWithUnsupportedMediaType() throws IOException { + URL resource = Resources.getResource("sonia/scm/repository/repository-001.json"); + rootNode = objectMapper.readTree(resource); + JsonEnricherContext context = new JsonEnricherContext( + URI.create("/"), + MediaType.valueOf(VndMediaType.USER), + rootNode + ); + + linkEnricher.enrich(context); + + boolean hasNewPullRequestLink = context.getResponseEntity() + .get("_links") + .has("configuration"); + + assertThat(hasNewPullRequestLink).isFalse(); + } +} diff --git a/scm-plugins/scm-git-plugin/src/test/resources/sonia/scm/repository/repository-001.json b/scm-plugins/scm-git-plugin/src/test/resources/sonia/scm/repository/repository-001.json new file mode 100644 index 0000000000..43ea136942 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/test/resources/sonia/scm/repository/repository-001.json @@ -0,0 +1,42 @@ +{ + "creationDate": "2018-11-09T09:48:32.732Z", + "description": "Handling static webresources made easy", + "healthCheckFailures": [], + "lastModified": "2018-11-09T09:49:20.973Z", + "namespace": "scmadmin", + "name": "web-resources", + "archived": false, + "type": "git", + "_links": { + "self": { + "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources" + }, + "delete": { + "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources" + }, + "update": { + "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources" + }, + "permissions": { + "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/permissions/" + }, + "protocol": [ + { + "href": "http://localhost:8081/scm/repo/scmadmin/web-resources", + "name": "http" + } + ], + "tags": { + "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/tags/" + }, + "branches": { + "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/branches/" + }, + "changesets": { + "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/changesets/" + }, + "sources": { + "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/sources/" + } + } +} diff --git a/scm-plugins/scm-git-plugin/src/test/resources/sonia/scm/repository/repository-collection-001.json b/scm-plugins/scm-git-plugin/src/test/resources/sonia/scm/repository/repository-collection-001.json new file mode 100644 index 0000000000..f4eeb24bbc --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/test/resources/sonia/scm/repository/repository-collection-001.json @@ -0,0 +1,106 @@ +{ + "page": 0, + "pageTotal": 1, + "_links": { + "self": { + "href": "http://localhost:8081/scm/api/v2/repositories/?page=0&pageSize=10" + }, + "first": { + "href": "http://localhost:8081/scm/api/v2/repositories/?page=0&pageSize=10" + }, + "last": { + "href": "http://localhost:8081/scm/api/v2/repositories/?page=0&pageSize=10" + }, + "create": { + "href": "http://localhost:8081/scm/api/v2/repositories/" + } + }, + "_embedded": { + "repositories": [ + { + "creationDate": "2018-11-09T09:48:32.732Z", + "description": "Handling static webresources made easy", + "healthCheckFailures": [], + "lastModified": "2018-11-09T09:49:20.973Z", + "namespace": "scmadmin", + "name": "web-resources", + "archived": false, + "type": "git", + "_links": { + "self": { + "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources" + }, + "delete": { + "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources" + }, + "update": { + "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources" + }, + "permissions": { + "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/permissions/" + }, + "protocol": [ + { + "href": "http://localhost:8081/scm/repo/scmadmin/web-resources", + "name": "http" + } + ], + "tags": { + "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/tags/" + }, + "branches": { + "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/branches/" + }, + "changesets": { + "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/changesets/" + }, + "sources": { + "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/sources/" + } + } + }, + { + "creationDate": "2018-11-09T09:48:32.732Z", + "description": "Handling static webresources made easy", + "healthCheckFailures": [], + "lastModified": "2018-11-09T09:49:20.973Z", + "namespace": "scmadmin", + "name": "web-resources", + "archived": false, + "type": "git", + "_links": { + "self": { + "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources" + }, + "delete": { + "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources" + }, + "update": { + "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources" + }, + "permissions": { + "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/permissions/" + }, + "protocol": [ + { + "href": "http://localhost:8081/scm/repo/scmadmin/web-resources", + "name": "http" + } + ], + "tags": { + "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/tags/" + }, + "branches": { + "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/branches/" + }, + "changesets": { + "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/changesets/" + }, + "sources": { + "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/sources/" + } + } + } + ] + } +} From 360cba6c500029ad9ce1c8439639c5db80e06f3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 13 Dec 2018 11:32:44 +0100 Subject: [PATCH 15/76] Use constant --- .../scm/api/v2/resources/GitRepositoryConfigEnricher.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigEnricher.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigEnricher.java index 58634464ec..5aecd4229d 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigEnricher.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitRepositoryConfigEnricher.java @@ -3,6 +3,7 @@ package sonia.scm.api.v2.resources; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import sonia.scm.plugin.Extension; +import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.RepositoryManager; import sonia.scm.web.JsonEnricherBase; @@ -43,7 +44,7 @@ public class GitRepositoryConfigEnricher extends JsonEnricherBase { String namespace = repositoryNode.get("namespace").asText(); String name = repositoryNode.get("name").asText(); - if ("git".equals(manager.get(new NamespaceAndName(namespace, name)).getType())) { + if (GitRepositoryHandler.TYPE_NAME.equals(manager.get(new NamespaceAndName(namespace, name)).getType())) { String repositoryConfigLink = new LinkBuilder(scmPathInfoStore.get().get(), GitConfigResource.class) .method("getRepositoryConfig") .parameters(namespace, name) From 3a62f81ba0f50e253fafadd7e2ac3ec889c8197c Mon Sep 17 00:00:00 2001 From: Janika Kefel Date: Thu, 13 Dec 2018 14:49:59 +0100 Subject: [PATCH 16/76] Added first UI changes --- .../packages/ui-components/src/HelpIcon.js | 36 +- .../ui-components/src/buttons/AddButton.js | 22 +- .../ui-components/src/buttons/CreateButton.js | 51 +- .../ui-components/src/layout/Header.js | 62 +- scm-ui/public/images/scmManagerHero.jpg | Bin 0 -> 128042 bytes .../config/components/form/AdminSettings.js | 179 +- .../config/components/form/BaseUrlSettings.js | 101 +- .../config/components/form/GeneralSettings.js | 302 +- .../config/components/form/LoginAttempt.js | 188 +- .../config/components/form/ProxySettings.js | 272 +- scm-ui/src/config/containers/Config.js | 172 +- .../src/groups/components/table/GroupTable.js | 66 +- .../components/list/RepositoryGroupEntry.js | 135 +- scm-ui/src/users/components/table/UserRow.js | 62 +- .../src/users/components/table/UserTable.js | 72 +- scm-ui/src/users/containers/Users.js | 286 +- scm-ui/styles/scm.css | 10277 +--------------- scm-ui/styles/scm.scss | 298 +- 18 files changed, 1339 insertions(+), 11242 deletions(-) create mode 100644 scm-ui/public/images/scmManagerHero.jpg diff --git a/scm-ui-components/packages/ui-components/src/HelpIcon.js b/scm-ui-components/packages/ui-components/src/HelpIcon.js index fba8ead422..a794ae2915 100644 --- a/scm-ui-components/packages/ui-components/src/HelpIcon.js +++ b/scm-ui-components/packages/ui-components/src/HelpIcon.js @@ -1,14 +1,22 @@ -//@flow -import React from "react"; -import classNames from "classnames"; - -type Props = { -}; - -class HelpIcon extends React.Component { - render() { - return - } -} - -export default HelpIcon; +//@flow +import React from "react"; +import injectSheet from "react-jss"; +import classNames from "classnames"; + +type Props = { +}; + +const styles = { + textinfo: { + color: "#98d8f3 !important" + } +}; + +class HelpIcon extends React.Component { + render() { + const { classes } = this.props; + return + } +} + +export default injectSheet(styles)(HelpIcon); diff --git a/scm-ui-components/packages/ui-components/src/buttons/AddButton.js b/scm-ui-components/packages/ui-components/src/buttons/AddButton.js index de72bdaab9..8f46fb66a4 100644 --- a/scm-ui-components/packages/ui-components/src/buttons/AddButton.js +++ b/scm-ui-components/packages/ui-components/src/buttons/AddButton.js @@ -1,11 +1,11 @@ -//@flow -import React from "react"; -import Button, { type ButtonProps } from "./Button"; - -class AddButton extends React.Component { - render() { - return