RSS syndication feature. Documentation. CSS tweaks.
3 files added
17 files modified
| | |
| | | http://www.jcraft.com/jsch
|
| | |
|
| | | ---------------------------------------------------------------------------
|
| | | Rome
|
| | | ---------------------------------------------------------------------------
|
| | | Rome RSS and Atom Java Utilities, released under the
|
| | | Apache Software License, Version 1.1.
|
| | |
|
| | | http://rome.dev.java.net
|
| | |
|
| | | ---------------------------------------------------------------------------
|
| | | jdom
|
| | | ---------------------------------------------------------------------------
|
| | | jdom xml library, released under the
|
| | | Apache-style Software License.
|
| | |
|
| | | http://www.jdom.org
|
| | |
|
| | | ---------------------------------------------------------------------------
|
| | | JUnit
|
| | | ---------------------------------------------------------------------------
|
| | | JUnit, released under the
|
| | |
| | | # Allow dyanamic zip downloads.
|
| | | web.allowZipDownloads = true
|
| | |
|
| | | # Default number of entries to include in RSS/Atom Syndication links
|
| | | web.syndicationEntries = 25
|
| | |
|
| | | # This is the message display above the repositories table.
|
| | | # This can point to a file with Markdown content.
|
| | | # Specifying "gitblit" uses the internal welcome message.
|
| | |
| | | - Automatically generates a self-signed certificate for https communications
|
| | | - Git-notes support
|
| | | - Branch metrics (uses Google Charts)
|
| | | - HEAD and branch RSS feeds
|
| | | - Blame annotations view
|
| | | - Dates can optionally be displayed using the browser's reported timezone
|
| | | - Display of Author and Committer email addresses can be disabled
|
| | |
| | | - Gitblit may have security holes. Patches welcome. :)
|
| | |
|
| | | ### Todo List
|
| | | - Custom BASIC authentication servlet or servlet filter
|
| | | - Code documentation
|
| | | - Unit testing
|
| | | - Update Build.java to JGit 1.0.0, when its released
|
| | |
| | | - [JCommander](http://jcommander.org) (Apache 2.0)
|
| | | - [BouncyCastle](http://www.bouncycastle.org) (MIT/X11)
|
| | | - [JSch - Java Secure Channel](http://www.jcraft.com/jsch) (BSD)
|
| | | - [Rome](http://rome.dev.java.net) (Apache 1.1)
|
| | | - [jdom](http://www.jdom.org) (Apache-style JDOM license)
|
| | |
|
| | | ### Other Build Dependencies
|
| | | - [Fancybox image viewer](http://fancybox.net) (MIT and GPL dual-licensed)
|
| | |
| | | 3. <pre>Key = *http.sslVerify*
|
| | | Value = *false*</pre>
|
| | | - Command-line Git ([Git-Config Manual Page](http://www.kernel.org/pub/software/scm/git/docs/git-config.html))
|
| | | <pre>git-config --global --bool --add http.sslVerify false</pre>
|
| | | <pre>git config --global --bool --add http.sslVerify false</pre>
|
| | |
|
| | | ### Cloning an Access Restricted Repository
|
| | | - Eclipse/Egit<br/>Nothing special to configure, EGit figures out everything.
|
| | |
| | | [git]: http://git-scm.com "Official Git Site"
|
| | | [mina]: http://mina.apache.org "Apache Mina"
|
| | | [bouncycastle]: http://bouncycastle.org "The Legion of the Bouncy Castle"
|
| | | [hg4j]: http://code.google.com/p/hg4j/ "hg4j" |
| | |
| | | downloadFromApache(MavenObject.BOUNCYCASTLE, BuildType.RUNTIME);
|
| | | downloadFromApache(MavenObject.BOUNCYCASTLE_MAIL, BuildType.RUNTIME);
|
| | | downloadFromApache(MavenObject.JSCH, BuildType.RUNTIME);
|
| | | downloadFromApache(MavenObject.ROME, BuildType.RUNTIME);
|
| | | downloadFromApache(MavenObject.JDOM, BuildType.RUNTIME);
|
| | |
|
| | | downloadFromEclipse(MavenObject.JGIT, BuildType.RUNTIME);
|
| | | downloadFromEclipse(MavenObject.JGIT_HTTP, BuildType.RUNTIME);
|
| | |
| | | downloadFromApache(MavenObject.BOUNCYCASTLE, BuildType.COMPILETIME);
|
| | | downloadFromApache(MavenObject.BOUNCYCASTLE_MAIL, BuildType.COMPILETIME);
|
| | | downloadFromApache(MavenObject.JSCH, BuildType.COMPILETIME);
|
| | | downloadFromApache(MavenObject.ROME, BuildType.COMPILETIME);
|
| | | downloadFromApache(MavenObject.JDOM, BuildType.COMPILETIME);
|
| | |
|
| | | downloadFromEclipse(MavenObject.JGIT, BuildType.COMPILETIME);
|
| | | downloadFromEclipse(MavenObject.JGIT_HTTP, BuildType.COMPILETIME);
|
| | |
| | | "",
|
| | | "");
|
| | |
|
| | | public static final MavenObject ROME = new MavenObject("rome", "rome", "rome",
|
| | | "0.9", 208000, 196000, 407000, "dee2705dd01e79a5a96a17225f5a1ae30470bb18",
|
| | | "226f851dc44fd94fe70b9c471881b71f88949cbf",
|
| | | "8d7d867b97eeb3a9196c3926da550ad042941c1b");
|
| | |
|
| | | public static final MavenObject JDOM = new MavenObject("jdom", "org/jdom", "jdom",
|
| | | "1.1", 153000, 235000, 445000, "1d04c0f321ea337f3661cf7ede8f4c6f653a8fdd",
|
| | | "a7ed425c4c46605b8f2bf2ee118c1609682f4f2c",
|
| | | "f3df91edccba2f07a0fced70887c2f7b7836cb75");
|
| | |
|
| | | public final String name;
|
| | | public final String group;
|
| | | public final String artifact;
|
| | |
| | | public static final String GIT_SERVLET_PATH = "/git/";
|
| | |
|
| | | public static final String ZIP_SERVLET_PATH = "/zip/";
|
| | | |
| | | public static final String SYNDICATION_SERVLET_PATH = "/feed/";
|
| | |
|
| | | public static final String BORDER = "***********************************************************";
|
| | |
|
| | |
| | | }
|
| | |
|
| | | public static String asLink(String baseURL, String repository, String objectId, String path) {
|
| | | return baseURL + (baseURL.endsWith("/") ? "" : "/") + "zip?r=" + repository
|
| | | if (baseURL.charAt(baseURL.length() - 1) == '/') {
|
| | | baseURL = baseURL.substring(0, baseURL.length() - 1);
|
| | | }
|
| | | return baseURL + Constants.ZIP_SERVLET_PATH + "?r=" + repository
|
| | | + (path == null ? "" : ("&p=" + path))
|
| | | + (objectId == null ? "" : ("&h=" + objectId));
|
| | | }
|
| | |
| | | // Zip Servlet
|
| | | rootContext.addServlet(DownloadZipServlet.class, Constants.ZIP_SERVLET_PATH + "*");
|
| | |
|
| | | // Syndication Servlet
|
| | | rootContext.addServlet(SyndicationServlet.class, Constants.SYNDICATION_SERVLET_PATH + "*");
|
| | |
|
| | | // Git Servlet
|
| | | ServletHolder gitServlet = null;
|
| | | String gitServletPathSpec = Constants.GIT_SERVLET_PATH + "*";
|
| | |
| | | FileWriter writer = new FileWriter(realmFileCopy);
|
| | | properties
|
| | | .store(writer,
|
| | | "# Git:Blit realm file format: username=password,\\#permission,repository1,repository2...");
|
| | | "# Gitblit realm file format: username=password,\\#permission,repository1,repository2...");
|
| | | writer.close();
|
| | | if (realmFileCopy.exists() && realmFileCopy.length() > 0) {
|
| | | if (realmFile.delete()) {
|
New file |
| | |
| | | /*
|
| | | * Copyright 2011 gitblit.com.
|
| | | *
|
| | | * Licensed under the Apache License, Version 2.0 (the "License");
|
| | | * you may not use this file except in compliance with the License.
|
| | | * You may obtain a copy of the License at
|
| | | *
|
| | | * http://www.apache.org/licenses/LICENSE-2.0
|
| | | *
|
| | | * Unless required by applicable law or agreed to in writing, software
|
| | | * distributed under the License is distributed on an "AS IS" BASIS,
|
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| | | * See the License for the specific language governing permissions and
|
| | | * limitations under the License.
|
| | | */
|
| | | package com.gitblit;
|
| | |
|
| | | import java.util.List;
|
| | |
|
| | | import javax.servlet.http.HttpServlet;
|
| | |
|
| | | import org.eclipse.jgit.lib.Repository;
|
| | | import org.eclipse.jgit.revwalk.RevCommit;
|
| | | import org.slf4j.Logger;
|
| | | import org.slf4j.LoggerFactory;
|
| | |
|
| | | import com.gitblit.models.RepositoryModel;
|
| | | import com.gitblit.utils.JGitUtils;
|
| | | import com.gitblit.utils.StringUtils;
|
| | | import com.gitblit.utils.SyndicationUtils;
|
| | |
|
| | | public class SyndicationServlet extends HttpServlet {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | | private transient Logger logger = LoggerFactory.getLogger(SyndicationServlet.class);
|
| | |
|
| | | public static String asLink(String baseURL, String repository, String objectId, int length) {
|
| | | if (baseURL.charAt(baseURL.length() - 1) == '/') {
|
| | | baseURL = baseURL.substring(0, baseURL.length() - 1);
|
| | | }
|
| | | return baseURL + Constants.SYNDICATION_SERVLET_PATH + "?r=" + repository
|
| | | + (objectId == null ? "" : ("&h=" + objectId)) + (length > 0 ? "&l=" + length : "");
|
| | | }
|
| | |
|
| | | private void processRequest(javax.servlet.http.HttpServletRequest request,
|
| | | javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException,
|
| | | java.io.IOException {
|
| | | String hostUrl = request.getRequestURL().toString();
|
| | | String servlet = request.getServletPath();
|
| | | hostUrl = hostUrl.substring(0, hostUrl.indexOf(servlet));
|
| | | String repositoryName = request.getParameter("r");
|
| | | String objectId = request.getParameter("h");
|
| | | String l = request.getParameter("l");
|
| | | int length = GitBlit.getInteger(Keys.web.syndicationEntries, 25);
|
| | | if (StringUtils.isEmpty(objectId)) {
|
| | | objectId = org.eclipse.jgit.lib.Constants.HEAD;
|
| | | }
|
| | | if (!StringUtils.isEmpty(l)) {
|
| | | try {
|
| | | length = Integer.parseInt(l);
|
| | | } catch (NumberFormatException x) {
|
| | | }
|
| | | }
|
| | | |
| | | // TODO confirm repository is accessible!!
|
| | |
|
| | | Repository repository = GitBlit.self().getRepository(repositoryName);
|
| | | RepositoryModel model = GitBlit.self().getRepositoryModel(repositoryName);
|
| | | List<RevCommit> commits = JGitUtils.getRevLog(repository, objectId, 0, length);
|
| | | try {
|
| | | SyndicationUtils.toRSS(hostUrl, model.name + " " + objectId, model.description, model.name, commits, response.getOutputStream());
|
| | | } catch (Exception e) {
|
| | | logger.error("An error occurred during feed generation", e);
|
| | | }
|
| | | }
|
| | |
|
| | | @Override
|
| | | protected void doPost(javax.servlet.http.HttpServletRequest request,
|
| | | javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException,
|
| | | java.io.IOException {
|
| | | processRequest(request, response);
|
| | | }
|
| | |
|
| | | @Override
|
| | | protected void doGet(javax.servlet.http.HttpServletRequest request,
|
| | | javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException,
|
| | | java.io.IOException {
|
| | | processRequest(request, response);
|
| | | }
|
| | | }
|
New file |
| | |
| | | /*
|
| | | * Copyright 2011 gitblit.com.
|
| | | *
|
| | | * Licensed under the Apache License, Version 2.0 (the "License");
|
| | | * you may not use this file except in compliance with the License.
|
| | | * You may obtain a copy of the License at
|
| | | *
|
| | | * http://www.apache.org/licenses/LICENSE-2.0
|
| | | *
|
| | | * Unless required by applicable law or agreed to in writing, software
|
| | | * distributed under the License is distributed on an "AS IS" BASIS,
|
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| | | * See the License for the specific language governing permissions and
|
| | | * limitations under the License.
|
| | | */
|
| | | package com.gitblit.utils;
|
| | |
|
| | | import java.io.IOException;
|
| | | import java.io.OutputStream;
|
| | | import java.io.OutputStreamWriter;
|
| | | import java.text.MessageFormat;
|
| | | import java.util.ArrayList;
|
| | | import java.util.List;
|
| | |
|
| | | import org.eclipse.jgit.revwalk.RevCommit;
|
| | |
|
| | | import com.sun.syndication.feed.synd.SyndContent;
|
| | | import com.sun.syndication.feed.synd.SyndContentImpl;
|
| | | import com.sun.syndication.feed.synd.SyndEntry;
|
| | | import com.sun.syndication.feed.synd.SyndEntryImpl;
|
| | | import com.sun.syndication.feed.synd.SyndFeed;
|
| | | import com.sun.syndication.feed.synd.SyndFeedImpl;
|
| | | import com.sun.syndication.io.FeedException;
|
| | | import com.sun.syndication.io.SyndFeedOutput;
|
| | |
|
| | | public class SyndicationUtils {
|
| | |
|
| | | public static void toRSS(String hostUrl, String title, String description, String repository, List<RevCommit> commits, OutputStream os)
|
| | | throws IOException, FeedException {
|
| | |
|
| | | SyndFeed feed = new SyndFeedImpl();
|
| | | feed.setFeedType("rss_1.0");
|
| | | feed.setTitle(title);
|
| | | feed.setLink(MessageFormat.format("{0}/summary/{1}", hostUrl, repository));
|
| | | feed.setDescription(description);
|
| | |
|
| | | List<SyndEntry> entries = new ArrayList<SyndEntry>();
|
| | | for (RevCommit commit : commits) {
|
| | | SyndEntry entry = new SyndEntryImpl();
|
| | | entry.setTitle(commit.getShortMessage());
|
| | | entry.setAuthor(commit.getAuthorIdent().getName());
|
| | | entry.setLink(MessageFormat.format("{0}/commit/{1}/{2}", hostUrl, repository, commit.getName()));
|
| | | entry.setPublishedDate(commit.getCommitterIdent().getWhen());
|
| | |
|
| | | SyndContent content = new SyndContentImpl();
|
| | | content.setType("text/html");
|
| | | String html = StringUtils.escapeForHtml(commit.getFullMessage(), false);
|
| | | content.setValue(StringUtils.breakLinesForHtml(html));
|
| | | entry.setDescription(content);
|
| | | entries.add(entry);
|
| | | }
|
| | | feed.setEntries(entries);
|
| | |
|
| | | OutputStreamWriter writer = new OutputStreamWriter(os);
|
| | | SyndFeedOutput output = new SyndFeedOutput();
|
| | | output.output(feed, writer);
|
| | | writer.close();
|
| | | }
|
| | | }
|
| | |
| | | gb.commitActivityTrend = commit activity trend
|
| | | gb.commitActivityDOW = commit activity by day of week
|
| | | gb.commitActivityAuthors = primary authors by commit activity |
| | | gb.feed = feed |
| | |
| | | SimpleDateFormat sdf = new SimpleDateFormat("E");
|
| | | Calendar cal = Calendar.getInstance();
|
| | |
|
| | | List<Metric> sorted = new ArrayList<Metric>(7);
|
| | | List<Metric> sorted = new ArrayList<Metric>();
|
| | | int firstDayOfWeek = cal.getFirstDayOfWeek();
|
| | | int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
|
| | |
|
| | |
| | | String day = sdf.format(cal.getTime());
|
| | | for (Metric metric : list) {
|
| | | if (metric.name.equals(day)) {
|
| | | sorted.add(i, metric);
|
| | | sorted.add(metric);
|
| | | list.remove(metric);
|
| | | break;
|
| | | }
|
| | |
| | | <!-- page header bar -->
|
| | | <div>
|
| | | <!-- floating search form on right -->
|
| | | <form wicket:id="searchForm">
|
| | | <div class="search">
|
| | | <form wicket:id="searchForm">
|
| | | <select wicket:id="searchType"/>
|
| | | <input type="text" id="searchBox" wicket:id="searchBox" size="25" value=""/>
|
| | | </div>
|
| | | </form>
|
| | | </div>
|
| | |
|
| | | <!-- page nav links -->
|
| | | <div class="page_nav">
|
| | | <a style="text-decoration: none;" wicket:id="syndication">
|
| | | <img style="border:0px;vertical-align:middle;" src="/com/gitblit/wicket/resources/feed_16x16.png"></img>
|
| | | </a> |
| | | <a wicket:id="summary"><wicket:message key="gb.summary"></wicket:message></a> | <a wicket:id="log"><wicket:message key="gb.log"></wicket:message></a> | <a wicket:id="branches"><wicket:message key="gb.branches"></wicket:message></a> | <a wicket:id="tags"><wicket:message key="gb.tags"></wicket:message></a> | <a wicket:id="tree"><wicket:message key="gb.tree"></wicket:message></a> <span wicket:id="extra"><span wicket:id="extraSeparator"></span><span wicket:id="extraLink"></span></span>
|
| | | </div>
|
| | | </div>
|
| | |
| | | import org.apache.wicket.markup.html.form.StatelessForm;
|
| | | import org.apache.wicket.markup.html.form.TextField;
|
| | | import org.apache.wicket.markup.html.link.BookmarkablePageLink;
|
| | | import org.apache.wicket.markup.html.link.ExternalLink;
|
| | | import org.apache.wicket.markup.html.panel.Fragment;
|
| | | import org.apache.wicket.markup.repeater.Item;
|
| | | import org.apache.wicket.markup.repeater.data.DataView;
|
| | |
| | |
|
| | | import com.gitblit.GitBlit;
|
| | | import com.gitblit.Keys;
|
| | | import com.gitblit.SyndicationServlet;
|
| | | import com.gitblit.models.RepositoryModel;
|
| | | import com.gitblit.utils.JGitUtils;
|
| | | import com.gitblit.utils.JGitUtils.SearchType;
|
| | |
| | | };
|
| | | add(extrasView);
|
| | |
|
| | | add(new ExternalLink("syndication", SyndicationServlet.asLink(getRequest()
|
| | | .getRelativePathPrefixToContextRoot(), repositoryName, null, 0)));
|
| | |
|
| | | // disable current page
|
| | | disablePageLink(getPageName());
|
| | |
|
| | |
| | | <!-- branch page links -->
|
| | | <wicket:fragment wicket:id="branchPageLinks">
|
| | | <span class="link">
|
| | | <a wicket:id="log"><wicket:message key="gb.log"></wicket:message></a> | <a wicket:id="tree"><wicket:message key="gb.tree"></wicket:message></a> | <a wicket:id="metrics"><wicket:message key="gb.metrics"></wicket:message></a>
|
| | | <a wicket:id="log"><wicket:message key="gb.log"></wicket:message></a> | <a wicket:id="tree"><wicket:message key="gb.tree"></wicket:message></a> | <a wicket:id="metrics"><wicket:message key="gb.metrics"></wicket:message></a> | <a wicket:id="syndication"><wicket:message key="gb.feed"></wicket:message></a>
|
| | | </span>
|
| | | </wicket:fragment>
|
| | |
|
| | |
| | |
|
| | | import org.apache.wicket.markup.html.basic.Label;
|
| | | import org.apache.wicket.markup.html.link.BookmarkablePageLink;
|
| | | import org.apache.wicket.markup.html.link.ExternalLink;
|
| | | import org.apache.wicket.markup.html.panel.Fragment;
|
| | | import org.apache.wicket.markup.repeater.Item;
|
| | | import org.apache.wicket.markup.repeater.data.DataView;
|
| | |
| | | import org.eclipse.jgit.lib.Constants;
|
| | | import org.eclipse.jgit.lib.Repository;
|
| | |
|
| | | import com.gitblit.SyndicationServlet;
|
| | | import com.gitblit.models.RefModel;
|
| | | import com.gitblit.models.RepositoryModel;
|
| | | import com.gitblit.utils.JGitUtils;
|
| | |
| | | .newObjectParameter(model.name, entry.getName())));
|
| | | fragment.add(new BookmarkablePageLink<Void>("metrics", MetricsPage.class,
|
| | | WicketUtils.newObjectParameter(model.name, entry.getName())));
|
| | | fragment.add(new ExternalLink("syndication", SyndicationServlet.asLink(getRequest()
|
| | | .getRelativePathPrefixToContextRoot(), model.name, entry.getName(), 0)));
|
| | | item.add(fragment);
|
| | | } else {
|
| | | Fragment fragment = new Fragment("branchLinks", "branchPanelLinks", this);
|
| | |
| | | padding: 8px;
|
| | | }
|
| | |
|
| | | table.plain td {
|
| | | white-space: nowrap;
|
| | | }
|
| | |
|
| | | table.plain td.edit {
|
| | | padding: 3px;
|
| | | }
|