This can also be fixed by adding a literal newline into the output, as the errors and warnings are output in a <pre> formatted block. I have posted a patch under issue CC-810 which fixes this issue and an additional issue with the CheckStyle output widget.
> html br being wrongly encoded on dashboard errors and warnings page
> -------------------------------------------------------------------
>
> Key: CC-806
> URL:
http://jira.public.thoughtworks.org/browse/CC-806> Project: CruiseControl
> Issue Type: Bug
> Components: Reporting Application
> Affects Versions: 2.7.2
> Environment: Suse 10.1, cruise control 2.7.2 built from tagged SVN 2.7.2 release source
> Reporter: Richard Hands
> Priority: Minor
>
> The errors and warnings tab on the dashboard incorrectly html encodes the <br/> characters that it inserts.
> this results in text such as
> Warnings Generated 0<br/>Reading SVN for update<br/>
> etc instead of the obvious desired result of
> Warnings Generated 0
> Reading SVN for update
> etc.
> This is due to the call to StringEscapeUtils.escapeHtml(error) being applied to the whole errors and messages string, after the <br/> characters have already been put in place, hence encoding them as well. It would be better (although slightly less efficient, at least this gives the desired effect) to call escapeHtml per message as you add it to the html, so that it's pre-encoded.
> my patch for it, which makes it work correctly on my machine is thus
> ErrorsAndWarningsMessagesWidget.java (original)
> private String errorsAndWarnings(List messages, String currentHtml) {
> StringBuffer sb = new StringBuffer();
> for (Iterator iter = messages.iterator(); iter.hasNext();) {
> BuildMessage message = (BuildMessage) iter.next();
> MessageLevel level = message.getLevel();
> if (MessageLevel.WARN.equals(level) || MessageLevel.ERROR.equals(level)) {
> sb.append(message.getMessage()).append("<br/>");
> }
> }
> String error = StringUtils.defaultIfEmpty(sb.toString(), "No errors or warnings");
> String errorsAndWarningsHtml = StringUtils.replace(ERRORS_AND_WARNINGS_HTML, "$errors",
> StringEscapeUtils.escapeHtml(error));
> boolean hasErrorsOrWarnings = !StringUtils.isEmpty(sb.toString());
> return currentHtml + makeToggleable(errorsAndWarningsHtml, "errors_and_warnings_element", hasErrorsOrWarnings);
> }
> and the fixed version (note StringEscapeUtils.escapeHtml is the only things that's moved)
> private String errorsAndWarnings(List messages, String currentHtml) {
> StringBuffer sb = new StringBuffer();
> for (Iterator iter = messages.iterator(); iter.hasNext();) {
> BuildMessage message = (BuildMessage) iter.next();
> MessageLevel level = message.getLevel();
> if (MessageLevel.WARN.equals(level) || MessageLevel.ERROR.equals(level)) {
> sb.append(StringEscapeUtils.escapeHtml(message.getMessage())).append("<br/>");
> }
> }
> String error = StringUtils.defaultIfEmpty(sb.toString(), "No errors or warnings");
> String errorsAndWarningsHtml = StringUtils.replace(ERRORS_AND_WARNINGS_HTML, "$errors",
> error);
> boolean hasErrorsOrWarnings = !StringUtils.isEmpty(sb.toString());
> return currentHtml + makeToggleable(errorsAndWarningsHtml, "errors_and_warnings_element", hasErrorsOrWarnings);
> }