Revised incremental push tags feature
| | |
| | | - 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)
|
| | |
| | |
|
| | | dependencyChanges:
|
| | | - JGit 2.3.1.201302201838-r
|
| | | |
| | | settings:
|
| | | - { name: 'git.defaultIncrementalPushTagPrefix', defaultValue: 'r' }
|
| | | }
|
| | |
|
| | | #
|
| | |
| | | # 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!
|
| | |
| | | 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)));
|
| | |
| | | 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());
|
| | |
| | | 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;
|
| | |
| | | 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;
|
| | |
| | | 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;
|
| | |
| | | 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);
|
| | | }
|
| | | }
|
| | | }
|
| | |
| | | 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;
|
| | |
| | |
|
| | | private JCheckBox useDocs;
|
| | |
|
| | | private JCheckBox useIncrementalRevisionNumbers;
|
| | | private JCheckBox useIncrementalPushTags;
|
| | |
|
| | | private JCheckBox showRemoteBranches;
|
| | |
|
| | |
| | | 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);
|
| | |
| | | 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"),
|
| | |
| | | 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();
|
| | |
| | | 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;
|
| | |
| | | clone.showRemoteBranches = false;
|
| | | clone.allowForks = false;
|
| | | clone.useDocs = useDocs;
|
| | | clone.useIncrementalRevisionNumbers = useIncrementalRevisionNumbers;
|
| | | clone.useTickets = useTickets;
|
| | | clone.skipSizeCalculation = skipSizeCalculation;
|
| | | clone.skipSummaryMetrics = skipSummaryMetrics;
|
| | |
| | | package com.gitblit.utils;
|
| | |
|
| | | import java.io.ByteArrayOutputStream;
|
| | | import java.text.MessageFormat;
|
| | | import java.util.ArrayList;
|
| | | import java.util.List;
|
| | |
|
| | |
| | | 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;
|
| | | }
|
| | |
| | | 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;
|
| | |
| | | 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;
|
| | |
| | | */
|
| | | public class JGitUtils {
|
| | |
|
| | | private static final String REVISION_TAG_PREFIX = "rev_";
|
| | | static final Logger LOGGER = LoggerFactory.getLogger(JGitUtils.class);
|
| | |
|
| | | /**
|
| | |
| | |
|
| | | /**
|
| | | * 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);
|
| | |
| | | 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;
|
| | | }
|
| | |
| | | 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
|
| | |
| | | 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
|
| | |
| | | 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 |
| | |
| | | <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <span class="help-inline"><wicket:message key="gb.skipSizeCalculationDescription"></wicket:message></span></label></td></tr>
|
| | |
| | | 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"));
|
| | |
| | | enableTickets("ticgit.git");
|
| | | enableDocs("ticgit.git");
|
| | | showRemoteBranches("ticgit.git");
|
| | | automaticallyTagBranchTips("ticgit.git");
|
| | | showRemoteBranches("test/jgit.git");
|
| | | automaticallyTagBranchTips("test/jgit.git"); |
| | | }
|
| | | }
|
| | |
|
| | |
| | | }
|
| | | }
|
| | |
|
| | | 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());
|
| | |
| | | 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);
|
| | | }
|
| | |
|
| | |
| | | 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"));
|
| | |
| | | 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);
|
| | | }
|
| | |
|
| | |
| | | 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"));
|