From 90b8d7e0e1b5e5ed296c1213168b9a8937ac66fd Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Thu, 02 Feb 2012 20:02:40 -0500
Subject: [PATCH] Refactored and unit tested updating HEAD feature

---
 src/com/gitblit/GitBlit.java                         |   19 +++---
 src/com/gitblit/wicket/GitBlitWebApp.properties      |    3 
 src/com/gitblit/wicket/pages/EditRepositoryPage.java |    8 +-
 tests/com/gitblit/tests/JGitUtilsTest.java           |   22 +++++++
 src/com/gitblit/models/RepositoryModel.java          |    4 
 src/com/gitblit/client/EditRepositoryDialog.java     |   21 +++---
 src/com/gitblit/wicket/pages/EditRepositoryPage.html |    2 
 src/com/gitblit/utils/JGitUtils.java                 |   46 +++++++--------
 8 files changed, 71 insertions(+), 54 deletions(-)

diff --git a/src/com/gitblit/GitBlit.java b/src/com/gitblit/GitBlit.java
index 9712ea6..a689b48 100644
--- a/src/com/gitblit/GitBlit.java
+++ b/src/com/gitblit/GitBlit.java
@@ -786,8 +786,8 @@
 			model.mailingLists = new ArrayList<String>(Arrays.asList(config.getStringList(
 					"gitblit", null, "mailingList")));
 		}
-		model.defaultHead = JGitUtils.getSymbolicHeadTarget(r);
-		model.availableHeads = JGitUtils.getAvailableHeadTargets(r);
+		model.HEAD = JGitUtils.getHEADRef(r);
+		model.availableRefs = JGitUtils.getAvailableHeadTargets(r);
 		r.close();
 		return model;
 	}
@@ -984,15 +984,14 @@
 		if (r != null) {
 			updateConfiguration(r, repository);
 			// only update symbolic head if it changes
-			String currentHead = JGitUtils.getSymbolicHeadTarget(r);
-			if (!StringUtils.isEmpty(repository.defaultHead)  &&
-					!repository.defaultHead.equals(currentHead)) {
+			String currentRef = JGitUtils.getHEADRef(r);
+			if (!StringUtils.isEmpty(repository.HEAD) && !repository.HEAD.equals(currentRef)) {
 				logger.info(MessageFormat.format("Relinking {0} HEAD from {1} to {2}", 
-						repository.name, currentHead, repository.defaultHead));
-				JGitUtils.setSymbolicHeadTarget(r, repository.defaultHead);
-
-				// clear the cache
-				clearRepositoryCache(repository.name);
+						repository.name, currentRef, repository.HEAD));
+				if (JGitUtils.setHEADtoRef(r, repository.HEAD)) {
+					// clear the cache
+					clearRepositoryCache(repository.name);
+				}
 			}
 
 			// close the repository object
diff --git a/src/com/gitblit/client/EditRepositoryDialog.java b/src/com/gitblit/client/EditRepositoryDialog.java
index eaf7e0c..4d3485d 100644
--- a/src/com/gitblit/client/EditRepositoryDialog.java
+++ b/src/com/gitblit/client/EditRepositoryDialog.java
@@ -98,7 +98,7 @@
 
 	private JComboBox ownerField;
 
-	private JComboBox defaultHeadField;
+	private JComboBox headRefField;
 
 	private JPalette<String> usersPalette;
 
@@ -158,13 +158,13 @@
 				anRepository.origin == null ? "" : anRepository.origin, 40);
 		originField.setEditable(false);
 
-		if (ArrayUtils.isEmpty(anRepository.availableHeads)) {
-			defaultHeadField = new JComboBox();
-			defaultHeadField.setEnabled(false);			
+		if (ArrayUtils.isEmpty(anRepository.availableRefs)) {
+			headRefField = new JComboBox();
+			headRefField.setEnabled(false);			
 		} else {
-			defaultHeadField = new JComboBox(
-					anRepository.availableHeads.toArray());
-			defaultHeadField.setSelectedItem(anRepository.defaultHead);
+			headRefField = new JComboBox(
+					anRepository.availableRefs.toArray());
+			headRefField.setSelectedItem(anRepository.HEAD);
 		}
 
 		ownerField = new JComboBox();
@@ -213,8 +213,7 @@
 				descriptionField));
 		fieldsPanel
 				.add(newFieldPanel(Translation.get("gb.origin"), originField));
