Merged in feature/harmonize_branches_in_changesets (pull request #81)

Add branch to changeset collections
This commit is contained in:
Sebastian Sdorra
2018-10-09 09:10:20 +00:00
17 changed files with 292 additions and 158 deletions

View File

@@ -82,6 +82,22 @@ public class ChangesetPagingResult implements Iterable<Changeset>, Serializable
{ {
this.total = total; this.total = total;
this.changesets = changesets; this.changesets = changesets;
this.branchName = null;
}
/**
* Constructs a new changeset paging result for a specific branch.
*
*
* @param total total number of changesets
* @param changesets current list of fetched changesets
* @param branchName branch name this result was created for
*/
public ChangesetPagingResult(int total, List<Changeset> changesets, String branchName)
{
this.total = total;
this.changesets = changesets;
this.branchName = branchName;
} }
//~--- methods -------------------------------------------------------------- //~--- methods --------------------------------------------------------------
@@ -158,6 +174,7 @@ public class ChangesetPagingResult implements Iterable<Changeset>, Serializable
return MoreObjects.toStringHelper(this) return MoreObjects.toStringHelper(this)
.add("changesets", changesets) .add("changesets", changesets)
.add("total", total) .add("total", total)
.add("branch", branchName)
.toString(); .toString();
//J+ //J+
} }
@@ -186,37 +203,35 @@ public class ChangesetPagingResult implements Iterable<Changeset>, Serializable
return total; return total;
} }
//~--- set methods ---------------------------------------------------------- void setChangesets(List<Changeset> changesets)
/**
* Sets the current list of changesets.
*
*
* @param changesets current list of changesets
*/
public void setChangesets(List<Changeset> changesets)
{ {
this.changesets = changesets; this.changesets = changesets;
} }
/** void setTotal(int total)
* Sets the total number of changesets
*
*
* @param total total number of changesets
*/
public void setTotal(int total)
{ {
this.total = total; this.total = total;
} }
void setBranchName(String branchName) {
this.branchName = branchName;
}
/**
* Returns the branch name this result was created for. This can either be an explicit branch ("give me all
* changesets for branch xyz") or an implicit one ("give me the changesets for the default").
*/
public String getBranchName() {
return branchName;
}
//~--- fields --------------------------------------------------------------- //~--- fields ---------------------------------------------------------------
/** current list of changesets */
@XmlElement(name = "changeset") @XmlElement(name = "changeset")
@XmlElementWrapper(name = "changesets") @XmlElementWrapper(name = "changesets")
private List<Changeset> changesets; private List<Changeset> changesets;
/** total number of changesets */
private int total; private int total;
private String branchName;
} }

View File

