James Moger
2014-05-08 1d2d5efe6d5dafbd2236776bc4667521921e5c8c
Merged #66 "Query tags using RSS feeds"
7 files modified
298 ■■■■ changed files
releases.moxie 2 ●●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/Constants.java 21 ●●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/servlet/SyndicationServlet.java 133 ●●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/utils/JGitUtils.java 48 ●●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/utils/SyndicationUtils.java 57 ●●●●● patch | view | raw | blame | history
src/site/rpc.mkd 1 ●●●● patch | view | raw | blame | history
src/test/java/com/gitblit/tests/SyndicationUtilsTest.java 36 ●●●●● patch | view | raw | blame | history
releases.moxie
@@ -13,9 +13,11 @@
    changes: ~
    additions:
    - Add FORK_REPOSITORY RPC request type (issue-371, pr-161, ticket-65)
    - Add object type (ot) parameter for RSS queries to retrieve tag details (pr-165, ticket-66)
    dependencyChanges: ~
    contributors:
    - Manisha Gayathri
    - Gerard Smyth
}
#
src/main/java/com/gitblit/Constants.java
@@ -403,6 +403,27 @@
    }
    /**
     * Enumeration of the feed content object types.
     */
    public static enum FeedObjectType {
        COMMIT, TAG;
        public static FeedObjectType forName(String name) {
            for (FeedObjectType type : values()) {
                if (type.name().equalsIgnoreCase(name)) {
                    return type;
                }
            }
            return COMMIT;
        }
        @Override
        public String toString() {
            return name().toLowerCase();
        }
    }
    /**
     * The types of objects that can be indexed and queried.
     */
    public static enum SearchObjectType {
src/main/java/com/gitblit/servlet/SyndicationServlet.java
@@ -163,6 +163,15 @@
                searchType = type;
            }
        }
        Constants.FeedObjectType objectType = Constants.FeedObjectType.COMMIT;
        if (!StringUtils.isEmpty(request.getParameter("ot"))) {
            Constants.FeedObjectType type = Constants.FeedObjectType.forName(request.getParameter("ot"));
            if (type != null) {
                objectType = type;
            }
        }
        int length = settings.getInteger(Keys.web.syndicationEntries, 25);
        if (StringUtils.isEmpty(objectId)) {
            objectId = org.eclipse.jgit.lib.Constants.HEAD;
@@ -214,14 +223,7 @@
        boolean mountParameters = settings.getBoolean(Keys.web.mountParameters, true);
        String urlPattern;
        if (mountParameters) {
            // mounted parameters
            urlPattern = "{0}/commit/{1}/{2}";
        } else {
            // parameterized parameters
            urlPattern = "{0}/commit/?r={1}&h={2}";
        }
        String gitblitUrl = settings.getString(Keys.web.canonicalUrl, null);
        if (StringUtils.isEmpty(gitblitUrl)) {
            gitblitUrl = HttpUtils.getGitblitURL(request);
@@ -247,47 +249,92 @@
                feedDescription = model.description;
            }
            List<RevCommit> commits;
            if (StringUtils.isEmpty(searchString)) {
                // standard log/history lookup
                commits = JGitUtils.getRevLog(repository, objectId, offset, length);
            if (objectType == Constants.FeedObjectType.TAG) {
                String urlPattern;
                if (mountParameters) {
                    // mounted parameters
                    urlPattern = "{0}/tag/{1}/{2}";
                } else {
                    // parameterized parameters
                    urlPattern = "{0}/tag/?r={1}&h={2}";
                }
                List<RefModel> tags = JGitUtils.getTags(repository, false, length, offset);
                for (RefModel tag : tags) {
                    FeedEntryModel entry = new FeedEntryModel();
                    entry.title = tag.getName();
                    entry.author = tag.getAuthorIdent().getName();
                    entry.link = MessageFormat.format(urlPattern, gitblitUrl,
                            StringUtils.encodeURL(model.name.replace('/', fsc)), tag.getObjectId().getName());
                    entry.published = tag.getDate();
                    entry.contentType = "text/html";
                    entry.content = tag.getFullMessage();
                    entry.repository = model.name;
                    entry.branch = objectId;
                    entry.tags = new ArrayList<String>();
                    // add tag id and referenced commit id
                    entry.tags.add("tag:" + tag.getObjectId().getName());
                    entry.tags.add("commit:" + tag.getReferencedObjectId().getName());
                    entries.add(entry);
                }
            } else {
                // repository search
                commits = JGitUtils.searchRevlogs(repository, objectId, searchString, searchType,
                        offset, length);
            }
            Map<ObjectId, List<RefModel>> allRefs = JGitUtils.getAllRefs(repository, model.showRemoteBranches);
            BugtraqProcessor processor = new BugtraqProcessor(settings);
            // convert RevCommit to SyndicatedEntryModel
            for (RevCommit commit : commits) {
                FeedEntryModel entry = new FeedEntryModel();
                entry.title = commit.getShortMessage();
                entry.author = commit.getAuthorIdent().getName();
                entry.link = MessageFormat.format(urlPattern, gitblitUrl,
                        StringUtils.encodeURL(model.name.replace('/', fsc)), commit.getName());
                entry.published = commit.getCommitterIdent().getWhen();
                entry.contentType = "text/html";
                String message = processor.processCommitMessage(repository, model, commit.getFullMessage());
                entry.content = message;
                entry.repository = model.name;
                entry.branch = objectId;
                entry.tags = new ArrayList<String>();
                // add commit id and parent commit ids
                entry.tags.add("commit:" + commit.getName());
                for (RevCommit parent : commit.getParents()) {
                    entry.tags.add("parent:" + parent.getName());
                String urlPattern;
                if (mountParameters) {
                    // mounted parameters
                    urlPattern = "{0}/commit/{1}/{2}";
                } else {
                    // parameterized parameters
                    urlPattern = "{0}/commit/?r={1}&h={2}";
                }
                // add refs to tabs list
                List<RefModel> refs = allRefs.get(commit.getId());
                if (refs != null && refs.size() > 0) {
                    for (RefModel ref : refs) {
                        entry.tags.add("ref:" + ref.getName());
                List<RevCommit> commits;
                if (StringUtils.isEmpty(searchString)) {
                    // standard log/history lookup
                    commits = JGitUtils.getRevLog(repository, objectId, offset, length);
                } else {
                    // repository search
                    commits = JGitUtils.searchRevlogs(repository, objectId, searchString, searchType,
                            offset, length);
                }
                Map<ObjectId, List<RefModel>> allRefs = JGitUtils.getAllRefs(repository, model.showRemoteBranches);
                BugtraqProcessor processor = new BugtraqProcessor(settings);
                // convert RevCommit to SyndicatedEntryModel
                for (RevCommit commit : commits) {
                    FeedEntryModel entry = new FeedEntryModel();
                    entry.title = commit.getShortMessage();
                    entry.author = commit.getAuthorIdent().getName();
                    entry.link = MessageFormat.format(urlPattern, gitblitUrl,
                            StringUtils.encodeURL(model.name.replace('/', fsc)), commit.getName());
                    entry.published = commit.getCommitterIdent().getWhen();
                    entry.contentType = "text/html";
                    String message = processor.processCommitMessage(repository, model, commit.getFullMessage());
                    entry.content = message;
                    entry.repository = model.name;
                    entry.branch = objectId;
                    entry.tags = new ArrayList<String>();
                    // add commit id and parent commit ids
                    entry.tags.add("commit:" + commit.getName());
                    for (RevCommit parent : commit.getParents()) {
                        entry.tags.add("parent:" + parent.getName());
                    }
                    // add refs to tabs list
                    List<RefModel> refs = allRefs.get(commit.getId());
                    if (refs != null && refs.size() > 0) {
                        for (RefModel ref : refs) {
                            entry.tags.add("ref:" + ref.getName());
                        }
                    }
                    entries.add(entry);
                }
                entries.add(entry);
            }
        }
src/main/java/com/gitblit/utils/JGitUtils.java
@@ -1668,6 +1668,24 @@
    }
    /**
     * Returns the list of tags in the repository. If repository does not exist
     * or is empty, an empty list is returned.
     *
     * @param repository
     * @param fullName
     *            if true, /refs/tags/yadayadayada is returned. If false,
     *            yadayadayada is returned.
     * @param maxCount
     *            if < 0, all tags are returned
     * @param offset
     *            if maxCount provided sets the starting point of the records to return
     * @return list of tags
     */
    public static List<RefModel> getTags(Repository repository, boolean fullName, int maxCount, int offset) {
        return getRefs(repository, Constants.R_TAGS, fullName, maxCount, offset);
    }
    /**
     * Returns the list of local branches in the repository. If repository does
     * not exist or is empty, an empty list is returned.
     *
@@ -1748,6 +1766,27 @@
     */
    private static List<RefModel> getRefs(Repository repository, String refs, boolean fullName,
            int maxCount) {
        return getRefs(repository, refs, fullName, maxCount, 0);
    }
    /**
     * Returns a list of references in the repository matching "refs". If the
     * repository is null or empty, an empty list is returned.
     *
     * @param repository
     * @param refs
     *            if unspecified, all refs are returned
     * @param fullName
     *            if true, /refs/something/yadayadayada is returned. If false,
     *            yadayadayada is returned.
     * @param maxCount
     *            if < 0, all references are returned
     * @param offset
     *            if maxCount provided sets the starting point of the records to return
     * @return list of references
     */
    private static List<RefModel> getRefs(Repository repository, String refs, boolean fullName,
            int maxCount, int offset) {
        List<RefModel> list = new ArrayList<RefModel>();
        if (maxCount == 0) {
            return list;
@@ -1771,7 +1810,14 @@
            Collections.sort(list);
            Collections.reverse(list);
            if (maxCount > 0 && list.size() > maxCount) {
                list = new ArrayList<RefModel>(list.subList(0, maxCount));
                if (offset < 0) {
                    offset = 0;
                }
                int endIndex = offset + maxCount;
                if (endIndex > list.size()) {
                    endIndex = list.size();
                }
                list = new ArrayList<RefModel>(list.subList(offset, endIndex));
            }
        } catch (IOException e) {
            error(e, repository, "{0} failed to retrieve {1}", refs);
src/main/java/com/gitblit/utils/SyndicationUtils.java
@@ -25,6 +25,7 @@
import java.util.List;
import com.gitblit.Constants;
import com.gitblit.Constants.FeedObjectType;
import com.gitblit.GitBlitException;
import com.gitblit.models.FeedEntryModel;
import com.sun.syndication.feed.synd.SyndCategory;
@@ -137,6 +138,59 @@
     */
    public static List<FeedEntryModel> readFeed(String url, String repository, String branch,
            int numberOfEntries, int page, String username, char[] password) throws IOException {
        return readFeed(url, repository, branch, FeedObjectType.COMMIT, numberOfEntries,
                page, username, password);
    }
    /**
     * Reads tags from the specified repository.
     *
     * @param url
     *            the url of the Gitblit server
     * @param repository
     *            the repository name
     * @param branch
     *            the branch name (optional)
     * @param numberOfEntries
     *            the number of entries to retrieve. if <= 0 the server default
     *            is used.
     * @param page
     *            0-indexed. used to paginate the results.
     * @param username
     * @param password
     * @return a list of SyndicationModel entries
     * @throws {@link IOException}
     */
    public static List<FeedEntryModel> readTags(String url, String repository,
            int numberOfEntries, int page, String username, char[] password) throws IOException {
        return readFeed(url, repository, null, FeedObjectType.TAG, numberOfEntries,
                page, username, password);
    }
    /**
     * Reads a Gitblit RSS feed.
     *
     * @param url
     *            the url of the Gitblit server
     * @param repository
     *            the repository name
     * @param branch
     *            the branch name (optional)
     * @param objectType
     *            the object type to return (optional, COMMIT assummed)
     * @param numberOfEntries
     *            the number of entries to retrieve. if <= 0 the server default
     *            is used.
     * @param page
     *            0-indexed. used to paginate the results.
     * @param username
     * @param password
     * @return a list of SyndicationModel entries
     * @throws {@link IOException}
     */
    private static List<FeedEntryModel> readFeed(String url, String repository, String branch,
            FeedObjectType objectType, int numberOfEntries, int page, String username,
            char[] password) throws IOException {
        // build feed url
        List<String> parameters = new ArrayList<String>();
        if (numberOfEntries > 0) {
@@ -148,6 +202,9 @@
        if (!StringUtils.isEmpty(branch)) {
            parameters.add("h=" + branch);
        }
        if (objectType != null) {
            parameters.add("ot=" + objectType.name());
        }
        return readFeed(url, parameters, repository, branch, username, password);
    }
src/site/rpc.mkd
@@ -32,6 +32,7 @@
<tr><th>url parameter</th><th>default</th><th>description</th></tr>
<tr><td colspan='3'><b>standard query</b></td></tr>
<tr><td><em>repository</em></td><td><em>required</em></td><td>repository name is part of the url (see examples below)</td></tr>
<tr><td>ot=</td><td><em>optional</em><br/>default: COMMIT</td><td>object type to return in results. COMMIT or TAG</td></tr>
<tr><td>h=</td><td><em>optional</em><br/>default: HEAD</td><td>starting branch, ref, or commit id</td></tr>
<tr><td>l=</td><td><em>optional</em><br/>default: web.syndicationEntries</td><td>maximum return count</td></tr>
<tr><td>pg=</td><td><em>optional</em><br/>default: 0</td><td>page number for paging<br/>(offset into history = pagenumber*maximum return count)</td></tr>
src/test/java/com/gitblit/tests/SyndicationUtilsTest.java
@@ -21,7 +21,10 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import com.gitblit.Constants.SearchType;
@@ -29,6 +32,20 @@
import com.gitblit.utils.SyndicationUtils;
public class SyndicationUtilsTest extends GitblitUnitTest {
    private static final AtomicBoolean started = new AtomicBoolean(false);
    @BeforeClass
    public static void startGitblit() throws Exception {
        started.set(GitBlitSuite.startGitblit());
    }
    @AfterClass
    public static void stopGitblit() throws Exception {
        if (started.get()) {
            GitBlitSuite.stopGitblit();
        }
    }
    @Test
    public void testSyndication() throws Exception {
@@ -60,7 +77,7 @@
    }
    @Test
    public void testFeedRead() throws Exception {
    public void testFeedReadCommits() throws Exception {
        Set<String> links = new HashSet<String>();
        for (int i = 0; i < 2; i++) {
            List<FeedEntryModel> feed = SyndicationUtils.readFeed(GitBlitSuite.url, "ticgit.git",
@@ -77,6 +94,23 @@
    }
    @Test
    public void testFeedReadTags() throws Exception {
        Set<String> links = new HashSet<String>();
        for (int i = 0; i < 2; i++) {
            List<FeedEntryModel> feed = SyndicationUtils.readTags(GitBlitSuite.url, "test/gitective.git",
                    5, i, GitBlitSuite.account, GitBlitSuite.password.toCharArray());
            assertTrue(feed != null);
            assertTrue(feed.size() > 0);
            assertEquals(5, feed.size());
            for (FeedEntryModel entry : feed) {
                links.add(entry.link);
            }
        }
        // confirm we have 10 unique tags
        assertEquals("Feed pagination failed", 10, links.size());
    }
    @Test
    public void testSearchFeedRead() throws Exception {
        List<FeedEntryModel> feed = SyndicationUtils
                .readSearchFeed(GitBlitSuite.url, "ticgit.git", null, "test", null, 5, 0,