diff options
author | Henri Sara <henri.sara@itmill.com> | 2009-03-25 07:10:17 +0000 |
---|---|---|
committer | Henri Sara <henri.sara@itmill.com> | 2009-03-25 07:10:17 +0000 |
commit | b77e0f7dfbf7d80b806f1dbea4ce7f1d85248d61 (patch) | |
tree | c7f1efc877104151f1195f5ded78979d6dd97f84 /build | |
parent | f65586e992add15e7d89c251ed8bee45aa5cfcfe (diff) | |
download | vaadin-framework-b77e0f7dfbf7d80b806f1dbea4ce7f1d85248d61.tar.gz vaadin-framework-b77e0f7dfbf7d80b806f1dbea4ce7f1d85248d61.zip |
Merge from 5.3 to 6.0:
[7015] Updated browser support list in Release Notes. For #2538.
[7028] Merge from branches/release/5.3.0 to versions/5.3 (multiple changesets concerning build)
[7039] Updated tutorial PDF, also added the header logo element.
svn changeset:7166/svn branch:6.0
Diffstat (limited to 'build')
-rw-r--r-- | build/VERSION.properties | 2 | ||||
-rwxr-xr-x | build/bin/mergetool.py | 682 | ||||
-rwxr-xr-x | build/bin/svnlog-to-rn.py | 109 | ||||
-rw-r--r-- | build/bin/svnlog-to-rn.xsl | 19 |
4 files changed, 811 insertions, 1 deletions
diff --git a/build/VERSION.properties b/build/VERSION.properties index 1d7413b235..85aede4896 100644 --- a/build/VERSION.properties +++ b/build/VERSION.properties @@ -1 +1 @@ -version=5.3.0-rc13 +version=5.3.0 diff --git a/build/bin/mergetool.py b/build/bin/mergetool.py new file mode 100755 index 0000000000..bc1b23b090 --- /dev/null +++ b/build/bin/mergetool.py @@ -0,0 +1,682 @@ +#!/usr/bin/python + +import sys,re,os,string,urllib,httplib + +################################################################################ +# Configuration +################################################################################ + +# Determine repository root +pin = os.popen("svn info|grep 'Repository Root'|sed -e 's/^.\+: //'", "r") +REPOSITORY = pin.read().rstrip()+"/" +pin.close() + +print "Repository: %s" % (REPOSITORY) + +################################################################################ +# Parse command-line arguments +################################################################################ +def help(exitvalue = 0): + print "Usage: batchmerge [options] <command>\n" + print "Options:" + print "\t-m\tOnly merge. (For 'single' command.)" + print "\t-c\tOnly commit. (For 'single' command.)" + print "\t-html\tHTML output. (For 'log' command.)" + print "\t-author\tHTML output. (Include author in HTML log.)" + print "\t-milestone <ms>\tList tickets in milestone (For 'log' command.)" + print "\nCommands:" + print "massmerge <cfg> <src> <trg> [<from>] " + print " - Merges changesets listed in the configuration" + print " file. The file is in svn log (text) format." + print " You can comment out unwanted changesets." + print " Merge is stopped on conflict." + print " If you give the optional <from> parameter," + print " merge is started from the changeset number. " + print "single <chg#> <target> - Merges a single changeset. If -m is given," + print " only merge is done. If -c is given, only commit is done." + print "revert - Reverts all changes made to repository except" + print " changes in this program and the merge files." + print "log <cfg> <src> <trg> - Prints a ChangeLog as it will appear in the" + print " commit log. If -html option is given," + print " the log is printed in a HTML format" + print " suitable for the Release Notes." + print "commit <cfg> <src> <trg> - Commits all changes, except changes to this" + print " program and merge files. The commit log" + print " comment includes list of all changesets" + print " listed in the configuration. The <target>" + print " is the branch name, e.g., \"5.2\".\n" + print "Common parameters:" + print " <cfg> - Configuration file (svn text log format)." + print " <src> - Source branch relative to repository URI." + print " <trg> - Target branch relative to repository URI." + print "You must run the command in the root directory of the branch." + print "The program file contains some basic configuration parameters." + sys.exit(exitvalue) + +################################################################################ +# Globals +################################################################################ +tickets = {} + +################################################################################ +# Utility Functions +################################################################################ +def command(cmd, dryrun=0): + print cmd + if not dryrun: + if os.system(cmd): + print "Command failed, exiting." + sys.exit(1) + else: + print "Dry run - not executing." + +def listChangedFiles(): + # Get Svn status + pin = os.popen("svn st", "r") + lines = pin.readlines() + pin.close() + + changed = [] + for line in lines: + # Remove trailing newline + line = line[:-1] + + # Extract the file state and name + (filestate, filename) = re.split(r'[ \+]+', line) + + # Ignore files in build directory + if (filename.startswith("build/merge/") \ + or filename.startswith("build/bin/mergetool.py") \ + or filename.startswith("build/testing")) \ + and filestate == "M": + continue + + # File is changed if it is not local + if filestate != "?": + changed.append(filename) + + return changed + +# Retrieves ticket summary string with HTTP +# Returns: (summary, milestone) +def fetchSummary(ticketno): + params = urllib.urlencode({'format': 'tab'}) + conn = httplib.HTTPConnection("dev.itmill.com") + conn.request("GET", "/ticket/%d?%s" % (ticketno, params) ) + response = conn.getresponse() + data = response.read() + conn.close() + + lines = data.split("\n") + data = reduce(lambda x,y: x+"\n"+y, lines[1:]) + #cols = lines[1].split("\t") + + cols = data.split("\t") + + return (cols[1],cols[8]) + +# Adds summary to ticket number, unless the context already has it +# Returns: (summary, milestone) +def addSummary(m): + ticketnum = int(m.group(1)) + context = m.group(2) + if re.match(" *\(", context): + # The context already has ticket summary + return "#%d%s" % (ticketnum, context) + + (summary,milestone) = fetchSummary(ticketnum) + + # Remove possible " quotation from the summary + if summary.startswith('"'): + summary = summary.strip('"') + summary = summary.replace('""', '"') + + # Add summaries to further ticket numbers recursively + context = re.sub(r'#([0-9]+)(.*)', addSummary, context) + + return "#%s (<i>%s</i>) %s" % (ticketnum, summary, context) + +################################################################################ +# Change +################################################################################ +class Ticket: + def __init__(self, id, summary=None, milestone=None): + self.id = id + self.summary = summary + self.milestone = milestone + + def fetchData(self): + (summary, milestone) = fetchSummary(self.id) + self.summary = summary + self.milestone = milestone + +################################################################################ +# Change +################################################################################ +class Change: + def __init__(self, id, undo=0, author=""): + self.id = id + self.author = author + self.comment = "" + self.undo = undo + self.tickets = [] + + def addCommentLine(self, line): + self.comment += line + + def merge(self, trunkURI, dryrun=0): + drycmd = "" + if dryrun: + drycmd = "--dry-run" + + # Handle negative merge + mergesign = "" + if self.undo: + mergesign = "-" + + # Build the merge command + cmd = "svn merge --non-interactive %s -c %s%d %s" % (drycmd, mergesign, self.id, trunkURI) + print cmd + + # Run the merge command + pin = os.popen(cmd, "r") + lines = pin.readlines() + pin.close() + + # Parse the lines for conflicts + conflicts = 0 + for line in lines: + print line[:-1] + + # Check for conflict + if line.startswith("C"): + conflicts += 1 + + # Check for skipped file + elif line.startswith("Skipped"): + conflicts += 1 + + filename = line[8:-1] + + # Simply exit if there was any problem + if conflicts > 0: + print "Problems detected. Exiting." + sys.exit(1) + + def fetchComment(self, trunkURI): + cmd = "svn log -r %d %s" % (self.id, trunkURI) + + # Run the log command + pin = os.popen(cmd, "r") + lines = pin.readlines() + pin.close() + + STATE_START = 0 + STATE_COMMENT = 1 + comment = None + state = STATE_START + for line in lines: + if state == STATE_START: + if line == "\n": + state = STATE_COMMENT + elif state == STATE_COMMENT: + if line.startswith("-----------------"): + self.comment = comment + return comment + elif comment: + comment += "\n" + line.rstrip("\n") + else: + comment = line.rstrip("\n") + + self.comment = comment + return comment + + def commit(self): + # Write the log comment to a temporary file + logtmpname = "/tmp/merge-single-%d.log" % (os.getpid()) + fout = open(logtmpname, "w") + fout.write(self.comment) + fout.close() + + # Get listo + files = listChangedFiles() + if len(files) == 0: + print "Error: Will not do empty commit." + sys.exit(1) + + # Write the list of files to be committed to a temporary file + changedfiles = ("\n".join(files)) + "\n" + targettmpname = "/tmp/merge-targets-%d.txt" % (os.getpid()) + fout = open(targettmpname, "w") + fout.write(changedfiles) + fout.close() + print changedfiles, + + command("svn commit --file %s --targets %s" % (logtmpname, targettmpname)) + + command("rm %s %s" % (logtmpname, targettmpname)) + + + def getNumber(self): + return self.id + + def getComment(self): + return self.comment + + def getUndo(self): + return self.undo + + def getAuthor(self): + return self.author + + def isForMilestone(self, milestone): + return self.author + + def addSummary(self, m, target_milestone=None): + ticketnum = int(m.group(1)) + context = m.group(2) + if re.match(" *\(", context): + # The context already has ticket summary + return "#%d%s" % (ticketnum, context) + + # Check for cached ticket + if tickets.has_key(ticketnum): + summary = tickets[ticketnum].summary + ticket_milestone = tickets[ticketnum].milestone + else: + # Fetch ticket from server and add to cache + (summary,ticket_milestone) = fetchSummary(ticketnum) + tickets[ticketnum] = Ticket(ticketnum,summary,ticket_milestone) + + self.tickets.append(ticketnum); + + # Remove possible " quotation from the summary + if summary.startswith('"'): + summary = summary.strip('"') + summary = summary.replace('""', '"') + + ticketnum = "#%s" % (ticketnum) + + # Emphasize tickets matching the target milestone + if target_milestone: + if ticket_milestone.find(target_milestone) != -1: + ticketnum = "<b>%s</b>" % (ticketnum) + + # Add summaries to further ticket numbers recursively + context = re.sub(r'#([0-9]+)(.*)', lambda m: self.addSummary(m, target_milestone=target_milestone), context) + + return "%s (<i>%s</i>) %s" % (ticketnum, summary, context) + + def registerTicket(self, m, ticketNumbers): + ticketNumbers[int(m.group(1))] = 1 + return "" + + # Returns a list of ticket numbers referenced by this change + def listTickets(self): + ticketNumbers = {} + re.sub(r'#([0-9]+)', lambda m: self.registerTicket(m,ticketNumbers=ticketNumbers), self.comment) + return ticketNumbers.keys() + +################################################################################ +# Read configuration file +################################################################################ +class Configuration: + def __init__(self, cfgfilename, startfrom=0): + self.changes = [] + self.readConfig(cfgfilename, startfrom) + + def readConfig(self, cfgfilename, startfrom=0): + fin = open(cfgfilename, "r") + content = fin.readlines() + fin.close() + + # Parse configuration + currentChange = None + skipChange = 0 + for line in content: + m_changestart = re.match(r'(-?)r([0-9]+)', line) + m_endofchange = re.match(r'------+', line) + m_emptyline = re.match(r'^$', line) + if m_changestart: + # Parse negative merge + undo = 0 + if m_changestart.group(1) == "-": + undo = 1 + + # Get changeset number + id = int(m_changestart.group(2)) + + # Skip the target if its number is too small + if startfrom != 0 and id < startfrom: + skipChange = 1 + + # Get the author + author = re.sub(r'\@.+', '', line.split("|")[1].strip()) + + currentChange = Change(id, undo=undo, author=author) + + elif m_endofchange: + # Register changeset, unless it is marked + # for skipping. + if currentChange: + if skipChange: + skipChange = 0 + else: + self.changes.append(currentChange) + currentChange = None + elif m_emptyline: + pass + else: + if currentChange: + currentChange.addCommentLine(line) + + def massMerge(self, trunkURI, dryrun=0): + for change in self.changes: + change.merge(trunkURI, dryrun=dryrun) + + def createLogComment(self): + # Create a log comment that lists all merged changesets with + # comments + logcomment = "Merge from %s to %s:\n" % (sourcebranch, targetbranch) + for change in self.changes: + changeno = change.getNumber() + changecomment = change.getComment().rstrip("\n") + if change.getUndo(): + logcomment += "Reverted [%d] merge: %s\n" % (changeno, changecomment) + else: + logcomment += "Merged [%d]: %s\n" % (changeno, changecomment) + return logcomment + + def logHtml(self, author=0, milestone=None): + # In author inclusion mode, include some styles to make a printout look better + if author: + print "<head>\n<style type=\"text/css\">\n"+ \ + "tr {\n vertical-align: top;\n}\ntd {\n font-size: 8pt;\n}\n</style>\n</head>\n" + + # Print header + print "<table id=\"changelog-table\">" + authorcolumnheader = "" + if author: + authorcolumnheader = "<td>Author</td>" + print " <tr><td>#</td><td>Changeset Comment</td>%s</tr>" % (authorcolumnheader) + + # Print body: the changes + for change in self.changes: + changeno = change.getNumber() + changecomment = change.getComment().rstrip("\n") + + changeref = "[%d]" % (changeno) + + # Handle merge undo markup + if change.getUndo(): + changeref = "<font class=\"changeset-merge-undone\">%s</font>" % (changeref) + changecomment = "<font class=\"changeset-merge-undone\">%s</font>" % (changecomment) + changecomment = "Reverted a change: "+changecomment + + authorcolumn = "" + if author: + authorcolumn = "<td>%s</td>" % (change.getAuthor()) + + # Add ticket summary after ticket number, if missing + # TODO: this handles only one + changecomment = re.sub(r'#([0-9]+)(.*)', lambda m: change.addSummary(m, target_milestone=milestone), changecomment, 100) + # item = re.sub(r'#([0-9]+)(.*)', '#\\1 (SUMMARY) \\2', item) + + # Change ticket numbers to references to tickets + changecomment = re.sub(r'#([0-9]+)', '#<a href="http://dev.itmill.com/ticket/\\1">\\1</a>', changecomment) + + # Change changeset numbers to references to changesets + changecomment = re.sub(r'\[([0-9]+)\]', '[<a href="http://dev.itmill.com/changeset/\\1">\\1</a>]', changecomment) + changeref = re.sub(r'\[([0-9]+)\]', '[<a href="http://dev.itmill.com/changeset/\\1">\\1</a>]', changeref) + + # See if any of the tickets have milestone under work. + if milestone: + for ticketnum in change.tickets: + ticket = tickets[ticketnum] + if ticket.milestone.find(milestone) != -1: + changeref = "<b>%s</b>" % (changeref) + + # Make basic HTML formatting + item = " <tr><td>%s:</td><td>%s</td>%s</tr>" % (changeref, changecomment, authorcolumn) + + print item + sys.stdout.flush() + print "</table>" + + # Prints a commit log to standard output + def log(self, sourcebranch, targetbranch, html=0, author=0, milestone=None): + if html: + self.logHtml(author=author,milestone=milestone) + return + sys.stdout.write(self.createLogComment()) + + def commit(self, sourcebranch, targetbranch, dryrun=0): + logcomment = self.createLogComment() + + # Write the log comment to a temporary file + logtmpname = "/tmp/massmerge-pid-%d.log" % (os.getpid()) + fout = open(logtmpname, "w") + fout.write(logcomment) + fout.close() + + # Write the list of files to be committed to a temporary file + changedfiles = "\n".join(listChangedFiles()) + targettmpname = "/tmp/massmerge-targets-%d.txt" % (os.getpid()) + fout = open(targettmpname, "w") + fout.write(changedfiles) + fout.close() + + if dryrun: + print "Log:" + os.system("cat %s" % (logtmpname)) + print "\nChanged Files:" + os.system("cat %s" % (targettmpname)) + print "\n" + + command("svn commit --file %s --targets %s" % (logtmpname, targettmpname), dryrun=dryrun) + + command("rm %s %s" % (logtmpname, targettmpname)) + + def listTickets(self): + fixed = {} + + for change in self.changes: + changeno = change.getNumber() + changeTickets = change.listTickets() + if len(changeTickets)>0 and change.comment.lower().find("fix") != -1: + for ticket in changeTickets: + fixed[ticket] = 1 + + fixedlist = fixed.keys() + fixedlist.sort() + # print "Fixed:", fixedlist + + print "<ul>" + + for ticketNum in fixedlist: + if not tickets.has_key(ticketNum): + ticket = Ticket(ticketNum) + ticket.fetchData() + tickets[ticketNum] = ticket + + ticket = tickets[ticketNum] + # print "%d: %s" % (ticket.id, ticket.summary) + print " <li><a href=\"http://dev.itmill.com/ticket/%d\">#%d</a>: %s</li>" % (ticket.id, ticket.id, ticket.summary) + sys.stdout.flush() + + print "</ul>" + +################################################################################ +# Commands +################################################################################ + +# Command: revert +def commandRevert(): + # Get Svn status + pin = os.popen("svn st", "r") + lines = pin.readlines() + pin.close() + + reverted = [] + removed = [] + for line in lines: + # Remove trailing newline + line = line[:-1] + + # Extract the file state and name + (filestate, filename) = re.split(r'[ \+]+', line) + + # Ignore files in build directory + if (filename.startswith("build/merge/") \ + or filename.startswith("build/bin/")) \ + and filestate == "M": + continue + + # Added files are simply deleted + if filestate != "?": + reverted.append(filename) + + # Added files have to be removed in addition to reverting + if filestate == "A": + removed.append(filename) + + # Remove conflict choises + elif filestate == "?" and \ + (filename.find(".merge-left.r") != -1 or \ + filename.find(".merge-right.r") != -1): + removed.append(filename) + + # Revert files marked for reverting + donework = 0 + if len(reverted) > 0: + files = " ".join(reverted) + command("svn revert -R %s" % (files)) + donework = 1 + + # Remove files marked for deletion + if len(removed) > 0: + files = " ".join(removed) + command("rm %s" % (files)) + donework = 1 + + if not donework: + print "Nothing to do." + +# Command: massmerge +def commandMassmerge(cfgfilename, sourceuri, startfrom, dryrun=0): + cfg = Configuration(cfgfilename, startfrom=startfrom) + cfg.massMerge(sourceuri, dryrun=dryrun) + +# Command: single +def commandSingle(trunkuri, changeset, sourcebranch, targetbranch, onlymerge=0, onlycommit=0): + change = Change(changeset) + print "Found changeset with log comment:\n "+change.fetchComment(trunkuri) + "\n" + + change.merge(trunkuri, dryrun=onlycommit) + if onlycommit: + print "Got file list." + else: + print "Merge successful." + + # Change the comment + change.comment = "Merged [%d] from %s to %s branch: %s" % (change.id, sourcebranch, branchname, change.comment) + print "\nLog comment: \"%s\"" % (change.comment) + + if not onlymerge: + print "Committing." + change.commit() + +# Command: commit +def commandCommit(cfgfilename, sourcebranch, targetbranch, dryrun=0): + cfg = Configuration(cfgfilename) + cfg.commit(sourcebranch, targetbranch, dryrun=dryrun) + +# Command: log +def commandLog(cfgfilename, sourcebranch, targetbranch, html=0, author=0, milestone=None): + cfg = Configuration(cfgfilename) + cfg.log(sourcebranch, targetbranch, html=html, author=author, milestone=milestone) + +# Command: tickets +def commandTickets(cfgfilename): + cfg = Configuration(cfgfilename) + cfg.listTickets() + +################################################################################ +# Main Program +################################################################################ + +# Handle switches +dryrun = 0 +html = 0 +html_author = 0 +html_milestone = None +onlymerge = 0 +onlycommit = 0 +while len(sys.argv)>1 and sys.argv[1][0] == '-': + if sys.argv[1] == "-d": + dryrun = 1 + del sys.argv[1:2] + + elif sys.argv[1] == "-html": + html = 1 + del sys.argv[1:2] + + elif sys.argv[1] == "-author": + html_author = 1 + del sys.argv[1:2] + + elif sys.argv[1] == "-milestone": + html_milestone = sys.argv[2] + del sys.argv[1:3] + + elif sys.argv[1] == "-m": + onlymerge = 1 + del sys.argv[1:2] + + elif sys.argv[1] == "-c": + onlycommit = 1 + del sys.argv[1:2] + + else: + print "Invalid option '%s'." % (sys.argv[1]) + sys.exit(1) + +if len(sys.argv) < 2: + help(1) + +# Handle commands +if sys.argv[1] == "revert": + commandRevert() + +elif (len(sys.argv) == 4 or len(sys.argv)==5) and sys.argv[1] == "massmerge": + cfgfilename = sys.argv[2] + sourcebranch = sys.argv[3] + startfrom = None + if len(sys.argv)>4: + startfrom = int(sys.argv[4]) + commandMassmerge(cfgfilename, sourceuri=REPOSITORY+sourcebranch, startfrom=startfrom, dryrun=dryrun) + +elif len(sys.argv) == 5 and sys.argv[1] == "single": + changeset = int(sys.argv[2]) + sourcebranch = sys.argv[3] + targetbranch = sys.argv[4] + commandSingle(REPOSITORY+sourcebranch, changeset, targetbranch, onlymerge=onlymerge, onlycommit=onlycommit) + +elif len(sys.argv) == 5 and sys.argv[1] == "commit": + cfgfilename = sys.argv[2] + sourcebranch = sys.argv[3] + targetbranch = sys.argv[4] + commandCommit(cfgfilename, sourcebranch, targetbranch, dryrun=dryrun) + +elif len(sys.argv) == 5 and sys.argv[1] == "log": + cfgfilename = sys.argv[2] + sourcebranch = sys.argv[3] + targetbranch = sys.argv[4] + commandLog(cfgfilename, sourcebranch, targetbranch, html=html, author=html_author, milestone=html_milestone) + +elif len(sys.argv) == 3 and sys.argv[1] == "tickets": + cfgfilename = sys.argv[2] + commandTickets(cfgfilename) + +else: + help(1) diff --git a/build/bin/svnlog-to-rn.py b/build/bin/svnlog-to-rn.py new file mode 100755 index 0000000000..5cca3705f9 --- /dev/null +++ b/build/bin/svnlog-to-rn.py @@ -0,0 +1,109 @@ +#!/usr/bin/python +################################################################################ +# SVN Log to ChangeLog generator for Release Notes +# +# Generates list of changes in HTML for ChangeLog +# from SVN Log in XML format. You typically generate the log with +# a command such as: +# svn log -v -r 1234:HEAD > svnlog-1234:HEAD.log.xml +# The command must be executed in the root directory of Toolkit project, +# either in the trunk or in the proper branch. The converter is then +# used as follows: +# ./build/bin/svnlog-to-rn.py svnlog-1234:HEAD.log.xml +# +# The ChangeLog generator will strip away any merges that begin with +# "Merged [...] from trunk to x.x branch." +# +# The generator will handle the following markup: +# - Changeset tags such as [1234] to links to dev.itmill.com/changeset/1234 +# - Ticket references such as #1234 to links to dev.itmill.com/ticket/1234 +# - If ticket reference does not have explanation in parentheses, +# the script will fetch the summary of the ticket from Trac and +# add it in parentheses after the reference, such as: +# "fixes #1234 (A nasty bug I found)". +# +# Requirements: +# - Xalan +################################################################################ + +import sys,re,os,httplib,urllib + +################################################################################ +# Convert XML to XHTML +# - The transformation includes various relevent information +# and does basic formatting +################################################################################ + +# Determine path to XSLT file +pathToScript = sys.argv[0] +sloc = pathToScript.rfind("/") +pathToScript = pathToScript[:sloc] + +if len(sys.argv) != 2: + print "Usage: svnlog-to-rn.py <logfile.xml>" + print "Read the svnlog-to-rn.py header for more info." + sys.exit(1) + +# Open Xalan +filename = sys.argv[1] +fin = open(filename, "r") +(pout,pin) = os.popen2("xalan -xsl %s/svnlog-to-rn.xsl" % (pathToScript)) + +# Preprocessing before feeding to XSLT Processor +lines = fin.readlines() +out = "" +for line in lines: + if line.find("action") != -1: + line = line.replace(r'>[^<]+/', '') + #print line, + pout.write(line) +pout.close() + +################################################################################ +# Helper functions for postprocessing +################################################################################ + +# Retrieves summary string with HTTP +def fetchSummary(ticketno): + params = urllib.urlencode({'format': 'tab'}) + conn = httplib.HTTPConnection("dev.itmill.com") + conn.request("GET", "/ticket/%d?%s" % (ticketno, params) ) + response = conn.getresponse() + data = response.read() + conn.close() + + lines = data.split("\n") + cols = lines[1].split("\t") + return cols[1] + +# Adds summary to ticket number, unless the context already has it +def addSummary(m): + ticketnum = int(m.group(1)) + context = m.group(2) + if re.match(" *\(", context): + # The context already has ticket summary + return "#%d%s" % (ticketnum, context) + + summary = fetchSummary(ticketnum) + + return "#%s (<i>%s</i>) %s" % (ticketnum, summary, context) + +################################################################################ +# Postprocessing for XSLT output +################################################################################ + +lines = pin.readlines() +for line in lines: + # Add ticket summary after ticket number, if missing + line = re.sub(r'#([0-9]+)(.*)', addSummary, line) + + # Change ticket numbers to references to tickets + line = re.sub(r'#([0-9]+)', '#<a href="http://dev.itmill.com/ticket/\\1">\\1</a>', line) + + # Change changeset numbers to references to changesets + #line = re.sub(r'\[([0-9]+)\]', '[<a href="http://dev.itmill.com/changeset/\\1">\\1</a>]', line) + + # Remove prefix about merging + line = re.sub(r'Merged.+from trunk to [0-9]+.[0-9]+ branch: ', '', line) + + print line, diff --git a/build/bin/svnlog-to-rn.xsl b/build/bin/svnlog-to-rn.xsl new file mode 100644 index 0000000000..75dd762db9 --- /dev/null +++ b/build/bin/svnlog-to-rn.xsl @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + version="1.0"> + + <xsl:output method="html"/> + + <xsl:template match="logentry"> + <li>[<xsl:element name="a"><xsl:attribute name="href">http://dev.itmill.com/changeset/<xsl:value-of select="@revision"/></xsl:attribute><xsl:value-of select="@revision"/></xsl:element>]: <xsl:value-of select="msg"/></li> + </xsl:template> + + <xsl:template match="/"> + <html> + <body bgcolor="#FFFFFF"> + <xsl:apply-templates/> + </body> + </html> + </xsl:template> + +</xsl:stylesheet> |