PR: MPCHANGELOG-63

Submitted By: David Jackman
Reviewed By:  Brett Porter
Add the ability to show several sets of changes
 Add ability to log based on absolute date or tag

git-svn-id: https://svn.apache.org/repos/asf/maven/maven-1/plugins/trunk@170716 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
brett 2005-05-18 07:37:34 +00:00
parent 6c8f445657
commit 67c00be2b9
17 changed files with 791 additions and 151 deletions

View File

@ -69,6 +69,27 @@
<j:set var="_connection">${pom.repository.developerConnection}</j:set>
</j:if>
<j:if test="${!empty(_connection)}">
<!-- Make sure the correct properties are set -->
<j:switch on="${maven.changelog.type}">
<j:case value="range">
<!-- It's okay not to have a range (to support Subversion on web-based repositories). -->
</j:case>
<j:case value="date">
<maven:paramCheck value="${maven.changelog.date}" fail="true">
The maven.changelog.date property is required when maven.changelog.type==date. The value should be the absolute date for the start of the log.
</maven:paramCheck>
</j:case>
<j:case value="tag">
<maven:paramCheck value="${maven.changelog.tag}" fail="true">
The maven.changelog.tag property is required when maven.changelog.type==tag. The value should be the value of the tag for the start of the log.
</maven:paramCheck>
</j:case>
<j:default>
<ant:fail>The maven.changelog.type property has an invalid value: ${maven.changelog.type} The value should be "range", "date", or "tag".</ant:fail>
</j:default>
</j:switch>
<!-- Generate the report -->
<ant:echo>Generating the changelog report</ant:echo>
<changelog:changelog
@ -77,7 +98,10 @@
factory="${maven.changelog.factory}"
output="${maven.build.dir}/changelog.xml"
outputEncoding="${maven.docs.outputencoding}"
type="${maven.changelog.type}"
range="${maven.changelog.range}"
date="${maven.changelog.date}"
tag="${maven.changelog.tag}"
repositoryConnection="${_connection}"
dateFormat="${maven.changelog.dateformat}"
/>

View File

@ -22,4 +22,8 @@
maven.changelog.basedir=${basedir}
maven.changelog.type = range
maven.changelog.range = 30
#maven.changelog.date =
#maven.changelog.tag =

View File

@ -65,6 +65,11 @@
<tag>changelog-1.7.2</tag>
</version>
</versions>
<contributors>
<contributor>
<name>David Jackman</name>
</contributor>
</contributors>
<developers>
<developer>
<name>Pete Kazmier</name>

View File

