From 1cf7fc58387259e198c7426bbf21e6307c726ca3 Mon Sep 17 00:00:00 2001 From: PyvesB Date: Fri, 22 Dec 2017 20:54:52 +0100 Subject: [PATCH 01/13] Fixed remaining CodeClimate badges --- lib/all-badge-examples.js | 4 +- lib/color-formatters.js | 17 +++ lib/color-formatters.spec.js | 11 ++ server.js | 194 +++++++++++------------------------ service-tests/codeclimate.js | 69 +++++++++---- 5 files changed, 142 insertions(+), 153 deletions(-) diff --git a/lib/all-badge-examples.js b/lib/all-badge-examples.js index cd56d1956346f..fe76890955e88 100644 --- a/lib/all-badge-examples.js +++ b/lib/all-badge-examples.js @@ -1222,11 +1222,11 @@ const allBadgeExamples = [ examples: [ { title: 'Code Climate', - previewUri: '/codeclimate/github/kabisaict/flow.svg' + previewUri: '/codeclimate/Nickersoft/dql.svg' }, { title: 'Code Climate', - previewUri: '/codeclimate/coverage/github/triAGENS/ashikawa-core.svg' + previewUri: '/codeclimate/coverage/Nickersoft/dql.svg' }, { title: 'Code Climate', diff --git a/lib/color-formatters.js b/lib/color-formatters.js index dc9356dcff69e..4739f33f8dd67 100644 --- a/lib/color-formatters.js +++ b/lib/color-formatters.js @@ -40,6 +40,22 @@ function floorCount(value, yellow, yellowgreen, green) { } } +function letterScore(score) { + if (score === 'A') { + return 'brightgreen'; + } else if (score === 'B') { + return 'green'; + } else if (score === 'C') { + return 'yellowgreen'; + } else if (score === 'D') { + return 'yellow'; + } else if (score === 'E') { + return 'orange'; + } else { + return 'red'; + } +} + function colorScale(steps, colors, reversed) { if (steps === undefined) { throw Error('When invoking colorScale, steps should be provided.'); @@ -89,6 +105,7 @@ module.exports = { downloadCount, coveragePercentage, floorCount, + letterScore, colorScale, age }; diff --git a/lib/color-formatters.spec.js b/lib/color-formatters.spec.js index 4c54c78920e7b..2f815e09e22c0 100644 --- a/lib/color-formatters.spec.js +++ b/lib/color-formatters.spec.js @@ -4,6 +4,7 @@ const { test, given, forCases } = require('sazerac'); const { coveragePercentage, colorScale, + letterScore, age, version } = require('./color-formatters'); @@ -40,6 +41,16 @@ describe('Color formatters', function() { }); }); + test(letterScore, () => { + given('A').expect('brightgreen'); + given('B').expect('green'); + given('C').expect('yellowgreen'); + given('D').expect('yellow'); + given('E').expect('orange'); + given('F').expect('red'); + given('Z').expect('red'); + }); + const monthsAgo = months => { const result = new Date(); // This looks wack but it works. diff --git a/server.js b/server.js index 78948f08e9b5f..293518df41909 100644 --- a/server.js +++ b/server.js @@ -44,6 +44,7 @@ const { coveragePercentage: coveragePercentageColor, downloadCount: downloadCountColor, floorCount: floorCountColor, + letterScore: letterScoreColor, version: versionColor, age: ageColor, colorScale @@ -2690,80 +2691,58 @@ cache(function(data, match, sendBadge, request) { }); })); -// Code Climate coverage integration -camp.route(/^\/codeclimate\/coverage\/(.+)\.(svg|png|gif|jpg|json)$/, +// Code Climate test reports integration +camp.route(/^\/codeclimate\/(c|coverage)\/(.+)\.(svg|png|gif|jpg|json)$/, cache(function(data, match, sendBadge, request) { - var userRepo = match[1]; // eg, `github/triAGENS/ashikawa-core`. - var format = match[2]; - var options = { - method: 'HEAD', - uri: 'https://codeclimate.com/' + userRepo + '/coverage.png', - }; - var badgeData = getBadgeData('coverage', data); - request(options, function(err, res) { + const isPercentage = match[1] === 'coverage'; + const userRepo = match[2]; // eg, `Nickersoft/dql`. + const format = match[3]; + request({ + method: 'GET', + uri: `https://api.codeclimate.com/v1/repos?github_slug=${userRepo}`, + json: true + }, function (err, res, body) { + const badgeData = getBadgeData('coverage', data); if (err != null) { - badgeData.text[1] = 'inaccessible'; + badgeData.text[1] = 'invalid'; sendBadge(format, badgeData); return; } + try { - var score = res.headers['content-disposition'] - .match(/filename=".*coverage_(.+)\.png"/)[1]; - if (!score) { - badgeData.text[1] = 'malformed'; + if (!body.data || body.data.length === 0) { + badgeData.text[1] = 'not found'; sendBadge(format, badgeData); return; } - var percentage = parseInt(score); - if (percentage !== percentage) { - // It is NaN, treat it as unknown. + + const testReportData = body.data[0].relationships.latest_default_branch_test_report.data; + if (testReportData == null) { badgeData.text[1] = 'unknown'; sendBadge(format, badgeData); return; } - badgeData.text[1] = score + '%'; - badgeData.colorscheme = coveragePercentageColor(percentage); - sendBadge(format, badgeData); - } catch(e) { - badgeData.text[1] = 'not found'; - sendBadge(format, badgeData); - } - }); -})); -// Code Climate issues integration -camp.route(/^\/codeclimate\/issues\/(.+)\.(svg|png|gif|jpg|json)$/, -cache(function(data, match, sendBadge, request) { - var userRepo = match[1]; // eg, `github/me-and/mdf`. - var format = match[2]; - var options = 'https://codeclimate.com/' + userRepo + '/badges/issue_count.svg'; - var badgeData = getBadgeData('issues', data); - request(options, function(err, res, buffer) { - if (err != null) { - badgeData.text[1] = 'inaccessible'; - sendBadge(format, badgeData); - return; - } - try { - var count = buffer.match(/>([0-9]+) issues?/)[1]; - if (!count) { - badgeData.text[1] = 'malformed'; + const testReportsUrl = `https://api.codeclimate.com/v1/repos/${body.data[0].id}/test_reports/${testReportData.id}`; + request(testReportsUrl, function(err, res, buffer) { + if (err != null) { + badgeData.text[1] = 'invalid'; + sendBadge(format, badgeData); + return; + } + + const parsedData = JSON.parse(buffer); + if (isPercentage) { + const percentage = parseFloat(parsedData.data.attributes.covered_percent); + badgeData.text[1] = percentage.toFixed(0) + '%'; + badgeData.colorscheme = coveragePercentageColor(percentage); + } else { + const score = parsedData.data.attributes.rating.letter; + badgeData.text[1] = score; + badgeData.colorscheme = letterScoreColor(score); + } sendBadge(format, badgeData); - return; - } - badgeData.text[1] = count; - if (count == 0) { - badgeData.colorscheme = 'brightgreen'; - } else if (count < 5) { - badgeData.colorscheme = 'green'; - } else if (count < 10) { - badgeData.colorscheme = 'yellowgreen'; - } else if (count < 20) { - badgeData.colorscheme = 'yellow'; - } else { - badgeData.colorscheme = 'red'; - } - sendBadge(format, badgeData); + }); } catch(e) { badgeData.text[1] = 'invalid'; sendBadge(format, badgeData); @@ -2771,19 +2750,18 @@ cache(function(data, match, sendBadge, request) { }); })); -// New Code Climate scores (coverage + maintainability) -camp.route(/^\/codeclimate\/(c|maintainability)\/(.+)\.(svg|png|gif|jpg|json)$/, +//Code Climate snapshots integration +camp.route(/^\/codeclimate(\/(maintainability|issues))?\/(.+)\.(svg|png|gif|jpg|json)$/, cache(function(data, match, sendBadge, request) { - const isCoverage = match[1] === 'c'; - const userRepo = match[2]; // eg, `kabisaict/flow`. - const format = match[3]; + const type = match[2] ? match[2] : 'technical debt'; + const userRepo = match[3]; // eg, `Nickersoft/dql`. + const format = match[4]; request({ method: 'GET', uri: `https://api.codeclimate.com/v1/repos?github_slug=${userRepo}`, json: true }, function (err, res, body) { - const badgeData = getBadgeData(isCoverage ? 'coverage' : 'maintainability', data); - + const badgeData = getBadgeData(type, data); if (err != null) { badgeData.text[1] = 'invalid'; sendBadge(format, badgeData); @@ -2795,20 +2773,17 @@ cache(function(data, match, sendBadge, request) { badgeData.text[1] = 'not found'; sendBadge(format, badgeData); return; - } else if (isCoverage && body.data[0].relationships.latest_default_branch_test_report.data == null - || !isCoverage && body.data[0].relationships.latest_default_branch_snapshot.data == null) { + } + + const snapshotData = body.data[0].relationships.latest_default_branch_snapshot.data; + if (snapshotData == null) { badgeData.text[1] = 'unknown'; sendBadge(format, badgeData); return; } - let apiUrl = `https://api.codeclimate.com/v1/repos/${body.data[0].id}/`; - if (isCoverage) { - apiUrl += `test_reports/${body.data[0].relationships.latest_default_branch_test_report.data.id}`; - } else { - apiUrl += `snapshots/${body.data[0].relationships.latest_default_branch_snapshot.data.id}`; - } - request(apiUrl, function(err, res, buffer) { + const snapshotsUrl = `https://api.codeclimate.com/v1/repos/${body.data[0].id}/snapshots/${snapshotData.id}`; + request(snapshotsUrl, function(err, res, buffer) { if (err != null) { badgeData.text[1] = 'invalid'; sendBadge(format, badgeData); @@ -2816,19 +2791,18 @@ cache(function(data, match, sendBadge, request) { } const parsedData = JSON.parse(buffer); - const score = isCoverage ? parsedData.data.attributes.rating.letter : parsedData.data.attributes.ratings[0].letter; - badgeData.text[1] = score; - - if (score === 'A') { - badgeData.colorscheme = 'brightgreen'; - } else if (score === 'B') { - badgeData.colorscheme = 'green'; - } else if (score === 'C') { - badgeData.colorscheme = 'yellow'; - } else if (score === 'D') { - badgeData.colorscheme = 'orange'; + if (type === 'issues') { + const count = parsedData.data.meta.issues_count; + badgeData.text[1] = count; + badgeData.colorscheme = colorScale([1, 5, 10, 20], ['brightgreen', 'green', 'yellowgreen', 'yellow', 'red'])(count); + } else if (type === 'maintainability') { + const score = parsedData.data.attributes.ratings[0].letter; + badgeData.text[1] = score; + badgeData.colorscheme = letterScoreColor(score); } else { - badgeData.colorscheme = 'red'; + const percentage = parseFloat(parsedData.data.meta.measures.technical_debt_ratio.value); + badgeData.text[1] = percentage.toFixed(0) + '%'; + badgeData.colorscheme = colorScale([5, 10, 20, 50], ['brightgreen', 'green', 'yellowgreen', 'yellow', 'red'])(percentage); } sendBadge(format, badgeData); }); @@ -2839,52 +2813,6 @@ cache(function(data, match, sendBadge, request) { }); })); -// // Code Climate integration -camp.route(/^\/codeclimate\/(.+)\.(svg|png|gif|jpg|json)$/, -cache(function(data, match, sendBadge, request) { - var userRepo = match[1]; // eg, `github/kabisaict/flow`. - var format = match[2]; - var options = { - method: 'HEAD', - uri: 'https://codeclimate.com/' + userRepo + '.png', - }; - var badgeData = getBadgeData('code climate', data); - request(options, function(err, res) { - if (err != null) { - badgeData.text[1] = 'inaccessible'; - sendBadge(format, badgeData); - return; - } - try { - var statusMatch = res.headers['content-disposition'] - .match(/filename=".*code_climate-(.+)\.png"/); - if (!statusMatch) { - badgeData.text[1] = 'unknown'; - sendBadge(format, badgeData); - return; - } - var state = statusMatch[1].replace('-', '.'); - var score = +state; - badgeData.text[1] = state; - if (score == 4) { - badgeData.colorscheme = 'brightgreen'; - } else if (score > 3) { - badgeData.colorscheme = 'green'; - } else if (score > 2) { - badgeData.colorscheme = 'yellow'; - } else if (score > 1) { - badgeData.colorscheme = 'orange'; - } else { - badgeData.colorscheme = 'red'; - } - sendBadge(format, badgeData); - } catch(e) { - badgeData.text[1] = 'not found'; - sendBadge(format, badgeData); - } - }); -})); - // Scrutinizer coverage integration. camp.route(/^\/scrutinizer\/coverage\/(.*)\.(svg|png|gif|jpg|json)$/, cache(function(data, match, sendBadge, request) { diff --git a/service-tests/codeclimate.js b/service-tests/codeclimate.js index 55d4aca440998..36bdcc898e821 100644 --- a/service-tests/codeclimate.js +++ b/service-tests/codeclimate.js @@ -2,14 +2,61 @@ const Joi = require('joi'); const ServiceTester = require('./runner/service-tester'); +const { + isPercentage, +} = require('./helpers/validators'); const t = new ServiceTester({ id: 'codeclimate', title: 'Code Climate' }) +// Tests based on Code Climate's test reports endpoint. +t.create('test coverage percentage') +.get('/coverage/Nickersoft/dql.json') +.expectJSONTypes(Joi.object().keys({ + name: 'coverage', + value: isPercentage +})); + +t.create('test coverage score') +.get('/c/Nickersoft/dql.json') +.expectJSONTypes(Joi.object().keys({ + name: 'coverage', + value: Joi.equal('A', 'B', 'C', 'D', 'E', 'F') +})); + +t.create('test coverage score for non-existent repo') +.get('/c/unknown/unknown.json') +.expectJSON({ + name: 'coverage', + value: 'not found' +}); + +t.create('test coverage score for repo without test reports') +.get('/c/kabisaict/flow.json') +.expectJSON({ + name: 'coverage', + value: 'unknown' +}); + +// Tests based on Code Climate's snapshots endpoint. +t.create('technical debt percentage') + .get('/Nickersoft/dql.json') + .expectJSONTypes(Joi.object().keys({ + name: 'technical debt', + value: isPercentage + })); + +t.create('issues count') + .get('/issues/Nickersoft/dql.json') + .expectJSONTypes(Joi.object().keys({ + name: 'issues', + value: Joi.number().integer().positive() + })); + t.create('maintainability score') .get('/maintainability/Nickersoft/dql.json') .expectJSONTypes(Joi.object().keys({ name: 'maintainability', - value: Joi.equal('A', 'B', 'C', 'D', 'F') + value: Joi.equal('A', 'B', 'C', 'D', 'E', 'F') })); t.create('maintainability score for non-existent repo') @@ -19,24 +66,10 @@ t.create('maintainability score for non-existent repo') value: 'not found' }); -t.create('test coverage score') - .get('/c/Nickersoft/dql.json') - .expectJSONTypes(Joi.object().keys({ - name: 'coverage', - value: Joi.equal('A', 'B', 'C', 'D', 'F') - })); - -t.create('test coverage score for non-existent repo') - .get('/c/unknown/unknown.json') - .expectJSON({ - name: 'coverage', - value: 'not found' - }); - -t.create('test coverage score for repo without test reports') - .get('/c/kabisaict/flow.json') +t.create('maintainability score for repo without snapshots') + .get('/maintainability/kabisaict/flow.json') .expectJSON({ - name: 'coverage', + name: 'maintainability', value: 'unknown' }); From dc07788d3a8d808c0e13106f40096ab1f9d89e2a Mon Sep 17 00:00:00 2001 From: PyvesB Date: Tue, 26 Dec 2017 19:22:48 +0100 Subject: [PATCH 02/13] Added explicit percentage keyword and dropped top level URL --- server.js | 26 ++++++++------- service-tests/codeclimate.js | 65 ++++++++++++++++++++---------------- 2 files changed, 50 insertions(+), 41 deletions(-) diff --git a/server.js b/server.js index 293518df41909..988ccb67f3b00 100644 --- a/server.js +++ b/server.js @@ -2692,11 +2692,12 @@ cache(function(data, match, sendBadge, request) { })); // Code Climate test reports integration -camp.route(/^\/codeclimate\/(c|coverage)\/(.+)\.(svg|png|gif|jpg|json)$/, +camp.route(/^\/codeclimate\/(c|coverage)(\/percentage)?\/(.+)\.(svg|png|gif|jpg|json)$/, cache(function(data, match, sendBadge, request) { - const isPercentage = match[1] === 'coverage'; - const userRepo = match[2]; // eg, `Nickersoft/dql`. - const format = match[3]; + // match[1] ignored. c and coverage are both equivalent, see #1387. + const isPercentage = match[2]; + const userRepo = match[3]; // eg, `Nickersoft/dql`. + const format = match[4]; request({ method: 'GET', uri: `https://api.codeclimate.com/v1/repos?github_slug=${userRepo}`, @@ -2750,10 +2751,11 @@ cache(function(data, match, sendBadge, request) { }); })); -//Code Climate snapshots integration -camp.route(/^\/codeclimate(\/(maintainability|issues))?\/(.+)\.(svg|png|gif|jpg|json)$/, +// Code Climate snapshots integration +camp.route(/^\/codeclimate\/(maintainability|issues)(\/percentage)?\/(.+)\.(svg|png|gif|jpg|json)$/, cache(function(data, match, sendBadge, request) { - const type = match[2] ? match[2] : 'technical debt'; + const type = match[1]; + const isPercentage = match[2]; const userRepo = match[3]; // eg, `Nickersoft/dql`. const format = match[4]; request({ @@ -2795,14 +2797,14 @@ cache(function(data, match, sendBadge, request) { const count = parsedData.data.meta.issues_count; badgeData.text[1] = count; badgeData.colorscheme = colorScale([1, 5, 10, 20], ['brightgreen', 'green', 'yellowgreen', 'yellow', 'red'])(count); - } else if (type === 'maintainability') { - const score = parsedData.data.attributes.ratings[0].letter; - badgeData.text[1] = score; - badgeData.colorscheme = letterScoreColor(score); - } else { + } else if (isPercentage) { const percentage = parseFloat(parsedData.data.meta.measures.technical_debt_ratio.value); badgeData.text[1] = percentage.toFixed(0) + '%'; badgeData.colorscheme = colorScale([5, 10, 20, 50], ['brightgreen', 'green', 'yellowgreen', 'yellow', 'red'])(percentage); + } else { + const score = parsedData.data.attributes.ratings[0].letter; + badgeData.text[1] = score; + badgeData.colorscheme = letterScoreColor(score); } sendBadge(format, badgeData); }); diff --git a/service-tests/codeclimate.js b/service-tests/codeclimate.js index 36bdcc898e821..93e07035b3636 100644 --- a/service-tests/codeclimate.js +++ b/service-tests/codeclimate.js @@ -9,42 +9,42 @@ const { const t = new ServiceTester({ id: 'codeclimate', title: 'Code Climate' }) // Tests based on Code Climate's test reports endpoint. -t.create('test coverage percentage') -.get('/coverage/Nickersoft/dql.json') -.expectJSONTypes(Joi.object().keys({ - name: 'coverage', - value: isPercentage -})); - t.create('test coverage score') -.get('/c/Nickersoft/dql.json') -.expectJSONTypes(Joi.object().keys({ - name: 'coverage', - value: Joi.equal('A', 'B', 'C', 'D', 'E', 'F') -})); - -t.create('test coverage score for non-existent repo') -.get('/c/unknown/unknown.json') -.expectJSON({ - name: 'coverage', - value: 'not found' -}); + .get('/coverage/Nickersoft/dql.json') + .expectJSONTypes(Joi.object().keys({ + name: 'coverage', + value: Joi.equal('A', 'B', 'C', 'D', 'E', 'F') + })); -t.create('test coverage score for repo without test reports') -.get('/c/kabisaict/flow.json') -.expectJSON({ - name: 'coverage', - value: 'unknown' -}); +t.create('test coverage score alternative URL') + .get('/c/Nickersoft/dql.json') + .expectJSONTypes(Joi.object().keys({ + name: 'coverage', + value: Joi.equal('A', 'B', 'C', 'D', 'E', 'F') + })); -// Tests based on Code Climate's snapshots endpoint. -t.create('technical debt percentage') - .get('/Nickersoft/dql.json') +t.create('test coverage percentage') + .get('/coverage/percentage/Nickersoft/dql.json') .expectJSONTypes(Joi.object().keys({ - name: 'technical debt', + name: 'coverage', value: isPercentage })); +t.create('test coverage score for non-existent repo') + .get('/coverage/unknown/unknown.json') + .expectJSON({ + name: 'coverage', + value: 'not found' + }); + +t.create('test coverage score for repo without test reports') + .get('/coverage/kabisaict/flow.json') + .expectJSON({ + name: 'coverage', + value: 'unknown' + }); + +// Tests based on Code Climate's snapshots endpoint. t.create('issues count') .get('/issues/Nickersoft/dql.json') .expectJSONTypes(Joi.object().keys({ @@ -59,6 +59,13 @@ t.create('maintainability score') value: Joi.equal('A', 'B', 'C', 'D', 'E', 'F') })); +t.create('maintainability percentage') + .get('/maintainability/percentage/Nickersoft/dql.json') + .expectJSONTypes(Joi.object().keys({ + name: 'maintainability', + value: isPercentage + })); + t.create('maintainability score for non-existent repo') .get('/maintainability/unknown/unknown.json') .expectJSON({ From 6a0c728a3121a7c537e7d2097b4ab41edea4ce35 Mon Sep 17 00:00:00 2001 From: PyvesB Date: Wed, 27 Dec 2017 10:35:09 +0100 Subject: [PATCH 03/13] Merged the two badge handlers into one --- server.js | 84 +++++++++++++------------------------------------------ 1 file changed, 19 insertions(+), 65 deletions(-) diff --git a/server.js b/server.js index 988ccb67f3b00..d3ef142757844 100644 --- a/server.js +++ b/server.js @@ -2692,9 +2692,10 @@ cache(function(data, match, sendBadge, request) { })); // Code Climate test reports integration -camp.route(/^\/codeclimate\/(c|coverage)(\/percentage)?\/(.+)\.(svg|png|gif|jpg|json)$/, +camp.route(/^\/codeclimate\/(c|coverage|maintainability|issues)(\/percentage)?\/(.+)\.(svg|png|gif|jpg|json)$/, cache(function(data, match, sendBadge, request) { - // match[1] ignored. c and coverage are both equivalent, see #1387. + // c and coverage are both equivalent, see #1387. + const type = match[1] === 'c' ? 'coverage' : match[1]; const isPercentage = match[2]; const userRepo = match[3]; // eg, `Nickersoft/dql`. const format = match[4]; @@ -2703,7 +2704,7 @@ cache(function(data, match, sendBadge, request) { uri: `https://api.codeclimate.com/v1/repos?github_slug=${userRepo}`, json: true }, function (err, res, body) { - const badgeData = getBadgeData('coverage', data); + const badgeData = getBadgeData(type, data); if (err != null) { badgeData.text[1] = 'invalid'; sendBadge(format, badgeData); @@ -2716,16 +2717,21 @@ cache(function(data, match, sendBadge, request) { sendBadge(format, badgeData); return; } - - const testReportData = body.data[0].relationships.latest_default_branch_test_report.data; - if (testReportData == null) { + + let branchData; + if (type === 'coverage') { + branchData = body.data[0].relationships.latest_default_branch_test_report.data; + } else { + branchData = body.data[0].relationships.latest_default_branch_snapshot.data; + } + if (branchData == null) { badgeData.text[1] = 'unknown'; sendBadge(format, badgeData); return; } - const testReportsUrl = `https://api.codeclimate.com/v1/repos/${body.data[0].id}/test_reports/${testReportData.id}`; - request(testReportsUrl, function(err, res, buffer) { + const url = `https://api.codeclimate.com/v1/repos/${body.data[0].id}/${type === 'coverage' ? 'test_reports' : 'snapshots'}/${branchData.id}`; + request(url, function(err, res, buffer) { if (err != null) { badgeData.text[1] = 'invalid'; sendBadge(format, badgeData); @@ -2733,75 +2739,23 @@ cache(function(data, match, sendBadge, request) { } const parsedData = JSON.parse(buffer); - if (isPercentage) { + if (type === 'coverage' && isPercentage) { const percentage = parseFloat(parsedData.data.attributes.covered_percent); badgeData.text[1] = percentage.toFixed(0) + '%'; badgeData.colorscheme = coveragePercentageColor(percentage); - } else { + } else if (type === 'coverage') { const score = parsedData.data.attributes.rating.letter; badgeData.text[1] = score; badgeData.colorscheme = letterScoreColor(score); - } - sendBadge(format, badgeData); - }); - } catch(e) { - badgeData.text[1] = 'invalid'; - sendBadge(format, badgeData); - } - }); -})); - -// Code Climate snapshots integration -camp.route(/^\/codeclimate\/(maintainability|issues)(\/percentage)?\/(.+)\.(svg|png|gif|jpg|json)$/, -cache(function(data, match, sendBadge, request) { - const type = match[1]; - const isPercentage = match[2]; - const userRepo = match[3]; // eg, `Nickersoft/dql`. - const format = match[4]; - request({ - method: 'GET', - uri: `https://api.codeclimate.com/v1/repos?github_slug=${userRepo}`, - json: true - }, function (err, res, body) { - const badgeData = getBadgeData(type, data); - if (err != null) { - badgeData.text[1] = 'invalid'; - sendBadge(format, badgeData); - return; - } - - try { - if (!body.data || body.data.length === 0) { - badgeData.text[1] = 'not found'; - sendBadge(format, badgeData); - return; - } - - const snapshotData = body.data[0].relationships.latest_default_branch_snapshot.data; - if (snapshotData == null) { - badgeData.text[1] = 'unknown'; - sendBadge(format, badgeData); - return; - } - - const snapshotsUrl = `https://api.codeclimate.com/v1/repos/${body.data[0].id}/snapshots/${snapshotData.id}`; - request(snapshotsUrl, function(err, res, buffer) { - if (err != null) { - badgeData.text[1] = 'invalid'; - sendBadge(format, badgeData); - return; - } - - const parsedData = JSON.parse(buffer); - if (type === 'issues') { + } else if (type === 'issues') { const count = parsedData.data.meta.issues_count; badgeData.text[1] = count; badgeData.colorscheme = colorScale([1, 5, 10, 20], ['brightgreen', 'green', 'yellowgreen', 'yellow', 'red'])(count); - } else if (isPercentage) { + } else if (type === 'maintainability' && isPercentage) { const percentage = parseFloat(parsedData.data.meta.measures.technical_debt_ratio.value); badgeData.text[1] = percentage.toFixed(0) + '%'; badgeData.colorscheme = colorScale([5, 10, 20, 50], ['brightgreen', 'green', 'yellowgreen', 'yellow', 'red'])(percentage); - } else { + } else if (type === 'maintainability') { const score = parsedData.data.attributes.ratings[0].letter; badgeData.text[1] = score; badgeData.colorscheme = letterScoreColor(score); From cdd9c0d74023a8c759ce839b79455a760a0f7a8e Mon Sep 17 00:00:00 2001 From: PyvesB Date: Wed, 27 Dec 2017 10:37:45 +0100 Subject: [PATCH 04/13] Removed trailing space --- server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.js b/server.js index d3ef142757844..9ed1715248d8a 100644 --- a/server.js +++ b/server.js @@ -2717,7 +2717,7 @@ cache(function(data, match, sendBadge, request) { sendBadge(format, badgeData); return; } - + let branchData; if (type === 'coverage') { branchData = body.data[0].relationships.latest_default_branch_test_report.data; From d12c073a84e40b1e555fcc6f381f329a528c708b Mon Sep 17 00:00:00 2001 From: PyvesB Date: Wed, 27 Dec 2017 10:44:05 +0100 Subject: [PATCH 05/13] Switched to "dash" URL style --- server.js | 2 +- service-tests/codeclimate.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/server.js b/server.js index 9ed1715248d8a..4d424f492e663 100644 --- a/server.js +++ b/server.js @@ -2692,7 +2692,7 @@ cache(function(data, match, sendBadge, request) { })); // Code Climate test reports integration -camp.route(/^\/codeclimate\/(c|coverage|maintainability|issues)(\/percentage)?\/(.+)\.(svg|png|gif|jpg|json)$/, +camp.route(/^\/codeclimate\/(c|coverage|maintainability|issues)(-percentage)?\/(.+)\.(svg|png|gif|jpg|json)$/, cache(function(data, match, sendBadge, request) { // c and coverage are both equivalent, see #1387. const type = match[1] === 'c' ? 'coverage' : match[1]; diff --git a/service-tests/codeclimate.js b/service-tests/codeclimate.js index 93e07035b3636..a13081002fb3b 100644 --- a/service-tests/codeclimate.js +++ b/service-tests/codeclimate.js @@ -24,7 +24,7 @@ t.create('test coverage score alternative URL') })); t.create('test coverage percentage') - .get('/coverage/percentage/Nickersoft/dql.json') + .get('/coverage-percentage/Nickersoft/dql.json') .expectJSONTypes(Joi.object().keys({ name: 'coverage', value: isPercentage @@ -60,7 +60,7 @@ t.create('maintainability score') })); t.create('maintainability percentage') - .get('/maintainability/percentage/Nickersoft/dql.json') + .get('/maintainability-percentage/Nickersoft/dql.json') .expectJSONTypes(Joi.object().keys({ name: 'maintainability', value: isPercentage From 26d58b1b4e8a41b9ab1ebc62ed9af9996a6757a6 Mon Sep 17 00:00:00 2001 From: PyvesB Date: Wed, 27 Dec 2017 10:53:45 +0100 Subject: [PATCH 06/13] Reinstated top-level URL --- server.js | 12 ++++++------ service-tests/codeclimate.js | 7 +++++++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/server.js b/server.js index 4d424f492e663..3552589270912 100644 --- a/server.js +++ b/server.js @@ -2692,13 +2692,13 @@ cache(function(data, match, sendBadge, request) { })); // Code Climate test reports integration -camp.route(/^\/codeclimate\/(c|coverage|maintainability|issues)(-percentage)?\/(.+)\.(svg|png|gif|jpg|json)$/, +camp.route(/^\/codeclimate(\/(c|coverage|maintainability|issues)(-percentage)?)?\/(.+)\.(svg|png|gif|jpg|json)$/, cache(function(data, match, sendBadge, request) { - // c and coverage are both equivalent, see #1387. - const type = match[1] === 'c' ? 'coverage' : match[1]; - const isPercentage = match[2]; - const userRepo = match[3]; // eg, `Nickersoft/dql`. - const format = match[4]; + // c and coverage are both equivalent. Top-level URL still supported for backwards compatibility. See #1387. + const type = match[2] === 'c' || !match[2] ? 'coverage' : match[2]; + const isPercentage = match[3]; + const userRepo = match[4]; // eg, `Nickersoft/dql`. + const format = match[5]; request({ method: 'GET', uri: `https://api.codeclimate.com/v1/repos?github_slug=${userRepo}`, diff --git a/service-tests/codeclimate.js b/service-tests/codeclimate.js index a13081002fb3b..efc6465e95c89 100644 --- a/service-tests/codeclimate.js +++ b/service-tests/codeclimate.js @@ -23,6 +23,13 @@ t.create('test coverage score alternative URL') value: Joi.equal('A', 'B', 'C', 'D', 'E', 'F') })); +t.create('test coverage score alternative top-level URL') + .get('/Nickersoft/dql.json') + .expectJSONTypes(Joi.object().keys({ + name: 'coverage', + value: Joi.equal('A', 'B', 'C', 'D', 'E', 'F') + })); + t.create('test coverage percentage') .get('/coverage-percentage/Nickersoft/dql.json') .expectJSONTypes(Joi.object().keys({ From 890878c165f06b152be0199ea5c965ac5c8252ef Mon Sep 17 00:00:00 2001 From: PyvesB Date: Wed, 27 Dec 2017 11:00:31 +0100 Subject: [PATCH 07/13] Swicthed to use letter as optional keyword --- server.js | 24 ++++++++++++------------ service-tests/codeclimate.js | 36 ++++++++++++++++++------------------ 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/server.js b/server.js index 3552589270912..1fec5be789cda 100644 --- a/server.js +++ b/server.js @@ -2692,11 +2692,11 @@ cache(function(data, match, sendBadge, request) { })); // Code Climate test reports integration -camp.route(/^\/codeclimate(\/(c|coverage|maintainability|issues)(-percentage)?)?\/(.+)\.(svg|png|gif|jpg|json)$/, +camp.route(/^\/codeclimate(\/(c|coverage|maintainability|issues)(-letter)?)?\/(.+)\.(svg|png|gif|jpg|json)$/, cache(function(data, match, sendBadge, request) { // c and coverage are both equivalent. Top-level URL still supported for backwards compatibility. See #1387. const type = match[2] === 'c' || !match[2] ? 'coverage' : match[2]; - const isPercentage = match[3]; + const isLetter = match[3]; const userRepo = match[4]; // eg, `Nickersoft/dql`. const format = match[5]; request({ @@ -2739,26 +2739,26 @@ cache(function(data, match, sendBadge, request) { } const parsedData = JSON.parse(buffer); - if (type === 'coverage' && isPercentage) { - const percentage = parseFloat(parsedData.data.attributes.covered_percent); - badgeData.text[1] = percentage.toFixed(0) + '%'; - badgeData.colorscheme = coveragePercentageColor(percentage); - } else if (type === 'coverage') { + if (type === 'coverage' && isLetter) { const score = parsedData.data.attributes.rating.letter; badgeData.text[1] = score; badgeData.colorscheme = letterScoreColor(score); + } else if (type === 'coverage') { + const percentage = parseFloat(parsedData.data.attributes.covered_percent); + badgeData.text[1] = percentage.toFixed(0) + '%'; + badgeData.colorscheme = coveragePercentageColor(percentage); } else if (type === 'issues') { const count = parsedData.data.meta.issues_count; badgeData.text[1] = count; badgeData.colorscheme = colorScale([1, 5, 10, 20], ['brightgreen', 'green', 'yellowgreen', 'yellow', 'red'])(count); - } else if (type === 'maintainability' && isPercentage) { - const percentage = parseFloat(parsedData.data.meta.measures.technical_debt_ratio.value); - badgeData.text[1] = percentage.toFixed(0) + '%'; - badgeData.colorscheme = colorScale([5, 10, 20, 50], ['brightgreen', 'green', 'yellowgreen', 'yellow', 'red'])(percentage); - } else if (type === 'maintainability') { + } else if (type === 'maintainability' && isLetter) { const score = parsedData.data.attributes.ratings[0].letter; badgeData.text[1] = score; badgeData.colorscheme = letterScoreColor(score); + } else if (type === 'maintainability') { + const percentage = parseFloat(parsedData.data.meta.measures.technical_debt_ratio.value); + badgeData.text[1] = percentage.toFixed(0) + '%'; + badgeData.colorscheme = colorScale([5, 10, 20, 50], ['brightgreen', 'green', 'yellowgreen', 'yellow', 'red'])(percentage); } sendBadge(format, badgeData); }); diff --git a/service-tests/codeclimate.js b/service-tests/codeclimate.js index efc6465e95c89..8773ff0fd30cc 100644 --- a/service-tests/codeclimate.js +++ b/service-tests/codeclimate.js @@ -9,42 +9,42 @@ const { const t = new ServiceTester({ id: 'codeclimate', title: 'Code Climate' }) // Tests based on Code Climate's test reports endpoint. -t.create('test coverage score') +t.create('test coverage percentage') .get('/coverage/Nickersoft/dql.json') .expectJSONTypes(Joi.object().keys({ name: 'coverage', - value: Joi.equal('A', 'B', 'C', 'D', 'E', 'F') + value: isPercentage })); -t.create('test coverage score alternative URL') +t.create('test coverage percentage alternative URL') .get('/c/Nickersoft/dql.json') .expectJSONTypes(Joi.object().keys({ name: 'coverage', - value: Joi.equal('A', 'B', 'C', 'D', 'E', 'F') + value: isPercentage })); -t.create('test coverage score alternative top-level URL') +t.create('test coverage percentage alternative top-level URL') .get('/Nickersoft/dql.json') .expectJSONTypes(Joi.object().keys({ name: 'coverage', - value: Joi.equal('A', 'B', 'C', 'D', 'E', 'F') + value: isPercentage })); -t.create('test coverage percentage') - .get('/coverage-percentage/Nickersoft/dql.json') +t.create('test coverage letter') + .get('/coverage-letter/Nickersoft/dql.json') .expectJSONTypes(Joi.object().keys({ name: 'coverage', - value: isPercentage + value: Joi.equal('A', 'B', 'C', 'D', 'E', 'F') })); -t.create('test coverage score for non-existent repo') +t.create('test coverage percentage for non-existent repo') .get('/coverage/unknown/unknown.json') .expectJSON({ name: 'coverage', value: 'not found' }); -t.create('test coverage score for repo without test reports') +t.create('test coverage percentage for repo without test reports') .get('/coverage/kabisaict/flow.json') .expectJSON({ name: 'coverage', @@ -59,28 +59,28 @@ t.create('issues count') value: Joi.number().integer().positive() })); -t.create('maintainability score') +t.create('maintainability percentage') .get('/maintainability/Nickersoft/dql.json') .expectJSONTypes(Joi.object().keys({ name: 'maintainability', - value: Joi.equal('A', 'B', 'C', 'D', 'E', 'F') + value: isPercentage })); -t.create('maintainability percentage') - .get('/maintainability-percentage/Nickersoft/dql.json') +t.create('maintainability letter') + .get('/maintainability-letter/Nickersoft/dql.json') .expectJSONTypes(Joi.object().keys({ name: 'maintainability', - value: isPercentage + value: Joi.equal('A', 'B', 'C', 'D', 'E', 'F') })); -t.create('maintainability score for non-existent repo') +t.create('maintainability percentage for non-existent repo') .get('/maintainability/unknown/unknown.json') .expectJSON({ name: 'maintainability', value: 'not found' }); -t.create('maintainability score for repo without snapshots') +t.create('maintainability percentage for repo without snapshots') .get('/maintainability/kabisaict/flow.json') .expectJSON({ name: 'maintainability', From 767c02d966f11ee880c9eba7bc35aa0034904d9b Mon Sep 17 00:00:00 2001 From: PyvesB Date: Wed, 27 Dec 2017 11:01:35 +0100 Subject: [PATCH 08/13] Updated badge examples --- lib/all-badge-examples.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/all-badge-examples.js b/lib/all-badge-examples.js index fe76890955e88..17b09369b4be2 100644 --- a/lib/all-badge-examples.js +++ b/lib/all-badge-examples.js @@ -1222,11 +1222,11 @@ const allBadgeExamples = [ examples: [ { title: 'Code Climate', - previewUri: '/codeclimate/Nickersoft/dql.svg' + previewUri: '/codeclimate/c/Nickersoft/dql.svg' }, { title: 'Code Climate', - previewUri: '/codeclimate/coverage/Nickersoft/dql.svg' + previewUri: '/codeclimate/c-letter/Nickersoft/dql.svg' }, { title: 'Code Climate', @@ -1238,7 +1238,7 @@ const allBadgeExamples = [ }, { title: 'Code Climate', - previewUri: '/codeclimate/c/Nickersoft/dql.svg' + previewUri: '/codeclimate/maintainability-letter/Nickersoft/dql.svg' }, { title: 'bitHound', From 82fe7d2512568e29aa64ad416ea50501ccb59cbc Mon Sep 17 00:00:00 2001 From: PyvesB Date: Wed, 27 Dec 2017 11:51:15 +0100 Subject: [PATCH 09/13] Cleaned up --- server.js | 15 ++++++--------- service-tests/codeclimate.js | 12 ++++++------ 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/server.js b/server.js index 1fec5be789cda..44ccedbb1975a 100644 --- a/server.js +++ b/server.js @@ -2691,10 +2691,10 @@ cache(function(data, match, sendBadge, request) { }); })); -// Code Climate test reports integration +// Code Climate integration. camp.route(/^\/codeclimate(\/(c|coverage|maintainability|issues)(-letter)?)?\/(.+)\.(svg|png|gif|jpg|json)$/, cache(function(data, match, sendBadge, request) { - // c and coverage are both equivalent. Top-level URL still supported for backwards compatibility. See #1387. + // Top-level and /coverage URLs equivalent to /c, still supported for backwards compatibility. See #1387. const type = match[2] === 'c' || !match[2] ? 'coverage' : match[2]; const isLetter = match[3]; const userRepo = match[4]; // eg, `Nickersoft/dql`. @@ -2718,12 +2718,9 @@ cache(function(data, match, sendBadge, request) { return; } - let branchData; - if (type === 'coverage') { - branchData = body.data[0].relationships.latest_default_branch_test_report.data; - } else { - branchData = body.data[0].relationships.latest_default_branch_snapshot.data; - } + const branchData = type === 'coverage' + ? body.data[0].relationships.latest_default_branch_test_report.data + : body.data[0].relationships.latest_default_branch_snapshot.data; if (branchData == null) { badgeData.text[1] = 'unknown'; sendBadge(format, badgeData); @@ -2756,7 +2753,7 @@ cache(function(data, match, sendBadge, request) { badgeData.text[1] = score; badgeData.colorscheme = letterScoreColor(score); } else if (type === 'maintainability') { - const percentage = parseFloat(parsedData.data.meta.measures.technical_debt_ratio.value); + const percentage = parseFloat(parsedData.data.attributes.ratings[0].measure.value); badgeData.text[1] = percentage.toFixed(0) + '%'; badgeData.colorscheme = colorScale([5, 10, 20, 50], ['brightgreen', 'green', 'yellowgreen', 'yellow', 'red'])(percentage); } diff --git a/service-tests/codeclimate.js b/service-tests/codeclimate.js index 8773ff0fd30cc..6336676750206 100644 --- a/service-tests/codeclimate.js +++ b/service-tests/codeclimate.js @@ -10,14 +10,14 @@ const t = new ServiceTester({ id: 'codeclimate', title: 'Code Climate' }) // Tests based on Code Climate's test reports endpoint. t.create('test coverage percentage') - .get('/coverage/Nickersoft/dql.json') + .get('/c/Nickersoft/dql.json') .expectJSONTypes(Joi.object().keys({ name: 'coverage', value: isPercentage })); -t.create('test coverage percentage alternative URL') - .get('/c/Nickersoft/dql.json') +t.create('test coverage percentage alternative coverage URL') + .get('/coverage/Nickersoft/dql.json') .expectJSONTypes(Joi.object().keys({ name: 'coverage', value: isPercentage @@ -31,21 +31,21 @@ t.create('test coverage percentage alternative top-level URL') })); t.create('test coverage letter') - .get('/coverage-letter/Nickersoft/dql.json') + .get('/c-letter/Nickersoft/dql.json') .expectJSONTypes(Joi.object().keys({ name: 'coverage', value: Joi.equal('A', 'B', 'C', 'D', 'E', 'F') })); t.create('test coverage percentage for non-existent repo') - .get('/coverage/unknown/unknown.json') + .get('/c/unknown/unknown.json') .expectJSON({ name: 'coverage', value: 'not found' }); t.create('test coverage percentage for repo without test reports') - .get('/coverage/kabisaict/flow.json') + .get('/c/kabisaict/flow.json') .expectJSON({ name: 'coverage', value: 'unknown' From 0b03f72766fef1ff4638197095fda3f45458b974 Mon Sep 17 00:00:00 2001 From: PyvesB Date: Wed, 27 Dec 2017 12:02:12 +0100 Subject: [PATCH 10/13] Changed badge label to technical debt --- server.js | 1 + service-tests/codeclimate.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/server.js b/server.js index 44ccedbb1975a..4fb2669beb855 100644 --- a/server.js +++ b/server.js @@ -2754,6 +2754,7 @@ cache(function(data, match, sendBadge, request) { badgeData.colorscheme = letterScoreColor(score); } else if (type === 'maintainability') { const percentage = parseFloat(parsedData.data.attributes.ratings[0].measure.value); + badgeData.text[0] = getLabel('technical debt', data); badgeData.text[1] = percentage.toFixed(0) + '%'; badgeData.colorscheme = colorScale([5, 10, 20, 50], ['brightgreen', 'green', 'yellowgreen', 'yellow', 'red'])(percentage); } diff --git a/service-tests/codeclimate.js b/service-tests/codeclimate.js index 6336676750206..9135b8a3d2b32 100644 --- a/service-tests/codeclimate.js +++ b/service-tests/codeclimate.js @@ -59,10 +59,10 @@ t.create('issues count') value: Joi.number().integer().positive() })); -t.create('maintainability percentage') +t.create('maintainability percentage (technical debt)') .get('/maintainability/Nickersoft/dql.json') .expectJSONTypes(Joi.object().keys({ - name: 'maintainability', + name: 'technical debt', value: isPercentage })); From ca86554e0d88c405a92fad0195e98eeb1a6e99a0 Mon Sep 17 00:00:00 2001 From: PyvesB Date: Tue, 23 Jan 2018 18:32:17 +0000 Subject: [PATCH 11/13] Switched tests to more mainstream projects as previous ones were deleted --- server.js | 2 +- service-tests/codeclimate.js | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/server.js b/server.js index 4fb2669beb855..146779bd99913 100644 --- a/server.js +++ b/server.js @@ -2697,7 +2697,7 @@ cache(function(data, match, sendBadge, request) { // Top-level and /coverage URLs equivalent to /c, still supported for backwards compatibility. See #1387. const type = match[2] === 'c' || !match[2] ? 'coverage' : match[2]; const isLetter = match[3]; - const userRepo = match[4]; // eg, `Nickersoft/dql`. + const userRepo = match[4]; // eg, `twbs/bootstrap`. const format = match[5]; request({ method: 'GET', diff --git a/service-tests/codeclimate.js b/service-tests/codeclimate.js index 9135b8a3d2b32..3ae5db5805947 100644 --- a/service-tests/codeclimate.js +++ b/service-tests/codeclimate.js @@ -10,28 +10,28 @@ const t = new ServiceTester({ id: 'codeclimate', title: 'Code Climate' }) // Tests based on Code Climate's test reports endpoint. t.create('test coverage percentage') - .get('/c/Nickersoft/dql.json') + .get('/c/jekyll/jekyll.json') .expectJSONTypes(Joi.object().keys({ name: 'coverage', value: isPercentage })); t.create('test coverage percentage alternative coverage URL') - .get('/coverage/Nickersoft/dql.json') + .get('/coverage/jekyll/jekyll.json') .expectJSONTypes(Joi.object().keys({ name: 'coverage', value: isPercentage })); t.create('test coverage percentage alternative top-level URL') - .get('/Nickersoft/dql.json') + .get('/jekyll/jekyll.json') .expectJSONTypes(Joi.object().keys({ name: 'coverage', value: isPercentage })); t.create('test coverage letter') - .get('/c-letter/Nickersoft/dql.json') + .get('/c-letter/jekyll/jekyll.json') .expectJSONTypes(Joi.object().keys({ name: 'coverage', value: Joi.equal('A', 'B', 'C', 'D', 'E', 'F') @@ -45,7 +45,7 @@ t.create('test coverage percentage for non-existent repo') }); t.create('test coverage percentage for repo without test reports') - .get('/c/kabisaict/flow.json') + .get('/c/angular/angular.js.json') .expectJSON({ name: 'coverage', value: 'unknown' @@ -53,21 +53,21 @@ t.create('test coverage percentage for repo without test reports') // Tests based on Code Climate's snapshots endpoint. t.create('issues count') - .get('/issues/Nickersoft/dql.json') + .get('/issues/angular/angular.js.json') .expectJSONTypes(Joi.object().keys({ name: 'issues', value: Joi.number().integer().positive() })); t.create('maintainability percentage (technical debt)') - .get('/maintainability/Nickersoft/dql.json') + .get('/maintainability/angular/angular.js.json') .expectJSONTypes(Joi.object().keys({ name: 'technical debt', value: isPercentage })); t.create('maintainability letter') - .get('/maintainability-letter/Nickersoft/dql.json') + .get('/maintainability-letter/angular/angular.js.json') .expectJSONTypes(Joi.object().keys({ name: 'maintainability', value: Joi.equal('A', 'B', 'C', 'D', 'E', 'F') From 780c6501063a61136e669cacedf19655bc37130a Mon Sep 17 00:00:00 2001 From: PyvesB Date: Tue, 23 Jan 2018 18:49:09 +0000 Subject: [PATCH 12/13] Rearranged badge URLs and default formats --- server.js | 36 ++++++++++++++++++++++++------------ service-tests/codeclimate.js | 18 +++++++++++++----- 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/server.js b/server.js index 146779bd99913..8b9ecaaf77d93 100644 --- a/server.js +++ b/server.js @@ -2692,11 +2692,19 @@ cache(function(data, match, sendBadge, request) { })); // Code Climate integration. -camp.route(/^\/codeclimate(\/(c|coverage|maintainability|issues)(-letter)?)?\/(.+)\.(svg|png|gif|jpg|json)$/, -cache(function(data, match, sendBadge, request) { - // Top-level and /coverage URLs equivalent to /c, still supported for backwards compatibility. See #1387. - const type = match[2] === 'c' || !match[2] ? 'coverage' : match[2]; - const isLetter = match[3]; +camp.route(/^\/codeclimate(\/(c|coverage|maintainability|issues|tech-debt)(-letter|-percentage)?)?\/(.+)\.(svg|png|gif|jpg|json)$/, +cache(function(data, match, sendBadge, request) { + let type; + if (match[2] === 'c' || !match[2]) { + // Top-level and /coverage URLs equivalent to /c, still supported for backwards compatibility. See #1387. + type = 'coverage'; + } else if (match[2] === 'tech-debt') { + type = 'technical debt'; + } else { + type = match[2]; + } + // For maintainability, default is letter, alternative is percentage. For coverage, default is percentage, alternative is letter. + const isAlternativeFormat = match[3]; const userRepo = match[4]; // eg, `twbs/bootstrap`. const format = match[5]; request({ @@ -2736,7 +2744,7 @@ cache(function(data, match, sendBadge, request) { } const parsedData = JSON.parse(buffer); - if (type === 'coverage' && isLetter) { + if (type === 'coverage' && isAlternativeFormat) { const score = parsedData.data.attributes.rating.letter; badgeData.text[1] = score; badgeData.colorscheme = letterScoreColor(score); @@ -2748,15 +2756,19 @@ cache(function(data, match, sendBadge, request) { const count = parsedData.data.meta.issues_count; badgeData.text[1] = count; badgeData.colorscheme = colorScale([1, 5, 10, 20], ['brightgreen', 'green', 'yellowgreen', 'yellow', 'red'])(count); - } else if (type === 'maintainability' && isLetter) { - const score = parsedData.data.attributes.ratings[0].letter; - badgeData.text[1] = score; - badgeData.colorscheme = letterScoreColor(score); - } else if (type === 'maintainability') { + } else if (type === 'technical debt') { const percentage = parseFloat(parsedData.data.attributes.ratings[0].measure.value); - badgeData.text[0] = getLabel('technical debt', data); badgeData.text[1] = percentage.toFixed(0) + '%'; badgeData.colorscheme = colorScale([5, 10, 20, 50], ['brightgreen', 'green', 'yellowgreen', 'yellow', 'red'])(percentage); + } else if (type === 'maintainability' && isAlternativeFormat) { + // maintainability = 100 - technical debt + const percentage = 100 - parseFloat(parsedData.data.attributes.ratings[0].measure.value); + badgeData.text[1] = percentage.toFixed(0) + '%'; + badgeData.colorscheme = colorScale([50, 80, 90, 95], ['red', 'yellow', 'yellowgreen', 'green', 'brightgreen'])(percentage); + } else if (type === 'maintainability') { + const score = parsedData.data.attributes.ratings[0].letter; + badgeData.text[1] = score; + badgeData.colorscheme = letterScoreColor(score); } sendBadge(format, badgeData); }); diff --git a/service-tests/codeclimate.js b/service-tests/codeclimate.js index 3ae5db5805947..02ddae2abe687 100644 --- a/service-tests/codeclimate.js +++ b/service-tests/codeclimate.js @@ -59,28 +59,36 @@ t.create('issues count') value: Joi.number().integer().positive() })); -t.create('maintainability percentage (technical debt)') - .get('/maintainability/angular/angular.js.json') +t.create('technical debt percentage') + .get('/tech-debt/angular/angular.js.json') .expectJSONTypes(Joi.object().keys({ name: 'technical debt', value: isPercentage })); +t.create('maintainability percentage') + .get('/maintainability-percentage/angular/angular.js.json') + .expectJSONTypes(Joi.object().keys({ + name: 'maintainability', + value: isPercentage + })); + + t.create('maintainability letter') - .get('/maintainability-letter/angular/angular.js.json') + .get('/maintainability/angular/angular.js.json') .expectJSONTypes(Joi.object().keys({ name: 'maintainability', value: Joi.equal('A', 'B', 'C', 'D', 'E', 'F') })); -t.create('maintainability percentage for non-existent repo') +t.create('maintainability letter for non-existent repo') .get('/maintainability/unknown/unknown.json') .expectJSON({ name: 'maintainability', value: 'not found' }); -t.create('maintainability percentage for repo without snapshots') +t.create('maintainability letter for repo without snapshots') .get('/maintainability/kabisaict/flow.json') .expectJSON({ name: 'maintainability', From f785cedc90a6cbd43b62ad3eb7d972f25be3b0ea Mon Sep 17 00:00:00 2001 From: PyvesB Date: Tue, 23 Jan 2018 19:02:45 +0000 Subject: [PATCH 13/13] Updated examples --- lib/all-badge-examples.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/all-badge-examples.js b/lib/all-badge-examples.js index 17b09369b4be2..0460ceb3bc067 100644 --- a/lib/all-badge-examples.js +++ b/lib/all-badge-examples.js @@ -1222,23 +1222,27 @@ const allBadgeExamples = [ examples: [ { title: 'Code Climate', - previewUri: '/codeclimate/c/Nickersoft/dql.svg' + previewUri: '/codeclimate/issues/twbs/bootstrap.svg' }, { title: 'Code Climate', - previewUri: '/codeclimate/c-letter/Nickersoft/dql.svg' + previewUri: '/codeclimate/maintainability/angular/angular.js.svg' }, { title: 'Code Climate', - previewUri: '/codeclimate/issues/github/me-and/mdf.svg' + previewUri: '/codeclimate/maintainability-percentage/angular/angular.js.svg' }, { title: 'Code Climate', - previewUri: '/codeclimate/maintainability/Nickersoft/dql.svg' + previewUri: '/codeclimate/coverage/jekyll/jekyll.svg' }, { title: 'Code Climate', - previewUri: '/codeclimate/maintainability-letter/Nickersoft/dql.svg' + previewUri: '/codeclimate/coverage-letter/jekyll/jekyll.svg' + }, + { + title: 'Code Climate', + previewUri: '/codeclimate/tech-debt/jekyll/jekyll.svg' }, { title: 'bitHound',