diff --git a/docs/dtd/plugin/2.0.0-01.dtd b/docs/dtd/plugin/2.0.0-01.dtd index 4b330fd652..954a2c2219 100644 --- a/docs/dtd/plugin/2.0.0-01.dtd +++ b/docs/dtd/plugin/2.0.0-01.dtd @@ -46,11 +46,11 @@ - - + + - - + + diff --git a/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java b/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java index 5c504291d2..b50c64b321 100644 --- a/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java +++ b/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java @@ -73,9 +73,7 @@ public class ScmConfiguration implements Configuration { * Default plugin url */ public static final String DEFAULT_PLUGINURL = - "http://download.scm-manager.org/api/v2/plugins.json"; - // Keep the parameters - // "http://plugins.scm-manager.org/scm-plugin-backend/api/{version}/plugins?os={os}&arch={arch}&snapshot=false"; + "http://download.scm-manager.org/api/v2/plugins.json?os={os}&arch={arch}&snapshot=false&version={version}"; /** * Default plugin url from version 1.0 diff --git a/scm-core/src/main/java/sonia/scm/plugin/PluginInformation.java b/scm-core/src/main/java/sonia/scm/plugin/PluginInformation.java index bb33069afe..22911041d4 100644 --- a/scm-core/src/main/java/sonia/scm/plugin/PluginInformation.java +++ b/scm-core/src/main/java/sonia/scm/plugin/PluginInformation.java @@ -35,10 +35,7 @@ package sonia.scm.plugin; import com.github.sdorra.ssp.PermissionObject; import com.github.sdorra.ssp.StaticPermissions; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.Setter; -import lombok.ToString; +import lombok.Data; import sonia.scm.Validateable; import sonia.scm.util.Util; @@ -52,6 +49,7 @@ import java.io.Serializable; /** * @author Sebastian Sdorra */ +@Data @StaticPermissions( value = "plugin", generatedClass = "PluginPermissions", @@ -61,40 +59,34 @@ import java.io.Serializable; ) @XmlAccessorType(XmlAccessType.FIELD) @XmlRootElement(name = "plugin-information") -@Getter -@Setter -@EqualsAndHashCode -@ToString public class PluginInformation implements PermissionObject, Validateable, Cloneable, Serializable { private static final long serialVersionUID = 461382048865977206L; - private String author; - private String category; - private PluginCondition condition; - private String description; private String name; - private PluginState state; private String version; private String displayName; + private String description; + private String author; + private String category; private String avatarUrl; + private PluginCondition condition; + private PluginState state; @Override public PluginInformation clone() { PluginInformation clone = new PluginInformation(); clone.setName(name); - clone.setAuthor(author); - clone.setCategory(category); - clone.setDescription(description); - clone.setState(state); clone.setVersion(version); clone.setDisplayName(displayName); + clone.setDescription(description); + clone.setAuthor(author); + clone.setCategory(category); clone.setAvatarUrl(avatarUrl); - + clone.setState(state); if (condition != null) { clone.setCondition(condition.clone()); } - return clone; } diff --git a/scm-plugins/scm-git-plugin/pom.xml b/scm-plugins/scm-git-plugin/pom.xml index a838e2f146..7f5531691f 100644 --- a/scm-plugins/scm-git-plugin/pom.xml +++ b/scm-plugins/scm-git-plugin/pom.xml @@ -10,7 +10,7 @@ scm-git-plugin - scm-git-plugin + Git smp https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Git diff --git a/scm-plugins/scm-git-plugin/src/main/resources/META-INF/scm/plugin.xml b/scm-plugins/scm-git-plugin/src/main/resources/META-INF/scm/plugin.xml index ff699441a8..1706603e8a 100644 --- a/scm-plugins/scm-git-plugin/src/main/resources/META-INF/scm/plugin.xml +++ b/scm-plugins/scm-git-plugin/src/main/resources/META-INF/scm/plugin.xml @@ -47,13 +47,7 @@ Sebastian Sdorra - Git - - git - scm - vcs - dvcs - + Source Code Management diff --git a/scm-plugins/scm-hg-plugin/pom.xml b/scm-plugins/scm-hg-plugin/pom.xml index 025f79add3..ace7642e91 100644 --- a/scm-plugins/scm-hg-plugin/pom.xml +++ b/scm-plugins/scm-hg-plugin/pom.xml @@ -10,7 +10,7 @@ scm-hg-plugin - scm-hg-plugin + Mercurial smp https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Mercurial diff --git a/scm-plugins/scm-hg-plugin/src/main/resources/META-INF/scm/plugin.xml b/scm-plugins/scm-hg-plugin/src/main/resources/META-INF/scm/plugin.xml index 1d0b05c4a8..90d4270a40 100644 --- a/scm-plugins/scm-hg-plugin/src/main/resources/META-INF/scm/plugin.xml +++ b/scm-plugins/scm-hg-plugin/src/main/resources/META-INF/scm/plugin.xml @@ -47,14 +47,7 @@ jo Sebastian Sdorra - Mercurial - - mercurial - hg - scm - vcs - dvcs - + Source Code Management diff --git a/scm-plugins/scm-legacy-plugin/pom.xml b/scm-plugins/scm-legacy-plugin/pom.xml index 6cfa74ea61..5f876beaa2 100644 --- a/scm-plugins/scm-legacy-plugin/pom.xml +++ b/scm-plugins/scm-legacy-plugin/pom.xml @@ -6,8 +6,10 @@ scm-plugins 2.0.0-SNAPSHOT - sonia.scm.plugins + scm-legacy-plugin + Legacy + Support migrated repository urls and v1 passwords 2.0.0-SNAPSHOT smp @@ -21,6 +23,7 @@ ${servlet.version} provided + javax.ws.rs jsr311-api diff --git a/scm-plugins/scm-svn-plugin/pom.xml b/scm-plugins/scm-svn-plugin/pom.xml index 4386efde5b..b924997711 100644 --- a/scm-plugins/scm-svn-plugin/pom.xml +++ b/scm-plugins/scm-svn-plugin/pom.xml @@ -10,7 +10,7 @@ scm-svn-plugin - scm-svn-plugin + Subversion smp https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Subversion diff --git a/scm-plugins/scm-svn-plugin/src/main/resources/META-INF/scm/plugin.xml b/scm-plugins/scm-svn-plugin/src/main/resources/META-INF/scm/plugin.xml index 302abd2b10..7a36cc1486 100644 --- a/scm-plugins/scm-svn-plugin/src/main/resources/META-INF/scm/plugin.xml +++ b/scm-plugins/scm-svn-plugin/src/main/resources/META-INF/scm/plugin.xml @@ -47,13 +47,7 @@ Sebastian Sdorra - Subversion - - subversion - scm - vcs - svn - + Source Code Management diff --git a/scm-ui-components/packages/ui-types/src/Plugin.js b/scm-ui-components/packages/ui-types/src/Plugin.js index 5a4b015224..3f4f9858c1 100644 --- a/scm-ui-components/packages/ui-types/src/Plugin.js +++ b/scm-ui-components/packages/ui-types/src/Plugin.js @@ -1,14 +1,15 @@ //@flow import type {Collection, Links} from "./hal"; + export type Plugin = { name: string, - type: string, version: string, - author: string, displayName: string, - avatarUrl: string, description?: string, + author: string, + category: string, + avatarUrl: string, _links: Links }; diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MapperModule.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MapperModule.java index cf09eeb128..0b419cf542 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MapperModule.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MapperModule.java @@ -54,5 +54,7 @@ public class MapperModule extends AbstractModule { bind(UIPluginDtoCollectionMapper.class); bind(ScmPathInfoStore.class).in(ServletScopes.REQUEST); + + bind(PluginDtoMapper.class).to(Mappers.getMapper(PluginDtoMapper.class).getClass()); } } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginCenterDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginCenterDtoMapper.java deleted file mode 100644 index 3a4e8a1947..0000000000 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginCenterDtoMapper.java +++ /dev/null @@ -1,33 +0,0 @@ -package sonia.scm.api.v2.resources; - -import sonia.scm.plugin.PluginCondition; -import sonia.scm.plugin.PluginInformation; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -public class PluginCenterDtoMapper { - - public static Set map(List plugins) { - HashSet pluginInformationSet = new HashSet<>(); - - for (PluginCenterDto.Plugin plugin : plugins) { - - PluginInformation pluginInformation = new PluginInformation(); - pluginInformation.setName(plugin.getName()); - pluginInformation.setAuthor(plugin.getAuthor()); - pluginInformation.setCategory(plugin.getCategory()); - pluginInformation.setVersion(plugin.getVersion()); - pluginInformation.setDescription(plugin.getDescription()); - - if (plugin.getConditions() != null) { - PluginCenterDto.Condition condition = plugin.getConditions(); - pluginInformation.setCondition(new PluginCondition(condition.getMinVersion(), condition.getOs(), condition.getArch())); - } - - pluginInformationSet.add(pluginInformation); - } - return pluginInformationSet; - } -} diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDto.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDto.java index 75386aed63..b096266537 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDto.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDto.java @@ -12,11 +12,12 @@ import lombok.Setter; public class PluginDto extends HalRepresentation { private String name; - private String category; private String version; - private String author; - private String avatarUrl; + private String displayName; private String description; + private String author; + private String category; + private String avatarUrl; public PluginDto(Links links) { add(links); diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDtoMapper.java index 020e706e43..ca81edd7ff 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDtoMapper.java @@ -1,6 +1,10 @@ package sonia.scm.api.v2.resources; import de.otto.edison.hal.Links; +import org.mapstruct.AfterMapping; +import org.mapstruct.Mapper; +import org.mapstruct.MappingTarget; +import org.mapstruct.ObjectFactory; import sonia.scm.plugin.PluginInformation; import sonia.scm.plugin.PluginState; import sonia.scm.plugin.PluginWrapper; @@ -10,20 +14,27 @@ import javax.inject.Inject; import static de.otto.edison.hal.Link.link; import static de.otto.edison.hal.Links.linkingTo; -public class PluginDtoMapper { - - private final ResourceLinks resourceLinks; +@Mapper +public abstract class PluginDtoMapper { @Inject - public PluginDtoMapper(ResourceLinks resourceLinks) { - this.resourceLinks = resourceLinks; - } + private ResourceLinks resourceLinks; public PluginDto map(PluginWrapper plugin) { return map(plugin.getPlugin().getInformation()); } - public PluginDto map(PluginInformation pluginInformation) { + public abstract PluginDto map(PluginInformation plugin); + + @AfterMapping + protected void appendCategory(@MappingTarget PluginDto dto) { + if (dto.getCategory() == null) { + dto.setCategory("Miscellaneous"); + } + } + + @ObjectFactory + public PluginDto createDto(PluginInformation pluginInformation) { Links.Builder linksBuilder; if (pluginInformation.getState() != null && pluginInformation.getState().equals(PluginState.AVAILABLE)) { linksBuilder = linkingTo() @@ -38,14 +49,6 @@ public class PluginDtoMapper { .self(pluginInformation.getName())); } - PluginDto pluginDto = new PluginDto(linksBuilder.build()); - pluginDto.setName(pluginInformation.getName()); - pluginDto.setCategory(pluginInformation.getCategory() != null ? pluginInformation.getCategory() : "Miscellaneous"); - pluginDto.setVersion(pluginInformation.getVersion()); - pluginDto.setAuthor(pluginInformation.getAuthor()); - pluginDto.setDescription(pluginInformation.getDescription()); - pluginDto.setAvatarUrl(pluginInformation.getAvatarUrl()); - - return pluginDto; + return new PluginDto(linksBuilder.build()); } } diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java b/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java index 55b5dd9328..b718a43a81 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java @@ -46,7 +46,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.SCMContextProvider; -import sonia.scm.api.v2.resources.PluginCenterDto; import sonia.scm.cache.Cache; import sonia.scm.cache.CacheManager; import sonia.scm.config.ScmConfiguration; @@ -79,7 +78,7 @@ import javax.xml.bind.JAXB; import sonia.scm.net.ahc.AdvancedHttpClient; -import static sonia.scm.api.v2.resources.PluginCenterDtoMapper.*; +import static sonia.scm.plugin.PluginCenterDtoMapper.*; /** * TODO replace aether stuff. @@ -595,14 +594,8 @@ public class DefaultPluginManager implements PluginManager { synchronized (DefaultPluginManager.class) { - String pluginUrl = configuration.getPluginUrl(); - - pluginUrl = buildPluginUrl(pluginUrl); - - if (logger.isInfoEnabled()) - { - logger.info("fetch plugin informations from {}", pluginUrl); - } + String pluginUrl = buildPluginUrl(configuration.getPluginUrl()); + logger.info("fetch plugin information from {}", pluginUrl); if (REMOTE_PLUGINS_ENABLED && Util.isNotEmpty(pluginUrl)) { diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginCenterDto.java b/scm-webapp/src/main/java/sonia/scm/plugin/PluginCenterDto.java similarity index 96% rename from scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginCenterDto.java rename to scm-webapp/src/main/java/sonia/scm/plugin/PluginCenterDto.java index 423a0ba0d2..8bb48c8ceb 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginCenterDto.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/PluginCenterDto.java @@ -1,4 +1,4 @@ -package sonia.scm.api.v2.resources; +package sonia.scm.plugin; import com.google.common.collect.ImmutableList; import lombok.AllArgsConstructor; @@ -45,10 +45,10 @@ public final class PluginCenterDto implements Serializable { public static class Plugin { private String name; + private String version; private String displayName; private String description; private String category; - private String version; private String author; private String avatarUrl; private String sha256; @@ -86,6 +86,5 @@ public final class PluginCenterDto implements Serializable { @Getter static class Link { private String href; - private boolean templated; } } diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/PluginCenterDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/plugin/PluginCenterDtoMapper.java new file mode 100644 index 0000000000..ea445b3ede --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/plugin/PluginCenterDtoMapper.java @@ -0,0 +1,27 @@ +package sonia.scm.plugin; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@Mapper +public interface PluginCenterDtoMapper { + + @Mapping(source = "conditions", target = "condition") + PluginInformation map(PluginCenterDto.Plugin plugin); + + PluginCondition map(PluginCenterDto.Condition condition); + + static Set map(List dtos) { + PluginCenterDtoMapper mapper = Mappers.getMapper(PluginCenterDtoMapper.class); + Set plugins = new HashSet<>(); + for (PluginCenterDto.Plugin plugin : dtos) { + plugins.add(mapper.map(plugin)); + } + return plugins; + } +} diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PluginDtoMapperTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PluginDtoMapperTest.java new file mode 100644 index 0000000000..97b46603d3 --- /dev/null +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PluginDtoMapperTest.java @@ -0,0 +1,88 @@ +package sonia.scm.api.v2.resources; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.junit.jupiter.MockitoExtension; +import sonia.scm.plugin.PluginInformation; +import sonia.scm.plugin.PluginState; + +import java.net.URI; + +import static org.assertj.core.api.Assertions.assertThat; + +@ExtendWith(MockitoExtension.class) +class PluginDtoMapperTest { + + @SuppressWarnings("unused") // Is injected + private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(URI.create("https://hitchhiker.com/")); + + @InjectMocks + private PluginDtoMapperImpl mapper; + + @Test + void shouldMapInformation() { + PluginInformation information = createPluginInformation(); + + PluginDto dto = mapper.map(information); + + assertThat(dto.getName()).isEqualTo("scm-cas-plugin"); + assertThat(dto.getVersion()).isEqualTo("1.0.0"); + assertThat(dto.getDisplayName()).isEqualTo("CAS"); + assertThat(dto.getAuthor()).isEqualTo("Sebastian Sdorra"); + assertThat(dto.getCategory()).isEqualTo("Authentication"); + assertThat(dto.getAvatarUrl()).isEqualTo("https://avatar.scm-manager.org/plugins/cas.png"); + } + + private PluginInformation createPluginInformation() { + PluginInformation information = new PluginInformation(); + information.setName("scm-cas-plugin"); + information.setVersion("1.0.0"); + information.setDisplayName("CAS"); + information.setAuthor("Sebastian Sdorra"); + information.setCategory("Authentication"); + information.setAvatarUrl("https://avatar.scm-manager.org/plugins/cas.png"); + return information; + } + + @Test + void shouldAppendInstalledSelfLink() { + PluginInformation information = createPluginInformation(); + information.setState(PluginState.INSTALLED); + + PluginDto dto = mapper.map(information); + assertThat(dto.getLinks().getLinkBy("self").get().getHref()) + .isEqualTo("https://hitchhiker.com/v2/plugins/installed/scm-cas-plugin"); + } + + @Test + void shouldAppendAvailableSelfLink() { + PluginInformation information = createPluginInformation(); + information.setState(PluginState.AVAILABLE); + + PluginDto dto = mapper.map(information); + assertThat(dto.getLinks().getLinkBy("self").get().getHref()) + .isEqualTo("https://hitchhiker.com/v2/plugins/available/scm-cas-plugin/1.0.0"); + } + + @Test + void shouldAppendInstallLink() { + PluginInformation information = createPluginInformation(); + information.setState(PluginState.AVAILABLE); + + PluginDto dto = mapper.map(information); + assertThat(dto.getLinks().getLinkBy("install").get().getHref()) + .isEqualTo("https://hitchhiker.com/v2/plugins/available/scm-cas-plugin/1.0.0/install"); + } + + @Test + void shouldReturnMiscellaneousIfCategoryIsNull() { + PluginInformation information = createPluginInformation(); + information.setCategory(null); + + PluginDto dto = mapper.map(information); + assertThat(dto.getCategory()).isEqualTo("Miscellaneous"); + } + +} diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PluginCenterDtoMapperTest.java b/scm-webapp/src/test/java/sonia/scm/plugin/PluginCenterDtoMapperTest.java similarity index 79% rename from scm-webapp/src/test/java/sonia/scm/api/v2/resources/PluginCenterDtoMapperTest.java rename to scm-webapp/src/test/java/sonia/scm/plugin/PluginCenterDtoMapperTest.java index 1175526f75..66a90255b3 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PluginCenterDtoMapperTest.java +++ b/scm-webapp/src/test/java/sonia/scm/plugin/PluginCenterDtoMapperTest.java @@ -1,8 +1,6 @@ -package sonia.scm.api.v2.resources; +package sonia.scm.plugin; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import sonia.scm.plugin.PluginInformation; import java.util.ArrayList; import java.util.Arrays; @@ -12,19 +10,11 @@ import java.util.List; import java.util.Set; import static org.assertj.core.api.Assertions.assertThat; -import static sonia.scm.api.v2.resources.PluginCenterDto.Condition; -import static sonia.scm.api.v2.resources.PluginCenterDto.Dependency; -import static sonia.scm.api.v2.resources.PluginCenterDto.Plugin; +import static sonia.scm.plugin.PluginCenterDto.Plugin; +import static sonia.scm.plugin.PluginCenterDto.*; class PluginCenterDtoMapperTest { - private PluginCenterDtoMapper pluginCenterDtoMapper; - - @BeforeEach - void initMapper() { - pluginCenterDtoMapper = new PluginCenterDtoMapper(); - } - @Test void shouldMapSinglePlugin() { Plugin plugin = new Plugin( @@ -82,10 +72,10 @@ class PluginCenterDtoMapperTest { Set resultSet = PluginCenterDtoMapper.map(Arrays.asList(plugin1, plugin2)); - List pluginsList = new ArrayList(resultSet); + List pluginsList = new ArrayList<>(resultSet); - PluginInformation pluginInformation1 = (PluginInformation) pluginsList.get(1); - PluginInformation pluginInformation2 = (PluginInformation) pluginsList.get(0); + PluginInformation pluginInformation1 = pluginsList.get(1); + PluginInformation pluginInformation2 = pluginsList.get(0); assertThat(pluginInformation1.getAuthor()).isEqualTo(plugin1.getAuthor()); assertThat(pluginInformation1.getVersion()).isEqualTo(plugin1.getVersion());