Handle non-fast-forward pushes
Change-Id: I040d6b8b0e7e65c09494642a952f53c3db135950
diff --git a/src/main/java/com/googlesource/gerrit/plugins/refprotection/RefUpdateListener.java b/src/main/java/com/googlesource/gerrit/plugins/refprotection/RefUpdateListener.java
index ebfca25..7a67960 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/refprotection/RefUpdateListener.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/refprotection/RefUpdateListener.java
@@ -9,13 +9,18 @@
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.project.CreateBranch;
import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.server.project.ProjectControl;
import com.google.gerrit.server.project.ProjectResource;
import com.google.inject.Inject;
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -30,20 +35,30 @@
private final CreateBranch.Factory createBranchFactory;
private final ProjectControl.GenericFactory projectControl;
private final CurrentUser user;
+ private final GitRepositoryManager repoManager;
@Inject
RefUpdateListener(CreateBranch.Factory createBranchFactory,
- ProjectControl.GenericFactory p, CurrentUser user) {
+ ProjectControl.GenericFactory p, CurrentUser user,
+ GitRepositoryManager repoManager) {
this.createBranchFactory = createBranchFactory;
this.projectControl = p;
this.user = user;
+ this.repoManager = repoManager;
}
@Override
public void onGitReferenceUpdated(final Event event) {
- if (!isNewRef(event) && isRelevantRef(event)) {
- if (isRefDeleted(event) || isNonFastForwardUpdate(event)) {
- createBackupBranch(event);
+ if (isRelevantRef(event)) {
+ Project.NameKey nameKey = new Project.NameKey(event.getProjectName());
+ try {
+ ProjectResource project =
+ new ProjectResource(projectControl.controlFor(nameKey, user));
+ if (isRefDeleted(event) || isNonFastForwardUpdate(event, project)) {
+ createBackupBranch(event, project);
+ }
+ } catch (NoSuchProjectException | IOException e) {
+ log.error(e.getMessage(), e);
}
}
}
@@ -53,7 +68,7 @@
*
* @param event the Event
*/
- private void createBackupBranch(Event event) {
+ private void createBackupBranch(Event event, ProjectResource project) {
String branchName = event.getRefName().replaceFirst(R_HEADS, "");
try {
String branchPrefix = "";
@@ -70,13 +85,10 @@
CreateBranch.Input input = new CreateBranch.Input();
input.ref = ref;
input.revision = event.getOldObjectId();
- Project.NameKey nameKey = new Project.NameKey(event.getProjectName());
- ProjectResource project =
- new ProjectResource(projectControl.controlFor(nameKey, user));
createBranchFactory.create(ref).apply(project, input);
} catch (BadRequestException | AuthException | ResourceConflictException
- | IOException | NoSuchProjectException e) {
+ | IOException e) {
log.error(e.getMessage(), e);
}
}
@@ -88,8 +100,9 @@
* @return True if relevant, otherwise False.
*/
private boolean isRelevantRef(Event event) {
- return event.getRefName().startsWith(R_HEADS)
- || event.getRefName().startsWith(R_TAGS);
+ return (!isNewRef(event)) &&
+ (event.getRefName().startsWith(R_HEADS)
+ || event.getRefName().startsWith(R_TAGS));
}
/**
@@ -124,8 +137,25 @@
* @param event the Event
* @return True if a non-fast-forward update, otherwise False.
*/
- private boolean isNonFastForwardUpdate(Event event) {
- // TODO
- return false;
+ private boolean isNonFastForwardUpdate(Event event, ProjectResource project)
+ throws RepositoryNotFoundException, IOException {
+ Repository repo = null;
+ RevWalk walk = null;
+ try {
+ repo = repoManager.openRepository(project.getNameKey());
+ walk = new RevWalk(repo);
+ RevCommit oldCommit =
+ walk.parseCommit(repo.resolve(event.getOldObjectId()));
+ RevCommit newCommit =
+ walk.parseCommit(repo.resolve(event.getNewObjectId()));
+ return !walk.isMergedInto(oldCommit, newCommit);
+ } finally {
+ if (walk != null) {
+ walk.release();
+ }
+ if (repo != null) {
+ repo.close();
+ }
+ }
}
}