A few days ago I asked on the BlogCFC blog about a way to display a report from Subversion. I knew how to get a report of the latest updates for one file, but not for a project as a whole. A few people recommended Trac, but being the kind of guy I am, I wanted to build something myself.
Scott P (who has contributed some good changes to BlogCFC) told me what the SVN command was:
svn log -v svn://199.231.128.19:8000/blogcfc5 --limit 10
This command will give you a nice report of the last ten changes to the subversion repository. I was about to hook this up to CFEXECUTE and start writing a string parser when I had the brilliant idea of actually checking the documentation. Turns out if you add --xml to the command, you actually get the report back in XML:
svn log -v svn://199.231.128.19:8000/blogcfc5 --limit 10 --xml
No string parsing necessary! So I quickly whipped up some code (included below) and added the report to BlogCFC. You can find the SVN info here:
http://www.blogcfc.com/blogcfcsvn.cfm
Nice design, eh? Hard to believe I'm just a developer. The code is a work in progress, and not encapsulated into a CFC, but for those who want to add this to your site, I've included it below. Some notes:
- I'm not parsing the dates yet. It's UTC, so I just need to add the offset which I can get from getTimeZoneInfo().
- You could make the files linkable if you wanted, but you always need to be extra-super-anal-etc when writing code that will dump another file live on the web. In fact, I'd probably just not recommend doing this unless the entire application is very secure.
- SVN also reports what happened to the file. So for example, I think it uses M to signify that the file was modified. I bet it uses A for Add and D for Delete, but I haven't confirmed this. I'd like to update my code to not just show the files but what the change was.
- And as I said above, this should be rewritten into a little UDF or CFC.
<!--- path to svn --->
<cfset svnPath = "svn">
<!--- whats the url? --->
<cfset svnURL = "svn://199.231.128.19:8000">
<!--- how many entries --->
<cfset top = 10>
<!--- args --->
<cfset args = "log -v #svnURL# --limit #top# --xml">
<!--- run it --->
<cfexecute name="#svnPath#" arguments="#args#" variable="result" timeout="30" />
<!--- parse to xml --->
<cfset data = xmlparse(result)>
<!--- get entries --->
<cfset entries = xmlSearch(data, "//logentry")>
<cfset logEntries = arrayNew(1)>
<cfloop index="x" from="1" to="#arrayLen(entries)#">
<cfset entry = entries[x]>
<cfset logEntry = structNew()>
<cfset logEntry.revision = entry.xmlAttributes.revision>
<cfset logEntry.files = arrayNew(1)>
<cfloop index="y" from="1" to="#arrayLen(entry.xmlChildren)#">
<cfset xmlChild = entry.xmlChildren[y]>
<cfswitch expression="#xmlChild.xmlName#">
<cfcase value="author,msg,date">
<cfset logEntry[xmlChild.xmlName] = xmlChild.xmlText>
</cfcase>
<cfcase value="paths">
<cfloop index="z" from="1" to="#arrayLen(xmlChild.xmlChildren)#">
<cfset thisFile = xmlChild.xmlChildren[z].xmlText>
<cfset arrayAppend(logEntry.files, thisFile)>
</cfloop>
</cfcase>
</cfswitch>
</cfloop>
<cfset arrayAppend(logEntries, logEntry)>
</cfloop>
<cfdump var="#logEntries#">