James Moger
2012-02-02 90b8d7e0e1b5e5ed296c1213168b9a8937ac66fd
Refactored and unit tested updating HEAD feature
8 files modified
117 ■■■■■ changed files
src/com/gitblit/GitBlit.java 15 ●●●● patch | view | raw | blame | history
src/com/gitblit/client/EditRepositoryDialog.java 21 ●●●● patch | view | raw | blame | history
src/com/gitblit/models/RepositoryModel.java 4 ●●●● patch | view | raw | blame | history
src/com/gitblit/utils/JGitUtils.java 42 ●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/GitBlitWebApp.properties 3 ●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/EditRepositoryPage.html 2 ●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/EditRepositoryPage.java 8 ●●●● patch | view | raw | blame | history
tests/com/gitblit/tests/JGitUtilsTest.java 22 ●●●●● patch | view | raw | blame | history
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,16 +984,15 @@
        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);
                        repository.name, currentRef, repository.HEAD));
                if (JGitUtils.setHEADtoRef(r, repository.HEAD)) {
                // clear the cache
                clearRepositoryCache(repository.name);
            }
            }
            // close the repository object
            r.close();
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();
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;
    
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) {
        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) {
        for (RefModel tagModel : JGitUtils.getTags(repository, true, -1)) {
                targets.add(tagModel.getName());
            }
        }
        return targets;
    }
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
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>
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.
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 {