-		fieldsPanel.add(newFieldPanel(Translation.get("gb.defaultHead"),
-				defaultHeadField));
+		fieldsPanel.add(newFieldPanel(Translation.get("gb.head"), headRefField));
 		fieldsPanel.add(newFieldPanel(Translation.get("gb.owner"), ownerField));
 
 		fieldsPanel.add(newFieldPanel(Translation.get("gb.enableTickets"),
@@ -404,8 +403,8 @@
 		repository.description = descriptionField.getText();
 		repository.owner = ownerField.getSelectedItem() == null ? null
 				: ownerField.getSelectedItem().toString();
-		repository.defaultHead = defaultHeadField.getSelectedItem() == null ? null
-				: defaultHeadField.getSelectedItem().toString();
+		repository.HEAD = headRefField.getSelectedItem() == null ? null
+				: headRefField.getSelectedItem().toString();
 		repository.useTickets = useTickets.isSelected();
 		repository.useDocs = useDocs.isSelected();
 		repository.showRemoteBranches = showRemoteBranches.isSelected();
diff --git a/src/com/gitblit/models/RepositoryModel.java b/src/com/gitblit/models/RepositoryModel.java
index e7a0880..b633c69 100644
--- a/src/com/gitblit/models/RepositoryModel.java
+++ b/src/com/gitblit/models/RepositoryModel.java
@@ -58,8 +58,8 @@
 	public List<String> preReceiveScripts;
 	public List<String> postReceiveScripts;
 	public List<String> mailingLists;
-	public String defaultHead;
-	public List<String> availableHeads;
+	public String HEAD;
+	public List<String> availableRefs;
 
 	private String displayName;
 	
diff --git a/src/com/gitblit/utils/JGitUtils.java b/src/com/gitblit/utils/JGitUtils.java
index 319aca5..c80fb8a 100644
--- a/src/com/gitblit/utils/JGitUtils.java
+++ b/src/com/gitblit/utils/JGitUtils.java
@@ -1163,9 +1163,9 @@
 	 * no match is found, the SHA1 is returned.
 	 *
 	 * @param repository
-	 * @return the ref name or the SHA1 for detached HEADs
+	 * @return the ref name or the SHA1 for a detached HEAD
 	 */
-	public static String getSymbolicHeadTarget(Repository repository) {
+	public static String getHEADRef(Repository repository) {
 		String target = null;
 		try {
 			target = repository.getFullBranch();
@@ -1193,58 +1193,56 @@
 	}
 	
 	/**
-	 * Sets the HEAD symbolic ref name for a repository. The HEAD will
-	 * be detached if the name does not reference a branch.
+	 * Sets the symbolic ref HEAD to the specified target ref. The
+	 * HEAD will be detached if the target ref is not a branch.
 	 *
 	 * @param repository
-	 * @param name
+	 * @param targetRef
+	 * @return true if successful
 	 */
-	public static void setSymbolicHeadTarget(Repository repository, String name) {
+	public static boolean setHEADtoRef(Repository repository, String targetRef) {
 		try {
-			boolean detach = !name.startsWith(Constants.R_HEADS); // detach if not a branch
+			 // detach HEAD if target ref is not a branch
+			boolean detach = !targetRef.startsWith(Constants.R_HEADS);
 			RefUpdate.Result result;
 			RefUpdate head = repository.updateRef(Constants.HEAD, detach);
 			if (detach) { // Tag
-				RevCommit commit = getCommit(repository, name);
+				RevCommit commit = getCommit(repository, targetRef);
 				head.setNewObjectId(commit.getId());
 				result = head.forceUpdate();
 			} else {
-				result = head.link(name);
+				result = head.link(targetRef);
 			}
 			switch (result) {
 			case NEW:
 			case FORCED:
 			case NO_CHANGE:
 			case FAST_FORWARD:
-				break;
+				return true;				
 			default:
-				LOGGER.error(MessageFormat.format("{0} symbolic HEAD update to {1} returned result {2}",
-						repository.getDirectory().getAbsolutePath(), name, result));
+				LOGGER.error(MessageFormat.format("{0} HEAD update to {1} returned result {2}",
+						repository.getDirectory().getAbsolutePath(), targetRef, result));
 			}
 		} catch (Throwable t) {
-			error(t, repository, "{0} failed to set symbolic HEAD to {1}", name);
+			error(t, repository, "{0} failed to set HEAD to {1}", targetRef);
 		}
+		return false;
 	}
 	
 	/**
-	 * Get the full branch and tag ref names for any potential symbolic head targets.
+	 * Get the full branch and tag ref names for any potential HEAD targets.
 	 *
 	 * @param repository
 	 * @return a list of ref names
 	 */
 	public static List<String> getAvailableHeadTargets(Repository repository) {
 		List<String> targets = new ArrayList<String>();
-		List<RefModel> branchModels = JGitUtils.getLocalBranches(repository, true, -1);
-		if (branchModels.size() > 0) {
-			for (RefModel branchModel : branchModels) {
-				targets.add(branchModel.getName());
-			}
+		for (RefModel branchModel : JGitUtils.getLocalBranches(repository, true, -1)) {
+			targets.add(branchModel.getName());
 		}
-		List<RefModel> tagModels = JGitUtils.getTags(repository, true, -1);
-		if (tagModels.size() > 0) {
-			for (RefModel tagModel : tagModels) {
-				targets.add(tagModel.getName());
-			}
+
+		for (RefModel tagModel : JGitUtils.getTags(repository, true, -1)) {
+			targets.add(tagModel.getName());
 		}
 		return targets;
 	}
diff --git a/src/com/gitblit/wicket/GitBlitWebApp.properties b/src/com/gitblit/wicket/GitBlitWebApp.properties
index f039a36..1a8513a 100644
--- a/src/com/gitblit/wicket/GitBlitWebApp.properties
+++ b/src/com/gitblit/wicket/GitBlitWebApp.properties
@@ -131,8 +131,7 @@
 gb.sendProposal propose
 gb.status = status
 gb.origin = origin
-gb.defaultHead = default HEAD
-gb.defaultHeadDescription = current branch after clone. e.g. refs/heads/master
+gb.headRefDescription = change the ref that HEAD links to. e.g. refs/heads/master
 gb.federationStrategy = federation strategy
 gb.federationRegistration = federation registration
 gb.federationResults = federation pull results
diff --git a/src/com/gitblit/wicket/pages/EditRepositoryPage.html b/src/com/gitblit/wicket/pages/EditRepositoryPage.html
index 9bd8c51..7c694ba 100644
--- a/src/com/gitblit/wicket/pages/EditRepositoryPage.html
+++ b/src/com/gitblit/wicket/pages/EditRepositoryPage.html
@@ -14,7 +14,7 @@
 				<tr><th><wicket:message key="gb.name"></wicket:message></th><td class="edit"><input class="span6" type="text" wicket:id="name" id="name" size="40" tabindex="1" /> &nbsp;<span class="help-inline"><wicket:message key="gb.nameDescription"></wicket:message></span></td></tr>
 				<tr><th><wicket:message key="gb.description"></wicket:message></th><td class="edit"><input class="span6" type="text" wicket:id="description" size="40" tabindex="2" /></td></tr>
 				<tr><th><wicket:message key="gb.origin"></wicket:message></th><td class="edit"><input class="span7" type="text" wicket:id="origin" size="80" tabindex="3" /></td></tr>
-				<tr><th><wicket:message key="gb.defaultHead"></wicket:message></th><td class="edit"><select wicket:id="defaultHead" tabindex="4" /> &nbsp;<span class="help-inline"><wicket:message key="gb.defaultHeadDescription"></wicket:message></span></td></tr>
+				<tr><th><wicket:message key="gb.head"></wicket:message></th><td class="edit"><select wicket:id="HEAD" tabindex="4" /> &nbsp;<span class="help-inline"><wicket:message key="gb.headRefDescription"></wicket:message></span></td></tr>
 				<tr><th><wicket:message key="gb.owner"></wicket:message></th><td class="edit"><select wicket:id="owner" tabindex="5" /> &nbsp;<span class="help-inline"><wicket:message key="gb.ownerDescription"></wicket:message></span></td></tr>
 				<tr><th><wicket:message key="gb.enableTickets"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="useTickets" tabindex="6" /> &nbsp;<span class="help-inline"><wicket:message key="gb.useTicketsDescription"></wicket:message></span></td></tr>
 				<tr><th><wicket:message key="gb.enableDocs"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="useDocs" tabindex="7" /> &nbsp;<span class="help-inline"><wicket:message key="gb.useDocsDescription"></wicket:message></span></td></tr>
diff --git a/src/com/gitblit/wicket/pages/EditRepositoryPage.java b/src/com/gitblit/wicket/pages/EditRepositoryPage.java
index ec52aaf..a259a99 100644
--- a/src/com/gitblit/wicket/pages/EditRepositoryPage.java
+++ b/src/com/gitblit/wicket/pages/EditRepositoryPage.java
@@ -273,11 +273,11 @@
 		form.add(new TextField<String>("origin").setEnabled(false/* isCreate */));
 		
 		// allow relinking HEAD to a branch or tag other than master on edit repository
-		List<String> availableHeads = new ArrayList<String>();
-		if (!ArrayUtils.isEmpty(repositoryModel.availableHeads)) {
-			availableHeads.addAll(repositoryModel.availableHeads);
+		List<String> availableRefs = new ArrayList<String>();
+		if (!ArrayUtils.isEmpty(repositoryModel.availableRefs)) {
+			availableRefs.addAll(repositoryModel.availableRefs);
 		}
-		form.add(new DropDownChoice<String>("defaultHead", availableHeads).setEnabled(!isCreate));
+		form.add(new DropDownChoice<String>("HEAD", availableRefs).setEnabled(!isCreate));
 
 		// federation strategies - remove ORIGIN choice if this repository has
 		// no origin.
diff --git a/tests/com/gitblit/tests/JGitUtilsTest.java b/tests/com/gitblit/tests/JGitUtilsTest.java
index 7c3f8ab..8d70d2f 100644
--- a/tests/com/gitblit/tests/JGitUtilsTest.java
+++ b/tests/com/gitblit/tests/JGitUtilsTest.java
@@ -212,6 +212,28 @@
 		assertEquals("183474d554e6f68478a02d9d7888b67a9338cdff", list.get(0).notesRef
 				.getReferencedObjectId().getName());
 	}
+	
+	@Test
+	public void testRelinkHEAD() throws Exception {
+		Repository repository = GitBlitSuite.getJGitRepository();
+		// confirm HEAD is master
+		String currentRef = JGitUtils.getHEADRef(repository);
+		assertEquals("refs/heads/master", currentRef);
+		List<String> availableHeads = JGitUtils.getAvailableHeadTargets(repository);
+		assertTrue(availableHeads.size() > 0);
+		
+		// set HEAD to stable-1.2
+		JGitUtils.setHEADtoRef(repository, "refs/heads/stable-1.2");
+		currentRef = JGitUtils.getHEADRef(repository);
+		assertEquals("refs/heads/stable-1.2", currentRef);
+
+		// restore HEAD to master
+		JGitUtils.setHEADtoRef(repository, "refs/heads/master");
+		currentRef = JGitUtils.getHEADRef(repository);
+		assertEquals("refs/heads/master", currentRef);
+		
+		repository.close();
+	}
 
 	@Test
 	public void testCreateOrphanedBranch() throws Exception {

--
Gitblit v1.9.1