Unit testing. Documentation. Simplified settings classes.
| | |
| | | - Repository Owners may edit repositories through the web UI
|
| | | - Automatically generates a self-signed certificate for https communications
|
| | | - Git-notes support
|
| | | - Branch metrics
|
| | | - Branch metrics (uses Google Charts)
|
| | | - Blame annotations view
|
| | | - Dates can optionally be displayed using the browser's reported timezone
|
| | | - Author and Committer email address display can be controlled
|
| | | - Search commit messages, authors, and committers
|
| | | - Display of Author and Committer email addresses can be disabled
|
| | | - Case-insensitive searching of commit messages, authors, or committers
|
| | | - Dynamic zip downloads feature
|
| | | - Markdown view support
|
| | | - Syntax highlighting
|
| | | - Customizable regular expression handling for commit messages
|
| | | - Markdown file view support
|
| | | - Syntax highlighting for popular source code types
|
| | | - Customizable regular expression substitution for commit messages (i.e. bug or code review link integration)
|
| | | - Single text file for server configuration
|
| | | - Single text file for users configuration
|
| | | - Simple repository stats and activity graph (uses Google Charts)
|
| | | - Optional utility pages
|
| | | <ul class='noBullets'>
|
| | | <li> Docs page which enumerates all Markdown files within a repository</li>
|
| | |
| | | </ul>
|
| | |
|
| | | ### Limitations
|
| | | - [%JGIT%][jgit] does not [garbage collect or repack](http://www.kernel.org/pub/software/scm/git/docs/git-gc.html)
|
| | | - [%JGIT%][jgit] does not currently [garbage collect or repack](http://www.kernel.org/pub/software/scm/git/docs/git-gc.html)
|
| | | - HTTP/HTTPS are the only supported protocols
|
| | | - Access controls are not path-based, they are repository-based
|
| | | - Only Administrators can create, rename or delete repositories
|
| | | - Gitblit is an integrated, full-stack solution. There is no WAR build at this time.
|
| | |
|
| | | ### Caveats
|
| | | - I don't know everything there is to know about [Git][git] nor [JGit][jgit].
|
| | | - Gitblit may eat your data. Use at your own risk.
|
| | | - Gitblit may have security holes. Patches welcome. :)
|
| | |
|
| | | ### Todo List
|
| | | - Code documentation
|
| | | - Unit testing
|
| | | - Finish Blame (waiting for JGit 1.0.0 release)
|
| | | - Clone remote repository
|
| | | - Update Build.java to JGit 1.0.0, when its released
|
| | |
|
| | | ### Idea List
|
| | | - Consider clone remote repository feature
|
| | | - Consider [Apache Shiro](http://shiro.apache.org) for authentication
|
| | | - Stronger Ticgit read-only integration
|
| | | - activity/timeline
|
| | |
| | |
|
| | | ## Architecture
|
| | |
|
| | | 
|
| | | 
|
| | |
|
| | | ### Bundled Dependencies
|
| | | The following dependencies are bundled with the Gitblit zip distribution file.
|
| | |
| | | ### Other Build Dependencies
|
| | | - [Fancybox image viewer](http://fancybox.net) (MIT and GPL dual-licensed)
|
| | | - [JUnit](http://junit.org) (Common Public License)
|
| | | - [commons-net](http://commons.apache.org/net) (Apache 2.0)
|
| | |
|
| | | ## Building from Source
|
| | | [Eclipse](http://eclipse.org) is recommended for development as the project settings are preconfigured.
|
| | |
| | | import java.io.File;
|
| | | import java.io.FileInputStream;
|
| | | import java.io.FileNotFoundException;
|
| | | import java.util.ArrayList;
|
| | | import java.util.List;
|
| | | import java.util.Properties;
|
| | | import java.util.regex.PatternSyntaxException;
|
| | |
|
| | | import org.slf4j.Logger;
|
| | | import org.slf4j.LoggerFactory;
|
| | |
|
| | | /**
|
| | | * Reads GitBlit settings file.
|
| | | *
|
| | | */
|
| | | public class FileSettings implements IStoredSettings {
|
| | |
|
| | | private final Logger logger = LoggerFactory.getLogger(FileSettings.class);
|
| | | public class FileSettings extends IStoredSettings {
|
| | |
|
| | | private final File propertiesFile;
|
| | |
|
| | | private Properties properties = new Properties();
|
| | | private final Properties properties = new Properties();
|
| | |
|
| | | private long lastread;
|
| | | private volatile long lastread;
|
| | |
|
| | | public FileSettings(String file) {
|
| | | super(FileSettings.class);
|
| | | this.propertiesFile = new File(file);
|
| | | }
|
| | |
|
| | | @Override
|
| | | public List<String> getAllKeys(String startingWith) {
|
| | | startingWith = startingWith.toLowerCase();
|
| | | List<String> keys = new ArrayList<String>();
|
| | | Properties props = read();
|
| | | for (Object o : props.keySet()) {
|
| | | String key = o.toString().toLowerCase();
|
| | | if (key.startsWith(startingWith)) {
|
| | | keys.add(key);
|
| | | }
|
| | | }
|
| | | return keys;
|
| | | }
|
| | |
|
| | | @Override
|
| | | public boolean getBoolean(String name, boolean defaultValue) {
|
| | | Properties props = read();
|
| | | if (props.containsKey(name)) {
|
| | | try {
|
| | | String value = props.getProperty(name);
|
| | | if (value != null && value.trim().length() > 0) {
|
| | | return Boolean.parseBoolean(value);
|
| | | }
|
| | | } catch (Exception e) {
|
| | | logger.warn("No override setting for " + name + " using default of " + defaultValue);
|
| | | }
|
| | | }
|
| | | return defaultValue;
|
| | | }
|
| | |
|
| | | @Override
|
| | | public int getInteger(String name, int defaultValue) {
|
| | | Properties props = read();
|
| | | if (props.containsKey(name)) {
|
| | | try {
|
| | | String value = props.getProperty(name);
|
| | | if (value != null && value.trim().length() > 0) {
|
| | | return Integer.parseInt(value);
|
| | | }
|
| | | } catch (Exception e) {
|
| | | logger.warn("No override setting for " + name + " using default of " + defaultValue);
|
| | | }
|
| | | }
|
| | | return defaultValue;
|
| | | }
|
| | |
|
| | | @Override
|
| | | public String getString(String name, String defaultValue) {
|
| | | Properties props = read();
|
| | | if (props.containsKey(name)) {
|
| | | try {
|
| | | String value = props.getProperty(name);
|
| | | if (value != null) {
|
| | | return value;
|
| | | }
|
| | | } catch (Exception e) {
|
| | | logger.warn("No override setting for " + name + " using default of " + defaultValue);
|
| | | }
|
| | | }
|
| | | return defaultValue;
|
| | | }
|
| | |
|
| | | @Override
|
| | | public List<String> getStrings(String name) {
|
| | | return getStrings(name, " ");
|
| | | }
|
| | |
|
| | | @Override
|
| | | public List<String> getStringsFromValue(String value) {
|
| | | return getStringsFromValue(value, " ");
|
| | | }
|
| | |
|
| | | @Override
|
| | | public List<String> getStrings(String name, String separator) {
|
| | | List<String> strings = new ArrayList<String>();
|
| | | Properties props = read();
|
| | | if (props.containsKey(name)) {
|
| | | String value = props.getProperty(name);
|
| | | strings = getStringsFromValue(value, separator);
|
| | | }
|
| | | return strings;
|
| | | }
|
| | |
|
| | | @Override
|
| | | public List<String> getStringsFromValue(String value, String separator) {
|
| | | List<String> strings = new ArrayList<String>();
|
| | | try {
|
| | | String[] chunks = value.split(separator);
|
| | | for (String chunk : chunks) {
|
| | | chunk = chunk.trim();
|
| | | if (chunk.length() > 0) {
|
| | | strings.add(chunk);
|
| | | }
|
| | | }
|
| | | } catch (PatternSyntaxException e) {
|
| | | logger.error("Failed to parse " + value, e);
|
| | | }
|
| | | return strings;
|
| | | }
|
| | |
|
| | | private synchronized Properties read() {
|
| | | protected synchronized Properties read() {
|
| | | if (propertiesFile.exists() && (propertiesFile.lastModified() > lastread)) {
|
| | | FileInputStream is = null;
|
| | | try {
|
| | | properties = new Properties();
|
| | | Properties props = new Properties();
|
| | | is = new FileInputStream(propertiesFile);
|
| | | properties.load(is);
|
| | | props.load(is);
|
| | | |
| | | // load properties after we have successfully read file
|
| | | properties.clear();
|
| | | properties.putAll(props);
|
| | | lastread = propertiesFile.lastModified();
|
| | | } catch (FileNotFoundException f) {
|
| | | // IGNORE - won't happen because file.exists() check above
|
| | | } catch (Throwable t) {
|
| | | t.printStackTrace();
|
| | | logger.error("Failed to read " + propertiesFile.getName(), t);
|
| | | } finally {
|
| | | if (is != null) {
|
| | | try {
|
| | |
| | | return false;
|
| | | }
|
| | |
|
| | | public boolean renameRepository(RepositoryModel model, String newName) {
|
| | | File folder = new File(repositoriesFolder, model.name);
|
| | | if (folder.exists() && folder.isDirectory()) {
|
| | | File newFolder = new File(repositoriesFolder, newName);
|
| | | if (folder.renameTo(newFolder)) {
|
| | | return loginService.renameRole(model.name, newName);
|
| | | }
|
| | | }
|
| | | return false;
|
| | | }
|
| | |
|
| | | public void configureContext(IStoredSettings settings) {
|
| | | logger.info("Reading configuration from " + settings.toString());
|
| | | this.storedSettings = settings;
|
| | |
| | | @Override
|
| | | public void contextInitialized(ServletContextEvent contextEvent) {
|
| | | if (storedSettings == null) {
|
| | | // for running gitblit as a traditional webapp in a servlet container
|
| | | WebXmlSettings webxmlSettings = new WebXmlSettings(contextEvent.getServletContext());
|
| | | configureContext(webxmlSettings);
|
| | | }
|
| | |
| | |
|
| | | @Override
|
| | | public void contextDestroyed(ServletContextEvent contextEvent) {
|
| | | logger.info("GitBlit context destroyed by servlet container.");
|
| | | logger.info("Gitblit context destroyed by servlet container.");
|
| | | }
|
| | | }
|
| | |
| | | */
|
| | | package com.gitblit;
|
| | |
|
| | | import java.util.ArrayList;
|
| | | import java.util.List;
|
| | | import java.util.Properties;
|
| | |
|
| | | public interface IStoredSettings {
|
| | | import org.slf4j.Logger;
|
| | | import org.slf4j.LoggerFactory;
|
| | |
|
| | | List<String> getAllKeys(String startingWith);
|
| | | import com.gitblit.utils.StringUtils;
|
| | |
|
| | | boolean getBoolean(String name, boolean defaultValue);
|
| | | public abstract class IStoredSettings {
|
| | |
|
| | | int getInteger(String name, int defaultValue);
|
| | | protected final Logger logger;
|
| | | |
| | | public IStoredSettings(Class<? extends IStoredSettings> clazz) {
|
| | | logger = LoggerFactory.getLogger(clazz);
|
| | | }
|
| | | |
| | | protected abstract Properties read();
|
| | |
|
| | | String getString(String name, String defaultValue);
|
| | | public List<String> getAllKeys(String startingWith) {
|
| | | startingWith = startingWith.toLowerCase();
|
| | | List<String> keys = new ArrayList<String>();
|
| | | Properties props = read();
|
| | | for (Object o : props.keySet()) {
|
| | | String key = o.toString();
|
| | | if (key.toLowerCase().startsWith(startingWith)) {
|
| | | keys.add(key);
|
| | | }
|
| | | }
|
| | | return keys;
|
| | | }
|
| | |
|
| | | List<String> getStrings(String name);
|
| | | public boolean getBoolean(String name, boolean defaultValue) {
|
| | | Properties props = read();
|
| | | if (props.containsKey(name)) {
|
| | | String value = props.getProperty(name);
|
| | | if (!StringUtils.isEmpty(value)) {
|
| | | return Boolean.parseBoolean(value);
|
| | | }
|
| | | }
|
| | | return defaultValue;
|
| | | }
|
| | |
|
| | | List<String> getStringsFromValue(String value);
|
| | | public int getInteger(String name, int defaultValue) {
|
| | | Properties props = read();
|
| | | if (props.containsKey(name)) {
|
| | | try {
|
| | | String value = props.getProperty(name);
|
| | | if (!StringUtils.isEmpty(value)) {
|
| | | return Integer.parseInt(value);
|
| | | }
|
| | | } catch (NumberFormatException e) {
|
| | | logger.warn("Failed to parse integer for " + name + " using default of "
|
| | | + defaultValue);
|
| | | }
|
| | | }
|
| | | return defaultValue;
|
| | | }
|
| | |
|
| | | List<String> getStrings(String name, String separator);
|
| | | public String getString(String name, String defaultValue) {
|
| | | Properties props = read();
|
| | | if (props.containsKey(name)) {
|
| | | String value = props.getProperty(name);
|
| | | if (value != null) {
|
| | | return value;
|
| | | }
|
| | | }
|
| | | return defaultValue;
|
| | | }
|
| | |
|
| | | List<String> getStringsFromValue(String value, String separator);
|
| | | public List<String> getStrings(String name) {
|
| | | return getStrings(name, " ");
|
| | | }
|
| | |
|
| | | public List<String> getStrings(String name, String separator) {
|
| | | List<String> strings = new ArrayList<String>();
|
| | | Properties props = read();
|
| | | if (props.containsKey(name)) {
|
| | | String value = props.getProperty(name);
|
| | | strings = StringUtils.getStringsFromValue(value, separator);
|
| | | }
|
| | | return strings;
|
| | | }
|
| | | } |
| | |
| | | */
|
| | | package com.gitblit;
|
| | |
|
| | | import java.util.List;
|
| | | import java.util.Enumeration;
|
| | | import java.util.Properties;
|
| | |
|
| | | import javax.servlet.ServletContext;
|
| | |
|
| | | public class WebXmlSettings implements IStoredSettings {
|
| | | public class WebXmlSettings extends IStoredSettings {
|
| | |
|
| | | private final Properties properties = new Properties();
|
| | | |
| | | public WebXmlSettings(ServletContext context) {
|
| | |
|
| | | super(WebXmlSettings.class);
|
| | | Enumeration<?> keys = context.getInitParameterNames();
|
| | | while (keys.hasMoreElements()) {
|
| | | String key = keys.nextElement().toString();
|
| | | String value = context.getInitParameter(key);
|
| | | properties.put(key, value);
|
| | | }
|
| | | }
|
| | |
|
| | | |
| | | @Override
|
| | | public List<String> getAllKeys(String startingWith) {
|
| | | // TODO Auto-generated method stub
|
| | | return null;
|
| | | }
|
| | |
|
| | | @Override
|
| | | public boolean getBoolean(String name, boolean defaultValue) {
|
| | | // TODO Auto-generated method stub
|
| | | return false;
|
| | | }
|
| | |
|
| | | @Override
|
| | | public int getInteger(String name, int defaultValue) {
|
| | | // TODO Auto-generated method stub
|
| | | return 0;
|
| | | }
|
| | |
|
| | | @Override
|
| | | public String getString(String name, String defaultValue) {
|
| | | // TODO Auto-generated method stub
|
| | | return null;
|
| | | }
|
| | |
|
| | | @Override
|
| | | public List<String> getStrings(String name) {
|
| | | // TODO Auto-generated method stub
|
| | | return null;
|
| | | }
|
| | |
|
| | | @Override
|
| | | public List<String> getStringsFromValue(String value) {
|
| | | // TODO Auto-generated method stub
|
| | | return null;
|
| | | }
|
| | |
|
| | | @Override
|
| | | public List<String> getStrings(String name, String separator) {
|
| | | // TODO Auto-generated method stub
|
| | | return null;
|
| | | }
|
| | |
|
| | | @Override
|
| | | public List<String> getStringsFromValue(String value, String separator) {
|
| | | // TODO Auto-generated method stub
|
| | | return null;
|
| | | protected Properties read() {
|
| | | return properties;
|
| | | }
|
| | |
|
| | | @Override
|
| | |
| | | import org.eclipse.jgit.diff.DiffFormatter;
|
| | | import org.eclipse.jgit.diff.RawText;
|
| | | import org.eclipse.jgit.diff.RawTextComparator;
|
| | | import org.eclipse.jgit.lib.Constants;
|
| | | import org.eclipse.jgit.lib.Repository;
|
| | | import org.eclipse.jgit.revwalk.RevCommit;
|
| | | import org.eclipse.jgit.revwalk.RevTree;
|
| | |
| | |
|
| | | public static String getDiff(Repository r, RevCommit baseCommit, RevCommit commit, String path,
|
| | | DiffOutputType outputType) {
|
| | | String diff = null;
|
| | | try {
|
| | | RevTree baseTree;
|
| | | if (baseCommit == null) {
|
| | |
| | | df.setRepository(r);
|
| | | df.setDiffComparator(cmp);
|
| | | df.setDetectRenames(true);
|
| | | List<DiffEntry> diffs = df.scan(baseTree, commitTree);
|
| | | List<DiffEntry> diffEntries = df.scan(baseTree, commitTree);
|
| | | if (path != null && path.length() > 0) {
|
| | | for (DiffEntry diff : diffs) {
|
| | | if (diff.getNewPath().equalsIgnoreCase(path)) {
|
| | | df.format(diff);
|
| | | for (DiffEntry diffEntry : diffEntries) {
|
| | | if (diffEntry.getNewPath().equalsIgnoreCase(path)) {
|
| | | df.format(diffEntry);
|
| | | break;
|
| | | }
|
| | | }
|
| | | } else {
|
| | | df.format(diffs);
|
| | | df.format(diffEntries);
|
| | | }
|
| | | String diff;
|
| | | if (df instanceof GitWebDiffFormatter) {
|
| | | // workaround for complex private methods in DiffFormatter
|
| | | diff = ((GitWebDiffFormatter) df).getHtml();
|
| | |
| | | diff = os.toString();
|
| | | }
|
| | | df.flush();
|
| | | return diff;
|
| | | } catch (Throwable t) {
|
| | | LOGGER.error("failed to generate commit diff!", t);
|
| | | }
|
| | | return null;
|
| | | return diff;
|
| | | }
|
| | |
|
| | | public static String getCommitPatch(Repository r, RevCommit baseCommit, RevCommit commit,
|
| | | String path) {
|
| | | String diff = null;
|
| | | try {
|
| | | RevTree baseTree;
|
| | | if (baseCommit == null) {
|
| | |
| | | df.setRepository(r);
|
| | | df.setDiffComparator(cmp);
|
| | | df.setDetectRenames(true);
|
| | | List<DiffEntry> diffs = df.scan(baseTree, commitTree);
|
| | | List<DiffEntry> diffEntries = df.scan(baseTree, commitTree);
|
| | | if (path != null && path.length() > 0) {
|
| | | for (DiffEntry diff : diffs) {
|
| | | if (diff.getNewPath().equalsIgnoreCase(path)) {
|
| | | df.format(diff);
|
| | | for (DiffEntry diffEntry : diffEntries) {
|
| | | if (diffEntry.getNewPath().equalsIgnoreCase(path)) {
|
| | | df.format(diffEntry);
|
| | | break;
|
| | | }
|
| | | }
|
| | | } else {
|
| | | df.format(diffs);
|
| | | df.format(diffEntries);
|
| | | }
|
| | | String diff = df.getPatch(commit);
|
| | | diff = df.getPatch(commit);
|
| | | df.flush();
|
| | | return diff;
|
| | | } catch (Throwable t) {
|
| | | LOGGER.error("failed to generate commit diff!", t);
|
| | | }
|
| | | return null;
|
| | | return diff;
|
| | | }
|
| | |
|
| | | public static List<AnnotatedLine> blame(Repository r, String blobPath, String objectId) {
|
| | | List<AnnotatedLine> lines = new ArrayList<AnnotatedLine>();
|
| | | try {
|
| | | if (StringUtils.isEmpty(objectId)) {
|
| | | objectId = Constants.HEAD;
|
| | | }
|
| | | BlameCommand blameCommand = new BlameCommand(r);
|
| | | blameCommand.setFilePath(blobPath);
|
| | | blameCommand.setStartCommit(r.resolve(objectId));
|
| | |
| | | import java.io.UnsupportedEncodingException;
|
| | | import java.security.MessageDigest;
|
| | | import java.security.NoSuchAlgorithmException;
|
| | | import java.util.ArrayList;
|
| | | import java.util.List;
|
| | | import java.util.regex.PatternSyntaxException;
|
| | |
|
| | | public class StringUtils {
|
| | |
|
| | |
| | | }
|
| | | return relativePath;
|
| | | }
|
| | | |
| | | public static List<String> getStringsFromValue(String value) {
|
| | | return getStringsFromValue(value, " ");
|
| | | }
|
| | | |
| | | public static List<String> getStringsFromValue(String value, String separator) {
|
| | | List<String> strings = new ArrayList<String>();
|
| | | try {
|
| | | String[] chunks = value.split(separator);
|
| | | for (String chunk : chunks) {
|
| | | chunk = chunk.trim();
|
| | | if (chunk.length() > 0) {
|
| | | strings.add(chunk);
|
| | | }
|
| | | }
|
| | | } catch (PatternSyntaxException e) {
|
| | | throw new RuntimeException(e);
|
| | | }
|
| | | return strings;
|
| | | }
|
| | | }
|
| | |
| | | import com.gitblit.models.PathModel.PathChangeModel;
|
| | | import com.gitblit.utils.JGitUtils;
|
| | | import com.gitblit.utils.JGitUtils.SearchType;
|
| | | import com.gitblit.utils.StringUtils;
|
| | | import com.gitblit.wicket.WicketUtils;
|
| | | import com.gitblit.wicket.panels.CommitHeaderPanel;
|
| | | import com.gitblit.wicket.panels.CommitLegendPanel;
|
| | |
| | | SearchType.AUTHOR));
|
| | | item.add(WicketUtils.createTimestampLabel("authorDate", entry.notesRef
|
| | | .getAuthorIdent().getWhen(), getTimeZone()));
|
| | | item.add(new Label("noteContent", StringUtils.breakLinesForHtml(entry.content))
|
| | | item.add(new Label("noteContent", substituteText(entry.content))
|
| | | .setEscapeModelStrings(false));
|
| | | }
|
| | | };
|
| | |
| | | }
|
| | |
|
| | | protected void addFullText(String wicketId, String text, boolean substituteRegex) {
|
| | | String html = StringUtils.breakLinesForHtml(text);
|
| | | String html;
|
| | | if (substituteRegex) {
|
| | | Map<String, String> map = new HashMap<String, String>();
|
| | | // global regex keys
|
| | | if (GitBlit.getBoolean(Keys.regex.global, false)) {
|
| | | for (String key : GitBlit.getAllKeys(Keys.regex.global)) {
|
| | | if (!key.equals(Keys.regex.global)) {
|
| | | String subKey = key.substring(key.lastIndexOf('.') + 1);
|
| | | map.put(subKey, GitBlit.getString(key, ""));
|
| | | }
|
| | | }
|
| | | }
|
| | | html = substituteText(text);
|
| | | } else {
|
| | | html = StringUtils.breakLinesForHtml(text);
|
| | | }
|
| | | add(new Label(wicketId, html).setEscapeModelStrings(false));
|
| | | }
|
| | |
|
| | | // repository-specific regex keys
|
| | | List<String> keys = GitBlit.getAllKeys(Keys.regex._ROOT + "."
|
| | | + repositoryName.toLowerCase());
|
| | | for (String key : keys) {
|
| | | String subKey = key.substring(key.lastIndexOf('.') + 1);
|
| | | map.put(subKey, GitBlit.getString(key, ""));
|
| | | }
|
| | |
|
| | | for (Entry<String, String> entry : map.entrySet()) {
|
| | | String definition = entry.getValue().trim();
|
| | | String[] chunks = definition.split("!!!");
|
| | | if (chunks.length == 2) {
|
| | | html = html.replaceAll(chunks[0], chunks[1]);
|
| | | } else {
|
| | | logger.warn(entry.getKey()
|
| | | + " improperly formatted. Use !!! to separate match from replacement: "
|
| | | + definition);
|
| | | protected String substituteText(String text) {
|
| | | String html = StringUtils.breakLinesForHtml(text);
|
| | | Map<String, String> map = new HashMap<String, String>();
|
| | | // global regex keys
|
| | | if (GitBlit.getBoolean(Keys.regex.global, false)) {
|
| | | for (String key : GitBlit.getAllKeys(Keys.regex.global)) {
|
| | | if (!key.equals(Keys.regex.global)) {
|
| | | String subKey = key.substring(key.lastIndexOf('.') + 1);
|
| | | map.put(subKey, GitBlit.getString(key, ""));
|
| | | }
|
| | | }
|
| | | }
|
| | | add(new Label(wicketId, html).setEscapeModelStrings(false));
|
| | |
|
| | | // repository-specific regex keys
|
| | | List<String> keys = GitBlit.getAllKeys(Keys.regex._ROOT + "."
|
| | | + repositoryName.toLowerCase());
|
| | | for (String key : keys) {
|
| | | String subKey = key.substring(key.lastIndexOf('.') + 1);
|
| | | map.put(subKey, GitBlit.getString(key, ""));
|
| | | }
|
| | |
|
| | | for (Entry<String, String> entry : map.entrySet()) {
|
| | | String definition = entry.getValue().trim();
|
| | | String[] chunks = definition.split("!!!");
|
| | | if (chunks.length == 2) {
|
| | | html = html.replaceAll(chunks[0], chunks[1]);
|
| | | } else {
|
| | | logger.warn(entry.getKey()
|
| | | + " improperly formatted. Use !!! to separate match from replacement: "
|
| | | + definition);
|
| | | }
|
| | | }
|
| | | return html;
|
| | | }
|
| | |
|
| | | protected abstract String getPageName();
|
| | |
| | | border-width: 1px 0px 0px;
|
| | | }
|
| | |
|
| | | div.commit_message a {
|
| | | font-family: monospace;
|
| | | }
|
| | |
|
| | | div.bug_open, span.bug_open {
|
| | | padding: 2px;
|
| | | background-color: #803333;
|
| | |
| | | */
|
| | | package com.gitblit.tests;
|
| | |
|
| | | import java.util.List;
|
| | |
|
| | | import junit.framework.TestCase;
|
| | |
|
| | | import org.eclipse.jgit.lib.Repository;
|
| | | import org.eclipse.jgit.revwalk.RevCommit;
|
| | |
|
| | | import com.gitblit.models.AnnotatedLine;
|
| | | import com.gitblit.utils.DiffUtils;
|
| | | import com.gitblit.utils.DiffUtils.DiffOutputType;
|
| | | import com.gitblit.utils.JGitUtils;
|
| | |
|
| | | public class DiffUtilsTest extends TestCase {
|
| | |
|
| | | public void testDiffOutputTypes() throws Exception {
|
| | | assertTrue(DiffOutputType.forName("plain").equals(DiffOutputType.PLAIN));
|
| | | assertTrue(DiffOutputType.forName("gitweb").equals(DiffOutputType.GITWEB));
|
| | | assertTrue(DiffOutputType.forName("gitblit").equals(DiffOutputType.GITBLIT));
|
| | | assertTrue(DiffOutputType.forName(null) == null);
|
| | | }
|
| | | |
| | | public void testParentCommitDiff() throws Exception {
|
| | | Repository repository = GitBlitSuite.getHelloworldRepository();
|
| | | RevCommit commit = JGitUtils.getCommit(repository,
|
| | |
| | | String expected = "- system.out.println(\"Hello World\");\n+ System.out.println(\"Hello World\"";
|
| | | assertTrue(patch.indexOf(expected) > -1);
|
| | | }
|
| | | |
| | | public void testBlame() throws Exception {
|
| | | Repository repository = GitBlitSuite.getHelloworldRepository();
|
| | | List<AnnotatedLine> lines = DiffUtils.blame(repository, "java.java", "1d0c2933a4ae69c362f76797d42d6bd182d05176");
|
| | | repository.close();
|
| | | assertTrue(lines.size() > 0);
|
| | | assertTrue(lines.get(0).commitId.equals("c6d31dccf5cc75e8e46299fc62d38f60ec6d41e0"));
|
| | | }
|
| | | }
|
| | |
| | |
|
| | | import junit.framework.TestCase;
|
| | |
|
| | | import com.gitblit.Constants.AccessRestrictionType;
|
| | | import com.gitblit.FileSettings;
|
| | | import com.gitblit.GitBlit;
|
| | | import com.gitblit.models.RepositoryModel;
|
| | | import com.gitblit.models.UserModel;
|
| | |
| | | assertTrue(model.toString().equals("admin"));
|
| | | assertTrue("Admin missing #admin role!", model.canAdmin);
|
| | | model.canAdmin = false;
|
| | | assertFalse("Admin should not hae #admin!", model.canAdmin);
|
| | | assertFalse("Admin should not have #admin!", model.canAdmin);
|
| | | String repository = GitBlitSuite.getHelloworldRepository().getDirectory().getName();
|
| | | assertFalse("Admin can still access repository!", model.canAccessRepository(repository));
|
| | | model.addRepository(repository);
|
| | | assertTrue("Admin can't access repository!", model.canAccessRepository(repository));
|
| | | }
|
| | | |
| | | public void testAccessRestrictionTypes() throws Exception {
|
| | | assertTrue(AccessRestrictionType.PUSH.exceeds(AccessRestrictionType.NONE));
|
| | | assertTrue(AccessRestrictionType.CLONE.exceeds(AccessRestrictionType.PUSH));
|
| | | assertTrue(AccessRestrictionType.VIEW.exceeds(AccessRestrictionType.CLONE));
|
| | |
|
| | | assertFalse(AccessRestrictionType.NONE.exceeds(AccessRestrictionType.PUSH));
|
| | | assertFalse(AccessRestrictionType.PUSH.exceeds(AccessRestrictionType.CLONE));
|
| | | assertFalse(AccessRestrictionType.CLONE.exceeds(AccessRestrictionType.VIEW));
|
| | |
|
| | | assertTrue(AccessRestrictionType.PUSH.atLeast(AccessRestrictionType.NONE));
|
| | | assertTrue(AccessRestrictionType.CLONE.atLeast(AccessRestrictionType.PUSH));
|
| | | assertTrue(AccessRestrictionType.VIEW.atLeast(AccessRestrictionType.CLONE));
|
| | |
|
| | | assertFalse(AccessRestrictionType.NONE.atLeast(AccessRestrictionType.PUSH));
|
| | | assertFalse(AccessRestrictionType.PUSH.atLeast(AccessRestrictionType.CLONE));
|
| | | assertFalse(AccessRestrictionType.CLONE.atLeast(AccessRestrictionType.VIEW));
|
| | | |
| | | assertTrue(AccessRestrictionType.PUSH.toString().equals("PUSH"));
|
| | | assertTrue(AccessRestrictionType.CLONE.toString().equals("CLONE"));
|
| | | assertTrue(AccessRestrictionType.VIEW.toString().equals("VIEW"));
|
| | |
|
| | | assertTrue(AccessRestrictionType.fromName("none").equals(AccessRestrictionType.NONE));
|
| | | assertTrue(AccessRestrictionType.fromName("push").equals(AccessRestrictionType.PUSH));
|
| | | assertTrue(AccessRestrictionType.fromName("clone").equals(AccessRestrictionType.CLONE));
|
| | | assertTrue(AccessRestrictionType.fromName("view").equals(AccessRestrictionType.VIEW));
|
| | | }
|
| | | |
| | | public void testFileSettings() throws Exception {
|
| | | FileSettings settings = new FileSettings("distrib/gitblit.properties");
|
| | | assertTrue(settings.getBoolean("missing", true) == true);
|
| | | assertTrue(settings.getString("missing", "default").equals("default"));
|
| | | assertTrue(settings.getInteger("missing", 10) == 10);
|
| | | assertTrue(settings.getInteger("realm.realmFile", 5) == 5);
|
| | | |
| | | assertTrue(settings.getBoolean("git.enableGitServlet", false) == true);
|
| | | assertTrue(settings.getString("realm.realmFile", null).equals("users.properties"));
|
| | | assertTrue(settings.getInteger("realm.minPasswordLength", 0) == 5);
|
| | | List<String> mdExtensions = settings.getStrings("web.markdownExtensions");
|
| | | assertTrue(mdExtensions.size() > 0);
|
| | | assertTrue(mdExtensions.contains("md"));
|
| | | |
| | | List<String> keys = settings.getAllKeys("server");
|
| | | assertTrue(keys.size() > 0);
|
| | | assertTrue(keys.contains("server.httpsPort"));
|
| | | }
|
| | | |
| | | public void testGitblitSettings() throws Exception {
|
| | | // These are already tested by above test method.
|
| | | assertTrue(GitBlit.getBoolean("missing", true) == true);
|
| | | assertTrue(GitBlit.getString("missing", "default").equals("default"));
|
| | | assertTrue(GitBlit.getInteger("missing", 10) == 10);
|
| | | assertTrue(GitBlit.getInteger("realm.realmFile", 5) == 5);
|
| | | |
| | | assertTrue(GitBlit.getBoolean("git.enableGitServlet", false) == true);
|
| | | assertTrue(GitBlit.getString("realm.realmFile", null).equals("users.properties"));
|
| | | assertTrue(GitBlit.getInteger("realm.minPasswordLength", 0) == 5);
|
| | | List<String> mdExtensions = GitBlit.getStrings("web.markdownExtensions");
|
| | | assertTrue(mdExtensions.size() > 0);
|
| | | assertTrue(mdExtensions.contains("md"));
|
| | | |
| | | List<String> keys = GitBlit.getAllKeys("server");
|
| | | assertTrue(keys.size() > 0);
|
| | | assertTrue(keys.contains("server.httpsPort"));
|
| | | }
|
| | | |
| | | public void testAuthentication() throws Exception {
|
| | | assertTrue(GitBlit.self().authenticate("admin", "admin".toCharArray()) != null);
|
| | | }
|
| | | |
| | | public void testRepositories() throws Exception {
|
| | | assertTrue(GitBlit.self().getRepository("missing") == null);
|
| | | assertTrue(GitBlit.self().getRepositoryModel("missing") == null);
|
| | | }
|
| | | }
|
| | |
| | | List<RefModel> list = entry.getValue();
|
| | | for (RefModel ref : list) {
|
| | | if (ref.displayName.equals("refs/tags/spearce-gpg-pub")) {
|
| | | assertTrue(ref.toString().equals("refs/tags/spearce-gpg-pub"));
|
| | | assertTrue(ref.getObjectId().getName()
|
| | | .equals("8bbde7aacf771a9afb6992434f1ae413e010c6d8"));
|
| | | assertTrue(ref.getAuthorIdent().getEmailAddress().equals("spearce@spearce.org"));
|
| | |
| | | package com.gitblit.tests;
|
| | |
|
| | | import java.util.Arrays;
|
| | | import java.util.List;
|
| | |
|
| | | import junit.framework.TestCase;
|
| | |
|
| | |
| | | assertTrue(StringUtils.getRootPath(input).equals(output));
|
| | | assertTrue(StringUtils.getRootPath("repository").equals(""));
|
| | | }
|
| | | |
| | | public void testStringsFromValue() throws Exception {
|
| | | List<String> strings = StringUtils.getStringsFromValue("A B C D");
|
| | | assertTrue(strings.size() == 4);
|
| | | assertTrue(strings.get(0).equals("A"));
|
| | | assertTrue(strings.get(1).equals("B"));
|
| | | assertTrue(strings.get(2).equals("C"));
|
| | | assertTrue(strings.get(3).equals("D"));
|
| | | }
|
| | | }
|