From 8f3c0dce1e62df976189e2c10678a0513554a07f Mon Sep 17 00:00:00 2001 From: Konstantin Schaper Date: Fri, 21 Aug 2020 18:27:48 +0200 Subject: [PATCH 01/23] initial implementation --- scm-ui/ui-components/src/repos/Diff.tsx | 53 ++++++++++++++++++--- scm-ui/ui-components/src/repos/DiffFile.tsx | 16 ++++++- 2 files changed, 62 insertions(+), 7 deletions(-) diff --git a/scm-ui/ui-components/src/repos/Diff.tsx b/scm-ui/ui-components/src/repos/Diff.tsx index 5a0571e95f..f5086f2881 100644 --- a/scm-ui/ui-components/src/repos/Diff.tsx +++ b/scm-ui/ui-components/src/repos/Diff.tsx @@ -22,34 +22,75 @@ * SOFTWARE. */ import React from "react"; -import DiffFile from "./DiffFile"; +import DiffFile, {escapeWhitespace} from "./DiffFile"; import { DiffObjectProps, File, FileControlFactory } from "./DiffTypes"; import Notification from "../Notification"; import { WithTranslation, withTranslation } from "react-i18next"; +import {RouteComponentProps, withRouter} from "react-router-dom"; -type Props = WithTranslation & +type Props = RouteComponentProps & WithTranslation & DiffObjectProps & { diff: File[]; fileControlFactory?: FileControlFactory; }; -class Diff extends React.Component { +type State = { + contentRef?: HTMLElement; +} + +function getAnchorSelector(uriHashContent: string) { + return "#" + escapeWhitespace(decodeURIComponent(uriHashContent)); +} + +class Diff extends React.Component { static defaultProps: Partial = { sideBySide: false }; + constructor(props: Readonly) { + super(props); + this.state = { + contentRef: undefined + }; + } + + componentDidUpdate() { + const { contentRef } = this.state; + + // we have to use componentDidUpdate, because we have to wait until all + // children are rendered and componentDidMount is called before the + // changeset content was rendered. + const hash = this.props.location.hash; + const match = hash && hash.match(/^#diff-(.*)$/); + if (contentRef && match) { + const selector = getAnchorSelector(match[1]); + const element = contentRef.querySelector(selector); + if (element && element.scrollIntoView) { + element.scrollIntoView(); + } + } + } + render() { const { diff, t, ...fileProps } = this.props; + const updateContentRef = (el: HTMLElement | null) => { + if (el !== null && this.state.contentRef === undefined) { + this.setState({ contentRef: el }); + } + }; + return ( - <> +
{diff.length === 0 ? ( {t("diff.noDiffFound")} ) : ( diff.map((file, index) => ) )} - +
); } } -export default withTranslation("repos")(Diff); +export default withRouter(withTranslation("repos")(Diff)); diff --git a/scm-ui/ui-components/src/repos/DiffFile.tsx b/scm-ui/ui-components/src/repos/DiffFile.tsx index 637128fae9..91f87e821b 100644 --- a/scm-ui/ui-components/src/repos/DiffFile.tsx +++ b/scm-ui/ui-components/src/repos/DiffFile.tsx @@ -90,6 +90,10 @@ const ChangeTypeTag = styled(Tag)` margin-left: 0.75rem; `; +export function escapeWhitespace(path: string) { + return path.toLowerCase().replace(/\W/g, "-"); +} + class DiffFile extends React.Component { static defaultProps: Partial = { defaultCollapse: false, @@ -350,6 +354,16 @@ class DiffFile extends React.Component { } }; + getAnchorId(file: File) { + let path: string; + if (file.type === "delete") { + path = file.oldPath; + } else { + path = file.newPath; + } + return escapeWhitespace(path); + } + renderFileTitle = (file: File) => { if (file.oldPath !== file.newPath && (file.type === "copy" || file.type === "rename")) { return ( @@ -454,7 +468,7 @@ class DiffFile extends React.Component { } return ( - + {errorModal}
From 6d409c65c0a9f7a3db524ac550217abf483dc564 Mon Sep 17 00:00:00 2001 From: Konstantin Schaper Date: Tue, 25 Aug 2020 14:45:48 +0200 Subject: [PATCH 02/23] initial implementation --- .../main/java/sonia/scm/repository/Tag.java | 15 ++++ .../java/sonia/scm/repository/GitUtil.java | 40 +++++++++++ .../repository/api/GitHookTagProvider.java | 61 +++++++++------- .../spi/GitHookContextProvider.java | 2 +- .../scm/repository/spi/GitTagsCommand.java | 65 +++++++---------- .../repository/client/spi/GitTagCommand.java | 6 +- .../repository/spi/GitTagsCommandTest.java | 67 ++++++++++++++++++ .../repository/spi/scm-git-spi-test-tags.zip | Bin 0 -> 44688 bytes .../scm/repository/spi/HgTagsCommand.java | 43 ++++------- .../scm/repository/spi/HgTagsCommandTest.java | 45 ++++++++++++ .../DefaultChangesetToChangesetDtoMapper.java | 19 ++++- .../sonia/scm/api/v2/resources/TagDto.java | 6 +- .../api/v2/resources/TagToTagDtoMapper.java | 9 +++ .../v2/resources/TagToTagDtoMapperTest.java | 8 +++ 14 files changed, 284 insertions(+), 102 deletions(-) create mode 100644 scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitTagsCommandTest.java create mode 100644 scm-plugins/scm-git-plugin/src/test/resources/sonia/scm/repository/spi/scm-git-spi-test-tags.zip create mode 100644 scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgTagsCommandTest.java diff --git a/scm-core/src/main/java/sonia/scm/repository/Tag.java b/scm-core/src/main/java/sonia/scm/repository/Tag.java index 3c40c2f38a..bdeec544a4 100644 --- a/scm-core/src/main/java/sonia/scm/repository/Tag.java +++ b/scm-core/src/main/java/sonia/scm/repository/Tag.java @@ -41,6 +41,7 @@ public final class Tag { private final String name; private final String revision; + private final Long date; /** * Constructs a new tag. @@ -49,7 +50,21 @@ public final class Tag { * @param revision tagged revision */ public Tag(String name, String revision) { + this(name, revision, null); + } + + /** + * Constructs a new tag. + * + * @param name name of the tag + * @param revision tagged revision + * @param date the creation timestamp (milliseconds) of the tag + * + * @since 2.5.0 + */ + public Tag(String name, String revision, Long date) { this.name = name; this.revision = revision; + this.date = date; } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java index b55aec06bd..96e4266a5d 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java @@ -42,6 +42,8 @@ import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevObject; +import org.eclipse.jgit.revwalk.RevTag; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.revwalk.filter.RevFilter; import org.eclipse.jgit.storage.file.FileRepositoryBuilder; @@ -387,6 +389,44 @@ public final class GitUtil return ref; } + /** + * Method description + * + * + * @param repository + * @param revWalk + * @param ref + * + * @return + * + * @throws IOException + * + * @since 2.5.0 + */ + public static Long getTagTime(org.eclipse.jgit.lib.Repository repository, + RevWalk revWalk, Ref ref) + throws IOException + { + ObjectId id = ref.getObjectId(); + + if (id != null) + { + if (revWalk == null) + { + revWalk = new RevWalk(repository); + } + + final RevObject revObject = revWalk.parseAny(id); + if (revObject instanceof RevTag) { + return ((RevTag) revObject).getTaggerIdent().getWhen().getTime(); + } else if (revObject instanceof RevCommit) { + return getCommitTime((RevCommit) revObject); + } + } + + return null; + } + /** * Method description * diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/api/GitHookTagProvider.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/api/GitHookTagProvider.java index 2a290c6ca9..5bc5069112 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/api/GitHookTagProvider.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/api/GitHookTagProvider.java @@ -21,12 +21,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.repository.api; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; + +import java.io.IOException; import java.util.List; + +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.transport.ReceiveCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,52 +40,60 @@ import sonia.scm.repository.Tag; /** * Git provider implementation of {@link HookTagProvider}. - * - * @since 1.50 + * * @author Sebastian Sdorra + * @since 1.50 */ public class GitHookTagProvider implements HookTagProvider { - private static final Logger logger = LoggerFactory.getLogger(GitHookTagProvider.class); - + private static final Logger LOG = LoggerFactory.getLogger(GitHookTagProvider.class); + private final List createdTags; private final List deletedTags; /** * Constructs new instance. - * + * * @param commands received commands */ - public GitHookTagProvider(List commands) { + public GitHookTagProvider(List commands, Repository repository) { ImmutableList.Builder createdTagBuilder = ImmutableList.builder(); ImmutableList.Builder deletedTagBuilder = ImmutableList.builder(); - - for ( ReceiveCommand rc : commands ){ + + for (ReceiveCommand rc : commands) { String refName = rc.getRefName(); String tag = GitUtil.getTagName(refName); - - if (Strings.isNullOrEmpty(tag)){ - logger.debug("received ref name {} is not a tag", refName); - } else if (isCreate(rc)) { - createdTagBuilder.add(createTagFromNewId(rc, tag)); - } else if (isDelete(rc)){ - deletedTagBuilder.add(createTagFromOldId(rc, tag)); - } else if (isUpdate(rc)) { - createdTagBuilder.add(createTagFromNewId(rc, tag)); - deletedTagBuilder.add(createTagFromOldId(rc, tag)); + + if (Strings.isNullOrEmpty(tag)) { + LOG.debug("received ref name {} is not a tag", refName); + } else { + Long tagTime = null; + try (RevWalk walk = new RevWalk(repository)) { + tagTime = GitUtil.getTagTime(repository, walk, rc.getRef()); + } catch (IOException e) { + LOG.error("Could not read tag time", e); + } + if (isCreate(rc)) { + createdTagBuilder.add(createTagFromNewId(rc, tag, tagTime)); + } else if (isDelete(rc)) { + deletedTagBuilder.add(createTagFromOldId(rc, tag, tagTime)); + } else if (isUpdate(rc)) { + createdTagBuilder.add(createTagFromNewId(rc, tag, tagTime)); + deletedTagBuilder.add(createTagFromOldId(rc, tag, tagTime)); + } } } - + createdTags = createdTagBuilder.build(); deletedTags = deletedTagBuilder.build(); } - private Tag createTagFromNewId(ReceiveCommand rc, String tag) { - return new Tag(tag, GitUtil.getId(rc.getNewId())); + private Tag createTagFromNewId(ReceiveCommand rc, String tag, Long tagTime) { + return new Tag(tag, GitUtil.getId(rc.getNewId()), tagTime); } - private Tag createTagFromOldId(ReceiveCommand rc, String tag) { - return new Tag(tag, GitUtil.getId(rc.getOldId())); + private Tag createTagFromOldId(ReceiveCommand rc, String tag, Long tagTime) { + return new Tag(tag, GitUtil.getId(rc.getOldId()), tagTime); } private boolean isUpdate(ReceiveCommand rc) { diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitHookContextProvider.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitHookContextProvider.java index 13a11007a2..ce61b85a57 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitHookContextProvider.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitHookContextProvider.java @@ -103,7 +103,7 @@ public class GitHookContextProvider extends HookContextProvider @Override public HookTagProvider getTagProvider() { - return new GitHookTagProvider(receiveCommands); + return new GitHookTagProvider(receiveCommands, repository); } @Override diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitTagsCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitTagsCommand.java index 208c931f63..97b9c91be1 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitTagsCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitTagsCommand.java @@ -31,7 +31,7 @@ import com.google.common.collect.Lists; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.lib.Ref; -import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevObject; import org.eclipse.jgit.revwalk.RevWalk; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,34 +45,28 @@ import java.util.List; //~--- JDK imports ------------------------------------------------------------ /** - * * @author Sebastian Sdorra */ -public class GitTagsCommand extends AbstractGitCommand implements TagsCommand -{ +public class GitTagsCommand extends AbstractGitCommand implements TagsCommand { /** * Constructs ... * - * @param context - * + * @param context */ - public GitTagsCommand(GitContext context) - { + public GitTagsCommand(GitContext context) { super(context); } //~--- get methods ---------------------------------------------------------- @Override - public List getTags() throws IOException - { + public List getTags() throws IOException { List tags = null; RevWalk revWalk = null; - try - { + try { final Git git = new Git(open()); revWalk = new RevWalk(git.getRepository()); @@ -81,13 +75,9 @@ public class GitTagsCommand extends AbstractGitCommand implements TagsCommand tags = Lists.transform(tagList, new TransformFuntion(git.getRepository(), revWalk)); - } - catch (GitAPIException ex) - { + } catch (GitAPIException ex) { throw new InternalRepositoryException(repository, "could not read tags from repository", ex); - } - finally - { + } finally { GitUtil.release(revWalk); } @@ -99,12 +89,10 @@ public class GitTagsCommand extends AbstractGitCommand implements TagsCommand /** * Class description * - * - * @version Enter version here..., 12/07/06 - * @author Enter your name here... + * @author Enter your name here... + * @version Enter version here..., 12/07/06 */ - private static class TransformFuntion implements Function - { + private static class TransformFuntion implements Function { /** * the logger for TransformFuntion @@ -117,13 +105,11 @@ public class GitTagsCommand extends AbstractGitCommand implements TagsCommand /** * Constructs ... * - * * @param repository * @param revWalk */ public TransformFuntion(org.eclipse.jgit.lib.Repository repository, - RevWalk revWalk) - { + RevWalk revWalk) { this.repository = repository; this.revWalk = revWalk; } @@ -133,30 +119,23 @@ public class GitTagsCommand extends AbstractGitCommand implements TagsCommand /** * Method description * - * * @param ref - * * @return */ @Override - public Tag apply(Ref ref) - { + public Tag apply(Ref ref) { Tag tag = null; - try - { - RevCommit commit = GitUtil.getCommit(repository, revWalk, ref); + try { + RevObject revObject = revWalk.parseAny(ref.getObjectId()); - if (commit != null) - { + if (revObject != null) { String name = GitUtil.getTagName(ref); - tag = new Tag(name, commit.getId().name()); + tag = new Tag(name, revObject.getId().name(), GitUtil.getTagTime(repository, revWalk, ref)); } - } - catch (IOException ex) - { + } catch (IOException ex) { logger.error("could not get commit for tag", ex); } @@ -165,10 +144,14 @@ public class GitTagsCommand extends AbstractGitCommand implements TagsCommand //~--- fields ------------------------------------------------------------- - /** Field description */ + /** + * Field description + */ private org.eclipse.jgit.lib.Repository repository; - /** Field description */ + /** + * Field description + */ private RevWalk revWalk; } } diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/client/spi/GitTagCommand.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/client/spi/GitTagCommand.java index db44ee5a90..19b93d0775 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/client/spi/GitTagCommand.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/client/spi/GitTagCommand.java @@ -78,6 +78,7 @@ public class GitTagCommand implements TagCommand String revision = request.getRevision(); RevObject revObject = null; + Long tagTime = null; if (!Strings.isNullOrEmpty(revision)) { @@ -88,6 +89,7 @@ public class GitTagCommand implements TagCommand { walk = new RevWalk(git.getRepository()); revObject = walk.parseAny(id); + tagTime = GitUtil.getTagTime(git.getRepository(), walk, GitUtil.getRefForCommit(git.getRepository(), id)); } finally { @@ -110,9 +112,9 @@ public class GitTagCommand implements TagCommand } if (ref.isPeeled()) { - tag = new Tag(request.getName(), ref.getPeeledObjectId().toString()); + tag = new Tag(request.getName(), ref.getPeeledObjectId().toString(), tagTime); } else { - tag = new Tag(request.getName(), ref.getObjectId().toString()); + tag = new Tag(request.getName(), ref.getObjectId().toString(), tagTime); } } diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitTagsCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitTagsCommandTest.java new file mode 100644 index 0000000000..afa3cc4930 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitTagsCommandTest.java @@ -0,0 +1,67 @@ +/* + * 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.spi; + +import com.github.sdorra.shiro.ShiroRule; +import com.github.sdorra.shiro.SubjectAware; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import sonia.scm.repository.Tag; + +import java.io.IOException; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@SubjectAware(configuration = "classpath:sonia/scm/configuration/shiro.ini", username = "admin", password = "secret") +public class GitTagsCommandTest extends AbstractGitCommandTestBase { + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Rule + public BindTransportProtocolRule transportProtocolRule = new BindTransportProtocolRule(); + + @Rule + public ShiroRule shiro = new ShiroRule(); + + @Test + public void shouldGetDatesCorrectly() throws IOException { + final GitContext gitContext = createContext(); + final GitTagsCommand tagsCommand = new GitTagsCommand(gitContext); + final List tags = tagsCommand.getTags(); + assertThat(tags).hasSize(2); + assertThat(tags.get(0).getName()).isEqualTo("1.0.0"); + assertThat(tags.get(0).getDate()).isEqualTo(1598348105000L); // Annotated - Take tag date + assertThat(tags.get(1).getName()).isEqualTo("test-tag"); + assertThat(tags.get(1).getDate()).isEqualTo(1339416344000L); // Lightweight - Take commit date + } + + @Override + protected String getZippedRepositoryResource() { + return "sonia/scm/repository/spi/scm-git-spi-test-tags.zip"; + } +} diff --git a/scm-plugins/scm-git-plugin/src/test/resources/sonia/scm/repository/spi/scm-git-spi-test-tags.zip b/scm-plugins/scm-git-plugin/src/test/resources/sonia/scm/repository/spi/scm-git-spi-test-tags.zip new file mode 100644 index 0000000000000000000000000000000000000000..05b2f0f7cab59ed00cab488ed71e36611e5f6983 GIT binary patch literal 44688 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 Xyu6rL`jhSIzuVO5qDRyp`F#HeSg)q) literal 0 HcmV?d00001 diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgTagsCommand.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgTagsCommand.java index 309265617c..b0fb323bab 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgTagsCommand.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgTagsCommand.java @@ -29,29 +29,22 @@ package sonia.scm.repository.spi; import com.google.common.base.Function; import com.google.common.base.Strings; import com.google.common.collect.Lists; - import sonia.scm.repository.Tag; import sonia.scm.util.Util; -//~--- JDK imports ------------------------------------------------------------ - import java.util.List; /** - * * @author Sebastian Sdorra */ -public class HgTagsCommand extends AbstractCommand implements TagsCommand -{ +public class HgTagsCommand extends AbstractCommand implements TagsCommand { /** * Constructs ... * - * @param context - * + * @param context */ - public HgTagsCommand(HgCommandContext context) - { + public HgTagsCommand(HgCommandContext context) { super(context); } @@ -60,12 +53,10 @@ public class HgTagsCommand extends AbstractCommand implements TagsCommand /** * Method description * - * * @return */ @Override - public List getTags() - { + public List getTags() { com.aragost.javahg.commands.TagsCommand cmd = com.aragost.javahg.commands.TagsCommand.on(open()); @@ -74,13 +65,11 @@ public class HgTagsCommand extends AbstractCommand implements TagsCommand List tags = null; // check for empty repository - if (Util.isNotEmpty(tagList) && tagList.get(0).getChangeset() != null) - { + if (Util.isNotEmpty(tagList) && tagList.get(0).getChangeset() != null) { tags = Lists.transform(tagList, new TagTransformer()); } - if (tags == null) - { + if (tags == null) { tags = Lists.newArrayList(); } @@ -92,31 +81,25 @@ public class HgTagsCommand extends AbstractCommand implements TagsCommand /** * Class description * - * - * @version Enter version here..., 12/08/03 - * @author Enter your name here... + * @author Enter your name here... + * @version Enter version here..., 12/08/03 */ private static class TagTransformer - implements Function - { + implements Function { /** * Method description * - * * @param f - * * @return */ @Override - public Tag apply(com.aragost.javahg.Tag f) - { + public Tag apply(com.aragost.javahg.Tag f) { Tag t = null; - if ((f != null) &&!Strings.isNullOrEmpty(f.getName()) - && (f.getChangeset() != null)) - { - t = new Tag(f.getName(), f.getChangeset().getNode()); + if ((f != null) && !Strings.isNullOrEmpty(f.getName()) + && (f.getChangeset() != null)) { + t = new Tag(f.getName(), f.getChangeset().getNode(), f.getChangeset().getTimestamp().getDate().getTime()); } return t; diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgTagsCommandTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgTagsCommandTest.java new file mode 100644 index 0000000000..f9d3fdd5b2 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgTagsCommandTest.java @@ -0,0 +1,45 @@ +/* + * 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.spi; + +import org.junit.Test; +import sonia.scm.repository.Tag; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class HgTagsCommandTest extends AbstractHgCommandTestBase { + + @Test + public void shouldGetTagDatesCorrectly() { + HgTagsCommand hgTagsCommand = new HgTagsCommand(cmdContext); + final List tags = hgTagsCommand.getTags(); + assertThat(tags).hasSize(1); + assertThat(tags.get(0).getName()).isEqualTo("tip"); + assertThat(tags.get(0).getDate()).isEqualTo(1339586381000L); + } + +} 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 384331c6ad..c05547b295 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 @@ -29,13 +29,15 @@ import de.otto.edison.hal.Links; import org.mapstruct.Context; import org.mapstruct.Mapper; import org.mapstruct.ObjectFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import sonia.scm.repository.Branch; import sonia.scm.repository.Changeset; import sonia.scm.repository.Contributor; import sonia.scm.repository.Person; import sonia.scm.repository.Repository; import sonia.scm.repository.Signature; -import sonia.scm.repository.Tag; +import sonia.scm.repository.Tags; import sonia.scm.repository.api.Command; import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; @@ -45,6 +47,7 @@ import sonia.scm.security.gpg.RawGpgKey; import sonia.scm.web.EdisonHalAppender; import javax.inject.Inject; +import java.io.IOException; import java.util.List; import java.util.Optional; import java.util.function.Function; @@ -57,6 +60,8 @@ import static de.otto.edison.hal.Links.linkingTo; @Mapper public abstract class DefaultChangesetToChangesetDtoMapper extends HalAppenderMapper implements InstantAttributeMapper, ChangesetToChangesetDtoMapper { + private static Logger LOG = LoggerFactory.getLogger(DefaultChangesetToChangesetDtoMapper.class); + @Inject private RepositoryServiceFactory serviceFactory; @@ -115,8 +120,16 @@ public abstract class DefaultChangesetToChangesetDtoMapper extends HalAppenderMa try (RepositoryService repositoryService = serviceFactory.create(repository)) { if (repositoryService.isSupported(Command.TAGS)) { - embeddedBuilder.with("tags", tagCollectionToDtoMapper.getTagDtoList(namespace, name, - getListOfObjects(source.getTags(), tagName -> new Tag(tagName, source.getId())))); + Tags tags = null; + try { + tags = repositoryService.getTagsCommand().getTags(); + } catch (IOException e) { + LOG.error("Error while retrieving tags from repository", e); + } + if (tags != null) { + embeddedBuilder.with("tags", tagCollectionToDtoMapper.getTagDtoList(namespace, name, + getListOfObjects(source.getTags(), tags::getTagByName))); + } } if (repositoryService.isSupported(Command.BRANCHES)) { embeddedBuilder.with("branches", branchCollectionToDtoMapper.getBranchDtoList(namespace, name, diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagDto.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagDto.java index f96417a6bd..b7c6b3bacf 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagDto.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagDto.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.api.v2.resources; import de.otto.edison.hal.Embedded; @@ -31,6 +31,8 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import java.time.Instant; + @Getter @Setter @NoArgsConstructor @@ -40,6 +42,8 @@ public class TagDto extends HalRepresentation { private String revision; + private Instant date; + TagDto(Links links, Embedded embedded) { super(links, embedded); } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagToTagDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagToTagDtoMapper.java index e056162dcc..532eb9be85 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagToTagDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagToTagDtoMapper.java @@ -29,6 +29,7 @@ import de.otto.edison.hal.Links; import org.mapstruct.Context; import org.mapstruct.Mapper; import org.mapstruct.Mapping; +import org.mapstruct.Named; import org.mapstruct.ObjectFactory; import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.Tag; @@ -36,6 +37,8 @@ import sonia.scm.web.EdisonHalAppender; import javax.inject.Inject; +import java.time.Instant; + import static de.otto.edison.hal.Embedded.embeddedBuilder; import static de.otto.edison.hal.Link.link; import static de.otto.edison.hal.Links.linkingTo; @@ -46,6 +49,7 @@ public abstract class TagToTagDtoMapper extends HalAppenderMapper { @Inject private ResourceLinks resourceLinks; + @Mapping(target = "date", source = "date", qualifiedByName = "mapDate") @Mapping(target = "attributes", ignore = true) // We do not map HAL attributes public abstract TagDto map(Tag tag, @Context NamespaceAndName namespaceAndName); @@ -61,4 +65,9 @@ public abstract class TagToTagDtoMapper extends HalAppenderMapper { return new TagDto(linksBuilder.build(), embeddedBuilder.build()); } + + @Named("mapDate") + Instant map(Long value) { + return value == null ? null : Instant.ofEpochMilli(value); + } } diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagToTagDtoMapperTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagToTagDtoMapperTest.java index f53a10797b..ebf71f6b85 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagToTagDtoMapperTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagToTagDtoMapperTest.java @@ -32,6 +32,7 @@ import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.Tag; import java.net.URI; +import java.time.Instant; import static org.assertj.core.api.Assertions.assertThat; @@ -58,4 +59,11 @@ class TagToTagDtoMapperTest { assertThat(dto.getLinks().getLinkBy("yo").get().getHref()).isEqualTo("http://hitchhiker/hog/1.0.0"); } + @Test + void shouldMapDate() { + final long now = Instant.now().getEpochSecond() * 1000; + TagDto dto = mapper.map(new Tag("1.0.0", "42", now), new NamespaceAndName("hitchhiker", "hog")); + assertThat(dto.getDate()).isEqualTo(Instant.ofEpochMilli(now)); + } + } From 36231d077ac3feeb80a0c0f7553e1c8faa095a5b Mon Sep 17 00:00:00 2001 From: Konstantin Schaper Date: Tue, 25 Aug 2020 18:08:31 +0200 Subject: [PATCH 03/23] cleanup and update tests --- .../main/java/sonia/scm/repository/Tag.java | 11 ++++ .../java/sonia/scm/repository/GitUtil.java | 32 +++++++--- .../repository/api/GitHookTagProvider.java | 4 +- .../api/GitHookTagProviderTest.java | 64 ++++++++++++++----- .../scm/repository/api/HgHookTagProvider.java | 2 +- .../repository/api/HgHookTagProviderTest.java | 8 ++- .../sonia/scm/api/v2/resources/TagDto.java | 2 + 7 files changed, 91 insertions(+), 32 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/Tag.java b/scm-core/src/main/java/sonia/scm/repository/Tag.java index bdeec544a4..1c037e4764 100644 --- a/scm-core/src/main/java/sonia/scm/repository/Tag.java +++ b/scm-core/src/main/java/sonia/scm/repository/Tag.java @@ -67,4 +67,15 @@ public final class Tag { this.revision = revision; this.date = date; } + + /** + * The date is retrieved in a best-effort fashion. + * In certain situations it might not be available. + * In these cases, this method returns null. + * + * @since 2.5.0 + */ + public Long getDate() { + return date; + } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java index 96e4266a5d..97fc29163a 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java @@ -392,27 +392,39 @@ public final class GitUtil /** * Method description * + * @param repository + * @param ref + * @return + * @throws IOException + * @since 2.5.0 + */ + public static Long getTagTime(org.eclipse.jgit.lib.Repository repository, Ref ref) throws IOException { + try (RevWalk walk = new RevWalk(repository)) { + return GitUtil.getTagTime(repository, walk, ref); + } + } + + /** + * Method description * * @param repository * @param revWalk * @param ref - * * @return - * * @throws IOException - * * @since 2.5.0 */ public static Long getTagTime(org.eclipse.jgit.lib.Repository repository, - RevWalk revWalk, Ref ref) - throws IOException - { + RevWalk revWalk, Ref ref) + throws IOException { + if (ref == null) { + return null; + } + ObjectId id = ref.getObjectId(); - if (id != null) - { - if (revWalk == null) - { + if (id != null) { + if (revWalk == null) { revWalk = new RevWalk(repository); } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/api/GitHookTagProvider.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/api/GitHookTagProvider.java index 5bc5069112..c1a333400b 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/api/GitHookTagProvider.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/api/GitHookTagProvider.java @@ -68,8 +68,8 @@ public class GitHookTagProvider implements HookTagProvider { LOG.debug("received ref name {} is not a tag", refName); } else { Long tagTime = null; - try (RevWalk walk = new RevWalk(repository)) { - tagTime = GitUtil.getTagTime(repository, walk, rc.getRef()); + try { + tagTime = GitUtil.getTagTime(repository, rc.getRef()); } catch (IOException e) { LOG.error("Could not read tag time", e); } diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/api/GitHookTagProviderTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/api/GitHookTagProviderTest.java index d27f881a13..f40d71378c 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/api/GitHookTagProviderTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/api/GitHookTagProviderTest.java @@ -26,6 +26,11 @@ package sonia.scm.repository.api; import com.google.common.collect.Lists; import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectLoader; +import org.eclipse.jgit.lib.ObjectReader; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevTag; import org.eclipse.jgit.transport.ReceiveCommand; import org.junit.Before; import org.junit.Rule; @@ -33,13 +38,19 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; +import sonia.scm.repository.GitUtil; import sonia.scm.repository.Tag; import java.util.List; import static org.hamcrest.Matchers.empty; import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; /** @@ -48,16 +59,22 @@ import static org.mockito.Mockito.when; * @author Sebastian Sdorra */ @RunWith(MockitoJUnitRunner.class) -public class GitHookTagProviderTest { +public class GitHookTagProviderTest{ private static final String ZERO = ObjectId.zeroId().getName(); - @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); - @Mock private ReceiveCommand command; - + + @Mock + private Repository repository; + + @Mock + private Ref gitRef; + + @Mock + private ObjectId objectId; + private List commands; /** @@ -73,11 +90,21 @@ public class GitHookTagProviderTest { */ @Test public void testGetCreatedTags() { - String revision = "b2002b64013e54b78eac251df0672bd5d6a83aa7"; - GitHookTagProvider provider = createProvider(ReceiveCommand.Type.CREATE, "refs/tags/1.0.0", revision, ZERO); - - assertTag("1.0.0", revision, provider.getCreatedTags()); - assertThat(provider.getDeletedTags(), empty()); + try (MockedStatic dummy = Mockito.mockStatic(GitUtil.class)) { + String revision = "86a6645eceefe8b9a247db5eb16e3d89a7e6e6d1"; + Long timestamp = 1339416344000L; + String tagName = "test-tag"; + String ref = "refs/tags/" + tagName; + + dummy.when(() -> GitUtil.getTagTime(repository, gitRef)).thenReturn(timestamp); + dummy.when(() -> GitUtil.getTagName(ref)).thenReturn(tagName); + dummy.when(() -> GitUtil.getId(ObjectId.fromString(revision))).thenReturn(revision); + + GitHookTagProvider provider = createProvider(ReceiveCommand.Type.CREATE, ref, revision, ZERO); + + assertTag(tagName, revision, timestamp, provider.getCreatedTags()); + assertThat(provider.getDeletedTags(), empty()); + } } /** @@ -89,14 +116,14 @@ public class GitHookTagProviderTest { GitHookTagProvider provider = createProvider(ReceiveCommand.Type.DELETE, "refs/tags/1.0.0", ZERO, revision); assertThat(provider.getCreatedTags(), empty()); - assertTag("1.0.0", revision, provider.getDeletedTags()); + assertTag("1.0.0", revision, null, provider.getDeletedTags()); } /** * Tests {@link GitHookTagProvider} with a branch ref instead of a tag. */ @Test - public void testWithBranch(){ + public void testWithBranch() { String revision = "b2002b64013e54b78eac251df0672bd5d6a83aa7"; GitHookTagProvider provider = createProvider(ReceiveCommand.Type.CREATE, "refs/heads/1.0.0", revision, revision); @@ -113,25 +140,28 @@ public class GitHookTagProviderTest { String oldId = "e0f2be968b147ff7043684a7715d2fe852553db4"; GitHookTagProvider provider = createProvider(ReceiveCommand.Type.UPDATE, "refs/tags/1.0.0", newId, oldId); - assertTag("1.0.0", newId, provider.getCreatedTags()); - assertTag("1.0.0", oldId, provider.getDeletedTags()); + assertTag("1.0.0", newId, null, provider.getCreatedTags()); + assertTag("1.0.0", oldId, null, provider.getDeletedTags()); } - private void assertTag(String name, String revision, List tags){ + private void assertTag(String name, String revision, Long date, List tags){ assertNotNull(tags); assertFalse(tags.isEmpty()); assertEquals(1, tags.size()); Tag tag = tags.get(0); assertEquals(name, tag.getName()); assertEquals(revision, tag.getRevision()); + assertEquals(date, tag.getDate()); } - private GitHookTagProvider createProvider(ReceiveCommand.Type type, String ref, String newId, String oldId){ + private GitHookTagProvider createProvider(ReceiveCommand.Type type, String ref, String newId, String oldId) { when(command.getNewId()).thenReturn(ObjectId.fromString(newId)); when(command.getOldId()).thenReturn(ObjectId.fromString(oldId)); when(command.getType()).thenReturn(type); when(command.getRefName()).thenReturn(ref); - return new GitHookTagProvider(commands); + when(command.getRef()).thenReturn(gitRef); + when(gitRef.getObjectId()).thenReturn(objectId); + return new GitHookTagProvider(commands, repository); } } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/api/HgHookTagProvider.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/api/HgHookTagProvider.java index ed140ee4b6..7b8ecef67d 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/api/HgHookTagProvider.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/api/HgHookTagProvider.java @@ -92,7 +92,7 @@ public class HgHookTagProvider implements HookTagProvider { if (tagNames != null){ for ( String tagName : tagNames ){ logger.trace("found tag {} at changeset {}", tagName, c.getId()); - tags.add(new Tag(tagName, c.getId())); + tags.add(new Tag(tagName, c.getId(), c.getDate())); } } } diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/api/HgHookTagProviderTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/api/HgHookTagProviderTest.java index a2486732a0..f557fec51e 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/api/HgHookTagProviderTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/api/HgHookTagProviderTest.java @@ -26,6 +26,8 @@ package sonia.scm.repository.api; import com.google.common.collect.Lists; import java.util.List; + +import org.assertj.core.api.Assertions; import org.junit.Test; import static org.junit.Assert.*; import static org.mockito.Mockito.*; @@ -71,7 +73,7 @@ public class HgHookTagProviderTest { public void testGetCreatedTags(){ Changeset c1 = new Changeset("1", Long.MIN_VALUE, null); c1.getTags().add("1.0.0"); - Changeset c2 = new Changeset("2", Long.MIN_VALUE, null); + Changeset c2 = new Changeset("2", Long.MAX_VALUE, null); c2.getTags().add("2.0.0"); Changeset c3 = new Changeset("3", Long.MIN_VALUE, null); prepareChangesets(c1, c2, c3); @@ -83,10 +85,12 @@ public class HgHookTagProviderTest { Tag t1 = tags.get(0); assertEquals("1", t1.getRevision()); assertEquals("1.0.0", t1.getName()); - + Assertions.assertThat(t1.getDate()).isEqualTo(Long.MIN_VALUE); + Tag t2 = tags.get(1); assertEquals("2", t2.getRevision()); assertEquals("2.0.0", t2.getName()); + Assertions.assertThat(t2.getDate()).isEqualTo(Long.MAX_VALUE); } private void prepareChangesets(Changeset... changesets){ diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagDto.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagDto.java index b7c6b3bacf..7d4fd6dada 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagDto.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagDto.java @@ -24,6 +24,7 @@ package sonia.scm.api.v2.resources; +import com.fasterxml.jackson.annotation.JsonInclude; import de.otto.edison.hal.Embedded; import de.otto.edison.hal.HalRepresentation; import de.otto.edison.hal.Links; @@ -42,6 +43,7 @@ public class TagDto extends HalRepresentation { private String revision; + @JsonInclude(JsonInclude.Include.NON_NULL) private Instant date; TagDto(Links links, Embedded embedded) { From 8d613effeea14f2f6e9ee74189f48cebf3de912e Mon Sep 17 00:00:00 2001 From: Konstantin Schaper Date: Tue, 25 Aug 2020 18:10:03 +0200 Subject: [PATCH 04/23] update mockito dependency version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 189584d1fd..3110c769fc 100644 --- a/pom.xml +++ b/pom.xml @@ -903,7 +903,7 @@ - 2.28.2 + 3.5.6 2.1 5.6.2 From ecfc70eb77192cfc6c4ca28de97e30ea5be5d5a6 Mon Sep 17 00:00:00 2001 From: Konstantin Schaper Date: Wed, 26 Aug 2020 10:01:51 +0200 Subject: [PATCH 05/23] wip refactoring --- .../main/java/sonia/scm/repository/Tag.java | 6 +- .../api/GitHookTagProviderTest.java | 81 ++++++++++++------- .../repository/spi/GitTagsCommandTest.java | 4 +- .../repository/api/HgHookTagProviderTest.java | 4 +- .../scm/repository/spi/HgTagsCommandTest.java | 2 +- .../api/v2/resources/TagToTagDtoMapper.java | 5 +- 6 files changed, 62 insertions(+), 40 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/Tag.java b/scm-core/src/main/java/sonia/scm/repository/Tag.java index 1c037e4764..0262888e55 100644 --- a/scm-core/src/main/java/sonia/scm/repository/Tag.java +++ b/scm-core/src/main/java/sonia/scm/repository/Tag.java @@ -28,6 +28,8 @@ import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.ToString; +import java.util.Optional; + /** * Represents a tag in a repository. * @@ -75,7 +77,7 @@ public final class Tag { * * @since 2.5.0 */ - public Long getDate() { - return date; + public Optional getDate() { + return Optional.ofNullable(date); } } diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/api/GitHookTagProviderTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/api/GitHookTagProviderTest.java index f40d71378c..e0a83e1272 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/api/GitHookTagProviderTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/api/GitHookTagProviderTest.java @@ -21,21 +21,16 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.repository.api; import com.google.common.collect.Lists; import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.ObjectLoader; -import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.revwalk.RevTag; import org.eclipse.jgit.transport.ReceiveCommand; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockedStatic; @@ -47,19 +42,19 @@ import sonia.scm.repository.Tag; import java.util.List; import static org.hamcrest.Matchers.empty; -import static org.junit.Assert.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; import static org.mockito.Mockito.when; /** * Unit tests for {@link GitHookTagProvider}. - * + * * @author Sebastian Sdorra */ @RunWith(MockitoJUnitRunner.class) -public class GitHookTagProviderTest{ +public class GitHookTagProviderTest { private static final String ZERO = ObjectId.zeroId().getName(); @@ -76,12 +71,12 @@ public class GitHookTagProviderTest{ private ObjectId objectId; private List commands; - + /** * Set up mocks for upcoming tests. */ @Before - public void setUpMocks(){ + public void setUpMocks() { commands = Lists.newArrayList(command); } @@ -93,7 +88,7 @@ public class GitHookTagProviderTest{ try (MockedStatic dummy = Mockito.mockStatic(GitUtil.class)) { String revision = "86a6645eceefe8b9a247db5eb16e3d89a7e6e6d1"; Long timestamp = 1339416344000L; - String tagName = "test-tag"; + String tagName = "1.0.0"; String ref = "refs/tags/" + tagName; dummy.when(() -> GitUtil.getTagTime(repository, gitRef)).thenReturn(timestamp); @@ -106,19 +101,29 @@ public class GitHookTagProviderTest{ assertThat(provider.getDeletedTags(), empty()); } } - + /** * Tests {@link GitHookTagProvider#getDeletedTags()}. */ @Test public void testGetDeletedTags() { - String revision = "b2002b64013e54b78eac251df0672bd5d6a83aa7"; - GitHookTagProvider provider = createProvider(ReceiveCommand.Type.DELETE, "refs/tags/1.0.0", ZERO, revision); - - assertThat(provider.getCreatedTags(), empty()); - assertTag("1.0.0", revision, null, provider.getDeletedTags()); + try (MockedStatic dummy = Mockito.mockStatic(GitUtil.class)) { + String revision = "b2002b64013e54b78eac251df0672bd5d6a83aa7"; + Long timestamp = 1339416344000L; + String tagName = "1.0.0"; + String ref = "refs/tags/" + tagName; + + dummy.when(() -> GitUtil.getTagTime(repository, gitRef)).thenReturn(timestamp); + dummy.when(() -> GitUtil.getTagName(ref)).thenReturn(tagName); + dummy.when(() -> GitUtil.getId(ObjectId.fromString(revision))).thenReturn(revision); + + GitHookTagProvider provider = createProvider(ReceiveCommand.Type.DELETE, ref, ZERO, revision); + + assertThat(provider.getCreatedTags(), empty()); + assertTag("1.0.0", revision, 1339416344000L, provider.getDeletedTags()); + } } - + /** * Tests {@link GitHookTagProvider} with a branch ref instead of a tag. */ @@ -126,7 +131,7 @@ public class GitHookTagProviderTest{ public void testWithBranch() { String revision = "b2002b64013e54b78eac251df0672bd5d6a83aa7"; GitHookTagProvider provider = createProvider(ReceiveCommand.Type.CREATE, "refs/heads/1.0.0", revision, revision); - + assertThat(provider.getCreatedTags(), empty()); assertThat(provider.getDeletedTags(), empty()); } @@ -136,24 +141,38 @@ public class GitHookTagProviderTest{ */ @Test public void testUpdateTags() { - String newId = "b2002b64013e54b78eac251df0672bd5d6a83aa7"; - String oldId = "e0f2be968b147ff7043684a7715d2fe852553db4"; + try (MockedStatic dummy = Mockito.mockStatic(GitUtil.class)) { + String newRevision = "b2002b64013e54b78eac251df0672bd5d6a83aa7"; + Long newTimestamp = 1339416344000L; + String newTagName = "1.0.0"; + String newRef = "refs/tags/" + newTagName; - GitHookTagProvider provider = createProvider(ReceiveCommand.Type.UPDATE, "refs/tags/1.0.0", newId, oldId); - assertTag("1.0.0", newId, null, provider.getCreatedTags()); - assertTag("1.0.0", oldId, null, provider.getDeletedTags()); + String oldRevision = "e0f2be968b147ff7043684a7715d2fe852553db4"; + String oldTagName = "0.9.0"; + + dummy.when(() -> GitUtil.getTagTime(repository, gitRef)).thenReturn(newTimestamp); + dummy.when(() -> GitUtil.getTagName(newRef)).thenReturn(newTagName); + dummy.when(() -> GitUtil.getId(ObjectId.fromString(newRevision))).thenReturn(newRevision); + + dummy.when(() -> GitUtil.getId(ObjectId.fromString(oldRevision))).thenReturn(oldRevision); + + GitHookTagProvider provider = createProvider(ReceiveCommand.Type.UPDATE, newRef, newRevision, oldRevision); + + assertTag(newTagName, newRevision, newTimestamp, provider.getCreatedTags()); + assertTag(oldTagName, oldRevision, null, provider.getDeletedTags()); + } } - private void assertTag(String name, String revision, Long date, List tags){ + private void assertTag(String name, String revision, Long date, List tags) { assertNotNull(tags); assertFalse(tags.isEmpty()); assertEquals(1, tags.size()); Tag tag = tags.get(0); assertEquals(name, tag.getName()); assertEquals(revision, tag.getRevision()); - assertEquals(date, tag.getDate()); + assertEquals(date, tag.getDate().orElse(null)); } - + private GitHookTagProvider createProvider(ReceiveCommand.Type type, String ref, String newId, String oldId) { when(command.getNewId()).thenReturn(ObjectId.fromString(newId)); when(command.getOldId()).thenReturn(ObjectId.fromString(oldId)); diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitTagsCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitTagsCommandTest.java index afa3cc4930..3152b36040 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitTagsCommandTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitTagsCommandTest.java @@ -55,9 +55,9 @@ public class GitTagsCommandTest extends AbstractGitCommandTestBase { final List tags = tagsCommand.getTags(); assertThat(tags).hasSize(2); assertThat(tags.get(0).getName()).isEqualTo("1.0.0"); - assertThat(tags.get(0).getDate()).isEqualTo(1598348105000L); // Annotated - Take tag date + assertThat(tags.get(0).getDate()).contains(1598348105000L); // Annotated - Take tag date assertThat(tags.get(1).getName()).isEqualTo("test-tag"); - assertThat(tags.get(1).getDate()).isEqualTo(1339416344000L); // Lightweight - Take commit date + assertThat(tags.get(1).getDate()).contains(1339416344000L); // Lightweight - Take commit date } @Override diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/api/HgHookTagProviderTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/api/HgHookTagProviderTest.java index f557fec51e..18e7fb8c48 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/api/HgHookTagProviderTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/api/HgHookTagProviderTest.java @@ -85,12 +85,12 @@ public class HgHookTagProviderTest { Tag t1 = tags.get(0); assertEquals("1", t1.getRevision()); assertEquals("1.0.0", t1.getName()); - Assertions.assertThat(t1.getDate()).isEqualTo(Long.MIN_VALUE); + Assertions.assertThat(t1.getDate()).contains(Long.MIN_VALUE); Tag t2 = tags.get(1); assertEquals("2", t2.getRevision()); assertEquals("2.0.0", t2.getName()); - Assertions.assertThat(t2.getDate()).isEqualTo(Long.MAX_VALUE); + Assertions.assertThat(t2.getDate()).contains(Long.MAX_VALUE); } private void prepareChangesets(Changeset... changesets){ diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgTagsCommandTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgTagsCommandTest.java index f9d3fdd5b2..e9bb65bf89 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgTagsCommandTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgTagsCommandTest.java @@ -39,7 +39,7 @@ public class HgTagsCommandTest extends AbstractHgCommandTestBase { final List tags = hgTagsCommand.getTags(); assertThat(tags).hasSize(1); assertThat(tags.get(0).getName()).isEqualTo("tip"); - assertThat(tags.get(0).getDate()).isEqualTo(1339586381000L); + assertThat(tags.get(0).getDate()).contains(1339586381000L); } } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagToTagDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagToTagDtoMapper.java index 532eb9be85..940b33dd05 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagToTagDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagToTagDtoMapper.java @@ -38,6 +38,7 @@ import sonia.scm.web.EdisonHalAppender; import javax.inject.Inject; import java.time.Instant; +import java.util.Optional; import static de.otto.edison.hal.Embedded.embeddedBuilder; import static de.otto.edison.hal.Link.link; @@ -67,7 +68,7 @@ public abstract class TagToTagDtoMapper extends HalAppenderMapper { } @Named("mapDate") - Instant map(Long value) { - return value == null ? null : Instant.ofEpochMilli(value); + Instant map(Optional value) { + return value.map(Instant::ofEpochMilli).orElse(null); } } From e9a4a9f1733cf523291c5a9fcbff4d7f64f02683 Mon Sep 17 00:00:00 2001 From: Konstantin Schaper Date: Wed, 26 Aug 2020 11:18:45 +0200 Subject: [PATCH 06/23] update storyshots and fix endless loop in tests --- .../src/__snapshots__/storyshots.test.ts.snap | 76525 ++++++++-------- scm-ui/ui-components/src/repos/Diff.tsx | 15 +- 2 files changed, 38318 insertions(+), 38222 deletions(-) diff --git a/scm-ui/ui-components/src/__snapshots__/storyshots.test.ts.snap b/scm-ui/ui-components/src/__snapshots__/storyshots.test.ts.snap index c725cfbb6d..3a1290349d 100644 --- a/scm-ui/ui-components/src/__snapshots__/storyshots.test.ts.snap +++ b/scm-ui/ui-components/src/__snapshots__/storyshots.test.ts.snap @@ -3896,261 +3896,265 @@ exports[`Storyshots Diff Binaries 1`] = `
-
+
- - - Main.java - - - modify - -
-
+ + + Main.java + + + modify + +
+
- - - - - + + + + +
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- 1 - - 1 - - class Main { -
- 2 - - 2 - - - public static void main(String[] args) { -
- 3 - - 3 - - + public static void main(String[] arguments) { -
- 4 - - 4 - - System.out.println("Expect nothing more to happen."); -
- 5 - - 5 - - } -
-
-
-
-
-
- + + + + + - conflict.png - - - add - -
-
-
-
+ + + 1 + + + 1 + + + class Main { + + + + + 2 + + + 2 + + + - public static void main(String[] args) { + + + + + 3 + + + 3 + + + + public static void main(String[] arguments) { + + + + + 4 + + + 4 + + + System.out.println("Expect nothing more to happen."); + + + + + 5 + + + 5 + + + } + + + +
- - - - - - -
+
+
+ + conflict.png + + + add + +
+
+
+
+
+
+
+ + + + + + +
+
@@ -4160,570 +4164,578 @@ exports[`Storyshots Diff Collapsed 1`] = `
-
+
- - - src/main/java/com/cloudogu/scm/review/events/EventListener.java - - - modify - -
-
+ + + src/main/java/com/cloudogu/scm/review/events/EventListener.java + + + modify + +
+
- - - - - -
-
- + + + +
+
- - - - -
-
- + + + +
+
- - - - + + + + +
-
-
- - - src/main/js/ChangeNotification.tsx - - - modify - -
-
+ + + src/main/js/ChangeNotification.tsx + + + modify + +
+
- - - - - -
-
- + + + +
+
- - - - -
-
- + + + +
+
- - - - + + + + +
-
-
- - - src/main/resources/locales/de/plugins.json - - - modify - -
-
+ + + src/main/resources/locales/de/plugins.json + + + modify + +
+
- - - - - -
-
- + + + +
+
- - - - -
-
- + + + +
+
- - - - + + + + +
-
-
- - - src/main/resources/locales/en/plugins.json - - - modify - -
-
+ + + src/main/resources/locales/en/plugins.json + + + modify + +
+
- - - - - -
-
- + + + +
+
- - - - -
-
- + + + +
+
- - - - + + + + +
-
-
- - - src/test/java/com/cloudogu/scm/review/events/ClientTest.java - - - modify - -
-
+ + + src/test/java/com/cloudogu/scm/review/events/ClientTest.java + + + modify + +
+
- - - - - -
-
- + + + +
+
- - - - -
-
- + + + +
+
- - - - + + + + +
- -
- - - Main.java - - - modify - -
-
+ + + Main.java + + + modify + +
+
- - - - - -
-
- + + + +
+
- - - - -
-
- + + + +
+
- - - - + + + + +
@@ -4737,1883 +4749,1891 @@ exports[`Storyshots Diff CollapsingWithFunction 1`] = `
-
+
- - - src/main/java/com/cloudogu/scm/review/events/EventListener.java - - - modify - -
-
-
- - - - - -
-
-
-
-
-
-
-
-
-
- - - src/main/js/ChangeNotification.tsx - - - modify - -
-
-
-
- - - - - -
-
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - + +
-
- - - - - - - - - - - - - - - + + + + + + + + + + + +
+
+
-
- + + + + +
- 2 - - 2 - - import { Link } from "@scm-manager/ui-types"; -
- 3 - - 3 - - import { apiClient, Toast, ToastButtons, ToastButton } from "@scm-manager/ui-components"; -
- 4 - - 4 - - import { PullRequest } from "./types/PullRequest"; -
- - 5 - + - import { useTranslation } from "react-i18next"; -
- 5 - - 6 - - -
- 6 - - 7 - - type HandlerProps = { -
- 7 - - 8 - - url: string; -
+ + -
+ + modify + + +
+
+
+ + + + + +
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + - - - - + 5 + + + + + + + + + + + + + + + + + + + + - - - - - + + + + - - + + + + - 17 - - + + + + - }); - - - - + + + + - 17 - - + + + - 18 - - + + + + - }, [url]); - - - - + + + + - 19 - - + + + - const { t } = useTranslation("plugins"); - - - - + + + - 18 - - + + + - 20 - - + + + - if (event) { - - - - + + + - 19 - - + + + - 21 - - + + + + - return ( - - - - + + + - 20 - - + + + - <Toast type="warning" title="New Changes"> - - - - + + + - 21 - - + + + - <p>The underlying Pull-Request has changed. Press reload to see the changes.</p> - - - - + + + - 22 - - + + + - <p>Warning: Non saved modification will be lost.</p> - - - - + + + - 22 - - + + + - <Toast type="warning" title={t("scm-review-plugin.changeNotification.title")}> - - - - + + + + - 23 - - + + + + - <p>{t("scm-review-plugin.changeNotification.description")}</p> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ 2 + + 2 + + import { Link } from "@scm-manager/ui-types"; +
+ 3 + + 3 + + import { apiClient, Toast, ToastButtons, ToastButton } from "@scm-manager/ui-components"; +
+ 4 + + 4 + + import { PullRequest } from "./types/PullRequest"; +
-
+ import { useTranslation } from "react-i18next"; +
+ 5 + + 6 + + +
+ 6 + + 7 + + type HandlerProps = { +
+ 7 + + 8 + + url: string; +
- 15 - - 16 - - pullRequest: setEvent -
+
+
- 16 - + 15 + + 16 + + pullRequest: setEvent +
+ 16 + + 17 + + }); +
+ 17 + + 18 + + }, [url]); +
+ + 19 + + const { t } = useTranslation("plugins"); +
+ 18 + + 20 + + if (event) { +
- + 19 + + 21 + + return ( +
+ 20 + + + <Toast type="warning" title="New Changes"> +
+ 21 + + + <p>The underlying Pull-Request has changed. Press reload to see the changes.</p> +
+ 22 + + + <p>Warning: Non saved modification will be lost.</p> +
+ + 22 + + <Toast type="warning" title={t("scm-review-plugin.changeNotification.title")}> +
+ + 23 + + <p>{t("scm-review-plugin.changeNotification.description")}</p> +
+ + 24 + + <p>{t("scm-review-plugin.changeNotification.modificationWarning")}</p> +
+ 23 + + 25 + + <ToastButtons> +
+ 24 + + + <ToastButton icon="redo" onClick={reload}>Reload</ToastButton> +
- + 25 + + + <ToastButton icon="times" onClick={() => setEvent(undefined)}>Ignore</ToastButton> +
+ + 26 + + <ToastButton icon="redo" onClick={reload}> +
- + + 27 + + {t("scm-review-plugin.changeNotification.buttons.reload")} +
+ + 28 + + </ToastButton> +
- + + 29 + + <ToastButton icon="times" onClick={() => setEvent(undefined)}> +
- + + 30 + + {t("scm-review-plugin.changeNotification.buttons.ignore")} +
+ + 31 + + </ToastButton> +
- + 26 + + 32 + + </ToastButtons> +
+ 27 + + 33 + + </Toast> +
- - 24 - - <p>{t("scm-review-plugin.changeNotification.modificationWarning")}</p> -
- 23 - - 25 - - <ToastButtons> -
- 24 - - - <ToastButton icon="redo" onClick={reload}>Reload</ToastButton> -
- 25 - - - <ToastButton icon="times" onClick={() => setEvent(undefined)}>Ignore</ToastButton> -
- - 26 - - <ToastButton icon="redo" onClick={reload}> -
- - 27 - - {t("scm-review-plugin.changeNotification.buttons.reload")} -
- - 28 - - </ToastButton> -
- - 29 - - <ToastButton icon="times" onClick={() => setEvent(undefined)}> -
- - 30 - - {t("scm-review-plugin.changeNotification.buttons.ignore")} -
- - 31 - - </ToastButton> -
- 26 - - 32 - - </ToastButtons> -
- 27 - - 33 - - </Toast> -
- 28 - - 34 - - ); -
+
+ 28 + + 34 + + ); +
+
-
-
- - - src/main/resources/locales/de/plugins.json - - - modify - -
-
+ + + src/main/resources/locales/de/plugins.json + + + modify + +
+
- - - - - + + + + +
-
-
- - - - - - - - + + + + + - - + + + + - 181 - - - - - - - + + + + + + + - - - + - 183 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- 181 - + 181 + + 181 + + "titleClickable": "Der Kommentar bezieht sich auf eine ältere Version des Source- oder Target-Branches. Klicken Sie hier, um den ursprünglichen Kontext zu sehen." +
- "titleClickable": "Der Kommentar bezieht sich auf eine ältere Version des Source- oder Target-Branches. Klicken Sie hier, um den ursprünglichen Kontext zu sehen." -
- 182 - - 182 - + 182 + + 182 + + } +
+ 183 + + 183 + } -
+
- 183 - - } -
- - 184 - - }, -
- - 185 - - "changeNotification": { -
- - 186 - - "title": "Neue Änderungen", -
- - 187 - - "description": "An diesem Pull Request wurden Änderungen vorgenommen. Laden Sie die Seite neu um diese anzuzeigen.", -
- - 188 - - "modificationWarning": "Warnung: Nicht gespeicherte Eingaben gehen verloren.", -
- - 189 - - "buttons": { -
- - 190 - - "reload": "Neu laden", -
- - 191 - - "ignore": "Ignorieren" -
- - 192 - - } -
- 184 - - 193 - - } -
- 185 - - 194 - - }, -
- 186 - - 195 - - "permissions": { -
-
-
-
-
-
-
- - - src/main/resources/locales/en/plugins.json - - - modify - -
-
-
-
- + - - - - -
-
-
-
-
-
- - - - - - - - - + + - 181 - - + + + - 181 - - + + + - "titleClickable": "The comment is related to an older of the source or target branch. Click here to see the original context." - - - - + + + - 182 - - + + + - 182 - - + + + + + + + + + + + + + - - - - - + + + + - - - - + + + + - - - + - 185 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ + }, +
+ + 185 + + "changeNotification": { +
+ + 186 + + "title": "Neue Änderungen", +
+ + 187 + + "description": "An diesem Pull Request wurden Änderungen vorgenommen. Laden Sie die Seite neu um diese anzuzeigen.", +
+ + 188 + + "modificationWarning": "Warnung: Nicht gespeicherte Eingaben gehen verloren.", +
+ + 189 + + "buttons": { +
+ + 190 + + "reload": "Neu laden", +
+ + 191 + + "ignore": "Ignorieren" +
+ + 192 + } -
- 183 - - 183 - +
+ 184 + + 193 + } -
- - 184 - +
+ 185 + + 194 + }, -
- +
- "changeNotification": { -
- - 186 - - "title": "New Changes", -
- - 187 - - "description": "The underlying Pull-Request has changed. Press reload to see the changes.", -
- - 188 - - "modificationWarning": "Warning: Non saved modification will be lost.", -
- - 189 - - "buttons": { -
- - 190 - - "reload": "Reload", -
- - 191 - - "ignore": "Ignore" -
- - 192 - - } -
- 184 - - 193 - - } -
- 185 - - 194 - - }, -
- 186 - - 195 - - "permissions": { -
+ + 186 + + + 195 + + + "permissions": { + + + + +
-
-
- - - src/test/java/com/cloudogu/scm/review/events/ClientTest.java - - - modify - -
-
+ + + src/main/resources/locales/en/plugins.json + + + modify + +
+
- - - - - + + + + +
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 181 + + 181 + + "titleClickable": "The comment is related to an older of the source or target branch. Click here to see the original context." +
+ 182 + + 182 + + } +
+ 183 + + 183 + + } +
+ + 184 + + }, +
+ + 185 + + "changeNotification": { +
+ + 186 + + "title": "New Changes", +
+ + 187 + + "description": "The underlying Pull-Request has changed. Press reload to see the changes.", +
+ + 188 + + "modificationWarning": "Warning: Non saved modification will be lost.", +
+ + 189 + + "buttons": { +
+ + 190 + + "reload": "Reload", +
+ + 191 + + "ignore": "Ignore" +
+ + 192 + + } +
+ 184 + + 193 + + } +
+ 185 + + 194 + + }, +
+ 186 + + 195 + + "permissions": { +
+
+
+
+
+
+
+ + + src/test/java/com/cloudogu/scm/review/events/ClientTest.java + + + modify + +
+
+
+
+ + + + + +
-
-
- - - Main.java - - - modify - -
-
+ + + Main.java + + + modify + +
+
- - - - - + + + + +
@@ -6627,3834 +6647,3842 @@ exports[`Storyshots Diff Default 1`] = `
-
+
- - - src/main/java/com/cloudogu/scm/review/events/EventListener.java - - - modify - -
-
+ + + src/main/java/com/cloudogu/scm/review/events/EventListener.java + + + modify + +
+
- - - - - + + + + +
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- 1 - - 1 - - package com.cloudogu.scm.review.events; -
- 2 - - 2 - - -
- 3 - - - import com.cloudogu.scm.review.comment.service.BasicComment; -
- 4 - - - import com.cloudogu.scm.review.comment.service.BasicCommentEvent; -
- 5 - - - import com.cloudogu.scm.review.comment.service.CommentEvent; -
- 6 - - - import com.cloudogu.scm.review.comment.service.ReplyEvent; -
- 7 - - 3 - - import com.cloudogu.scm.review.pullrequest.service.BasicPullRequestEvent; -
- 8 - - 4 - - import com.cloudogu.scm.review.pullrequest.service.PullRequest; -
- 9 - - - import com.cloudogu.scm.review.pullrequest.service.PullRequestEvent; -
- 10 - - 5 - - import com.github.legman.Subscribe; -
- 11 - - - import lombok.Data; -
- 12 - - 6 - - import org.apache.shiro.SecurityUtils; -
- 13 - - 7 - - import org.apache.shiro.subject.PrincipalCollection; -
- 14 - - 8 - - import org.apache.shiro.subject.Subject; -
- 15 - - 9 - - import sonia.scm.EagerSingleton; -
- 16 - - - import sonia.scm.HandlerEventType; -
- 17 - - - import sonia.scm.event.HandlerEvent; -
- 18 - - 10 - - import sonia.scm.plugin.Extension; -
- 19 - - 11 - - import sonia.scm.repository.Repository; -
- 20 - - 12 - - import sonia.scm.security.SessionId; -
-
-
-
-
-
- - - src/main/js/ChangeNotification.tsx - - - modify - -
-
-
-
- - - - - -
-
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - + + + + - 6 - - + + + + - - - - - - - - - - - - - - - - - + - - - - - + + - 15 - - + + + - 16 - - + + + - pullRequest: setEvent - - - - + + + - 16 - - + + + + - 17 - - + + + + - }); - - - - + + + - 17 - - + + + + - 18 - - + + + - }, [url]); - - - - + + + + - 19 - - + + + + - const { t } = useTranslation("plugins"); - - - - + + + + - 18 - - + + + + - 20 - - + + + - if (event) { - - - - + + + - 19 - - + + + + - 21 - - + + + + - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- 2 - - 2 - - import { Link } from "@scm-manager/ui-types"; -
- 3 - - 3 - - import { apiClient, Toast, ToastButtons, ToastButton } from "@scm-manager/ui-components"; -
- 4 - - 4 - - import { PullRequest } from "./types/PullRequest"; -
+
- 5 - - import { useTranslation } from "react-i18next"; -
- 5 - + 1 + + 1 + + package com.cloudogu.scm.review.events; +
+ 2 + + 2 + + +
- 6 - - 7 - - type HandlerProps = { -
- 7 - - 8 - - url: string; -
-
+ 3 +
-
+ import com.cloudogu.scm.review.comment.service.BasicComment; +
+ 4 + + + import com.cloudogu.scm.review.comment.service.BasicCommentEvent; +
+ 5 + + + import com.cloudogu.scm.review.comment.service.CommentEvent; +
+ 6 + + + import com.cloudogu.scm.review.comment.service.ReplyEvent; +
+ 7 + + 3 + + import com.cloudogu.scm.review.pullrequest.service.BasicPullRequestEvent; +
+ 8 + + 4 + + import com.cloudogu.scm.review.pullrequest.service.PullRequest; +
+ 9 + + + import com.cloudogu.scm.review.pullrequest.service.PullRequestEvent; +
+ 10 + + 5 + + import com.github.legman.Subscribe; +
+ 11 + + + import lombok.Data; +
- + 12 + + 6 + + import org.apache.shiro.SecurityUtils; +
+ 13 + + 7 + + import org.apache.shiro.subject.PrincipalCollection; +
+ 14 + + 8 + + import org.apache.shiro.subject.Subject; +
+ 15 + + 9 + + import sonia.scm.EagerSingleton; +
+ 16 + + + import sonia.scm.HandlerEventType; +
+ 17 + + + import sonia.scm.event.HandlerEvent; +
+ 18 + + 10 + + import sonia.scm.plugin.Extension; +
+ 19 + + 11 + + import sonia.scm.repository.Repository; +
- 20 - - - <Toast type="warning" title="New Changes"> -
- 21 - - - <p>The underlying Pull-Request has changed. Press reload to see the changes.</p> -
- 22 - - - <p>Warning: Non saved modification will be lost.</p> -
- - 22 - - <Toast type="warning" title={t("scm-review-plugin.changeNotification.title")}> -
- - 23 - - <p>{t("scm-review-plugin.changeNotification.description")}</p> -
- - 24 - - <p>{t("scm-review-plugin.changeNotification.modificationWarning")}</p> -
- 23 - - 25 - - <ToastButtons> -
- 24 - - - <ToastButton icon="redo" onClick={reload}>Reload</ToastButton> -
- 25 - - - <ToastButton icon="times" onClick={() => setEvent(undefined)}>Ignore</ToastButton> -
- - 26 - - <ToastButton icon="redo" onClick={reload}> -
- - 27 - - {t("scm-review-plugin.changeNotification.buttons.reload")} -
- - 28 - - </ToastButton> -
- - 29 - - <ToastButton icon="times" onClick={() => setEvent(undefined)}> -
- - 30 - - {t("scm-review-plugin.changeNotification.buttons.ignore")} -
- - 31 - - </ToastButton> -
- 26 - - 32 - - </ToastButtons> -
- 27 - - 33 - - </Toast> -
- 28 - - 34 - - ); -
+ + 20 + + + 12 + + + import sonia.scm.security.SessionId; + + + + +
-
-
- - - src/main/resources/locales/de/plugins.json - - - modify - -
-
+ + + src/main/js/ChangeNotification.tsx + + + modify + +
+
- - - - - + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 2 + + 2 + + import { Link } from "@scm-manager/ui-types"; +
+ 3 + + 3 + + import { apiClient, Toast, ToastButtons, ToastButton } from "@scm-manager/ui-components"; +
+ 4 + + 4 + + import { PullRequest } from "./types/PullRequest"; +
+ + 5 + + import { useTranslation } from "react-i18next"; +
+ 5 + + 6 + + +
+ 6 + + 7 + + type HandlerProps = { +
+ 7 + + 8 + + url: string; +
+
+
+ 15 + + 16 + + pullRequest: setEvent +
+ 16 + + 17 + + }); +
+ 17 + + 18 + + }, [url]); +
+ + 19 + + const { t } = useTranslation("plugins"); +
+ 18 + + 20 + + if (event) { +
+ 19 + + 21 + + return ( +
+ 20 + + + <Toast type="warning" title="New Changes"> +
+ 21 + + + <p>The underlying Pull-Request has changed. Press reload to see the changes.</p> +
+ 22 + + + <p>Warning: Non saved modification will be lost.</p> +
+ + 22 + + <Toast type="warning" title={t("scm-review-plugin.changeNotification.title")}> +
+ + 23 + + <p>{t("scm-review-plugin.changeNotification.description")}</p> +
+ + 24 + + <p>{t("scm-review-plugin.changeNotification.modificationWarning")}</p> +
+ 23 + + 25 + + <ToastButtons> +
+ 24 + + + <ToastButton icon="redo" onClick={reload}>Reload</ToastButton> +
+ 25 + + + <ToastButton icon="times" onClick={() => setEvent(undefined)}>Ignore</ToastButton> +
+ + 26 + + <ToastButton icon="redo" onClick={reload}> +
+ + 27 + + {t("scm-review-plugin.changeNotification.buttons.reload")} +
+ + 28 + + </ToastButton> +
+ + 29 + + <ToastButton icon="times" onClick={() => setEvent(undefined)}> +
+ + 30 + + {t("scm-review-plugin.changeNotification.buttons.ignore")} +
+ + 31 + + </ToastButton> +
+ 26 + + 32 + + </ToastButtons> +
+ 27 + + 33 + + </Toast> +
+ 28 + + 34 + + ); +
+
- - - - - - - - - - - - - + +
-
- + + + + +
+ - 181 - + - 181 - - "titleClickable": "Der Kommentar bezieht sich auf eine ältere Version des Source- oder Target-Branches. Klicken Sie hier, um den ursprünglichen Kontext zu sehen." -
- 182 - + + + + + + + + + + +
+ + + + + + + + - 182 - - + + + + + + + + + + + + - - - + - 183 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ 181 + + 181 + + "titleClickable": "Der Kommentar bezieht sich auf eine ältere Version des Source- oder Target-Branches. Klicken Sie hier, um den ursprünglichen Kontext zu sehen." +
+ 182 + + 182 + + } +
+ 183 + + 183 + } -
+
- 183 - - } -
- - 184 - - }, -
- - 185 - - "changeNotification": { -
- - 186 - - "title": "Neue Änderungen", -
- - 187 - - "description": "An diesem Pull Request wurden Änderungen vorgenommen. Laden Sie die Seite neu um diese anzuzeigen.", -
- - 188 - - "modificationWarning": "Warnung: Nicht gespeicherte Eingaben gehen verloren.", -
- - 189 - - "buttons": { -
- - 190 - - "reload": "Neu laden", -
- - 191 - - "ignore": "Ignorieren" -
- - 192 - - } -
- 184 - - 193 - - } -
- 185 - - 194 - - }, -
- 186 - - 195 - - "permissions": { -
-
- -
-
-
-
- - - src/main/resources/locales/en/plugins.json - - - modify - -
-
-
-
- +
- - - - - - - - - -
- - - - - - - - - + + - 181 - - + + + - 181 - - + + + - "titleClickable": "The comment is related to an older of the source or target branch. Click here to see the original context." - - - - + + + - 182 - - + + + - 182 - - + + + + + + + + + + + + + - - - - - + + + + - - - - + + + + - - - + - 185 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ + }, +
+ + 185 + + "changeNotification": { +
+ + 186 + + "title": "Neue Änderungen", +
+ + 187 + + "description": "An diesem Pull Request wurden Änderungen vorgenommen. Laden Sie die Seite neu um diese anzuzeigen.", +
+ + 188 + + "modificationWarning": "Warnung: Nicht gespeicherte Eingaben gehen verloren.", +
+ + 189 + + "buttons": { +
+ + 190 + + "reload": "Neu laden", +
+ + 191 + + "ignore": "Ignorieren" +
+ + 192 + } -
- 183 - - 183 - +
+ 184 + + 193 + } -
- - 184 - +
+ 185 + + 194 + }, -
- +
- "changeNotification": { -
- - 186 - - "title": "New Changes", -
- - 187 - - "description": "The underlying Pull-Request has changed. Press reload to see the changes.", -
- - 188 - - "modificationWarning": "Warning: Non saved modification will be lost.", -
- - 189 - - "buttons": { -
- - 190 - - "reload": "Reload", -
- - 191 - - "ignore": "Ignore" -
- - 192 - - } -
- 184 - - 193 - - } -
- 185 - - 194 - - }, -
- 186 - - 195 - - "permissions": { -
+
+ 186 + + 195 + + "permissions": { +
+
-
-
- - - src/test/java/com/cloudogu/scm/review/events/ClientTest.java - - - modify - -
-
+ + + src/main/resources/locales/en/plugins.json + + + modify + +
+
- - - - - + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 181 + + 181 + + "titleClickable": "The comment is related to an older of the source or target branch. Click here to see the original context." +
+ 182 + + 182 + + } +
+ 183 + + 183 + + } +
+ + 184 + + }, +
+ + 185 + + "changeNotification": { +
+ + 186 + + "title": "New Changes", +
+ + 187 + + "description": "The underlying Pull-Request has changed. Press reload to see the changes.", +
+ + 188 + + "modificationWarning": "Warning: Non saved modification will be lost.", +
+ + 189 + + "buttons": { +
+ + 190 + + "reload": "Reload", +
+ + 191 + + "ignore": "Ignore" +
+ + 192 + + } +
+ 184 + + 193 + + } +
+ 185 + + 194 + + }, +
+ 186 + + 195 + + "permissions": { +
+
- - - - - - - - - - - - - - - - - - - - - - - - - - - + +
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + +
+
- 7 - - 7 - - import org.mockito.Mock; -
- 8 - - 8 - - import org.mockito.junit.jupiter.MockitoExtension; -
- 9 - - 9 - - import sonia.scm.security.SessionId; -
- - 10 - + - -
- 10 - - 11 - - import javax.ws.rs.sse.OutboundSseEvent; -
- 11 - - 12 - - import javax.ws.rs.sse.SseEventSink; -
- 12 - - - -
- 13 - - 13 - - import java.time.Clock; -
- 14 - - 14 - - import java.time.Instant; -
- 15 - - 15 - - import java.time.LocalDateTime; -
- 16 - - 16 - - import java.time.ZoneOffset; -
- 17 - - 17 - - import java.time.temporal.ChronoField; -
- 18 - - - import java.time.temporal.ChronoUnit; -
- 19 - - - import java.time.temporal.TemporalField; -
- 20 - - 18 - - import java.util.concurrent.CompletableFuture; -
- 21 - - 19 - - import java.util.concurrent.CompletionStage; -
- 22 - - - import java.util.concurrent.atomic.AtomicLong; -
- 23 - - 20 - - import java.util.concurrent.atomic.AtomicReference; -
- 24 - - 21 - - -
- 25 - - 22 - - import static java.time.temporal.ChronoUnit.MINUTES; -
- - + + + + + -
+ 7 + +
+ + + + + + + + + + + + + + - - - - - + + + - 83 - - + + + + - 80 - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ 7 + + import org.mockito.Mock; +
+ 8 + + 8 + + import org.mockito.junit.jupiter.MockitoExtension; +
+ 9 + + 9 + + import sonia.scm.security.SessionId; +
-
+ 10 + + +
+ 10 + + 11 + + import javax.ws.rs.sse.OutboundSseEvent; +
+ 11 + + 12 + + import javax.ws.rs.sse.SseEventSink; +
- 84 - - 81 - - @Test -
- 85 - - 82 - - @SuppressWarnings("unchecked") -
- 86 - - - void shouldCloseEventSinkOnFailure() throws InterruptedException { -
- - 83 - - void shouldCloseEventSinkOnFailure() { -
- 87 - - 84 - - CompletionStage future = CompletableFuture.supplyAsync(() -> { -
- 88 - - 85 - - throw new RuntimeException("failed to send message"); -
- 89 - - 86 - - }); -
-
+ 12 +
-
+ 13 + + 13 + + import java.time.Clock; +
+ 14 + + 14 + + import java.time.Instant; +
+ 15 + + 15 + + import java.time.LocalDateTime; +
+ 16 + + 16 + + import java.time.ZoneOffset; +
+ 17 + + 17 + + import java.time.temporal.ChronoField; +
+ 18 + + + import java.time.temporal.ChronoUnit; +
+ 19 + + + import java.time.temporal.TemporalField; +
+ 20 + + 18 + + import java.util.concurrent.CompletableFuture; +
+ 21 + + 19 + + import java.util.concurrent.CompletionStage; +
+ 22 + + + import java.util.concurrent.atomic.AtomicLong; +
+ 23 + + 20 + + import java.util.concurrent.atomic.AtomicReference; +
+ 24 + + 21 + + +
+ 25 + + 22 + + import static java.time.temporal.ChronoUnit.MINUTES; +
+
+
+ 83 + + 80 + + +
+ 84 + + 81 + + @Test +
+ 85 + + 82 + + @SuppressWarnings("unchecked") +
+ 86 + + + void shouldCloseEventSinkOnFailure() throws InterruptedException { +
+ + 83 + + void shouldCloseEventSinkOnFailure() { +
+ 87 + + 84 + + CompletionStage future = CompletableFuture.supplyAsync(() -> { +
+ 88 + + 85 + + throw new RuntimeException("failed to send message"); +
+ 89 + + 86 + + }); +
+
+
+ 91 + + 88 + + +
+ 92 + + 89 + + client.send(message); +
+ 93 + + 90 + + +
+ 94 + + + Thread.sleep(50L); +
+ 95 + + + +
+ 96 + + + verify(eventSink).close(); +
+ + 91 + + verify(eventSink, timeout(50L)).close(); +
+ 97 + + 92 + + } +
+ 98 + + 93 + + +
+ 99 + + 94 + + @Test +
+
+ +
+
+
- - - 91 - - - 88 - - - - - - - - 92 - - - 89 - - - client.send(message); - - - - - 93 - - - 90 - - - - - - - - 94 - - - - Thread.sleep(50L); - - - + + modify + +
+
- - 95 - - + + + + + +
+
+
+ + +
+ + + - - - - - - - + + - - + + + - verify(eventSink, timeout(50L)).close(); - - - - + + + + - 97 - - + + + + - 92 - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - -
- -
- 96 - - - verify(eventSink).close(); -
- - 91 - + + 1 + + import java.io.PrintStream; +
+ 1 + + 2 + + import java.util.Arrays; +
+ 2 + + 3 + + +
+ 3 + + 4 + + class Main { +
+ + 5 + + private static final PrintStream OUT = System.out; +
+ + 6 + + +
+ 4 + + 7 + + public static void main(String[] args) { +
+ + 8 + + <<<<<<< HEAD +
+ 5 + + 9 + + System.out.println("Expect nothing more to happen."); +
+ 6 + + 10 + + System.out.println("The command line parameters are:"); +
+ 7 + + 11 + + Arrays.stream(args).map(arg -> "- " + arg).forEach(System.out::println); +
+ + 12 + + ======= +
+ + 13 + + OUT.println("Expect nothing more to happen."); +
+ + 14 + + OUT.println("Parameters:"); +
+ + 15 + + Arrays.stream(args).map(arg -> "- " + arg).forEach(OUT::println); +
+ + 16 + + >>>>>>> feature/use_constant +
+ 8 + + 17 + + } +
+ 9 + + 18 + } -
- 98 - - 93 - - -
- 99 - - 94 - - @Test -
-
- -
-
-
-
- - - Main.java - - - modify - -
-
-
-
- - - - - -
-
-
+ + + +
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - 1 - - import java.io.PrintStream; -
- 1 - - 2 - - import java.util.Arrays; -
- 2 - - 3 - - -
- 3 - - 4 - - class Main { -
- - 5 - - private static final PrintStream OUT = System.out; -
- - 6 - - -
- 4 - - 7 - - public static void main(String[] args) { -
- - 8 - - <<<<<<< HEAD -
- 5 - - 9 - - System.out.println("Expect nothing more to happen."); -
- 6 - - 10 - - System.out.println("The command line parameters are:"); -
- 7 - - 11 - - Arrays.stream(args).map(arg -> "- " + arg).forEach(System.out::println); -
- - 12 - - ======= -
- - 13 - - OUT.println("Expect nothing more to happen."); -
- - 14 - - OUT.println("Parameters:"); -
- - 15 - - Arrays.stream(args).map(arg -> "- " + arg).forEach(OUT::println); -
- - 16 - - >>>>>>> feature/use_constant -
- 8 - - 17 - - } -
- 9 - - 18 - - } -
-
`; @@ -10463,4304 +10491,4312 @@ exports[`Storyshots Diff Expandable 1`] = `
-
+
- - - src/main/java/com/cloudogu/scm/review/events/EventListener.java - - - modify - -
-
+ + + src/main/java/com/cloudogu/scm/review/events/EventListener.java + + + modify + +
+
- - - - - + + + + +
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - -
- 1 - - 1 - - package com.cloudogu.scm.review.events; -
- 2 - - 2 - - -
- 3 - +
- import com.cloudogu.scm.review.comment.service.BasicComment; -
- 4 - - - import com.cloudogu.scm.review.comment.service.BasicCommentEvent; -
- 5 - - - import com.cloudogu.scm.review.comment.service.CommentEvent; -
- 6 - - - import com.cloudogu.scm.review.comment.service.ReplyEvent; -
- 7 - - 3 - - import com.cloudogu.scm.review.pullrequest.service.BasicPullRequestEvent; -
- 8 - - 4 - - import com.cloudogu.scm.review.pullrequest.service.PullRequest; -
- 9 - - - import com.cloudogu.scm.review.pullrequest.service.PullRequestEvent; -
- 10 - - 5 - - import com.github.legman.Subscribe; -
- 11 - - - import lombok.Data; -
- 12 - - 6 - - import org.apache.shiro.SecurityUtils; -
- 13 - - 7 - - import org.apache.shiro.subject.PrincipalCollection; -
- 14 - - 8 - - import org.apache.shiro.subject.Subject; -
- 15 - - 9 - - import sonia.scm.EagerSingleton; -
- 16 - - - import sonia.scm.HandlerEventType; -
- 17 - - - import sonia.scm.event.HandlerEvent; -
- 18 - - 10 - - import sonia.scm.plugin.Extension; -
- 19 - - 11 - - import sonia.scm.repository.Repository; -
- 20 - - 12 - - import sonia.scm.security.SessionId; -
-
+ 1 +
+ 1 + + package com.cloudogu.scm.review.events; +
+ 2 + + 2 + - - - - diff.expandLastBottomByLines - - +
+ 3 + + + import com.cloudogu.scm.review.comment.service.BasicComment; +
+ 4 + + + import com.cloudogu.scm.review.comment.service.BasicCommentEvent; +
+ 5 + + + import com.cloudogu.scm.review.comment.service.CommentEvent; +
+ 6 + + + import com.cloudogu.scm.review.comment.service.ReplyEvent; +
+ 7 + + 3 + + import com.cloudogu.scm.review.pullrequest.service.BasicPullRequestEvent; +
+ 8 + + 4 + + import com.cloudogu.scm.review.pullrequest.service.PullRequest; +
+ 9 + + + import com.cloudogu.scm.review.pullrequest.service.PullRequestEvent; +
+ 10 + + 5 + + import com.github.legman.Subscribe; +
+ 11 + + + import lombok.Data; +
+ 12 + + 6 + + import org.apache.shiro.SecurityUtils; +
+ 13 + + 7 + + import org.apache.shiro.subject.PrincipalCollection; +
+ 14 + + 8 + + import org.apache.shiro.subject.Subject; +
+ 15 + + 9 + + import sonia.scm.EagerSingleton; +
+ 16 + + + import sonia.scm.HandlerEventType; +
+ 17 + + + import sonia.scm.event.HandlerEvent; +
+ 18 + + 10 + + import sonia.scm.plugin.Extension; +
+ 19 + + 11 + + import sonia.scm.repository.Repository; +
+ 20 + + 12 + + import sonia.scm.security.SessionId; +
+
- + + + + diff.expandLastBottomByLines + - diff.expandLastBottomComplete - -
-
+ + + + diff.expandLastBottomComplete + +
+ + + + +
- -
- - - src/main/js/ChangeNotification.tsx - - - modify - -
-
+ + + src/main/js/ChangeNotification.tsx + + + modify + +
+
- - - - - + + + + +
-
-
- - - - - - - - - + + + + + + - - - - + + + diff.expandComplete + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - -
-
+
- - - - diff.expandComplete - - -
- 2 - - 2 - - import { Link } from "@scm-manager/ui-types"; -
- 3 - - 3 - - import { apiClient, Toast, ToastButtons, ToastButton } from "@scm-manager/ui-components"; -
- 4 - - 4 - - import { PullRequest } from "./types/PullRequest"; -
- - 5 - - import { useTranslation } from "react-i18next"; -
- 5 - - 6 - - -
- 6 - - 7 - - type HandlerProps = { -
- 7 - - 8 - - url: string; -
-
- - - - diff.expandComplete - -
-
-
+
- - - - diff.expandComplete - - -
- 15 - - 16 - - pullRequest: setEvent -
- 16 - - 17 - - }); -
- 17 - - 18 - - }, [url]); -
- - 19 - - const { t } = useTranslation("plugins"); -
- 18 - - 20 - - if (event) { -
- 19 - - 21 - - return ( -
- 20 - - - <Toast type="warning" title="New Changes"> -
- 21 - - - <p>The underlying Pull-Request has changed. Press reload to see the changes.</p> -
- 22 - - - <p>Warning: Non saved modification will be lost.</p> -
- - 22 - - <Toast type="warning" title={t("scm-review-plugin.changeNotification.title")}> -
- - 23 - - <p>{t("scm-review-plugin.changeNotification.description")}</p> -
- - 24 - - <p>{t("scm-review-plugin.changeNotification.modificationWarning")}</p> -
- 23 - - 25 - - <ToastButtons> -
- 24 - - - <ToastButton icon="redo" onClick={reload}>Reload</ToastButton> -
- 25 - - - <ToastButton icon="times" onClick={() => setEvent(undefined)}>Ignore</ToastButton> -
- - 26 - - <ToastButton icon="redo" onClick={reload}> -
- - 27 - - {t("scm-review-plugin.changeNotification.buttons.reload")} -
- - 28 - - </ToastButton> -
- - 29 - - <ToastButton icon="times" onClick={() => setEvent(undefined)}> -
- - 30 - - {t("scm-review-plugin.changeNotification.buttons.ignore")} -
- - 31 - - </ToastButton> -
- 26 - - 32 - - </ToastButtons> -
- 27 - - 33 - - </Toast> -
- 28 - - 34 - - ); -
-
+
+ import { Link } from "@scm-manager/ui-types"; +
+ 3 + + 3 + + import { apiClient, Toast, ToastButtons, ToastButton } from "@scm-manager/ui-components"; +
+ 4 + + 4 + + import { PullRequest } from "./types/PullRequest"; +
+ + 5 + + import { useTranslation } from "react-i18next"; +
+ 5 + + 6 + - - - - diff.expandLastBottomByLines - - +
+ 6 + + 7 + + type HandlerProps = { +
+ 7 + + 8 + + url: string; +
+
- + + + + diff.expandComplete + +
+
+
+ + + + diff.expandComplete + +
+
+ 15 + + 16 + + pullRequest: setEvent +
+ 16 + + 17 + + }); +
+ 17 + + 18 + + }, [url]); +
+ + 19 + + const { t } = useTranslation("plugins"); +
+ 18 + + 20 + + if (event) { +
+ 19 + + 21 + + return ( +
+ 20 + + + <Toast type="warning" title="New Changes"> +
+ 21 + + + <p>The underlying Pull-Request has changed. Press reload to see the changes.</p> +
+ 22 + + + <p>Warning: Non saved modification will be lost.</p> +
+ + 22 + + <Toast type="warning" title={t("scm-review-plugin.changeNotification.title")}> +
+ + 23 + + <p>{t("scm-review-plugin.changeNotification.description")}</p> +
+ + 24 + + <p>{t("scm-review-plugin.changeNotification.modificationWarning")}</p> +
+ 23 + + 25 + + <ToastButtons> +
+ 24 + + + <ToastButton icon="redo" onClick={reload}>Reload</ToastButton> +
+ 25 + + + <ToastButton icon="times" onClick={() => setEvent(undefined)}>Ignore</ToastButton> +
+ + 26 + + <ToastButton icon="redo" onClick={reload}> +
+ + 27 + + {t("scm-review-plugin.changeNotification.buttons.reload")} +
+ + 28 + + </ToastButton> +
+ + 29 + + <ToastButton icon="times" onClick={() => setEvent(undefined)}> +
+ + 30 + + {t("scm-review-plugin.changeNotification.buttons.ignore")} +
+ + 31 + + </ToastButton> +
+ 26 + + 32 + + </ToastButtons> +
+ 27 + + 33 + + </Toast> +
+ 28 + + 34 + + ); +
+
+ + + + diff.expandLastBottomByLines + - diff.expandLastBottomComplete - -
-
+ + + + diff.expandLastBottomComplete + +
+ + + + + - -
- - - src/main/resources/locales/de/plugins.json - - - modify - -
-
+ + + src/main/resources/locales/de/plugins.json + + + modify + +
+
- - - - - + + + + +
-
-
- - - - - - - - - + + + + + + - - - - + + + diff.expandComplete + + + + + + - - + + + + - 181 - - - - - - - + + + + + + + - - - + - 183 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
+
- - + + + + diff.expandByLines + - diff.expandByLines - - - - - - diff.expandComplete - - -
- 181 - + 181 + + 181 + + "titleClickable": "Der Kommentar bezieht sich auf eine ältere Version des Source- oder Target-Branches. Klicken Sie hier, um den ursprünglichen Kontext zu sehen." +
- "titleClickable": "Der Kommentar bezieht sich auf eine ältere Version des Source- oder Target-Branches. Klicken Sie hier, um den ursprünglichen Kontext zu sehen." -
- 182 - - 182 - + 182 + + 182 + + } +
+ 183 + + 183 + } -
+
- 183 - - } -
- - 184 - - }, -
- - 185 - - "changeNotification": { -
- - 186 - - "title": "Neue Änderungen", -
- - 187 - - "description": "An diesem Pull Request wurden Änderungen vorgenommen. Laden Sie die Seite neu um diese anzuzeigen.", -
- - 188 - - "modificationWarning": "Warnung: Nicht gespeicherte Eingaben gehen verloren.", -
- - 189 - - "buttons": { -
- - 190 - - "reload": "Neu laden", -
- - 191 - - "ignore": "Ignorieren" -
- - 192 - - } -
- 184 - - 193 - - } -
- 185 - - 194 - - }, -
- 186 - - 195 - - "permissions": { -
-
+
- - - - diff.expandLastBottomByLines - - - - - - diff.expandLastBottomComplete - - -
-
- -
-
-
-
- - - src/main/resources/locales/en/plugins.json - - - modify - -
-
-
-
- + - - - - -
-
-
-
-
-
- - - - - - - - - + -
+
- - - - - + + - 181 - - + + + - 181 - - + + + - "titleClickable": "The comment is related to an older of the source or target branch. Click here to see the original context." - - - - + + + - 182 - - + + + - 182 - - + + + + + + + + + - - - + - 183 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - -
+
- - - - diff.expandByLines - - - - - - diff.expandComplete - - -
+ + "changeNotification": { +
+ + 186 + + "title": "Neue Änderungen", +
+ + 187 + + "description": "An diesem Pull Request wurden Änderungen vorgenommen. Laden Sie die Seite neu um diese anzuzeigen.", +
+ + 188 + + "modificationWarning": "Warnung: Nicht gespeicherte Eingaben gehen verloren.", +
+ + 189 + + "buttons": { +
+ + 190 + + "reload": "Neu laden", +
+ + 191 + + "ignore": "Ignorieren" +
+ + 192 + } -
+
- 183 - - } -
- - 184 - - }, -
- - 185 - - "changeNotification": { -
- - 186 - - "title": "New Changes", -
- - 187 - - "description": "The underlying Pull-Request has changed. Press reload to see the changes.", -
- - 188 - - "modificationWarning": "Warning: Non saved modification will be lost.", -
- - 189 - - "buttons": { -
- - 190 - - "reload": "Reload", -
- - 191 - - "ignore": "Ignore" -
- - 192 - - } -
- 184 - - 193 - - } -
- 185 - - 194 - - }, -
- 186 - - 195 - - "permissions": { -
-
- +
+ 193 + + } +
+ 185 + + 194 + + }, +
+ 186 + + 195 + + "permissions": { +
+
- + + + + diff.expandLastBottomByLines + - diff.expandLastBottomByLines - - - - - - diff.expandLastBottomComplete - -
-
+ + + + diff.expandLastBottomComplete + +
+ + + + +
- -
- - - src/test/java/com/cloudogu/scm/review/events/ClientTest.java - - - modify - -
-
+ + + src/main/resources/locales/en/plugins.json + + + modify + +
+
- - - - - + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + diff.expandByLines + + + + + + diff.expandComplete + +
+
+ 181 + + 181 + + "titleClickable": "The comment is related to an older of the source or target branch. Click here to see the original context." +
+ 182 + + 182 + + } +
+ 183 + + 183 + + } +
+ + 184 + + }, +
+ + 185 + + "changeNotification": { +
+ + 186 + + "title": "New Changes", +
+ + 187 + + "description": "The underlying Pull-Request has changed. Press reload to see the changes.", +
+ + 188 + + "modificationWarning": "Warning: Non saved modification will be lost.", +
+ + 189 + + "buttons": { +
+ + 190 + + "reload": "Reload", +
+ + 191 + + "ignore": "Ignore" +
+ + 192 + + } +
+ 184 + + 193 + + } +
+ 185 + + 194 + + }, +
+ 186 + + 195 + + "permissions": { +
+
+ + + + diff.expandLastBottomByLines + + + + + + diff.expandLastBottomComplete + +
+
+
- - - - - - - - - - - - + + + +
+
+ + + src/test/java/com/cloudogu/scm/review/events/ClientTest.java + + + modify + + +
+
- - - diff.expandComplete + + +
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - + -
+ 10 + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + diff.expandComplete + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
- 7 - - 7 - - import org.mockito.Mock; -
- 8 - - 8 - - import org.mockito.junit.jupiter.MockitoExtension; -
- 9 - - 9 - - import sonia.scm.security.SessionId; -
+
- 10 - - -
- 10 - - 11 - - import javax.ws.rs.sse.OutboundSseEvent; -
- 11 - - 12 - - import javax.ws.rs.sse.SseEventSink; -
- 12 - - - -
- 13 - - 13 - - import java.time.Clock; -
- 14 - - 14 - - import java.time.Instant; -
- 15 - - 15 - - import java.time.LocalDateTime; -
- 16 - - 16 - - import java.time.ZoneOffset; -
- 17 - - 17 - - import java.time.temporal.ChronoField; -
- 18 - - - import java.time.temporal.ChronoUnit; -
- 19 - - - import java.time.temporal.TemporalField; -
- 20 - - 18 - - import java.util.concurrent.CompletableFuture; -
- 21 - - 19 - - import java.util.concurrent.CompletionStage; -
- 22 - - - import java.util.concurrent.atomic.AtomicLong; -
- 23 - - 20 - - import java.util.concurrent.atomic.AtomicReference; -
- 24 - - 21 - - -
- 25 - - 22 - - import static java.time.temporal.ChronoUnit.MINUTES; -
-
+
- - - - diff.expandByLines - + + + + diff.expandComplete + + +
+ 7 + + 7 + + import org.mockito.Mock; +
+ 8 + + 8 + + import org.mockito.junit.jupiter.MockitoExtension; +
+ 9 + + 9 + + import sonia.scm.security.SessionId; +
+ + 10 + - - - - diff.expandComplete - - -
+
+ 11 + + import javax.ws.rs.sse.OutboundSseEvent; +
+ 11 + + 12 + + import javax.ws.rs.sse.SseEventSink; +
+ 12 + + - - - - diff.expandByLines - - +
+ 13 + + 13 + + import java.time.Clock; +
+ 14 + + 14 + + import java.time.Instant; +
+ 15 + + 15 + + import java.time.LocalDateTime; +
+ 16 + + 16 + + import java.time.ZoneOffset; +
+ 17 + + 17 + + import java.time.temporal.ChronoField; +
+ 18 + + + import java.time.temporal.ChronoUnit; +
+ 19 + + + import java.time.temporal.TemporalField; +
+ 20 + + 18 + + import java.util.concurrent.CompletableFuture; +
+ 21 + + 19 + + import java.util.concurrent.CompletionStage; +
+ 22 + + + import java.util.concurrent.atomic.AtomicLong; +
+ 23 + + 20 + + import java.util.concurrent.atomic.AtomicReference; +
+ 24 + + 21 + + +
+ 25 + + 22 + + import static java.time.temporal.ChronoUnit.MINUTES; +
+
- + + + + diff.expandByLines + - diff.expandComplete - -
-
+
+ + + + diff.expandByLines + + + + + + diff.expandComplete + +
+
+ 83 + + 80 + + +
+ 84 + + 81 + + @Test +
+ 85 + + 82 + + @SuppressWarnings("unchecked") +
+ 86 + + + void shouldCloseEventSinkOnFailure() throws InterruptedException { +
+ + 83 + + void shouldCloseEventSinkOnFailure() { +
+ 87 + + 84 + + CompletionStage future = CompletableFuture.supplyAsync(() -> { +
+ 88 + + 85 + + throw new RuntimeException("failed to send message"); +
+ 89 + + 86 + + }); +
+
+ + + + diff.expandComplete + +
+
+
+ + + + diff.expandComplete + +
+
+ 91 + + 88 + + +
+ 92 + + 89 + + client.send(message); +
+ 93 + + 90 + + +
+ 94 + + + Thread.sleep(50L); +
+ 95 + + + +
+ 96 + + + verify(eventSink).close(); +
+ + 91 + + verify(eventSink, timeout(50L)).close(); +
+ 97 + + 92 + + } +
+ 98 + + 93 + + +
+ 99 + + 94 + + @Test +
+
+ + + + diff.expandLastBottomByLines + + + + + + diff.expandLastBottomComplete + +
+
+
+ +
+
+
- - - 83 - - - 80 - - - - - - - - 84 - - - 81 - - - @Test - - - - - 85 - - - 82 - - - @SuppressWarnings("unchecked") - - - - - 86 - - - - void shouldCloseEventSinkOnFailure() throws InterruptedException { - - - + + modify + +
+
- - - 83 - - - void shouldCloseEventSinkOnFailure() { - - - - - 87 - - - 84 - - - CompletionStage future = CompletableFuture.supplyAsync(() -> { - - - - - 88 - - - 85 - - - throw new RuntimeException("failed to send message"); - - - - - 89 - - - 86 - - - }); - - - - - -
- - - diff.expandComplete + + +
- - - - +
+
+
+
+ - - + + + + + + -
+
- - - - - + + - 91 - - + + + + - 88 - - + + + + - - - - - + + + + - 92 - - + + + - 89 - - + + + - client.send(message); - - - - + + + + - 93 - - + + + - 90 - - + + + + - - - - - + + + + - 94 - - + + + + - Thread.sleep(50L); - - - - + + + - 95 - - + + + - - - - - + + + - 96 - - + + + - verify(eventSink).close(); - - - - + + + - 91 - - - - - - - + + + + + + + - - + + + - - - - - - - - - - - - - - - -
+
- - - - diff.expandComplete - - -
+ + import java.io.PrintStream; +
+ 1 + + 2 + + import java.util.Arrays; +
+ 2 + + 3 + + +
+ 3 + + 4 + + class Main { +
+ + 5 + + private static final PrintStream OUT = System.out; +
+ + 6 + + +
+ 4 + + 7 + + public static void main(String[] args) { +
+ + 8 + + <<<<<<< HEAD +
+ 5 + + 9 + + System.out.println("Expect nothing more to happen."); +
+ 6 + + 10 + + System.out.println("The command line parameters are:"); +
- + 7 + + 11 + + Arrays.stream(args).map(arg -> "- " + arg).forEach(System.out::println); +
+ + 12 + + ======= +
- + + 13 + + OUT.println("Expect nothing more to happen."); +
+ + 14 + + OUT.println("Parameters:"); +
- + + 15 + + Arrays.stream(args).map(arg -> "- " + arg).forEach(OUT::println); +
- + + 16 + + >>>>>>> feature/use_constant +
- verify(eventSink, timeout(50L)).close(); -
- 97 - - 92 - + 8 + + 17 + + } +
+ 9 + + 18 + } -
- 98 - - 93 - - -
- 99 - - 94 - - @Test -
-
+
- - + + + + diff.expandLastBottomByLines + - diff.expandLastBottomByLines - - - - - - diff.expandLastBottomComplete - - -
-
- -
-
-
-
- - - Main.java - - - modify - -
-
-
-
- - - - - -
-
-
+ + + + diff.expandLastBottomComplete + +
+ + + +
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - 1 - - import java.io.PrintStream; -
- 1 - - 2 - - import java.util.Arrays; -
- 2 - - 3 - - -
- 3 - - 4 - - class Main { -
- - 5 - - private static final PrintStream OUT = System.out; -
- - 6 - - -
- 4 - - 7 - - public static void main(String[] args) { -
- - 8 - - <<<<<<< HEAD -
- 5 - - 9 - - System.out.println("Expect nothing more to happen."); -
- 6 - - 10 - - System.out.println("The command line parameters are:"); -
- 7 - - 11 - - Arrays.stream(args).map(arg -> "- " + arg).forEach(System.out::println); -
- - 12 - - ======= -
- - 13 - - OUT.println("Expect nothing more to happen."); -
- - 14 - - OUT.println("Parameters:"); -
- - 15 - - Arrays.stream(args).map(arg -> "- " + arg).forEach(OUT::println); -
- - 16 - - >>>>>>> feature/use_constant -
- 8 - - 17 - - } -
- 9 - - 18 - - } -
-
- - - - diff.expandLastBottomByLines - - - - - - diff.expandLastBottomComplete - -
-
-
`; @@ -14769,3858 +14805,3866 @@ exports[`Storyshots Diff File Annotation 1`] = `
-
+
- - - src/main/java/com/cloudogu/scm/review/events/EventListener.java - - - modify - -
-
+ + + src/main/java/com/cloudogu/scm/review/events/EventListener.java + + + modify + +
+
- - - - - + + + + +
-
-
-

- Custom File annotation for - src/main/java/com/cloudogu/scm/review/events/EventListener.java -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- 1 - - 1 - - package com.cloudogu.scm.review.events; -
- 2 - - 2 - - -
- 3 - - - import com.cloudogu.scm.review.comment.service.BasicComment; -
- 4 - - - import com.cloudogu.scm.review.comment.service.BasicCommentEvent; -
- 5 - - - import com.cloudogu.scm.review.comment.service.CommentEvent; -
- 6 - - - import com.cloudogu.scm.review.comment.service.ReplyEvent; -
- 7 - - 3 - - import com.cloudogu.scm.review.pullrequest.service.BasicPullRequestEvent; -
- 8 - - 4 - - import com.cloudogu.scm.review.pullrequest.service.PullRequest; -
- 9 - - - import com.cloudogu.scm.review.pullrequest.service.PullRequestEvent; -
- 10 - - 5 - - import com.github.legman.Subscribe; -
- 11 - - - import lombok.Data; -
- 12 - - 6 - - import org.apache.shiro.SecurityUtils; -
- 13 - - 7 - - import org.apache.shiro.subject.PrincipalCollection; -
- 14 - - 8 - - import org.apache.shiro.subject.Subject; -
- 15 - - 9 - - import sonia.scm.EagerSingleton; -
- 16 - - - import sonia.scm.HandlerEventType; -
- 17 - - - import sonia.scm.event.HandlerEvent; -
- 18 - - 10 - - import sonia.scm.plugin.Extension; -
- 19 - - 11 - - import sonia.scm.repository.Repository; -
- 20 - - 12 - - import sonia.scm.security.SessionId; -
-
-
-
-
-
+ Custom File annotation for + src/main/java/com/cloudogu/scm/review/events/EventListener.java +

+ - - - src/main/js/ChangeNotification.tsx - - - modify - - -
-
-
- - - - - -
-
-
- - -
-

- Custom File annotation for - src/main/js/ChangeNotification.tsx -

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - + + + + - 6 - - + + + + - - - - - - - - - - - - - - - - - + - - - - - + + - 15 - - + + + - 16 - - + + + - pullRequest: setEvent - - - - + + + - 16 - - + + + + - 17 - - + + + + - }); - - - - + + + - 17 - - + + + + - 18 - - + + + - }, [url]); - - - - + + + + - 19 - - + + + + - const { t } = useTranslation("plugins"); - - - - + + + + - 18 - - + + + + - 20 - - + + + - if (event) { - - - - + + + - 19 - - + + + + - 21 - - + + + + - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- 2 - - 2 - - import { Link } from "@scm-manager/ui-types"; -
- 3 - - 3 - - import { apiClient, Toast, ToastButtons, ToastButton } from "@scm-manager/ui-components"; -
- 4 - - 4 - - import { PullRequest } from "./types/PullRequest"; -
+
- 5 - - import { useTranslation } from "react-i18next"; -
- 5 - + 1 + + 1 + + package com.cloudogu.scm.review.events; +
+ 2 + + 2 + + +
- 6 - - 7 - - type HandlerProps = { -
- 7 - - 8 - - url: string; -
-
+ 3 +
-
+ import com.cloudogu.scm.review.comment.service.BasicComment; +
+ 4 + + + import com.cloudogu.scm.review.comment.service.BasicCommentEvent; +
+ 5 + + + import com.cloudogu.scm.review.comment.service.CommentEvent; +
+ 6 + + + import com.cloudogu.scm.review.comment.service.ReplyEvent; +
+ 7 + + 3 + + import com.cloudogu.scm.review.pullrequest.service.BasicPullRequestEvent; +
+ 8 + + 4 + + import com.cloudogu.scm.review.pullrequest.service.PullRequest; +
+ 9 + + + import com.cloudogu.scm.review.pullrequest.service.PullRequestEvent; +
+ 10 + + 5 + + import com.github.legman.Subscribe; +
+ 11 + + + import lombok.Data; +
- + 12 + + 6 + + import org.apache.shiro.SecurityUtils; +
+ 13 + + 7 + + import org.apache.shiro.subject.PrincipalCollection; +
+ 14 + + 8 + + import org.apache.shiro.subject.Subject; +
+ 15 + + 9 + + import sonia.scm.EagerSingleton; +
+ 16 + + + import sonia.scm.HandlerEventType; +
+ 17 + + + import sonia.scm.event.HandlerEvent; +
+ 18 + + 10 + + import sonia.scm.plugin.Extension; +
+ 19 + + 11 + + import sonia.scm.repository.Repository; +
- 20 - - - <Toast type="warning" title="New Changes"> -
- 21 - - - <p>The underlying Pull-Request has changed. Press reload to see the changes.</p> -
- 22 - - - <p>Warning: Non saved modification will be lost.</p> -
- - 22 - - <Toast type="warning" title={t("scm-review-plugin.changeNotification.title")}> -
- - 23 - - <p>{t("scm-review-plugin.changeNotification.description")}</p> -
- - 24 - - <p>{t("scm-review-plugin.changeNotification.modificationWarning")}</p> -
- 23 - - 25 - - <ToastButtons> -
- 24 - - - <ToastButton icon="redo" onClick={reload}>Reload</ToastButton> -
- 25 - - - <ToastButton icon="times" onClick={() => setEvent(undefined)}>Ignore</ToastButton> -
- - 26 - - <ToastButton icon="redo" onClick={reload}> -
- - 27 - - {t("scm-review-plugin.changeNotification.buttons.reload")} -
- - 28 - - </ToastButton> -
- - 29 - - <ToastButton icon="times" onClick={() => setEvent(undefined)}> -
- - 30 - - {t("scm-review-plugin.changeNotification.buttons.ignore")} -
- - 31 - - </ToastButton> -
- 26 - - 32 - - </ToastButtons> -
- 27 - - 33 - - </Toast> -
- 28 - - 34 - - ); -
+ + 20 + + + 12 + + + import sonia.scm.security.SessionId; + + + + +
-
-
- - - src/main/resources/locales/de/plugins.json - - - modify - -
-
+ + + src/main/js/ChangeNotification.tsx + + + modify + +
+
- - - - - + + + + +
+
+

+ Custom File annotation for + src/main/js/ChangeNotification.tsx +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 2 + + 2 + + import { Link } from "@scm-manager/ui-types"; +
+ 3 + + 3 + + import { apiClient, Toast, ToastButtons, ToastButton } from "@scm-manager/ui-components"; +
+ 4 + + 4 + + import { PullRequest } from "./types/PullRequest"; +
+ + 5 + + import { useTranslation } from "react-i18next"; +
+ 5 + + 6 + + +
+ 6 + + 7 + + type HandlerProps = { +
+ 7 + + 8 + + url: string; +
+
+
+ 15 + + 16 + + pullRequest: setEvent +
+ 16 + + 17 + + }); +
+ 17 + + 18 + + }, [url]); +
+ + 19 + + const { t } = useTranslation("plugins"); +
+ 18 + + 20 + + if (event) { +
+ 19 + + 21 + + return ( +
+ 20 + + + <Toast type="warning" title="New Changes"> +
+ 21 + + + <p>The underlying Pull-Request has changed. Press reload to see the changes.</p> +
+ 22 + + + <p>Warning: Non saved modification will be lost.</p> +
+ + 22 + + <Toast type="warning" title={t("scm-review-plugin.changeNotification.title")}> +
+ + 23 + + <p>{t("scm-review-plugin.changeNotification.description")}</p> +
+ + 24 + + <p>{t("scm-review-plugin.changeNotification.modificationWarning")}</p> +
+ 23 + + 25 + + <ToastButtons> +
+ 24 + + + <ToastButton icon="redo" onClick={reload}>Reload</ToastButton> +
+ 25 + + + <ToastButton icon="times" onClick={() => setEvent(undefined)}>Ignore</ToastButton> +
+ + 26 + + <ToastButton icon="redo" onClick={reload}> +
+ + 27 + + {t("scm-review-plugin.changeNotification.buttons.reload")} +
+ + 28 + + </ToastButton> +
+ + 29 + + <ToastButton icon="times" onClick={() => setEvent(undefined)}> +
+ + 30 + + {t("scm-review-plugin.changeNotification.buttons.ignore")} +
+ + 31 + + </ToastButton> +
+ 26 + + 32 + + </ToastButtons> +
+ 27 + + 33 + + </Toast> +
+ 28 + + 34 + + ); +
+
-

- Custom File annotation for - src/main/resources/locales/de/plugins.json -

- - - - - - - - - - - - - + +
-
- + + + + +
+ - 181 - + - 181 - - "titleClickable": "Der Kommentar bezieht sich auf eine ältere Version des Source- oder Target-Branches. Klicken Sie hier, um den ursprünglichen Kontext zu sehen." -
- 182 - + + + + + + + + + + +
+

+ Custom File annotation for + src/main/resources/locales/de/plugins.json +

+ + + + + + + + - 182 - - + + + + + + + + + + + + - - - + - 183 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ 181 + + 181 + + "titleClickable": "Der Kommentar bezieht sich auf eine ältere Version des Source- oder Target-Branches. Klicken Sie hier, um den ursprünglichen Kontext zu sehen." +
+ 182 + + 182 + + } +
+ 183 + + 183 + } -
+
- 183 - - } -
- - 184 - - }, -
- - 185 - - "changeNotification": { -
- - 186 - - "title": "Neue Änderungen", -
- - 187 - - "description": "An diesem Pull Request wurden Änderungen vorgenommen. Laden Sie die Seite neu um diese anzuzeigen.", -
- - 188 - - "modificationWarning": "Warnung: Nicht gespeicherte Eingaben gehen verloren.", -
- - 189 - - "buttons": { -
- - 190 - - "reload": "Neu laden", -
- - 191 - - "ignore": "Ignorieren" -
- - 192 - - } -
- 184 - - 193 - - } -
- 185 - - 194 - - }, -
- 186 - - 195 - - "permissions": { -
-
- -
-
-
-
- - - src/main/resources/locales/en/plugins.json - - - modify - -
-
-
-
- +
- - - - - - - - - -
-

- Custom File annotation for - src/main/resources/locales/en/plugins.json -

- - - - - - - - - + + - 181 - - + + + - 181 - - + + + - "titleClickable": "The comment is related to an older of the source or target branch. Click here to see the original context." - - - - + + + - 182 - - + + + - 182 - - + + + + + + + + + + + + + - - - - - + + + + - - - - + + + + - - - + - 185 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ + }, +
+ + 185 + + "changeNotification": { +
+ + 186 + + "title": "Neue Änderungen", +
+ + 187 + + "description": "An diesem Pull Request wurden Änderungen vorgenommen. Laden Sie die Seite neu um diese anzuzeigen.", +
+ + 188 + + "modificationWarning": "Warnung: Nicht gespeicherte Eingaben gehen verloren.", +
+ + 189 + + "buttons": { +
+ + 190 + + "reload": "Neu laden", +
+ + 191 + + "ignore": "Ignorieren" +
+ + 192 + } -
- 183 - - 183 - +
+ 184 + + 193 + } -
- - 184 - +
+ 185 + + 194 + }, -
- +
- "changeNotification": { -
- - 186 - - "title": "New Changes", -
- - 187 - - "description": "The underlying Pull-Request has changed. Press reload to see the changes.", -
- - 188 - - "modificationWarning": "Warning: Non saved modification will be lost.", -
- - 189 - - "buttons": { -
- - 190 - - "reload": "Reload", -
- - 191 - - "ignore": "Ignore" -
- - 192 - - } -
- 184 - - 193 - - } -
- 185 - - 194 - - }, -
- 186 - - 195 - - "permissions": { -
+
+ 186 + + 195 + + "permissions": { +
+
-
-
- - - src/test/java/com/cloudogu/scm/review/events/ClientTest.java - - - modify - -
-
+ + + src/main/resources/locales/en/plugins.json + + + modify + +
+
- - - - - + + + + +
+
+

+ Custom File annotation for + src/main/resources/locales/en/plugins.json +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 181 + + 181 + + "titleClickable": "The comment is related to an older of the source or target branch. Click here to see the original context." +
+ 182 + + 182 + + } +
+ 183 + + 183 + + } +
+ + 184 + + }, +
+ + 185 + + "changeNotification": { +
+ + 186 + + "title": "New Changes", +
+ + 187 + + "description": "The underlying Pull-Request has changed. Press reload to see the changes.", +
+ + 188 + + "modificationWarning": "Warning: Non saved modification will be lost.", +
+ + 189 + + "buttons": { +
+ + 190 + + "reload": "Reload", +
+ + 191 + + "ignore": "Ignore" +
+ + 192 + + } +
+ 184 + + 193 + + } +
+ 185 + + 194 + + }, +
+ 186 + + 195 + + "permissions": { +
+
-

- Custom File annotation for - src/test/java/com/cloudogu/scm/review/events/ClientTest.java -

- - - - - - - - - - - - - - - - - - - - - - - - - - - + +
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + +
+

+ Custom File annotation for + src/test/java/com/cloudogu/scm/review/events/ClientTest.java +

+
- 7 - - 7 - - import org.mockito.Mock; -
- 8 - - 8 - - import org.mockito.junit.jupiter.MockitoExtension; -
- 9 - - 9 - - import sonia.scm.security.SessionId; -
- - 10 - + - -
- 10 - - 11 - - import javax.ws.rs.sse.OutboundSseEvent; -
- 11 - - 12 - - import javax.ws.rs.sse.SseEventSink; -
- 12 - - - -
- 13 - - 13 - - import java.time.Clock; -
- 14 - - 14 - - import java.time.Instant; -
- 15 - - 15 - - import java.time.LocalDateTime; -
- 16 - - 16 - - import java.time.ZoneOffset; -
- 17 - - 17 - - import java.time.temporal.ChronoField; -
- 18 - - - import java.time.temporal.ChronoUnit; -
- 19 - - - import java.time.temporal.TemporalField; -
- 20 - - 18 - - import java.util.concurrent.CompletableFuture; -
- 21 - - 19 - - import java.util.concurrent.CompletionStage; -
- 22 - - - import java.util.concurrent.atomic.AtomicLong; -
- 23 - - 20 - - import java.util.concurrent.atomic.AtomicReference; -
- 24 - - 21 - - -
- 25 - - 22 - - import static java.time.temporal.ChronoUnit.MINUTES; -
- - + + + + + -
+ 7 + +
+ + + + + + + + + + + + + + - - - - - + + + - 83 - - + + + + - 80 - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ 7 + + import org.mockito.Mock; +
+ 8 + + 8 + + import org.mockito.junit.jupiter.MockitoExtension; +
+ 9 + + 9 + + import sonia.scm.security.SessionId; +
-
+ 10 + + +
+ 10 + + 11 + + import javax.ws.rs.sse.OutboundSseEvent; +
+ 11 + + 12 + + import javax.ws.rs.sse.SseEventSink; +
- 84 - - 81 - - @Test -
- 85 - - 82 - - @SuppressWarnings("unchecked") -
- 86 - - - void shouldCloseEventSinkOnFailure() throws InterruptedException { -
- - 83 - - void shouldCloseEventSinkOnFailure() { -
- 87 - - 84 - - CompletionStage future = CompletableFuture.supplyAsync(() -> { -
- 88 - - 85 - - throw new RuntimeException("failed to send message"); -
- 89 - - 86 - - }); -
-
+ 12 +
-
+ 13 + + 13 + + import java.time.Clock; +
+ 14 + + 14 + + import java.time.Instant; +
+ 15 + + 15 + + import java.time.LocalDateTime; +
+ 16 + + 16 + + import java.time.ZoneOffset; +
+ 17 + + 17 + + import java.time.temporal.ChronoField; +
+ 18 + + + import java.time.temporal.ChronoUnit; +
+ 19 + + + import java.time.temporal.TemporalField; +
+ 20 + + 18 + + import java.util.concurrent.CompletableFuture; +
+ 21 + + 19 + + import java.util.concurrent.CompletionStage; +
+ 22 + + + import java.util.concurrent.atomic.AtomicLong; +
+ 23 + + 20 + + import java.util.concurrent.atomic.AtomicReference; +
+ 24 + + 21 + + +
+ 25 + + 22 + + import static java.time.temporal.ChronoUnit.MINUTES; +
+
+
+ 83 + + 80 + + +
+ 84 + + 81 + + @Test +
+ 85 + + 82 + + @SuppressWarnings("unchecked") +
+ 86 + + + void shouldCloseEventSinkOnFailure() throws InterruptedException { +
+ + 83 + + void shouldCloseEventSinkOnFailure() { +
+ 87 + + 84 + + CompletionStage future = CompletableFuture.supplyAsync(() -> { +
+ 88 + + 85 + + throw new RuntimeException("failed to send message"); +
+ 89 + + 86 + + }); +
+
+
+ 91 + + 88 + + +
+ 92 + + 89 + + client.send(message); +
+ 93 + + 90 + + +
+ 94 + + + Thread.sleep(50L); +
+ 95 + + + +
+ 96 + + + verify(eventSink).close(); +
+ + 91 + + verify(eventSink, timeout(50L)).close(); +
+ 97 + + 92 + + } +
+ 98 + + 93 + + +
+ 99 + + 94 + + @Test +
+
+ +
+
+
- - - 91 - - - 88 - - - - - - - - 92 - - - 89 - - - client.send(message); - - - - - 93 - - - 90 - - - - - - - - 94 - - - - Thread.sleep(50L); - - - + + modify + +
+
- - 95 - - + + + + + +
+
+
+ + +
+

+ Custom File annotation for + Main.java +

+ + + - - - - - - - + + - - + + + - verify(eventSink, timeout(50L)).close(); - - - - + + + + - 97 - - + + + + - 92 - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - -
- -
- 96 - - - verify(eventSink).close(); -
- - 91 - + + 1 + + import java.io.PrintStream; +
+ 1 + + 2 + + import java.util.Arrays; +
+ 2 + + 3 + + +
+ 3 + + 4 + + class Main { +
+ + 5 + + private static final PrintStream OUT = System.out; +
+ + 6 + + +
+ 4 + + 7 + + public static void main(String[] args) { +
+ + 8 + + <<<<<<< HEAD +
+ 5 + + 9 + + System.out.println("Expect nothing more to happen."); +
+ 6 + + 10 + + System.out.println("The command line parameters are:"); +
+ 7 + + 11 + + Arrays.stream(args).map(arg -> "- " + arg).forEach(System.out::println); +
+ + 12 + + ======= +
+ + 13 + + OUT.println("Expect nothing more to happen."); +
+ + 14 + + OUT.println("Parameters:"); +
+ + 15 + + Arrays.stream(args).map(arg -> "- " + arg).forEach(OUT::println); +
+ + 16 + + >>>>>>> feature/use_constant +
+ 8 + + 17 + + } +
+ 9 + + 18 + } -
- 98 - - 93 - - -
- 99 - - 94 - - @Test -
-
- -
-
-
-
- - - Main.java - - - modify - -
-
-
-
- - - - - -
-
-
+ + + +
-
-

- Custom File annotation for - Main.java -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - 1 - - import java.io.PrintStream; -
- 1 - - 2 - - import java.util.Arrays; -
- 2 - - 3 - - -
- 3 - - 4 - - class Main { -
- - 5 - - private static final PrintStream OUT = System.out; -
- - 6 - - -
- 4 - - 7 - - public static void main(String[] args) { -
- - 8 - - <<<<<<< HEAD -
- 5 - - 9 - - System.out.println("Expect nothing more to happen."); -
- 6 - - 10 - - System.out.println("The command line parameters are:"); -
- 7 - - 11 - - Arrays.stream(args).map(arg -> "- " + arg).forEach(System.out::println); -
- - 12 - - ======= -
- - 13 - - OUT.println("Expect nothing more to happen."); -
- - 14 - - OUT.println("Parameters:"); -
- - 15 - - Arrays.stream(args).map(arg -> "- " + arg).forEach(OUT::println); -
- - 16 - - >>>>>>> feature/use_constant -
- 8 - - 17 - - } -
- 9 - - 18 - - } -
-
`; @@ -18629,3942 +18673,3950 @@ exports[`Storyshots Diff File Controls 1`] = `
-
+
- - - src/main/java/com/cloudogu/scm/review/events/EventListener.java - - - modify - -
-
+ + + src/main/java/com/cloudogu/scm/review/events/EventListener.java + + + modify + +
+
- - - - - -
-
- + + + +
+
- - - - + + + + +
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- 1 - - 1 - - package com.cloudogu.scm.review.events; -
- 2 - - 2 - - -
- 3 - - - import com.cloudogu.scm.review.comment.service.BasicComment; -
- 4 - - - import com.cloudogu.scm.review.comment.service.BasicCommentEvent; -
- 5 - - - import com.cloudogu.scm.review.comment.service.CommentEvent; -
- 6 - - - import com.cloudogu.scm.review.comment.service.ReplyEvent; -
- 7 - - 3 - - import com.cloudogu.scm.review.pullrequest.service.BasicPullRequestEvent; -
- 8 - - 4 - - import com.cloudogu.scm.review.pullrequest.service.PullRequest; -
- 9 - - - import com.cloudogu.scm.review.pullrequest.service.PullRequestEvent; -
- 10 - - 5 - - import com.github.legman.Subscribe; -
- 11 - - - import lombok.Data; -
- 12 - - 6 - - import org.apache.shiro.SecurityUtils; -
- 13 - - 7 - - import org.apache.shiro.subject.PrincipalCollection; -
- 14 - - 8 - - import org.apache.shiro.subject.Subject; -
- 15 - - 9 - - import sonia.scm.EagerSingleton; -
- 16 - - - import sonia.scm.HandlerEventType; -
- 17 - - - import sonia.scm.event.HandlerEvent; -
- 18 - - 10 - - import sonia.scm.plugin.Extension; -
- 19 - - 11 - - import sonia.scm.repository.Repository; -
- 20 - - 12 - - import sonia.scm.security.SessionId; -
-
-
-
-
-
- - - src/main/js/ChangeNotification.tsx - - - modify - -
-
-
-
- - - - - -
-
- - - - - -
-
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - + + + + - 6 - - + + + + - - - - - - - - - - - - - - - - - + - - - - - + + - 15 - - + + + - 16 - - + + + - pullRequest: setEvent - - - - + + + - 16 - - + + + + - 17 - - + + + + - }); - - - - + + + - 17 - - + + + + - 18 - - + + + - }, [url]); - - - - + + + + - 19 - - + + + + - const { t } = useTranslation("plugins"); - - - - + + + + - 18 - - + + + + - 20 - - + + + - if (event) { - - - - + + + - 19 - - + + + + - 21 - - + + + + - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- 2 - - 2 - - import { Link } from "@scm-manager/ui-types"; -
- 3 - - 3 - - import { apiClient, Toast, ToastButtons, ToastButton } from "@scm-manager/ui-components"; -
- 4 - - 4 - - import { PullRequest } from "./types/PullRequest"; -
+
- 5 - - import { useTranslation } from "react-i18next"; -
- 5 - + 1 + + 1 + + package com.cloudogu.scm.review.events; +
+ 2 + + 2 + + +
- 6 - - 7 - - type HandlerProps = { -
- 7 - - 8 - - url: string; -
-
+ 3 +
-
+ import com.cloudogu.scm.review.comment.service.BasicComment; +
+ 4 + + + import com.cloudogu.scm.review.comment.service.BasicCommentEvent; +
+ 5 + + + import com.cloudogu.scm.review.comment.service.CommentEvent; +
+ 6 + + + import com.cloudogu.scm.review.comment.service.ReplyEvent; +
+ 7 + + 3 + + import com.cloudogu.scm.review.pullrequest.service.BasicPullRequestEvent; +
+ 8 + + 4 + + import com.cloudogu.scm.review.pullrequest.service.PullRequest; +
+ 9 + + + import com.cloudogu.scm.review.pullrequest.service.PullRequestEvent; +
+ 10 + + 5 + + import com.github.legman.Subscribe; +
+ 11 + + + import lombok.Data; +
- + 12 + + 6 + + import org.apache.shiro.SecurityUtils; +
+ 13 + + 7 + + import org.apache.shiro.subject.PrincipalCollection; +
+ 14 + + 8 + + import org.apache.shiro.subject.Subject; +
+ 15 + + 9 + + import sonia.scm.EagerSingleton; +
+ 16 + + + import sonia.scm.HandlerEventType; +
+ 17 + + + import sonia.scm.event.HandlerEvent; +
+ 18 + + 10 + + import sonia.scm.plugin.Extension; +
+ 19 + + 11 + + import sonia.scm.repository.Repository; +
- 20 - - - <Toast type="warning" title="New Changes"> -
- 21 - - - <p>The underlying Pull-Request has changed. Press reload to see the changes.</p> -
- 22 - - - <p>Warning: Non saved modification will be lost.</p> -
- - 22 - - <Toast type="warning" title={t("scm-review-plugin.changeNotification.title")}> -
- - 23 - - <p>{t("scm-review-plugin.changeNotification.description")}</p> -
- - 24 - - <p>{t("scm-review-plugin.changeNotification.modificationWarning")}</p> -
- 23 - - 25 - - <ToastButtons> -
- 24 - - - <ToastButton icon="redo" onClick={reload}>Reload</ToastButton> -
- 25 - - - <ToastButton icon="times" onClick={() => setEvent(undefined)}>Ignore</ToastButton> -
- - 26 - - <ToastButton icon="redo" onClick={reload}> -
- - 27 - - {t("scm-review-plugin.changeNotification.buttons.reload")} -
- - 28 - - </ToastButton> -
- - 29 - - <ToastButton icon="times" onClick={() => setEvent(undefined)}> -
- - 30 - - {t("scm-review-plugin.changeNotification.buttons.ignore")} -
- - 31 - - </ToastButton> -
- 26 - - 32 - - </ToastButtons> -
- 27 - - 33 - - </Toast> -
- 28 - - 34 - - ); -
+ + 20 + + + 12 + + + import sonia.scm.security.SessionId; + + + + +
-
-
- - - src/main/resources/locales/de/plugins.json - - - modify - -
-
+ + + src/main/js/ChangeNotification.tsx + + + modify + +
+
- - - - - -
-
- + + + +
+
- - - - + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 2 + + 2 + + import { Link } from "@scm-manager/ui-types"; +
+ 3 + + 3 + + import { apiClient, Toast, ToastButtons, ToastButton } from "@scm-manager/ui-components"; +
+ 4 + + 4 + + import { PullRequest } from "./types/PullRequest"; +
+ + 5 + + import { useTranslation } from "react-i18next"; +
+ 5 + + 6 + + +
+ 6 + + 7 + + type HandlerProps = { +
+ 7 + + 8 + + url: string; +
+
+
+ 15 + + 16 + + pullRequest: setEvent +
+ 16 + + 17 + + }); +
+ 17 + + 18 + + }, [url]); +
+ + 19 + + const { t } = useTranslation("plugins"); +
+ 18 + + 20 + + if (event) { +
+ 19 + + 21 + + return ( +
+ 20 + + + <Toast type="warning" title="New Changes"> +
+ 21 + + + <p>The underlying Pull-Request has changed. Press reload to see the changes.</p> +
+ 22 + + + <p>Warning: Non saved modification will be lost.</p> +
+ + 22 + + <Toast type="warning" title={t("scm-review-plugin.changeNotification.title")}> +
+ + 23 + + <p>{t("scm-review-plugin.changeNotification.description")}</p> +
+ + 24 + + <p>{t("scm-review-plugin.changeNotification.modificationWarning")}</p> +
+ 23 + + 25 + + <ToastButtons> +
+ 24 + + + <ToastButton icon="redo" onClick={reload}>Reload</ToastButton> +
+ 25 + + + <ToastButton icon="times" onClick={() => setEvent(undefined)}>Ignore</ToastButton> +
+ + 26 + + <ToastButton icon="redo" onClick={reload}> +
+ + 27 + + {t("scm-review-plugin.changeNotification.buttons.reload")} +
+ + 28 + + </ToastButton> +
+ + 29 + + <ToastButton icon="times" onClick={() => setEvent(undefined)}> +
+ + 30 + + {t("scm-review-plugin.changeNotification.buttons.ignore")} +
+ + 31 + + </ToastButton> +
+ 26 + + 32 + + </ToastButtons> +
+ 27 + + 33 + + </Toast> +
+ 28 + + 34 + + ); +
+
- - - - - - - - - - - - - + +
-
- + + + + +
+ - 181 - + - 181 - - "titleClickable": "Der Kommentar bezieht sich auf eine ältere Version des Source- oder Target-Branches. Klicken Sie hier, um den ursprünglichen Kontext zu sehen." -
- 182 - + + + + + + +
+ + + + + +
+ + + + +
+ + + + + + + + - 182 - - + + + + + + + + + + + + - - - + - 183 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ 181 + + 181 + + "titleClickable": "Der Kommentar bezieht sich auf eine ältere Version des Source- oder Target-Branches. Klicken Sie hier, um den ursprünglichen Kontext zu sehen." +
+ 182 + + 182 + + } +
+ 183 + + 183 + } -
+
- 183 - - } -
- - 184 - - }, -
- - 185 - - "changeNotification": { -
- - 186 - - "title": "Neue Änderungen", -
- - 187 - - "description": "An diesem Pull Request wurden Änderungen vorgenommen. Laden Sie die Seite neu um diese anzuzeigen.", -
- - 188 - - "modificationWarning": "Warnung: Nicht gespeicherte Eingaben gehen verloren.", -
- - 189 - - "buttons": { -
- - 190 - - "reload": "Neu laden", -
- - 191 - - "ignore": "Ignorieren" -
- - 192 - - } -
- 184 - - 193 - - } -
- 185 - - 194 - - }, -
- 186 - - 195 - - "permissions": { -
-
- -
-
-
-
- - - src/main/resources/locales/en/plugins.json - - - modify - -
-
-
-
- +
- - - - - -
- +
- - - - - - - - - -
- - - - - - - - - + - 181 - - + + + - 181 - - + + + - "titleClickable": "The comment is related to an older of the source or target branch. Click here to see the original context." - - - - + + + - 182 - - + + + - 182 - - + + + + + + + + + + + + + - - - - - + + + + - - - - + + + + - - - + - 185 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ + 185 + + "changeNotification": { +
+ + 186 + + "title": "Neue Änderungen", +
+ + 187 + + "description": "An diesem Pull Request wurden Änderungen vorgenommen. Laden Sie die Seite neu um diese anzuzeigen.", +
+ + 188 + + "modificationWarning": "Warnung: Nicht gespeicherte Eingaben gehen verloren.", +
+ + 189 + + "buttons": { +
+ + 190 + + "reload": "Neu laden", +
+ + 191 + + "ignore": "Ignorieren" +
+ + 192 + } -
- 183 - - 183 - +
+ 184 + + 193 + } -
- - 184 - +
+ 185 + + 194 + }, -
- +
- "changeNotification": { -
- - 186 - - "title": "New Changes", -
- - 187 - - "description": "The underlying Pull-Request has changed. Press reload to see the changes.", -
- - 188 - - "modificationWarning": "Warning: Non saved modification will be lost.", -
- - 189 - - "buttons": { -
- - 190 - - "reload": "Reload", -
- - 191 - - "ignore": "Ignore" -
- - 192 - - } -
- 184 - - 193 - - } -
- 185 - - 194 - - }, -
- 186 - - 195 - - "permissions": { -
+
+ 186 + + 195 + + "permissions": { +
+
- -
- - - src/test/java/com/cloudogu/scm/review/events/ClientTest.java - - - modify - -
-
+ + + src/main/resources/locales/en/plugins.json + + + modify + +
+
- - - - - -
-
- + + + +
+
- - - - + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 181 + + 181 + + "titleClickable": "The comment is related to an older of the source or target branch. Click here to see the original context." +
+ 182 + + 182 + + } +
+ 183 + + 183 + + } +
+ + 184 + + }, +
+ + 185 + + "changeNotification": { +
+ + 186 + + "title": "New Changes", +
+ + 187 + + "description": "The underlying Pull-Request has changed. Press reload to see the changes.", +
+ + 188 + + "modificationWarning": "Warning: Non saved modification will be lost.", +
+ + 189 + + "buttons": { +
+ + 190 + + "reload": "Reload", +
+ + 191 + + "ignore": "Ignore" +
+ + 192 + + } +
+ 184 + + 193 + + } +
+ 185 + + 194 + + }, +
+ 186 + + 195 + + "permissions": { +
+
- - - - - - - - - - - - - - - - - - - - - - - - - - - + +
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + +
+ + + + + +
+ + + + +
+
- 7 - - 7 - - import org.mockito.Mock; -
- 8 - - 8 - - import org.mockito.junit.jupiter.MockitoExtension; -
- 9 - - 9 - - import sonia.scm.security.SessionId; -
- - 10 - + - -
- 10 - - 11 - - import javax.ws.rs.sse.OutboundSseEvent; -
- 11 - - 12 - - import javax.ws.rs.sse.SseEventSink; -
- 12 - - - -
- 13 - - 13 - - import java.time.Clock; -
- 14 - - 14 - - import java.time.Instant; -
- 15 - - 15 - - import java.time.LocalDateTime; -
- 16 - - 16 - - import java.time.ZoneOffset; -
- 17 - - 17 - - import java.time.temporal.ChronoField; -
- 18 - - - import java.time.temporal.ChronoUnit; -
- 19 - - - import java.time.temporal.TemporalField; -
- 20 - - 18 - - import java.util.concurrent.CompletableFuture; -
- 21 - - 19 - - import java.util.concurrent.CompletionStage; -
- 22 - - - import java.util.concurrent.atomic.AtomicLong; -
- 23 - - 20 - - import java.util.concurrent.atomic.AtomicReference; -
- 24 - - 21 - - -
- 25 - - 22 - - import static java.time.temporal.ChronoUnit.MINUTES; -
- - + + + + + -
+ 7 + +
+ + + + + + + + + + + + + + - - - - - + + + - 83 - - + + + + - 80 - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ 7 + + import org.mockito.Mock; +
+ 8 + + 8 + + import org.mockito.junit.jupiter.MockitoExtension; +
+ 9 + + 9 + + import sonia.scm.security.SessionId; +
-
+ 10 + + +
+ 10 + + 11 + + import javax.ws.rs.sse.OutboundSseEvent; +
+ 11 + + 12 + + import javax.ws.rs.sse.SseEventSink; +
- 84 - - 81 - - @Test -
- 85 - - 82 - - @SuppressWarnings("unchecked") -
- 86 - - - void shouldCloseEventSinkOnFailure() throws InterruptedException { -
- - 83 - - void shouldCloseEventSinkOnFailure() { -
- 87 - - 84 - - CompletionStage future = CompletableFuture.supplyAsync(() -> { -
- 88 - - 85 - - throw new RuntimeException("failed to send message"); -
- 89 - - 86 - - }); -
-
+ 12 +
-
+ 13 + + 13 + + import java.time.Clock; +
+ 14 + + 14 + + import java.time.Instant; +
+ 15 + + 15 + + import java.time.LocalDateTime; +
+ 16 + + 16 + + import java.time.ZoneOffset; +
+ 17 + + 17 + + import java.time.temporal.ChronoField; +
+ 18 + + + import java.time.temporal.ChronoUnit; +
+ 19 + + + import java.time.temporal.TemporalField; +
+ 20 + + 18 + + import java.util.concurrent.CompletableFuture; +
+ 21 + + 19 + + import java.util.concurrent.CompletionStage; +
+ 22 + + + import java.util.concurrent.atomic.AtomicLong; +
+ 23 + + 20 + + import java.util.concurrent.atomic.AtomicReference; +
+ 24 + + 21 + + +
+ 25 + + 22 + + import static java.time.temporal.ChronoUnit.MINUTES; +
+
+
+ 83 + + 80 + + +
+ 84 + + 81 + + @Test +
+ 85 + + 82 + + @SuppressWarnings("unchecked") +
+ 86 + + + void shouldCloseEventSinkOnFailure() throws InterruptedException { +
+ + 83 + + void shouldCloseEventSinkOnFailure() { +
+ 87 + + 84 + + CompletionStage future = CompletableFuture.supplyAsync(() -> { +
+ 88 + + 85 + + throw new RuntimeException("failed to send message"); +
+ 89 + + 86 + + }); +
+
+
+ 91 + + 88 + + +
+ 92 + + 89 + + client.send(message); +
+ 93 + + 90 + + +
+ 94 + + + Thread.sleep(50L); +
+ 95 + + + +
+ 96 + + + verify(eventSink).close(); +
+ + 91 + + verify(eventSink, timeout(50L)).close(); +
+ 97 + + 92 + + } +
+ 98 + + 93 + + +
+ 99 + + 94 + + @Test +
+
+ +
+
+
- - - 91 - - - 88 - - - - - - - - 92 - - - 89 - - - client.send(message); - - - - - 93 - - - 90 - - - - - - - - 94 - - - - Thread.sleep(50L); - - - + + modify + +
+
- - 95 - - + + + + + +
+
+ + + + + +
+
+
+ + +
+ + + - - - - - - - + + - - + + + - verify(eventSink, timeout(50L)).close(); - - - - + + + + - 97 - - + + + + - 92 - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - -
- -
- 96 - - - verify(eventSink).close(); -
- - 91 - + + 1 + + import java.io.PrintStream; +
+ 1 + + 2 + + import java.util.Arrays; +
+ 2 + + 3 + + +
+ 3 + + 4 + + class Main { +
+ + 5 + + private static final PrintStream OUT = System.out; +
+ + 6 + + +
+ 4 + + 7 + + public static void main(String[] args) { +
+ + 8 + + <<<<<<< HEAD +
+ 5 + + 9 + + System.out.println("Expect nothing more to happen."); +
+ 6 + + 10 + + System.out.println("The command line parameters are:"); +
+ 7 + + 11 + + Arrays.stream(args).map(arg -> "- " + arg).forEach(System.out::println); +
+ + 12 + + ======= +
+ + 13 + + OUT.println("Expect nothing more to happen."); +
+ + 14 + + OUT.println("Parameters:"); +
+ + 15 + + Arrays.stream(args).map(arg -> "- " + arg).forEach(OUT::println); +
+ + 16 + + >>>>>>> feature/use_constant +
+ 8 + + 17 + + } +
+ 9 + + 18 + } -
- 98 - - 93 - - -
- 99 - - 94 - - @Test -
-
- -
-
-
-
- - - Main.java - - - modify - -
-
-
-
- - - - - -
-
- - - - - -
-
-
+ + + +
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - 1 - - import java.io.PrintStream; -
- 1 - - 2 - - import java.util.Arrays; -
- 2 - - 3 - - -
- 3 - - 4 - - class Main { -
- - 5 - - private static final PrintStream OUT = System.out; -
- - 6 - - -
- 4 - - 7 - - public static void main(String[] args) { -
- - 8 - - <<<<<<< HEAD -
- 5 - - 9 - - System.out.println("Expect nothing more to happen."); -
- 6 - - 10 - - System.out.println("The command line parameters are:"); -
- 7 - - 11 - - Arrays.stream(args).map(arg -> "- " + arg).forEach(System.out::println); -
- - 12 - - ======= -
- - 13 - - OUT.println("Expect nothing more to happen."); -
- - 14 - - OUT.println("Parameters:"); -
- - 15 - - Arrays.stream(args).map(arg -> "- " + arg).forEach(OUT::println); -
- - 16 - - >>>>>>> feature/use_constant -
- 8 - - 17 - - } -
- 9 - - 18 - - } -
-
`; @@ -22573,822 +22625,825 @@ exports[`Storyshots Diff Hunks 1`] = `
-
+
- - - src/main/java/com/cloudogu/scm/review/pullrequest/service/DefaultPullRequestService.java - - - modify - -
-
+ + + src/main/java/com/cloudogu/scm/review/pullrequest/service/DefaultPullRequestService.java + + + modify + +
+
- - - - - + + + + +
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - + + + + - 30 - - + + + + - import static com.cloudogu.scm.review.pullrequest.service.PullRequestStatus.MERGED; - - - - + + + + - 29 - - - - - - - - - - - - - - - - - - + + + - 200 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + 29 + + + + + + + + + + + + + + + + + + + + - - - - - + + + + - - + + + + - 215 - - + + + + - .filter(recipient -> user.getId().equals(recipient)) - - - + 202 + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + - - + + + + - .ifPresent(pullRequest::removeApprover); - - - - + + + + - 215 - - + + + + - getStore(repository).update(pullRequest); - - - - + + + - 217 - - + + + - .ifPresent( - - - - + + + - 218 - - + + + - approval -> { - - - - + + + - 219 - - + + + - pullRequest.removeApprover(approval); - - - - + + + - 220 - - + + + - getStore(repository).update(pullRequest); - - - - + + + + - 221 - - + + + + - eventBus.post(new PullRequestApprovalEvent(repository, pullRequest, APPROVAL_REMOVED)); - - - - - - - - - - - - - - - - - - - - - - -
- 25 - - 25 - - import java.util.Set; -
- 26 - - 26 - - import java.util.stream.Collectors; -
- 27 - - 27 - - -
+
- 28 - - import static com.cloudogu.scm.review.pullrequest.service.PullRequestApprovalEvent.ApprovalCause.APPROVAL_REMOVED; -
- - 29 - - import static com.cloudogu.scm.review.pullrequest.service.PullRequestApprovalEvent.ApprovalCause.APPROVED; -
- 28 - + 25 + + 25 + + import java.util.Set; +
+ 26 + + 26 + + import java.util.stream.Collectors; +
+ 27 + + 27 + + +
- 31 - - import static com.cloudogu.scm.review.pullrequest.service.PullRequestStatus.OPEN; -
- 30 - - 32 - - import static com.cloudogu.scm.review.pullrequest.service.PullRequestStatus.REJECTED; -
-
-
+ 28 + + import static com.cloudogu.scm.review.pullrequest.service.PullRequestApprovalEvent.ApprovalCause.APPROVAL_REMOVED; +
- 202 - - PullRequest pullRequest = getPullRequestFromStore(repository, pullRequestId); -
- 201 - - 203 - - pullRequest.addApprover(user.getId()); -
- 202 - - 204 - - getStore(repository).update(pullRequest); -
- - 205 - - eventBus.post(new PullRequestApprovalEvent(repository, pullRequest, APPROVED)); -
- 203 - - 206 - - } -
- 204 - - 207 - - -
- 205 - - 208 - - @Override -
-
-
+ import static com.cloudogu.scm.review.pullrequest.service.PullRequestApprovalEvent.ApprovalCause.APPROVED; +
+ 28 + + 30 + + import static com.cloudogu.scm.review.pullrequest.service.PullRequestStatus.MERGED; +
+ 29 + + 31 + + import static com.cloudogu.scm.review.pullrequest.service.PullRequestStatus.OPEN; +
+ 30 + + 32 + + import static com.cloudogu.scm.review.pullrequest.service.PullRequestStatus.REJECTED; +
- 211 - - 214 - - approver.stream() -
+
+
- 212 - + 200 + + 202 + + PullRequest pullRequest = getPullRequestFromStore(repository, pullRequestId); +
+ 201 + + 203 + + pullRequest.addApprover(user.getId()); +
+ 204 + + getStore(repository).update(pullRequest); +
+ + 205 + + eventBus.post(new PullRequestApprovalEvent(repository, pullRequest, APPROVED)); +
+ 203 + + 206 + + } +
+ 204 + + 207 + + +
+ 205 + + 208 + + @Override +
- 213 - - 216 - - .findFirst() -
+
+
- 214 - - + 211 + + 214 + + approver.stream() +
+ 212 + + 215 + + .filter(recipient -> user.getId().equals(recipient)) +
- + 213 + + 216 + + .findFirst() +
- + 214 + + + .ifPresent(pullRequest::removeApprover); +
+ 215 + + + getStore(repository).update(pullRequest); +
- + + 217 + + .ifPresent( +
+ + 218 + + approval -> { +
- + + 219 + + pullRequest.removeApprover(approval); +
+ + 220 + + getStore(repository).update(pullRequest); +
- + + 221 + + eventBus.post(new PullRequestApprovalEvent(repository, pullRequest, APPROVAL_REMOVED)); +
+ + 222 + + }); +
- + 216 + + 223 + + } +
+ 217 + + 224 + + +
- - 222 - - }); -
- 216 - - 223 - - } -
- 217 - - 224 - - -
- 218 - - 225 - - @Override -
+ + 218 + + + 225 + + + @Override + + + + +
@@ -23398,3870 +23453,3878 @@ exports[`Storyshots Diff Line Annotation 1`] = `
-
+
- - - src/main/java/com/cloudogu/scm/review/events/EventListener.java - - - modify - -
-
+ + + src/main/java/com/cloudogu/scm/review/events/EventListener.java + + + modify + +
+
- - - - - + + + + +
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- 1 - - 1 - - package com.cloudogu.scm.review.events; -
- 2 - - 2 - - -
-

- Line Annotation -

-
- 3 - - - import com.cloudogu.scm.review.comment.service.BasicComment; -
- 4 - - - import com.cloudogu.scm.review.comment.service.BasicCommentEvent; -
- 5 - - - import com.cloudogu.scm.review.comment.service.CommentEvent; -
- 6 - - - import com.cloudogu.scm.review.comment.service.ReplyEvent; -
- 7 - - 3 - - import com.cloudogu.scm.review.pullrequest.service.BasicPullRequestEvent; -
- 8 - - 4 - - import com.cloudogu.scm.review.pullrequest.service.PullRequest; -
- 9 - - - import com.cloudogu.scm.review.pullrequest.service.PullRequestEvent; -
- 10 - - 5 - - import com.github.legman.Subscribe; -
- 11 - - - import lombok.Data; -
- 12 - - 6 - - import org.apache.shiro.SecurityUtils; -
- 13 - - 7 - - import org.apache.shiro.subject.PrincipalCollection; -
- 14 - - 8 - - import org.apache.shiro.subject.Subject; -
- 15 - - 9 - - import sonia.scm.EagerSingleton; -
- 16 - - - import sonia.scm.HandlerEventType; -
- 17 - - - import sonia.scm.event.HandlerEvent; -
- 18 - - 10 - - import sonia.scm.plugin.Extension; -
- 19 - - 11 - - import sonia.scm.repository.Repository; -
- 20 - - 12 - - import sonia.scm.security.SessionId; -
-
-
-
-
-
- - - src/main/js/ChangeNotification.tsx - - - modify - -
-
-
-
- - - - - -
-
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - + + + + - 6 - - + + + + - - - - - + + - 6 - - - - - - - - - - - - - + - - - - - + + - 15 - - + + + - 16 - - + + + - pullRequest: setEvent - - - - + + + - 16 - - + + + + - 17 - - + + + + - }); - - - - + + + - 17 - - + + + + - 18 - - + + + - }, [url]); - - - - + + + + - 19 - - + + + + - const { t } = useTranslation("plugins"); - - - - + + + + - 18 - - + + + + - 20 - - + + + - if (event) { - - - - + + + - 19 - - + + + + - 21 - - + + + + - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- 2 - - 2 - - import { Link } from "@scm-manager/ui-types"; -
-

- Line Annotation -

-
- 3 - - 3 - - import { apiClient, Toast, ToastButtons, ToastButton } from "@scm-manager/ui-components"; -
- 4 - - 4 - - import { PullRequest } from "./types/PullRequest"; -
+
- 5 - - import { useTranslation } from "react-i18next"; -
- 5 - + 1 + + 1 + + package com.cloudogu.scm.review.events; +
+ 2 + + 2 + + +
+

+ Line Annotation +

+
- 7 - - type HandlerProps = { -
- 7 - - 8 - - url: string; -
-
+ 3 +
-
+ import com.cloudogu.scm.review.comment.service.BasicComment; +
+ 4 + + + import com.cloudogu.scm.review.comment.service.BasicCommentEvent; +
+ 5 + + + import com.cloudogu.scm.review.comment.service.CommentEvent; +
+ 6 + + + import com.cloudogu.scm.review.comment.service.ReplyEvent; +
+ 7 + + 3 + + import com.cloudogu.scm.review.pullrequest.service.BasicPullRequestEvent; +
+ 8 + + 4 + + import com.cloudogu.scm.review.pullrequest.service.PullRequest; +
+ 9 + + + import com.cloudogu.scm.review.pullrequest.service.PullRequestEvent; +
+ 10 + + 5 + + import com.github.legman.Subscribe; +
+ 11 + + + import lombok.Data; +
- + 12 + + 6 + + import org.apache.shiro.SecurityUtils; +
+ 13 + + 7 + + import org.apache.shiro.subject.PrincipalCollection; +
+ 14 + + 8 + + import org.apache.shiro.subject.Subject; +
+ 15 + + 9 + + import sonia.scm.EagerSingleton; +
+ 16 + + + import sonia.scm.HandlerEventType; +
+ 17 + + + import sonia.scm.event.HandlerEvent; +
+ 18 + + 10 + + import sonia.scm.plugin.Extension; +
+ 19 + + 11 + + import sonia.scm.repository.Repository; +
- 20 - - - <Toast type="warning" title="New Changes"> -
- 21 - - - <p>The underlying Pull-Request has changed. Press reload to see the changes.</p> -
- 22 - - - <p>Warning: Non saved modification will be lost.</p> -
- - 22 - - <Toast type="warning" title={t("scm-review-plugin.changeNotification.title")}> -
- - 23 - - <p>{t("scm-review-plugin.changeNotification.description")}</p> -
- - 24 - - <p>{t("scm-review-plugin.changeNotification.modificationWarning")}</p> -
- 23 - - 25 - - <ToastButtons> -
- 24 - - - <ToastButton icon="redo" onClick={reload}>Reload</ToastButton> -
- 25 - - - <ToastButton icon="times" onClick={() => setEvent(undefined)}>Ignore</ToastButton> -
- - 26 - - <ToastButton icon="redo" onClick={reload}> -
- - 27 - - {t("scm-review-plugin.changeNotification.buttons.reload")} -
- - 28 - - </ToastButton> -
- - 29 - - <ToastButton icon="times" onClick={() => setEvent(undefined)}> -
- - 30 - - {t("scm-review-plugin.changeNotification.buttons.ignore")} -
- - 31 - - </ToastButton> -
- 26 - - 32 - - </ToastButtons> -
- 27 - - 33 - - </Toast> -
- 28 - - 34 - - ); -
+ + 20 + + + 12 + + + import sonia.scm.security.SessionId; + + + + +
-
-
- - - src/main/resources/locales/de/plugins.json - - - modify - -
-
+ + + src/main/js/ChangeNotification.tsx + + + modify + +
+
- - - - - + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 2 + + 2 + + import { Link } from "@scm-manager/ui-types"; +
+

+ Line Annotation +

+
+ 3 + + 3 + + import { apiClient, Toast, ToastButtons, ToastButton } from "@scm-manager/ui-components"; +
+ 4 + + 4 + + import { PullRequest } from "./types/PullRequest"; +
+ + 5 + + import { useTranslation } from "react-i18next"; +
+ 5 + + 6 + + +
+ 6 + + 7 + + type HandlerProps = { +
+ 7 + + 8 + + url: string; +
+
+
+ 15 + + 16 + + pullRequest: setEvent +
+ 16 + + 17 + + }); +
+ 17 + + 18 + + }, [url]); +
+ + 19 + + const { t } = useTranslation("plugins"); +
+ 18 + + 20 + + if (event) { +
+ 19 + + 21 + + return ( +
+ 20 + + + <Toast type="warning" title="New Changes"> +
+ 21 + + + <p>The underlying Pull-Request has changed. Press reload to see the changes.</p> +
+ 22 + + + <p>Warning: Non saved modification will be lost.</p> +
+ + 22 + + <Toast type="warning" title={t("scm-review-plugin.changeNotification.title")}> +
+ + 23 + + <p>{t("scm-review-plugin.changeNotification.description")}</p> +
+ + 24 + + <p>{t("scm-review-plugin.changeNotification.modificationWarning")}</p> +
+ 23 + + 25 + + <ToastButtons> +
+ 24 + + + <ToastButton icon="redo" onClick={reload}>Reload</ToastButton> +
+ 25 + + + <ToastButton icon="times" onClick={() => setEvent(undefined)}>Ignore</ToastButton> +
+ + 26 + + <ToastButton icon="redo" onClick={reload}> +
+ + 27 + + {t("scm-review-plugin.changeNotification.buttons.reload")} +
+ + 28 + + </ToastButton> +
+ + 29 + + <ToastButton icon="times" onClick={() => setEvent(undefined)}> +
+ + 30 + + {t("scm-review-plugin.changeNotification.buttons.ignore")} +
+ + 31 + + </ToastButton> +
+ 26 + + 32 + + </ToastButtons> +
+ 27 + + 33 + + </Toast> +
+ 28 + + 34 + + ); +
+
- - - - - - - - - - - - - + +
-
- + + + + +
+ - 181 - + - 181 - - "titleClickable": "Der Kommentar bezieht sich auf eine ältere Version des Source- oder Target-Branches. Klicken Sie hier, um den ursprünglichen Kontext zu sehen." -
- 182 - + + + + + + + + + + +
+ + + + + + + + - 182 - - + + + + + + + + + + + + - - - + - 183 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ 181 + + 181 + + "titleClickable": "Der Kommentar bezieht sich auf eine ältere Version des Source- oder Target-Branches. Klicken Sie hier, um den ursprünglichen Kontext zu sehen." +
+ 182 + + 182 + + } +
+ 183 + + 183 + } -
+
- 183 - - } -
- - 184 - - }, -
- - 185 - - "changeNotification": { -
- - 186 - - "title": "Neue Änderungen", -
- - 187 - - "description": "An diesem Pull Request wurden Änderungen vorgenommen. Laden Sie die Seite neu um diese anzuzeigen.", -
- - 188 - - "modificationWarning": "Warnung: Nicht gespeicherte Eingaben gehen verloren.", -
- - 189 - - "buttons": { -
- - 190 - - "reload": "Neu laden", -
- - 191 - - "ignore": "Ignorieren" -
- - 192 - - } -
- 184 - - 193 - - } -
- 185 - - 194 - - }, -
- 186 - - 195 - - "permissions": { -
-
- -
-
-
-
- - - src/main/resources/locales/en/plugins.json - - - modify - -
-
-
-
- +
- - - - - - - - - -
- - - - - - - - - + + - 181 - - + + + - 181 - - + + + - "titleClickable": "The comment is related to an older of the source or target branch. Click here to see the original context." - - - - + + + - 182 - - + + + - 182 - - + + + + + + + + + + + + + - - - - - + + + + - - - - + + + + - - - + - 185 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ + }, +
+ + 185 + + "changeNotification": { +
+ + 186 + + "title": "Neue Änderungen", +
+ + 187 + + "description": "An diesem Pull Request wurden Änderungen vorgenommen. Laden Sie die Seite neu um diese anzuzeigen.", +
+ + 188 + + "modificationWarning": "Warnung: Nicht gespeicherte Eingaben gehen verloren.", +
+ + 189 + + "buttons": { +
+ + 190 + + "reload": "Neu laden", +
+ + 191 + + "ignore": "Ignorieren" +
+ + 192 + } -
- 183 - - 183 - +
+ 184 + + 193 + } -
- - 184 - +
+ 185 + + 194 + }, -
- +
- "changeNotification": { -
- - 186 - - "title": "New Changes", -
- - 187 - - "description": "The underlying Pull-Request has changed. Press reload to see the changes.", -
- - 188 - - "modificationWarning": "Warning: Non saved modification will be lost.", -
- - 189 - - "buttons": { -
- - 190 - - "reload": "Reload", -
- - 191 - - "ignore": "Ignore" -
- - 192 - - } -
- 184 - - 193 - - } -
- 185 - - 194 - - }, -
- 186 - - 195 - - "permissions": { -
+
+ 186 + + 195 + + "permissions": { +
+
- -
- - - src/test/java/com/cloudogu/scm/review/events/ClientTest.java - - - modify - -
-
+ + + src/main/resources/locales/en/plugins.json + + + modify + +
+
- - - - - + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 181 + + 181 + + "titleClickable": "The comment is related to an older of the source or target branch. Click here to see the original context." +
+ 182 + + 182 + + } +
+ 183 + + 183 + + } +
+ + 184 + + }, +
+ + 185 + + "changeNotification": { +
+ + 186 + + "title": "New Changes", +
+ + 187 + + "description": "The underlying Pull-Request has changed. Press reload to see the changes.", +
+ + 188 + + "modificationWarning": "Warning: Non saved modification will be lost.", +
+ + 189 + + "buttons": { +
+ + 190 + + "reload": "Reload", +
+ + 191 + + "ignore": "Ignore" +
+ + 192 + + } +
+ 184 + + 193 + + } +
+ 185 + + 194 + + }, +
+ 186 + + 195 + + "permissions": { +
+
- - - - - - - - - - - - - - - - - - - - - - - - - - - + +
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + +
+
- 7 - - 7 - - import org.mockito.Mock; -
- 8 - - 8 - - import org.mockito.junit.jupiter.MockitoExtension; -
- 9 - - 9 - - import sonia.scm.security.SessionId; -
- - 10 - + - -
- 10 - - 11 - - import javax.ws.rs.sse.OutboundSseEvent; -
- 11 - - 12 - - import javax.ws.rs.sse.SseEventSink; -
- 12 - - - -
- 13 - - 13 - - import java.time.Clock; -
- 14 - - 14 - - import java.time.Instant; -
- 15 - - 15 - - import java.time.LocalDateTime; -
- 16 - - 16 - - import java.time.ZoneOffset; -
- 17 - - 17 - - import java.time.temporal.ChronoField; -
- 18 - - - import java.time.temporal.ChronoUnit; -
- 19 - - - import java.time.temporal.TemporalField; -
- 20 - - 18 - - import java.util.concurrent.CompletableFuture; -
- 21 - - 19 - - import java.util.concurrent.CompletionStage; -
- 22 - - - import java.util.concurrent.atomic.AtomicLong; -
- 23 - - 20 - - import java.util.concurrent.atomic.AtomicReference; -
- 24 - - 21 - - -
- 25 - - 22 - - import static java.time.temporal.ChronoUnit.MINUTES; -
- - + + + + + -
+ 7 + +
+ + + + + + + + + + + + + + - - - - - + + + - 83 - - + + + + - 80 - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ 7 + + import org.mockito.Mock; +
+ 8 + + 8 + + import org.mockito.junit.jupiter.MockitoExtension; +
+ 9 + + 9 + + import sonia.scm.security.SessionId; +
-
+ 10 + + +
+ 10 + + 11 + + import javax.ws.rs.sse.OutboundSseEvent; +
+ 11 + + 12 + + import javax.ws.rs.sse.SseEventSink; +
- 84 - - 81 - - @Test -
- 85 - - 82 - - @SuppressWarnings("unchecked") -
- 86 - - - void shouldCloseEventSinkOnFailure() throws InterruptedException { -
- - 83 - - void shouldCloseEventSinkOnFailure() { -
- 87 - - 84 - - CompletionStage future = CompletableFuture.supplyAsync(() -> { -
- 88 - - 85 - - throw new RuntimeException("failed to send message"); -
- 89 - - 86 - - }); -
-
+ 12 +
-
+ 13 + + 13 + + import java.time.Clock; +
+ 14 + + 14 + + import java.time.Instant; +
+ 15 + + 15 + + import java.time.LocalDateTime; +
+ 16 + + 16 + + import java.time.ZoneOffset; +
+ 17 + + 17 + + import java.time.temporal.ChronoField; +
+ 18 + + + import java.time.temporal.ChronoUnit; +
+ 19 + + + import java.time.temporal.TemporalField; +
+ 20 + + 18 + + import java.util.concurrent.CompletableFuture; +
+ 21 + + 19 + + import java.util.concurrent.CompletionStage; +
+ 22 + + + import java.util.concurrent.atomic.AtomicLong; +
+ 23 + + 20 + + import java.util.concurrent.atomic.AtomicReference; +
+ 24 + + 21 + + +
+ 25 + + 22 + + import static java.time.temporal.ChronoUnit.MINUTES; +
+
+
+ 83 + + 80 + + +
+ 84 + + 81 + + @Test +
+ 85 + + 82 + + @SuppressWarnings("unchecked") +
+ 86 + + + void shouldCloseEventSinkOnFailure() throws InterruptedException { +
+ + 83 + + void shouldCloseEventSinkOnFailure() { +
+ 87 + + 84 + + CompletionStage future = CompletableFuture.supplyAsync(() -> { +
+ 88 + + 85 + + throw new RuntimeException("failed to send message"); +
+ 89 + + 86 + + }); +
+
+
+ 91 + + 88 + + +
+ 92 + + 89 + + client.send(message); +
+ 93 + + 90 + + +
+ 94 + + + Thread.sleep(50L); +
+ 95 + + + +
+ 96 + + + verify(eventSink).close(); +
+ + 91 + + verify(eventSink, timeout(50L)).close(); +
+ 97 + + 92 + + } +
+ 98 + + 93 + + +
+ 99 + + 94 + + @Test +
+
+ +
+
+
- - - 91 - - - 88 - - - - - - - - 92 - - - 89 - - - client.send(message); - - - - - 93 - - - 90 - - - - - - - - 94 - - - - Thread.sleep(50L); - - - + + modify + +
+
- - 95 - - + + + + + +
+
+
+ + +
+ + + - - - - - - - + + - - + + + - verify(eventSink, timeout(50L)).close(); - - - - + + + + - 97 - - + + + + - 92 - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - -
- -
- 96 - - - verify(eventSink).close(); -
- - 91 - + + 1 + + import java.io.PrintStream; +
+ 1 + + 2 + + import java.util.Arrays; +
+ 2 + + 3 + + +
+

+ Line Annotation +

+
+ 3 + + 4 + + class Main { +
+ + 5 + + private static final PrintStream OUT = System.out; +
+ + 6 + + +
+ 4 + + 7 + + public static void main(String[] args) { +
+ + 8 + + <<<<<<< HEAD +
+ 5 + + 9 + + System.out.println("Expect nothing more to happen."); +
+ 6 + + 10 + + System.out.println("The command line parameters are:"); +
+ 7 + + 11 + + Arrays.stream(args).map(arg -> "- " + arg).forEach(System.out::println); +
+ + 12 + + ======= +
+ + 13 + + OUT.println("Expect nothing more to happen."); +
+ + 14 + + OUT.println("Parameters:"); +
+ + 15 + + Arrays.stream(args).map(arg -> "- " + arg).forEach(OUT::println); +
+ + 16 + + >>>>>>> feature/use_constant +
+ 8 + + 17 + + } +
+ 9 + + 18 + } -
- 98 - - 93 - - -
- 99 - - 94 - - @Test -
-
- -
-
-
-
- - - Main.java - - - modify - -
-
-
-
- - - - - -
-
-
+ + + +
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - 1 - - import java.io.PrintStream; -
- 1 - - 2 - - import java.util.Arrays; -
- 2 - - 3 - - -
-

- Line Annotation -

-
- 3 - - 4 - - class Main { -
- - 5 - - private static final PrintStream OUT = System.out; -
- - 6 - - -
- 4 - - 7 - - public static void main(String[] args) { -
- - 8 - - <<<<<<< HEAD -
- 5 - - 9 - - System.out.println("Expect nothing more to happen."); -
- 6 - - 10 - - System.out.println("The command line parameters are:"); -
- 7 - - 11 - - Arrays.stream(args).map(arg -> "- " + arg).forEach(System.out::println); -
- - 12 - - ======= -
- - 13 - - OUT.println("Expect nothing more to happen."); -
- - 14 - - OUT.println("Parameters:"); -
- - 15 - - Arrays.stream(args).map(arg -> "- " + arg).forEach(OUT::println); -
- - 16 - - >>>>>>> feature/use_constant -
- 8 - - 17 - - } -
- 9 - - 18 - - } -
-
`; @@ -27270,4108 +27333,4116 @@ exports[`Storyshots Diff OnClick 1`] = `
-
+
- - - src/main/java/com/cloudogu/scm/review/events/EventListener.java - - - modify - -
-
+ + + src/main/java/com/cloudogu/scm/review/events/EventListener.java + + + modify + +
+
- - - - - + + + + +
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- 1 - - 1 - - package com.cloudogu.scm.review.events; -
- 2 - - 2 - - -
- 3 - - - import com.cloudogu.scm.review.comment.service.BasicComment; -
- 4 - - - import com.cloudogu.scm.review.comment.service.BasicCommentEvent; -
- 5 - - - import com.cloudogu.scm.review.comment.service.CommentEvent; -
- 6 - - - import com.cloudogu.scm.review.comment.service.ReplyEvent; -
- 7 - - 3 - - import com.cloudogu.scm.review.pullrequest.service.BasicPullRequestEvent; -
- 8 - - 4 - - import com.cloudogu.scm.review.pullrequest.service.PullRequest; -
- 9 - - - import com.cloudogu.scm.review.pullrequest.service.PullRequestEvent; -
- 10 - - 5 - - import com.github.legman.Subscribe; -
- 11 - - - import lombok.Data; -
- 12 - - 6 - - import org.apache.shiro.SecurityUtils; -
- 13 - - 7 - - import org.apache.shiro.subject.PrincipalCollection; -
- 14 - - 8 - - import org.apache.shiro.subject.Subject; -
- 15 - - 9 - - import sonia.scm.EagerSingleton; -
- 16 - - - import sonia.scm.HandlerEventType; -
- 17 - - - import sonia.scm.event.HandlerEvent; -
- 18 - - 10 - - import sonia.scm.plugin.Extension; -
- 19 - - 11 - - import sonia.scm.repository.Repository; -
- 20 - - 12 - - import sonia.scm.security.SessionId; -
-
-
-
-
-
- - - src/main/js/ChangeNotification.tsx - - - modify - -
-
-
-
- - - - - -
-
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - + + + + - 6 - - + + + + - - - - - - - - - - - - - - - - - + - - - - - + + - 15 - - + + + - 16 - - + + + - pullRequest: setEvent - - - - + + + - 16 - - + + + + - 17 - - + + + + - }); - - - - + + + - 17 - - + + + + - 18 - - + + + - }, [url]); - - - - + + + + - 19 - - + + + + - const { t } = useTranslation("plugins"); - - - - + + + + - 18 - - + + + + - 20 - - + + + - if (event) { - - - - + + + - 19 - - + + + + - 21 - - + + + + - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- 2 - - 2 - - import { Link } from "@scm-manager/ui-types"; -
- 3 - - 3 - - import { apiClient, Toast, ToastButtons, ToastButton } from "@scm-manager/ui-components"; -
- 4 - - 4 - - import { PullRequest } from "./types/PullRequest"; -
+
- 5 - - import { useTranslation } from "react-i18next"; -
- 5 - + 1 + + 1 + + package com.cloudogu.scm.review.events; +
+ 2 + + 2 + + +
- 6 - - 7 - - type HandlerProps = { -
- 7 - - 8 - - url: string; -
-
+ 3 +
-
+ import com.cloudogu.scm.review.comment.service.BasicComment; +
+ 4 + + + import com.cloudogu.scm.review.comment.service.BasicCommentEvent; +
+ 5 + + + import com.cloudogu.scm.review.comment.service.CommentEvent; +
+ 6 + + + import com.cloudogu.scm.review.comment.service.ReplyEvent; +
+ 7 + + 3 + + import com.cloudogu.scm.review.pullrequest.service.BasicPullRequestEvent; +
+ 8 + + 4 + + import com.cloudogu.scm.review.pullrequest.service.PullRequest; +
+ 9 + + + import com.cloudogu.scm.review.pullrequest.service.PullRequestEvent; +
+ 10 + + 5 + + import com.github.legman.Subscribe; +
+ 11 + + + import lombok.Data; +
- + 12 + + 6 + + import org.apache.shiro.SecurityUtils; +
+ 13 + + 7 + + import org.apache.shiro.subject.PrincipalCollection; +
+ 14 + + 8 + + import org.apache.shiro.subject.Subject; +
+ 15 + + 9 + + import sonia.scm.EagerSingleton; +
+ 16 + + + import sonia.scm.HandlerEventType; +
+ 17 + + + import sonia.scm.event.HandlerEvent; +
+ 18 + + 10 + + import sonia.scm.plugin.Extension; +
+ 19 + + 11 + + import sonia.scm.repository.Repository; +
- 20 - - - <Toast type="warning" title="New Changes"> -
- 21 - - - <p>The underlying Pull-Request has changed. Press reload to see the changes.</p> -
- 22 - - - <p>Warning: Non saved modification will be lost.</p> -
- - 22 - - <Toast type="warning" title={t("scm-review-plugin.changeNotification.title")}> -
- - 23 - - <p>{t("scm-review-plugin.changeNotification.description")}</p> -
- - 24 - - <p>{t("scm-review-plugin.changeNotification.modificationWarning")}</p> -
- 23 - - 25 - - <ToastButtons> -
- 24 - - - <ToastButton icon="redo" onClick={reload}>Reload</ToastButton> -
- 25 - - - <ToastButton icon="times" onClick={() => setEvent(undefined)}>Ignore</ToastButton> -
- - 26 - - <ToastButton icon="redo" onClick={reload}> -
- - 27 - - {t("scm-review-plugin.changeNotification.buttons.reload")} -
- - 28 - - </ToastButton> -
- - 29 - - <ToastButton icon="times" onClick={() => setEvent(undefined)}> -
- - 30 - - {t("scm-review-plugin.changeNotification.buttons.ignore")} -
- - 31 - - </ToastButton> -
- 26 - - 32 - - </ToastButtons> -
- 27 - - 33 - - </Toast> -
- 28 - - 34 - - ); -
+ + 20 + + + 12 + + + import sonia.scm.security.SessionId; + + + + +
-
-
- - - src/main/resources/locales/de/plugins.json - - - modify - -
-
+ + + src/main/js/ChangeNotification.tsx + + + modify + +
+
- - - - - + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 2 + + 2 + + import { Link } from "@scm-manager/ui-types"; +
+ 3 + + 3 + + import { apiClient, Toast, ToastButtons, ToastButton } from "@scm-manager/ui-components"; +
+ 4 + + 4 + + import { PullRequest } from "./types/PullRequest"; +
+ + 5 + + import { useTranslation } from "react-i18next"; +
+ 5 + + 6 + + +
+ 6 + + 7 + + type HandlerProps = { +
+ 7 + + 8 + + url: string; +
+
+
+ 15 + + 16 + + pullRequest: setEvent +
+ 16 + + 17 + + }); +
+ 17 + + 18 + + }, [url]); +
+ + 19 + + const { t } = useTranslation("plugins"); +
+ 18 + + 20 + + if (event) { +
+ 19 + + 21 + + return ( +
+ 20 + + + <Toast type="warning" title="New Changes"> +
+ 21 + + + <p>The underlying Pull-Request has changed. Press reload to see the changes.</p> +
+ 22 + + + <p>Warning: Non saved modification will be lost.</p> +
+ + 22 + + <Toast type="warning" title={t("scm-review-plugin.changeNotification.title")}> +
+ + 23 + + <p>{t("scm-review-plugin.changeNotification.description")}</p> +
+ + 24 + + <p>{t("scm-review-plugin.changeNotification.modificationWarning")}</p> +
+ 23 + + 25 + + <ToastButtons> +
+ 24 + + + <ToastButton icon="redo" onClick={reload}>Reload</ToastButton> +
+ 25 + + + <ToastButton icon="times" onClick={() => setEvent(undefined)}>Ignore</ToastButton> +
+ + 26 + + <ToastButton icon="redo" onClick={reload}> +
+ + 27 + + {t("scm-review-plugin.changeNotification.buttons.reload")} +
+ + 28 + + </ToastButton> +
+ + 29 + + <ToastButton icon="times" onClick={() => setEvent(undefined)}> +
+ + 30 + + {t("scm-review-plugin.changeNotification.buttons.ignore")} +
+ + 31 + + </ToastButton> +
+ 26 + + 32 + + </ToastButtons> +
+ 27 + + 33 + + </Toast> +
+ 28 + + 34 + + ); +
+
- - - - - - - - - - - - - + +
-
- + + + + +
+ - 181 - + - 181 - - "titleClickable": "Der Kommentar bezieht sich auf eine ältere Version des Source- oder Target-Branches. Klicken Sie hier, um den ursprünglichen Kontext zu sehen." -
- 182 - + + + + + + + + + + +
+ + + + + + + + - 182 - - + + + + + + + + + + + + - - - + - 183 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ 181 + + 181 + + "titleClickable": "Der Kommentar bezieht sich auf eine ältere Version des Source- oder Target-Branches. Klicken Sie hier, um den ursprünglichen Kontext zu sehen." +
+ 182 + + 182 + + } +
+ 183 + + 183 + } -
+
- 183 - - } -
- - 184 - - }, -
- - 185 - - "changeNotification": { -
- - 186 - - "title": "Neue Änderungen", -
- - 187 - - "description": "An diesem Pull Request wurden Änderungen vorgenommen. Laden Sie die Seite neu um diese anzuzeigen.", -
- - 188 - - "modificationWarning": "Warnung: Nicht gespeicherte Eingaben gehen verloren.", -
- - 189 - - "buttons": { -
- - 190 - - "reload": "Neu laden", -
- - 191 - - "ignore": "Ignorieren" -
- - 192 - - } -
- 184 - - 193 - - } -
- 185 - - 194 - - }, -
- 186 - - 195 - - "permissions": { -
-
- -
-
-
-
- - - src/main/resources/locales/en/plugins.json - - - modify - -
-
-
-
- +
- - - - - - - - - -
- - - - - - - - - + + - 181 - - + + + - 181 - - + + + - "titleClickable": "The comment is related to an older of the source or target branch. Click here to see the original context." - - - - + + + - 182 - - + + + - 182 - - + + + + + + + + + + + + + - - - - - + + + + - - - - + + + + - - - + - 185 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ + }, +
+ + 185 + + "changeNotification": { +
+ + 186 + + "title": "Neue Änderungen", +
+ + 187 + + "description": "An diesem Pull Request wurden Änderungen vorgenommen. Laden Sie die Seite neu um diese anzuzeigen.", +
+ + 188 + + "modificationWarning": "Warnung: Nicht gespeicherte Eingaben gehen verloren.", +
+ + 189 + + "buttons": { +
+ + 190 + + "reload": "Neu laden", +
+ + 191 + + "ignore": "Ignorieren" +
+ + 192 + } -
- 183 - - 183 - +
+ 184 + + 193 + } -
- - 184 - +
+ 185 + + 194 + }, -
- +
- "changeNotification": { -
- - 186 - - "title": "New Changes", -
- - 187 - - "description": "The underlying Pull-Request has changed. Press reload to see the changes.", -
- - 188 - - "modificationWarning": "Warning: Non saved modification will be lost.", -
- - 189 - - "buttons": { -
- - 190 - - "reload": "Reload", -
- - 191 - - "ignore": "Ignore" -
- - 192 - - } -
- 184 - - 193 - - } -
- 185 - - 194 - - }, -
- 186 - - 195 - - "permissions": { -
+
+ 186 + + 195 + + "permissions": { +
+
- -
- - - src/test/java/com/cloudogu/scm/review/events/ClientTest.java - - - modify - -
-
+ + + src/main/resources/locales/en/plugins.json + + + modify + +
+
- - - - - + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 181 + + 181 + + "titleClickable": "The comment is related to an older of the source or target branch. Click here to see the original context." +
+ 182 + + 182 + + } +
+ 183 + + 183 + + } +
+ + 184 + + }, +
+ + 185 + + "changeNotification": { +
+ + 186 + + "title": "New Changes", +
+ + 187 + + "description": "The underlying Pull-Request has changed. Press reload to see the changes.", +
+ + 188 + + "modificationWarning": "Warning: Non saved modification will be lost.", +
+ + 189 + + "buttons": { +
+ + 190 + + "reload": "Reload", +
+ + 191 + + "ignore": "Ignore" +
+ + 192 + + } +
+ 184 + + 193 + + } +
+ 185 + + 194 + + }, +
+ 186 + + 195 + + "permissions": { +
+
- - - - - - - - - - - - - - - - - - - - - - - - - - - + +
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + +
+
- 7 - - 7 - - import org.mockito.Mock; -
- 8 - - 8 - - import org.mockito.junit.jupiter.MockitoExtension; -
- 9 - - 9 - - import sonia.scm.security.SessionId; -
- - 10 - + - -
- 10 - - 11 - - import javax.ws.rs.sse.OutboundSseEvent; -
- 11 - - 12 - - import javax.ws.rs.sse.SseEventSink; -
- 12 - - - -
- 13 - - 13 - - import java.time.Clock; -
- 14 - - 14 - - import java.time.Instant; -
- 15 - - 15 - - import java.time.LocalDateTime; -
- 16 - - 16 - - import java.time.ZoneOffset; -
- 17 - - 17 - - import java.time.temporal.ChronoField; -
- 18 - - - import java.time.temporal.ChronoUnit; -
- 19 - - - import java.time.temporal.TemporalField; -
- 20 - - 18 - - import java.util.concurrent.CompletableFuture; -
- 21 - - 19 - - import java.util.concurrent.CompletionStage; -
- 22 - - - import java.util.concurrent.atomic.AtomicLong; -
- 23 - - 20 - - import java.util.concurrent.atomic.AtomicReference; -
- 24 - - 21 - - -
- 25 - - 22 - - import static java.time.temporal.ChronoUnit.MINUTES; -
- - + + + + + -
+ 7 + +
+ + + + + + + + + + + + + + - - - - - + + + - 83 - - + + + + - 80 - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ 7 + + import org.mockito.Mock; +
+ 8 + + 8 + + import org.mockito.junit.jupiter.MockitoExtension; +
+ 9 + + 9 + + import sonia.scm.security.SessionId; +
-
+ 10 + + +
+ 10 + + 11 + + import javax.ws.rs.sse.OutboundSseEvent; +
+ 11 + + 12 + + import javax.ws.rs.sse.SseEventSink; +
- 84 - - 81 - - @Test -
- 85 - - 82 - - @SuppressWarnings("unchecked") -
- 86 - - - void shouldCloseEventSinkOnFailure() throws InterruptedException { -
- - 83 - - void shouldCloseEventSinkOnFailure() { -
- 87 - - 84 - - CompletionStage future = CompletableFuture.supplyAsync(() -> { -
- 88 - - 85 - - throw new RuntimeException("failed to send message"); -
- 89 - - 86 - - }); -
-
+ 12 +
-
+ 13 + + 13 + + import java.time.Clock; +
+ 14 + + 14 + + import java.time.Instant; +
+ 15 + + 15 + + import java.time.LocalDateTime; +
+ 16 + + 16 + + import java.time.ZoneOffset; +
+ 17 + + 17 + + import java.time.temporal.ChronoField; +
+ 18 + + + import java.time.temporal.ChronoUnit; +
+ 19 + + + import java.time.temporal.TemporalField; +
+ 20 + + 18 + + import java.util.concurrent.CompletableFuture; +
+ 21 + + 19 + + import java.util.concurrent.CompletionStage; +
+ 22 + + + import java.util.concurrent.atomic.AtomicLong; +
+ 23 + + 20 + + import java.util.concurrent.atomic.AtomicReference; +
+ 24 + + 21 + + +
+ 25 + + 22 + + import static java.time.temporal.ChronoUnit.MINUTES; +
+
+
+ 83 + + 80 + + +
+ 84 + + 81 + + @Test +
+ 85 + + 82 + + @SuppressWarnings("unchecked") +
+ 86 + + + void shouldCloseEventSinkOnFailure() throws InterruptedException { +
+ + 83 + + void shouldCloseEventSinkOnFailure() { +
+ 87 + + 84 + + CompletionStage future = CompletableFuture.supplyAsync(() -> { +
+ 88 + + 85 + + throw new RuntimeException("failed to send message"); +
+ 89 + + 86 + + }); +
+
+
+ 91 + + 88 + + +
+ 92 + + 89 + + client.send(message); +
+ 93 + + 90 + + +
+ 94 + + + Thread.sleep(50L); +
+ 95 + + + +
+ 96 + + + verify(eventSink).close(); +
+ + 91 + + verify(eventSink, timeout(50L)).close(); +
+ 97 + + 92 + + } +
+ 98 + + 93 + + +
+ 99 + + 94 + + @Test +
+
+ +
+
+
- - - 91 - - - 88 - - - - - - - - 92 - - - 89 - - - client.send(message); - - - - - 93 - - - 90 - - - - - - - - 94 - - - - Thread.sleep(50L); - - - + + modify + +
+
- - 95 - - + + + + + +
+
+
+ + +
+ + + - - - - - - - + + - - + + + - verify(eventSink, timeout(50L)).close(); - - - - + + + + - 97 - - + + + + - 92 - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - -
- -
- 96 - - - verify(eventSink).close(); -
- - 91 - + + 1 + + import java.io.PrintStream; +
+ 1 + + 2 + + import java.util.Arrays; +
+ 2 + + 3 + + +
+ 3 + + 4 + + class Main { +
+ + 5 + + private static final PrintStream OUT = System.out; +
+ + 6 + + +
+ 4 + + 7 + + public static void main(String[] args) { +
+ + 8 + + <<<<<<< HEAD +
+ 5 + + 9 + + System.out.println("Expect nothing more to happen."); +
+ 6 + + 10 + + System.out.println("The command line parameters are:"); +
+ 7 + + 11 + + Arrays.stream(args).map(arg -> "- " + arg).forEach(System.out::println); +
+ + 12 + + ======= +
+ + 13 + + OUT.println("Expect nothing more to happen."); +
+ + 14 + + OUT.println("Parameters:"); +
+ + 15 + + Arrays.stream(args).map(arg -> "- " + arg).forEach(OUT::println); +
+ + 16 + + >>>>>>> feature/use_constant +
+ 8 + + 17 + + } +
+ 9 + + 18 + } -
- 98 - - 93 - - -
- 99 - - 94 - - @Test -
-
- -
-
-
-
- - - Main.java - - - modify - -
-
-
-
- - - - - -
-
-
+ + + +
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - 1 - - import java.io.PrintStream; -
- 1 - - 2 - - import java.util.Arrays; -
- 2 - - 3 - - -
- 3 - - 4 - - class Main { -
- - 5 - - private static final PrintStream OUT = System.out; -
- - 6 - - -
- 4 - - 7 - - public static void main(String[] args) { -
- - 8 - - <<<<<<< HEAD -
- 5 - - 9 - - System.out.println("Expect nothing more to happen."); -
- 6 - - 10 - - System.out.println("The command line parameters are:"); -
- 7 - - 11 - - Arrays.stream(args).map(arg -> "- " + arg).forEach(System.out::println); -
- - 12 - - ======= -
- - 13 - - OUT.println("Expect nothing more to happen."); -
- - 14 - - OUT.println("Parameters:"); -
- - 15 - - Arrays.stream(args).map(arg -> "- " + arg).forEach(OUT::println); -
- - 16 - - >>>>>>> feature/use_constant -
- 8 - - 17 - - } -
- 9 - - 18 - - } -
-
`; @@ -31380,4362 +31451,4370 @@ exports[`Storyshots Diff Side-By-Side 1`] = `
-
+
- - - src/main/java/com/cloudogu/scm/review/events/EventListener.java - - - modify - -
-
+ + + src/main/java/com/cloudogu/scm/review/events/EventListener.java + + + modify + +
+
- - - - - + + + + +
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- 1 - - package com.cloudogu.scm.review.events; - - 1 - - package com.cloudogu.scm.review.events; -
- 2 - - - - 2 - - -
- 3 - - import com.cloudogu.scm.review.comment.service.BasicComment; - - -
- 4 - - import com.cloudogu.scm.review.comment.service.BasicCommentEvent; - - -
- 5 - - import com.cloudogu.scm.review.comment.service.CommentEvent; - - -
- 6 - - import com.cloudogu.scm.review.comment.service.ReplyEvent; - - -
- 7 - - import com.cloudogu.scm.review.pullrequest.service.BasicPullRequestEvent; - - 3 - - import com.cloudogu.scm.review.pullrequest.service.BasicPullRequestEvent; -
- 8 - - import com.cloudogu.scm.review.pullrequest.service.PullRequest; - - 4 - - import com.cloudogu.scm.review.pullrequest.service.PullRequest; -
- 9 - - import com.cloudogu.scm.review.pullrequest.service.PullRequestEvent; - - -
- 10 - - import com.github.legman.Subscribe; - - 5 - - import com.github.legman.Subscribe; -
- 11 - - import lombok.Data; - - -
- 12 - - import org.apache.shiro.SecurityUtils; - - 6 - - import org.apache.shiro.SecurityUtils; -
- 13 - - import org.apache.shiro.subject.PrincipalCollection; - - 7 - - import org.apache.shiro.subject.PrincipalCollection; -
- 14 - - import org.apache.shiro.subject.Subject; - - 8 - - import org.apache.shiro.subject.Subject; -
- 15 - - import sonia.scm.EagerSingleton; - - 9 - - import sonia.scm.EagerSingleton; -
- 16 - - import sonia.scm.HandlerEventType; - - -
- 17 - - import sonia.scm.event.HandlerEvent; - - -
- 18 - - import sonia.scm.plugin.Extension; - - 10 - - import sonia.scm.plugin.Extension; -
- 19 - - import sonia.scm.repository.Repository; - - 11 - - import sonia.scm.repository.Repository; -
- 20 - - import sonia.scm.security.SessionId; - - 12 - - import sonia.scm.security.SessionId; -
-
-
-
-
-
- - + + + + + + - src/main/js/ChangeNotification.tsx - - - modify - -
-
-
-
- - - - - -
-
-
-
-
-
- - - - - - - - - - + + + + - 2 - - + + + + + - import { Link } from "@scm-manager/ui-types"; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ + package com.cloudogu.scm.review.events; + + 1 + + package com.cloudogu.scm.review.events; +
+ 2 + + + + 2 + + +
- 2 - - import { Link } from "@scm-manager/ui-types"; -
- 3 - - import { apiClient, Toast, ToastButtons, ToastButton } from "@scm-manager/ui-components"; - - 3 - - import { apiClient, Toast, ToastButtons, ToastButton } from "@scm-manager/ui-components"; -
- 4 - - import { PullRequest } from "./types/PullRequest"; - - 4 - - import { PullRequest } from "./types/PullRequest"; -
- - - 5 - - import { useTranslation } from "react-i18next"; -
- 5 - - - - 6 - - -
- 6 - - type HandlerProps = { - - 7 - - type HandlerProps = { -
- 7 - - url: string; - - 8 - - url: string; -
-
+ 3 +
+ import com.cloudogu.scm.review.comment.service.BasicComment; + -
- 15 - - pullRequest: setEvent - - 16 - - pullRequest: setEvent -
- 16 - - }); - - 17 - - }); -
- 17 - - }, [url]); - - 18 - - }, [url]); -
- - - 19 - - const { t } = useTranslation("plugins"); -
- 18 - - if (event) { - - 20 - - if (event) { -
- 19 - - return ( - - 21 - - return ( -
- 20 - - <Toast type="warning" title="New Changes"> - - -
- 21 - - <p>The underlying Pull-Request has changed. Press reload to see the changes.</p> - - -
- 22 - - <p>Warning: Non saved modification will be lost.</p> - - 22 - - <Toast type="warning" title={t("scm-review-plugin.changeNotification.title")}> -
- - - 23 - - <p>{t("scm-review-plugin.changeNotification.description")}</p> -
- - - 24 - - <p>{t("scm-review-plugin.changeNotification.modificationWarning")}</p> -
- 23 - - <ToastButtons> - - 25 - - <ToastButtons> -
- 24 - - <ToastButton icon="redo" onClick={reload}>Reload</ToastButton> - - -
- 25 - - <ToastButton icon="times" onClick={() => setEvent(undefined)}>Ignore</ToastButton> - - 26 - - <ToastButton icon="redo" onClick={reload}> -
- - - 27 - - {t("scm-review-plugin.changeNotification.buttons.reload")} -
- - - 28 - - </ToastButton> -
- - - 29 - - <ToastButton icon="times" onClick={() => setEvent(undefined)}> -
- - - 30 - - {t("scm-review-plugin.changeNotification.buttons.ignore")} -
- - - 31 - - </ToastButton> -
- 26 - - </ToastButtons> - - 32 - - </ToastButtons> -
- 27 - - </Toast> - - 33 - - </Toast> -
- 28 - - ); - - 34 - - ); -
+ + + + + 4 + + + import com.cloudogu.scm.review.comment.service.BasicCommentEvent; + + + + + + + 5 + + + import com.cloudogu.scm.review.comment.service.CommentEvent; + + + + + + + 6 + + + import com.cloudogu.scm.review.comment.service.ReplyEvent; + + + + + + + 7 + + + import com.cloudogu.scm.review.pullrequest.service.BasicPullRequestEvent; + + + 3 + + + import com.cloudogu.scm.review.pullrequest.service.BasicPullRequestEvent; + + + + + 8 + + + import com.cloudogu.scm.review.pullrequest.service.PullRequest; + + + 4 + + + import com.cloudogu.scm.review.pullrequest.service.PullRequest; + + + + + 9 + + + import com.cloudogu.scm.review.pullrequest.service.PullRequestEvent; + + + + + + + 10 + + + import com.github.legman.Subscribe; + + + 5 + + + import com.github.legman.Subscribe; + + + + + 11 + + + import lombok.Data; + + + + + + + 12 + + + import org.apache.shiro.SecurityUtils; + + + 6 + + + import org.apache.shiro.SecurityUtils; + + + + + 13 + + + import org.apache.shiro.subject.PrincipalCollection; + + + 7 + + + import org.apache.shiro.subject.PrincipalCollection; + + + + + 14 + + + import org.apache.shiro.subject.Subject; + + + 8 + + + import org.apache.shiro.subject.Subject; + + + + + 15 + + + import sonia.scm.EagerSingleton; + + + 9 + + + import sonia.scm.EagerSingleton; + + + + + 16 + + + import sonia.scm.HandlerEventType; + + + + + + + 17 + + + import sonia.scm.event.HandlerEvent; + + + + + + + 18 + + + import sonia.scm.plugin.Extension; + + + 10 + + + import sonia.scm.plugin.Extension; + + + + + 19 + + + import sonia.scm.repository.Repository; + + + 11 + + + import sonia.scm.repository.Repository; + + + + + 20 + + + import sonia.scm.security.SessionId; + + + 12 + + + import sonia.scm.security.SessionId; + + + + +
-
-
- - - src/main/resources/locales/de/plugins.json - - - modify - -
-
+ + + src/main/js/ChangeNotification.tsx + + + modify + +
+
- - - - - + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 2 + + import { Link } from "@scm-manager/ui-types"; + + 2 + + import { Link } from "@scm-manager/ui-types"; +
+ 3 + + import { apiClient, Toast, ToastButtons, ToastButton } from "@scm-manager/ui-components"; + + 3 + + import { apiClient, Toast, ToastButtons, ToastButton } from "@scm-manager/ui-components"; +
+ 4 + + import { PullRequest } from "./types/PullRequest"; + + 4 + + import { PullRequest } from "./types/PullRequest"; +
+ + + 5 + + import { useTranslation } from "react-i18next"; +
+ 5 + + + + 6 + + +
+ 6 + + type HandlerProps = { + + 7 + + type HandlerProps = { +
+ 7 + + url: string; + + 8 + + url: string; +
+
+
+ 15 + + pullRequest: setEvent + + 16 + + pullRequest: setEvent +
+ 16 + + }); + + 17 + + }); +
+ 17 + + }, [url]); + + 18 + + }, [url]); +
+ + + 19 + + const { t } = useTranslation("plugins"); +
+ 18 + + if (event) { + + 20 + + if (event) { +
+ 19 + + return ( + + 21 + + return ( +
+ 20 + + <Toast type="warning" title="New Changes"> + + +
+ 21 + + <p>The underlying Pull-Request has changed. Press reload to see the changes.</p> + + +
+ 22 + + <p>Warning: Non saved modification will be lost.</p> + + 22 + + <Toast type="warning" title={t("scm-review-plugin.changeNotification.title")}> +
+ + + 23 + + <p>{t("scm-review-plugin.changeNotification.description")}</p> +
+ + + 24 + + <p>{t("scm-review-plugin.changeNotification.modificationWarning")}</p> +
+ 23 + + <ToastButtons> + + 25 + + <ToastButtons> +
+ 24 + + <ToastButton icon="redo" onClick={reload}>Reload</ToastButton> + + +
+ 25 + + <ToastButton icon="times" onClick={() => setEvent(undefined)}>Ignore</ToastButton> + + 26 + + <ToastButton icon="redo" onClick={reload}> +
+ + + 27 + + {t("scm-review-plugin.changeNotification.buttons.reload")} +
+ + + 28 + + </ToastButton> +
+ + + 29 + + <ToastButton icon="times" onClick={() => setEvent(undefined)}> +
+ + + 30 + + {t("scm-review-plugin.changeNotification.buttons.ignore")} +
+ + + 31 + + </ToastButton> +
+ 26 + + </ToastButtons> + + 32 + + </ToastButtons> +
+ 27 + + </Toast> + + 33 + + </Toast> +
+ 28 + + ); + + 34 + + ); +
+
- - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - + +
-
- - - + + + + + + + + + + +
+
- 181 - - "titleClickable": "Der Kommentar bezieht sich auf eine ältere Version des Source- oder Target-Branches. Klicken Sie hier, um den ursprünglichen Kontext zu sehen." - - 181 - - "titleClickable": "Der Kommentar bezieht sich auf eine ältere Version des Source- oder Target-Branches. Klicken Sie hier, um den ursprünglichen Kontext zu sehen." -
- 182 - - } - - 182 - - } -
- 183 - - } - - 183 - - } -
- + src/main/resources/locales/de/plugins.json + + + modify + + +
+
+
+ + + + + +
+
+
+ + +
+ + + - + + + + - 184 - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ 181 + + "titleClickable": "Der Kommentar bezieht sich auf eine ältere Version des Source- oder Target-Branches. Klicken Sie hier, um den ursprünglichen Kontext zu sehen." + + 181 + + "titleClickable": "Der Kommentar bezieht sich auf eine ältere Version des Source- oder Target-Branches. Klicken Sie hier, um den ursprünglichen Kontext zu sehen." +
+ 182 + + } + + 182 + + } +
+ 183 + + } + + 183 + + } +
+ + + 184 + + }, +
+ + + 185 + + "changeNotification": { +
+ + + 186 + + "title": "Neue Änderungen", +
+ + + 187 + + "description": "An diesem Pull Request wurden Änderungen vorgenommen. Laden Sie die Seite neu um diese anzuzeigen.", +
+ + + 188 + + "modificationWarning": "Warnung: Nicht gespeicherte Eingaben gehen verloren.", +
+ + + 189 + + "buttons": { +
+ + + 190 + + "reload": "Neu laden", +
+ + + 191 + + "ignore": "Ignorieren" +
+ + + 192 + + } +
+ 184 + + } + + 193 + + } +
+ 185 + }, -
- - - 185 - - "changeNotification": { -
- - - 186 - - "title": "Neue Änderungen", -
- - - 187 - - "description": "An diesem Pull Request wurden Änderungen vorgenommen. Laden Sie die Seite neu um diese anzuzeigen.", -
- - - 188 - - "modificationWarning": "Warnung: Nicht gespeicherte Eingaben gehen verloren.", -
- - - 189 - - "buttons": { -
- - - 190 - - "reload": "Neu laden", -
- - - 191 - - "ignore": "Ignorieren" -
- - - 192 - - } -
- 184 - - } - - 193 - - } -
- 185 - - }, - - 194 - - }, -
- 186 - - "permissions": { - - 195 - - "permissions": { -
-
- -
-
-
-
- - - src/main/resources/locales/en/plugins.json - - - modify - -
-
-
-
- +
+ 194 + - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + +
- 181 - - "titleClickable": "The comment is related to an older of the source or target branch. Click here to see the original context." - - 181 - - "titleClickable": "The comment is related to an older of the source or target branch. Click here to see the original context." -
- 182 - - } - - 182 - - } -
- 183 - - } - - 183 - - } -
- - - 184 - }, -
+ 186 + + "permissions": { + + 195 + + "permissions": { +
+
+ +
+
+
+
-
- - - 185 - + - "changeNotification": { -
- - - 186 - - "title": "New Changes", -
+ + + + + + + - - + + + + + - "description": "The underlying Pull-Request has changed. Press reload to see the changes.", - - - - + + + + + - 188 - - + + + + + - "modificationWarning": "Warning: Non saved modification will be lost.", - - - - + + + - 189 - - + + + - "buttons": { - - - - + + + - 190 - - + + + - "reload": "Reload", - - - - + + + - 191 - - + + + - "ignore": "Ignore" - - - - + + + - 192 - - + + + + + + + + + - - - + + + - 184 - - + + + + + - } - - - - - - - - - - - - - - - - - -
- - - 187 - + 181 + + "titleClickable": "The comment is related to an older of the source or target branch. Click here to see the original context." + + 181 + + "titleClickable": "The comment is related to an older of the source or target branch. Click here to see the original context." +
- - + 182 + + } + + 182 + + } +
+ 183 + + } + + 183 + + } +
- - + + + 184 + + }, +
+ + + 185 + + "changeNotification": { +
- - + + + 186 + + "title": "New Changes", +
+ + + 187 + + "description": "The underlying Pull-Request has changed. Press reload to see the changes.", +
- - + + + 188 + + "modificationWarning": "Warning: Non saved modification will be lost.", +
+ + + 189 + + "buttons": { +
- - + + + 190 + + "reload": "Reload", +
+ + + 191 + + "ignore": "Ignore" +
+ + + 192 + + } +
+ 184 + } -
+ + 193 + + } +
+ 185 + + }, + + 194 + + }, +
- 193 - - } -
- 185 - - }, - - 194 - - }, -
- 186 - - "permissions": { - - 195 - - "permissions": { -
+ + 186 + + + "permissions": { + + + 195 + + + "permissions": { + + + + +
- -
- - - src/test/java/com/cloudogu/scm/review/events/ClientTest.java - - - modify - -
-
+ + + src/test/java/com/cloudogu/scm/review/events/ClientTest.java + + + modify + +
+
- - - - - + + + + +
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - + + + + + - import javax.ws.rs.sse.OutboundSseEvent; - - + + + + + - 11 - - + + + + + - import javax.ws.rs.sse.OutboundSseEvent; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + 10 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + - - + + + + + - client.send(message); - - + + + + + - 89 - - + + + + + - client.send(message); - - - + 86 + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + - - + + + + + - Thread.sleep(50L); - - - - + + + + + - 95 - - + + + + + - - - - - + + + - 96 - - + + + - verify(eventSink).close(); - - + + + + + - 91 - - + + + + + - verify(eventSink, timeout(50L)).close(); - - - - + + + + + - 97 - - - - - - - - - - - - - - - - - - -
- 7 - - import org.mockito.Mock; - - 7 - - import org.mockito.Mock; -
- 8 - - import org.mockito.junit.jupiter.MockitoExtension; - - 8 - - import org.mockito.junit.jupiter.MockitoExtension; -
- 9 - - import sonia.scm.security.SessionId; - - 9 - - import sonia.scm.security.SessionId; -
+
+
- 10 - - -
- 10 - + 7 + + import org.mockito.Mock; + + 7 + + import org.mockito.Mock; +
+ 8 + + import org.mockito.junit.jupiter.MockitoExtension; + + 8 + + import org.mockito.junit.jupiter.MockitoExtension; +
+ 9 + + import sonia.scm.security.SessionId; + + 9 + + import sonia.scm.security.SessionId; +
- 11 - - import javax.ws.rs.sse.SseEventSink; - - 12 - - import javax.ws.rs.sse.SseEventSink; -
- 12 - - - - -
- 13 - - import java.time.Clock; - - 13 - - import java.time.Clock; -
- 14 - - import java.time.Instant; - - 14 - - import java.time.Instant; -
- 15 - - import java.time.LocalDateTime; - - 15 - - import java.time.LocalDateTime; -
- 16 - - import java.time.ZoneOffset; - - 16 - - import java.time.ZoneOffset; -
- 17 - - import java.time.temporal.ChronoField; - - 17 - - import java.time.temporal.ChronoField; -
- 18 - - import java.time.temporal.ChronoUnit; - - -
- 19 - - import java.time.temporal.TemporalField; - - -
- 20 - - import java.util.concurrent.CompletableFuture; - - 18 - - import java.util.concurrent.CompletableFuture; -
- 21 - - import java.util.concurrent.CompletionStage; - - 19 - - import java.util.concurrent.CompletionStage; -
- 22 - - import java.util.concurrent.atomic.AtomicLong; - - -
- 23 - - import java.util.concurrent.atomic.AtomicReference; - - 20 - - import java.util.concurrent.atomic.AtomicReference; -
- 24 - - - - 21 - - -
- 25 - - import static java.time.temporal.ChronoUnit.MINUTES; - - 22 - - import static java.time.temporal.ChronoUnit.MINUTES; -
-
-
- 83 - - - - 80 - - -
- 84 - - @Test - - 81 - - @Test -
- 85 - - @SuppressWarnings("unchecked") - - 82 - - @SuppressWarnings("unchecked") -
- 86 - - void shouldCloseEventSinkOnFailure() throws InterruptedException { - - 83 - - void shouldCloseEventSinkOnFailure() { -
- 87 - - CompletionStage future = CompletableFuture.supplyAsync(() -> { - - 84 - - CompletionStage future = CompletableFuture.supplyAsync(() -> { -
- 88 - - throw new RuntimeException("failed to send message"); - - 85 - - throw new RuntimeException("failed to send message"); -
- 89 - - }); - - 86 - - }); -
-
-
+ +
+ 10 + + import javax.ws.rs.sse.OutboundSseEvent; + + 11 + + import javax.ws.rs.sse.OutboundSseEvent; +
+ 11 + + import javax.ws.rs.sse.SseEventSink; + + 12 + + import javax.ws.rs.sse.SseEventSink; +
+ 12 + + + + +
+ 13 + + import java.time.Clock; + + 13 + + import java.time.Clock; +
+ 14 + + import java.time.Instant; + + 14 + + import java.time.Instant; +
+ 15 + + import java.time.LocalDateTime; + + 15 + + import java.time.LocalDateTime; +
+ 16 + + import java.time.ZoneOffset; + + 16 + + import java.time.ZoneOffset; +
+ 17 + + import java.time.temporal.ChronoField; + + 17 + + import java.time.temporal.ChronoField; +
+ 18 + + import java.time.temporal.ChronoUnit; + + +
+ 19 + + import java.time.temporal.TemporalField; + + +
+ 20 + + import java.util.concurrent.CompletableFuture; + + 18 + + import java.util.concurrent.CompletableFuture; +
+ 21 + + import java.util.concurrent.CompletionStage; + + 19 + + import java.util.concurrent.CompletionStage; +
+ 22 + + import java.util.concurrent.atomic.AtomicLong; + + +
+ 23 + + import java.util.concurrent.atomic.AtomicReference; + + 20 + + import java.util.concurrent.atomic.AtomicReference; +
+ 24 + + + + 21 + + +
+ 25 + + import static java.time.temporal.ChronoUnit.MINUTES; + + 22 + + import static java.time.temporal.ChronoUnit.MINUTES; +
- 91 - - - - 88 - - -
+
+
- 92 - + 83 + + + + 80 + + +
+ 84 + + @Test + + 81 + + @Test +
+ 85 + + @SuppressWarnings("unchecked") + + 82 + + @SuppressWarnings("unchecked") +
+ void shouldCloseEventSinkOnFailure() throws InterruptedException { + + 83 + + void shouldCloseEventSinkOnFailure() { +
+ 87 + + CompletionStage future = CompletableFuture.supplyAsync(() -> { + + 84 + + CompletionStage future = CompletableFuture.supplyAsync(() -> { +
+ 88 + + throw new RuntimeException("failed to send message"); + + 85 + + throw new RuntimeException("failed to send message"); +
+ 89 + + }); + + 86 + + }); +
- 93 - - - - 90 - - -
+
+
- 94 - + 91 + + + + 88 + + +
- -
+ 92 + + client.send(message); + + 89 + + client.send(message); +
+ 93 + + + + 90 + + +
- -
+ 94 + + Thread.sleep(50L); + + +
+ 95 + + + + +
+ 96 + + verify(eventSink).close(); + + 91 + + verify(eventSink, timeout(50L)).close(); +
+ 97 + + } + + 92 + + } +
+ 98 + + + + 93 + + +
- } - - 92 - - } -
- 98 - - - - 93 - - -
- 99 - - @Test - - 94 - - @Test -
+ + 99 + + + @Test + + + 94 + + + @Test + + + + +
- -
- - - Main.java - - - modify - -
-
+ + + Main.java + + + modify + +
+
- - - - - + + + + +
-
-
- - - - - - - - - - - - - - - + + - - + + + - import java.util.Arrays; - - + + + + + - 2 - - + + + + + - import java.util.Arrays; - - - - + + + + + - 2 - - + + + - - - + + + - 3 - - + + + + + - - - - - + + + - 3 - - + + + + + - class Main { - - + + + + + - 4 - - + + + + + - class Main { - - - - + + + - 5 - - + + + - private static final PrintStream OUT = System.out; - - - - + + + - 6 - - + + + - - - - - + + + - 4 - - + + + + + - public static void main(String[] args) { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+
- 1 - - import java.io.PrintStream; -
- 1 - + + + 1 + + import java.io.PrintStream; +
+ 1 + + import java.util.Arrays; + + 2 + + import java.util.Arrays; +
+ 2 + + + + 3 + + +
+ 3 + + class Main { + + 4 + + class Main { +
+ + + 5 + + private static final PrintStream OUT = System.out; +
+ + + 6 + + +
+ 4 + + public static void main(String[] args) { + + 7 + + public static void main(String[] args) { +
+ + + 8 + + <<<<<<< HEAD +
+ 5 + + System.out.println("Expect nothing more to happen."); + + 9 + + System.out.println("Expect nothing more to happen."); +
+ 6 + + System.out.println("The command line parameters are:"); + + 10 + + System.out.println("The command line parameters are:"); +
+ 7 + + Arrays.stream(args).map(arg -> "- " + arg).forEach(System.out::println); + + 11 + + Arrays.stream(args).map(arg -> "- " + arg).forEach(System.out::println); +
- - + + + 12 + + ======= +
+ + + 13 + + OUT.println("Expect nothing more to happen."); +
- - + + + 14 + + OUT.println("Parameters:"); +
+ + + 15 + + Arrays.stream(args).map(arg -> "- " + arg).forEach(OUT::println); +
+ + + 16 + + >>>>>>> feature/use_constant +
+ 8 + + } + + 17 + + } +
- 7 - - public static void main(String[] args) { -
- - - 8 - - <<<<<<< HEAD -
- 5 - - System.out.println("Expect nothing more to happen."); - - 9 - - System.out.println("Expect nothing more to happen."); -
- 6 - - System.out.println("The command line parameters are:"); - - 10 - - System.out.println("The command line parameters are:"); -
- 7 - - Arrays.stream(args).map(arg -> "- " + arg).forEach(System.out::println); - - 11 - - Arrays.stream(args).map(arg -> "- " + arg).forEach(System.out::println); -
- - - 12 - - ======= -
- - - 13 - - OUT.println("Expect nothing more to happen."); -
- - - 14 - - OUT.println("Parameters:"); -
- - - 15 - - Arrays.stream(args).map(arg -> "- " + arg).forEach(OUT::println); -
- - - 16 - - >>>>>>> feature/use_constant -
- 8 - - } - - 17 - - } -
- 9 - - } - - 18 - - } -
+ + 9 + + + } + + + 18 + + + } + + + + +
@@ -35745,3834 +35824,3842 @@ exports[`Storyshots Diff SyntaxHighlighting 1`] = `
-
+
- - - src/main/java/com/cloudogu/scm/review/events/EventListener.java - - - modify - -
-
+ + + src/main/java/com/cloudogu/scm/review/events/EventListener.java + + + modify + +
+
- - - - - + + + + +
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- 1 - - 1 - - package com.cloudogu.scm.review.events; -
- 2 - - 2 - - -
- 3 - - - import com.cloudogu.scm.review.comment.service.BasicComment; -
- 4 - - - import com.cloudogu.scm.review.comment.service.BasicCommentEvent; -
- 5 - - - import com.cloudogu.scm.review.comment.service.CommentEvent; -
- 6 - - - import com.cloudogu.scm.review.comment.service.ReplyEvent; -
- 7 - - 3 - - import com.cloudogu.scm.review.pullrequest.service.BasicPullRequestEvent; -
- 8 - - 4 - - import com.cloudogu.scm.review.pullrequest.service.PullRequest; -
- 9 - - - import com.cloudogu.scm.review.pullrequest.service.PullRequestEvent; -
- 10 - - 5 - - import com.github.legman.Subscribe; -
- 11 - - - import lombok.Data; -
- 12 - - 6 - - import org.apache.shiro.SecurityUtils; -
- 13 - - 7 - - import org.apache.shiro.subject.PrincipalCollection; -
- 14 - - 8 - - import org.apache.shiro.subject.Subject; -
- 15 - - 9 - - import sonia.scm.EagerSingleton; -
- 16 - - - import sonia.scm.HandlerEventType; -
- 17 - - - import sonia.scm.event.HandlerEvent; -
- 18 - - 10 - - import sonia.scm.plugin.Extension; -
- 19 - - 11 - - import sonia.scm.repository.Repository; -
- 20 - - 12 - - import sonia.scm.security.SessionId; -
-
-
-
-
-
- - - src/main/js/ChangeNotification.tsx - - - modify - -
-
-
-
- - - - - -
-
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - + + + + - 6 - - + + + + - - - - - - - - - - - - - - - - - + - - - - - + + - 15 - - + + + - 16 - - + + + - pullRequest: setEvent - - - - + + + - 16 - - + + + + - 17 - - + + + + - }); - - - - + + + - 17 - - + + + + - 18 - - + + + - }, [url]); - - - - + + + + - 19 - - + + + + - const { t } = useTranslation("plugins"); - - - - + + + + - 18 - - + + + + - 20 - - + + + - if (event) { - - - - + + + - 19 - - + + + + - 21 - - + + + + - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- 2 - - 2 - - import { Link } from "@scm-manager/ui-types"; -
- 3 - - 3 - - import { apiClient, Toast, ToastButtons, ToastButton } from "@scm-manager/ui-components"; -
- 4 - - 4 - - import { PullRequest } from "./types/PullRequest"; -
+
- 5 - - import { useTranslation } from "react-i18next"; -
- 5 - + 1 + + 1 + + package com.cloudogu.scm.review.events; +
+ 2 + + 2 + + +
- 6 - - 7 - - type HandlerProps = { -
- 7 - - 8 - - url: string; -
-
+ 3 +
-
+ import com.cloudogu.scm.review.comment.service.BasicComment; +
+ 4 + + + import com.cloudogu.scm.review.comment.service.BasicCommentEvent; +
+ 5 + + + import com.cloudogu.scm.review.comment.service.CommentEvent; +
+ 6 + + + import com.cloudogu.scm.review.comment.service.ReplyEvent; +
+ 7 + + 3 + + import com.cloudogu.scm.review.pullrequest.service.BasicPullRequestEvent; +
+ 8 + + 4 + + import com.cloudogu.scm.review.pullrequest.service.PullRequest; +
+ 9 + + + import com.cloudogu.scm.review.pullrequest.service.PullRequestEvent; +
+ 10 + + 5 + + import com.github.legman.Subscribe; +
+ 11 + + + import lombok.Data; +
- + 12 + + 6 + + import org.apache.shiro.SecurityUtils; +
+ 13 + + 7 + + import org.apache.shiro.subject.PrincipalCollection; +
+ 14 + + 8 + + import org.apache.shiro.subject.Subject; +
+ 15 + + 9 + + import sonia.scm.EagerSingleton; +
+ 16 + + + import sonia.scm.HandlerEventType; +
+ 17 + + + import sonia.scm.event.HandlerEvent; +
+ 18 + + 10 + + import sonia.scm.plugin.Extension; +
+ 19 + + 11 + + import sonia.scm.repository.Repository; +
- 20 - - - <Toast type="warning" title="New Changes"> -
- 21 - - - <p>The underlying Pull-Request has changed. Press reload to see the changes.</p> -
- 22 - - - <p>Warning: Non saved modification will be lost.</p> -
- - 22 - - <Toast type="warning" title={t("scm-review-plugin.changeNotification.title")}> -
- - 23 - - <p>{t("scm-review-plugin.changeNotification.description")}</p> -
- - 24 - - <p>{t("scm-review-plugin.changeNotification.modificationWarning")}</p> -
- 23 - - 25 - - <ToastButtons> -
- 24 - - - <ToastButton icon="redo" onClick={reload}>Reload</ToastButton> -
- 25 - - - <ToastButton icon="times" onClick={() => setEvent(undefined)}>Ignore</ToastButton> -
- - 26 - - <ToastButton icon="redo" onClick={reload}> -
- - 27 - - {t("scm-review-plugin.changeNotification.buttons.reload")} -
- - 28 - - </ToastButton> -
- - 29 - - <ToastButton icon="times" onClick={() => setEvent(undefined)}> -
- - 30 - - {t("scm-review-plugin.changeNotification.buttons.ignore")} -
- - 31 - - </ToastButton> -
- 26 - - 32 - - </ToastButtons> -
- 27 - - 33 - - </Toast> -
- 28 - - 34 - - ); -
+ + 20 + + + 12 + + + import sonia.scm.security.SessionId; + + + + +
-
-
- - - src/main/resources/locales/de/plugins.json - - - modify - -
-
+ + + src/main/js/ChangeNotification.tsx + + + modify + +
+
- - - - - + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 2 + + 2 + + import { Link } from "@scm-manager/ui-types"; +
+ 3 + + 3 + + import { apiClient, Toast, ToastButtons, ToastButton } from "@scm-manager/ui-components"; +
+ 4 + + 4 + + import { PullRequest } from "./types/PullRequest"; +
+ + 5 + + import { useTranslation } from "react-i18next"; +
+ 5 + + 6 + + +
+ 6 + + 7 + + type HandlerProps = { +
+ 7 + + 8 + + url: string; +
+
+
+ 15 + + 16 + + pullRequest: setEvent +
+ 16 + + 17 + + }); +
+ 17 + + 18 + + }, [url]); +
+ + 19 + + const { t } = useTranslation("plugins"); +
+ 18 + + 20 + + if (event) { +
+ 19 + + 21 + + return ( +
+ 20 + + + <Toast type="warning" title="New Changes"> +
+ 21 + + + <p>The underlying Pull-Request has changed. Press reload to see the changes.</p> +
+ 22 + + + <p>Warning: Non saved modification will be lost.</p> +
+ + 22 + + <Toast type="warning" title={t("scm-review-plugin.changeNotification.title")}> +
+ + 23 + + <p>{t("scm-review-plugin.changeNotification.description")}</p> +
+ + 24 + + <p>{t("scm-review-plugin.changeNotification.modificationWarning")}</p> +
+ 23 + + 25 + + <ToastButtons> +
+ 24 + + + <ToastButton icon="redo" onClick={reload}>Reload</ToastButton> +
+ 25 + + + <ToastButton icon="times" onClick={() => setEvent(undefined)}>Ignore</ToastButton> +
+ + 26 + + <ToastButton icon="redo" onClick={reload}> +
+ + 27 + + {t("scm-review-plugin.changeNotification.buttons.reload")} +
+ + 28 + + </ToastButton> +
+ + 29 + + <ToastButton icon="times" onClick={() => setEvent(undefined)}> +
+ + 30 + + {t("scm-review-plugin.changeNotification.buttons.ignore")} +
+ + 31 + + </ToastButton> +
+ 26 + + 32 + + </ToastButtons> +
+ 27 + + 33 + + </Toast> +
+ 28 + + 34 + + ); +
+
- - - - - - - - - - - - - + +
-
- + + + + +
+ - 181 - + - 181 - - "titleClickable": "Der Kommentar bezieht sich auf eine ältere Version des Source- oder Target-Branches. Klicken Sie hier, um den ursprünglichen Kontext zu sehen." -
- 182 - + + + + + + + + + + +
+ + + + + + + + - 182 - - + + + + + + + + + + + + - - - + - 183 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ 181 + + 181 + + "titleClickable": "Der Kommentar bezieht sich auf eine ältere Version des Source- oder Target-Branches. Klicken Sie hier, um den ursprünglichen Kontext zu sehen." +
+ 182 + + 182 + + } +
+ 183 + + 183 + } -
+
- 183 - - } -
- - 184 - - }, -
- - 185 - - "changeNotification": { -
- - 186 - - "title": "Neue Änderungen", -
- - 187 - - "description": "An diesem Pull Request wurden Änderungen vorgenommen. Laden Sie die Seite neu um diese anzuzeigen.", -
- - 188 - - "modificationWarning": "Warnung: Nicht gespeicherte Eingaben gehen verloren.", -
- - 189 - - "buttons": { -
- - 190 - - "reload": "Neu laden", -
- - 191 - - "ignore": "Ignorieren" -
- - 192 - - } -
- 184 - - 193 - - } -
- 185 - - 194 - - }, -
- 186 - - 195 - - "permissions": { -
-
- -
-
-
-
- - - src/main/resources/locales/en/plugins.json - - - modify - -
-
-
-
- +
- - - - - - - - - -
- - - - - - - - - + + - 181 - - + + + - 181 - - + + + - "titleClickable": "The comment is related to an older of the source or target branch. Click here to see the original context." - - - - + + + - 182 - - + + + - 182 - - + + + + + + + + + + + + + - - - - - + + + + - - - - + + + + - - - + - 185 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ + }, +
+ + 185 + + "changeNotification": { +
+ + 186 + + "title": "Neue Änderungen", +
+ + 187 + + "description": "An diesem Pull Request wurden Änderungen vorgenommen. Laden Sie die Seite neu um diese anzuzeigen.", +
+ + 188 + + "modificationWarning": "Warnung: Nicht gespeicherte Eingaben gehen verloren.", +
+ + 189 + + "buttons": { +
+ + 190 + + "reload": "Neu laden", +
+ + 191 + + "ignore": "Ignorieren" +
+ + 192 + } -
- 183 - - 183 - +
+ 184 + + 193 + } -
- - 184 - +
+ 185 + + 194 + }, -
- +
- "changeNotification": { -
- - 186 - - "title": "New Changes", -
- - 187 - - "description": "The underlying Pull-Request has changed. Press reload to see the changes.", -
- - 188 - - "modificationWarning": "Warning: Non saved modification will be lost.", -
- - 189 - - "buttons": { -
- - 190 - - "reload": "Reload", -
- - 191 - - "ignore": "Ignore" -
- - 192 - - } -
- 184 - - 193 - - } -
- 185 - - 194 - - }, -
- 186 - - 195 - - "permissions": { -
+
+ 186 + + 195 + + "permissions": { +
+
- -
- - - src/test/java/com/cloudogu/scm/review/events/ClientTest.java - - - modify - -
-
+ + + src/main/resources/locales/en/plugins.json + + + modify + +
+
- - - - - + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 181 + + 181 + + "titleClickable": "The comment is related to an older of the source or target branch. Click here to see the original context." +
+ 182 + + 182 + + } +
+ 183 + + 183 + + } +
+ + 184 + + }, +
+ + 185 + + "changeNotification": { +
+ + 186 + + "title": "New Changes", +
+ + 187 + + "description": "The underlying Pull-Request has changed. Press reload to see the changes.", +
+ + 188 + + "modificationWarning": "Warning: Non saved modification will be lost.", +
+ + 189 + + "buttons": { +
+ + 190 + + "reload": "Reload", +
+ + 191 + + "ignore": "Ignore" +
+ + 192 + + } +
+ 184 + + 193 + + } +
+ 185 + + 194 + + }, +
+ 186 + + 195 + + "permissions": { +
+
- - - - - - - - - - - - - - - - - - - - - - - - - - - + +
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + +
+
- 7 - - 7 - - import org.mockito.Mock; -
- 8 - - 8 - - import org.mockito.junit.jupiter.MockitoExtension; -
- 9 - - 9 - - import sonia.scm.security.SessionId; -
- - 10 - + - -
- 10 - - 11 - - import javax.ws.rs.sse.OutboundSseEvent; -
- 11 - - 12 - - import javax.ws.rs.sse.SseEventSink; -
- 12 - - - -
- 13 - - 13 - - import java.time.Clock; -
- 14 - - 14 - - import java.time.Instant; -
- 15 - - 15 - - import java.time.LocalDateTime; -
- 16 - - 16 - - import java.time.ZoneOffset; -
- 17 - - 17 - - import java.time.temporal.ChronoField; -
- 18 - - - import java.time.temporal.ChronoUnit; -
- 19 - - - import java.time.temporal.TemporalField; -
- 20 - - 18 - - import java.util.concurrent.CompletableFuture; -
- 21 - - 19 - - import java.util.concurrent.CompletionStage; -
- 22 - - - import java.util.concurrent.atomic.AtomicLong; -
- 23 - - 20 - - import java.util.concurrent.atomic.AtomicReference; -
- 24 - - 21 - - -
- 25 - - 22 - - import static java.time.temporal.ChronoUnit.MINUTES; -
- - + + + + + -
+ 7 + +
+ + + + + + + + + + + + + + - - - - - + + + - 83 - - + + + + - 80 - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ 7 + + import org.mockito.Mock; +
+ 8 + + 8 + + import org.mockito.junit.jupiter.MockitoExtension; +
+ 9 + + 9 + + import sonia.scm.security.SessionId; +
-
+ 10 + + +
+ 10 + + 11 + + import javax.ws.rs.sse.OutboundSseEvent; +
+ 11 + + 12 + + import javax.ws.rs.sse.SseEventSink; +
- 84 - - 81 - - @Test -
- 85 - - 82 - - @SuppressWarnings("unchecked") -
- 86 - - - void shouldCloseEventSinkOnFailure() throws InterruptedException { -
- - 83 - - void shouldCloseEventSinkOnFailure() { -
- 87 - - 84 - - CompletionStage future = CompletableFuture.supplyAsync(() -> { -
- 88 - - 85 - - throw new RuntimeException("failed to send message"); -
- 89 - - 86 - - }); -
-
+ 12 +
-
+ 13 + + 13 + + import java.time.Clock; +
+ 14 + + 14 + + import java.time.Instant; +
+ 15 + + 15 + + import java.time.LocalDateTime; +
+ 16 + + 16 + + import java.time.ZoneOffset; +
+ 17 + + 17 + + import java.time.temporal.ChronoField; +
+ 18 + + + import java.time.temporal.ChronoUnit; +
+ 19 + + + import java.time.temporal.TemporalField; +
+ 20 + + 18 + + import java.util.concurrent.CompletableFuture; +
+ 21 + + 19 + + import java.util.concurrent.CompletionStage; +
+ 22 + + + import java.util.concurrent.atomic.AtomicLong; +
+ 23 + + 20 + + import java.util.concurrent.atomic.AtomicReference; +
+ 24 + + 21 + + +
+ 25 + + 22 + + import static java.time.temporal.ChronoUnit.MINUTES; +
+
+
+ 83 + + 80 + + +
+ 84 + + 81 + + @Test +
+ 85 + + 82 + + @SuppressWarnings("unchecked") +
+ 86 + + + void shouldCloseEventSinkOnFailure() throws InterruptedException { +
+ + 83 + + void shouldCloseEventSinkOnFailure() { +
+ 87 + + 84 + + CompletionStage future = CompletableFuture.supplyAsync(() -> { +
+ 88 + + 85 + + throw new RuntimeException("failed to send message"); +
+ 89 + + 86 + + }); +
+
+
+ 91 + + 88 + + +
+ 92 + + 89 + + client.send(message); +
+ 93 + + 90 + + +
+ 94 + + + Thread.sleep(50L); +
+ 95 + + + +
+ 96 + + + verify(eventSink).close(); +
+ + 91 + + verify(eventSink, timeout(50L)).close(); +
+ 97 + + 92 + + } +
+ 98 + + 93 + + +
+ 99 + + 94 + + @Test +
+
+ +
+
+
- - - 91 - - - 88 - - - - - - - - 92 - - - 89 - - - client.send(message); - - - - - 93 - - - 90 - - - - - - - - 94 - - - - Thread.sleep(50L); - - - + + modify + +
+
- - 95 - - + + + + + +
+
+
+ + +
+ + + - - - - - - - + + - - + + + - verify(eventSink, timeout(50L)).close(); - - - - + + + + - 97 - - + + + + - 92 - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - -
- -
- 96 - - - verify(eventSink).close(); -
- - 91 - + + 1 + + import java.io.PrintStream; +
+ 1 + + 2 + + import java.util.Arrays; +
+ 2 + + 3 + + +
+ 3 + + 4 + + class Main { +
+ + 5 + + private static final PrintStream OUT = System.out; +
+ + 6 + + +
+ 4 + + 7 + + public static void main(String[] args) { +
+ + 8 + + <<<<<<< HEAD +
+ 5 + + 9 + + System.out.println("Expect nothing more to happen."); +
+ 6 + + 10 + + System.out.println("The command line parameters are:"); +
+ 7 + + 11 + + Arrays.stream(args).map(arg -> "- " + arg).forEach(System.out::println); +
+ + 12 + + ======= +
+ + 13 + + OUT.println("Expect nothing more to happen."); +
+ + 14 + + OUT.println("Parameters:"); +
+ + 15 + + Arrays.stream(args).map(arg -> "- " + arg).forEach(OUT::println); +
+ + 16 + + >>>>>>> feature/use_constant +
+ 8 + + 17 + + } +
+ 9 + + 18 + } -
- 98 - - 93 - - -
- 99 - - 94 - - @Test -
-
- -
-
-
-
- - - Main.java - - - modify - -
-
-
-
- - - - - -
-
-
+ + + +
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - 1 - - import java.io.PrintStream; -
- 1 - - 2 - - import java.util.Arrays; -
- 2 - - 3 - - -
- 3 - - 4 - - class Main { -
- - 5 - - private static final PrintStream OUT = System.out; -
- - 6 - - -
- 4 - - 7 - - public static void main(String[] args) { -
- - 8 - - <<<<<<< HEAD -
- 5 - - 9 - - System.out.println("Expect nothing more to happen."); -
- 6 - - 10 - - System.out.println("The command line parameters are:"); -
- 7 - - 11 - - Arrays.stream(args).map(arg -> "- " + arg).forEach(System.out::println); -
- - 12 - - ======= -
- - 13 - - OUT.println("Expect nothing more to happen."); -
- - 14 - - OUT.println("Parameters:"); -
- - 15 - - Arrays.stream(args).map(arg -> "- " + arg).forEach(OUT::println); -
- - 16 - - >>>>>>> feature/use_constant -
- 8 - - 17 - - } -
- 9 - - 18 - - } -
-
`; @@ -39581,4304 +39668,4312 @@ exports[`Storyshots Diff WithLinkToFile 1`] = `
-
+
- - - src/main/java/com/cloudogu/scm/review/events/EventListener.java - - - modify - -
-
+ + + src/main/java/com/cloudogu/scm/review/events/EventListener.java + + + modify + +
+
- - - - - + + + + +
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - -
- 1 - - 1 - - package com.cloudogu.scm.review.events; -
- 2 - - 2 - - -
- 3 - +
- import com.cloudogu.scm.review.comment.service.BasicComment; -
- 4 - - - import com.cloudogu.scm.review.comment.service.BasicCommentEvent; -
- 5 - - - import com.cloudogu.scm.review.comment.service.CommentEvent; -
- 6 - - - import com.cloudogu.scm.review.comment.service.ReplyEvent; -
- 7 - - 3 - - import com.cloudogu.scm.review.pullrequest.service.BasicPullRequestEvent; -
- 8 - - 4 - - import com.cloudogu.scm.review.pullrequest.service.PullRequest; -
- 9 - - - import com.cloudogu.scm.review.pullrequest.service.PullRequestEvent; -
- 10 - - 5 - - import com.github.legman.Subscribe; -
- 11 - - - import lombok.Data; -
- 12 - - 6 - - import org.apache.shiro.SecurityUtils; -
- 13 - - 7 - - import org.apache.shiro.subject.PrincipalCollection; -
- 14 - - 8 - - import org.apache.shiro.subject.Subject; -
- 15 - - 9 - - import sonia.scm.EagerSingleton; -
- 16 - - - import sonia.scm.HandlerEventType; -
- 17 - - - import sonia.scm.event.HandlerEvent; -
- 18 - - 10 - - import sonia.scm.plugin.Extension; -
- 19 - - 11 - - import sonia.scm.repository.Repository; -
- 20 - - 12 - - import sonia.scm.security.SessionId; -
-
+ 1 +
+ 1 + + package com.cloudogu.scm.review.events; +
+ 2 + + 2 + - - - - diff.expandLastBottomByLines - - +
+ 3 + + + import com.cloudogu.scm.review.comment.service.BasicComment; +
+ 4 + + + import com.cloudogu.scm.review.comment.service.BasicCommentEvent; +
+ 5 + + + import com.cloudogu.scm.review.comment.service.CommentEvent; +
+ 6 + + + import com.cloudogu.scm.review.comment.service.ReplyEvent; +
+ 7 + + 3 + + import com.cloudogu.scm.review.pullrequest.service.BasicPullRequestEvent; +
+ 8 + + 4 + + import com.cloudogu.scm.review.pullrequest.service.PullRequest; +
+ 9 + + + import com.cloudogu.scm.review.pullrequest.service.PullRequestEvent; +
+ 10 + + 5 + + import com.github.legman.Subscribe; +
+ 11 + + + import lombok.Data; +
+ 12 + + 6 + + import org.apache.shiro.SecurityUtils; +
+ 13 + + 7 + + import org.apache.shiro.subject.PrincipalCollection; +
+ 14 + + 8 + + import org.apache.shiro.subject.Subject; +
+ 15 + + 9 + + import sonia.scm.EagerSingleton; +
+ 16 + + + import sonia.scm.HandlerEventType; +
+ 17 + + + import sonia.scm.event.HandlerEvent; +
+ 18 + + 10 + + import sonia.scm.plugin.Extension; +
+ 19 + + 11 + + import sonia.scm.repository.Repository; +
+ 20 + + 12 + + import sonia.scm.security.SessionId; +
+
- + + + + diff.expandLastBottomByLines + - diff.expandLastBottomComplete - -
-
+ + + + diff.expandLastBottomComplete + +
+ + + + +
- -
- - - src/main/js/ChangeNotification.tsx - - - modify - -
-
+ + + src/main/js/ChangeNotification.tsx + + + modify + +
+
- - - - - + + + + +
-
-
- - - - - - - - - + + + + + + - - - - + + + diff.expandComplete + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - -
-
+
- - - - diff.expandComplete - - -
- 2 - - 2 - - import { Link } from "@scm-manager/ui-types"; -
- 3 - - 3 - - import { apiClient, Toast, ToastButtons, ToastButton } from "@scm-manager/ui-components"; -
- 4 - - 4 - - import { PullRequest } from "./types/PullRequest"; -
- - 5 - - import { useTranslation } from "react-i18next"; -
- 5 - - 6 - - -
- 6 - - 7 - - type HandlerProps = { -
- 7 - - 8 - - url: string; -
-
- - - - diff.expandComplete - -
-
-
+
- - - - diff.expandComplete - - -
- 15 - - 16 - - pullRequest: setEvent -
- 16 - - 17 - - }); -
- 17 - - 18 - - }, [url]); -
- - 19 - - const { t } = useTranslation("plugins"); -
- 18 - - 20 - - if (event) { -
- 19 - - 21 - - return ( -
- 20 - - - <Toast type="warning" title="New Changes"> -
- 21 - - - <p>The underlying Pull-Request has changed. Press reload to see the changes.</p> -
- 22 - - - <p>Warning: Non saved modification will be lost.</p> -
- - 22 - - <Toast type="warning" title={t("scm-review-plugin.changeNotification.title")}> -
- - 23 - - <p>{t("scm-review-plugin.changeNotification.description")}</p> -
- - 24 - - <p>{t("scm-review-plugin.changeNotification.modificationWarning")}</p> -
- 23 - - 25 - - <ToastButtons> -
- 24 - - - <ToastButton icon="redo" onClick={reload}>Reload</ToastButton> -
- 25 - - - <ToastButton icon="times" onClick={() => setEvent(undefined)}>Ignore</ToastButton> -
- - 26 - - <ToastButton icon="redo" onClick={reload}> -
- - 27 - - {t("scm-review-plugin.changeNotification.buttons.reload")} -
- - 28 - - </ToastButton> -
- - 29 - - <ToastButton icon="times" onClick={() => setEvent(undefined)}> -
- - 30 - - {t("scm-review-plugin.changeNotification.buttons.ignore")} -
- - 31 - - </ToastButton> -
- 26 - - 32 - - </ToastButtons> -
- 27 - - 33 - - </Toast> -
- 28 - - 34 - - ); -
-
+
+ import { Link } from "@scm-manager/ui-types"; +
+ 3 + + 3 + + import { apiClient, Toast, ToastButtons, ToastButton } from "@scm-manager/ui-components"; +
+ 4 + + 4 + + import { PullRequest } from "./types/PullRequest"; +
+ + 5 + + import { useTranslation } from "react-i18next"; +
+ 5 + + 6 + - - - - diff.expandLastBottomByLines - - +
+ 6 + + 7 + + type HandlerProps = { +
+ 7 + + 8 + + url: string; +
+
- + + + + diff.expandComplete + +
+
+
+ + + + diff.expandComplete + +
+
+ 15 + + 16 + + pullRequest: setEvent +
+ 16 + + 17 + + }); +
+ 17 + + 18 + + }, [url]); +
+ + 19 + + const { t } = useTranslation("plugins"); +
+ 18 + + 20 + + if (event) { +
+ 19 + + 21 + + return ( +
+ 20 + + + <Toast type="warning" title="New Changes"> +
+ 21 + + + <p>The underlying Pull-Request has changed. Press reload to see the changes.</p> +
+ 22 + + + <p>Warning: Non saved modification will be lost.</p> +
+ + 22 + + <Toast type="warning" title={t("scm-review-plugin.changeNotification.title")}> +
+ + 23 + + <p>{t("scm-review-plugin.changeNotification.description")}</p> +
+ + 24 + + <p>{t("scm-review-plugin.changeNotification.modificationWarning")}</p> +
+ 23 + + 25 + + <ToastButtons> +
+ 24 + + + <ToastButton icon="redo" onClick={reload}>Reload</ToastButton> +
+ 25 + + + <ToastButton icon="times" onClick={() => setEvent(undefined)}>Ignore</ToastButton> +
+ + 26 + + <ToastButton icon="redo" onClick={reload}> +
+ + 27 + + {t("scm-review-plugin.changeNotification.buttons.reload")} +
+ + 28 + + </ToastButton> +
+ + 29 + + <ToastButton icon="times" onClick={() => setEvent(undefined)}> +
+ + 30 + + {t("scm-review-plugin.changeNotification.buttons.ignore")} +
+ + 31 + + </ToastButton> +
+ 26 + + 32 + + </ToastButtons> +
+ 27 + + 33 + + </Toast> +
+ 28 + + 34 + + ); +
+
+ + + + diff.expandLastBottomByLines + - diff.expandLastBottomComplete - -
-
+ + + + diff.expandLastBottomComplete + +
+ + + + + - -
- - - src/main/resources/locales/de/plugins.json - - - modify - -
-
+ + + src/main/resources/locales/de/plugins.json + + + modify + +
+
- - - - - + + + + +
-
-
- - - - - - - - - + + + + + + - - - - + + + diff.expandComplete + + + + + + - - + + + + - 181 - - - - - - - + + + + + + + - - - + - 183 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
+
- - + + + + diff.expandByLines + - diff.expandByLines - - - - - - diff.expandComplete - - -
- 181 - + 181 + + 181 + + "titleClickable": "Der Kommentar bezieht sich auf eine ältere Version des Source- oder Target-Branches. Klicken Sie hier, um den ursprünglichen Kontext zu sehen." +
- "titleClickable": "Der Kommentar bezieht sich auf eine ältere Version des Source- oder Target-Branches. Klicken Sie hier, um den ursprünglichen Kontext zu sehen." -
- 182 - - 182 - + 182 + + 182 + + } +
+ 183 + + 183 + } -
+
- 183 - - } -
- - 184 - - }, -
- - 185 - - "changeNotification": { -
- - 186 - - "title": "Neue Änderungen", -
- - 187 - - "description": "An diesem Pull Request wurden Änderungen vorgenommen. Laden Sie die Seite neu um diese anzuzeigen.", -
- - 188 - - "modificationWarning": "Warnung: Nicht gespeicherte Eingaben gehen verloren.", -
- - 189 - - "buttons": { -
- - 190 - - "reload": "Neu laden", -
- - 191 - - "ignore": "Ignorieren" -
- - 192 - - } -
- 184 - - 193 - - } -
- 185 - - 194 - - }, -
- 186 - - 195 - - "permissions": { -
-
+
- - - - diff.expandLastBottomByLines - - - - - - diff.expandLastBottomComplete - - -
-
- -
-
-
-
- - - src/main/resources/locales/en/plugins.json - - - modify - -
-
-
-
- + - - - - -
-
-
-
-
-
- - - - - - - - - + -
+
- - - - - + + - 181 - - + + + - 181 - - + + + - "titleClickable": "The comment is related to an older of the source or target branch. Click here to see the original context." - - - - + + + - 182 - - + + + - 182 - - + + + + + + + + + - - - + - 183 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - -
+
- - - - diff.expandByLines - - - - - - diff.expandComplete - - -
+ + "changeNotification": { +
+ + 186 + + "title": "Neue Änderungen", +
+ + 187 + + "description": "An diesem Pull Request wurden Änderungen vorgenommen. Laden Sie die Seite neu um diese anzuzeigen.", +
+ + 188 + + "modificationWarning": "Warnung: Nicht gespeicherte Eingaben gehen verloren.", +
+ + 189 + + "buttons": { +
+ + 190 + + "reload": "Neu laden", +
+ + 191 + + "ignore": "Ignorieren" +
+ + 192 + } -
+
- 183 - - } -
- - 184 - - }, -
- - 185 - - "changeNotification": { -
- - 186 - - "title": "New Changes", -
- - 187 - - "description": "The underlying Pull-Request has changed. Press reload to see the changes.", -
- - 188 - - "modificationWarning": "Warning: Non saved modification will be lost.", -
- - 189 - - "buttons": { -
- - 190 - - "reload": "Reload", -
- - 191 - - "ignore": "Ignore" -
- - 192 - - } -
- 184 - - 193 - - } -
- 185 - - 194 - - }, -
- 186 - - 195 - - "permissions": { -
-
- +
+ 193 + + } +
+ 185 + + 194 + + }, +
+ 186 + + 195 + + "permissions": { +
+
- + + + + diff.expandLastBottomByLines + - diff.expandLastBottomByLines - - - - - - diff.expandLastBottomComplete - -
-
+ + + + diff.expandLastBottomComplete + +
+ + + + +
- -
- - - src/test/java/com/cloudogu/scm/review/events/ClientTest.java - - - modify - -
-
+ + + src/main/resources/locales/en/plugins.json + + + modify + +
+
- - - - - + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + diff.expandByLines + + + + + + diff.expandComplete + +
+
+ 181 + + 181 + + "titleClickable": "The comment is related to an older of the source or target branch. Click here to see the original context." +
+ 182 + + 182 + + } +
+ 183 + + 183 + + } +
+ + 184 + + }, +
+ + 185 + + "changeNotification": { +
+ + 186 + + "title": "New Changes", +
+ + 187 + + "description": "The underlying Pull-Request has changed. Press reload to see the changes.", +
+ + 188 + + "modificationWarning": "Warning: Non saved modification will be lost.", +
+ + 189 + + "buttons": { +
+ + 190 + + "reload": "Reload", +
+ + 191 + + "ignore": "Ignore" +
+ + 192 + + } +
+ 184 + + 193 + + } +
+ 185 + + 194 + + }, +
+ 186 + + 195 + + "permissions": { +
+
+ + + + diff.expandLastBottomByLines + + + + + + diff.expandLastBottomComplete + +
+
+
- - - - - - - - - - - - + + + +
+
+ + + src/test/java/com/cloudogu/scm/review/events/ClientTest.java + + + modify + + +
+
- - - diff.expandComplete + + +
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - + -
+ 10 + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + diff.expandComplete + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
- 7 - - 7 - - import org.mockito.Mock; -
- 8 - - 8 - - import org.mockito.junit.jupiter.MockitoExtension; -
- 9 - - 9 - - import sonia.scm.security.SessionId; -
+
- 10 - - -
- 10 - - 11 - - import javax.ws.rs.sse.OutboundSseEvent; -
- 11 - - 12 - - import javax.ws.rs.sse.SseEventSink; -
- 12 - - - -
- 13 - - 13 - - import java.time.Clock; -
- 14 - - 14 - - import java.time.Instant; -
- 15 - - 15 - - import java.time.LocalDateTime; -
- 16 - - 16 - - import java.time.ZoneOffset; -
- 17 - - 17 - - import java.time.temporal.ChronoField; -
- 18 - - - import java.time.temporal.ChronoUnit; -
- 19 - - - import java.time.temporal.TemporalField; -
- 20 - - 18 - - import java.util.concurrent.CompletableFuture; -
- 21 - - 19 - - import java.util.concurrent.CompletionStage; -
- 22 - - - import java.util.concurrent.atomic.AtomicLong; -
- 23 - - 20 - - import java.util.concurrent.atomic.AtomicReference; -
- 24 - - 21 - - -
- 25 - - 22 - - import static java.time.temporal.ChronoUnit.MINUTES; -
-
+
- - - - diff.expandByLines - + + + + diff.expandComplete + + +
+ 7 + + 7 + + import org.mockito.Mock; +
+ 8 + + 8 + + import org.mockito.junit.jupiter.MockitoExtension; +
+ 9 + + 9 + + import sonia.scm.security.SessionId; +
+ + 10 + - - - - diff.expandComplete - - -
+
+ 11 + + import javax.ws.rs.sse.OutboundSseEvent; +
+ 11 + + 12 + + import javax.ws.rs.sse.SseEventSink; +
+ 12 + + - - - - diff.expandByLines - - +
+ 13 + + 13 + + import java.time.Clock; +
+ 14 + + 14 + + import java.time.Instant; +
+ 15 + + 15 + + import java.time.LocalDateTime; +
+ 16 + + 16 + + import java.time.ZoneOffset; +
+ 17 + + 17 + + import java.time.temporal.ChronoField; +
+ 18 + + + import java.time.temporal.ChronoUnit; +
+ 19 + + + import java.time.temporal.TemporalField; +
+ 20 + + 18 + + import java.util.concurrent.CompletableFuture; +
+ 21 + + 19 + + import java.util.concurrent.CompletionStage; +
+ 22 + + + import java.util.concurrent.atomic.AtomicLong; +
+ 23 + + 20 + + import java.util.concurrent.atomic.AtomicReference; +
+ 24 + + 21 + + +
+ 25 + + 22 + + import static java.time.temporal.ChronoUnit.MINUTES; +
+
- + + + + diff.expandByLines + - diff.expandComplete - -
-
+
+ + + + diff.expandByLines + + + + + + diff.expandComplete + +
+
+ 83 + + 80 + + +
+ 84 + + 81 + + @Test +
+ 85 + + 82 + + @SuppressWarnings("unchecked") +
+ 86 + + + void shouldCloseEventSinkOnFailure() throws InterruptedException { +
+ + 83 + + void shouldCloseEventSinkOnFailure() { +
+ 87 + + 84 + + CompletionStage future = CompletableFuture.supplyAsync(() -> { +
+ 88 + + 85 + + throw new RuntimeException("failed to send message"); +
+ 89 + + 86 + + }); +
+
+ + + + diff.expandComplete + +
+
+
+ + + + diff.expandComplete + +
+
+ 91 + + 88 + + +
+ 92 + + 89 + + client.send(message); +
+ 93 + + 90 + + +
+ 94 + + + Thread.sleep(50L); +
+ 95 + + + +
+ 96 + + + verify(eventSink).close(); +
+ + 91 + + verify(eventSink, timeout(50L)).close(); +
+ 97 + + 92 + + } +
+ 98 + + 93 + + +
+ 99 + + 94 + + @Test +
+
+ + + + diff.expandLastBottomByLines + + + + + + diff.expandLastBottomComplete + +
+
+
+ +
+
+
- - - 83 - - - 80 - - - - - - - - 84 - - - 81 - - - @Test - - - - - 85 - - - 82 - - - @SuppressWarnings("unchecked") - - - - - 86 - - - - void shouldCloseEventSinkOnFailure() throws InterruptedException { - - - + + modify + +
+
- - - 83 - - - void shouldCloseEventSinkOnFailure() { - - - - - 87 - - - 84 - - - CompletionStage future = CompletableFuture.supplyAsync(() -> { - - - - - 88 - - - 85 - - - throw new RuntimeException("failed to send message"); - - - - - 89 - - - 86 - - - }); - - - - - -
- - - diff.expandComplete + + +
- - - - +
+
+
+
+ - - + + + + + + -
+
- - - - - + + - 91 - - + + + + - 88 - - + + + + - - - - - + + + + - 92 - - + + + - 89 - - + + + - client.send(message); - - - - + + + + - 93 - - + + + - 90 - - + + + + - - - - - + + + + - 94 - - + + + + - Thread.sleep(50L); - - - - + + + - 95 - - + + + - - - - - + + + - 96 - - + + + - verify(eventSink).close(); - - - - + + + - 91 - - - - - - - + + + + + + + - - + + + - - - - - - - - - - - - - - - -
+
- - - - diff.expandComplete - - -
+ + import java.io.PrintStream; +
+ 1 + + 2 + + import java.util.Arrays; +
+ 2 + + 3 + + +
+ 3 + + 4 + + class Main { +
+ + 5 + + private static final PrintStream OUT = System.out; +
+ + 6 + + +
+ 4 + + 7 + + public static void main(String[] args) { +
+ + 8 + + <<<<<<< HEAD +
+ 5 + + 9 + + System.out.println("Expect nothing more to happen."); +
+ 6 + + 10 + + System.out.println("The command line parameters are:"); +
- + 7 + + 11 + + Arrays.stream(args).map(arg -> "- " + arg).forEach(System.out::println); +
+ + 12 + + ======= +
- + + 13 + + OUT.println("Expect nothing more to happen."); +
+ + 14 + + OUT.println("Parameters:"); +
- + + 15 + + Arrays.stream(args).map(arg -> "- " + arg).forEach(OUT::println); +
- + + 16 + + >>>>>>> feature/use_constant +
- verify(eventSink, timeout(50L)).close(); -
- 97 - - 92 - + 8 + + 17 + + } +
+ 9 + + 18 + } -
- 98 - - 93 - - -
- 99 - - 94 - - @Test -
-
+
- - + + + + diff.expandLastBottomByLines + - diff.expandLastBottomByLines - - - - - - diff.expandLastBottomComplete - - -
-
- -
-
-
-
- - - Main.java - - - modify - -
-
-
-
- - - - - -
-
-
+ + + + diff.expandLastBottomComplete + +
+ + + +
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - 1 - - import java.io.PrintStream; -
- 1 - - 2 - - import java.util.Arrays; -
- 2 - - 3 - - -
- 3 - - 4 - - class Main { -
- - 5 - - private static final PrintStream OUT = System.out; -
- - 6 - - -
- 4 - - 7 - - public static void main(String[] args) { -
- - 8 - - <<<<<<< HEAD -
- 5 - - 9 - - System.out.println("Expect nothing more to happen."); -
- 6 - - 10 - - System.out.println("The command line parameters are:"); -
- 7 - - 11 - - Arrays.stream(args).map(arg -> "- " + arg).forEach(System.out::println); -
- - 12 - - ======= -
- - 13 - - OUT.println("Expect nothing more to happen."); -
- - 14 - - OUT.println("Parameters:"); -
- - 15 - - Arrays.stream(args).map(arg -> "- " + arg).forEach(OUT::println); -
- - 16 - - >>>>>>> feature/use_constant -
- 8 - - 17 - - } -
- 9 - - 18 - - } -
-
- - - - diff.expandLastBottomByLines - - - - - - diff.expandLastBottomComplete - -
-
-
`; diff --git a/scm-ui/ui-components/src/repos/Diff.tsx b/scm-ui/ui-components/src/repos/Diff.tsx index f5086f2881..3fb81571e6 100644 --- a/scm-ui/ui-components/src/repos/Diff.tsx +++ b/scm-ui/ui-components/src/repos/Diff.tsx @@ -35,7 +35,7 @@ type Props = RouteComponentProps & WithTranslation & }; type State = { - contentRef?: HTMLElement; + contentRef?: HTMLElement | null; } function getAnchorSelector(uriHashContent: string) { @@ -71,17 +71,18 @@ class Diff extends React.Component { } } + shouldComponentUpdate(nextProps: Readonly, nextState: Readonly): boolean { + // We have check if the contentRef changed and update afterwards so the page can scroll to the anchor links. + // Otherwise it can happen that componentDidUpdate is never executed depending on how fast the markdown got rendered + return this.state.contentRef !== nextState.contentRef; + } + render() { const { diff, t, ...fileProps } = this.props; - const updateContentRef = (el: HTMLElement | null) => { - if (el !== null && this.state.contentRef === undefined) { - this.setState({ contentRef: el }); - } - }; return (
this.setState({ contentRef: el })} > {diff.length === 0 ? ( {t("diff.noDiffFound")} From cfbaf63b5c8d9b563b7b4da7242a7c782f0f3d60 Mon Sep 17 00:00:00 2001 From: Konstantin Schaper Date: Wed, 26 Aug 2020 11:34:15 +0200 Subject: [PATCH 07/23] add additional precautious check --- scm-ui/ui-components/src/repos/Diff.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scm-ui/ui-components/src/repos/Diff.tsx b/scm-ui/ui-components/src/repos/Diff.tsx index 3fb81571e6..7f11bb6cca 100644 --- a/scm-ui/ui-components/src/repos/Diff.tsx +++ b/scm-ui/ui-components/src/repos/Diff.tsx @@ -74,7 +74,7 @@ class Diff extends React.Component { shouldComponentUpdate(nextProps: Readonly, nextState: Readonly): boolean { // We have check if the contentRef changed and update afterwards so the page can scroll to the anchor links. // Otherwise it can happen that componentDidUpdate is never executed depending on how fast the markdown got rendered - return this.state.contentRef !== nextState.contentRef; + return this.state.contentRef !== nextState.contentRef || this.props !== nextProps; } render() { From 0069f401f814b397849957897e77e7c8da31ec71 Mon Sep 17 00:00:00 2001 From: Konstantin Schaper Date: Wed, 26 Aug 2020 11:37:53 +0200 Subject: [PATCH 08/23] update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d8fd79db9..fbd175bc70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased +### Added +- Add support for scroll anchors in url hash of diff page ([#1304](https://github.com/scm-manager/scm-manager/pull/1304)) + ## [2.4.0] - 2020-08-14 ### Added - Introduced merge detection for receive hooks ([#1278](https://github.com/scm-manager/scm-manager/pull/1278)) From 15fac8ba2c7518a3780ab154e636f0c0e7ef3769 Mon Sep 17 00:00:00 2001 From: Konstantin Schaper Date: Wed, 26 Aug 2020 15:06:00 +0200 Subject: [PATCH 09/23] remove ref usage and directly use objectId --- .../main/java/sonia/scm/repository/Tag.java | 2 +- .../java/sonia/scm/repository/GitUtil.java | 28 ++------ .../repository/api/GitHookTagProvider.java | 26 ++++---- .../scm/repository/spi/GitTagsCommand.java | 2 +- .../api/GitHookTagProviderTest.java | 64 ++++++++++++------- .../repository/client/spi/GitTagCommand.java | 2 +- 6 files changed, 59 insertions(+), 65 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/Tag.java b/scm-core/src/main/java/sonia/scm/repository/Tag.java index 0262888e55..49f81c7516 100644 --- a/scm-core/src/main/java/sonia/scm/repository/Tag.java +++ b/scm-core/src/main/java/sonia/scm/repository/Tag.java @@ -73,7 +73,7 @@ public final class Tag { /** * The date is retrieved in a best-effort fashion. * In certain situations it might not be available. - * In these cases, this method returns null. + * In these cases, this method returns an empty optional. * * @since 2.5.0 */ diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java index 97fc29163a..5426422def 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java @@ -390,45 +390,27 @@ public final class GitUtil } /** - * Method description - * - * @param repository - * @param ref - * @return - * @throws IOException * @since 2.5.0 */ - public static Long getTagTime(org.eclipse.jgit.lib.Repository repository, Ref ref) throws IOException { + public static Long getTagTime(org.eclipse.jgit.lib.Repository repository, ObjectId objectId) throws IOException { try (RevWalk walk = new RevWalk(repository)) { - return GitUtil.getTagTime(repository, walk, ref); + return GitUtil.getTagTime(repository, walk, objectId); } } /** - * Method description - * - * @param repository - * @param revWalk - * @param ref - * @return - * @throws IOException * @since 2.5.0 */ public static Long getTagTime(org.eclipse.jgit.lib.Repository repository, - RevWalk revWalk, Ref ref) + RevWalk revWalk, ObjectId objectId) throws IOException { - if (ref == null) { - return null; - } - ObjectId id = ref.getObjectId(); - - if (id != null) { + if (objectId != null) { if (revWalk == null) { revWalk = new RevWalk(repository); } - final RevObject revObject = revWalk.parseAny(id); + final RevObject revObject = revWalk.parseAny(objectId); if (revObject instanceof RevTag) { return ((RevTag) revObject).getTaggerIdent().getWhen().getTime(); } else if (revObject instanceof RevCommit) { diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/api/GitHookTagProvider.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/api/GitHookTagProvider.java index c1a333400b..7889badc30 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/api/GitHookTagProvider.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/api/GitHookTagProvider.java @@ -26,18 +26,16 @@ package sonia.scm.repository.api; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; - -import java.io.IOException; -import java.util.List; - import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.transport.ReceiveCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.repository.GitUtil; import sonia.scm.repository.Tag; +import java.io.IOException; +import java.util.List; + /** * Git provider implementation of {@link HookTagProvider}. * @@ -67,20 +65,18 @@ public class GitHookTagProvider implements HookTagProvider { if (Strings.isNullOrEmpty(tag)) { LOG.debug("received ref name {} is not a tag", refName); } else { - Long tagTime = null; try { - tagTime = GitUtil.getTagTime(repository, rc.getRef()); + if (isCreate(rc)) { + createdTagBuilder.add(createTagFromNewId(rc, tag, GitUtil.getTagTime(repository, rc.getNewId()))); + } else if (isDelete(rc)) { + deletedTagBuilder.add(createTagFromOldId(rc, tag, GitUtil.getTagTime(repository, rc.getOldId()))); + } else if (isUpdate(rc)) { + createdTagBuilder.add(createTagFromNewId(rc, tag, GitUtil.getTagTime(repository, rc.getNewId()))); + deletedTagBuilder.add(createTagFromOldId(rc, tag, GitUtil.getTagTime(repository, rc.getOldId()))); + } } catch (IOException e) { LOG.error("Could not read tag time", e); } - if (isCreate(rc)) { - createdTagBuilder.add(createTagFromNewId(rc, tag, tagTime)); - } else if (isDelete(rc)) { - deletedTagBuilder.add(createTagFromOldId(rc, tag, tagTime)); - } else if (isUpdate(rc)) { - createdTagBuilder.add(createTagFromNewId(rc, tag, tagTime)); - deletedTagBuilder.add(createTagFromOldId(rc, tag, tagTime)); - } } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitTagsCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitTagsCommand.java index 97b9c91be1..b8c000ed03 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitTagsCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitTagsCommand.java @@ -132,7 +132,7 @@ public class GitTagsCommand extends AbstractGitCommand implements TagsCommand { if (revObject != null) { String name = GitUtil.getTagName(ref); - tag = new Tag(name, revObject.getId().name(), GitUtil.getTagTime(repository, revWalk, ref)); + tag = new Tag(name, revObject.getId().name(), GitUtil.getTagTime(repository, revWalk, ref.getObjectId())); } } catch (IOException ex) { diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/api/GitHookTagProviderTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/api/GitHookTagProviderTest.java index e0a83e1272..ccf21b83c9 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/api/GitHookTagProviderTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/api/GitHookTagProviderTest.java @@ -26,7 +26,6 @@ package sonia.scm.repository.api; import com.google.common.collect.Lists; import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.transport.ReceiveCommand; import org.junit.Before; @@ -64,12 +63,6 @@ public class GitHookTagProviderTest { @Mock private Repository repository; - @Mock - private Ref gitRef; - - @Mock - private ObjectId objectId; - private List commands; /** @@ -91,7 +84,7 @@ public class GitHookTagProviderTest { String tagName = "1.0.0"; String ref = "refs/tags/" + tagName; - dummy.when(() -> GitUtil.getTagTime(repository, gitRef)).thenReturn(timestamp); + dummy.when(() -> GitUtil.getTagTime(repository, ObjectId.fromString(revision))).thenReturn(timestamp); dummy.when(() -> GitUtil.getTagName(ref)).thenReturn(tagName); dummy.when(() -> GitUtil.getId(ObjectId.fromString(revision))).thenReturn(revision); @@ -113,7 +106,7 @@ public class GitHookTagProviderTest { String tagName = "1.0.0"; String ref = "refs/tags/" + tagName; - dummy.when(() -> GitUtil.getTagTime(repository, gitRef)).thenReturn(timestamp); + dummy.when(() -> GitUtil.getTagTime(repository, ObjectId.fromString(revision))).thenReturn(timestamp); dummy.when(() -> GitUtil.getTagName(ref)).thenReturn(tagName); dummy.when(() -> GitUtil.getId(ObjectId.fromString(revision))).thenReturn(revision); @@ -137,29 +130,54 @@ public class GitHookTagProviderTest { } /** - * Tests {@link GitHookTagProvider} with update command. + * Tests {@link GitHookTagProvider} with update command pre receive. */ @Test - public void testUpdateTags() { + public void testUpdateTagsPreReceive() { try (MockedStatic dummy = Mockito.mockStatic(GitUtil.class)) { - String newRevision = "b2002b64013e54b78eac251df0672bd5d6a83aa7"; - Long newTimestamp = 1339416344000L; - String newTagName = "1.0.0"; - String newRef = "refs/tags/" + newTagName; - String oldRevision = "e0f2be968b147ff7043684a7715d2fe852553db4"; - String oldTagName = "0.9.0"; + String newRevision = "b2002b64013e54b78eac251df0672bd5d6a83aa7"; - dummy.when(() -> GitUtil.getTagTime(repository, gitRef)).thenReturn(newTimestamp); - dummy.when(() -> GitUtil.getTagName(newRef)).thenReturn(newTagName); + Long timestamp = 1339416344000L; + String tagName = "1.0.0"; + String ref = "refs/tags/" + tagName; + + dummy.when(() -> GitUtil.getTagTime(repository, ObjectId.fromString(oldRevision))).thenReturn(timestamp); + dummy.when(() -> GitUtil.getTagTime(repository, ObjectId.fromString(newRevision))).thenReturn(null); + dummy.when(() -> GitUtil.getTagName(ref)).thenReturn(tagName); + dummy.when(() -> GitUtil.getId(ObjectId.fromString(oldRevision))).thenReturn(oldRevision); dummy.when(() -> GitUtil.getId(ObjectId.fromString(newRevision))).thenReturn(newRevision); + GitHookTagProvider provider = createProvider(ReceiveCommand.Type.UPDATE, ref, newRevision, oldRevision); + + assertTag(tagName, newRevision, null, provider.getCreatedTags()); + assertTag(tagName, oldRevision, timestamp, provider.getDeletedTags()); + } + } + + /** + * Tests {@link GitHookTagProvider} with update command post receive. + */ + @Test + public void testUpdateTagsPostReceive() { + try (MockedStatic dummy = Mockito.mockStatic(GitUtil.class)) { + String oldRevision = "e0f2be968b147ff7043684a7715d2fe852553db4"; + String newRevision = "b2002b64013e54b78eac251df0672bd5d6a83aa7"; + + Long timestamp = 1339416344000L; + String tagName = "1.0.0"; + String ref = "refs/tags/" + tagName; + + dummy.when(() -> GitUtil.getTagTime(repository, ObjectId.fromString(newRevision))).thenReturn(timestamp); + dummy.when(() -> GitUtil.getTagTime(repository, ObjectId.fromString(oldRevision))).thenReturn(null); + dummy.when(() -> GitUtil.getTagName(ref)).thenReturn(tagName); dummy.when(() -> GitUtil.getId(ObjectId.fromString(oldRevision))).thenReturn(oldRevision); + dummy.when(() -> GitUtil.getId(ObjectId.fromString(newRevision))).thenReturn(newRevision); - GitHookTagProvider provider = createProvider(ReceiveCommand.Type.UPDATE, newRef, newRevision, oldRevision); + GitHookTagProvider provider = createProvider(ReceiveCommand.Type.UPDATE, ref, newRevision, oldRevision); - assertTag(newTagName, newRevision, newTimestamp, provider.getCreatedTags()); - assertTag(oldTagName, oldRevision, null, provider.getDeletedTags()); + assertTag(tagName, newRevision, timestamp, provider.getCreatedTags()); + assertTag(tagName, oldRevision, null, provider.getDeletedTags()); } } @@ -178,8 +196,6 @@ public class GitHookTagProviderTest { when(command.getOldId()).thenReturn(ObjectId.fromString(oldId)); when(command.getType()).thenReturn(type); when(command.getRefName()).thenReturn(ref); - when(command.getRef()).thenReturn(gitRef); - when(gitRef.getObjectId()).thenReturn(objectId); return new GitHookTagProvider(commands, repository); } diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/client/spi/GitTagCommand.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/client/spi/GitTagCommand.java index 19b93d0775..28664c463d 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/client/spi/GitTagCommand.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/client/spi/GitTagCommand.java @@ -89,7 +89,7 @@ public class GitTagCommand implements TagCommand { walk = new RevWalk(git.getRepository()); revObject = walk.parseAny(id); - tagTime = GitUtil.getTagTime(git.getRepository(), walk, GitUtil.getRefForCommit(git.getRepository(), id)); + tagTime = GitUtil.getTagTime(git.getRepository(), walk, id); } finally { From bf1ff26f19352914d85343e8e396dc651d0a6848 Mon Sep 17 00:00:00 2001 From: Konstantin Schaper Date: Wed, 26 Aug 2020 15:35:37 +0200 Subject: [PATCH 10/23] update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d8fd79db9..e5e7320d5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased +### Added +- Tags now have date information attached ([#1305](https://github.com/scm-manager/scm-manager/pull/1305)) + ## [2.4.0] - 2020-08-14 ### Added - Introduced merge detection for receive hooks ([#1278](https://github.com/scm-manager/scm-manager/pull/1278)) From 565ec3ff3c089fcb3db3bcc54bfd48aab48e6a27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 27 Aug 2020 10:48:54 +0200 Subject: [PATCH 11/23] Cleanup --- .../java/sonia/scm/repository/GitUtil.java | 11 ++----- .../scm/repository/spi/GitTagsCommand.java | 2 +- .../repository/client/spi/GitTagCommand.java | 4 +-- .../repository/api/HgHookTagProviderTest.java | 31 ++++++++++--------- 4 files changed, 21 insertions(+), 27 deletions(-) diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java index 5426422def..6baa48111b 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java @@ -394,22 +394,15 @@ public final class GitUtil */ public static Long getTagTime(org.eclipse.jgit.lib.Repository repository, ObjectId objectId) throws IOException { try (RevWalk walk = new RevWalk(repository)) { - return GitUtil.getTagTime(repository, walk, objectId); + return GitUtil.getTagTime(walk, objectId); } } /** * @since 2.5.0 */ - public static Long getTagTime(org.eclipse.jgit.lib.Repository repository, - RevWalk revWalk, ObjectId objectId) - throws IOException { - + public static Long getTagTime(RevWalk revWalk, ObjectId objectId) throws IOException { if (objectId != null) { - if (revWalk == null) { - revWalk = new RevWalk(repository); - } - final RevObject revObject = revWalk.parseAny(objectId); if (revObject instanceof RevTag) { return ((RevTag) revObject).getTaggerIdent().getWhen().getTime(); diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitTagsCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitTagsCommand.java index b8c000ed03..bc0a8c95a8 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitTagsCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitTagsCommand.java @@ -132,7 +132,7 @@ public class GitTagsCommand extends AbstractGitCommand implements TagsCommand { if (revObject != null) { String name = GitUtil.getTagName(ref); - tag = new Tag(name, revObject.getId().name(), GitUtil.getTagTime(repository, revWalk, ref.getObjectId())); + tag = new Tag(name, revObject.getId().name(), GitUtil.getTagTime(revWalk, ref.getObjectId())); } } catch (IOException ex) { diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/client/spi/GitTagCommand.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/client/spi/GitTagCommand.java index 28664c463d..8c4eb3f89f 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/client/spi/GitTagCommand.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/client/spi/GitTagCommand.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.repository.client.spi; //~--- non-JDK imports -------------------------------------------------------- @@ -89,7 +89,7 @@ public class GitTagCommand implements TagCommand { walk = new RevWalk(git.getRepository()); revObject = walk.parseAny(id); - tagTime = GitUtil.getTagTime(git.getRepository(), walk, id); + tagTime = GitUtil.getTagTime(walk, id); } finally { diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/api/HgHookTagProviderTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/api/HgHookTagProviderTest.java index 18e7fb8c48..b756b4097d 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/api/HgHookTagProviderTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/api/HgHookTagProviderTest.java @@ -21,17 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.repository.api; import com.google.common.collect.Lists; -import java.util.List; - -import org.assertj.core.api.Assertions; import org.junit.Test; -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; -import static org.hamcrest.Matchers.*; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; @@ -43,9 +37,16 @@ import sonia.scm.repository.spi.HookChangesetProvider; import sonia.scm.repository.spi.HookChangesetRequest; import sonia.scm.repository.spi.HookChangesetResponse; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.when; + /** * Unit tests for {@link HgHookTagProvider}. - * + * * @author Sebastian Sdorra */ @RunWith(MockitoJUnitRunner.class) @@ -53,7 +54,7 @@ public class HgHookTagProviderTest { @Mock private HookChangesetProvider changesetProvider; - + @InjectMocks private HgHookTagProvider tagProvider; @@ -63,9 +64,9 @@ public class HgHookTagProviderTest { @Test public void testGetDeletedTags() { prepareChangesets(new Changeset("1", Long.MIN_VALUE, null)); - assertThat(tagProvider.getDeletedTags(), empty()); + assertThat(tagProvider.getDeletedTags()).isEmpty(); } - + /** * Tests {@link HgHookTagProvider#getCreatedTags()}. */ @@ -77,20 +78,20 @@ public class HgHookTagProviderTest { c2.getTags().add("2.0.0"); Changeset c3 = new Changeset("3", Long.MIN_VALUE, null); prepareChangesets(c1, c2, c3); - + List tags = tagProvider.getCreatedTags(); assertNotNull(tags); assertEquals(2, tags.size()); - + Tag t1 = tags.get(0); assertEquals("1", t1.getRevision()); assertEquals("1.0.0", t1.getName()); - Assertions.assertThat(t1.getDate()).contains(Long.MIN_VALUE); + assertThat(t1.getDate()).contains(Long.MIN_VALUE); Tag t2 = tags.get(1); assertEquals("2", t2.getRevision()); assertEquals("2.0.0", t2.getName()); - Assertions.assertThat(t2.getDate()).contains(Long.MAX_VALUE); + assertThat(t2.getDate()).contains(Long.MAX_VALUE); } private void prepareChangesets(Changeset... changesets){ From 96d16fe4cce7901eacfb727cdfa5bef330891930 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 27 Aug 2020 11:15:13 +0200 Subject: [PATCH 12/23] "Unpeel" annotated tags to get correct changeset If we just parse the object id of the reference for annotated tags, we get the annotated tag object and not the reference the tag refers to. --- .../sonia/scm/repository/spi/GitTagsCommand.java | 2 +- .../scm/repository/spi/GitTagsCommandTest.java | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitTagsCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitTagsCommand.java index bc0a8c95a8..60b1105547 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitTagsCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitTagsCommand.java @@ -127,7 +127,7 @@ public class GitTagsCommand extends AbstractGitCommand implements TagsCommand { Tag tag = null; try { - RevObject revObject = revWalk.parseAny(ref.getObjectId()); + RevObject revObject = GitUtil.getCommit(repository, revWalk, ref); if (revObject != null) { String name = GitUtil.getTagName(ref); diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitTagsCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitTagsCommandTest.java index 3152b36040..9112aa3133 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitTagsCommandTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitTagsCommandTest.java @@ -54,10 +54,16 @@ public class GitTagsCommandTest extends AbstractGitCommandTestBase { final GitTagsCommand tagsCommand = new GitTagsCommand(gitContext); final List tags = tagsCommand.getTags(); assertThat(tags).hasSize(2); - assertThat(tags.get(0).getName()).isEqualTo("1.0.0"); - assertThat(tags.get(0).getDate()).contains(1598348105000L); // Annotated - Take tag date - assertThat(tags.get(1).getName()).isEqualTo("test-tag"); - assertThat(tags.get(1).getDate()).contains(1339416344000L); // Lightweight - Take commit date + + Tag annotatedTag = tags.get(0); + assertThat(annotatedTag.getName()).isEqualTo("1.0.0"); + assertThat(annotatedTag.getDate()).contains(1598348105000L); // Annotated - Take tag date + assertThat(annotatedTag.getRevision()).isEqualTo("fcd0ef1831e4002ac43ea539f4094334c79ea9ec"); + + Tag lightweightTag = tags.get(1); + assertThat(lightweightTag.getName()).isEqualTo("test-tag"); + assertThat(lightweightTag.getDate()).contains(1339416344000L); // Lightweight - Take commit date + assertThat(lightweightTag.getRevision()).isEqualTo("86a6645eceefe8b9a247db5eb16e3d89a7e6e6d1"); } @Override From 4d4834d115bfda61ca9c8074e743694f95b87838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 27 Aug 2020 11:30:04 +0200 Subject: [PATCH 13/23] Add some more documentation --- .../src/main/java/sonia/scm/repository/Tag.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/Tag.java b/scm-core/src/main/java/sonia/scm/repository/Tag.java index 49f81c7516..cdfac1c0e6 100644 --- a/scm-core/src/main/java/sonia/scm/repository/Tag.java +++ b/scm-core/src/main/java/sonia/scm/repository/Tag.java @@ -71,9 +71,18 @@ public final class Tag { } /** - * The date is retrieved in a best-effort fashion. - * In certain situations it might not be available. - * In these cases, this method returns an empty optional. + * Depending on the underlying source code management system + * (like git or hg) and depending on the type of this tag + * (for example git has lightweight and annotated + * tags), this date has different meaning. For annotated tags + * in git, this is the date the tag was created. In other cases + * (for lightweight tags in git or all tags in hg) this is the + * date of the referenced changeset. + *

+ * Please note, that the date is retrieved in a best-effort fashion. + * In certain situations (for example if this tag is announced in + * a pre or post receive hook), it might not be available. + * In these cases, this method returns an empty {@link Optional}. * * @since 2.5.0 */ From 95dde51bba0bcd7715f2ca6674314a728bbd9b50 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Wed, 2 Sep 2020 07:40:52 +0200 Subject: [PATCH 14/23] Move escapeWhitespace to diffs and add small test --- scm-ui/ui-components/src/repos/Diff.tsx | 14 +++++++------- scm-ui/ui-components/src/repos/DiffFile.tsx | 7 ++----- scm-ui/ui-components/src/repos/diffs.test.ts | 13 ++++++++++++- scm-ui/ui-components/src/repos/diffs.ts | 4 ++++ 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/scm-ui/ui-components/src/repos/Diff.tsx b/scm-ui/ui-components/src/repos/Diff.tsx index 7f11bb6cca..1cec03ab37 100644 --- a/scm-ui/ui-components/src/repos/Diff.tsx +++ b/scm-ui/ui-components/src/repos/Diff.tsx @@ -22,13 +22,15 @@ * SOFTWARE. */ import React from "react"; -import DiffFile, {escapeWhitespace} from "./DiffFile"; +import DiffFile from "./DiffFile"; import { DiffObjectProps, File, FileControlFactory } from "./DiffTypes"; +import { escapeWhitespace } from "./diffs"; import Notification from "../Notification"; import { WithTranslation, withTranslation } from "react-i18next"; -import {RouteComponentProps, withRouter} from "react-router-dom"; +import { RouteComponentProps, withRouter } from "react-router-dom"; -type Props = RouteComponentProps & WithTranslation & +type Props = RouteComponentProps & + WithTranslation & DiffObjectProps & { diff: File[]; fileControlFactory?: FileControlFactory; @@ -36,7 +38,7 @@ type Props = RouteComponentProps & WithTranslation & type State = { contentRef?: HTMLElement | null; -} +}; function getAnchorSelector(uriHashContent: string) { return "#" + escapeWhitespace(decodeURIComponent(uriHashContent)); @@ -81,9 +83,7 @@ class Diff extends React.Component { const { diff, t, ...fileProps } = this.props; return ( -

this.setState({ contentRef: el })} - > +
this.setState({ contentRef: el })}> {diff.length === 0 ? ( {t("diff.noDiffFound")} ) : ( diff --git a/scm-ui/ui-components/src/repos/DiffFile.tsx b/scm-ui/ui-components/src/repos/DiffFile.tsx index 91f87e821b..b4ec64a8e8 100644 --- a/scm-ui/ui-components/src/repos/DiffFile.tsx +++ b/scm-ui/ui-components/src/repos/DiffFile.tsx @@ -39,6 +39,7 @@ import HunkExpandLink from "./HunkExpandLink"; import { Modal } from "../modals"; import ErrorNotification from "../ErrorNotification"; import HunkExpandDivider from "./HunkExpandDivider"; +import { escapeWhitespace } from "./diffs"; const EMPTY_ANNOTATION_FACTORY = {}; @@ -90,10 +91,6 @@ const ChangeTypeTag = styled(Tag)` margin-left: 0.75rem; `; -export function escapeWhitespace(path: string) { - return path.toLowerCase().replace(/\W/g, "-"); -} - class DiffFile extends React.Component { static defaultProps: Partial = { defaultCollapse: false, @@ -110,7 +107,7 @@ class DiffFile extends React.Component { }; } - componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any): void { + componentDidUpdate(prevProps: Readonly) { if (this.props.defaultCollapse !== prevProps.defaultCollapse) { this.setState({ collapsed: this.defaultCollapse() diff --git a/scm-ui/ui-components/src/repos/diffs.test.ts b/scm-ui/ui-components/src/repos/diffs.test.ts index 9e02ed43e4..58c5caca5a 100644 --- a/scm-ui/ui-components/src/repos/diffs.test.ts +++ b/scm-ui/ui-components/src/repos/diffs.test.ts @@ -23,7 +23,7 @@ */ import { File, FileChangeType, Hunk } from "./DiffTypes"; -import { getPath, createHunkIdentifier, createHunkIdentifierFromContext } from "./diffs"; +import { getPath, createHunkIdentifier, createHunkIdentifierFromContext, escapeWhitespace } from "./diffs"; describe("tests for diff util functions", () => { const file = (type: FileChangeType, oldPath: string, newPath: string): File => { @@ -88,4 +88,15 @@ describe("tests for diff util functions", () => { expect(identifier).toBe("delete_/etc/passwd_@@ -1,42 +1,39 @@"); }); }); + + describe("escapeWhitespace tests", () => { + it("should escape whitespaces", () => { + const escaped = escapeWhitespace("spaceship hog"); + expect(escaped).toBe("spaceship-hog"); + }); + it("should escape multiple whitespaces", () => { + const escaped = escapeWhitespace("spaceship heart of gold"); + expect(escaped).toBe("spaceship-heart-of-gold"); + }); + }); }); diff --git a/scm-ui/ui-components/src/repos/diffs.ts b/scm-ui/ui-components/src/repos/diffs.ts index 9171b6ef09..029803a0a4 100644 --- a/scm-ui/ui-components/src/repos/diffs.ts +++ b/scm-ui/ui-components/src/repos/diffs.ts @@ -39,3 +39,7 @@ export function createHunkIdentifier(file: File, hunk: Hunk) { export function createHunkIdentifierFromContext(ctx: BaseContext) { return createHunkIdentifier(ctx.file, ctx.hunk); } + +export function escapeWhitespace(path: string) { + return path.toLowerCase().replace(/\W/g, "-"); +} From abedebda10ac07cc5acbc38de0a8daf560d1202e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 2 Sep 2020 10:18:42 +0200 Subject: [PATCH 15/23] Fix redirect to requested location in anonymous mode If anonymous mode is enabled, the user should be redirected to the requested location after login, when he entered a restricted URL. Therefore we have to append the requested location to the login link here. --- scm-ui/ui-components/src/ErrorBoundary.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scm-ui/ui-components/src/ErrorBoundary.tsx b/scm-ui/ui-components/src/ErrorBoundary.tsx index 33c8a48494..3d0144b95b 100644 --- a/scm-ui/ui-components/src/ErrorBoundary.tsx +++ b/scm-ui/ui-components/src/ErrorBoundary.tsx @@ -72,10 +72,10 @@ class ErrorBoundary extends React.Component { } redirectToLogin = (error: Error) => { - const { loginLink } = this.props; + const { loginLink, location } = this.props; if (error instanceof MissingLinkError) { if (loginLink) { - window.location.assign(withContextPath("/login")); + window.location.assign(withContextPath("/login?from=" + location.pathname)); } } }; From b60b737712e05f56fbea7059ba01f7d6b0a2e41a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 2 Sep 2020 10:25:56 +0200 Subject: [PATCH 16/23] Log chage --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d469b6fd5..c0d5ea7ff0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased +### Fixed +- Redirection to requested page after login in anonymous mode + ## [2.4.1] - 2020-09-01 ### Added - Add "sonia.scm.restart-migration.wait" to set wait in milliseconds before restarting scm-server after migration ([#1308](https://github.com/scm-manager/scm-manager/pull/1308)) From 43b1c7e2d9383aab8d00c6637320f45053bdb7e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 2 Sep 2020 10:41:02 +0200 Subject: [PATCH 17/23] Set new version in all package.json files --- scm-ui/ui-scripts/src/lerna.js | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/scm-ui/ui-scripts/src/lerna.js b/scm-ui/ui-scripts/src/lerna.js index c0250e1385..3b9af49e3a 100644 --- a/scm-ui/ui-scripts/src/lerna.js +++ b/scm-ui/ui-scripts/src/lerna.js @@ -37,16 +37,8 @@ const yarn = args => { } }; -const version = version => { - yarn([ - "run", - "lerna", - "--no-git-tag-version", - "--no-push", - "version", - "--yes", - version - ]); +const version = v => { + yarn(["run", "lerna", "--no-git-tag-version", "--no-push", "version", "--force-publish", "--yes", v]); }; const publish = () => { From 2cfd3faf34a180cdf6f42d58d7683bf49681a97b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 3 Sep 2020 07:56:01 +0200 Subject: [PATCH 18/23] Set version to 2.5.0-SNAPSHOT globally --- lerna.json | 2 +- scm-plugins/scm-git-plugin/package.json | 4 ++-- scm-plugins/scm-hg-plugin/package.json | 4 ++-- scm-plugins/scm-legacy-plugin/package.json | 4 ++-- scm-plugins/scm-svn-plugin/package.json | 4 ++-- scm-ui/babel-preset/package.json | 2 +- scm-ui/e2e-tests/package.json | 2 +- scm-ui/eslint-config/package.json | 2 +- scm-ui/jest-preset/package.json | 2 +- scm-ui/prettier-config/package.json | 2 +- scm-ui/tsconfig/package.json | 2 +- scm-ui/ui-components/package.json | 8 ++++---- scm-ui/ui-extensions/package.json | 2 +- scm-ui/ui-plugins/package.json | 22 +++++++++++----------- scm-ui/ui-polyfill/package.json | 2 +- scm-ui/ui-scripts/package.json | 2 +- scm-ui/ui-styles/package.json | 2 +- scm-ui/ui-tests/package.json | 2 +- scm-ui/ui-types/package.json | 2 +- scm-ui/ui-webapp/package.json | 8 ++++---- 20 files changed, 40 insertions(+), 40 deletions(-) diff --git a/lerna.json b/lerna.json index 4db07d9ee9..2f57f9256d 100644 --- a/lerna.json +++ b/lerna.json @@ -5,5 +5,5 @@ ], "npmClient": "yarn", "useWorkspaces": true, - "version": "2.4.1" + "version": "2.5.0-SNAPSHOT" } diff --git a/scm-plugins/scm-git-plugin/package.json b/scm-plugins/scm-git-plugin/package.json index 0a789bde38..0c8c1fe4e1 100644 --- a/scm-plugins/scm-git-plugin/package.json +++ b/scm-plugins/scm-git-plugin/package.json @@ -1,7 +1,7 @@ { "name": "@scm-manager/scm-git-plugin", "private": true, - "version": "2.4.1", + "version": "2.5.0-SNAPSHOT", "license": "MIT", "main": "./src/main/js/index.ts", "scripts": { @@ -20,6 +20,6 @@ }, "prettier": "@scm-manager/prettier-config", "dependencies": { - "@scm-manager/ui-plugins": "^2.4.1" + "@scm-manager/ui-plugins": "^2.5.0-SNAPSHOT" } } diff --git a/scm-plugins/scm-hg-plugin/package.json b/scm-plugins/scm-hg-plugin/package.json index c67c73bd4b..3e4cc110e2 100644 --- a/scm-plugins/scm-hg-plugin/package.json +++ b/scm-plugins/scm-hg-plugin/package.json @@ -1,7 +1,7 @@ { "name": "@scm-manager/scm-hg-plugin", "private": true, - "version": "2.4.1", + "version": "2.5.0-SNAPSHOT", "license": "MIT", "main": "./src/main/js/index.ts", "scripts": { @@ -19,6 +19,6 @@ }, "prettier": "@scm-manager/prettier-config", "dependencies": { - "@scm-manager/ui-plugins": "^2.4.1" + "@scm-manager/ui-plugins": "^2.5.0-SNAPSHOT" } } diff --git a/scm-plugins/scm-legacy-plugin/package.json b/scm-plugins/scm-legacy-plugin/package.json index e5d158a9fb..29f16b35bf 100644 --- a/scm-plugins/scm-legacy-plugin/package.json +++ b/scm-plugins/scm-legacy-plugin/package.json @@ -1,7 +1,7 @@ { "name": "@scm-manager/scm-legacy-plugin", "private": true, - "version": "2.4.1", + "version": "2.5.0-SNAPSHOT", "license": "MIT", "main": "./src/main/js/index.tsx", "scripts": { @@ -19,6 +19,6 @@ }, "prettier": "@scm-manager/prettier-config", "dependencies": { - "@scm-manager/ui-plugins": "^2.4.1" + "@scm-manager/ui-plugins": "^2.5.0-SNAPSHOT" } } diff --git a/scm-plugins/scm-svn-plugin/package.json b/scm-plugins/scm-svn-plugin/package.json index 978e2296d1..f8fb87228a 100644 --- a/scm-plugins/scm-svn-plugin/package.json +++ b/scm-plugins/scm-svn-plugin/package.json @@ -1,7 +1,7 @@ { "name": "@scm-manager/scm-svn-plugin", "private": true, - "version": "2.4.1", + "version": "2.5.0-SNAPSHOT", "license": "MIT", "main": "./src/main/js/index.ts", "scripts": { @@ -19,6 +19,6 @@ }, "prettier": "@scm-manager/prettier-config", "dependencies": { - "@scm-manager/ui-plugins": "^2.4.1" + "@scm-manager/ui-plugins": "^2.5.0-SNAPSHOT" } } diff --git a/scm-ui/babel-preset/package.json b/scm-ui/babel-preset/package.json index e0f0d08c0b..19156b7a2f 100644 --- a/scm-ui/babel-preset/package.json +++ b/scm-ui/babel-preset/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/babel-preset", - "version": "2.1.0", + "version": "2.5.0-SNAPSHOT", "license": "MIT", "description": "Babel configuration for scm-manager and its plugins", "main": "index.js", diff --git a/scm-ui/e2e-tests/package.json b/scm-ui/e2e-tests/package.json index 5ba065dbf4..29f0526b9e 100644 --- a/scm-ui/e2e-tests/package.json +++ b/scm-ui/e2e-tests/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/e2e-tests", - "version": "2.4.1", + "version": "2.5.0-SNAPSHOT", "description": "End to end Tests for SCM-Manager", "main": "index.js", "author": "Eduard Heimbuch ", diff --git a/scm-ui/eslint-config/package.json b/scm-ui/eslint-config/package.json index 15d5283148..ff84d952d4 100644 --- a/scm-ui/eslint-config/package.json +++ b/scm-ui/eslint-config/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/eslint-config", - "version": "2.1.0", + "version": "2.5.0-SNAPSHOT", "description": "ESLint configuration for scm-manager and its plugins", "main": "src/index.js", "author": "Sebastian Sdorra ", diff --git a/scm-ui/jest-preset/package.json b/scm-ui/jest-preset/package.json index 86a50e5caa..152a7e6875 100644 --- a/scm-ui/jest-preset/package.json +++ b/scm-ui/jest-preset/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/jest-preset", - "version": "2.1.0", + "version": "2.5.0-SNAPSHOT", "description": "Jest presets for SCM-Manager and its plugins", "main": "src/index.js", "author": "Sebastian Sdorra ", diff --git a/scm-ui/prettier-config/package.json b/scm-ui/prettier-config/package.json index 12bdd0b638..0c7def2dc7 100644 --- a/scm-ui/prettier-config/package.json +++ b/scm-ui/prettier-config/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/prettier-config", - "version": "2.1.0", + "version": "2.5.0-SNAPSHOT", "license": "MIT", "description": "Prettier configuration", "author": "Sebastian Sdorra ", diff --git a/scm-ui/tsconfig/package.json b/scm-ui/tsconfig/package.json index be69821d18..63211a761f 100644 --- a/scm-ui/tsconfig/package.json +++ b/scm-ui/tsconfig/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/tsconfig", - "version": "2.1.0", + "version": "2.5.0-SNAPSHOT", "license": "MIT", "description": "TypeScript configuration", "author": "Sebastian Sdorra ", diff --git a/scm-ui/ui-components/package.json b/scm-ui/ui-components/package.json index f6a51262eb..73ea80b6de 100644 --- a/scm-ui/ui-components/package.json +++ b/scm-ui/ui-components/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-components", - "version": "2.4.1", + "version": "2.5.0-SNAPSHOT", "description": "UI Components for SCM-Manager and its plugins", "main": "src/index.ts", "files": [ @@ -18,7 +18,7 @@ "update-storyshots": "jest --testPathPattern=\"storyshots.test.ts\" --collectCoverage=false -u" }, "devDependencies": { - "@scm-manager/ui-tests": "^2.1.0", + "@scm-manager/ui-tests": "^2.5.0-SNAPSHOT", "@storybook/addon-actions": "^5.2.3", "@storybook/addon-storyshots": "^5.2.3", "@storybook/react": "^5.2.3", @@ -46,8 +46,8 @@ "worker-plugin": "^3.2.0" }, "dependencies": { - "@scm-manager/ui-extensions": "^2.1.0", - "@scm-manager/ui-types": "^2.4.0", + "@scm-manager/ui-extensions": "^2.5.0-SNAPSHOT", + "@scm-manager/ui-types": "^2.5.0-SNAPSHOT", "classnames": "^2.2.6", "date-fns": "^2.4.1", "gitdiff-parser": "^0.1.2", diff --git a/scm-ui/ui-extensions/package.json b/scm-ui/ui-extensions/package.json index 398b6c6f6f..96fb2224f7 100644 --- a/scm-ui/ui-extensions/package.json +++ b/scm-ui/ui-extensions/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-extensions", - "version": "2.1.0", + "version": "2.5.0-SNAPSHOT", "main": "src/index.ts", "license": "MIT", "private": false, diff --git a/scm-ui/ui-plugins/package.json b/scm-ui/ui-plugins/package.json index 6a6d5c2efb..e5812c1883 100644 --- a/scm-ui/ui-plugins/package.json +++ b/scm-ui/ui-plugins/package.json @@ -1,13 +1,13 @@ { "name": "@scm-manager/ui-plugins", - "version": "2.4.1", + "version": "2.5.0-SNAPSHOT", "license": "MIT", "bin": { "ui-plugins": "./bin/ui-plugins.js" }, "dependencies": { - "@scm-manager/ui-components": "^2.4.1", - "@scm-manager/ui-extensions": "^2.1.0", + "@scm-manager/ui-components": "^2.5.0-SNAPSHOT", + "@scm-manager/ui-extensions": "^2.5.0-SNAPSHOT", "classnames": "^2.2.6", "query-string": "^5.0.1", "react": "^16.10.2", @@ -18,14 +18,14 @@ "styled-components": "^5.1.0" }, "devDependencies": { - "@scm-manager/babel-preset": "^2.1.0", - "@scm-manager/eslint-config": "^2.1.0", - "@scm-manager/jest-preset": "^2.1.0", - "@scm-manager/prettier-config": "^2.1.0", - "@scm-manager/tsconfig": "^2.1.0", - "@scm-manager/ui-scripts": "^2.4.1", - "@scm-manager/ui-tests": "^2.1.0", - "@scm-manager/ui-types": "^2.4.0", + "@scm-manager/babel-preset": "^2.5.0-SNAPSHOT", + "@scm-manager/eslint-config": "^2.5.0-SNAPSHOT", + "@scm-manager/jest-preset": "^2.5.0-SNAPSHOT", + "@scm-manager/prettier-config": "^2.5.0-SNAPSHOT", + "@scm-manager/tsconfig": "^2.5.0-SNAPSHOT", + "@scm-manager/ui-scripts": "^2.5.0-SNAPSHOT", + "@scm-manager/ui-tests": "^2.5.0-SNAPSHOT", + "@scm-manager/ui-types": "^2.5.0-SNAPSHOT", "@types/classnames": "^2.2.9", "@types/enzyme": "^3.10.3", "@types/fetch-mock": "^7.3.1", diff --git a/scm-ui/ui-polyfill/package.json b/scm-ui/ui-polyfill/package.json index b7a3c65bf8..73e7617aa8 100644 --- a/scm-ui/ui-polyfill/package.json +++ b/scm-ui/ui-polyfill/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-polyfill", - "version": "2.1.0", + "version": "2.5.0-SNAPSHOT", "description": "Polyfills for SCM-Manager UI", "main": "src/index.js", "author": "Sebastian Sdorra ", diff --git a/scm-ui/ui-scripts/package.json b/scm-ui/ui-scripts/package.json index 5669523362..96e066e3dd 100644 --- a/scm-ui/ui-scripts/package.json +++ b/scm-ui/ui-scripts/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-scripts", - "version": "2.4.1", + "version": "2.5.0-SNAPSHOT", "description": "Build scripts for SCM-Manager", "main": "src/index.js", "author": "Sebastian Sdorra ", diff --git a/scm-ui/ui-styles/package.json b/scm-ui/ui-styles/package.json index 5e194620c9..30babcba23 100644 --- a/scm-ui/ui-styles/package.json +++ b/scm-ui/ui-styles/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-styles", - "version": "2.4.1", + "version": "2.5.0-SNAPSHOT", "description": "Styles for SCM-Manager", "main": "src/scm.scss", "license": "MIT", diff --git a/scm-ui/ui-tests/package.json b/scm-ui/ui-tests/package.json index f01de13f97..cc7cb45edf 100644 --- a/scm-ui/ui-tests/package.json +++ b/scm-ui/ui-tests/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-tests", - "version": "2.1.0", + "version": "2.5.0-SNAPSHOT", "description": "UI-Tests helpers", "author": "Sebastian Sdorra ", "license": "MIT", diff --git a/scm-ui/ui-types/package.json b/scm-ui/ui-types/package.json index a65dc06aae..a5587274b2 100644 --- a/scm-ui/ui-types/package.json +++ b/scm-ui/ui-types/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-types", - "version": "2.4.0", + "version": "2.5.0-SNAPSHOT", "description": "Flow types for SCM-Manager related Objects", "main": "src/index.ts", "files": [ diff --git a/scm-ui/ui-webapp/package.json b/scm-ui/ui-webapp/package.json index 4c039cf0c8..49b3f1f0d9 100644 --- a/scm-ui/ui-webapp/package.json +++ b/scm-ui/ui-webapp/package.json @@ -1,10 +1,10 @@ { "name": "@scm-manager/ui-webapp", - "version": "2.4.1", + "version": "2.5.0-SNAPSHOT", "private": true, "dependencies": { - "@scm-manager/ui-components": "^2.4.1", - "@scm-manager/ui-extensions": "^2.1.0", + "@scm-manager/ui-components": "^2.5.0-SNAPSHOT", + "@scm-manager/ui-extensions": "^2.5.0-SNAPSHOT", "classnames": "^2.2.5", "history": "^4.10.1", "i18next": "^19.6.0", @@ -29,7 +29,7 @@ "test": "jest" }, "devDependencies": { - "@scm-manager/ui-tests": "^2.1.0", + "@scm-manager/ui-tests": "^2.5.0-SNAPSHOT", "@types/classnames": "^2.2.9", "@types/enzyme": "^3.10.3", "@types/fetch-mock": "^7.3.1", From af9e2529caf9a2075524b950679df35a591c2c3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 3 Sep 2020 14:26:58 +0200 Subject: [PATCH 19/23] Adapt test to additional 'date' attribute in tag object --- .../src/test/java/sonia/scm/it/RepositoryAccessITCase.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java b/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java index e75fbb9e69..e3311f2296 100644 --- a/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java +++ b/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.it; import groovy.util.logging.Slf4j; @@ -178,9 +178,9 @@ public class RepositoryAccessITCase { .isGreaterThan(0); assertThat(response.body().jsonPath().getMap("_embedded.tags.find{it.name=='" + tagName + "'}")) - .as("assert tag name and revision") + .as("assert tag has attributes for name, revision, date and links") .isNotNull() - .hasSize(3) + .hasSize(4) .containsEntry("name", tagName) .containsEntry("revision", changeset.getId()); From bc13d715cc4a041a5d4d2c0dcad82ec157e6b42e Mon Sep 17 00:00:00 2001 From: snyk-bot Date: Wed, 2 Sep 2020 22:15:48 +0000 Subject: [PATCH 20/23] fix: upgrade org.apache.shiro:shiro-core from 1.5.3 to 1.6.0 Snyk has created this PR to upgrade org.apache.shiro:shiro-core from 1.5.3 to 1.6.0. See this package in Maven Repository: https://mvnrepository.com/artifact/org.apache.shiro/shiro-core/ See this project in Snyk: https://app.snyk.io/org/scm-manager/project/0397d943-538d-483e-9c87-a3f7e7665d7b?utm_source=github&utm_medium=upgrade-pr --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 280c1e73ee..edc597c901 100644 --- a/pom.xml +++ b/pom.xml @@ -930,7 +930,7 @@ 1.2.0 - 1.5.3 + 1.6.0 5.6.1.202002131546-r-scm1 From 89aa1dbe167ada7550dedf57fc11a969bed3c8e4 Mon Sep 17 00:00:00 2001 From: galinette-34 <62066654+galinette-34@users.noreply.github.com> Date: Thu, 3 Sep 2020 14:56:04 +0200 Subject: [PATCH 21/23] Update ProtocolInformation.tsx Second output redirection to file .hg/hgrc need operator ">>" --- scm-plugins/scm-hg-plugin/src/main/js/ProtocolInformation.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scm-plugins/scm-hg-plugin/src/main/js/ProtocolInformation.tsx b/scm-plugins/scm-hg-plugin/src/main/js/ProtocolInformation.tsx index 1a23cf5428..5d964336ee 100644 --- a/scm-plugins/scm-hg-plugin/src/main/js/ProtocolInformation.tsx +++ b/scm-plugins/scm-hg-plugin/src/main/js/ProtocolInformation.tsx @@ -53,7 +53,7 @@ class ProtocolInformation extends React.Component { echo "[paths]" > .hg/hgrc
echo "default = {href} - " > .hg/hgrc + " >> .hg/hgrc
echo "# {repository.name} " > README.md From 8ec782bc9332064aa9660747eb00b029eb255521 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 4 Sep 2020 07:20:56 +0200 Subject: [PATCH 22/23] Update jdk to 11.0.8 for docker installations --- scm-packaging/docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scm-packaging/docker/Dockerfile b/scm-packaging/docker/Dockerfile index b1ec5d7f6d..be60fa9fbe 100644 --- a/scm-packaging/docker/Dockerfile +++ b/scm-packaging/docker/Dockerfile @@ -22,7 +22,7 @@ # SOFTWARE. # -FROM adoptopenjdk/openjdk11:jdk-11.0.7_10-alpine-slim +FROM adoptopenjdk/openjdk11:jdk-11.0.8_10-alpine-slim ENV SCM_HOME=/var/lib/scm ENV CACHE_DIR=/var/cache/scm/work From a7491ea45f1e1560d076bfac1bdd3bef46b5dc02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Fri, 4 Sep 2020 07:35:51 +0200 Subject: [PATCH 23/23] Describe how data and plugins are migrated to v2 --- CHANGELOG.md | 1 + docs/en/migrate-scm-manager-from-v1/index.md | 18 +++++++++++++++++- .../templates/repository-migration.mustache | 6 ++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4e859c4ce..c862e998c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Tags now have date information attached ([#1305](https://github.com/scm-manager/scm-manager/pull/1305)) - Add support for scroll anchors in url hash of diff page ([#1304](https://github.com/scm-manager/scm-manager/pull/1304)) +- Documentation regarding data and plugin migration from v1 to v2 ([#1321](https://github.com/scm-manager/scm-manager/pull/1321)) ### Fixed - Redirection to requested page after login in anonymous mode diff --git a/docs/en/migrate-scm-manager-from-v1/index.md b/docs/en/migrate-scm-manager-from-v1/index.md index 0adbed9034..5cbe5f4419 100644 --- a/docs/en/migrate-scm-manager-from-v1/index.md +++ b/docs/en/migrate-scm-manager-from-v1/index.md @@ -3,9 +3,15 @@ title: Migrate from v1 to v2 subtitle: How to use the Migration-Wizard --- +# Preparation + To upgrade an SCM-Manager from version 1 to version 2, some changes have to be made according the home directory of the SCM-Manager. So before you start, **make sure that you have an up to date backup of your SCM home folder!** -Before the migration process can be started, the last running version of SCM-Manager had to be (at least) 1.60. Data of older versions cannot be migrated automatically. If this is the case, you can stop version 1 and start a version 2 SCM-Manager (make sure that you have configured the same SCM home folder). When SCM-Manager starts for the first time, you have to choose how to migrate your existing repositories. The background of this is the following: +Before the migration process can be started, the last running version of SCM-Manager had to be (at least) 1.60. Data of older versions cannot be migrated automatically. If this is the case, you can stop version 1 and start a version 2 SCM-Manager (make sure that you have configured the same SCM home folder). + +# Repository migration + +When SCM-Manager starts for the first time, you have to choose how to migrate your existing repositories. The background of this is the following: While in version 1 of SCM-Manager the repositories were stored in a directory according to their type (`git`, `hg` or `svn`) and their name, in version 2 the directory is independent of the type and name. Therefore a repository is no longer named with an arbitrary number of name parts devided by slashes (`/`), but it has a namespace and a name (both of which must not contain slashes). The namespace should be used to group your repositories (for example you can use this to distinguish between the types of repositories like *git* and *hg* like version 1 or to assign them to different projects or users). @@ -37,6 +43,16 @@ In the figure you can see an example of the page. We tried to guess meaningful n The probably most safe strategy (but also the most costly) is *COPY*. The old folder of the repository will be kept and all data will be copied to the new default folder (so this also is the default). *MOVE* and *INLINE* are more efficient. When you have a lot of repositories, maybe you will take the chance to clean them up and *IGNORE* or even *DELETE* old stuff. +# Migration of other data + +For version 2 of SCM-Manager we introduced a new way to store data for repositories. We did our best to migrate old data like settings in plugins, so that nothing will be lost during update. What we did **not** do is to automatically install the new versions of your plugins. When you start your new instance, you will get a clean instance. You can install your new plugins from the administration page. Any plugin related data or settings will be migrated automatically. + +# Manual plugin installation + +If however you have to install plugins manually (for example because you cannot log in without the LDAP plugin), you can download them from the [plugins section](https://www.scm-manager.org/plugins/#categories) on our homepage. The download can be found in the "Releases" section of each plugin. Just store the `smp` file in the `plugin` directory of your SCM home and restart your server. + +# Huge number of repositories + If you have more than 100 Repositories to migrate, you may have to adapt some configuration and increase the limit of jetty form keys. You can do this by setting the `maxFormKeys` and `maxFormContentSize` of the webapp in `conf/server-config.xml`. You have to add the keys to the `WebAppContext` with the id `"scm-webapp"` e.g.: ``` diff --git a/scm-webapp/src/main/resources/templates/repository-migration.mustache b/scm-webapp/src/main/resources/templates/repository-migration.mustache index 0845655c90..c2d6db2843 100644 --- a/scm-webapp/src/main/resources/templates/repository-migration.mustache +++ b/scm-webapp/src/main/resources/templates/repository-migration.mustache @@ -30,6 +30,12 @@
{{/validationErrorsFound}} +

+ Please note that your old plugins from version 1 will not be installed automatically. + After this migration step you can install plugins from the "Plugins" section in the "Administration" + panel again. Data and settings for plugins will then be migrated on the fly. +

+