James Moger
2013-04-01 0f47b2f605ed4119a6042b72d3499b223f40ec90
Revised incremental push tags feature
13 files modified
193 ■■■■■ changed files
releases.moxie 8 ●●●● patch | view | raw | blame | history
src/main/distrib/data/gitblit.properties 11 ●●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/GitBlit.java 11 ●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/GitServlet.java 58 ●●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/client/EditRepositoryDialog.java 10 ●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/models/RepositoryModel.java 4 ●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/utils/DiffUtils.java 3 ●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/utils/JGitUtils.java 59 ●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/wicket/GitBlitWebApp.properties 5 ●●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html 2 ●●● patch | view | raw | blame | history
src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java 2 ●●● patch | view | raw | blame | history
src/test/java/com/gitblit/tests/GitBlitSuite.java 12 ●●●●● patch | view | raw | blame | history
src/test/java/com/gitblit/tests/GitServletTest.java 8 ●●●● patch | view | raw | blame | history
releases.moxie
@@ -24,12 +24,13 @@
     - Use standard ServletRequestWrapper instead of custom wrapper (issue 224)
    additions: 
     - Support --baseFolder parameter in Federation Client
     - Option to automatically tag branch tips on each push with an incremental revision number
     - Implemented multiple repository owners
     - Optional periodic LDAP user and team pre-fetching & synchronization
     - Display name and version in Tomcat Manager
     - FogBugz post-receive hook script
     - Implemented multiple repository owners
     - Chinese translation
     - Support --baseFolder parameter in Federation Client
     - Added weblogic.xml to WAR for deployment on WebLogic (issue 199)
     - Support username substitution in web.otherUrls (issue 213)
     - Option to force client-side basic authentication instead of form-based authentication if web.authenticateViewPages=true (issue 222)
@@ -59,6 +60,9 @@
    
    dependencyChanges:
    - JGit 2.3.1.201302201838-r
    settings:
    - { name: 'git.defaultIncrementalPushTagPrefix', defaultValue: 'r' }
}
#
src/main/distrib/data/gitblit.properties
@@ -146,6 +146,17 @@
# SINCE 1.1.0
git.defaultAuthorizationControl = NAMED
# The default incremental push tag prefix.  Tag prefix applied to a repository
# that has automatic push tags enabled and does not specify a custom tag prefix.
#
# If incremental push tags are enabled, the tips of each branch in the push will
# be tagged with an increasing revision integer.
#
# e.g. refs/tags/r2345 or refs/tags/rev_2345
#
# SINCE 1.3.0
git.defaultIncrementalPushTagPrefix = r
# Enable JGit-based garbage collection. (!!EXPERIMENTAL!!)
#
# USE AT YOUR OWN RISK!
src/main/java/com/gitblit/GitBlit.java
@@ -1676,7 +1676,8 @@
            model.addOwners(ArrayUtils.fromString(getConfig(config, "owner", "")));
            model.useTickets = getConfig(config, "useTickets", false);
            model.useDocs = getConfig(config, "useDocs", false);
            model.useIncrementalRevisionNumbers = getConfig(config, "useIncrementalRevisionNumbers", false);
            model.useIncrementalPushTags = getConfig(config, "useIncrementalPushTags", false);
            model.incrementalPushTagPrefix = getConfig(config, "incrementalPushTagPrefix", null);
            model.allowForks = getConfig(config, "allowForks", true);
            model.accessRestriction = AccessRestrictionType.fromName(getConfig(config,
                    "accessRestriction", settings.getString(Keys.git.defaultAccessRestriction, null)));
@@ -2198,7 +2199,13 @@
        config.setString(Constants.CONFIG_GITBLIT, null, "owner", ArrayUtils.toString(repository.owners));
        config.setBoolean(Constants.CONFIG_GITBLIT, null, "useTickets", repository.useTickets);
        config.setBoolean(Constants.CONFIG_GITBLIT, null, "useDocs", repository.useDocs);
        config.setBoolean(Constants.CONFIG_GITBLIT, null, "useIncrementalRevisionNumbers", repository.useIncrementalRevisionNumbers);
        config.setBoolean(Constants.CONFIG_GITBLIT, null, "useIncrementalPushTags", repository.useIncrementalPushTags);
        if (StringUtils.isEmpty(repository.incrementalPushTagPrefix) ||
                repository.incrementalPushTagPrefix.equals(settings.getString(Keys.git.defaultIncrementalPushTagPrefix, "r"))) {
            config.unset(Constants.CONFIG_GITBLIT, null, "incrementalPushTagPrefix");
        } else {
            config.setString(Constants.CONFIG_GITBLIT, null, "incrementalPushTagPrefix", repository.incrementalPushTagPrefix);
        }
        config.setBoolean(Constants.CONFIG_GITBLIT, null, "allowForks", repository.allowForks);
        config.setString(Constants.CONFIG_GITBLIT, null, "accessRestriction", repository.accessRestriction.name());
        config.setString(Constants.CONFIG_GITBLIT, null, "authorizationControl", repository.authorizationControl.name());
