Merged in feature/editor_plugin_delete (pull request #307)

Feature/editor plugin delete
This commit is contained in:
Rene Pfeuffer
2019-09-05 09:37:10 +00:00
7 changed files with 94 additions and 18 deletions

View File

@@ -8,7 +8,7 @@ public interface ModifyCommand {
String execute(ModifyCommandRequest request);
interface Worker {
void delete(String toBeDeleted);
void delete(String toBeDeleted) throws IOException;
void create(String toBeCreated, File file, boolean overwrite) throws IOException;

View File

@@ -89,7 +89,7 @@ public class ModifyCommandRequest implements Resetable, Validateable {
}
@Override
public void execute(ModifyCommand.Worker worker) {
public void execute(ModifyCommand.Worker worker) throws IOException {
worker.delete(path);
}
}

View File

@@ -9,7 +9,7 @@ import org.eclipse.jgit.revwalk.RevCommit;
import sonia.scm.BadRequestException;
import sonia.scm.ConcurrentModificationException;
import sonia.scm.ContextEntry;
import sonia.scm.ScmConstraintViolationException;
import sonia.scm.NotFoundException;
import sonia.scm.repository.GitWorkdirFactory;
import sonia.scm.repository.InternalRepositoryException;
import sonia.scm.repository.Repository;
@@ -18,6 +18,7 @@ import java.io.File;
import java.io.IOException;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.util.Optional;
@@ -83,11 +84,7 @@ public class GitModifyCommand extends AbstractGitCommand implements ModifyComman
try {
Files.copy(file.toPath(), targetFile);
} catch (FileAlreadyExistsException e) {
ContextEntry.ContextBuilder contextBuilder = entity("file", toBeCreated);
if (!StringUtils.isEmpty(request.getBranch())) {
contextBuilder.in("branch", request.getBranch());
}
throw alreadyExists(contextBuilder.in(context.getRepository()));
throw alreadyExists(createFileContext(toBeCreated));
}
}
try {
@@ -98,8 +95,27 @@ public class GitModifyCommand extends AbstractGitCommand implements ModifyComman
}
@Override
public void delete(String toBeDeleted) {
public void delete(String toBeDeleted) throws IOException {
Path fileToBeDeleted = new File(workDir, toBeDeleted).toPath();
try {
Files.delete(fileToBeDeleted);
} catch (NoSuchFileException e) {
throw NotFoundException.notFound(createFileContext(toBeDeleted));
}
try {
getClone().rm().addFilepattern(toBeDeleted).call();
} catch (GitAPIException e) {
throwInternalRepositoryException("could not remove file from index", e);
}
}
private ContextEntry.ContextBuilder createFileContext(String toBeDeleted) {
ContextEntry.ContextBuilder contextBuilder = entity("file", toBeDeleted);
if (!StringUtils.isEmpty(request.getBranch())) {
contextBuilder.in("branch", request.getBranch());
}
contextBuilder.in(context.getRepository());
return contextBuilder;
}
@Override

View File

@@ -16,6 +16,7 @@ import org.junit.rules.TemporaryFolder;
import sonia.scm.AlreadyExistsException;
import sonia.scm.BadRequestException;
import sonia.scm.ConcurrentModificationException;
import sonia.scm.NotFoundException;
import sonia.scm.ScmConstraintViolationException;
import sonia.scm.repository.Person;
import sonia.scm.repository.util.WorkdirProvider;
@@ -157,6 +158,47 @@ public class GitModifyCommandTest extends AbstractGitCommandTestBase {
command.execute(request);
}
@Test
public void shouldDeleteExistingFile() throws IOException, GitAPIException {
GitModifyCommand command = createCommand();
ModifyCommandRequest request = new ModifyCommandRequest();
request.setCommitMessage("test commit");
request.addRequest(new ModifyCommandRequest.DeleteFileRequest("a.txt"));
request.setAuthor(new Person("Dirk Gently", "dirk@holistic.det"));
command.execute(request);
TreeAssertions assertions = canonicalTreeParser -> assertThat(canonicalTreeParser.findFile("a.txt")).isFalse();
assertInTree(assertions);
}
@Test(expected = NotFoundException.class)
public void shouldThrowNotFoundExceptionWhenFileToDeleteDoesNotExist() {
GitModifyCommand command = createCommand();
ModifyCommandRequest request = new ModifyCommandRequest();
request.setCommitMessage("test commit");
request.addRequest(new ModifyCommandRequest.DeleteFileRequest("no/such/file"));
request.setAuthor(new Person("Dirk Gently", "dirk@holistic.det"));
command.execute(request);
}
@Test(expected = NotFoundException.class)
public void shouldThrowNotFoundExceptionWhenBranchDoesNotExist() {
GitModifyCommand command = createCommand();
ModifyCommandRequest request = new ModifyCommandRequest();
request.setBranch("does-not-exist");
request.setCommitMessage("test commit");
request.addRequest(new ModifyCommandRequest.DeleteFileRequest("a.txt"));
request.setAuthor(new Person("Dirk Gently", "dirk@holistic.det"));
command.execute(request);
}
@Test(expected = ScmConstraintViolationException.class)
public void shouldFailWithConstraintViolationIfBranchIsNoBranch() throws IOException {
File newFile = Files.write(temporaryFolder.newFile().toPath(), "irrelevant\n".getBytes()).toFile();

View File

@@ -1,13 +1,14 @@
//@flow
import React from "react";
import { Link } from "react-router-dom";
import type { Branch } from "@scm-manager/ui-types";
import type { Branch, Repository } from "@scm-manager/ui-types";
import injectSheet from "react-jss";
import { ExtensionPoint, binder } from "@scm-manager/ui-extensions";
import {ButtonGroup} from "./buttons";
import classNames from "classnames";
type Props = {
repository: Repository,
branch: Branch,
defaultBranch: Branch,
branches: Branch[],
@@ -63,7 +64,7 @@ class Breadcrumb extends React.Component<Props> {
}
render() {
const { classes, baseUrl, branch, defaultBranch, branches, revision, path } = this.props;
const { classes, baseUrl, branch, defaultBranch, branches, revision, path, repository } = this.props;
return (
<>
@@ -82,7 +83,9 @@ class Breadcrumb extends React.Component<Props> {
branch: branch ? branch : defaultBranch,
path,
isBranchUrl: branches &&
branches.filter(b => b.name.replace("/", "%2F") === revision).length > 0 }}
branches.filter(b => b.name.replace("/", "%2F") === revision).length > 0,
repository
}}
renderAll={true}
/>
</ButtonGroup>

View File

@@ -2,7 +2,12 @@
import React from "react";
import { translate } from "react-i18next";
import type { File, Repository } from "@scm-manager/ui-types";
import { DateFromNow, ButtonGroup, FileSize } from "@scm-manager/ui-components";
import {
DateFromNow,
ButtonGroup,
FileSize,
ErrorNotification
} from "@scm-manager/ui-components";
import injectSheet from "react-jss";
import classNames from "classnames";
import FileButtonGroup from "../components/content/FileButtonGroup";
@@ -14,7 +19,6 @@ import { ExtensionPoint } from "@scm-manager/ui-extensions";
type Props = {
loading: boolean,
error: Error,
file: File,
repository: Repository,
revision: string,
@@ -25,7 +29,8 @@ type Props = {
type State = {
collapsed: boolean,
showHistory: boolean
showHistory: boolean,
errorFromExtension?: Error
};
const styles = {
@@ -67,8 +72,12 @@ class Content extends React.Component<Props, State> {
});
}
handleExtensionError = (error: Error) => {
this.setState({ errorFromExtension: error });
};
showHeader() {
const { file, classes } = this.props;
const { file, revision, classes } = this.props;
const { showHistory, collapsed } = this.state;
const icon = collapsed ? "fa-angle-right" : "fa-angle-down";
@@ -100,7 +109,11 @@ class Content extends React.Component<Props, State> {
<ButtonGroup>
<ExtensionPoint
name="repos.sources.content.actionbar"
props={{ file }}
props={{
file,
revision,
handleExtensionError: this.handleExtensionError
}}
renderAll={true}
/>
</ButtonGroup>
@@ -167,7 +180,7 @@ class Content extends React.Component<Props, State> {
render() {
const { file, revision, repository, path } = this.props;
const { showHistory } = this.state;
const { showHistory, errorFromExtension } = this.state;
const header = this.showHeader();
const content =
@@ -190,6 +203,7 @@ class Content extends React.Component<Props, State> {
{moreInformation}
{content}
</div>
{errorFromExtension && <ErrorNotification error={errorFromExtension} />}
</div>
);
}

View File

@@ -150,6 +150,7 @@ class Sources extends React.Component<Props, State> {
branches && branches.filter(b => b.defaultBranch === true)[0]
}
branches={branches && branches}
repository={repository}
/>
<FileTree
repository={repository}