From c37ed2030300f3ddf6782cdcc02381b017aa3a76 Mon Sep 17 00:00:00 2001 From: Rene Pfeuffer Date: Wed, 4 Sep 2019 10:31:01 +0200 Subject: [PATCH 1/5] Implement delete for git --- .../scm/repository/spi/ModifyCommand.java | 2 +- .../repository/spi/ModifyCommandRequest.java | 2 +- .../scm/repository/spi/GitModifyCommand.java | 29 ++++++++++--- .../repository/spi/GitModifyCommandTest.java | 42 +++++++++++++++++++ 4 files changed, 67 insertions(+), 8 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/ModifyCommand.java b/scm-core/src/main/java/sonia/scm/repository/spi/ModifyCommand.java index 578944c47f..012c7ef2c6 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/ModifyCommand.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/ModifyCommand.java @@ -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; diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/ModifyCommandRequest.java b/scm-core/src/main/java/sonia/scm/repository/spi/ModifyCommandRequest.java index 76f420803a..9069154951 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/ModifyCommandRequest.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/ModifyCommandRequest.java @@ -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); } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java index 4ff60445f7..66dceaa0f7 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java @@ -7,6 +7,7 @@ import org.eclipse.jgit.revwalk.RevCommit; import sonia.scm.BadRequestException; import sonia.scm.ConcurrentModificationException; import sonia.scm.ContextEntry; +import sonia.scm.NotFoundException; import sonia.scm.repository.GitWorkdirFactory; import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.Repository; @@ -15,6 +16,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; @@ -76,11 +78,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 { @@ -91,8 +89,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 diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommandTest.java index 96cc256cf4..49ab28ca49 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommandTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommandTest.java @@ -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.repository.Person; import sonia.scm.repository.util.WorkdirProvider; @@ -156,6 +157,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); + } + private void assertInTree(TreeAssertions assertions) throws IOException, GitAPIException { try (Git git = new Git(createContext().open())) { RevCommit lastCommit = getLastCommit(git); From 90d1236df2f0c14dddfd9f080873ae61889d12cc Mon Sep 17 00:00:00 2001 From: Rene Pfeuffer Date: Thu, 5 Sep 2019 10:19:29 +0200 Subject: [PATCH 2/5] Extend extension point for editor plugin --- scm-ui/src/repos/sources/containers/Content.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scm-ui/src/repos/sources/containers/Content.js b/scm-ui/src/repos/sources/containers/Content.js index 64a0fb472f..ee8e3673bf 100644 --- a/scm-ui/src/repos/sources/containers/Content.js +++ b/scm-ui/src/repos/sources/containers/Content.js @@ -69,7 +69,7 @@ class Content extends React.Component { } 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"; @@ -101,7 +101,7 @@ class Content extends React.Component { From b608ed4de2dc89edde80e56d4683f310d3a0e2f5 Mon Sep 17 00:00:00 2001 From: Eduard Heimbuch Date: Thu, 5 Sep 2019 10:46:27 +0200 Subject: [PATCH 3/5] add repository to source actionbar extensionPoint --- .../packages/ui-components/src/Breadcrumb.js | 14 +++++++++++--- scm-ui/src/repos/sources/containers/Sources.js | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/scm-ui-components/packages/ui-components/src/Breadcrumb.js b/scm-ui-components/packages/ui-components/src/Breadcrumb.js index d81a4cbf63..d2f3409af6 100644 --- a/scm-ui-components/packages/ui-components/src/Breadcrumb.js +++ b/scm-ui-components/packages/ui-components/src/Breadcrumb.js @@ -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 { } render() { - const { classes, baseUrl, branch, defaultBranch, branches, revision, path } = this.props; + const { classes, baseUrl, branch, defaultBranch, branches, revision, path, repository } = this.props; return ( <> @@ -77,7 +78,14 @@ class Breadcrumb extends React.Component { b.name === revision).length > 0 }} + props={{ + baseUrl, + branch: branch ? branch : defaultBranch, + path, + isBranchUrl: branches && + branches.filter(b => b.name.replace("/", "%2F") === revision).length > 0, + repository + }} renderAll={true} /> diff --git a/scm-ui/src/repos/sources/containers/Sources.js b/scm-ui/src/repos/sources/containers/Sources.js index 9a485459a6..95cfe9e332 100644 --- a/scm-ui/src/repos/sources/containers/Sources.js +++ b/scm-ui/src/repos/sources/containers/Sources.js @@ -157,6 +157,7 @@ class Sources extends React.Component { branches && branches.filter(b => b.defaultBranch === true)[0] } branches={branches && branches} + repository={repository} /> Date: Thu, 5 Sep 2019 11:32:12 +0200 Subject: [PATCH 4/5] Add error notification for errors from extensions --- .../src/repos/sources/containers/Content.js | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/scm-ui/src/repos/sources/containers/Content.js b/scm-ui/src/repos/sources/containers/Content.js index 927e1869c0..b9032ae681 100644 --- a/scm-ui/src/repos/sources/containers/Content.js +++ b/scm-ui/src/repos/sources/containers/Content.js @@ -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,6 +72,10 @@ class Content extends React.Component { }); } + handleExtensionError = (error: Error) => { + this.setState({ errorFromExtension: error }); + }; + showHeader() { const { file, revision, classes } = this.props; const { showHistory, collapsed } = this.state; @@ -100,7 +109,11 @@ class Content extends React.Component { @@ -167,7 +180,7 @@ class Content extends React.Component { 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 { {moreInformation} {content} + {errorFromExtension && } ); } From c6198669ec2d5e62b3e35183b96d0cae6ffcef8c Mon Sep 17 00:00:00 2001 From: Rene Pfeuffer Date: Thu, 5 Sep 2019 09:37:10 +0000 Subject: [PATCH 5/5] Close branch feature/editor_plugin_delete