src/main/java/com/gitblit/GitServlet.java
@@ -23,7 +23,6 @@
import java.text.MessageFormat;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
@@ -33,9 +32,7 @@
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Part;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.http.server.resolver.DefaultReceivePackFactory;
import org.eclipse.jgit.http.server.resolver.DefaultUploadPackFactory;
import org.eclipse.jgit.lib.PersonIdent;
@@ -55,6 +52,7 @@
import org.slf4j.LoggerFactory;
import com.gitblit.Constants.AccessRestrictionType;
import com.gitblit.client.Translation;
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.UserModel;
import com.gitblit.utils.ClientLogger;
@@ -297,26 +295,41 @@
                return;
            }
            UserModel user = getUserModel(rp);
            UserModel user = getUserModel(rp);
            RepositoryModel repository = GitBlit.self().getRepositoryModel(repositoryName);
            
            if (repository.useIncrementalRevisionNumbers) {
                List<ReceiveCommand> allCommands = rp.getAllCommands();
                String cmds = "";
                for (ReceiveCommand receiveCommand : allCommands) {
                    cmds += receiveCommand.getType() + "_"
                            + receiveCommand.getResult() + "_"
                            + receiveCommand.getMessage() + ", ";
                    if (receiveCommand.getType().equals(
                            ReceiveCommand.Type.UPDATE)
                            && receiveCommand.getResult().equals(
                                    ReceiveCommand.Result.OK)) {
                        // if type=update and update was ok, autotag
                        String objectId = receiveCommand.getNewId().toString()
                                .replace("AnyObjectId[", "").replace("]", "");
                        boolean result = JGitUtils
                                .createIncrementalRevisionTag(
                                        rp.getRepository(), objectId);
            if (repository.useIncrementalPushTags) {
                // tag each pushed branch tip
                String emailAddress = user.emailAddress == null ? rp.getRefLogIdent().getEmailAddress() : user.emailAddress;
                PersonIdent userIdent = new PersonIdent(user.getDisplayName(), emailAddress);
                for (ReceiveCommand cmd : commands) {
                    if (!cmd.getRefName().startsWith("refs/heads/")) {
                        // only tag branch ref changes
                        continue;
                    }
                    if (!ReceiveCommand.Type.DELETE.equals(cmd.getType())
                            && ReceiveCommand.Result.OK.equals(cmd.getResult())) {
                        String objectId = cmd.getNewId().getName();
                        String branch = cmd.getRefName().substring("refs/heads/".length());
                        // get translation based on the server's locale setting
                        String template = Translation.get("gb.incrementalPushTagMessage");
                        String msg = MessageFormat.format(template, branch);
                        String prefix;
                        if (StringUtils.isEmpty(repository.incrementalPushTagPrefix)) {
                            prefix = GitBlit.getString(Keys.git.defaultIncrementalPushTagPrefix, "r");
                        } else {
                            prefix = repository.incrementalPushTagPrefix;
                        }
                        JGitUtils.createIncrementalRevisionTag(
                                    rp.getRepository(),
                                    objectId,
                                    userIdent,
                                    prefix,
                                    "0",
                                    msg);
                    }
                }                
            }
@@ -332,6 +345,9 @@
                    case CREATE:
                        logger.info(MessageFormat.format("{0} CREATED {1} in {2}", user.username, cmd.getRefName(), repository.name));
                        break;
                    case UPDATE:
                        logger.info(MessageFormat.format("{0} UPDATED {1} in {2} (from {3} to {4})", user.username, cmd.getRefName(), repository.name, cmd.getOldId().name(), cmd.getNewId().name()));
                        break;
                    case UPDATE_NONFASTFORWARD:
                        logger.info(MessageFormat.format("{0} UPDATED NON-FAST-FORWARD {1} in {2} (from {3} to {4})", user.username, cmd.getRefName(), repository.name, cmd.getOldId().name(), cmd.getNewId().name()));
                        break;
src/main/java/com/gitblit/client/EditRepositoryDialog.java
@@ -92,7 +92,7 @@
    private JCheckBox useDocs;
    private JCheckBox useIncrementalRevisionNumbers;
    private JCheckBox useIncrementalPushTags;
    
    private JCheckBox showRemoteBranches;
@@ -214,8 +214,8 @@
                anRepository.useTickets);
        useDocs = new JCheckBox(Translation.get("gb.useDocsDescription"),
                anRepository.useDocs);
        useIncrementalRevisionNumbers = new JCheckBox(Translation.get("gb.useIncrementalRevisionNumbersDescription"),
                anRepository.useIncrementalRevisionNumbers);
        useIncrementalPushTags = new JCheckBox(Translation.get("gb.useIncrementalPushTagsDescription"),
                anRepository.useIncrementalPushTags);
        showRemoteBranches = new JCheckBox(
                Translation.get("gb.showRemoteBranchesDescription"),
                anRepository.showRemoteBranches);
@@ -314,7 +314,7 @@
        fieldsPanel
                .add(newFieldPanel(Translation.get("gb.enableDocs"), useDocs));
        fieldsPanel
        .add(newFieldPanel(Translation.get("gb.enableIncrementalRevisionNumbers"), useIncrementalRevisionNumbers));
        .add(newFieldPanel(Translation.get("gb.enableIncrementalPushTags"), useIncrementalPushTags));
        fieldsPanel.add(newFieldPanel(Translation.get("gb.showRemoteBranches"),
                showRemoteBranches));
        fieldsPanel.add(newFieldPanel(Translation.get("gb.showReadme"),
@@ -569,7 +569,7 @@
        repository.gcThreshold = gcThreshold.getText();
        repository.useTickets = useTickets.isSelected();
        repository.useDocs = useDocs.isSelected();
        repository.useIncrementalRevisionNumbers = useIncrementalRevisionNumbers.isSelected();
        repository.useIncrementalPushTags = useIncrementalPushTags.isSelected();
        repository.showRemoteBranches = showRemoteBranches.isSelected();
        repository.showReadme = showReadme.isSelected();
        repository.skipSizeCalculation = skipSizeCalculation.isSelected();
src/main/java/com/gitblit/models/RepositoryModel.java
@@ -50,7 +50,8 @@
    public boolean showRemoteBranches;
    public boolean useTickets;
    public boolean useDocs;
    public boolean useIncrementalRevisionNumbers;
    public boolean useIncrementalPushTags;
    public String incrementalPushTagPrefix;
    public AccessRestrictionType accessRestriction;
    public AuthorizationControl authorizationControl;
    public boolean allowAuthenticated;
@@ -202,7 +203,6 @@
        clone.showRemoteBranches = false;
        clone.allowForks = false;
        clone.useDocs = useDocs;
        clone.useIncrementalRevisionNumbers = useIncrementalRevisionNumbers;
        clone.useTickets = useTickets;
        clone.skipSizeCalculation = skipSizeCalculation;
        clone.skipSummaryMetrics = skipSummaryMetrics;
src/main/java/com/gitblit/utils/DiffUtils.java
@@ -16,6 +16,7 @@
package com.gitblit.utils;
import java.io.ByteArrayOutputStream;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
@@ -274,7 +275,7 @@
                lines.add(line);
            }
        } catch (Throwable t) {
            LOGGER.error("failed to generate blame!", t);
            LOGGER.error(MessageFormat.format("failed to generate blame for {0} {1}!", blobPath, objectId), t);
        }
        return lines;
    }
src/main/java/com/gitblit/utils/JGitUtils.java
@@ -19,6 +19,7 @@
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
@@ -82,8 +83,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.gitblit.GitBlit;
import com.gitblit.Keys;
import com.gitblit.models.GitNote;
import com.gitblit.models.PathModel;
import com.gitblit.models.PathModel.PathChangeModel;
@@ -98,7 +97,6 @@
 */
public class JGitUtils {
    private static final String REVISION_TAG_PREFIX = "rev_";
    static final Logger LOGGER = LoggerFactory.getLogger(JGitUtils.class);
    /**
@@ -1692,59 +1690,58 @@
        }
        return list;
    }
    /**
     * this method creates an incremental revision number as a tag according to
     * the amount of already existing tags, which start with a defined prefix {@link REVISION_TAG_PREFIX}
     * the amount of already existing tags, which start with a defined prefix.
     * 
     * @param repository
     * @param objectId
     * @param tagger
     * @param prefix
     * @param intPattern
     * @param message
     * @return true if operation was successful, otherwise false
     */
    public static boolean createIncrementalRevisionTag(Repository repository, String objectId) {
    public static boolean createIncrementalRevisionTag(Repository repository,
            String objectId, PersonIdent tagger, String prefix, String intPattern, String message) {
        boolean result = false;
        Iterator<Entry<String, Ref>> iterator = repository.getTags().entrySet().iterator();
        long revisionNumber = 1;
        long lastRev = 0;
        while (iterator.hasNext()) {
            Entry<String, Ref> entry = iterator.next();
            if (entry.getKey().startsWith(REVISION_TAG_PREFIX)) {
                revisionNumber++;
            if (entry.getKey().startsWith(prefix)) {
                try {
                    long val = Long.parseLong(entry.getKey().substring(prefix.length()));
                    if (val > lastRev) {
                        lastRev = val;
                    }
                } catch (Exception e) {
                    // this tag is NOT an incremental revision tag
                }
            }
        }
        result = createTag(repository,REVISION_TAG_PREFIX+revisionNumber,objectId);
        DecimalFormat df = new DecimalFormat(intPattern);
        result = createTag(repository, objectId, tagger, prefix + df.format((lastRev + 1)), message);
        return result;
    }
    /**
     * creates a tag in a repository referring to the current head
     *
     * @param repository
     * @param tag, the string label
     * @return boolean, true if operation was successful, otherwise false
     */
    public static boolean createTag(Repository repository, String tag) {
        return createTag(repository, tag, null);
    }
    /**
     * creates a tag in a repository
     * 
     * @param repository
     * @param tag, the string label
     * @param objectId, the ref the tag points towards
     * @param tagger, the person tagging the object
     * @param tag, the string label
     * @param message, the string message
     * @return boolean, true if operation was successful, otherwise false
     */
    public static boolean createTag(Repository repository, String tag,
            String objectId) {
    public static boolean createTag(Repository repository, String objectId, PersonIdent tagger, String tag, String message) {
        try {            
            PersonIdent author = new PersonIdent("GitblitAutoTagPush",
                    "gitblit@localhost");
            LOGGER.debug("createTag in repo: "+repository.getDirectory().getAbsolutePath());
            Git gitClient = Git.open(repository.getDirectory());
            TagCommand tagCommand = gitClient.tag();
            tagCommand.setTagger(author);
            tagCommand.setMessage("autotag");
            tagCommand.setTagger(tagger);
            tagCommand.setMessage(message);
            if (objectId != null) {
                RevObject revObj = getCommit(repository, objectId);
                tagCommand.setObjectId(revObj);
@@ -1753,7 +1750,7 @@
            Ref call = tagCommand.call();            
            return call != null ? true : false;
        } catch (Exception e) {
            e.printStackTrace();
            error(e, repository, "Failed to create tag {1} in repository {0}", objectId, tag);
        }
        return false;
    }
src/main/java/com/gitblit/wicket/GitBlitWebApp.properties
@@ -73,7 +73,6 @@
gb.name = name
gb.enableTickets = enable tickets
gb.enableDocs = enable docs
gb.enableIncrementalRevisionNumbers = enable incremental revision numbers
gb.save = save
gb.showRemoteBranches = show remote branches
gb.editUsers = edit users
@@ -86,7 +85,6 @@
gb.viewRestricted = authenticated view, clone, & push
gb.useTicketsDescription = readonly, distributed Ticgit issues
gb.useDocsDescription = enumerates Markdown documentation in repository
gb.useIncrementalRevisionNumbersDescription = automatic tagging of each push with an incremental revision number
gb.showRemoteBranchesDescription = show remote branches
gb.canAdminDescription = can administer Gitblit server
gb.permittedUsers = permitted users
@@ -448,3 +446,6 @@
gb.sessionEnded = Session has been closed
gb.closeBrowser = Please close the browser to properly end the session.
gb.doesNotExistInTree = {0} does not exist in tree {1}
gb.enableIncrementalPushTags = enable incremental push tags
gb.useIncrementalPushTagsDescription = on push, automatically tag each branch tip with an incremental revision number
gb.incrementalPushTagMessage = Auto-tagged [{0}] branch on push
src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html
@@ -35,7 +35,7 @@
                <tr><th colspan="2"><hr/></th></tr>
                <tr><th><wicket:message key="gb.enableTickets"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="useTickets" tabindex="7" /> &nbsp;<span class="help-inline"><wicket:message key="gb.useTicketsDescription"></wicket:message></span></label></td></tr>
                <tr><th><wicket:message key="gb.enableDocs"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="useDocs" tabindex="8" /> &nbsp;<span class="help-inline"><wicket:message key="gb.useDocsDescription"></wicket:message></span></label></td></tr>
                <tr><th><wicket:message key="gb.enableIncrementalRevisionNumbers"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="useIncrementalRevisionNumbers" tabindex="8" /> &nbsp;<span class="help-inline"><wicket:message key="gb.useIncrementalRevisionNumbersDescription"></wicket:message></span></label></td></tr>
                <tr><th><wicket:message key="gb.enableIncrementalPushTags"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="useIncrementalPushTags" tabindex="8" /> &nbsp;<span class="help-inline"><wicket:message key="gb.useIncrementalPushTagsDescription"></wicket:message></span></label></td></tr>
                <tr><th><wicket:message key="gb.showRemoteBranches"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="showRemoteBranches" tabindex="9" /> &nbsp;<span class="help-inline"><wicket:message key="gb.showRemoteBranchesDescription"></wicket:message></span></label></td></tr>
                <tr><th><wicket:message key="gb.showReadme"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="showReadme" tabindex="10" /> &nbsp;<span class="help-inline"><wicket:message key="gb.showReadmeDescription"></wicket:message></span></label></td></tr>
                <tr><th><wicket:message key="gb.skipSizeCalculation"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="skipSizeCalculation" tabindex="11" /> &nbsp;<span class="help-inline"><wicket:message key="gb.skipSizeCalculationDescription"></wicket:message></span></label></td></tr>
src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java
@@ -422,7 +422,7 @@
                new FederationTypeRenderer()));
        form.add(new CheckBox("useTickets"));
        form.add(new CheckBox("useDocs"));
        form.add(new CheckBox("useIncrementalRevisionNumbers"));
        form.add(new CheckBox("useIncrementalPushTags"));
        form.add(new CheckBox("showRemoteBranches"));
        form.add(new CheckBox("showReadme"));
        form.add(new CheckBox("skipSizeCalculation"));
src/test/java/com/gitblit/tests/GitBlitSuite.java
@@ -153,7 +153,9 @@
            enableTickets("ticgit.git");
            enableDocs("ticgit.git");
            showRemoteBranches("ticgit.git");
            automaticallyTagBranchTips("ticgit.git");
            showRemoteBranches("test/jgit.git");
            automaticallyTagBranchTips("test/jgit.git");
        }
    }
@@ -198,6 +200,16 @@
        }
    }
    
    private static void automaticallyTagBranchTips(String repositoryName) {
        try {
            RepositoryModel model = GitBlit.self().getRepositoryModel(repositoryName);
            model.useIncrementalPushTags = true;
            GitBlit.self().updateRepositoryModel(model.name, model, false);
        } catch (GitBlitException g) {
            g.printStackTrace();
        }
    }
    public static void close(File repository) {
        try {
            File gitDir = FileKey.resolve(repository, FS.detect());
src/test/java/com/gitblit/tests/GitServletTest.java
@@ -248,7 +248,7 @@
        w.close();
        git.add().addFilepattern(file.getName()).call();
        git.commit().setMessage("test commit").call();
        git.push().setPushAll().call();
        git.push().setPushAll().setCredentialsProvider(new UsernamePasswordCredentialsProvider(account, password)).call();
        GitBlitSuite.close(git);
    }
    
@@ -283,7 +283,7 @@
        git.commit().setMessage("test commit").call();
        
        try {
            git.push().setPushAll().call();
            git.push().setPushAll().setCredentialsProvider(new UsernamePasswordCredentialsProvider(account, password)).call();
            assertTrue(false);
        } catch (Exception e) {
            assertTrue(e.getCause().getMessage().contains("access forbidden"));
@@ -293,7 +293,7 @@
        model.isFrozen = false;
        GitBlit.self().updateRepositoryModel(model.name, model, false);
        git.push().setPushAll().call();
        git.push().setPushAll().setCredentialsProvider(new UsernamePasswordCredentialsProvider(account, password)).call();
        GitBlitSuite.close(git);
    }
    
@@ -317,7 +317,7 @@
        git.add().addFilepattern(file.getName()).call();
        git.commit().setMessage("test commit followed by push to non-bare repository").call();
        try {
            git.push().setPushAll().call();
            git.push().setPushAll().setCredentialsProvider(new UsernamePasswordCredentialsProvider(account, password)).call();
            assertTrue(false);
        } catch (Exception e) {
            assertTrue(e.getCause().getMessage().contains("git-receive-pack not permitted"));