@@ -39,7 +39,6 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.TreeWalk;
@@ -51,8 +50,8 @@ import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set;
//~--- JDK imports ------------------------------------------------------------ //~--- JDK imports ------------------------------------------------------------
@@ -130,27 +129,9 @@ public class GitChangesetConverter implements Closeable
* *
* @throws IOException * @throws IOException
*/ */
public Changeset createChangeset(RevCommit commit) throws IOException public Changeset createChangeset(RevCommit commit)
{ {
List<String> branches = Lists.newArrayList(); return createChangeset(commit, Collections.emptyList());
Set<Ref> refs = repository.getAllRefsByPeeledObjectId().get(commit.getId());
if (Util.isNotEmpty(refs))
{
for (Ref ref : refs)
{
String branch = GitUtil.getBranch(ref);
if (branch != null)
{
branches.add(branch);
}
}
}
return createChangeset(commit, branches);
} }
/** /**
@@ -165,7 +146,6 @@ public class GitChangesetConverter implements Closeable
* @throws IOException * @throws IOException
*/ */
public Changeset createChangeset(RevCommit commit, String branch) public Changeset createChangeset(RevCommit commit, String branch)
throws IOException
{ {
return createChangeset(commit, Lists.newArrayList(branch)); return createChangeset(commit, Lists.newArrayList(branch));
} }
@@ -183,7 +163,6 @@ public class GitChangesetConverter implements Closeable
* @throws IOException * @throws IOException
*/ */
public Changeset createChangeset(RevCommit commit, List<String> branches) public Changeset createChangeset(RevCommit commit, List<String> branches)
throws IOException
{ {
String id = commit.getId().name(); String id = commit.getId().name();
List<String> parentList = null; List<String> parentList = null;

View File

@@ -63,8 +63,11 @@ import javax.servlet.http.HttpServletRequest;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static java.util.Optional.of;
//~--- JDK imports ------------------------------------------------------------ //~--- JDK imports ------------------------------------------------------------
/** /**
@@ -345,12 +348,11 @@ public final class GitUtil
* *
* @throws IOException * @throws IOException
*/ */
public static ObjectId getBranchId(org.eclipse.jgit.lib.Repository repo, public static Ref getBranchId(org.eclipse.jgit.lib.Repository repo,
String branchName) String branchName)
throws IOException throws IOException
{ {
ObjectId branchId = null; Ref ref = null;
if (!branchName.startsWith(REF_HEAD)) if (!branchName.startsWith(REF_HEAD))
{ {
branchName = PREFIX_HEADS.concat(branchName); branchName = PREFIX_HEADS.concat(branchName);
@@ -360,24 +362,19 @@ public final class GitUtil
try try
{ {
Ref ref = repo.findRef(branchName); ref = repo.findRef(branchName);
if (ref != null) if (ref == null)
{
branchId = ref.getObjectId();
}
else if (logger.isWarnEnabled())
{ {
logger.warn("could not find branch for {}", branchName); logger.warn("could not find branch for {}", branchName);
} }
} }
catch (IOException ex) catch (IOException ex)
{ {
logger.warn("error occured during resolve of branch id", ex); logger.warn("error occured during resolve of branch id", ex);
} }
return branchId; return ref;
} }
/** /**
@@ -499,68 +496,48 @@ public final class GitUtil
return ref; return ref;
} }
/** public static ObjectId getRepositoryHead(org.eclipse.jgit.lib.Repository repo) {
* Method description return getRepositoryHeadRef(repo).map(Ref::getObjectId).orElse(null);
* }
*
* @param repo
*
* @return
*
* @throws IOException
*/
public static ObjectId getRepositoryHead(org.eclipse.jgit.lib.Repository repo)
throws IOException
{
ObjectId id = null;
String head = null;
Map<String, Ref> refs = repo.getAllRefs();
for (Map.Entry<String, Ref> e : refs.entrySet()) public static Optional<Ref> getRepositoryHeadRef(org.eclipse.jgit.lib.Repository repo) {
{ Optional<Ref> foundRef = findMostAppropriateHead(repo.getAllRefs());
String key = e.getKey();
if (REF_HEAD.equals(key)) if (foundRef.isPresent()) {
{ if (logger.isDebugEnabled()) {
head = REF_HEAD; logger.debug("use {}:{} as repository head for directory {}",
id = e.getValue().getObjectId(); foundRef.map(GitUtil::getBranch).orElse(null),
foundRef.map(Ref::getObjectId).map(ObjectId::name).orElse(null),
break; repo.getDirectory());
}
else if (key.startsWith(REF_HEAD_PREFIX))
{
id = e.getValue().getObjectId();
head = key.substring(REF_HEAD_PREFIX.length());
if (REF_MASTER.equals(head))
{
break;
}
} }
} else {
logger.warn("could not find repository head in directory {}", repo.getDirectory());
} }
if (id == null) return foundRef;
{ }
id = repo.resolve(Constants.HEAD);
private static Optional<Ref> findMostAppropriateHead(Map<String, Ref> refs) {
Ref refHead = refs.get(REF_HEAD);
if (refHead != null && refHead.isSymbolic() && isBranch(refHead.getTarget().getName())) {
return of(refHead.getTarget());
} }
if (logger.isDebugEnabled()) Ref master = refs.get(REF_HEAD_PREFIX + REF_MASTER);
{ if (master != null) {
if ((head != null) && (id != null)) return of(master);
{
logger.debug("use {}:{} as repository head", head, id.name());
}
else if (id != null)
{
logger.debug("use {} as repository head", id.name());
}
else
{
logger.warn("could not find repository head");
}
} }
return id; Ref develop = refs.get(REF_HEAD_PREFIX + "develop");
if (develop != null) {
return of(develop);
}
return refs.entrySet()
.stream()
.filter(e -> e.getKey().startsWith(REF_HEAD_PREFIX))
.map(Map.Entry::getValue)
.findFirst();
} }
/** /**
@@ -648,7 +625,7 @@ public final class GitUtil
return tagName; return tagName;
} }
/** /**
* Method description * Method description
* *

View File

@@ -34,19 +34,20 @@ package sonia.scm.repository.spi;
//~--- non-JDK imports -------------------------------------------------------- //~--- non-JDK imports --------------------------------------------------------
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import org.eclipse.jgit.lib.Repository;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import sonia.scm.repository.GitConstants; import sonia.scm.repository.GitConstants;
import sonia.scm.repository.GitUtil; import sonia.scm.repository.GitUtil;
import java.io.IOException;
import java.util.Optional;
//~--- JDK imports ------------------------------------------------------------
/** /**
* *
* @author Sebastian Sdorra * @author Sebastian Sdorra
@@ -97,27 +98,29 @@ public class AbstractGitCommand
} }
return commit; return commit;
} }
protected ObjectId getBranchOrDefault(Repository gitRepository, String requestedBranch) throws IOException {
ObjectId head;
if ( Strings.isNullOrEmpty(requestedBranch) ) {
head = getDefaultBranch(gitRepository);
} else {
head = GitUtil.getBranchId(gitRepository, requestedBranch);
}
return head;
}
protected ObjectId getDefaultBranch(Repository gitRepository) throws IOException { protected ObjectId getDefaultBranch(Repository gitRepository) throws IOException {
ObjectId head; Ref ref = getBranchOrDefault(gitRepository, null);
String defaultBranchName = repository.getProperty(GitConstants.PROPERTY_DEFAULT_BRANCH); if (ref == null) {
if (!Strings.isNullOrEmpty(defaultBranchName)) { return null;
head = GitUtil.getBranchId(gitRepository, defaultBranchName);
} else { } else {
logger.trace("no default branch configured, use repository head as default"); return ref.getObjectId();
head = GitUtil.getRepositoryHead(gitRepository); }
}
protected Ref getBranchOrDefault(Repository gitRepository, String requestedBranch) throws IOException {
if ( Strings.isNullOrEmpty(requestedBranch) ) {
String defaultBranchName = repository.getProperty(GitConstants.PROPERTY_DEFAULT_BRANCH);
if (!Strings.isNullOrEmpty(defaultBranchName)) {
return GitUtil.getBranchId(gitRepository, defaultBranchName);
} else {
logger.trace("no default branch configured, use repository head as default");
Optional<Ref> repositoryHeadRef = GitUtil.getRepositoryHeadRef(gitRepository);
return repositoryHeadRef.orElse(null);
}
} else {
return GitUtil.getBranchId(gitRepository, requestedBranch);
} }
return head;
} }
//~--- fields --------------------------------------------------------------- //~--- fields ---------------------------------------------------------------

View File

@@ -39,6 +39,7 @@ import com.google.common.base.Strings;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.revwalk.RevWalk;
@@ -170,8 +171,8 @@ public class GitLogCommand extends AbstractGitCommand implements LogCommand
GitChangesetConverter converter = null; GitChangesetConverter converter = null;
RevWalk revWalk = null; RevWalk revWalk = null;
try (org.eclipse.jgit.lib.Repository gr = open()) { try (org.eclipse.jgit.lib.Repository repository = open()) {
if (!gr.getAllRefs().isEmpty()) { if (!repository.getAllRefs().isEmpty()) {
int counter = 0; int counter = 0;
int start = request.getPagingStart(); int start = request.getPagingStart();
@@ -188,18 +189,18 @@ public class GitLogCommand extends AbstractGitCommand implements LogCommand
ObjectId startId = null; ObjectId startId = null;
if (!Strings.isNullOrEmpty(request.getStartChangeset())) { if (!Strings.isNullOrEmpty(request.getStartChangeset())) {
startId = gr.resolve(request.getStartChangeset()); startId = repository.resolve(request.getStartChangeset());
} }
ObjectId endId = null; ObjectId endId = null;
if (!Strings.isNullOrEmpty(request.getEndChangeset())) { if (!Strings.isNullOrEmpty(request.getEndChangeset())) {
endId = gr.resolve(request.getEndChangeset()); endId = repository.resolve(request.getEndChangeset());
} }
revWalk = new RevWalk(gr); revWalk = new RevWalk(repository);
converter = new GitChangesetConverter(gr, revWalk); converter = new GitChangesetConverter(repository, revWalk);
if (!Strings.isNullOrEmpty(request.getPath())) { if (!Strings.isNullOrEmpty(request.getPath())) {
revWalk.setTreeFilter( revWalk.setTreeFilter(
@@ -207,13 +208,13 @@ public class GitLogCommand extends AbstractGitCommand implements LogCommand
PathFilter.create(request.getPath()), TreeFilter.ANY_DIFF)); PathFilter.create(request.getPath()), TreeFilter.ANY_DIFF));
} }
ObjectId head = getBranchOrDefault(gr, request.getBranch()); Ref branch = getBranchOrDefault(repository,request.getBranch());
if (head != null) { if (branch != null) {
if (startId != null) { if (startId != null) {
revWalk.markStart(revWalk.lookupCommit(startId)); revWalk.markStart(revWalk.lookupCommit(startId));
} else { } else {
revWalk.markStart(revWalk.lookupCommit(head)); revWalk.markStart(revWalk.lookupCommit(branch.getObjectId()));
} }
Iterator<RevCommit> iterator = revWalk.iterator(); Iterator<RevCommit> iterator = revWalk.iterator();
@@ -234,10 +235,14 @@ public class GitLogCommand extends AbstractGitCommand implements LogCommand
} }
} }
changesets = new ChangesetPagingResult(counter, changesetList); if (branch != null) {
changesets = new ChangesetPagingResult(counter, changesetList, GitUtil.getBranch(branch.getName()));
} else {
changesets = new ChangesetPagingResult(counter, changesetList);
}
} else if (logger.isWarnEnabled()) { } else if (logger.isWarnEnabled()) {
logger.warn("the repository {} seems to be empty", logger.warn("the repository {} seems to be empty",
repository.getName()); this.repository.getName());
changesets = new ChangesetPagingResult(0, Collections.EMPTY_LIST); changesets = new ChangesetPagingResult(0, Collections.EMPTY_LIST);
} }

View File

@@ -1,3 +1,4 @@
/** /**
* Copyright (c) 2010, Sebastian Sdorra * Copyright (c) 2010, Sebastian Sdorra
* All rights reserved. * All rights reserved.
@@ -33,14 +34,17 @@
package sonia.scm.repository.spi; package sonia.scm.repository.spi;
//~--- non-JDK imports -------------------------------------------------------- import com.google.common.io.Files;
import org.junit.Test; import org.junit.Test;
import sonia.scm.repository.Changeset; import sonia.scm.repository.Changeset;
import sonia.scm.repository.ChangesetPagingResult; import sonia.scm.repository.ChangesetPagingResult;
import sonia.scm.repository.GitConstants; import sonia.scm.repository.GitConstants;
import sonia.scm.repository.Modifications; import sonia.scm.repository.Modifications;
import java.io.File;
import java.io.IOException;
import static java.nio.charset.Charset.defaultCharset;
import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.contains;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
@@ -48,8 +52,6 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
//~--- JDK imports ------------------------------------------------------------
/** /**
* Unit tests for {@link GitLogCommand}. * Unit tests for {@link GitLogCommand}.
* *
@@ -72,6 +74,8 @@ public class GitLogCommandTest extends AbstractGitCommandTestBase
assertEquals("86a6645eceefe8b9a247db5eb16e3d89a7e6e6d1", result.getChangesets().get(1).getId()); assertEquals("86a6645eceefe8b9a247db5eb16e3d89a7e6e6d1", result.getChangesets().get(1).getId());
assertEquals("592d797cd36432e591416e8b2b98154f4f163411", result.getChangesets().get(2).getId()); assertEquals("592d797cd36432e591416e8b2b98154f4f163411", result.getChangesets().get(2).getId());
assertEquals("435df2f061add3589cb326cc64be9b9c3897ceca", result.getChangesets().get(3).getId()); assertEquals("435df2f061add3589cb326cc64be9b9c3897ceca", result.getChangesets().get(3).getId());
assertEquals("master", result.getBranchName());
assertTrue(result.getChangesets().stream().allMatch(r -> r.getBranches().isEmpty()));
// set default branch and fetch again // set default branch and fetch again
repository.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "test-branch"); repository.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "test-branch");
@@ -79,10 +83,12 @@ public class GitLogCommandTest extends AbstractGitCommandTestBase
result = createCommand().getChangesets(new LogCommandRequest()); result = createCommand().getChangesets(new LogCommandRequest());
assertNotNull(result); assertNotNull(result);
assertEquals("test-branch", result.getBranchName());
assertEquals(3, result.getTotal()); assertEquals(3, result.getTotal());
assertEquals("3f76a12f08a6ba0dc988c68b7f0b2cd190efc3c4", result.getChangesets().get(0).getId()); assertEquals("3f76a12f08a6ba0dc988c68b7f0b2cd190efc3c4", result.getChangesets().get(0).getId());
assertEquals("592d797cd36432e591416e8b2b98154f4f163411", result.getChangesets().get(1).getId()); assertEquals("592d797cd36432e591416e8b2b98154f4f163411", result.getChangesets().get(1).getId());
assertEquals("435df2f061add3589cb326cc64be9b9c3897ceca", result.getChangesets().get(2).getId()); assertEquals("435df2f061add3589cb326cc64be9b9c3897ceca", result.getChangesets().get(2).getId());
assertTrue(result.getChangesets().stream().allMatch(r -> r.getBranches().isEmpty()));
} }
@Test @Test
@@ -210,6 +216,32 @@ public class GitLogCommandTest extends AbstractGitCommandTestBase
assertEquals("435df2f061add3589cb326cc64be9b9c3897ceca", c2.getId()); assertEquals("435df2f061add3589cb326cc64be9b9c3897ceca", c2.getId());
} }
@Test
public void shouldFindDefaultBranchFromHEAD() throws Exception {
setRepositoryHeadReference("ref: refs/heads/test-branch");
ChangesetPagingResult changesets = createCommand().getChangesets(new LogCommandRequest());
assertEquals("test-branch", changesets.getBranchName());
}
@Test
public void shouldFindMasterBranchWhenHEADisNoRef() throws Exception {
setRepositoryHeadReference("592d797cd36432e591416e8b2b98154f4f163411");
ChangesetPagingResult changesets = createCommand().getChangesets(new LogCommandRequest());
assertEquals("master", changesets.getBranchName());
}
private void setRepositoryHeadReference(String s) throws IOException {
Files.write(s, repositoryHeadReferenceFile(), defaultCharset());
}
private File repositoryHeadReferenceFile() {
return new File(repositoryDirectory, "HEAD");
}
private GitLogCommand createCommand() private GitLogCommand createCommand()
{ {
return new GitLogCommand(createContext(), repository); return new GitLogCommand(createContext(), repository);

View File

@@ -132,7 +132,11 @@ public class HgLogCommand extends AbstractCommand implements LogCommand
List<Changeset> changesets = on(repository).rev(start + ":" List<Changeset> changesets = on(repository).rev(start + ":"
+ end).execute(); + end).execute();
result = new ChangesetPagingResult(total, changesets); if (request.getBranch() == null) {
result = new ChangesetPagingResult(total, changesets);
} else {
result = new ChangesetPagingResult(total, changesets, request.getBranch());
}
} }
else else
{ {

View File

@@ -216,10 +216,7 @@ public abstract class AbstractChangesetCommand extends AbstractCommand
String branch = in.textUpTo('\n'); String branch = in.textUpTo('\n');
if (!BRANCH_DEFAULT.equals(branch)) changeset.getBranches().add(branch);
{
changeset.getBranches().add(branch);
}
String p1 = readId(in, changeset, PROPERTY_PARENT1_REVISION); String p1 = readId(in, changeset, PROPERTY_PARENT1_REVISION);

View File

@@ -88,6 +88,21 @@ public class HgLogCommandTest extends AbstractHgCommandTestBase
result.getChangesets().get(2).getId()); result.getChangesets().get(2).getId());
} }
@Test
public void testGetDefaultBranchInfo() {
LogCommandRequest request = new LogCommandRequest();
request.setPath("a.txt");
ChangesetPagingResult result = createComamnd().getChangesets(request);
assertNotNull(result);
assertEquals(1,
result.getChangesets().get(0).getBranches().size());
assertEquals("default",
result.getChangesets().get(0).getBranches().get(0));
}
@Test @Test
public void testGetAllWithLimit() { public void testGetAllWithLimit() {
LogCommandRequest request = new LogCommandRequest(); LogCommandRequest request = new LogCommandRequest();

View File

@@ -12,12 +12,12 @@ public class BranchChangesetCollectionToDtoMapper extends ChangesetCollectionToD
@Inject @Inject
public BranchChangesetCollectionToDtoMapper(ChangesetToChangesetDtoMapper changesetToChangesetDtoMapper, ResourceLinks resourceLinks) { public BranchChangesetCollectionToDtoMapper(ChangesetToChangesetDtoMapper changesetToChangesetDtoMapper, ResourceLinks resourceLinks) {
super(changesetToChangesetDtoMapper); super(changesetToChangesetDtoMapper, resourceLinks);
this.resourceLinks = resourceLinks; this.resourceLinks = resourceLinks;
} }
public CollectionDto map(int pageNumber, int pageSize, PageResult<Changeset> pageResult, Repository repository, String branch) { public CollectionDto map(int pageNumber, int pageSize, PageResult<Changeset> pageResult, Repository repository, String branch) {
return this.map(pageNumber, pageSize, pageResult, repository, () -> createSelfLink(repository, branch)); return this.map(pageNumber, pageSize, pageResult, repository, () -> createSelfLink(repository, branch), branch);
} }
private String createSelfLink(Repository repository, String branch) { private String createSelfLink(Repository repository, String branch) {

View File

@@ -0,0 +1,19 @@
package sonia.scm.api.v2.resources;
import de.otto.edison.hal.HalRepresentation;
import de.otto.edison.hal.Links;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@NoArgsConstructor @AllArgsConstructor @Getter @Setter
public class BranchReferenceDto extends HalRepresentation {
private String name;
@Override
@SuppressWarnings("squid:S1185") // We want to have this method available in this package
protected HalRepresentation add(Links links) {
return super.add(links);
}
}

View File

@@ -12,10 +12,13 @@ public class ChangesetCollectionToDtoMapper extends ChangesetCollectionToDtoMapp
@Inject @Inject
public ChangesetCollectionToDtoMapper(ChangesetToChangesetDtoMapper changesetToChangesetDtoMapper, ResourceLinks resourceLinks) { public ChangesetCollectionToDtoMapper(ChangesetToChangesetDtoMapper changesetToChangesetDtoMapper, ResourceLinks resourceLinks) {
super(changesetToChangesetDtoMapper); super(changesetToChangesetDtoMapper, resourceLinks);
this.resourceLinks = resourceLinks; this.resourceLinks = resourceLinks;
} }
public CollectionDto map(int pageNumber, int pageSize, PageResult<Changeset> pageResult, Repository repository, String branchName) {
return super.map(pageNumber, pageSize, pageResult, repository, () -> createSelfLink(repository), branchName);
}
public CollectionDto map(int pageNumber, int pageSize, PageResult<Changeset> pageResult, Repository repository) { public CollectionDto map(int pageNumber, int pageSize, PageResult<Changeset> pageResult, Repository repository) {
return super.map(pageNumber, pageSize, pageResult, repository, () -> createSelfLink(repository)); return super.map(pageNumber, pageSize, pageResult, repository, () -> createSelfLink(repository));
} }

View File

@@ -1,5 +1,6 @@
package sonia.scm.api.v2.resources; package sonia.scm.api.v2.resources;
import de.otto.edison.hal.Links;
import sonia.scm.PageResult; import sonia.scm.PageResult;
import sonia.scm.repository.Changeset; import sonia.scm.repository.Changeset;
import sonia.scm.repository.Repository; import sonia.scm.repository.Repository;
@@ -10,14 +11,28 @@ import java.util.function.Supplier;
class ChangesetCollectionToDtoMapperBase extends PagedCollectionToDtoMapper<Changeset, ChangesetDto> { class ChangesetCollectionToDtoMapperBase extends PagedCollectionToDtoMapper<Changeset, ChangesetDto> {
private final ChangesetToChangesetDtoMapper changesetToChangesetDtoMapper; private final ChangesetToChangesetDtoMapper changesetToChangesetDtoMapper;
private final ResourceLinks resourceLinks;
ChangesetCollectionToDtoMapperBase(ChangesetToChangesetDtoMapper changesetToChangesetDtoMapper) { ChangesetCollectionToDtoMapperBase(ChangesetToChangesetDtoMapper changesetToChangesetDtoMapper, ResourceLinks resourceLinks) {
super("changesets"); super("changesets");
this.changesetToChangesetDtoMapper = changesetToChangesetDtoMapper; this.changesetToChangesetDtoMapper = changesetToChangesetDtoMapper;
this.resourceLinks = resourceLinks;
} }
CollectionDto map(int pageNumber, int pageSize, PageResult<Changeset> pageResult, Repository repository, Supplier<String> selfLinkSupplier) { CollectionDto map(int pageNumber, int pageSize, PageResult<Changeset> pageResult, Repository repository, Supplier<String> selfLinkSupplier) {
return super.map(pageNumber, pageSize, pageResult, selfLinkSupplier.get(), Optional.empty(), changeset -> changesetToChangesetDtoMapper.map(changeset, repository)); return super.map(pageNumber, pageSize, pageResult, selfLinkSupplier.get(), Optional.empty(), changeset -> changesetToChangesetDtoMapper.map(changeset, repository));
} }
}
CollectionDto map(int pageNumber, int pageSize, PageResult<Changeset> pageResult, Repository repository, Supplier<String> selfLinkSupplier, String branchName) {
CollectionDto collectionDto = this.map(pageNumber, pageSize, pageResult, repository, selfLinkSupplier);
collectionDto.withEmbedded("branch", createBranchReferenceDto(repository, branchName));
return collectionDto;
}
private BranchReferenceDto createBranchReferenceDto(Repository repository, String branchName) {
BranchReferenceDto branchReferenceDto = new BranchReferenceDto();
branchReferenceDto.setName(branchName);
branchReferenceDto.add(Links.linkingTo().self(resourceLinks.branch().self(repository.getNamespaceAndName(), branchName)).build());
return branchReferenceDto;
}
}

View File

@@ -65,7 +65,11 @@ public class ChangesetRootResource {
.getChangesets(); .getChangesets();
if (changesets != null && changesets.getChangesets() != null) { if (changesets != null && changesets.getChangesets() != null) {
PageResult<Changeset> pageResult = new PageResult<>(changesets.getChangesets(), changesets.getTotal()); PageResult<Changeset> pageResult = new PageResult<>(changesets.getChangesets(), changesets.getTotal());
return Response.ok(changesetCollectionToDtoMapper.map(page, pageSize, pageResult, repository)).build(); if (changesets.getBranchName() != null) {
return Response.ok(changesetCollectionToDtoMapper.map(page, pageSize, pageResult, repository, changesets.getBranchName())).build();
} else {
return Response.ok(changesetCollectionToDtoMapper.map(page, pageSize, pageResult, repository)).build();
}
} else { } else {
return Response.ok().build(); return Response.ok().build();
} }

View File

@@ -15,4 +15,9 @@ class CollectionDto extends HalRepresentation {
CollectionDto(Links links, Embedded embedded) { CollectionDto(Links links, Embedded embedded) {
super(links, embedded); super(links, embedded);
} }
@Override
protected HalRepresentation withEmbedded(String rel, HalRepresentation embeddedItem) {
return super.withEmbedded(rel, embeddedItem);
}
} }

View File

@@ -13,7 +13,7 @@ public class FileHistoryCollectionToDtoMapper extends ChangesetCollectionToDtoMa
@Inject @Inject
public FileHistoryCollectionToDtoMapper(ChangesetToChangesetDtoMapper changesetToChangesetDtoMapper, ResourceLinks resourceLinks) { public FileHistoryCollectionToDtoMapper(ChangesetToChangesetDtoMapper changesetToChangesetDtoMapper, ResourceLinks resourceLinks) {
super(changesetToChangesetDtoMapper); super(changesetToChangesetDtoMapper, resourceLinks);
this.resourceLinks = resourceLinks; this.resourceLinks = resourceLinks;
} }

View File

@@ -0,0 +1,61 @@
package sonia.scm.api.v2.resources;
import org.assertj.core.api.Assertions;
import org.junit.Test;
import sonia.scm.PageResult;
import sonia.scm.repository.Changeset;
import sonia.scm.repository.Repository;
import java.net.URI;
import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class ChangesetCollectionToDtoMapperTest {
public static final Repository REPOSITORY = new Repository("", "git", "space", "name");
public static final Changeset CHANGESET = new Changeset();
private final ChangesetToChangesetDtoMapper changesetToChangesetDtoMapper = mock(ChangesetToChangesetDtoMapper.class);
private final ChangesetCollectionToDtoMapper changesetCollectionToDtoMapper = new ChangesetCollectionToDtoMapper(changesetToChangesetDtoMapper, ResourceLinksMock.createMock(URI.create("/")));
@Test
public void shouldMapCollectionEntries() {
ChangesetDto expectedChangesetDto = new ChangesetDto();
when(changesetToChangesetDtoMapper.map(CHANGESET, REPOSITORY)).thenReturn(expectedChangesetDto);
CollectionDto collectionDto = changesetCollectionToDtoMapper.map(0, 1, new PageResult<>(asList(CHANGESET), 1), REPOSITORY);
assertThat(collectionDto.getEmbedded().hasItem("changesets")).isTrue();
assertThat(collectionDto.getEmbedded().getItemsBy("changesets")).containsExactly(expectedChangesetDto);
assertThat(collectionDto.getEmbedded().hasItem("branch")).isFalse();
}
@Test
public void shouldNotEmbedBranchIfNotSpecified() {
ChangesetDto expectedChangesetDto = new ChangesetDto();
when(changesetToChangesetDtoMapper.map(CHANGESET, REPOSITORY)).thenReturn(expectedChangesetDto);
CollectionDto collectionDto = changesetCollectionToDtoMapper.map(0, 1, new PageResult<>(asList(CHANGESET), 1), REPOSITORY);
assertThat(collectionDto.getEmbedded().hasItem("branch")).isFalse();
}
@Test
public void shouldEmbedBranchIfSpecified() {
ChangesetDto expectedChangesetDto = new ChangesetDto();
when(changesetToChangesetDtoMapper.map(CHANGESET, REPOSITORY)).thenReturn(expectedChangesetDto);
CollectionDto collectionDto = changesetCollectionToDtoMapper.map(0, 1, new PageResult<>(asList(CHANGESET), 1), REPOSITORY, "someBranch");
assertThat(collectionDto.getEmbedded().hasItem("branch")).isTrue();
assertThat(collectionDto.getEmbedded().getItemsBy("branch"))
.hasSize(1)
.first().matches(b -> b.getLinks().getLinkBy("self").isPresent())
.extracting(b -> b.getLinks().getLinkBy("self").get().getHref()).first().isEqualTo("/v2/repositories/space/name/branches/someBranch");
assertThat(collectionDto.getEmbedded().getItemsBy("branch"))
.first().extracting("name").first().isEqualTo("someBranch");
}
}