Skip to content

Commit

Permalink
JENKINS-22100 Added escape of messages in changelog
Browse files Browse the repository at this point in the history
  • Loading branch information
patbos committed Mar 10, 2014
1 parent 67e4402 commit b29e88c
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 27 deletions.
59 changes: 32 additions & 27 deletions src/main/webapp/pipe.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ function updatePipelines(divNames, errorDiv, view, showAvatars, showChanges, tim
}, timeout);
},
error: function (xhr, status, error) {
Q("#" + errorDiv).html('Error communicating to server! ' + error);
Q("#" + errorDiv).html('Error communicating to server! ' + htmlEncode(error));
Q("#" + errorDiv).show();
plumb.repaintEverything();
setTimeout(function () {
Expand Down Expand Up @@ -44,7 +44,7 @@ function refreshPipelines(data, divNames, errorDiv, view, showAvatars, showChang
for (var c = 0; c < data.pipelines.length; c++) {
var component = data.pipelines[c];
var html = "<section class='component'>";
html = html + "<h1>" + component.name + "</h1>";
html = html + "<h1>" + htmlEncode(component.name) + "</h1>";
if (component.pipelines.length == 0) {
html = html + "No builds done yet.";
}
Expand All @@ -56,7 +56,7 @@ function refreshPipelines(data, divNames, errorDiv, view, showAvatars, showChang
if (pipeline.triggeredBy && pipeline.triggeredBy.length > 0) {
for (var y = 0; y < pipeline.triggeredBy.length; y++) {
var trigger = pipeline.triggeredBy[y];
triggered = triggered + ' <span class="' + trigger.type + '">' + trigger.description + '</span>';
triggered = triggered + ' <span class="' + trigger.type + '">' + htmlEncode(trigger.description) + '</span>';
}
if (y < pipeline.triggeredBy.length - 1) {
triggered = triggered + ", ";
Expand All @@ -66,35 +66,17 @@ function refreshPipelines(data, divNames, errorDiv, view, showAvatars, showChang
if (pipeline.aggregated) {
html = html + '<h1>Aggregated view</h1>'
} else {
html = html + '<h1>' + pipeline.version;
html = html + '<h1>' + htmlEncode(pipeline.version);
if (triggered != "") {
html = html + " triggered by " + triggered;
}
html = html + ' started <span id="' + pipeline.id + '\">' + formatDate(pipeline.timestamp, lastUpdate) + '</span></h1>';

if (showChanges && pipeline.changes && pipeline.changes.length > 0) {
html = html + '<div class="changes">';
html = html + '<h1>Changes:</h1>';
for (var o = 0; o < pipeline.changes.length; o++) {
html = html + '<div class="change">';
var change = pipeline.changes[o];
html = html + '<div class="change-author">' + change.author.name + '</div>';
if (change.changeLink) {
html = html + '<div class="change-message"><a href="' + change.changeLink + '">' + change.message + '</a></div>';
} else {
html = html + '<div class="change-message">' + change.message + '</div>';
}
html = html + '</div>';
}
html = html + '</div>';


html = html + generateChangeLog(pipeline.changes);
}


}


var row = 0;
var column = 0;

Expand All @@ -116,15 +98,15 @@ function refreshPipelines(data, divNames, errorDiv, view, showAvatars, showChang
}

html = html + '<section id="' + getStageId(stage.name, i) + '" class="stage ' + getStageClassName(stage.name) + '">';
html = html + '<div class="stage-header"><span class="stage-name">' + stage.name + '</span>';
html = html + '<div class="stage-header"><span class="stage-name">' + htmlEncode(stage.name) + '</span>';
if (!pipeline.aggregated) {
html = html + '</div>'
} else {
var stageversion = stage.version;
if (!stageversion) {
stageversion = "N/A"
}
html = html + ' <span class="stage-version">' + stageversion + '</span></div>'
html = html + ' <span class="stage-version">' + htmlEncode(stageversion) + '</span></div>'
}
for (var k = 0; k < stage.tasks.length; k++) {
var task = stage.tasks[k];
Expand All @@ -136,7 +118,7 @@ function refreshPipelines(data, divNames, errorDiv, view, showAvatars, showChang
tasks.push({id: id, taskId: task.id, buildId: task.buildId});

html = html + "<div id=\"" + id + "\" class=\"task " + task.status.type +
"\"><div class=\"taskname\"><a href=\"" + task.link + "\">" + task.name + "</a></div>";
"\"><div class=\"taskname\"><a href=\"" + task.link + "\">" + htmlEncode(task.name) + "</a></div>";

if (timestamp != "") {
html = html + "<span id=\"" + id + ".timestamp\" class='timestamp'>" + timestamp + "</span>"
Expand Down Expand Up @@ -186,7 +168,7 @@ function refreshPipelines(data, divNames, errorDiv, view, showAvatars, showChang
[ "Arrow", { location: 1}]
],
cssClass: "relation",
connector: ["Flowchart", { stub: 25, gap: 2, midpoint: 1, alwaysRespectStubs:true } ],
connector: ["Flowchart", { stub: 25, gap: 2, midpoint: 1, alwaysRespectStubs: true } ],
paintStyle: { lineWidth: 2, strokeStyle: "rgba(0,0,0,0.5)" },
drawEndpoints: false
});
Expand Down Expand Up @@ -226,6 +208,24 @@ function refreshPipelines(data, divNames, errorDiv, view, showAvatars, showChang
plumb.repaintEverything();
}

function generateChangeLog(changes) {
var html = '<div class="changes">';
html = html + '<h1>Changes:</h1>';
for (var i = 0; i < changes.length; i++) {
html = html + '<div class="change">';
var change = changes[i];
html = html + '<div class="change-author">' + htmlEncode(change.author.name) + '</div>';
if (change.changeLink) {
html = html + '<div class="change-message"><a href="' + change.changeLink + '">' + htmlEncode(change.message) + '</a></div>';
} else {
html = html + '<div class="change-message">' + htmlEncode(change.message) + '</div>';
}
html = html + '</div>';
}
html = html + '</div>';
return html;
}

function getStageClassName(stagename) {
return "stage_" + replace(stagename, " ", "_");
}
Expand Down Expand Up @@ -268,6 +268,11 @@ function formatDuration(millis) {
return "0 sec";
}

function htmlEncode(html) {
html = document.createElement('a').appendChild(
document.createTextNode(html)).parentNode.innerHTML;
return html.replace(/\n/g, '<br/>');
}
function getStageId(name, count) {
var re = new RegExp(' ', 'g');
return name.replace(re, '_') + "_" + count;
Expand Down
26 changes: 26 additions & 0 deletions src/test/javascript/pipe-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,29 @@ describe("getStageClassName", function() {
expect(getStageClassName("QA 1")).toEqual("stage_QA_1");
});
});

describe("htmlEncode", function() {
it("correctly returns html safe strings", function() {
expect(htmlEncode("Line1\nLine2")).toEqual("Line1<br/>Line2");
expect(htmlEncode("<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>")).toEqual("&lt;project.reporting.outputEncoding&gt;UTF-8&lt;/project.reporting.outputEncoding&gt;");
});
});

describe("generateChangeLog", function() {
it("Linebreak in changelog comment", function() {
var data = JSON.parse('{"changes":[{"author":{"name":"Firstname Lastname","avatarUrl":null,"url":"user/user"},"changeLink":null,"commitId":"2718","message":"Firstline\\nSecondLine"}]}');
expect(generateChangeLog(data.changes)).toEqual('<div class="changes"><h1>Changes:</h1><div class="change"><div class="change-author">Firstname Lastname</div><div class="change-message">Firstline<br/>SecondLine</div></div></div>');
});
it("XML in changelog comment", function() {
var data = JSON.parse('{"changes":[{"author":{"name":"Firstname Lastname","avatarUrl":null,"url":"user/user"},"changeLink":null,"commitId":"2718","message":"<xml>data</xml>"}]}');
expect(generateChangeLog(data.changes)).toEqual('<div class="changes"><h1>Changes:</h1><div class="change"><div class="change-author">Firstname Lastname</div><div class="change-message">&lt;xml&gt;data&lt;/xml&gt;</div></div></div>');
});
it("Swedish characters in changelog comment", function() {
var data = JSON.parse('{"changes":[{"author":{"name":"Firstname Lastname","avatarUrl":null,"url":"user/user"},"changeLink":null,"commitId":"2718","message":"Räksmörgås"}]}');
expect(generateChangeLog(data.changes)).toEqual('<div class="changes"><h1>Changes:</h1><div class="change"><div class="change-author">Firstname Lastname</div><div class="change-message">Räksmörgås</div></div></div>');
});
it("Multiple changelogs", function() {
var data = JSON.parse('{"changes":[{"author":{"name":"Firstname Lastname","avatarUrl":null,"url":"user/user"},"changeLink":null,"commitId":"2718","message":"First change"}, {"author":{"name":"Firstname Lastname","avatarUrl":null,"url":"user/user"},"changeLink":null,"commitId":"2718","message":"Second change"}]}');
expect(generateChangeLog(data.changes)).toEqual('<div class="changes"><h1>Changes:</h1><div class="change"><div class="change-author">Firstname Lastname</div><div class="change-message">First change</div></div><div class="change"><div class="change-author">Firstname Lastname</div><div class="change-message">Second change</div></div></div>');
});
});

0 comments on commit b29e88c

Please sign in to comment.