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://184.108.40.206: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://220.127.116.11: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:
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://18.104.22.168: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)>