diff --git a/services/bitrise/bitrise.service.js b/services/bitrise/bitrise.service.js index abe3c64c9396b2b4c3c31d1b02caa08b29885f09..4df98eb7d452aa38601fa328dfa6b3e4e9584989 100644 --- a/services/bitrise/bitrise.service.js +++ b/services/bitrise/bitrise.service.js @@ -1,15 +1,18 @@ 'use strict' -const LegacyService = require('../legacy-service') -const { makeBadgeData: getBadgeData } = require('../../lib/badge-data') +const Joi = require('joi') +const { BaseJsonService } = require('..') -// This legacy service should be rewritten to use e.g. BaseJsonService. -// -// Tips for rewriting: -// https://github.com/badges/shields/blob/master/doc/rewriting-services.md -// -// Do not base new services on this code. -module.exports = class Bitrise extends LegacyService { +// https://devcenter.bitrise.io/api/app-status-badge/ +const schema = Joi.object({ + status: Joi.equal('success', 'error', 'unknown'), +}).required() + +const queryParamSchema = Joi.object({ + token: Joi.string().required(), +}).required() + +module.exports = class Bitrise extends BaseJsonService { static get category() { return 'build' } @@ -17,7 +20,8 @@ module.exports = class Bitrise extends LegacyService { static get route() { return { base: 'bitrise', - pattern: ':appId/:branch', + pattern: ':appId/:branch?', + queryParamSchema, } } @@ -27,56 +31,51 @@ module.exports = class Bitrise extends LegacyService { title: 'Bitrise', namedParams: { appId: 'cde737473028420d', branch: 'master' }, queryParams: { token: 'GCIdEzacE4GW32jLVrZb7A' }, - staticPreview: { - label: 'bitrise', - message: 'success', - color: 'brightgreen', - }, + staticPreview: this.render({ status: 'success' }), }, ] } - static registerLegacyRouteHandler({ camp, cache }) { - camp.route( - /^\/bitrise\/([^/]+)(?:\/(.+))?\.(svg|png|gif|jpg|json)$/, - cache({ - queryParams: ['token'], - handler: (data, match, sendBadge, request) => { - const appId = match[1] - const branch = match[2] - const format = match[3] - const token = data.token - const badgeData = getBadgeData('bitrise', data) - let apiUrl = `https://app.bitrise.io/app/${appId}/status.json?token=${token}` - if (typeof branch !== 'undefined') { - apiUrl += `&branch=${branch}` - } + static get defaultBadgeData() { + return { + label: 'bitrise', + } + } + + async fetch({ appId, branch, token }) { + return this._requestJson({ + url: `https://app.bitrise.io/app/${encodeURIComponent( + appId + )}/status.json`, + options: { qs: { token, branch } }, + schema, + errorMessages: { + 403: 'app not found or invalid token', + }, + }) + } - const statusColorScheme = { - success: 'brightgreen', - error: 'red', - unknown: 'lightgrey', - } + static render({ status }) { + const color = { + success: 'brightgreen', + error: 'red', + unknown: 'lightgrey', + }[status] - request(apiUrl, { json: true }, (err, res, data) => { - try { - if (!res || err !== null || res.statusCode !== 200) { - badgeData.text[1] = 'inaccessible' - sendBadge(format, badgeData) - return - } + let message + if (status === 'unknown') { + // This is the only case mentioned in the API docs. If we get feedback + // it's often wrong we can update this. + message = 'branch not found' + } else { + message = status + } - badgeData.text[1] = data.status - badgeData.colorscheme = statusColorScheme[data.status] + return { message, color } + } - sendBadge(format, badgeData) - } catch (e) { - badgeData.text[1] = 'invalid' - sendBadge(format, badgeData) - } - }) - }, - }) - ) + async handle({ appId, branch }, { token }) { + const { status } = await this.fetch({ appId, branch, token }) + return this.constructor.render({ status }) } } diff --git a/services/bitrise/bitrise.tester.js b/services/bitrise/bitrise.tester.js index 24b357f82d41d310b13a5e0bcaf1d034ac016844..b31ba9f78ea99b6704a78d04bc8c95ddce607ca5 100644 --- a/services/bitrise/bitrise.tester.js +++ b/services/bitrise/bitrise.tester.js @@ -1,53 +1,30 @@ 'use strict' -const Joi = require('joi') -const { ServiceTester } = require('../tester') - -const t = (module.exports = new ServiceTester({ - id: 'bitrise', - title: 'Bitrise', -})) +const { isBuildStatus } = require('../build-status') +const t = (module.exports = require('../tester').createServiceTester()) t.create('deploy status') - .get('/cde737473028420d/master.json?token=GCIdEzacE4GW32jLVrZb7A') - .expectJSONTypes( - Joi.object().keys({ - name: 'bitrise', - value: Joi.equal('success', 'error', 'unknown'), - }) - ) - -t.create('deploy status without branch') .get('/cde737473028420d.json?token=GCIdEzacE4GW32jLVrZb7A') - .expectJSONTypes( - Joi.object().keys({ - name: 'bitrise', - value: Joi.equal('success', 'error', 'unknown'), - }) - ) + .expectBadge({ + label: 'bitrise', + message: isBuildStatus, + }) + +t.create('deploy status with branch') + .get('/cde737473028420d/master.json?token=GCIdEzacE4GW32jLVrZb7A') + .expectBadge({ + label: 'bitrise', + message: isBuildStatus, + }) t.create('unknown branch') .get('/cde737473028420d/unknown.json?token=GCIdEzacE4GW32jLVrZb7A') - .expectJSON({ name: 'bitrise', value: 'unknown' }) + .expectBadge({ label: 'bitrise', message: 'branch not found' }) t.create('invalid token') .get('/cde737473028420d/unknown.json?token=token') - .expectJSON({ name: 'bitrise', value: 'inaccessible' }) + .expectBadge({ label: 'bitrise', message: 'app not found or invalid token' }) t.create('invalid App ID') .get('/invalid/master.json?token=GCIdEzacE4GW32jLVrZb7A') - .expectJSON({ name: 'bitrise', value: 'inaccessible' }) - -t.create('server error') - .get('/AppID/branch.json?token=token') - .intercept(nock => - nock('https://app.bitrise.io') - .get('/app/AppID/status.json?token=token&branch=branch') - .reply(500, 'Something went wrong') - ) - .expectJSON({ name: 'bitrise', value: 'inaccessible' }) - -t.create('connection error') - .get('/AppID/branch.json?token=token') - .networkOff() - .expectJSON({ name: 'bitrise', value: 'inaccessible' }) + .expectBadge({ label: 'bitrise', message: 'app not found or invalid token' })