@ -22,6 +22,8 @@ import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
@ -70,11 +72,23 @@ public abstract class AbstractChangeLogGenerator implements ChangeLogGenerator,
/** The connection string from the project */
private String connection;
/** The log type (range, date, or tag). */
protected String type;
/**
* The date range.
* The date range command line argument.
*/
protected String dateRange;
/** The tag command line argument. */
protected String tag;
/** Represents when this log starts (for the report). */
protected String logStart = "";
/** Represents when this log ends (for the report). */
protected String logEnd = "";
/**
* The collection of ChangeLogEntry's returned from clParser.
@ -105,14 +119,29 @@ public abstract class AbstractChangeLogGenerator implements ChangeLogGenerator,
changeLogExecutor = changeLog;
base = changeLogExecutor.getBasedir();
// This lets the user 'not' set a limit on the log command. We
// need this cuz Subversion doesn't currently support date
// commands on web-based repositories, so it would be nice to
// let the user still use the changelog plugin.
if (changeLogExecutor.getRange() != null && changeLogExecutor.getRange().length() != 0)
type = changeLogExecutor.getType();
if (type.equalsIgnoreCase("tag"))
{
setDateRange(changeLogExecutor.getRange());
tag = getScmTagArgument(changeLogExecutor.getMarkerStart(), changeLogExecutor.getMarkerEnd());
logStart = changeLogExecutor.getMarkerStart();
logEnd = (changeLogExecutor.getMarkerEnd() == null) ? "" : changeLogExecutor.getMarkerEnd();
}
else if (type.equalsIgnoreCase("date"))
{
setDateRangeFromAbsoluteDate(changeLogExecutor.getMarkerStart(), changeLogExecutor.getMarkerEnd());
}
else // type == "range" (the default)
{
// This lets the user 'not' set a limit on the log command. We
// need this cuz Subversion doesn't currently support date
// commands on web-based repositories, so it would be nice to
// let the user still use the changelog plugin.
if (changeLogExecutor.getRange() != null && changeLogExecutor.getRange().length() != 0)
{
setDateRange(changeLogExecutor.getRange());
}
}
setConnection(changeLogExecutor.getRepositoryConnection());
@ -133,6 +162,70 @@ public abstract class AbstractChangeLogGenerator implements ChangeLogGenerator,
Date to = new Date(System.currentTimeMillis() + (long) 1 * 24 * 60 * 60 * 1000);
dateRange = getScmDateArgument(before, to);
setLogStart(before);
setLogEnd(to);
}
/**
* Set the dateRange member based on an absolute date.
* @param startDate The start date for the range.
* @param endDate The end date for the range, or <code>null</code> to use the present time.
*/
protected void setDateRangeFromAbsoluteDate(String startDate, String endDate)
{
String dateFormat = changeLogExecutor.getDateFormat();
SimpleDateFormat format = dateFormat == null ? new SimpleDateFormat("yyyy-MM-dd") : new SimpleDateFormat(dateFormat);
Date before;
try
{
before = format.parse(startDate);
}
catch (ParseException ex)
{
throw new IllegalArgumentException("Unable to parse start date " + startDate + ": " + ex.getLocalizedMessage());
}
Date to;
try
{
to = (endDate != null) ? format.parse(endDate) : new Date(System.currentTimeMillis() + (long) 1 * 24 * 60 * 60 * 1000);
}
catch (ParseException ex)
{
throw new IllegalArgumentException("Unable to parse end date " + endDate + ": " + ex.getLocalizedMessage());
}
dateRange = getScmDateArgument(before, to);
setLogStart(before);
setLogEnd(to);
}
/**
* Sets the log start string based on the given date.
* This uses the date format supplied in the plugin properties.
*
* @param start date the log started.
*/
protected void setLogStart(Date start)
{
String dateFormat = changeLogExecutor.getDateFormat();
SimpleDateFormat format = dateFormat == null ? new SimpleDateFormat("yyyy-MM-dd") : new SimpleDateFormat(dateFormat);
logStart = format.format(start);
}
/**
* Sets the log end string based on the given date.
* This uses the date format supplied in the plugin properties.
*
* @param end date the log ended.
*/
protected void setLogEnd(Date end)
{
String dateFormat = changeLogExecutor.getDateFormat();
SimpleDateFormat format = dateFormat == null ? new SimpleDateFormat("yyyy-MM-dd") : new SimpleDateFormat(dateFormat);
logEnd = format.format(end);
}
/**
@ -200,6 +293,23 @@ public abstract class AbstractChangeLogGenerator implements ChangeLogGenerator,
throw ioe;
}
/**
* @see ChangeLogGenerator#getLogStart()
*/
public String getLogStart()
{
return logStart;
}
/**
* @see ChangeLogGenerator#getLogEnd()
*/
public String getLogEnd()
{
// TODO: Auto-generated method stub
return logEnd;
}
/**
* Clean up any generated resources for this run.
*
@ -228,6 +338,17 @@ public abstract class AbstractChangeLogGenerator implements ChangeLogGenerator,
*/
protected abstract String getScmDateArgument(Date before, Date to);
/**
* Construct the command-line argument that is passed to the scm
* client to specify the appropriate tag.
*
* @param tagStart The tag name for the start of the log (log shouldn't actually contain the tag).
* @param tagEnd The tag name for the end of the log (the log can contain this tag), or <code>null</code> to
* log all changes since <code>tagStart</code>.
* @return A string that can be used to specify the tag range to a scm system.
*/
protected abstract String getScmTagArgument(String tagStart, String tagEnd);
/**
* Stop the process - currently unimplemented
*/

View File

