From 76f2722ff40b440cbaed6b9691c16e82d861db37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Tue, 2 Jun 2020 09:33:20 +0200 Subject: [PATCH] Decouple extension point from dto --- .../scm/repository/ChangesetTrailers.java | 2 +- .../java/sonia/scm/repository/Trailer.java | 34 +++++++++ .../ChangesetDescriptionTrailers.java | 55 +++++++------- .../DefaultChangesetToChangesetDtoMapper.java | 12 +++- .../ChangesetDescriptionTrailersTest.java | 71 ++++++++----------- 5 files changed, 102 insertions(+), 72 deletions(-) create mode 100644 scm-core/src/main/java/sonia/scm/repository/Trailer.java diff --git a/scm-core/src/main/java/sonia/scm/repository/ChangesetTrailers.java b/scm-core/src/main/java/sonia/scm/repository/ChangesetTrailers.java index d273e70975..984a3d6e07 100644 --- a/scm-core/src/main/java/sonia/scm/repository/ChangesetTrailers.java +++ b/scm-core/src/main/java/sonia/scm/repository/ChangesetTrailers.java @@ -31,5 +31,5 @@ import java.util.List; @ExtensionPoint public interface ChangesetTrailers { - List getTrailers(Repository repository, Changeset changeset); + List getTrailers(Repository repository, Changeset changeset); } diff --git a/scm-core/src/main/java/sonia/scm/repository/Trailer.java b/scm-core/src/main/java/sonia/scm/repository/Trailer.java new file mode 100644 index 0000000000..9dcac3aa67 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/Trailer.java @@ -0,0 +1,34 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sonia.scm.repository; + +import lombok.Value; + +@Value +public class Trailer { + private String trailerType; + private String mail; + private String name; +} diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetDescriptionTrailers.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetDescriptionTrailers.java index ba5ec1a5a8..0885176f79 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetDescriptionTrailers.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetDescriptionTrailers.java @@ -24,59 +24,64 @@ package sonia.scm.api.v2.resources; -import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import sonia.scm.plugin.Extension; import sonia.scm.repository.Changeset; import sonia.scm.repository.ChangesetTrailers; import sonia.scm.repository.Repository; +import sonia.scm.repository.Trailer; import javax.inject.Inject; import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.Optional; import java.util.Scanner; +import java.util.regex.MatchResult; +import java.util.regex.Matcher; import java.util.regex.Pattern; +import static java.util.Optional.empty; +import static java.util.Optional.of; + @Extension public class ChangesetDescriptionTrailers implements ChangesetTrailers { - private static final List types = ImmutableList.of("Co-authored-by", "Reviewed-by", "Signed-off-by", "Committed-by"); + private static final Collection SUPPORTED_TRAILER_TYPES = ImmutableSet.of("Co-authored-by", "Reviewed-by", "Signed-off-by", "Committed-by"); + private static final Pattern PERSON_PATTERN = Pattern.compile("^\\W*(.*)\\W+<(.*)>\\W*$"); @Inject public ChangesetDescriptionTrailers() {} @Override - public List getTrailers(Repository repository, Changeset changeset) { - List persons = new ArrayList<>(); + public List getTrailers(Repository repository, Changeset changeset) { + List trailers = new ArrayList<>(); try (Scanner scanner = new Scanner(changeset.getDescription())) { - scanner.useDelimiter(Pattern.compile("[\\n]")); - while (scanner.hasNext()) { - String line = scanner.next(); + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); - for (String trailerType : types) { - if (line.contains(trailerType)) { - TrailerPersonDto personDto = createPersonDtoFromUser(line); - personDto.setTrailerType(trailerType); - persons.add(personDto); + String[] typeAndUser = line.split(":\\W"); + if (typeAndUser.length == 2) { + String type = typeAndUser[0]; + String person = typeAndUser[1]; + if (SUPPORTED_TRAILER_TYPES.contains(type)) { + Optional trailer = createTrailer(type, person); + trailer.ifPresent(trailers::add); } } } } - return persons; + return trailers; } - private TrailerPersonDto createPersonDtoFromUser(String line) { - TrailerPersonDto personDto = new TrailerPersonDto(); - - String[] splittedTrailer = line.split("[:<>]"); - - if (splittedTrailer.length > 1) { - personDto.setName(splittedTrailer[1].trim()); - if (splittedTrailer.length > 2) { - personDto.setMail(splittedTrailer[2]); - } + private Optional createTrailer(String type, String person) { + Matcher matcher = PERSON_PATTERN.matcher(person.trim()); + if (matcher.matches()) { + MatchResult matchResult = matcher.toMatchResult(); + return of(new Trailer(type, matchResult.group(2), matchResult.group(1))); + } else { + return empty(); } - - return personDto; } } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/DefaultChangesetToChangesetDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/DefaultChangesetToChangesetDtoMapper.java index 1565e46244..8558dc8a75 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/DefaultChangesetToChangesetDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/DefaultChangesetToChangesetDtoMapper.java @@ -37,6 +37,7 @@ import sonia.scm.repository.Changeset; import sonia.scm.repository.ChangesetTrailers; import sonia.scm.repository.Repository; import sonia.scm.repository.Tag; +import sonia.scm.repository.Trailer; import sonia.scm.repository.api.Command; import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; @@ -76,13 +77,18 @@ public abstract class DefaultChangesetToChangesetDtoMapper extends HalAppenderMa @Inject private Set changesetTrailersSet; - @Mapping(target = "attributes", ignore = true) // We do not map HAL attributes - public abstract ChangesetDto map(Changeset changeset, @Context Repository repository); +// @Mapping(target = "attributes", ignore = true) // We do not map HAL attributes +// public abstract ChangesetDto map(Changeset changeset, @Context Repository repository); + + abstract TrailerPersonDto map(Trailer trailer); @AfterMapping void appendTrailerPersons(Changeset changeset, @MappingTarget ChangesetDto target, @Context Repository repository) { List collectedTrailers = new ArrayList<>(); - changesetTrailersSet.forEach(changesetTrailers -> collectedTrailers.addAll(changesetTrailers.getTrailers(repository, changeset))); + changesetTrailersSet.stream() + .flatMap(changesetTrailers -> changesetTrailers.getTrailers(repository, changeset).stream()) + .map(this::map) + .forEach(collectedTrailers::add); target.setTrailerPersons(collectedTrailers); } diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetDescriptionTrailersTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetDescriptionTrailersTest.java index a9b10be1ac..84cf2d0574 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetDescriptionTrailersTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetDescriptionTrailersTest.java @@ -30,6 +30,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import sonia.scm.repository.Changeset; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryTestData; +import sonia.scm.repository.Trailer; import sonia.scm.user.DisplayUser; import sonia.scm.user.User; @@ -48,73 +49,65 @@ class ChangesetDescriptionTrailersTest { void shouldReturnEmptyList() { Changeset changeset = createChangeset("zaphod beeblebrox"); - List trailerPersons = changesetDescriptionTrailers.getTrailers(REPOSITORY, changeset); + List trailer = changesetDescriptionTrailers.getTrailers(REPOSITORY, changeset); - assertThat(trailerPersons).isNotNull(); - assertThat(trailerPersons).isEmpty(); + assertThat(trailer).isNotNull(); + assertThat(trailer).isEmpty(); } @Test - void shouldReturnTrailerPersonsWithCoAuthors() { + void shouldReturnTrailerWithCoAuthors() { DisplayUser displayUser = createDisplayUser("Arthur Dent", "dent@hitchhiker.org"); Changeset changeset = createChangeset("zaphod beeblebrox\n\nCo-authored-by: Arthur Dent "); - PersonDto personDto = createPersonDto(displayUser); + List Trailer = changesetDescriptionTrailers.getTrailers(REPOSITORY, changeset); - List trailerPersons = changesetDescriptionTrailers.getTrailers(REPOSITORY, changeset); - - TrailerPersonDto trailerPerson = trailerPersons.get(0); - assertThat(trailerPerson.getTrailerType()).isEqualTo("Co-authored-by"); - assertThat(trailerPerson.getName()).isEqualTo(personDto.getName()); - assertThat(trailerPerson.getMail()).isEqualTo(personDto.getMail()); + Trailer first = Trailer.get(0); + assertThat(first.getTrailerType()).isEqualTo("Co-authored-by"); + assertThat(first.getName()).isEqualTo(displayUser.getDisplayName()); + assertThat(first.getMail()).isEqualTo(displayUser.getMail()); } @Test - void shouldReturnTrailerPersonsWithReviewers() { + void shouldReturnTrailerWithReviewers() { DisplayUser displayUser = createDisplayUser("Tricia McMillan", "trillian@hitchhiker.org"); Changeset changeset = createChangeset("zaphod beeblebrox\nReviewed-by: Tricia McMillan "); - PersonDto personDto = createPersonDto(displayUser); + List trailer = changesetDescriptionTrailers.getTrailers(REPOSITORY, changeset); - List trailerPersons = changesetDescriptionTrailers.getTrailers(REPOSITORY, changeset); + Trailer Trailer = trailer.get(0); - TrailerPersonDto trailerPersonDto = trailerPersons.get(0); - - assertThat(trailerPersonDto.getTrailerType()).isEqualTo("Reviewed-by"); - assertThat(trailerPersonDto.getName()).isEqualTo(personDto.getName()); - assertThat(trailerPersonDto.getMail()).isEqualTo(personDto.getMail()); + assertThat(Trailer.getTrailerType()).isEqualTo("Reviewed-by"); + assertThat(Trailer.getName()).isEqualTo(displayUser.getDisplayName()); + assertThat(Trailer.getMail()).isEqualTo(displayUser.getMail()); } @Test - void shouldReturnTrailerPersonsWithSigner() { + void shouldReturnTrailerWithSigner() { DisplayUser displayUser = createDisplayUser("Tricia McMillan", "trillian@hitchhiker.org"); Changeset changeset = createChangeset("zaphod beeblebrox\nSigned-off-by: Tricia McMillan "); - PersonDto personDto = createPersonDto(displayUser); + List trailer = changesetDescriptionTrailers.getTrailers(REPOSITORY, changeset); - List trailerPersons = changesetDescriptionTrailers.getTrailers(REPOSITORY, changeset); + Trailer Trailer = trailer.get(0); - TrailerPersonDto trailerPersonDto = trailerPersons.get(0); - - assertThat(trailerPersonDto.getTrailerType()).isEqualTo("Signed-off-by"); - assertThat(trailerPersonDto.getName()).isEqualTo(personDto.getName()); - assertThat(trailerPersonDto.getMail()).isEqualTo(personDto.getMail()); + assertThat(Trailer.getTrailerType()).isEqualTo("Signed-off-by"); + assertThat(Trailer.getName()).isEqualTo(displayUser.getDisplayName()); + assertThat(Trailer.getMail()).isEqualTo(displayUser.getMail()); } @Test - void shouldReturnTrailerPersonsWithCommitter() { + void shouldReturnTrailerWithCommitter() { DisplayUser displayUser = createDisplayUser("Tricia McMillan", "trillian@hitchhiker.org"); Changeset changeset = createChangeset("zaphod beeblebrox\nCommitted-by: Tricia McMillan "); - PersonDto personDto = createPersonDto(displayUser); + List trailer = changesetDescriptionTrailers.getTrailers(REPOSITORY, changeset); - List trailerPersons = changesetDescriptionTrailers.getTrailers(REPOSITORY, changeset); + Trailer Trailer = trailer.get(0); - TrailerPersonDto trailerPersonDto = trailerPersons.get(0); - - assertThat(trailerPersonDto.getTrailerType()).isEqualTo("Committed-by"); - assertThat(trailerPersonDto.getName()).isEqualTo(personDto.getName()); - assertThat(trailerPersonDto.getMail()).isEqualTo(personDto.getMail()); + assertThat(Trailer.getTrailerType()).isEqualTo("Committed-by"); + assertThat(Trailer.getName()).isEqualTo(displayUser.getDisplayName()); + assertThat(Trailer.getMail()).isEqualTo(displayUser.getMail()); } private Changeset createChangeset(String commitMessage) { @@ -126,12 +119,4 @@ class ChangesetDescriptionTrailersTest { private DisplayUser createDisplayUser(String name, String mail) { return DisplayUser.from(new User(name, name, mail)); } - - private PersonDto createPersonDto(DisplayUser displayUser) { - PersonDto personDto = new PersonDto(); - personDto.setName(displayUser.getDisplayName()); - personDto.setMail(displayUser.getMail()); - return personDto; - } - }