diff options
author | Paul Martin <paul@paulsputer.com> | 2016-04-27 23:58:06 +0100 |
---|---|---|
committer | Paul Martin <paul@paulsputer.com> | 2016-04-27 23:58:06 +0100 |
commit | c2188a840bc4153ae92112b04b2e06a90d3944aa (patch) | |
tree | c11b48170773fcf1edfc53def832fe5a9b76f1c0 /src/test | |
parent | 56619e42f0a1e555c004374e7f2b13f744ab23f5 (diff) | |
download | gitblit-c2188a840bc4153ae92112b04b2e06a90d3944aa.tar.gz gitblit-c2188a840bc4153ae92112b04b2e06a90d3944aa.zip |
Ticket Reference handling #1048
+ Supports referencing:
+ Tickets from other tickets via comments
+ Tickets from commits on any branch
+ Common TicketLink class used for both commits and tickets
+ TicketLink is temporary and persisted to ticket as a Reference
+ Support deletion of ticket references
+ Rebasing patchsets/branches will generate new references
+ Deleting old patchsets/branches will remove the relevant references
+ Substantial testing of use cases
+ With and without patchsets, deleting, amending
+ BranchTicketService used during testing to allow end-to-end ref testing
+ Relocated common git helper functions to JGitUtils
Diffstat (limited to 'src/test')
-rw-r--r-- | src/test/config/test-gitblit.properties | 2 | ||||
-rw-r--r-- | src/test/java/com/gitblit/tests/GitBlitSuite.java | 2 | ||||
-rw-r--r-- | src/test/java/com/gitblit/tests/TicketReferenceTest.java | 939 |
3 files changed, 942 insertions, 1 deletions
diff --git a/src/test/config/test-gitblit.properties b/src/test/config/test-gitblit.properties index 78e9ab95..ef6a6c51 100644 --- a/src/test/config/test-gitblit.properties +++ b/src/test/config/test-gitblit.properties @@ -90,3 +90,5 @@ server.httpBindInterface = localhost server.httpsBindInterface = localhost server.storePassword = gitblit server.shutdownPort = 8081 + +tickets.service = com.gitblit.tickets.BranchTicketService diff --git a/src/test/java/com/gitblit/tests/GitBlitSuite.java b/src/test/java/com/gitblit/tests/GitBlitSuite.java index b01c82c4..133be77f 100644 --- a/src/test/java/com/gitblit/tests/GitBlitSuite.java +++ b/src/test/java/com/gitblit/tests/GitBlitSuite.java @@ -66,7 +66,7 @@ import com.gitblit.utils.JGitUtils; ModelUtilsTest.class, JnaUtilsTest.class, LdapSyncServiceTest.class, FileTicketServiceTest.class,
BranchTicketServiceTest.class, RedisTicketServiceTest.class, AuthenticationManagerTest.class,
SshKeysDispatcherTest.class, UITicketTest.class, PathUtilsTest.class, SshKerberosAuthenticationTest.class,
- GravatarTest.class, FilestoreManagerTest.class, FilestoreServletTest.class })
+ GravatarTest.class, FilestoreManagerTest.class, FilestoreServletTest.class, TicketReferenceTest.class })
public class GitBlitSuite {
public static final File BASEFOLDER = new File("data");
diff --git a/src/test/java/com/gitblit/tests/TicketReferenceTest.java b/src/test/java/com/gitblit/tests/TicketReferenceTest.java new file mode 100644 index 00000000..934659cc --- /dev/null +++ b/src/test/java/com/gitblit/tests/TicketReferenceTest.java @@ -0,0 +1,939 @@ +/* + * Copyright 2016 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.tests; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.text.MessageFormat; +import java.util.Date; +import java.util.List; + +import org.eclipse.jgit.api.CloneCommand; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.MergeResult; +import org.eclipse.jgit.api.MergeCommand.FastForwardMode; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.transport.CredentialsProvider; +import org.eclipse.jgit.transport.PushResult; +import org.eclipse.jgit.transport.RefSpec; +import org.eclipse.jgit.transport.RemoteRefUpdate; +import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; +import org.eclipse.jgit.transport.RemoteRefUpdate.Status; +import org.eclipse.jgit.util.FileUtils; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.gitblit.Constants.AccessPermission; +import com.gitblit.Constants.AccessRestrictionType; +import com.gitblit.Constants.AuthorizationControl; +import com.gitblit.GitBlitException; +import com.gitblit.models.RepositoryModel; +import com.gitblit.models.TicketModel; +import com.gitblit.models.UserModel; +import com.gitblit.models.TicketModel.Change; +import com.gitblit.models.TicketModel.Field; +import com.gitblit.models.TicketModel.Reference; +import com.gitblit.tickets.ITicketService; + +/** + * Creates and deletes a range of ticket references via ticket comments and commits + */ +public class TicketReferenceTest extends GitblitUnitTest { + + static File workingCopy = new File(GitBlitSuite.REPOSITORIES, "working/TicketReferenceTest.git-wc"); + + static ITicketService ticketService; + + static final String account = "TicketRefTest"; + static final String password = GitBlitSuite.password; + + static final String url = GitBlitSuite.gitServletUrl; + + static UserModel user = null; + static RepositoryModel repo = null; + static CredentialsProvider cp = null; + static Git git = null; + + @BeforeClass + public static void configure() throws Exception { + File repositoryName = new File("TicketReferenceTest.git");; + + GitBlitSuite.close(repositoryName); + if (repositoryName.exists()) { + FileUtils.delete(repositoryName, FileUtils.RECURSIVE | FileUtils.RETRY); + } + repo = new RepositoryModel("TicketReferenceTest.git", null, null, null); + + if (gitblit().hasRepository(repo.name)) { + gitblit().deleteRepositoryModel(repo); + } + + gitblit().updateRepositoryModel(repo.name, repo, true); + + user = new UserModel(account); + user.displayName = account; + user.emailAddress = account + "@example.com"; + user.password = password; + + cp = new UsernamePasswordCredentialsProvider(user.username, user.password); + + if (gitblit().getUserModel(user.username) != null) { + gitblit().deleteUser(user.username); + } + + repo.authorizationControl = AuthorizationControl.NAMED; + repo.accessRestriction = AccessRestrictionType.PUSH; + gitblit().updateRepositoryModel(repo.name, repo, false); + + // grant user push permission + user.setRepositoryPermission(repo.name, AccessPermission.REWIND); + gitblit().updateUserModel(user); + + ticketService = gitblit().getTicketService(); + assertTrue(ticketService.deleteAll(repo)); + + GitBlitSuite.close(workingCopy); + if (workingCopy.exists()) { + FileUtils.delete(workingCopy, FileUtils.RECURSIVE | FileUtils.RETRY); + } + + CloneCommand clone = Git.cloneRepository(); + clone.setURI(MessageFormat.format("{0}/{1}", url, repo.name)); + clone.setDirectory(workingCopy); + clone.setBare(false); + clone.setBranch("master"); + clone.setCredentialsProvider(cp); + GitBlitSuite.close(clone.call()); + + git = Git.open(workingCopy); + git.getRepository().getConfig().setString("user", null, "name", user.displayName); + git.getRepository().getConfig().setString("user", null, "email", user.emailAddress); + git.getRepository().getConfig().save(); + + final RevCommit revCommit1 = makeCommit("initial commit"); + final String initialSha = revCommit1.name(); + Iterable<PushResult> results = git.push().setPushAll().setCredentialsProvider(cp).call(); + GitBlitSuite.close(git); + for (PushResult result : results) { + for (RemoteRefUpdate update : result.getRemoteUpdates()) { + assertEquals(Status.OK, update.getStatus()); + assertEquals(initialSha, update.getNewObjectId().name()); + } + } + } + + @AfterClass + public static void cleanup() throws Exception { + GitBlitSuite.close(git); + } + + @Test + public void noReferencesOnTicketCreation() throws Exception { + + TicketModel a = ticketService.createTicket(repo, newTicket("noReferencesOnCreation")); + assertNotNull(a); + assertFalse(a.hasReferences()); + + //Ensure retrieval process doesn't affect anything + a = ticketService.getTicket(repo, a.number); + assertNotNull(a); + assertFalse(a.hasReferences()); + } + + + @Test + public void commentNoUnexpectedReference() throws Exception { + + TicketModel a = ticketService.createTicket(repo, newTicket("commentNoUnexpectedReference-A")); + TicketModel b = ticketService.createTicket(repo, newTicket("commentNoUnexpectedReference-B")); + + assertNotNull(ticketService.updateTicket(repo, a.number, newComment("comment for 1 - no reference"))); + assertNotNull(ticketService.updateTicket(repo, a.number, newComment("comment for # - no reference"))); + assertNotNull(ticketService.updateTicket(repo, a.number, newComment("comment for #42 - ignores invalid reference"))); + + a = ticketService.getTicket(repo, a.number); + b = ticketService.getTicket(repo, b.number); + + assertFalse(a.hasReferences()); + assertFalse(b.hasReferences()); + } + + @Test + public void commentNoSelfReference() throws Exception { + + TicketModel a = ticketService.createTicket(repo, newTicket("commentNoSelfReference-A")); + + final Change comment = newComment(String.format("comment for #%d - no self reference", a.number)); + assertNotNull(ticketService.updateTicket(repo, a.number, comment)); + + a = ticketService.getTicket(repo, a.number); + + assertFalse(a.hasReferences()); + } + + @Test + public void commentSingleReference() throws Exception { + + TicketModel a = ticketService.createTicket(repo, newTicket("commentSingleReference-A")); + TicketModel b = ticketService.createTicket(repo, newTicket("commentSingleReference-B")); + + final Change comment = newComment(String.format("comment for #%d - single reference", b.number)); + assertNotNull(ticketService.updateTicket(repo, a.number, comment)); + + a = ticketService.getTicket(repo, a.number); + b = ticketService.getTicket(repo, b.number); + + assertFalse(a.hasReferences()); + assertTrue(b.hasReferences()); + + List<Reference> cRefB = b.getReferences(); + assertNotNull(cRefB); + assertEquals(1, cRefB.size()); + assertEquals(a.number, cRefB.get(0).ticketId.longValue()); + assertEquals(comment.comment.id, cRefB.get(0).hash); + } + + @Test + public void commentSelfAndOtherReference() throws Exception { + TicketModel a = ticketService.createTicket(repo, newTicket("commentSelfAndOtherReference-A")); + TicketModel b = ticketService.createTicket(repo, newTicket("commentSelfAndOtherReference-B")); + + final Change comment = newComment(String.format("comment for #%d and #%d - self and other reference", a.number, b.number)); + assertNotNull(ticketService.updateTicket(repo, a.number, comment)); + + a = ticketService.getTicket(repo, a.number); + b = ticketService.getTicket(repo, b.number); + + assertFalse(a.hasReferences()); + assertTrue(b.hasReferences()); + + List<Reference> cRefB = b.getReferences(); + assertNotNull(cRefB); + assertEquals(1, cRefB.size()); + assertEquals(a.number, cRefB.get(0).ticketId.longValue()); + assertEquals(comment.comment.id, cRefB.get(0).hash); + } + + @Test + public void commentMultiReference() throws Exception { + TicketModel a = ticketService.createTicket(repo, newTicket("commentMultiReference-A")); + TicketModel b = ticketService.createTicket(repo, newTicket("commentMultiReference-B")); + TicketModel c = ticketService.createTicket(repo, newTicket("commentMultiReference-C")); + + final Change comment = newComment(String.format("comment for #%d and #%d - multi reference", b.number, c.number)); + assertNotNull(ticketService.updateTicket(repo, a.number, comment)); + + a = ticketService.getTicket(repo, a.number); + b = ticketService.getTicket(repo, b.number); + c = ticketService.getTicket(repo, c.number); + + assertFalse(a.hasReferences()); + assertTrue(b.hasReferences()); + assertTrue(c.hasReferences()); + + List<Reference> cRefB = b.getReferences(); + assertNotNull(cRefB); + assertEquals(1, cRefB.size()); + assertEquals(a.number, cRefB.get(0).ticketId.longValue()); + assertEquals(comment.comment.id, cRefB.get(0).hash); + + List<Reference> cRefC = c.getReferences(); + assertNotNull(cRefC); + assertEquals(1, cRefC.size()); + assertEquals(a.number, cRefC.get(0).ticketId.longValue()); + assertEquals(comment.comment.id, cRefC.get(0).hash); + } + + + + @Test + public void commitMasterNoUnexpectedReference() throws Exception { + TicketModel a = ticketService.createTicket(repo, newTicket("commentMultiReference-A")); + + final String branchName = "master"; + git.checkout().setCreateBranch(false).setName(branchName).call(); + + makeCommit("commit for 1 - no reference"); + makeCommit("comment for # - no reference"); + final RevCommit revCommit1 = makeCommit("comment for #42 - ignores invalid reference"); + final String commit1Sha = revCommit1.name(); + + assertPushSuccess(commit1Sha, branchName); + + a = ticketService.getTicket(repo, a.number); + assertFalse(a.hasReferences()); + } + + @Test + public void commitMasterSingleReference() throws Exception { + TicketModel a = ticketService.createTicket(repo, newTicket("commitMasterSingleReference-A")); + + final String branchName = "master"; + git.checkout().setCreateBranch(false).setName(branchName).call(); + + final String message = String.format("commit for #%d - single reference", a.number); + final RevCommit revCommit1 = makeCommit(message); + final String commit1Sha = revCommit1.name(); + + assertPushSuccess(commit1Sha, branchName); + + a = ticketService.getTicket(repo, a.number); + assertTrue(a.hasReferences()); + + List<Reference> cRefA = a.getReferences(); + assertNotNull(cRefA); + assertEquals(1, cRefA.size()); + assertNull(cRefA.get(0).ticketId); + assertEquals(commit1Sha, cRefA.get(0).hash); + } + + @Test + public void commitMasterMultiReference() throws Exception { + TicketModel a = ticketService.createTicket(repo, newTicket("commitMasterMultiReference-A")); + TicketModel b = ticketService.createTicket(repo, newTicket("commitMasterMultiReference-B")); + + final String branchName = "master"; + git.checkout().setCreateBranch(false).setName(branchName).call(); + + final String message = String.format("commit for #%d and #%d - multi reference", a.number, b.number); + final RevCommit revCommit1 = makeCommit(message); + final String commit1Sha = revCommit1.name(); + + assertPushSuccess(commit1Sha, branchName); + + a = ticketService.getTicket(repo, a.number); + b = ticketService.getTicket(repo, b.number); + assertTrue(a.hasReferences()); + assertTrue(b.hasReferences()); + + List<Reference> cRefA = a.getReferences(); + assertNotNull(cRefA); + assertEquals(1, cRefA.size()); + assertNull(cRefA.get(0).ticketId); + assertEquals(commit1Sha, cRefA.get(0).hash); + + List<Reference> cRefB = a.getReferences(); + assertNotNull(cRefB); + assertEquals(1, cRefB.size()); + assertNull(cRefB.get(0).ticketId); + assertEquals(commit1Sha, cRefB.get(0).hash); + } + + @Test + public void commitMasterAmendReference() throws Exception { + TicketModel a = ticketService.createTicket(repo, newTicket("commitMasterAmendReference-A")); + TicketModel b = ticketService.createTicket(repo, newTicket("commitMasterAmendReference-B")); + + final String branchName = "master"; + git.checkout().setCreateBranch(false).setName(branchName).call(); + + String message = String.format("commit before amend for #%d and #%d", a.number, b.number); + final RevCommit revCommit1 = makeCommit(message); + final String commit1Sha = revCommit1.name(); + assertPushSuccess(commit1Sha, branchName); + + a = ticketService.getTicket(repo, a.number); + b = ticketService.getTicket(repo, b.number); + assertTrue(a.hasReferences()); + assertTrue(b.hasReferences()); + + List<Reference> cRefA = a.getReferences(); + assertNotNull(cRefA); + assertEquals(1, cRefA.size()); + assertNull(cRefA.get(0).ticketId); + assertEquals(commit1Sha, cRefA.get(0).hash); + + List<Reference> cRefB = b.getReferences(); + assertNotNull(cRefB); + assertEquals(1, cRefB.size()); + assertNull(cRefB.get(0).ticketId); + assertEquals(commit1Sha, cRefB.get(0).hash); + + //Confirm that old invalid references removed for both tickets + //and new reference added for one referenced ticket + message = String.format("commit after amend for #%d", a.number); + final String commit2Sha = amendCommit(message); + + assertForcePushSuccess(commit2Sha, branchName); + + a = ticketService.getTicket(repo, a.number); + b = ticketService.getTicket(repo, b.number); + assertTrue(a.hasReferences()); + assertFalse(b.hasReferences()); + + cRefA = a.getReferences(); + assertNotNull(cRefA); + assertEquals(1, cRefA.size()); + assertNull(cRefA.get(0).ticketId); + assertEquals(commit2Sha, cRefA.get(0).hash); + } + + + @Test + public void commitPatchsetNoUnexpectedReference() throws Exception { + setPatchsetAvailable(true); + TicketModel a = ticketService.createTicket(repo, newTicket("commitPatchsetNoUnexpectedReference-A")); + + String branchName = String.format("ticket/%d", a.number); + git.checkout().setCreateBranch(true).setName(branchName).call(); + + makeCommit("commit for 1 - no reference"); + makeCommit("commit for # - no reference"); + final String message = "commit for #42 - ignores invalid reference"; + final RevCommit revCommit1 = makeCommit(message); + final String commit1Sha = revCommit1.name(); + + assertPushSuccess(commit1Sha, branchName); + + a = ticketService.getTicket(repo, a.number); + assertFalse(a.hasReferences()); + } + + @Test + public void commitPatchsetNoSelfReference() throws Exception { + setPatchsetAvailable(true); + TicketModel a = ticketService.createTicket(repo, newTicket("commitPatchsetNoSelfReference-A")); + + String branchName = String.format("ticket/%d", a.number); + git.checkout().setCreateBranch(true).setName(branchName).call(); + + final String message = String.format("commit for #%d - patchset self reference", a.number); + final RevCommit revCommit1 = makeCommit(message); + final String commit1Sha = revCommit1.name(); + + assertPushSuccess(commit1Sha, branchName); + + a = ticketService.getTicket(repo, a.number); + assertFalse(a.hasReferences()); + } + + @Test + public void commitPatchsetSingleReference() throws Exception { + setPatchsetAvailable(true); + TicketModel a = ticketService.createTicket(repo, newTicket("commitPatchsetSingleReference-A")); + TicketModel b = ticketService.createTicket(repo, newTicket("commitPatchsetSingleReference-B")); + + String branchName = String.format("ticket/%d", a.number); + git.checkout().setCreateBranch(true).setName(branchName).call(); + + final String message = String.format("commit for #%d - patchset single reference", b.number); + final RevCommit revCommit1 = makeCommit(message); + final String commit1Sha = revCommit1.name(); + + assertPushSuccess(commit1Sha, branchName); + + a = ticketService.getTicket(repo, a.number); + b = ticketService.getTicket(repo, b.number); + assertFalse(a.hasReferences()); + assertTrue(b.hasReferences()); + + List<Reference> cRefB = b.getReferences(); + assertNotNull(cRefB); + assertEquals(1, cRefB.size()); + assertNull(cRefB.get(0).ticketId); + assertEquals(commit1Sha, cRefB.get(0).hash); + } + + @Test + public void commitPatchsetMultiReference() throws Exception { + setPatchsetAvailable(true); + TicketModel a = ticketService.createTicket(repo, newTicket("commitPatchsetMultiReference-A")); + TicketModel b = ticketService.createTicket(repo, newTicket("commitPatchsetMultiReference-B")); + TicketModel c = ticketService.createTicket(repo, newTicket("commitPatchsetMultiReference-C")); + + String branchName = String.format("ticket/%d", a.number); + git.checkout().setCreateBranch(true).setName(branchName).call(); + + final String message = String.format("commit for #%d and #%d- patchset multi reference", b.number, c.number); + final RevCommit revCommit1 = makeCommit(message); + final String commit1Sha = revCommit1.name(); + + assertPushSuccess(commit1Sha, branchName); + + a = ticketService.getTicket(repo, a.number); + b = ticketService.getTicket(repo, b.number); + c = ticketService.getTicket(repo, c.number); + assertFalse(a.hasReferences()); + assertTrue(b.hasReferences()); + assertTrue(c.hasReferences()); + + List<Reference> cRefB = b.getReferences(); + assertNotNull(cRefB); + assertEquals(1, cRefB.size()); + assertNull(cRefB.get(0).ticketId); + assertEquals(commit1Sha, cRefB.get(0).hash); + + List<Reference> cRefC = c.getReferences(); + assertNotNull(cRefC); + assertEquals(1, cRefC.size()); + assertNull(cRefC.get(0).ticketId); + assertEquals(commit1Sha, cRefC.get(0).hash); + } + + @Test + public void commitPatchsetAmendReference() throws Exception { + setPatchsetAvailable(true); + + TicketModel a = ticketService.createTicket(repo, newTicket("commitPatchsetAmendReference-A")); + TicketModel b = ticketService.createTicket(repo, newTicket("commitPatchsetAmendReference-B")); + TicketModel c = ticketService.createTicket(repo, newTicket("commitPatchsetAmendReference-C")); + assertFalse(c.hasPatchsets()); + + String branchName = String.format("ticket/%d", c.number); + git.checkout().setCreateBranch(true).setName(branchName).call(); + + String message = String.format("commit before amend for #%d and #%d", a.number, b.number); + final RevCommit revCommit1 = makeCommit(message); + final String commit1Sha = revCommit1.name(); + assertPushSuccess(commit1Sha, branchName); + + a = ticketService.getTicket(repo, a.number); + b = ticketService.getTicket(repo, b.number); + c = ticketService.getTicket(repo, c.number); + assertTrue(a.hasReferences()); + assertTrue(b.hasReferences()); + assertFalse(c.hasReferences()); + + assertTrue(c.hasPatchsets()); + assertNotNull(c.getPatchset(1, 1)); + + List<Reference> cRefA = a.getReferences(); + assertNotNull(cRefA); + assertEquals(1, cRefA.size()); + assertNull(cRefA.get(0).ticketId); + assertEquals(commit1Sha, cRefA.get(0).hash); + + List<Reference> cRefB = b.getReferences(); + assertNotNull(cRefB); + assertEquals(1, cRefB.size()); + assertNull(cRefB.get(0).ticketId); + assertEquals(commit1Sha, cRefB.get(0).hash); + + //As a new patchset is created the references will remain until deleted + message = String.format("commit after amend for #%d", a.number); + final String commit2Sha = amendCommit(message); + + assertForcePushSuccess(commit2Sha, branchName); + + a = ticketService.getTicket(repo, a.number); + b = ticketService.getTicket(repo, b.number); + c = ticketService.getTicket(repo, c.number); + assertTrue(a.hasReferences()); + assertTrue(b.hasReferences()); + assertFalse(c.hasReferences()); + + assertNotNull(c.getPatchset(1, 1)); + assertNotNull(c.getPatchset(2, 1)); + + cRefA = a.getReferences(); + assertNotNull(cRefA); + assertEquals(2, cRefA.size()); + assertNull(cRefA.get(0).ticketId); + assertNull(cRefA.get(1).ticketId); + assertEquals(commit1Sha, cRefA.get(0).hash); + assertEquals(commit2Sha, cRefA.get(1).hash); + + cRefB = b.getReferences(); + assertNotNull(cRefB); + assertEquals(1, cRefB.size()); + assertNull(cRefB.get(0).ticketId); + assertEquals(commit1Sha, cRefB.get(0).hash); + + //Delete the original patchset and confirm old references are removed + ticketService.deletePatchset(c, c.getPatchset(1, 1), user.username); + + a = ticketService.getTicket(repo, a.number); + b = ticketService.getTicket(repo, b.number); + c = ticketService.getTicket(repo, c.number); + assertTrue(a.hasReferences()); + assertFalse(b.hasReferences()); + assertFalse(c.hasReferences()); + + assertNull(c.getPatchset(1, 1)); + assertNotNull(c.getPatchset(2, 1)); + + cRefA = a.getReferences(); + assertNotNull(cRefA); + assertEquals(1, cRefA.size()); + assertNull(cRefA.get(0).ticketId); + assertEquals(commit2Sha, cRefA.get(0).hash); + } + + + @Test + public void commitTicketBranchNoUnexpectedReference() throws Exception { + setPatchsetAvailable(false); + TicketModel a = ticketService.createTicket(repo, newTicket("commitTicketBranchNoUnexpectedReference-A")); + + String branchName = String.format("ticket/%d", a.number); + git.checkout().setCreateBranch(true).setName(branchName).call(); + + makeCommit("commit for 1 - no reference"); + makeCommit("commit for # - no reference"); + final String message = "commit for #42 - ignores invalid reference"; + final RevCommit revCommit1 = makeCommit(message); + final String commit1Sha = revCommit1.name(); + assertPushSuccess(commit1Sha, branchName); + + a = ticketService.getTicket(repo, a.number); + assertFalse(a.hasReferences()); + } + + @Test + public void commitTicketBranchSelfReference() throws Exception { + setPatchsetAvailable(false); + TicketModel a = ticketService.createTicket(repo, newTicket("commitTicketBranchSelfReference-A")); + + String branchName = String.format("ticket/%d", a.number); + git.checkout().setCreateBranch(true).setName(branchName).call(); + + final String message = String.format("commit for #%d - patchset self reference", a.number); + final RevCommit revCommit1 = makeCommit(message); + final String commit1Sha = revCommit1.name(); + + assertPushSuccess(commit1Sha, branchName); + + a = ticketService.getTicket(repo, a.number); + assertTrue(a.hasReferences()); + + List<Reference> cRefA = a.getReferences(); + assertNotNull(cRefA); + assertEquals(1, cRefA.size()); + assertNull(cRefA.get(0).ticketId); + assertEquals(commit1Sha, cRefA.get(0).hash); + } + + @Test + public void commitTicketBranchSingleReference() throws Exception { + setPatchsetAvailable(false); + TicketModel a = ticketService.createTicket(repo, newTicket("commitTicketBranchSingleReference-A")); + TicketModel b = ticketService.createTicket(repo, newTicket("commitTicketBranchSingleReference-B")); + + String branchName = String.format("ticket/%d", a.number); + git.checkout().setCreateBranch(true).setName(branchName).call(); + + final String message = String.format("commit for #%d - patchset single reference", b.number); + final RevCommit revCommit1 = makeCommit(message); + final String commit1Sha = revCommit1.name(); + + assertPushSuccess(commit1Sha, branchName); + + a = ticketService.getTicket(repo, a.number); + b = ticketService.getTicket(repo, b.number); + assertFalse(a.hasReferences()); + assertTrue(b.hasReferences()); + + List<Reference> cRefB = b.getReferences(); + assertNotNull(cRefB); + assertEquals(1, cRefB.size()); + assertNull(cRefB.get(0).ticketId); + assertEquals(commit1Sha, cRefB.get(0).hash); + } + + @Test + public void commitTicketBranchMultiReference() throws Exception { + setPatchsetAvailable(false); + TicketModel a = ticketService.createTicket(repo, newTicket("commitTicketBranchMultiReference-A")); + TicketModel b = ticketService.createTicket(repo, newTicket("commitTicketBranchMultiReference-B")); + TicketModel c = ticketService.createTicket(repo, newTicket("commitTicketBranchMultiReference-C")); + + String branchName = String.format("ticket/%d", a.number); + git.checkout().setCreateBranch(true).setName(branchName).call(); + + final String message = String.format("commit for #%d and #%d- patchset multi reference", b.number, c.number); + final RevCommit revCommit1 = makeCommit(message); + final String commit1Sha = revCommit1.name(); + + assertPushSuccess(commit1Sha, branchName); + + a = ticketService.getTicket(repo, a.number); + b = ticketService.getTicket(repo, b.number); + c = ticketService.getTicket(repo, c.number); + assertFalse(a.hasReferences()); + assertTrue(b.hasReferences()); + assertTrue(c.hasReferences()); + + List<Reference> cRefB = b.getReferences(); + assertNotNull(cRefB); + assertEquals(1, cRefB.size()); + assertNull(cRefB.get(0).ticketId); + assertEquals(commit1Sha, cRefB.get(0).hash); + + List<Reference> cRefC = c.getReferences(); + assertNotNull(cRefC); + assertEquals(1, cRefC.size()); + assertNull(cRefC.get(0).ticketId); + assertEquals(commit1Sha, cRefC.get(0).hash); + } + + @Test + public void commitTicketBranchAmendReference() throws Exception { + setPatchsetAvailable(false); + + TicketModel a = ticketService.createTicket(repo, newTicket("commitTicketBranchAmendReference-A")); + TicketModel b = ticketService.createTicket(repo, newTicket("commitTicketBranchAmendReference-B")); + TicketModel c = ticketService.createTicket(repo, newTicket("commitTicketBranchAmendReference-C")); + assertFalse(c.hasPatchsets()); + + String branchName = String.format("ticket/%d", c.number); + git.checkout().setCreateBranch(true).setName(branchName).call(); + + String message = String.format("commit before amend for #%d and #%d", a.number, b.number); + final RevCommit revCommit1 = makeCommit(message); + final String commit1Sha = revCommit1.name(); + assertPushSuccess(commit1Sha, branchName); + + a = ticketService.getTicket(repo, a.number); + b = ticketService.getTicket(repo, b.number); + c = ticketService.getTicket(repo, c.number); + assertTrue(a.hasReferences()); + assertTrue(b.hasReferences()); + assertFalse(c.hasReferences()); + assertFalse(c.hasPatchsets()); + + List<Reference> cRefA = a.getReferences(); + assertNotNull(cRefA); + assertEquals(1, cRefA.size()); + assertNull(cRefA.get(0).ticketId); + assertEquals(commit1Sha, cRefA.get(0).hash); + + List<Reference> cRefB = b.getReferences(); + assertNotNull(cRefB); + assertEquals(1, cRefB.size()); + assertNull(cRefB.get(0).ticketId); + assertEquals(commit1Sha, cRefB.get(0).hash); + + //Confirm that old invalid references removed for both tickets + //and new reference added for one referenced ticket + message = String.format("commit after amend for #%d", a.number); + final String commit2Sha = amendCommit(message); + + assertForcePushSuccess(commit2Sha, branchName); + + a = ticketService.getTicket(repo, a.number); + b = ticketService.getTicket(repo, b.number); + c = ticketService.getTicket(repo, c.number); + assertTrue(a.hasReferences()); + assertFalse(b.hasReferences()); + assertFalse(c.hasReferences()); + assertFalse(c.hasPatchsets()); + + cRefA = a.getReferences(); + assertNotNull(cRefA); + assertEquals(1, cRefA.size()); + assertNull(cRefA.get(0).ticketId); + assertEquals(commit2Sha, cRefA.get(0).hash); + } + + @Test + public void commitTicketBranchDeleteNoMergeReference() throws Exception { + setPatchsetAvailable(false); + + TicketModel a = ticketService.createTicket(repo, newTicket("commitTicketBranchDeleteNoMergeReference-A")); + TicketModel b = ticketService.createTicket(repo, newTicket("commitTicketBranchDeleteNoMergeReference-B")); + TicketModel c = ticketService.createTicket(repo, newTicket("commitTicketBranchDeleteNoMergeReference-C")); + assertFalse(c.hasPatchsets()); + + String branchName = String.format("ticket/%d", c.number); + git.checkout().setCreateBranch(true).setName(branchName).call(); + + String message = String.format("commit before amend for #%d and #%d", a.number, b.number); + final RevCommit revCommit1 = makeCommit(message); + final String commit1Sha = revCommit1.name(); + assertPushSuccess(commit1Sha, branchName); + + a = ticketService.getTicket(repo, a.number); + b = ticketService.getTicket(repo, b.number); + c = ticketService.getTicket(repo, c.number); + assertTrue(a.hasReferences()); + assertTrue(b.hasReferences()); + assertFalse(c.hasReferences()); + + List<Reference> cRefA = a.getReferences(); + assertNotNull(cRefA); + assertEquals(1, cRefA.size()); + assertNull(cRefA.get(0).ticketId); + assertEquals(commit1Sha, cRefA.get(0).hash); + + List<Reference> cRefB = b.getReferences(); + assertNotNull(cRefB); + assertEquals(1, cRefB.size()); + assertNull(cRefB.get(0).ticketId); + assertEquals(commit1Sha, cRefB.get(0).hash); + + //Confirm that old invalid references removed for both tickets + assertDeleteBranch(branchName); + + a = ticketService.getTicket(repo, a.number); + b = ticketService.getTicket(repo, b.number); + c = ticketService.getTicket(repo, c.number); + assertFalse(a.hasReferences()); + assertFalse(b.hasReferences()); + assertFalse(c.hasReferences()); + } + + @Test + public void commitTicketBranchDeletePostMergeReference() throws Exception { + setPatchsetAvailable(false); + + TicketModel a = ticketService.createTicket(repo, newTicket("commitTicketBranchDeletePostMergeReference-A")); + TicketModel b = ticketService.createTicket(repo, newTicket("commitTicketBranchDeletePostMergeReference-B")); + TicketModel c = ticketService.createTicket(repo, newTicket("commitTicketBranchDeletePostMergeReference-C")); + assertFalse(c.hasPatchsets()); + + String branchName = String.format("ticket/%d", c.number); + git.checkout().setCreateBranch(true).setName(branchName).call(); + + String message = String.format("commit before amend for #%d and #%d", a.number, b.number); + final RevCommit revCommit1 = makeCommit(message); + final String commit1Sha = revCommit1.name(); + assertPushSuccess(commit1Sha, branchName); + + a = ticketService.getTicket(repo, a.number); + b = ticketService.getTicket(repo, b.number); + c = ticketService.getTicket(repo, c.number); + assertTrue(a.hasReferences()); + assertTrue(b.hasReferences()); + assertFalse(c.hasReferences()); + + List<Reference> cRefA = a.getReferences(); + assertNotNull(cRefA); + assertEquals(1, cRefA.size()); + assertNull(cRefA.get(0).ticketId); + assertEquals(commit1Sha, cRefA.get(0).hash); + + List<Reference> cRefB = b.getReferences(); + assertNotNull(cRefB); + assertEquals(1, cRefB.size()); + assertNull(cRefB.get(0).ticketId); + assertEquals(commit1Sha, cRefB.get(0).hash); + + git.checkout().setCreateBranch(false).setName("refs/heads/master").call(); + + // merge the tip of the branch into master + MergeResult mergeResult = git.merge().setFastForward(FastForwardMode.NO_FF).include(revCommit1.getId()).call(); + assertEquals(MergeResult.MergeStatus.MERGED, mergeResult.getMergeStatus()); + + // push the merged master to the origin + Iterable<PushResult> results = git.push().setCredentialsProvider(cp).setRemote("origin").call(); + for (PushResult result : results) { + RemoteRefUpdate ref = result.getRemoteUpdate("refs/heads/master"); + assertEquals(Status.OK, ref.getStatus()); + } + + //As everything has been merged no references should be changed + assertDeleteBranch(branchName); + + a = ticketService.getTicket(repo, a.number); + b = ticketService.getTicket(repo, b.number); + c = ticketService.getTicket(repo, c.number); + assertTrue(a.hasReferences()); + assertTrue(b.hasReferences()); + assertFalse(c.hasReferences()); + + cRefA = a.getReferences(); + assertNotNull(cRefA); + assertEquals(1, cRefA.size()); + assertNull(cRefA.get(0).ticketId); + assertEquals(commit1Sha, cRefA.get(0).hash); + + cRefB = b.getReferences(); + assertNotNull(cRefB); + assertEquals(1, cRefB.size()); + assertNull(cRefB.get(0).ticketId); + assertEquals(commit1Sha, cRefB.get(0).hash); + } + + private static Change newComment(String text) { + Change change = new Change("JUnit"); + change.comment(text); + return change; + } + + private static Change newTicket(String title) { + Change change = new Change("JUnit"); + change.setField(Field.title, title); + change.setField(Field.type, TicketModel.Type.Bug ); + return change; + } + + private static RevCommit makeCommit(String message) throws Exception { + File file = new File(workingCopy, "testFile.txt"); + OutputStreamWriter os = new OutputStreamWriter(new FileOutputStream(file, true), Constants.CHARSET); + BufferedWriter w = new BufferedWriter(os); + w.write("// " + new Date().toString() + "\n"); + w.close(); + git.add().addFilepattern(file.getName()).call(); + RevCommit rev = git.commit().setMessage(message).call(); + return rev; + } + + private static String amendCommit(String message) throws Exception { + File file = new File(workingCopy, "testFile.txt"); + OutputStreamWriter os = new OutputStreamWriter(new FileOutputStream(file, true), Constants.CHARSET); + BufferedWriter w = new BufferedWriter(os); + w.write("// " + new Date().toString() + "\n"); + w.close(); + git.add().addFilepattern(file.getName()).call(); + RevCommit rev = git.commit().setAmend(true).setMessage(message).call(); + return rev.getId().name(); + } + + + private void setPatchsetAvailable(boolean state) throws GitBlitException { + repo.acceptNewPatchsets = state; + gitblit().updateRepositoryModel(repo.name, repo, false); + } + + + private void assertPushSuccess(String commitSha, String branchName) throws Exception { + Iterable<PushResult> results = git.push().setRemote("origin").setCredentialsProvider(cp).call(); + + for (PushResult result : results) { + RemoteRefUpdate ref = result.getRemoteUpdate("refs/heads/" + branchName); + assertEquals(Status.OK, ref.getStatus()); + assertEquals(commitSha, ref.getNewObjectId().name()); + } + } + + private void assertForcePushSuccess(String commitSha, String branchName) throws Exception { + Iterable<PushResult> results = git.push().setForce(true).setRemote("origin").setCredentialsProvider(cp).call(); + + for (PushResult result : results) { + RemoteRefUpdate ref = result.getRemoteUpdate("refs/heads/" + branchName); + assertEquals(Status.OK, ref.getStatus()); + assertEquals(commitSha, ref.getNewObjectId().name()); + } + } + + private void assertDeleteBranch(String branchName) throws Exception { + + RefSpec refSpec = new RefSpec() + .setSource(null) + .setDestination("refs/heads/" + branchName); + + Iterable<PushResult> results = git.push().setRefSpecs(refSpec).setRemote("origin").setCredentialsProvider(cp).call(); + + for (PushResult result : results) { + RemoteRefUpdate ref = result.getRemoteUpdate("refs/heads/" + branchName); + assertEquals(Status.OK, ref.getStatus()); + } + } +}
\ No newline at end of file |