@ -25,17 +25,18 @@ import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
// commons imports
import java.util.StringTokenizer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
// maven imports
import org.apache.maven.project.Developer;
/**
@ -54,11 +55,26 @@ import org.apache.maven.project.Developer;
*/
public class ChangeLog
{
/** Used to specify whether to build the log from a range, absolute date, or tag. */
private String type;
/**
* Used to specify the range of log entries to retrieve.
*/
private String range;
/** Used to specify the absolute date (or list of dates) to start log entries from. */
private String date;
/** Used to specify the tag (or list of tags) to start log entries from. */
private String tag;
/** This will contain the date/tag for the start of the current change set. */
private String markerStart;
/** This will contain the date/tag for the end of the current change set. */
private String markerEnd;
/**
* Used to specify the date format of log entries to retrieve.
*/
@ -83,9 +99,9 @@ public class ChangeLog
/** the list of developers on the project */
private List developers;
/** change log entries parsed */
private Collection entries;
/** change log sets parsed (sets of entries) */
private Collection sets;
/** Log */
private static final Log LOG = LogFactory.getLog(ChangeLog.class);
@ -117,9 +133,31 @@ public class ChangeLog
clFactoryClass = factoryClassName;
}
/**
* Set the type of log to generate (range, date, or tag).
*
* @param type one of "range", "date", or "tag".
*/
public void setType(String type)
{
this.type = type;
}
/**
* Get the type of log to generate (range, date, or tag).
*
* @return the basis for the log.
*/
public String getType()
{
return type;
}
/**
* Set the range of log entries to process; the interpretation of this
* parameter depends on the generator.
* This is only used if the type is "range".
*
* @param range the range of log entries.
*/
@ -138,6 +176,98 @@ public class ChangeLog
{
return range;
}
/**
* Set the date to start the log from.
* This is only used if the type is "date".
* The format is that given by the dateFormat property, if present. Otherwise, the format is "yyyy-MM-dd".
*
* @param date the date to use.
*/
public void setDate(String date)
{
this.date = date;
}
/**
* Get the date to start the log from.
*
* @return the start date.
*/
public String getDate()
{
return date;
}
/**
* Set the tag to start the log from.
* This is only used if the type is "tag".
*
* @param tag the tag to use.
*/
public void setTag(String tag)
{
this.tag = tag;
}
/**
* Get the tag to start the log from.
*
* @return the tag.
*/
public String getTag()
{
return tag;
}
/**
* Sets the marker (date or tag) for the start of the current change set.
* (This is only set internally, but also by test code.)
*
* @param marker start marker to use.
*/
public void setMarkerStart(String marker)
{
markerStart = marker;
}
/**
* Returns the marker (date or tag) for the start of the current change set.
* Whether it's a date or tag depends on {@link #getType}.
*
* @return the marker (date or tag) for the start of the current change set.
*/
public String getMarkerStart()
{
return markerStart;
}
/**
* Sets the marker (date or tag) for the end of the current change set.
* (This is only set internally, but also by test code.)
*
* @param marker end marker to use, or <code>null</code> to specify all changes since the start.
*/
public void setMarkerEnd(String marker)
{
markerEnd = marker;
}
/**
* Returns the marker (date or tag) for the end of the current change set.
* Whether it's a date or tag depends on {@link #getType}.
*
* @return the marker (date or tag) for the end of the current change set, or <code>null</code> if there is no
* end (meaning the change set should show all changes from the start to the present time).
*/
public String getMarkerEnd()
{
return markerEnd;
}
/**
* Set the date format of log entries to process; the
@ -223,7 +353,7 @@ public class ChangeLog
throw new NullPointerException("output must be set");
}
generateEntries();
generateSets();
replaceAuthorIdWithName();
createDocument();
}
@ -233,34 +363,73 @@ public class ChangeLog
* @throws IOException if there is a problem creating the change log
* entries.
*/
private void generateEntries() throws IOException
private void generateSets() throws IOException
{
ChangeLogFactory factory = createFactory();
ChangeLogGenerator generator = factory.createGenerator();
ChangeLogParser parser = factory.createParser();
if (getDateFormat() != null)
String markers = "";
if (getType().equalsIgnoreCase("tag"))
{
parser.setDateFormatInFile(getDateFormat());
markers = getTag();
}
generator.init(this);
parser.init(this);
else if (getType().equalsIgnoreCase("date"))
{
markers = getDate();
}
else
{
markers = getRange();
}
try
{
setEntries(generator.getEntries(parser));
if (LOG.isInfoEnabled()) {
LOG.info("ChangeLog found: " + getEntries().size()
+ " entries");
}
} catch (IOException e) {
LOG.warn(e.getLocalizedMessage(), e);
throw e;
StringTokenizer tokens = new StringTokenizer(markers, ",");
sets = new ArrayList(tokens.countTokens());
String end = tokens.nextToken();
do
{
String start = end;
end = (tokens.hasMoreTokens()) ? tokens.nextToken() : null;
setMarkerStart(start);
setMarkerEnd(end);
ChangeLogParser parser = factory.createParser();
if (getDateFormat() != null)
{
parser.setDateFormatInFile(getDateFormat());
}
parser.init(this);
ChangeLogGenerator generator = factory.createGenerator();
generator.init(this);
Collection entries;
String logStart;
String logEnd;
try
{
entries = generator.getEntries(parser);
logStart = generator.getLogStart();
logEnd = generator.getLogEnd();
} catch (IOException e) {
LOG.warn(e.getLocalizedMessage(), e);
throw e;
}
finally
{
generator.cleanup();
parser.cleanup();
}
sets.add(new ChangeLogSet(entries, logStart, logEnd));
if (LOG.isInfoEnabled()) {
LOG.info("ChangeSet between " + logStart + " and " + logEnd + ": "
+ entries.size() + " entries");
}
} while (end != null);
}
finally
{
parser.cleanup();
generator.cleanup();
}
}
@ -339,12 +508,17 @@ public class ChangeLog
{
Properties userList = getUserList();
ChangeLogEntry entry = null;
for (Iterator i = getEntries().iterator(); i.hasNext();)
for (final Iterator iSets = getChangeSets().iterator() ; iSets.hasNext() ;)
{
entry = (ChangeLogEntry) i.next();
if (userList.containsKey(entry.getAuthor()))
final ChangeLogSet set = (ChangeLogSet)iSets.next();
for (Iterator iEntries = set.getEntries().iterator(); iEntries.hasNext();)
{
entry.setAuthor(userList.getProperty(entry.getAuthor()));
entry = (ChangeLogEntry) iEntries.next();
if (userList.containsKey(entry.getAuthor()))
{
entry.setAuthor(userList.getProperty(entry.getAuthor()));
}
}
}
}
@ -381,9 +555,9 @@ public class ChangeLog
.append("\" ?>\n")
.append("<changelog>\n");
for (Iterator i = getEntries().iterator(); i.hasNext();)
for (Iterator i = getChangeSets().iterator(); i.hasNext();)
{
buffer.append(((ChangeLogEntry) i.next()).toXML());
buffer.append(((ChangeLogSet) i.next()).toXML());
}
buffer.append("</changelog>\n");
@ -392,25 +566,26 @@ public class ChangeLog
}
/**
* Getter for property entries.
* @return Value of property entries.
* Gets the collection of change sets.
*
* @return collection of {@link ChangeLogSet} objects.
*/
public Collection getEntries()
public Collection getChangeSets()
{
if (entries == null)
if (sets == null)
{
entries = Arrays.asList(new Object[0]);
sets = Collections.EMPTY_LIST;
}
return entries;
return sets;
}
/**
* Setter for property entries.
* @param entries New value of property entries.
* Sets the collection of change sets.
* @param sets New value of property sets.
*/
public void setEntries(Collection entries)
public void setChangeSets(Collection sets)
{
this.entries = entries;
this.sets = sets;
}
/**

View File

@ -59,6 +59,22 @@ public interface ChangeLogGenerator
*/
Collection getEntries(ChangeLogParser parser) throws IOException;
/**
* Return a string indicating the start of the entries.
* This will usually be a date or a tag.
*
* @return a string indicating the start of the entries.
*/
String getLogStart();
/**
* Return a string indicating the end of the entries.
* This will usually be a date or a tag.
*
* @return a string indicating the end of the entries.
*/
String getLogEnd();
/**
* Provides the opportunity for the generator to do any required cleanup.
* This method is guaranteed to be called after the getEntries method even

View File

@ -0,0 +1,109 @@
package org.apache.maven.changelog;
/* ====================================================================
* Copyright 2001-2004 The Apache Software Foundation.
*
* 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.
* ====================================================================
*/
import java.io.Writer;
import java.util.Collection;
import java.util.Iterator;
/**
* Change Log Set - holds details about a set of change log entries.
*
* @author <a href="mailto:david.jackman@fastsearch.com">David Jackman</a>
* @version $$
*/
public class ChangeLogSet
{
private final Collection entries;
private final String start;
private final String end;
/**
* Initializes a new instance of this class.
*
* @param entries collection of {@link ChangeLogEntry} objects for this set.
* @param start the start date/tag for this set.
* @param end the end date/tag for this set, or <code>null</code> if this set goes to the present time.
*/
public ChangeLogSet(Collection entries, String start, String end)
{
this.entries = entries;
this.start = start;
this.end = end;
}
/**
* Returns the collection of entries for this set.
*
* @return the collection of {@link ChangeLogEntry} objects for this set.
*/
public Collection getEntries()
{
return entries;
}
/**
* Returns the start date/tag for this set.
*
* @return the start date/tag for this set.
*/
public String getStart()
{
return start;
}
/**
* Returns the end date/tag for this set.
*
* @return the end date/tag for this set, or <code>null</code> if this set goes to the present time.
*/
public String getEnd()
{
return end;
}
/**
* Creates an XML representation of this change log set.
*/
public String toXML()
{
StringBuffer buffer = new StringBuffer();
buffer.append("<changeset start=\"")
.append(start)
.append("\" end=\"")
.append(end)
.append("\">\n");
// Write out the entries
for (Iterator i = getEntries().iterator(); i.hasNext();)
{
buffer.append(((ChangeLogEntry) i.next()).toXML());
}
buffer.append("</changeset>\n");
return buffer.toString();
}
}

