refactor [circleci] integration (#1927)

* refactor [circleci] integration
This commit is contained in:
chris48s
2018-08-28 15:49:43 +01:00
committed by GitHub
parent edea36dd10
commit e294dc4edc
4 changed files with 97 additions and 124 deletions

View File

@@ -167,24 +167,6 @@ const allBadgeExamples = [
title: 'Codeship',
previewUri: '/codeship/d6c1ddd0-16a3-0132-5f85-2e35c05e22b1/master.svg',
},
{
title: 'CircleCI',
previewUri: '/circleci/project/github/RedSparr0w/node-csgo-parser.svg',
},
{
title: 'CircleCI branch',
previewUri:
'/circleci/project/github/RedSparr0w/node-csgo-parser/master.svg',
},
{
title: 'CircleCI token',
previewUri:
'/circleci/project/github/RedSparr0w/node-csgo-parser/master.svg',
urlPattern:
'/circleci/token/:token/project/github/RedSparr0w/node-csgo-parser/master.svg',
exampleUri:
'/circleci/token/b90b5c49e59a4c67ba3a92f7992587ac7a0408c2/project/github/RedSparr0w/node-csgo-parser/master.svg',
},
{
title: 'Visual Studio Team services',
previewUri:

View File

@@ -3,7 +3,6 @@
const dom = require('xmldom').DOMParser;
const jp = require('jsonpath');
const path = require('path');
const queryString = require('query-string');
const xpath = require('xpath');
const yaml = require('js-yaml');
const Raven = require('raven');
@@ -118,85 +117,6 @@ loadServiceClasses().forEach(
{ camp, handleRequest: cache, githubApiProvider },
{ handleInternalErrors: config.handleInternalErrors }));
// CircleCI build integration.
// https://circleci.com/api/v1/project/BrightFlair/PHP.Gt?circle-token=0a5143728784b263d9f0238b8d595522689b3af2&limit=1&filter=completed
camp.route(/^\/circleci\/(?:token\/(\w+))?[+/]?project\/(?:(github|bitbucket)\/)?([^/]+\/[^/]+)(?:\/(.*))?\.(svg|png|gif|jpg|json)$/,
cache(function(data, match, sendBadge, request) {
const token = match[1];
const type = match[2] || 'github'; // github OR bitbucket
const userRepo = match[3]; // eg, `RedSparr0w/node-csgo-parser`.
const branch = match[4];
const format = match[5];
// Base API URL
let apiUrl = 'https://circleci.com/api/v1.1/project/' + type + '/' + userRepo;
// Query Params
var queryParams = {};
queryParams['limit'] = 1;
queryParams['filter'] = 'completed';
// Custom Banch if present
if (branch != null) {
apiUrl += "/tree/" + branch;
}
// Append Token to Query Params if present
if (token) {
queryParams['circle-token'] = token;
}
// Apprend query params to API URL
apiUrl += '?' + queryString.stringify(queryParams);
const badgeData = getBadgeData('build', data);
request(apiUrl, { json:true }, function(err, res, data) {
if (checkErrorResponse(badgeData, err, res, { 404: 'project not found' })) {
sendBadge(format, badgeData);
return;
}
try {
if (data.message !== undefined){
badgeData.text[1] = data.message;
sendBadge(format, badgeData);
return;
}
let passCount = 0;
let status;
for (let i=0; i<data.length; i++) {
status = data[i].status;
if (['success', 'fixed'].includes(status)) {
passCount++;
} else if (status === 'failed') {
badgeData.colorscheme = 'red';
badgeData.text[1] = 'failed';
sendBadge(format, badgeData);
return;
} else if (['no_tests', 'scheduled', 'not_run'].includes(status)) {
badgeData.colorscheme = 'yellow';
badgeData.text[1] = status.replace('_', ' ');
sendBadge(format, badgeData);
return;
} else {
badgeData.text[1] = status.replace('_', ' ');
sendBadge(format, badgeData);
return;
}
}
if (passCount === data.length) {
badgeData.colorscheme = 'brightgreen';
badgeData.text[1] = 'passing';
}
sendBadge(format, badgeData);
} catch(e) {
badgeData.text[1] = 'invalid';
sendBadge(format, badgeData);
}
});
}));
// User defined sources - JSON response
camp.route(/^\/badge\/dynamic\/(json|xml|yaml)\.(svg|png|gif|jpg|json)$/,
cache({

View File

@@ -0,0 +1,89 @@
'use strict'
const Joi = require('joi')
const BaseJsonService = require('../base-json')
const circleSchema = Joi.array()
.items(Joi.object({ status: Joi.string().required() }))
.min(1)
.max(1)
.required()
module.exports = class CircleCi extends BaseJsonService {
async fetch({ token, vcsType, userRepo, branch }) {
let url = `https://circleci.com/api/v1.1/project/${vcsType}/${userRepo}`
if (branch != null) {
url += `/tree/${branch}`
}
const query = { filter: 'completed', limit: 1 }
if (token) {
query['circle-token'] = token
}
return this._requestJson({
url,
schema: circleSchema,
options: { qs: query },
errorMessages: { 404: 'project not found' },
})
}
static render({ status }) {
if (['success', 'fixed'].includes(status)) {
return { message: 'passing', color: 'brightgreen' }
} else if (status === 'failed') {
return { message: 'failed', color: 'red' }
} else if (['no_tests', 'scheduled', 'not_run'].includes(status)) {
return { message: status.replace('_', ' '), color: 'yellow' }
} else {
return { message: status.replace('_', ' '), color: 'lightgrey' }
}
}
async handle({ token, vcsType, userRepo, branch }) {
const json = await this.fetch({ token, vcsType, userRepo, branch })
return this.constructor.render({ status: json[0].status })
}
// Metadata
static get defaultBadgeData() {
return { label: 'build' }
}
static get category() {
return 'build'
}
static get url() {
return {
base: 'circleci',
format:
'(?:token/(w+))?[+/]?project/(?:(github|bitbucket)/)?([^/]+/[^/]+)(?:/(.*))?',
capture: ['token', 'vcsType', 'userRepo', 'branch'],
}
}
static get examples() {
return [
{
title: 'CircleCI (all branches)',
exampleUrl: 'project/github/RedSparr0w/node-csgo-parser',
urlPattern: 'project/:vcsType/:owner/:repo',
staticExample: this.render({ status: 'success' }),
},
{
title: 'CircleCI branch',
exampleUrl: 'project/github/RedSparr0w/node-csgo-parser/master',
urlPattern: 'project/:vcsType/:owner/:repo/:branch',
staticExample: this.render({ status: 'success' }),
},
{
title: 'CircleCI token',
urlPattern:
'circleci/token/:token/project/:vcsType/:owner/:repo/:branch',
exampleUrl:
'circleci/token/b90b5c49e59a4c67ba3a92f7992587ac7a0408c2/project/github/RedSparr0w/node-csgo-parser/master',
staticExample: this.render({ status: 'success' }),
},
]
}
}

View File

@@ -2,7 +2,6 @@
const Joi = require('joi')
const ServiceTester = require('../service-tester')
const { invalidJSON } = require('../response-fixtures')
const { isBuildStatus } = require('../test-validators')
const t = new ServiceTester({ id: 'circleci', title: 'Circle CI' })
@@ -35,17 +34,6 @@ t.create('circle ci (connection error)')
.networkOff()
.expectJSON({ name: 'build', value: 'inaccessible' })
t.create('circle ci (unexpected response)')
.get('/project/github/RedSparr0w/node-csgo-parser.json')
.intercept(nock =>
nock('https://circleci.com')
.get(
'/api/v1.1/project/github/RedSparr0w/node-csgo-parser?filter=completed&limit=1'
)
.reply(invalidJSON)
)
.expectJSON({ name: 'build', value: 'invalid' })
t.create('circle ci (no response data)')
.get('/project/github/RedSparr0w/node-csgo-parser.json')
.intercept(nock =>
@@ -55,9 +43,10 @@ t.create('circle ci (no response data)')
)
.reply(200)
)
.expectJSON({ name: 'build', value: 'invalid' })
.expectJSON({ name: 'build', value: 'unparseable json response' })
t.create('circle ci (multiple pipelines, pass)')
// we're passing &limit=1 so we expect exactly one array element
t.create('circle ci (invalid json)')
.get('/project/github/RedSparr0w/node-csgo-parser.json?style=_shields_test')
.intercept(nock =>
nock('https://circleci.com')
@@ -66,15 +55,8 @@ t.create('circle ci (multiple pipelines, pass)')
)
.reply(200, [{ status: 'success' }, { status: 'fixed' }])
)
.expectJSON({ name: 'build', value: 'passing', colorB: '#4c1' })
t.create('circle ci (multiple pipelines, fail)')
.get('/project/github/RedSparr0w/node-csgo-parser.json?style=_shields_test')
.intercept(nock =>
nock('https://circleci.com')
.get(
'/api/v1.1/project/github/RedSparr0w/node-csgo-parser?filter=completed&limit=1'
)
.reply(200, [{ status: 'success' }, { status: 'failed' }])
)
.expectJSON({ name: 'build', value: 'failed', colorB: '#e05d44' })
.expectJSON({
name: 'build',
value: 'invalid json response',
colorB: '#9f9f9f',
})