Add grade badge for [lgtm] (#1681)
* Add LGTM Grade badge * Add new tests for LGTM Grade badge * Add lgtm grade example to homepage
This commit is contained in:
@@ -301,6 +301,10 @@ const allBadgeExamples = [
|
||||
title: 'LGTM Alerts',
|
||||
previewUri: '/lgtm/alerts/g/apache/cloudstack.svg'
|
||||
},
|
||||
{
|
||||
title: 'LGTM Grade',
|
||||
previewUri: '/lgtm/grade/java/g/apache/cloudstack.svg'
|
||||
},
|
||||
{
|
||||
title: 'HHVM',
|
||||
previewUri: '/hhvm/symfony/symfony.svg'
|
||||
|
||||
61
server.js
61
server.js
@@ -1098,6 +1098,67 @@ cache(function(data, match, sendBadge, request) {
|
||||
});
|
||||
}));
|
||||
|
||||
// LGTM grades integration
|
||||
camp.route(/^\/lgtm\/grade\/([^/]+)\/(.+)\.(svg|png|gif|jpg|json)$/,
|
||||
cache(function(data, match, sendBadge, request) {
|
||||
const language = match[1]; // eg, `java`
|
||||
const projectId = match[2]; // eg, `g/apache/cloudstack`
|
||||
const format = match[3];
|
||||
const url = 'https://lgtm.com/api/v0.1/project/' + projectId + '/details';
|
||||
const languageLabel = (() => {
|
||||
switch(language) {
|
||||
case 'cpp':
|
||||
return 'c/c++';
|
||||
case 'csharp':
|
||||
return 'c#';
|
||||
// Javascript analysis on LGTM also includes TypeScript
|
||||
case 'javascript':
|
||||
return 'js/ts';
|
||||
default:
|
||||
return language;
|
||||
}
|
||||
})();
|
||||
const badgeData = getBadgeData('code quality: ' + languageLabel, data);
|
||||
request(url, function(err, res, buffer) {
|
||||
if (checkErrorResponse(badgeData, err, res, 'project not found')) {
|
||||
sendBadge(format, badgeData);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const data = JSON.parse(buffer);
|
||||
if (!('languages' in data))
|
||||
throw new Error("Invalid data");
|
||||
for (const languageData of data.languages) {
|
||||
if (languageData.lang === language && 'grade' in languageData) {
|
||||
// Pretty label for the language
|
||||
badgeData.text[1] = languageData.grade;
|
||||
// Pick colour based on grade
|
||||
if (languageData.grade === 'A+') {
|
||||
badgeData.colorscheme = 'brightgreen';
|
||||
} else if (languageData.grade === 'A') {
|
||||
badgeData.colorscheme = 'green';
|
||||
} else if (languageData.grade === 'B') {
|
||||
badgeData.colorscheme = 'yellowgreen';
|
||||
} else if (languageData.grade === 'C') {
|
||||
badgeData.colorscheme = 'yellow';
|
||||
} else if (languageData.grade === 'D') {
|
||||
badgeData.colorscheme = 'orange';
|
||||
} else {
|
||||
badgeData.colorscheme = 'red';
|
||||
}
|
||||
sendBadge(format, badgeData);
|
||||
return;
|
||||
}
|
||||
}
|
||||
badgeData.text[1] = 'no data for language';
|
||||
sendBadge(format, badgeData);
|
||||
} catch(e) {
|
||||
badgeData.text[1] = 'invalid';
|
||||
sendBadge(format, badgeData);
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
// Gratipay integration.
|
||||
camp.route(/^\/(?:gittip|gratipay(\/user|\/team|\/project)?)\/(.*)\.(svg|png|gif|jpg|json)$/,
|
||||
cache(function(queryParams, match, sendBadge, request) {
|
||||
|
||||
@@ -6,56 +6,161 @@ const ServiceTester = require('../service-tester');
|
||||
const t = new ServiceTester({ id: 'lgtm', title: 'LGTM' })
|
||||
module.exports = t;
|
||||
|
||||
t.create('total alerts for a project')
|
||||
// Alerts Badge
|
||||
|
||||
t.create('alerts: total alerts for a project')
|
||||
.get('/alerts/g/apache/cloudstack.json')
|
||||
.expectJSONTypes(Joi.object().keys({
|
||||
name: 'lgtm',
|
||||
value: Joi.string().regex(/^[0-9kM.]+ alerts?$/)
|
||||
}));
|
||||
|
||||
t.create('missing project')
|
||||
t.create('alerts: missing project')
|
||||
.get('/alerts/g/some-org/this-project-doesnt-exist.json')
|
||||
.expectJSON({
|
||||
name: 'lgtm',
|
||||
value: 'project not found'
|
||||
});
|
||||
|
||||
t.create('no alerts')
|
||||
t.create('alerts: no alerts')
|
||||
.get('/alerts/g/apache/cloudstack.json')
|
||||
.intercept(nock => nock('https://lgtm.com')
|
||||
.get('/api/v0.1/project/g/apache/cloudstack/details')
|
||||
.reply(200, {alerts: 0}))
|
||||
.expectJSON({ name: 'lgtm', value: '0 alerts' });
|
||||
|
||||
t.create('single alert')
|
||||
t.create('alerts: single alert')
|
||||
.get('/alerts/g/apache/cloudstack.json')
|
||||
.intercept(nock => nock('https://lgtm.com')
|
||||
.get('/api/v0.1/project/g/apache/cloudstack/details')
|
||||
.reply(200, {alerts: 1}))
|
||||
.expectJSON({ name: 'lgtm', value: '1 alert' });
|
||||
|
||||
t.create('multiple alerts')
|
||||
t.create('alerts: multiple alerts')
|
||||
.get('/alerts/g/apache/cloudstack.json')
|
||||
.intercept(nock => nock('https://lgtm.com')
|
||||
.get('/api/v0.1/project/g/apache/cloudstack/details')
|
||||
.reply(200, {alerts: 123}))
|
||||
.expectJSON({ name: 'lgtm', value: '123 alerts' });
|
||||
|
||||
t.create('json missing alerts')
|
||||
t.create('alerts: json missing alerts')
|
||||
.get('/alerts/g/apache/cloudstack.json')
|
||||
.intercept(nock => nock('https://lgtm.com')
|
||||
.get('/api/v0.1/project/g/apache/cloudstack/details')
|
||||
.reply(200, {}))
|
||||
.expectJSON({ name: 'lgtm', value: 'invalid' });
|
||||
|
||||
t.create('invalid json')
|
||||
t.create('alerts: invalid json')
|
||||
.get('/alerts/g/apache/cloudstack.json')
|
||||
.intercept(nock => nock('https://lgtm.com')
|
||||
.get('/api/v0.1/project/g/apache/cloudstack/details')
|
||||
.reply(200, 'not a json string'))
|
||||
.expectJSON({ name: 'lgtm', value: 'invalid' });
|
||||
|
||||
t.create('lgtm inaccessible')
|
||||
t.create('alerts: lgtm inaccessible')
|
||||
.get('/alerts/g/apache/cloudstack.json')
|
||||
.networkOff()
|
||||
.expectJSON({ name: 'lgtm', value: 'inaccessible' });
|
||||
.expectJSON({ name: 'lgtm', value: 'inaccessible' });
|
||||
|
||||
// Grade Badge
|
||||
|
||||
t.create('grade: missing project')
|
||||
.get('/grade/java/g/some-org/this-project-doesnt-exist.json')
|
||||
.expectJSON({
|
||||
name: 'code quality: java',
|
||||
value: 'project not found'
|
||||
});
|
||||
|
||||
t.create('grade: lgtm inaccessible')
|
||||
.get('/grade/java/g/apache/cloudstack.json')
|
||||
.networkOff()
|
||||
.expectJSON({ name: 'code quality: java', value: 'inaccessible' });
|
||||
|
||||
t.create('grade: invalid json')
|
||||
.get('/grade/java/g/apache/cloudstack.json')
|
||||
.intercept(nock => nock('https://lgtm.com')
|
||||
.get('/api/v0.1/project/g/apache/cloudstack/details')
|
||||
.reply(200, 'not a json string'))
|
||||
.expectJSON({ name: 'code quality: java', value: 'invalid' });
|
||||
|
||||
t.create('grade: json missing languages')
|
||||
.get('/grade/java/g/apache/cloudstack.json')
|
||||
.intercept(nock => nock('https://lgtm.com')
|
||||
.get('/api/v0.1/project/g/apache/cloudstack/details')
|
||||
.reply(200, {}))
|
||||
.expectJSON({ name: 'code quality: java', value: 'invalid' });
|
||||
|
||||
t.create('grade: grade for a project (java)')
|
||||
.get('/grade/java/g/apache/cloudstack.json')
|
||||
.expectJSONTypes(Joi.object().keys({
|
||||
name: 'code quality: java',
|
||||
value: Joi.string().regex(/^(?:A\+)|A|B|C|D|E$/)
|
||||
}));
|
||||
|
||||
t.create('grade: grade for missing language')
|
||||
.get('/grade/foo/g/apache/cloudstack.json')
|
||||
.expectJSON({
|
||||
name: 'code quality: foo',
|
||||
value: 'no data for language'
|
||||
});
|
||||
|
||||
// Test display of languages
|
||||
|
||||
const data = {languages: [
|
||||
{lang: 'cpp', grade: 'A+'},
|
||||
{lang: 'javascript', grade: 'A'},
|
||||
{lang: 'java', grade: 'B'},
|
||||
{lang: 'python', grade: 'C'},
|
||||
{lang: 'csharp', grade: 'D'},
|
||||
{lang: 'other', grade: 'E'},
|
||||
{lang: 'foo'}
|
||||
]}
|
||||
|
||||
t.create('grade: cpp')
|
||||
.get('/grade/cpp/g/apache/cloudstack.json')
|
||||
.intercept(nock => nock('https://lgtm.com')
|
||||
.get('/api/v0.1/project/g/apache/cloudstack/details')
|
||||
.reply(200, data))
|
||||
.expectJSON({ name: 'code quality: c/c++', value: 'A+' });
|
||||
|
||||
t.create('grade: javascript')
|
||||
.get('/grade/javascript/g/apache/cloudstack.json')
|
||||
.intercept(nock => nock('https://lgtm.com')
|
||||
.get('/api/v0.1/project/g/apache/cloudstack/details')
|
||||
.reply(200, data))
|
||||
.expectJSON({ name: 'code quality: js/ts', value: 'A' });
|
||||
|
||||
t.create('grade: java')
|
||||
.get('/grade/java/g/apache/cloudstack.json')
|
||||
.intercept(nock => nock('https://lgtm.com')
|
||||
.get('/api/v0.1/project/g/apache/cloudstack/details')
|
||||
.reply(200, data))
|
||||
.expectJSON({ name: 'code quality: java', value: 'B' });
|
||||
|
||||
t.create('grade: python')
|
||||
.get('/grade/python/g/apache/cloudstack.json')
|
||||
.intercept(nock => nock('https://lgtm.com')
|
||||
.get('/api/v0.1/project/g/apache/cloudstack/details')
|
||||
.reply(200, data))
|
||||
.expectJSON({ name: 'code quality: python', value: 'C' });
|
||||
|
||||
t.create('grade: csharp')
|
||||
.get('/grade/csharp/g/apache/cloudstack.json')
|
||||
.intercept(nock => nock('https://lgtm.com')
|
||||
.get('/api/v0.1/project/g/apache/cloudstack/details')
|
||||
.reply(200, data))
|
||||
.expectJSON({ name: 'code quality: c#', value: 'D' });
|
||||
|
||||
t.create('grade: other')
|
||||
.get('/grade/other/g/apache/cloudstack.json')
|
||||
.intercept(nock => nock('https://lgtm.com')
|
||||
.get('/api/v0.1/project/g/apache/cloudstack/details')
|
||||
.reply(200, data))
|
||||
.expectJSON({ name: 'code quality: other', value: 'E' });
|
||||
|
||||
t.create('grade: foo (no grade for valid language)')
|
||||
.get('/grade/foo/g/apache/cloudstack.json')
|
||||
.intercept(nock => nock('https://lgtm.com')
|
||||
.get('/api/v0.1/project/g/apache/cloudstack/details')
|
||||
.reply(200, data))
|
||||
.expectJSON({ name: 'code quality: foo', value: 'no data for language' });
|
||||
|
||||
Reference in New Issue
Block a user