View File

@ -99,4 +99,11 @@ public class ClearcaseChangeLogGenerator extends AbstractChangeLogGenerator {
return argument;
}
/**
* @see AbstractChangeLogGenerator#getScmTagArgument(String, String)
*/
protected String getScmTagArgument(String tagStart, String tagEnd)
{
throw new UnsupportedOperationException("This plugin currently does not support generating logs from tags with Clearcase.");
}
}

View File

@ -178,6 +178,10 @@ class CvsChangeLogGenerator extends AbstractChangeLogGenerator
{
command.createArgument().setValue(dateRange);
}
else if (tag != null)
{
command.createArgument().setValue(tag);
}
return command;
}
@ -195,6 +199,14 @@ class CvsChangeLogGenerator extends AbstractChangeLogGenerator
SimpleDateFormat outputDate = new SimpleDateFormat("yyyy-MM-dd");
return "-d " + outputDate.format(before) + "<" + outputDate.format(to);
}
/**
* @see AbstractChangeLogGenerator#getScmTagArgument(String, String)
*/
protected String getScmTagArgument(String tagStart, String tagEnd)
{
return "-r" + tagStart + "::" + (tagEnd != null ? tagEnd : "");
}
/**
* Handle ChangeLogParser IOExceptions.

View File

@ -418,6 +418,7 @@ public class CvsConnection
cvsCommand.connect(root, password);
cvsCommand.addListener(listener);
LOG.debug("Executing CVS command: " + c.getCVSCommand());
cvsCommand.executeCommand(c);

View File

@ -109,4 +109,12 @@ class PerforceChangeLogGenerator extends AbstractChangeLogGenerator
throw ioe;
}
}
/**
* @see AbstractChangeLogGenerator#getScmTagArgument(String, String)
*/
protected String getScmTagArgument(String tagStart, String tagEnd)
{
throw new UnsupportedOperationException("This plugin currently does not support generating logs from tags with Perforce.");
}
}

