27 September 2012

Embed Url Links in TeamCity Build Logs

We at AutoScout24 are using TeamCity for our Continous Integration and Delivery. One step in our  Release Pipeline is integration testing in different browsers. If our test framework detects a problems it will create a screenshot of the breaking page. This screenshot contains valuable information that helps our developers to quickly analyze the issue. As an example, our test servers are configured to send stack traces which are visible in the screenshots.

But it seams that there is no way to include links in TeamCity build logs. TeamCity correctly escapes all the output from test and build tools so it is not possible to get some html into the log. So I investigated TeamCity extension points. Writing a complete custom html report seemed to be overkill because the test reporting tab worked really well. Writing a UI plugin means to learn Java, JSP and so on and as a .NET company we don't want to fumble around with the Java technology stack. But as a web company we know how to hack javascript ;-)

There is already a TeamCity plugin called StaticUIExtensions that allows you to embedd static html fragments in TeamCity pages. And because a script tag is a valid html fragment we could inject javascript into TeamCity. So I wrote a few lines of javascript that scan the dom for urls and transforms them into links. With this technique you get clickable links in all the build logs.


What you need to do:
  1. Install StaticUIExtensions 
  2. On your TeamCity server, open your "server\config\_static_ui_extensions" folder
  3. Open static-ui-extensions.xml
  4. Add a new rule that inserts "show-link.html" into every page that starts with "viewLog.html"
      <rule html-file="show-link.html" place-id="BEFORE_CONTENT">
        <url starts="viewLog.html" />
      </rule>
  5. Create a new file "show-link.html" with this content:
    <script>
      (function ($) {
        var regex = /url\((.*)\)/g
     
        function createLinksFromUrls() {
          $("div .fullStacktrace, div .msg").each(function () {
            var div = $(this);
            var oldHtml = div.html();
            var newHtml = oldHtml.replace(regex, "<a href='$1' target='_blank'>$1</a>");
            if (oldHtml !== newHtml) div.html(newHtml);
          });
        }
     
        $(document).ready(createLinksFromUrls);
        $(document).click(function () {
            window.setTimeout(createLinksFromUrls, 50);
            window.setTimeout(createLinksFromUrls, 100);
            window.setTimeout(createLinksFromUrls, 500);
        });
    })(window.jQuery); 
    
    </script>
    
This javascript searches for the url(*) pattern and replaces it with <a> tags.  Because TeamCity uses ajax to load the stacktraces when you expand a tree node, I used timers to delay the dom processing until the ajax call suceeded. Now you can log something like "url(http://www.autoscout24.de)" and this will be transformed to <a href="http://www.autoscout24.de">http://www.autoscout24.de</a>.

Voila, Mission completed.