mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-14 09:25:43 +01:00
Add parameter to check current revision to prevent conflicts
This commit is contained in:
@@ -57,15 +57,6 @@ public class ModifyCommandBuilder {
|
|||||||
this.workdir = workdirProvider.createNewWorkdir();
|
this.workdir = workdirProvider.createNewWorkdir();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the branch that should be modified. The new commit will be made for this branch.
|
|
||||||
* @param branchToModify The branch to modify.
|
|
||||||
* @return This builder instance.
|
|
||||||
*/
|
|
||||||
public ModifyCommandBuilder setBranchToModify(String branchToModify) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new file. The content of the file will be specified in a subsequent call to
|
* Create a new file. The content of the file will be specified in a subsequent call to
|
||||||
* {@link ContentLoader#withData(ByteSource)} or {@link ContentLoader#withData(InputStream)}.
|
* {@link ContentLoader#withData(ByteSource)} or {@link ContentLoader#withData(InputStream)}.
|
||||||
@@ -158,6 +149,17 @@ public class ModifyCommandBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected revision of the branch, before the changes are applied. If the branch does not have the
|
||||||
|
* expected revision, a concurrent modification exception will be thrown when the command is executed and no
|
||||||
|
* changes will be applied.
|
||||||
|
* @return This builder instance.
|
||||||
|
*/
|
||||||
|
public ModifyCommandBuilder setExpectedRevision(String expectedRevision) {
|
||||||
|
request.setExpectedRevision(expectedRevision);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public interface ContentLoader {
|
public interface ContentLoader {
|
||||||
/**
|
/**
|
||||||
* Specify the data of the file using a {@link ByteSource}.
|
* Specify the data of the file using a {@link ByteSource}.
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ public class ModifyCommandRequest implements Resetable, Validateable {
|
|||||||
private Person author;
|
private Person author;
|
||||||
private String commitMessage;
|
private String commitMessage;
|
||||||
private String branch;
|
private String branch;
|
||||||
|
private String expectedRevision;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reset() {
|
public void reset() {
|
||||||
@@ -63,11 +64,19 @@ public class ModifyCommandRequest implements Resetable, Validateable {
|
|||||||
return branch;
|
return branch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getExpectedRevision() {
|
||||||
|
return expectedRevision;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isValid() {
|
public boolean isValid() {
|
||||||
return StringUtils.isNotEmpty(commitMessage) && !requests.isEmpty();
|
return StringUtils.isNotEmpty(commitMessage) && !requests.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setExpectedRevision(String expectedRevision) {
|
||||||
|
this.expectedRevision = expectedRevision;
|
||||||
|
}
|
||||||
|
|
||||||
public interface PartialRequest {
|
public interface PartialRequest {
|
||||||
void execute(ModifyCommand.Worker worker) throws IOException;
|
void execute(ModifyCommand.Worker worker) throws IOException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -240,6 +240,10 @@ class AbstractGitCommand
|
|||||||
logger.debug("pushed changes");
|
logger.debug("pushed changes");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ref getCurrentRevision() throws IOException {
|
||||||
|
return getClone().getRepository().getRefDatabase().findRef("HEAD");
|
||||||
|
}
|
||||||
|
|
||||||
private Person determineAuthor(Person author) {
|
private Person determineAuthor(Person author) {
|
||||||
if (author == null) {
|
if (author == null) {
|
||||||
Subject subject = SecurityUtils.getSubject();
|
Subject subject = SecurityUtils.getSubject();
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import org.eclipse.jgit.api.Git;
|
|||||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||||
import org.eclipse.jgit.revwalk.RevCommit;
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
import sonia.scm.BadRequestException;
|
import sonia.scm.BadRequestException;
|
||||||
|
import sonia.scm.ConcurrentModificationException;
|
||||||
import sonia.scm.ContextEntry;
|
import sonia.scm.ContextEntry;
|
||||||
import sonia.scm.repository.GitWorkdirFactory;
|
import sonia.scm.repository.GitWorkdirFactory;
|
||||||
import sonia.scm.repository.InternalRepositoryException;
|
import sonia.scm.repository.InternalRepositoryException;
|
||||||
@@ -51,6 +52,11 @@ public class GitModifyCommand extends AbstractGitCommand implements ModifyComman
|
|||||||
if (!StringUtils.isEmpty(request.getBranch())) {
|
if (!StringUtils.isEmpty(request.getBranch())) {
|
||||||
checkOutBranch(request.getBranch());
|
checkOutBranch(request.getBranch());
|
||||||
}
|
}
|
||||||
|
if (!StringUtils.isEmpty(request.getExpectedRevision())) {
|
||||||
|
if (!request.getExpectedRevision().equals(getCurrentRevision().getName())) {
|
||||||
|
throw new ConcurrentModificationException("branch", request.getBranch() == null? "default": request.getBranch());
|
||||||
|
}
|
||||||
|
}
|
||||||
for (ModifyCommandRequest.PartialRequest r : request.getRequests()) {
|
for (ModifyCommandRequest.PartialRequest r : request.getRequests()) {
|
||||||
r.execute(this);
|
r.execute(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import org.junit.Test;
|
|||||||
import org.junit.rules.TemporaryFolder;
|
import org.junit.rules.TemporaryFolder;
|
||||||
import sonia.scm.AlreadyExistsException;
|
import sonia.scm.AlreadyExistsException;
|
||||||
import sonia.scm.BadRequestException;
|
import sonia.scm.BadRequestException;
|
||||||
|
import sonia.scm.ConcurrentModificationException;
|
||||||
import sonia.scm.repository.Person;
|
import sonia.scm.repository.Person;
|
||||||
import sonia.scm.repository.util.WorkdirProvider;
|
import sonia.scm.repository.util.WorkdirProvider;
|
||||||
|
|
||||||
@@ -56,7 +57,7 @@ public class GitModifyCommandTest extends AbstractGitCommandTestBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldCreateCommitOnSelectedBranch() throws IOException, GitAPIException {
|
public void shouldCreateCommitOnSelectedBranch() throws IOException {
|
||||||
File newFile = Files.write(temporaryFolder.newFile().toPath(), "new content".getBytes()).toFile();
|
File newFile = Files.write(temporaryFolder.newFile().toPath(), "new content".getBytes()).toFile();
|
||||||
|
|
||||||
GitModifyCommand command = createCommand();
|
GitModifyCommand command = createCommand();
|
||||||
@@ -95,7 +96,7 @@ public class GitModifyCommandTest extends AbstractGitCommandTestBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = AlreadyExistsException.class)
|
@Test(expected = AlreadyExistsException.class)
|
||||||
public void shouldFailIfOverwritingExistingFileWithoutOverwriteFlag() throws IOException, GitAPIException {
|
public void shouldFailIfOverwritingExistingFileWithoutOverwriteFlag() throws IOException {
|
||||||
File newFile = Files.write(temporaryFolder.newFile().toPath(), "new content".getBytes()).toFile();
|
File newFile = Files.write(temporaryFolder.newFile().toPath(), "new content".getBytes()).toFile();
|
||||||
|
|
||||||
GitModifyCommand command = createCommand();
|
GitModifyCommand command = createCommand();
|
||||||
@@ -140,6 +141,21 @@ public class GitModifyCommandTest extends AbstractGitCommandTestBase {
|
|||||||
command.execute(request);
|
command.execute(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = ConcurrentModificationException.class)
|
||||||
|
public void shouldFailBranchDoesNotHaveExpectedRevision() throws IOException {
|
||||||
|
File newFile = Files.write(temporaryFolder.newFile().toPath(), "irrelevant\n".getBytes()).toFile();
|
||||||
|
|
||||||
|
GitModifyCommand command = createCommand();
|
||||||
|
|
||||||
|
ModifyCommandRequest request = new ModifyCommandRequest();
|
||||||
|
request.setCommitMessage("test commit");
|
||||||
|
request.addRequest(new ModifyCommandRequest.CreateFileRequest("irrelevant", newFile, true));
|
||||||
|
request.setAuthor(new Person("Dirk Gently", "dirk@holistic.det"));
|
||||||
|
request.setExpectedRevision("abc");
|
||||||
|
|
||||||
|
command.execute(request);
|
||||||
|
}
|
||||||
|
|
||||||
private void assertInTree(TreeAssertions assertions) throws IOException, GitAPIException {
|
private void assertInTree(TreeAssertions assertions) throws IOException, GitAPIException {
|
||||||
try (Git git = new Git(createContext().open())) {
|
try (Git git = new Git(createContext().open())) {
|
||||||
RevCommit lastCommit = getLastCommit(git);
|
RevCommit lastCommit = getLastCommit(git);
|
||||||
|
|||||||
Reference in New Issue
Block a user