View File

@ -79,6 +79,14 @@ class StarteamChangeLogGenerator extends AbstractChangeLogGenerator
return "";
}
/**
* @see AbstractChangeLogGenerator#getScmTagArgument(String, String)
*/
protected String getScmTagArgument(String tagStart, String tagEnd)
{
throw new UnsupportedOperationException("This plugin currently does not support generating logs from tags with Starteam.");
}
/**
* Handle ChangeLogParser IOExceptions.
*

View File

@ -88,6 +88,14 @@ class SvnChangeLogGenerator extends AbstractChangeLogGenerator
outputDate.format(before) + "}\"";
}
/**
* @see AbstractChangeLogGenerator#getScmTagArgument(String, String)
*/
protected String getScmTagArgument(String tagStart, String tagEnd)
{
throw new UnsupportedOperationException("This plugin currently does not support generating logs from tags with Subversion.");
}
/**
* Handle ChangeLogParser IOExceptions.
*

View File

@ -36,89 +36,112 @@
<body>
<section name="Changelog Report">
<p>
<!-- The range needs to be fed in somehow. -->
Timeframe: ${maven.changelog.range} days,
Total Commits:
<x:expr select="count(./changelog-entry)"/>
Total Number of Files Changed:
<x:expr select="count(./changelog-entry/file)"/>
Total number of change sets:
<x:expr select="count(./changeset)" />
</p>
<table>
<thead>
<tr>
<th>Date</th>
<th>Author</th>
<th>File/Message</th>
</tr>
</thead>
<tbody>
<x:set var="changes" select="changelog-entry"/>
<j:forEach var="change" items="${changes}">
<tr>
<td>
<x:expr select="$change/date"/>
<x:expr select="$change/time"/>
</td>
<td>
<x:expr select="$change/author"/>
</td>
<td>
<x:forEach var="file" select="$change/file">
<p>
<j:set var="name"><x:expr select="$file/name"/></j:set>
<j:set var="revision"><x:expr select="$file/revision"/></j:set>
<j:set var="repositoryUrl" value="${pom.repository.url}"/>
<j:choose>
<j:when test="${!empty(repositoryUrl) and repositoryUrl.indexOf('?')>0}">
<j:set var="repository" value="${repositoryUrl.substring(0, repositoryUrl.indexOf('?'))}"/>
<j:set var="tmpMultiRepoParam" value="${repositoryUrl.substring(repository.length())}"/>
<j:set var="oneRepoParam" value="?${tmpMultiRepoParam.substring(1)}"/>
<j:set var="multiRepoParam" value="&amp;${tmpMultiRepoParam.substring(1)}"/>
</j:when>
<j:otherwise>
<j:set var="repository" value="${repositoryUrl}"/>
<j:set var="oneRepoParam" value=""/>
<j:set var="multiRepoParam" value=""/>
</j:otherwise>
</j:choose>
<j:choose>
<j:when test="${pom.repository.connection.startsWith('scm:perforce')}">
<a href="${repository}${name}?ac=22">${name}</a>
<a href="${repository}${name}?ac=64&amp;rev1=${revision}">v${revision}</a>
</j:when>
<j:otherwise>
<a href="${repository}${name}${oneRepoParam}">${name}</a>
<a href="${repository}${name}?rev=${revision}&amp;content-type=text/vnd.viewcvs-markup${multiRepoParam}">v${revision}</a>
</j:otherwise>
</j:choose>
</p>
</x:forEach>
<!-- This works -->
<x:expr select="$change/msg"/>
<!-- But this does not work ?
<j:set var="msg"><x:expr select="$change/msg"/></j:set>
${msg}
${escape.getText(msg)}
Something to track down. Probably not going to be much
html in the changelog entries any way.
-->
</td>
</tr>
</j:forEach>
</tbody>
</table>
<jsl:applyTemplates select="changeset" />
</section>
</body>
</document>
</jsl:template>
<jsl:template match="changeset">
<j:set var="logstart"><x:expr select="@start"/></j:set>
<j:set var="logend"><x:expr select="@end"/></j:set>
<j:choose>
<j:when test="${empty(logstart) and empty(logend)}">
<j:set var="setname">Changes from an unknown range</j:set>
</j:when>
<j:when test="${empty(logend)}">
<j:set var="setname">Changes since ${logstart}</j:set>
</j:when>
<j:otherwise>
<j:set var="setname">Changes between ${logstart} and ${logend}</j:set>
</j:otherwise>
</j:choose>
<subsection name="${setname}">
<p>
Total Commits:
<x:expr select="count(./changelog-entry)"/>
Total Number of Files Changed:
<x:expr select="count(./changelog-entry/file)"/>
</p>
<table>
<thead>
<tr>
<th>Date</th>
<th>Author</th>
<th>File/Message</th>
</tr>
</thead>
<tbody>
<x:set var="changes" select="changelog-entry"/>
<j:forEach var="change" items="${changes}">
<tr>
<td>
<x:expr select="$change/date"/>
<x:expr select="$change/time"/>
</td>
<td>
<x:expr select="$change/author"/>
</td>
<td>
<x:forEach var="file" select="$change/file">
<p>
<j:set var="name"><x:expr select="$file/name"/></j:set>
<j:set var="revision"><x:expr select="$file/revision"/></j:set>
<j:set var="repositoryUrl" value="${pom.repository.url}"/>
<j:choose>
<j:when test="${!empty(repositoryUrl) and repositoryUrl.indexOf('?')>0}">
<j:set var="repository" value="${repositoryUrl.substring(0, repositoryUrl.indexOf('?'))}"/>
<j:set var="tmpMultiRepoParam" value="${repositoryUrl.substring(repository.length())}"/>
<j:set var="oneRepoParam" value="?${tmpMultiRepoParam.substring(1)}"/>
<j:set var="multiRepoParam" value="&amp;${tmpMultiRepoParam.substring(1)}"/>
</j:when>
<j:otherwise>
<j:set var="repository" value="${repositoryUrl}"/>
<j:set var="oneRepoParam" value=""/>
<j:set var="multiRepoParam" value=""/>
</j:otherwise>
</j:choose>
<j:choose>
<j:when test="${pom.repository.connection.startsWith('scm:perforce')}">
<a href="${repository}${name}?ac=22">${name}</a>
<a href="${repository}${name}?ac=64&amp;rev1=${revision}">v${revision}</a>
</j:when>
<j:otherwise>
<a href="${repository}${name}${oneRepoParam}">${name}</a>
<a href="${repository}${name}?rev=${revision}&amp;content-type=text/vnd.viewcvs-markup${multiRepoParam}">v${revision}</a>
</j:otherwise>
</j:choose>
</p>
</x:forEach>
<!-- This works -->
<x:expr select="$change/msg"/>
<!-- But this does not work ?
<j:set var="msg"><x:expr select="$change/msg"/></j:set>
${msg}
${escape.getText(msg)}
Something to track down. Probably not going to be much
html in the changelog entries any way.
-->
</td>
</tr>
</j:forEach>
</tbody>
</table>
</subsection>
</jsl:template>
</jsl:stylesheet>

View File

@ -17,7 +17,13 @@ package org.apache.maven.cvslib;
* ====================================================================
*/
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import org.apache.maven.changelog.ChangeLog;
import org.apache.maven.util.EnhancedStringTokenizer;
import org.apache.maven.util.RepositoryUtils;
import org.apache.tools.ant.types.Commandline;
@ -48,52 +54,117 @@ public class CvsChangeLogGeneratorTest extends TestCase
String conn;
String args;
Class throwable;
public Test(String conn, String args, Class throwable)
Map map;
public Test(String params, String conn, String args, Class throwable)
{
this.conn = conn;
this.args = args;
this.throwable = throwable;
this.map = null;
if (params != null)
{
map = new HashMap();
StringTokenizer tokens = new StringTokenizer(params, "|");
while (tokens.hasMoreTokens())
{
String name = tokens.nextToken();
assertTrue("params must have an even number of values.", tokens.hasMoreTokens());
String value = tokens.nextToken();
map.put(name, value);
}
}
}
}
static SimpleDateFormat standardFormat = new SimpleDateFormat("yyyy-MM-dd");
static String now = standardFormat.format(new Date(System.currentTimeMillis() + (long) 1 * 24 * 60 * 60 * 1000));
static String range30 = standardFormat.format(new Date(System.currentTimeMillis() - (long) 30 * 24 * 60 * 60 * 1000));
static String range10 = standardFormat.format(new Date(System.currentTimeMillis() - (long) 10 * 24 * 60 * 60 * 1000));
Test[] tests =
{
new Test(null, "", NullPointerException.class),
new Test("asd:asd", "", IllegalArgumentException.class),
new Test(null, null, "", NullPointerException.class),
new Test(null, "asd:asd", "", IllegalArgumentException.class),
new Test(null, null, "", NullPointerException.class),
new Test(null, "asd:asd", "", IllegalArgumentException.class),
new Test(
null,
"scm:csvs:pserver:anoncvs@cvs.apache.org:/home/cvspublic:maven",
"",
IllegalArgumentException.class),
new Test(
null,
"scm:cvs:pserver:anoncvs@cvs.apache.org:/home/cvspublic:maven",
"cvs|-d|:pserver:anoncvs@cvs.apache.org:/home/cvspublic|log",
null),
new Test(
null,
"scm:cvs:pserver:anoncvs@cvs.apache.org:/home/cvspublic:maven:anoncvs",
"",
IllegalArgumentException.class),
new Test(
null,
"scm|cvs|pserver|anoncvs@cvs.apache.org|D:\\home\\cvspublic|maven",
"cvs|-d|:pserver:anoncvs@cvs.apache.org:D:\\home\\cvspublic|log",
null),
new Test(
null,
"scm|cvs|pserver|anoncvs@cvs.apache.org|D:/home/cvspublic|maven",
"cvs|-d|:pserver:anoncvs@cvs.apache.org:D:/home/cvspublic|log",
null),
new Test(
null,
"scm:cvs:lserver:anoncvs@cvs.apache.org:/home/cvspublic:maven",
"cvs|-d|anoncvs@cvs.apache.org:/home/cvspublic|log",
null) ,
new Test(
null,
"scm|cvs|local|local|D:/home/cvspublic|maven",
"cvs|-d|D:/home/cvspublic|log",
null),
new Test(
"scm:cvs:extssh:someuser@cvs.apache.org:/home/cvs:maven",
"cvs|-d|:extssh:someuser@cvs.apache.org:/home/cvs|log",
null)};
new Test(
null,
"scm:cvs:extssh:someuser@cvs.apache.org:/home/cvs:maven",
"cvs|-d|:extssh:someuser@cvs.apache.org:/home/cvs|log",
null),
new Test(
"type|range|range|30",
"scm:cvs:pserver:anoncvs@cvs.apache.org:/home/cvspublic:maven",
"cvs|-d|:pserver:anoncvs@cvs.apache.org:/home/cvspublic|log|-d " + range30 + "<" + now,
null),
new Test(
"type|range|range|10",
"scm:cvs:pserver:anoncvs@cvs.apache.org:/home/cvspublic:maven",
"cvs|-d|:pserver:anoncvs@cvs.apache.org:/home/cvspublic|log|-d " + range10 + "<" + now,
null),
new Test(
"type|date|start|2004-04-01",
"scm:cvs:pserver:anoncvs@cvs.apache.org:/home/cvspublic:maven",
"cvs|-d|:pserver:anoncvs@cvs.apache.org:/home/cvspublic|log|-d 2004-04-01<" + now,
null),
new Test(
"type|date|start|1996-06-12",
"scm:cvs:pserver:anoncvs@cvs.apache.org:/home/cvspublic:maven",
"cvs|-d|:pserver:anoncvs@cvs.apache.org:/home/cvspublic|log|-d 1996-06-12<" + now,
null),
new Test(
"type|date|start|1996-06-12|end|1998-05-13",
"scm:cvs:pserver:anoncvs@cvs.apache.org:/home/cvspublic:maven",
"cvs|-d|:pserver:anoncvs@cvs.apache.org:/home/cvspublic|log|-d 1996-06-12<1998-05-13",
null),
new Test(
"type|tag|start|my_tag_name",
"scm:cvs:pserver:anoncvs@cvs.apache.org:/home/cvspublic:maven",
"cvs|-d|:pserver:anoncvs@cvs.apache.org:/home/cvspublic|log|-rmy_tag_name::",
null),
new Test(
"type|tag|start|my_tag_name|end|end_tag_name",
"scm:cvs:pserver:anoncvs@cvs.apache.org:/home/cvspublic:maven",
"cvs|-d|:pserver:anoncvs@cvs.apache.org:/home/cvspublic|log|-rmy_tag_name::end_tag_name",
null),
};
public void testParse() throws Throwable
{
@ -101,36 +172,49 @@ public class CvsChangeLogGeneratorTest extends TestCase
{
Test t = tests[i];
testParse(t);
testParse(t, i);
}
}
public void testParse(Test test) throws Throwable
public void testParse(Test test, int index) throws Throwable
{
String[] expected = RepositoryUtils.tokenizerToArray(new EnhancedStringTokenizer(test.args, "|"));
ExposeGenerator eg = new ExposeGenerator();
try
{
eg.setConnection(test.conn);
ChangeLog changelog = new ChangeLog();
if (test.map != null)
{
changelog.setType((String)test.map.get("type"));
changelog.setRange((String)test.map.get("range"));
changelog.setMarkerStart((String)test.map.get("start"));
changelog.setMarkerEnd((String)test.map.get("end"));
changelog.setDateFormat((String)test.map.get("dateformat"));
}
else
{
changelog.setType("range");
}
changelog.setRepositoryConnection(test.conn);
eg.init(changelog);
Commandline cl = eg.getScmLogCommand();
String[] clArgs = cl.getCommandline();
if (test.throwable == null)
{
assertEquals("clArgs.length", expected.length, clArgs.length);
assertEquals("index " + index + ": clArgs.length", expected.length, clArgs.length);
for (int i = 0; i < expected.length; i++)
{
assertEquals("clArgs[" + i + "]", expected[i], clArgs[i]);
assertEquals("index " + index + ": clArgs[" + i + "]", expected[i], clArgs[i]);
}
}
else
{
fail("Failed to throw :" + test.throwable.getName());
fail("index " + index + ": Failed to throw :" + test.throwable.getName());
}
}
catch (Throwable t)
catch (Exception t)
{
if (test.throwable != null && test.throwable.isAssignableFrom(t.getClass()))
{
@ -138,7 +222,7 @@ public class CvsChangeLogGeneratorTest extends TestCase
}
else
{
throw new RuntimeException("Caught unexpected exception \"" + t.getLocalizedMessage() + "\" testing " + test.conn);
throw new RuntimeException("Caught unexpected exception \"" + t.getLocalizedMessage() + "\" testing " + test.conn + " (index " + index + ")", t);
}
}

View File

@ -26,6 +26,7 @@
</properties>
<body>
<release version="1.8-SNAPSHOT" date="in SVN">
<action dev="brett" type="fix" issue="MPCHANGELOG-63" due-to="David Jackman">Add the ability to show several sets of changes</action>
<action dev="brett" type="fix" issue="MPCHANGELOG-23">Guess factory from connection</action>
<action dev="brett" type="fix">Allow local CVSROOT to only have 5 tokens (no host name)</action>
</release>

View File

@ -41,15 +41,49 @@
<code>basedir</code>.
</td>
</tr>
<tr>
<td>maven.changelog.type</td>
<td>Yes</td>
<td>
Indicates what the change log is based on.
This is used by the "changelog" goal.
Possible values are: <code>range</code> (meaning a date range),
<code>date</code> (meaning an absolute date),
or <code>tag</code> (meaning a tag).
The default value is <code>range</code>.
</td>
</tr>
<tr>
<td>maven.changelog.range</td>
<td>Yes</td>
<td>
Specifies the range to use when generating the change log.
This is used by the "changelog" goal. The default value is
This is used by the "changelog" goal if the maven.changelog.type
property is "range". The default value is
<code>30</code> days.
</td>
</tr>
<tr>
<td>maven.changelog.date</td>
<td>No (if type==date)</td>
<td>
Specifies an absolute date to use when generating the change log.
This is used by the "changelog" goal if the maven.changelog.type
property is "date". The log will contain changes made after this date.
The date format is that specified by maven.changelog.dateformat if
present; otherwise, the format is yyyy-MM-dd.
</td>
</tr>
<tr>
<td>maven.changelog.tag</td>
<td>No (if type==tag)</td>
<td>
Specifies the range to use when generating the change log.
This is used by the "changelog" goal if the maven.changelog.type
property is "tag". The log will contain changes made after this
tag. Currently, this is supported for CVS only.
</td>
</tr>
<tr>
<td>maven.changelog.factory</td>
<td>Yes</td>
@ -87,7 +121,7 @@
<td>maven.changelog.dateformat</td>
<td>Yes</td>
<td>
The date format in input stream. It's only used by Starteam changelog.
The date format in input stream. It's only used by Starteam changelog and/or when specifying an absolute date.
</td>
</tr>
</table>