Index: C:/dev/maven-continuum/continuum-1.0.2/continuum-web/src/main/java/org/apache/maven/continuum/web/tool/RssFormatterTool.java =================================================================== --- C:/dev/maven-continuum/continuum-1.0.2/continuum-web/src/main/java/org/apache/maven/continuum/web/tool/RssFormatterTool.java (revision 0) +++ C:/dev/maven-continuum/continuum-1.0.2/continuum-web/src/main/java/org/apache/maven/continuum/web/tool/RssFormatterTool.java (revision 0) @@ -0,0 +1,134 @@ +package org.apache.maven.continuum.web.tool; + +/* + * Copyright 2004-2005 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 org.apache.maven.continuum.project.ContinuumProjectState; +import java.util.Date; +import java.text.DateFormat; +import java.text.SimpleDateFormat; + +/** + * @author John Didion + * @version $Id: $ + */ +public class RssFormatterTool { + private static final String formatString = "E, dd MMM yyyy HH:mm:ss z"; + private static final DateFormat format; + + static { + format = new SimpleDateFormat(formatString); + } + + // TODO: Add i18n + public String formatProjectState( int state ) + { + if ( state == ContinuumProjectState.NEW ) + { + return "New"; + } + else if ( state == ContinuumProjectState.OK ) + { + return "Ok"; + } + else if ( state == ContinuumProjectState.FAILED ) + { + return "Failed"; + } + else if ( state == ContinuumProjectState.ERROR ) + { + return "Error"; + } + else if ( state == ContinuumProjectState.BUILDING ) + { + return "Building"; + } + else + { + return "Unknown project state '" + state + "'"; + } + } + + public String formatTrigger( int trigger ) + { + if ( trigger == ContinuumProjectState.TRIGGER_UNKNOWN ) + { + // TODO: fix this + return "Schedule"; + } + else if ( trigger == ContinuumProjectState.TRIGGER_FORCED ) + { + return "Forced"; + } + else + { + return "Unknown build trigger: '" + trigger + "'"; + } + } + + public String formatTimestamp( long timestamp ) + { + return format.format( new Date( timestamp ) ); + } + + public String formatInterval( long start, long end ) + { + long diff = end - start; + + long interval = diff / 1000L; + + long hours = interval / 3600L; + + interval -= hours * 3600; + + long minutes = interval / 60; + + interval -= minutes * 60; + + long seconds = interval; + + if ( hours > 0 ) + { + return Long.toString( hours ) + "h " + Long.toString( minutes ) + "m " + Long.toString( seconds ) + "s"; + } + + if ( minutes > 0 ) + { + return Long.toString( minutes ) + "m " + Long.toString( seconds ) + "s"; + } + + return Long.toString( seconds ) + "s"; + } + + public String formatStateImage(int state) { + String icon = null; + + if ( state == ContinuumProjectState.OK ) + { + icon = "icon_success_sml.gif"; + } + else if ( state == ContinuumProjectState.FAILED ) + { + icon = "icon_warning_sml.gif"; + } + else if ( state == ContinuumProjectState.ERROR ) + { + icon = "icon_error_sml.gif"; + } + + return icon; + } +} \ No newline at end of file Index: C:/dev/maven-continuum/continuum-1.0.2/continuum-web/src/main/java/org/apache/maven/continuum/web/tool/XmlLinkTool.java =================================================================== --- C:/dev/maven-continuum/continuum-1.0.2/continuum-web/src/main/java/org/apache/maven/continuum/web/tool/XmlLinkTool.java (revision 0) +++ C:/dev/maven-continuum/continuum-1.0.2/continuum-web/src/main/java/org/apache/maven/continuum/web/tool/XmlLinkTool.java (revision 0) @@ -0,0 +1,115 @@ +package org.apache.maven.continuum.web.tool; + +/* + * Copyright 2004-2005 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 org.codehaus.plexus.summit.pull.tools.TemplateLink; + +/** + * @author John Didion + * @version $Id: $ + */ +public class XmlLinkTool extends TemplateLink { + private String image; + + public XmlLinkTool setImage(String image) { + this.image = image; + return this; + } + + public String toString() { + String s = toStringImpl(); + refresh(); + return s; + } + + public String getURI() { + return toStringImpl(); + } + + /* (non-Javadoc) + * @see org.codehaus.plexus.summit.util.UriBuilder#refresh() + */ + public void refresh() { + super.refresh(); + this.image = null; + } + + private String toStringImpl() { + StringBuffer output = new StringBuffer(); + if ( !isRelative() ) + { + output.append( data.getServerScheme() ); + output.append( "://" ); + output.append( data.getServerName() ); + if ( ( data.getServerScheme().equals( HTTP ) && + data.getServerPort() != 80 ) || + ( data.getServerScheme().equals( HTTPS ) && + data.getServerPort() != 443 ) ) + { + output.append( ':' ); + output.append( data.getServerPort() ); + } + } + + output.append( data.getContextPath() ); + + if (null != this.image) { + output.append("/images/").append(this.image); + } else { + output.append( data.getScriptName() ); + + if ( this.hasPathInfo() ) + { + output.append( '/' ); + renderPathInfo( this.pathInfo, output ); + } + if ( this.hasQueryData() ) + { + output.append( '?' ); + renderQueryString( this.queryData, output ); + } + } + + // There seems to be a bug in Apache JServ 1.0 where the + // session id is not appended to the end of the url when a + // cookie has not been set. + String url = null; + if ( this.res != null && isEncodeUrl() ) + { + if ( this.redirect ) + { + url = res.encodeRedirectURL( output.toString() ); + } + else + { + url = res.encodeURL( output.toString() ); + } + } + else + { + url = output.toString(); + } + return escape(url); + } + + private String escape(String s) { + if (null == s) { + return null; + } + return s.replaceAll("&", "&"); + } +} \ No newline at end of file Index: C:/dev/maven-continuum/continuum-1.0.2/continuum-web/src/main/resources/META-INF/plexus/components.xml =================================================================== --- C:/dev/maven-continuum/continuum-1.0.2/continuum-web/src/main/resources/META-INF/plexus/components.xml (revision 379571) +++ C:/dev/maven-continuum/continuum-1.0.2/continuum-web/src/main/resources/META-INF/plexus/components.xml (working copy) @@ -96,6 +96,11 @@ global + rssFormatter + rssFormatterTool + global + + trigger org.codehaus.plexus.formica.web.ContentGenerator continuum-trigger @@ -121,11 +126,22 @@ org.apache.maven.continuum.web.tool.StringTool global + + xmlLink + xmlLinkTool + request + + xmlLinkTool + org.apache.maven.continuum.web.tool.XmlLinkTool + per-lookup + + + datetool org.apache.maven.continuum.web.tool.DateTool @@ -139,6 +155,12 @@ + rssFormatterTool + org.apache.maven.continuum.web.tool.RssFormatterTool + + + + org.apache.maven.continuum.web.tool.FormDataTool org.apache.maven.continuum.web.tool.FormDataTool @@ -207,6 +229,24 @@ + + RSS + + + project + getProject(#id) + + + builds + getBuildResultsForProject(#id) + + + + Index: C:/dev/maven-continuum/continuum-1.0.2/continuum-web/src/main/resources/templates/layouts/RSS.vm =================================================================== --- C:/dev/maven-continuum/continuum-1.0.2/continuum-web/src/main/resources/templates/layouts/RSS.vm (revision 0) +++ C:/dev/maven-continuum/continuum-1.0.2/continuum-web/src/main/resources/templates/layouts/RSS.vm (revision 0) @@ -0,0 +1,2 @@ +$data.response.setContentType("text/xml") +$screenViewContent \ No newline at end of file Index: C:/dev/maven-continuum/continuum-1.0.2/continuum-web/src/main/resources/templates/screens/RSS.vm =================================================================== --- C:/dev/maven-continuum/continuum-1.0.2/continuum-web/src/main/resources/templates/screens/RSS.vm (revision 0) +++ C:/dev/maven-continuum/continuum-1.0.2/continuum-web/src/main/resources/templates/screens/RSS.vm (revision 0) @@ -0,0 +1,87 @@ +### TODO: is it possible to specify the ttl element using schedule information? +#set($channelTitle="${project.name} Builds") +#set($channelLink=$xmlLink.setPage('ProjectBuilds.vm').addPathInfo('view', "ProjectBuilds").addPathInfo('id', $project.id).toString()) + + + ${channelTitle} + ${channelLink} + Continuum build server results for ${project.name}. + Continuum + ${i18n.defaultLanguage} +#if(!$builds.isEmpty()) +#set($last=$builds.get(0)) + ${rssFormatter.formatTimestamp($last.endTime)} + ${rssFormatter.formatTimestamp($last.endTime)} +#end +### TODO: it would be cool to support this, though I'm not exactly sure where +### the cloud config would reside. One possibility is to make continuum itself +### a cloud server, adding the register procedure to the XML api. Then we could +### add a RssCloudNotifier, and here we could just loop through a project's +### notifiers to see if one of them is a RssCloudNotifier, and, if so, use its +### config to fill in the attributes. +###if() +## +###end +#set($imageFile=$rssFormatter.formatStateImage($project.state)) +#if($imageFile) + + ${xmlLink.setImage($imageFile)} + ${channelTitle} + ${channelLink} + +#end + + ${project.name} + $!{project.description} + ${project.groupId} + ${project.version} + ${project.executorId} + $!{project.url} + ${project.state} + ${rssFormatter.formatProjectState($project.state)} + #if($imageFile)${xmlLink.setImage($imageFile)}#end + ${project.buildNumber} + +#foreach($build in $builds) +#set($imageFile=$rssFormatter.formatStateImage($build.state)) + + ${rssFormatter.formatTimestamp($build.startTime)} ($rssFormatter.formatProjectState($build.state)) + ${xmlLink.setPage('ProjectBuild.vm').addQueryData('view','ProjectBuild').addQueryData('buildId',$build.id).addQueryData('id',$project.id)} + Results for build started at ${rssFormatter.formatTimestamp($build.startTime)}. + ${rssFormatter.formatTimestamp($build.endTime)} + + #if($build.state == 2)${build.buildNumber}#end + ${rssFormatter.formatTimestamp($build.startTime)} + ${rssFormatter.formatTimestamp($build.endTime)} + ${rssFormatter.formatInterval($build.startTime,$build.endTime)} + ${build.state} + ${rssFormatter.formatProjectState($build.state)} + #if($imageFile)${xmlLink.setImage($imageFile)}#end + ${build.trigger} + ${rssFormatter.formatTrigger($build.trigger)} + #if($build.error)#end + +### TODO: The following does not work because the scm result is not detached +### when the build result is attached. There are two possible solutions: +### 1. write a pull tool that can be used to detach objects (least invasive) +### 2. modify modello to add fetch-depth=0 attributes to the appropriate fields (cleanest) +## +###foreach($changeSet in $build.scmResult.changes) +## +## ${changeSet.author} +## ${changeSet.comment} +## ${rssFormatter.formatTimestamp($changeSet.date)} +###foreach($change in $changeSet.files) +## +## ${change.name} +## ${change.revision} +## +###end +## +###end +## + + +#end + + \ No newline at end of file Index: C:/dev/maven-continuum/continuum-1.0.2/continuum-web/src/main/resources/templates/screens/Summary.vm =================================================================== --- C:/dev/maven-continuum/continuum-1.0.2/continuum-web/src/main/resources/templates/screens/Summary.vm (revision 379571) +++ C:/dev/maven-continuum/continuum-1.0.2/continuum-web/src/main/resources/templates/screens/Summary.vm (working copy) @@ -103,6 +103,12 @@ Working Copy #end + #if ( $item.state == 1 || $item.state == 2 || $item.state == 3 || $item.state == 4 || $item.state == 6 ) + RSS Feed + #else + RSS Feed + #end + #if ( $continuum.security.isAuthorized( $c1user, "deleteProject" ) ) #if ( $item.state == 1 || $item.state == 2 || $item.state == 3 || $item.state == 4 ) Delete