diff --git a/services/cocoapods/cocoapods-base.js b/services/cocoapods/cocoapods-base.js new file mode 100644 index 0000000000..240d69d59a --- /dev/null +++ b/services/cocoapods/cocoapods-base.js @@ -0,0 +1,25 @@ +'use strict' + +const Joi = require('joi') +const { BaseJsonService } = require('..') + +const schema = Joi.object({ + version: Joi.string().required(), + license: Joi.alternatives( + Joi.string().required(), + Joi.object({ + type: Joi.string().required(), + }).required() + ).required(), + // https://github.com/badges/shields/pull/209 + platforms: Joi.object().default({ ios: '5.0', osx: '10.7' }), +}).required() + +module.exports = class BaseCocoaPodsService extends BaseJsonService { + async fetch({ spec }) { + return this._requestJson({ + schema, + url: `https://trunk.cocoapods.org/api/v1/pods/${spec}/specs/latest`, + }) + } +} diff --git a/services/cocoapods/cocoapods-docs.service.js b/services/cocoapods/cocoapods-docs.service.js new file mode 100644 index 0000000000..6110b651bd --- /dev/null +++ b/services/cocoapods/cocoapods-docs.service.js @@ -0,0 +1,62 @@ +'use strict' + +const { + coveragePercentage: coveragePercentageColor, +} = require('../../lib/color-formatters') +const Joi = require('joi') +const { BaseJsonService } = require('..') + +const schema = Joi.object({ + cocoadocs: Joi.object({ + doc_percent: Joi.number() + .allow(null) + .required(), + }).required(), +}).required() + +module.exports = class CocoapodsDocs extends BaseJsonService { + static get category() { + return 'analysis' + } + + static get route() { + return { + base: 'cocoapods/metrics/doc-percent', + pattern: ':spec', + } + } + + static get examples() { + return [ + { + title: 'Cocoapods doc percentage', + namedParams: { spec: 'AFNetworking' }, + staticPreview: this.render({ percentage: 94 }), + }, + ] + } + + async fetch({ spec }) { + return this._requestJson({ + schema, + url: `https://metrics.cocoapods.org/api/v1/pods/${spec}`, + }) + } + + static render({ percentage }) { + return { + message: `${percentage}%`, + color: coveragePercentageColor(percentage), + } + } + + async handle({ spec }) { + const data = await this.fetch({ spec }) + const percentage = data.cocoadocs.doc_percent || 0 + return this.constructor.render({ percentage }) + } + + static get defaultBadgeData() { + return { label: 'docs' } + } +} diff --git a/services/cocoapods/cocoapods-metrics.tester.js b/services/cocoapods/cocoapods-docs.tester.js similarity index 61% rename from services/cocoapods/cocoapods-metrics.tester.js rename to services/cocoapods/cocoapods-docs.tester.js index 5ced9e19e7..3edb8992c2 100644 --- a/services/cocoapods/cocoapods-metrics.tester.js +++ b/services/cocoapods/cocoapods-docs.tester.js @@ -1,7 +1,6 @@ 'use strict' const Joi = require('joi') -const { invalidJSON } = require('../response-fixtures') const { isIntegerPercentage } = require('../test-validators') const t = (module.exports = require('../tester').createServiceTester()) @@ -27,17 +26,3 @@ t.create('doc percent (null)') t.create('doc percent (not found)') .get('/not-a-package.json') .expectJSON({ name: 'docs', value: 'not found' }) - -t.create('doc percent (connection error)') - .get('/AFNetworking.json') - .networkOff() - .expectJSON({ name: 'docs', value: 'inaccessible' }) - -t.create('doc percent (unexpected response)') - .get('/AFNetworking.json') - .intercept(nock => - nock('https://metrics.cocoapods.org') - .get('/api/v1/pods/AFNetworking') - .reply(invalidJSON) - ) - .expectJSON({ name: 'docs', value: 'invalid' }) diff --git a/services/cocoapods/cocoapods-license.service.js b/services/cocoapods/cocoapods-license.service.js index ecee193d93..56ccf7e3aa 100644 --- a/services/cocoapods/cocoapods-license.service.js +++ b/services/cocoapods/cocoapods-license.service.js @@ -1,8 +1,8 @@ 'use strict' -const LegacyService = require('../legacy-service') +const BaseCocoaPodsService = require('./cocoapods-base') -module.exports = class CocoapodsLicense extends LegacyService { +module.exports = class CocoapodsLicense extends BaseCocoaPodsService { static get category() { return 'license' } @@ -19,11 +19,27 @@ module.exports = class CocoapodsLicense extends LegacyService { { title: 'Cocoapods', namedParams: { spec: 'AFNetworking' }, - staticPreview: { label: 'license', message: 'MIT', color: '000' }, + staticPreview: this.render({ license: 'MIT' }), }, ] } - // Legacy route handler is defined in cocoapods.service.js. - static registerLegacyRouteHandler() {} + static render({ license }) { + return { + message: license, + // https://github.com/badges/shields/pull/184 + color: '#373737', + } + } + + async handle({ spec }) { + const data = await this.fetch({ spec }) + const license = + typeof data.license === 'string' ? data.license : data.license.type + return this.constructor.render({ license }) + } + + static get defaultBadgeData() { + return { label: 'license' } + } } diff --git a/services/cocoapods/cocoapods-license.tester.js b/services/cocoapods/cocoapods-license.tester.js index bbc5a2375d..4bf6c7458d 100644 --- a/services/cocoapods/cocoapods-license.tester.js +++ b/services/cocoapods/cocoapods-license.tester.js @@ -1,7 +1,5 @@ 'use strict' -const { invalidJSON } = require('../response-fixtures') - const t = (module.exports = require('../tester').createServiceTester()) t.create('license (valid)') @@ -11,17 +9,3 @@ t.create('license (valid)') t.create('license (not found)') .get('/not-a-package.json') .expectJSON({ name: 'license', value: 'not found' }) - -t.create('license (connection error)') - .get('/AFNetworking.json') - .networkOff() - .expectJSON({ name: 'license', value: 'inaccessible' }) - -t.create('license (unexpected response)') - .get('/AFNetworking.json') - .intercept(nock => - nock('https://trunk.cocoapods.org') - .get('/api/v1/pods/AFNetworking/specs/latest') - .reply(invalidJSON) - ) - .expectJSON({ name: 'license', value: 'invalid' }) diff --git a/services/cocoapods/cocoapods-metrics.service.js b/services/cocoapods/cocoapods-metrics.service.js deleted file mode 100644 index 9fb9506aa9..0000000000 --- a/services/cocoapods/cocoapods-metrics.service.js +++ /dev/null @@ -1,68 +0,0 @@ -'use strict' - -const LegacyService = require('../legacy-service') -const { makeBadgeData: getBadgeData } = require('../../lib/badge-data') -const { checkErrorResponse } = require('../../lib/error-helper') -const { - coveragePercentage: coveragePercentageColor, -} = require('../../lib/color-formatters') - -// 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 CocoapodsMetrics extends LegacyService { - static get category() { - return 'analysis' - } - - static get route() { - return { - base: 'cocoapods/metrics/doc-percent', - pattern: ':spec', - } - } - - static get examples() { - return [ - { - title: 'Cocoapods doc percentage', - namedParams: { spec: 'AFNetworking' }, - staticPreview: { label: 'docs', message: '94%', color: 'green' }, - }, - ] - } - - static registerLegacyRouteHandler({ camp, cache }) { - camp.route( - /^\/cocoapods\/metrics\/doc-percent\/(.*)\.(svg|png|gif|jpg|json)$/, - cache((data, match, sendBadge, request) => { - const spec = match[1] // eg, AFNetworking - const format = match[2] - const apiUrl = `https://metrics.cocoapods.org/api/v1/pods/${spec}` - const badgeData = getBadgeData('docs', data) - request(apiUrl, (err, res, buffer) => { - if (checkErrorResponse(badgeData, err, res)) { - sendBadge(format, badgeData) - return - } - try { - const parsedData = JSON.parse(buffer) - let percentage = parsedData.cocoadocs.doc_percent - if (percentage == null) { - percentage = 0 - } - badgeData.colorscheme = coveragePercentageColor(percentage) - badgeData.text[1] = `${percentage}%` - sendBadge(format, badgeData) - } catch (e) { - badgeData.text[1] = 'invalid' - sendBadge(format, badgeData) - } - }) - }) - ) - } -} diff --git a/services/cocoapods/cocoapods-platform.service.js b/services/cocoapods/cocoapods-platform.service.js index 41fbdccc4c..0bcd7e7b43 100644 --- a/services/cocoapods/cocoapods-platform.service.js +++ b/services/cocoapods/cocoapods-platform.service.js @@ -1,8 +1,8 @@ 'use strict' -const LegacyService = require('../legacy-service') +const BaseCocoaPodsService = require('./cocoapods-base') -module.exports = class CocoapodsPlatform extends LegacyService { +module.exports = class CocoapodsPlatform extends BaseCocoaPodsService { static get category() { return 'platform-support' } @@ -19,15 +19,27 @@ module.exports = class CocoapodsPlatform extends LegacyService { { title: 'Cocoapods platforms', namedParams: { spec: 'AFNetworking' }, - staticPreview: { - label: 'platform', - message: 'ios | osx | watchos | tvos', - color: 'lightgrey', - }, + staticPreview: this.render({ + platforms: ['ios', 'osx', 'watchos', 'tvos'], + }), }, ] } - // Legacy route handler is defined in cocoapods.service.js. - static registerLegacyRouteHandler() {} + static render({ platforms }) { + return { + message: platforms.join(' | '), + // https://github.com/badges/shields/pull/184 + color: '#989898', + } + } + + async handle({ spec }) { + const { platforms } = await this.fetch({ spec }) + return this.constructor.render({ platforms: Object.keys(platforms) }) + } + + static get defaultBadgeData() { + return { label: 'platform' } + } } diff --git a/services/cocoapods/cocoapods-platform.tester.js b/services/cocoapods/cocoapods-platform.tester.js index 66e9fd16fa..8389e0ccdd 100644 --- a/services/cocoapods/cocoapods-platform.tester.js +++ b/services/cocoapods/cocoapods-platform.tester.js @@ -1,7 +1,6 @@ 'use strict' const Joi = require('joi') -const { invalidJSON } = require('../response-fixtures') const isPlatform = Joi.string().regex( /^(osx|ios|tvos|watchos)( \| (osx|ios|tvos|watchos))*$/ @@ -22,16 +21,11 @@ t.create('platform (not found)') .get('/not-a-package.json') .expectJSON({ name: 'platform', value: 'not found' }) -t.create('platform (connection error)') - .get('/AFNetworking.json') - .networkOff() - .expectJSON({ name: 'platform', value: 'inaccessible' }) - -t.create('platform (unexpected response)') +t.create('platform (missing platforms key)') .get('/AFNetworking.json') .intercept(nock => nock('https://trunk.cocoapods.org') .get('/api/v1/pods/AFNetworking/specs/latest') - .reply(invalidJSON) + .reply(200, { version: 'v1.0', license: 'MIT' }) ) - .expectJSON({ name: 'platform', value: 'invalid' }) + .expectJSON({ name: 'platform', value: 'ios | osx' }) diff --git a/services/cocoapods/cocoapods-version.service.js b/services/cocoapods/cocoapods-version.service.js index eb8ab49e7e..8ecf96f96e 100644 --- a/services/cocoapods/cocoapods-version.service.js +++ b/services/cocoapods/cocoapods-version.service.js @@ -1,8 +1,9 @@ 'use strict' -const LegacyService = require('../legacy-service') +const { renderVersionBadge } = require('../../lib/version') +const BaseCocoaPodsService = require('./cocoapods-base') -module.exports = class CocoapodsVersion extends LegacyService { +module.exports = class CocoapodsVersion extends BaseCocoaPodsService { static get category() { return 'version' } @@ -18,18 +19,18 @@ module.exports = class CocoapodsVersion extends LegacyService { return [ { title: 'Cocoapods', - namedParams: { - spec: 'AFNetworking', - }, - staticPreview: { - label: 'pod', - message: 'v3.2.1', - color: 'blue', - }, + namedParams: { spec: 'AFNetworking' }, + staticPreview: renderVersionBadge({ version: 'v3.2.1' }), }, ] } - // Legacy route handler is defined in cocoapods.service.js. - static registerLegacyRouteHandler() {} + async handle({ spec }) { + const { version } = await this.fetch({ spec }) + return renderVersionBadge({ version }) + } + + static get defaultBadgeData() { + return { label: 'pod' } + } } diff --git a/services/cocoapods/cocoapods-version.tester.js b/services/cocoapods/cocoapods-version.tester.js index cc2423b064..0f884bcc01 100644 --- a/services/cocoapods/cocoapods-version.tester.js +++ b/services/cocoapods/cocoapods-version.tester.js @@ -2,7 +2,6 @@ const Joi = require('joi') const { isVPlusDottedVersionAtLeastOne } = require('../test-validators') -const { invalidJSON } = require('../response-fixtures') const t = (module.exports = require('../tester').createServiceTester()) @@ -18,17 +17,3 @@ t.create('version (valid)') t.create('version (not found)') .get('/not-a-package.json') .expectJSON({ name: 'pod', value: 'not found' }) - -t.create('version (connection error)') - .get('/AFNetworking.json') - .networkOff() - .expectJSON({ name: 'pod', value: 'inaccessible' }) - -t.create('version (unexpected response)') - .get('/AFNetworking.json') - .intercept(nock => - nock('https://trunk.cocoapods.org') - .get('/api/v1/pods/AFNetworking/specs/latest') - .reply(invalidJSON) - ) - .expectJSON({ name: 'pod', value: 'invalid' }) diff --git a/services/cocoapods/cocoapods.service.js b/services/cocoapods/cocoapods.service.js deleted file mode 100644 index 007baa3339..0000000000 --- a/services/cocoapods/cocoapods.service.js +++ /dev/null @@ -1,72 +0,0 @@ -'use strict' - -const LegacyService = require('../legacy-service') -const { makeBadgeData: getBadgeData } = require('../../lib/badge-data') -const { checkErrorResponse } = require('../../lib/error-helper') -const { addv: versionText } = require('../../lib/text-formatters') -const { version: versionColor } = require('../../lib/color-formatters') - -// 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 CocoapodsVersionPlatformLicense extends LegacyService { - static get category() { - return 'other' - } - - static registerLegacyRouteHandler({ camp, cache }) { - camp.route( - /^\/cocoapods\/(v|p|l)\/(.*)\.(svg|png|gif|jpg|json)$/, - cache((data, match, sendBadge, request) => { - const type = match[1] - const spec = match[2] // eg, AFNetworking - const format = match[3] - const apiUrl = `https://trunk.cocoapods.org/api/v1/pods/${spec}/specs/latest` - const typeToLabel = { v: 'pod', p: 'platform', l: 'license' } - const badgeData = getBadgeData(typeToLabel[type], data) - badgeData.colorscheme = undefined - request(apiUrl, (err, res, buffer) => { - if (checkErrorResponse(badgeData, err, res)) { - sendBadge(format, badgeData) - return - } - try { - const parsedData = JSON.parse(buffer) - const version = parsedData.version - let license - if (typeof parsedData.license === 'string') { - license = parsedData.license - } else { - license = parsedData.license.type - } - - const platforms = Object.keys( - parsedData.platforms || { - ios: '5.0', - osx: '10.7', - } - ).join(' | ') - if (type === 'v') { - badgeData.text[1] = versionText(version) - badgeData.colorscheme = versionColor(version) - } else if (type === 'p') { - badgeData.text[1] = platforms - badgeData.colorB = '#989898' - } else if (type === 'l') { - badgeData.text[1] = license - badgeData.colorB = '#373737' - } - - sendBadge(format, badgeData) - } catch (e) { - badgeData.text[1] = 'invalid' - sendBadge(format, badgeData) - } - }) - }) - ) - } -}