@@ -13,9 +13,11 @@ r24: { | |||
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 | |||
} | |||
# |
@@ -402,6 +402,27 @@ public class Constants { | |||
} | |||
} | |||
/** | |||
* 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. | |||
*/ |
@@ -163,6 +163,15 @@ public class SyndicationServlet extends DaggerServlet { | |||
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 @@ public class SyndicationServlet extends DaggerServlet { | |||
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 @@ public class SyndicationServlet extends DaggerServlet { | |||
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); | |||
} | |||
} | |||
@@ -1667,6 +1667,24 @@ public class JGitUtils { | |||
return getRefs(repository, Constants.R_TAGS, fullName, maxCount); | |||
} | |||
/** | |||
* 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 @@ public class JGitUtils { | |||
*/ | |||
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 @@ public class JGitUtils { | |||
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); |
@@ -25,6 +25,7 @@ import java.util.ArrayList; | |||
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 class SyndicationUtils { | |||
*/ | |||
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 @@ public class SyndicationUtils { | |||
if (!StringUtils.isEmpty(branch)) { | |||
parameters.add("h=" + branch); | |||
} | |||
if (objectType != null) { | |||
parameters.add("ot=" + objectType.name()); | |||
} | |||
return readFeed(url, parameters, repository, branch, username, password); | |||
} | |||
@@ -32,6 +32,7 @@ The Gitblit API includes methods for retrieving and interpreting RSS feeds. The | |||
<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> |
@@ -21,7 +21,10 @@ import java.util.Date; | |||
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; | |||
@@ -30,6 +33,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 { | |||
List<FeedEntryModel> entries = new ArrayList<FeedEntryModel>(); | |||
@@ -60,7 +77,7 @@ public class SyndicationUtilsTest extends GitblitUnitTest { | |||
} | |||
@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", | |||
@@ -76,6 +93,23 @@ public class SyndicationUtilsTest extends GitblitUnitTest { | |||
assertEquals("Feed pagination failed", 10, links.size()); | |||
} | |||
@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 |