Merge with 2.0.0-m3

This commit is contained in:
René Pfeuffer
2018-10-25 10:15:32 +02:00
110 changed files with 4668 additions and 1403 deletions

View File

@@ -35,9 +35,9 @@ package sonia.scm.repository.spi;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
@@ -106,6 +106,7 @@ public class GitBrowseCommand extends AbstractGitCommand
logger.debug("try to create browse result for {}", request);
BrowserResult result;
org.eclipse.jgit.lib.Repository repo = open();
ObjectId revId;
@@ -120,7 +121,7 @@ public class GitBrowseCommand extends AbstractGitCommand
if (revId != null)
{
result = getResult(repo, request, revId);
result = new BrowserResult(revId.getName(), getEntry(repo, request, revId));
}
else
{
@@ -133,8 +134,7 @@ public class GitBrowseCommand extends AbstractGitCommand
logger.warn("coul not find head of repository, empty?");
}
result = new BrowserResult(Constants.HEAD, null, null,
Collections.EMPTY_LIST);
result = new BrowserResult(Constants.HEAD, createEmtpyRoot());
}
return result;
@@ -142,6 +142,14 @@ public class GitBrowseCommand extends AbstractGitCommand
//~--- methods --------------------------------------------------------------
private FileObject createEmtpyRoot() {
FileObject fileObject = new FileObject();
fileObject.setName("");
fileObject.setPath("");
fileObject.setDirectory(true);
return fileObject;
}
/**
* Method description
*
@@ -157,68 +165,52 @@ public class GitBrowseCommand extends AbstractGitCommand
private FileObject createFileObject(org.eclipse.jgit.lib.Repository repo,
BrowseCommandRequest request, ObjectId revId, TreeWalk treeWalk)
throws IOException {
FileObject file;
try
FileObject file = new FileObject();
String path = treeWalk.getPathString();
file.setName(treeWalk.getNameString());
file.setPath(path);
SubRepository sub = null;
if (!request.isDisableSubRepositoryDetection())
{
file = new FileObject();
sub = getSubRepository(repo, revId, path);
}
String path = treeWalk.getPathString();
if (sub != null)
{
logger.trace("{} seems to be a sub repository", path);
file.setDirectory(true);
file.setSubRepository(sub);
}
else
{
ObjectLoader loader = repo.open(treeWalk.getObjectId(0));
file.setName(treeWalk.getNameString());
file.setPath(path);
file.setDirectory(loader.getType() == Constants.OBJ_TREE);
file.setLength(loader.getSize());
SubRepository sub = null;
if (!request.isDisableSubRepositoryDetection())
// don't show message and date for directories to improve performance
if (!file.isDirectory() &&!request.isDisableLastCommit())
{
sub = getSubRepository(repo, revId, path);
}
logger.trace("fetch last commit for {} at {}", path, revId.getName());
RevCommit commit = getLatestCommit(repo, revId, path);
if (sub != null)
{
logger.trace("{} seems to be a sub repository", path);
file.setDirectory(true);
file.setSubRepository(sub);
}
else
{
ObjectLoader loader = repo.open(treeWalk.getObjectId(0));
file.setDirectory(loader.getType() == Constants.OBJ_TREE);
file.setLength(loader.getSize());
// don't show message and date for directories to improve performance
if (!file.isDirectory() &&!request.isDisableLastCommit())
if (commit != null)
{
logger.trace("fetch last commit for {} at {}", path, revId.getName());
RevCommit commit = getLatestCommit(repo, revId, path);
if (commit != null)
{
file.setLastModified(GitUtil.getCommitTime(commit));
file.setDescription(commit.getShortMessage());
}
else if (logger.isWarnEnabled())
{
logger.warn("could not find latest commit for {} on {}", path,
revId);
}
file.setLastModified(GitUtil.getCommitTime(commit));
file.setDescription(commit.getShortMessage());
}
else if (logger.isWarnEnabled())
{
logger.warn("could not find latest commit for {} on {}", path,
revId);
}
}
}
catch (MissingObjectException ex)
{
file = null;
logger.error("could not fetch object for id {}", revId);
if (logger.isTraceEnabled())
{
logger.trace("could not fetch object", ex);
}
}
return file;
}
@@ -264,22 +256,19 @@ public class GitBrowseCommand extends AbstractGitCommand
return result;
}
private BrowserResult getResult(org.eclipse.jgit.lib.Repository repo,
BrowseCommandRequest request, ObjectId revId)
throws IOException {
BrowserResult result = null;
private FileObject getEntry(org.eclipse.jgit.lib.Repository repo, BrowseCommandRequest request, ObjectId revId) throws IOException {
RevWalk revWalk = null;
TreeWalk treeWalk = null;
try
{
if (logger.isDebugEnabled())
{
logger.debug("load repository browser for revision {}", revId.name());
}
FileObject result;
try {
logger.debug("load repository browser for revision {}", revId.name());
treeWalk = new TreeWalk(repo);
treeWalk.setRecursive(request.isRecursive());
if (!isRootRequest(request)) {
treeWalk.setFilter(PathFilter.create(request.getPath()));
}
revWalk = new RevWalk(repo);
RevTree tree = revWalk.parseTree(revId);
@@ -290,65 +279,20 @@ public class GitBrowseCommand extends AbstractGitCommand
}
else
{
logger.error("could not find tree for {}", revId.name());
throw new IllegalStateException("could not find tree for " + revId.name());
}
result = new BrowserResult();
List<FileObject> files = Lists.newArrayList();
String path = request.getPath();
if (Util.isEmpty(path))
{
while (treeWalk.next())
{
FileObject fo = createFileObject(repo, request, revId, treeWalk);
if (fo != null)
{
files.add(fo);
}
}
}
else
{
String[] parts = path.split("/");
int current = 0;
int limit = parts.length;
while (treeWalk.next())
{
String name = treeWalk.getNameString();
if (current >= limit)
{
String p = treeWalk.getPathString();
if (p.split("/").length > limit)
{
FileObject fo = createFileObject(repo, request, revId, treeWalk);
if (fo != null)
{
files.add(fo);
}
}
}
else if (name.equalsIgnoreCase(parts[current]))
{
current++;
if (!request.isRecursive())
{
treeWalk.enterSubtree();
}
}
if (isRootRequest(request)) {
result = createEmtpyRoot();
findChildren(result, repo, request, revId, treeWalk);
} else {
result = findFirstMatch(repo, request, revId, treeWalk);
if ( result.isDirectory() ) {
treeWalk.enterSubtree();
findChildren(result, repo, request, revId, treeWalk);
}
}
result.setFiles(files);
result.setRevision(revId.getName());
}
finally
{
@@ -359,6 +303,60 @@ public class GitBrowseCommand extends AbstractGitCommand
return result;
}
private boolean isRootRequest(BrowseCommandRequest request) {
return Strings.isNullOrEmpty(request.getPath()) || "/".equals(request.getPath());
}
private FileObject findChildren(FileObject parent, org.eclipse.jgit.lib.Repository repo, BrowseCommandRequest request, ObjectId revId, TreeWalk treeWalk) throws IOException, NotFoundException {
List<FileObject> files = Lists.newArrayList();
while (treeWalk.next())
{
FileObject fileObject = createFileObject(repo, request, revId, treeWalk);
if (!fileObject.getPath().startsWith(parent.getPath())) {
parent.setChildren(files);
return fileObject;
}
files.add(fileObject);
if (request.isRecursive() && fileObject.isDirectory()) {
treeWalk.enterSubtree();
FileObject rc = findChildren(fileObject, repo, request, revId, treeWalk);
if (rc != null) {
files.add(rc);
}
}
}
parent.setChildren(files);
return null;
}
private FileObject findFirstMatch(org.eclipse.jgit.lib.Repository repo,
BrowseCommandRequest request, ObjectId revId, TreeWalk treeWalk) throws IOException, NotFoundException {
String[] pathElements = request.getPath().split("/");
int currentDepth = 0;
int limit = pathElements.length;
while (treeWalk.next()) {
String name = treeWalk.getNameString();
if (name.equalsIgnoreCase(pathElements[currentDepth])) {
currentDepth++;
if (currentDepth >= limit) {
return createFileObject(repo, request, revId, treeWalk);
} else {
treeWalk.enterSubtree();
}
}
}
throw new NotFoundException("file", request.getPath());
}
@SuppressWarnings("unchecked")
private Map<String,
SubRepository> getSubRepositories(org.eclipse.jgit.lib.Repository repo,

View File

@@ -2,15 +2,17 @@
import React from "react";
import { repositories } from "@scm-manager/ui-components";
import type { Repository } from "@scm-manager/ui-types";
import { translate } from "react-i18next";
type Props = {
repository: Repository
repository: Repository,
t: string => string
}
class ProtocolInformation extends React.Component<Props> {
render() {
const { repository } = this.props;
const { repository, t } = this.props;
const href = repositories.getProtocolLinkByType(repository, "http");
if (!href) {
return null;
@@ -18,11 +20,11 @@ class ProtocolInformation extends React.Component<Props> {
return (
<div>
<h4>Clone the repository</h4>
<h4>{t("scm-git-plugin.information.clone")}</h4>
<pre>
<code>git clone {href}</code>
</pre>
<h4>Create a new repository</h4>
<h4>{t("scm-git-plugin.information.create")}</h4>
<pre>
<code>
git init {repository.name}
@@ -39,7 +41,7 @@ class ProtocolInformation extends React.Component<Props> {
<br />
</code>
</pre>
<h4>Push an existing repository</h4>
<h4>{t("scm-git-plugin.information.replace")}</h4>
<pre>
<code>
git remote add origin {href}
@@ -54,4 +56,4 @@ class ProtocolInformation extends React.Component<Props> {
}
export default ProtocolInformation;
export default translate("plugins")(ProtocolInformation);

View File

@@ -0,0 +1,9 @@
{
"scm-git-plugin": {
"information": {
"clone" : "Repository Klonen",
"create" : "Neue Repository erstellen",
"replace" : "Eine existierende Repository aktualisieren"
}
}
}

View File

@@ -0,0 +1,9 @@
{
"scm-git-plugin": {
"information": {
"clone" : "Clone the repository",
"create" : "Create a new repository",
"replace" : "Push an existing repository"
}
}
}

View File

@@ -6,13 +6,13 @@
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -26,107 +26,87 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.repository.spi;
//~--- non-JDK imports --------------------------------------------------------
import org.junit.Test;
import sonia.scm.NotFoundException;
import sonia.scm.repository.BrowserResult;
import sonia.scm.repository.FileObject;
import sonia.scm.repository.GitConstants;
import java.io.IOException;
import java.util.List;
import java.util.Collection;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
//~--- JDK imports ------------------------------------------------------------
/**
* Unit tests for {@link GitBrowseCommand}.
*
*
* @author Sebastian Sdorra
*/
public class GitBrowseCommandTest extends AbstractGitCommandTestBase
{
/**
* Test browse command with default branch.
*/
public class GitBrowseCommandTest extends AbstractGitCommandTestBase {
@Test
public void testDefaultBranch() throws IOException {
BrowseCommandRequest request = new BrowseCommandRequest();
request.setPath("a.txt");
BrowserResult result = createCommand().getBrowserResult(request);
FileObject fileObject = result.getFile();
assertEquals("a.txt", fileObject.getName());
}
@Test
public void testDefaultDefaultBranch() throws IOException, NotFoundException {
// without default branch, the repository head should be used
BrowserResult result = createCommand().getBrowserResult(new BrowseCommandRequest());
assertNotNull(result);
FileObject root = createCommand().getBrowserResult(new BrowseCommandRequest()).getFile();
assertNotNull(root);
List<FileObject> foList = result.getFiles();
Collection<FileObject> foList = root.getChildren();
assertNotNull(foList);
assertFalse(foList.isEmpty());
assertEquals(4, foList.size());
assertEquals("a.txt", foList.get(0).getName());
assertEquals("b.txt", foList.get(1).getName());
assertEquals("c", foList.get(2).getName());
assertEquals("f.txt", foList.get(3).getName());
// set default branch and fetch again
assertThat(foList)
.extracting("name")
.containsExactly("a.txt", "b.txt", "c", "f.txt");
}
@Test
public void testExplicitDefaultBranch() throws IOException, NotFoundException {
repository.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "test-branch");
result = createCommand().getBrowserResult(new BrowseCommandRequest());
assertNotNull(result);
foList = result.getFiles();
assertNotNull(foList);
assertFalse(foList.isEmpty());
assertEquals(2, foList.size());
assertEquals("a.txt", foList.get(0).getName());
assertEquals("c", foList.get(1).getName());
FileObject root = createCommand().getBrowserResult(new BrowseCommandRequest()).getFile();
assertNotNull(root);
Collection<FileObject> foList = root.getChildren();
assertThat(foList)
.extracting("name")
.containsExactly("a.txt", "c");
}
@Test
public void testBrowse() throws IOException {
BrowserResult result =
createCommand().getBrowserResult(new BrowseCommandRequest());
FileObject root = createCommand().getBrowserResult(new BrowseCommandRequest()).getFile();
assertNotNull(root);
assertNotNull(result);
Collection<FileObject> foList = root.getChildren();
List<FileObject> foList = result.getFiles();
FileObject a = findFile(foList, "a.txt");
FileObject c = findFile(foList, "c");
assertNotNull(foList);
assertFalse(foList.isEmpty());
assertEquals(4, foList.size());
FileObject a = null;
FileObject c = null;
for (FileObject f : foList)
{
if ("a.txt".equals(f.getName()))
{
a = f;
}
else if ("c".equals(f.getName()))
{
c = f;
}
}
assertNotNull(a);
assertFalse(a.isDirectory());
assertEquals("a.txt", a.getName());
assertEquals("a.txt", a.getPath());
assertEquals("added new line for blame", a.getDescription());
assertTrue(a.getLength() > 0);
checkDate(a.getLastModified());
assertNotNull(c);
assertTrue(c.isDirectory());
assertEquals("c", c.getName());
assertEquals("c", c.getPath());
@@ -138,39 +118,22 @@ public class GitBrowseCommandTest extends AbstractGitCommandTestBase
request.setPath("c");
BrowserResult result = createCommand().getBrowserResult(request);
FileObject root = createCommand().getBrowserResult(request).getFile();
assertNotNull(result);
Collection<FileObject> foList = root.getChildren();
List<FileObject> foList = result.getFiles();
assertThat(foList).hasSize(2);
assertNotNull(foList);
assertFalse(foList.isEmpty());
assertEquals(2, foList.size());
FileObject d = findFile(foList, "d.txt");
FileObject e = findFile(foList, "e.txt");
FileObject d = null;
FileObject e = null;
for (FileObject f : foList)
{
if ("d.txt".equals(f.getName()))
{
d = f;
}
else if ("e.txt".equals(f.getName()))
{
e = f;
}
}
assertNotNull(d);
assertFalse(d.isDirectory());
assertEquals("d.txt", d.getName());
assertEquals("c/d.txt", d.getPath());
assertEquals("added file d and e in folder c", d.getDescription());
assertTrue(d.getLength() > 0);
checkDate(d.getLastModified());
assertNotNull(e);
assertFalse(e.isDirectory());
assertEquals("e.txt", e.getName());
assertEquals("c/e.txt", e.getPath());
@@ -185,25 +148,30 @@ public class GitBrowseCommandTest extends AbstractGitCommandTestBase
request.setRecursive(true);
BrowserResult result = createCommand().getBrowserResult(request);
FileObject root = createCommand().getBrowserResult(request).getFile();
assertNotNull(result);
Collection<FileObject> foList = root.getChildren();
List<FileObject> foList = result.getFiles();
assertThat(foList)
.extracting("name")
.containsExactly("a.txt", "b.txt", "c", "f.txt");
assertNotNull(foList);
assertFalse(foList.isEmpty());
assertEquals(5, foList.size());
FileObject c = findFile(foList, "c");
Collection<FileObject> cChildren = c.getChildren();
assertThat(cChildren)
.extracting("name")
.containsExactly("d.txt", "e.txt");
}
/**
* Method description
*
*
* @return
*/
private GitBrowseCommand createCommand()
{
private FileObject findFile(Collection<FileObject> foList, String name) {
return foList.stream()
.filter(f -> name.equals(f.getName()))
.findFirst()
.orElseThrow(() -> new AssertionError("file " + name + " not found"));
}
private GitBrowseCommand createCommand() {
return new GitBrowseCommand(createContext(), repository);
}
}