use new plugin api for [jetbrains] (#5974)
* use new plugin api for [jetbrains] * restore mocked XML response tests
This commit is contained in:
@@ -1,11 +1,32 @@
|
||||
'use strict'
|
||||
|
||||
const { BaseXmlService, NotFound } = require('..')
|
||||
const { parseJson } = require('../../core/base-service/json')
|
||||
|
||||
/*
|
||||
JetBrains is a bit awkward. Sometimes we want to call an XML API
|
||||
and sometimes we want to call a JSON API so we need a mongrel base class.
|
||||
When the legacy IntelliJ (XML) API is retired we can simplify all this and
|
||||
switch JetbrainsDownloads, JetbrainsRating and JetbrainsVersion to just
|
||||
inherit from BaseJsonService directly.
|
||||
*/
|
||||
module.exports = class JetbrainsBase extends BaseXmlService {
|
||||
static _isLegacyPluginId(pluginId) {
|
||||
return !pluginId.match(/^([0-9])+/)
|
||||
}
|
||||
|
||||
static _cleanPluginId(pluginId) {
|
||||
const match = pluginId.match(/^([0-9])+/)
|
||||
if (match) {
|
||||
return match[0]
|
||||
}
|
||||
return pluginId
|
||||
}
|
||||
|
||||
// xml
|
||||
static _validate(data, schema) {
|
||||
if (data['plugin-repository'] === '') {
|
||||
// Note the 'not found' response from JetBrains Plugins Repository is:
|
||||
// Note the 'not found' response from JetBrains IntelliJ API is:
|
||||
// status code = 200,
|
||||
// body = <?xml version="1.0" encoding="UTF-8"?><plugin-repository></plugin-repository>
|
||||
// which is parsed to object = { 'plugin-repository': '' }
|
||||
@@ -14,7 +35,7 @@ module.exports = class JetbrainsBase extends BaseXmlService {
|
||||
return super._validate(data, schema)
|
||||
}
|
||||
|
||||
async fetchPackageData({ pluginId, schema }) {
|
||||
async fetchIntelliJPluginData({ pluginId, schema }) {
|
||||
const parserOptions = {
|
||||
parseNodeValue: false,
|
||||
ignoreAttributes: false,
|
||||
@@ -25,4 +46,27 @@ module.exports = class JetbrainsBase extends BaseXmlService {
|
||||
parserOptions,
|
||||
})
|
||||
}
|
||||
|
||||
// json
|
||||
_parseJson(buffer) {
|
||||
return parseJson(buffer)
|
||||
}
|
||||
|
||||
static _validateJson(data, schema) {
|
||||
return super._validate(data, schema)
|
||||
}
|
||||
|
||||
async _requestJson({ schema, url, options = {}, errorMessages = {} }) {
|
||||
const mergedOptions = {
|
||||
...{ headers: { Accept: 'application/json' } },
|
||||
...options,
|
||||
}
|
||||
const { buffer } = await this._request({
|
||||
url,
|
||||
options: mergedOptions,
|
||||
errorMessages,
|
||||
})
|
||||
const json = this._parseJson(buffer)
|
||||
return this.constructor._validateJson(json, schema)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ const { downloadCount: downloadCountColor } = require('../color-formatters')
|
||||
const { nonNegativeInteger } = require('../validators')
|
||||
const JetbrainsBase = require('./jetbrains-base')
|
||||
|
||||
const schema = Joi.object({
|
||||
const intelliJschema = Joi.object({
|
||||
'plugin-repository': Joi.object({
|
||||
category: Joi.object({
|
||||
'idea-plugin': Joi.array()
|
||||
@@ -22,6 +22,8 @@ const schema = Joi.object({
|
||||
}).required(),
|
||||
}).required()
|
||||
|
||||
const jetbrainsSchema = Joi.object({ downloads: nonNegativeInteger }).required()
|
||||
|
||||
module.exports = class JetbrainsDownloads extends JetbrainsBase {
|
||||
static category = 'downloads'
|
||||
|
||||
@@ -32,9 +34,9 @@ module.exports = class JetbrainsDownloads extends JetbrainsBase {
|
||||
|
||||
static examples = [
|
||||
{
|
||||
title: 'JetBrains IntelliJ plugins',
|
||||
title: 'JetBrains plugins',
|
||||
namedParams: {
|
||||
pluginId: '1347-scala',
|
||||
pluginId: '1347',
|
||||
},
|
||||
staticPreview: this.render({ downloads: 10200000 }),
|
||||
},
|
||||
@@ -48,9 +50,27 @@ module.exports = class JetbrainsDownloads extends JetbrainsBase {
|
||||
}
|
||||
|
||||
async handle({ pluginId }) {
|
||||
const pluginData = await this.fetchPackageData({ pluginId, schema })
|
||||
const downloads =
|
||||
pluginData['plugin-repository'].category['idea-plugin'][0]['@_downloads']
|
||||
let downloads
|
||||
if (this.constructor._isLegacyPluginId(pluginId)) {
|
||||
const intelliJPluginData = await this.fetchIntelliJPluginData({
|
||||
pluginId,
|
||||
schema: intelliJschema,
|
||||
})
|
||||
downloads =
|
||||
intelliJPluginData['plugin-repository'].category['idea-plugin'][0][
|
||||
'@_downloads'
|
||||
]
|
||||
} else {
|
||||
const jetbrainsPluginData = await this._requestJson({
|
||||
schema: jetbrainsSchema,
|
||||
url: `https://plugins.jetbrains.com/api/plugins/${this.constructor._cleanPluginId(
|
||||
pluginId
|
||||
)}`,
|
||||
errorMessages: { 400: 'not found' },
|
||||
})
|
||||
downloads = jetbrainsPluginData.downloads
|
||||
}
|
||||
|
||||
return this.constructor.render({ downloads })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,12 +15,21 @@ t.create('downloads (user friendly plugin id)')
|
||||
.get('/1347-scala.json')
|
||||
.expectBadge({ label: 'downloads', message: isMetric })
|
||||
|
||||
t.create('downloads')
|
||||
t.create('downloads (numeric id)')
|
||||
.get('/9435.json')
|
||||
.intercept(nock =>
|
||||
nock('https://plugins.jetbrains.com')
|
||||
.get('/api/plugins/9435')
|
||||
.reply(200, { downloads: 2 })
|
||||
)
|
||||
.expectBadge({ label: 'downloads', message: '2' })
|
||||
|
||||
t.create('downloads (string id)')
|
||||
.get('/io.harply.plugin.json')
|
||||
.intercept(
|
||||
nock =>
|
||||
nock('https://plugins.jetbrains.com')
|
||||
.get('/plugins/list?pluginId=9435')
|
||||
.get('/plugins/list?pluginId=io.harply.plugin')
|
||||
.reply(
|
||||
200,
|
||||
`<?xml version="1.0" encoding="UTF-8"?>
|
||||
@@ -36,6 +45,14 @@ t.create('downloads')
|
||||
)
|
||||
.expectBadge({ label: 'downloads', message: '2' })
|
||||
|
||||
t.create('unknown plugin')
|
||||
t.create('unknown plugin (string id)')
|
||||
.get('/unknown-plugin.json')
|
||||
.expectBadge({ label: 'downloads', message: 'not found' })
|
||||
|
||||
t.create('unknown plugin (numeric id)')
|
||||
.get('/9999999999999.json')
|
||||
.expectBadge({ label: 'downloads', message: 'not found' })
|
||||
|
||||
t.create('unknown plugin (mixed id)')
|
||||
.get('/9999999999999-abc.json')
|
||||
.expectBadge({ label: 'downloads', message: 'not found' })
|
||||
|
||||
@@ -7,7 +7,7 @@ const JetbrainsBase = require('./jetbrains-base')
|
||||
|
||||
const pluginRatingColor = colorScale([2, 3, 4])
|
||||
|
||||
const schema = Joi.object({
|
||||
const intelliJschema = Joi.object({
|
||||
'plugin-repository': Joi.object({
|
||||
category: Joi.object({
|
||||
'idea-plugin': Joi.array()
|
||||
@@ -23,6 +23,10 @@ const schema = Joi.object({
|
||||
}).required(),
|
||||
}).required()
|
||||
|
||||
const jetbrainsSchema = Joi.object({
|
||||
meanRating: Joi.number().min(0).required(),
|
||||
}).required()
|
||||
|
||||
module.exports = class JetbrainsRating extends JetbrainsBase {
|
||||
static category = 'rating'
|
||||
|
||||
@@ -33,10 +37,10 @@ module.exports = class JetbrainsRating extends JetbrainsBase {
|
||||
|
||||
static examples = [
|
||||
{
|
||||
title: 'JetBrains IntelliJ Plugins',
|
||||
title: 'JetBrains Plugins',
|
||||
pattern: 'rating/:pluginId',
|
||||
namedParams: {
|
||||
pluginId: '11941-automatic-power-saver',
|
||||
pluginId: '11941',
|
||||
},
|
||||
staticPreview: this.render({
|
||||
rating: '4.5',
|
||||
@@ -44,10 +48,10 @@ module.exports = class JetbrainsRating extends JetbrainsBase {
|
||||
}),
|
||||
},
|
||||
{
|
||||
title: 'JetBrains IntelliJ Plugins',
|
||||
title: 'JetBrains Plugins',
|
||||
pattern: 'stars/:pluginId',
|
||||
namedParams: {
|
||||
pluginId: '11941-automatic-power-saver',
|
||||
pluginId: '11941',
|
||||
},
|
||||
staticPreview: this.render({
|
||||
rating: '4.5',
|
||||
@@ -70,9 +74,26 @@ module.exports = class JetbrainsRating extends JetbrainsBase {
|
||||
}
|
||||
|
||||
async handle({ format, pluginId }) {
|
||||
const pluginData = await this.fetchPackageData({ pluginId, schema })
|
||||
const pluginRating =
|
||||
pluginData['plugin-repository'].category['idea-plugin'][0].rating
|
||||
return this.constructor.render({ rating: pluginRating, format })
|
||||
let rating
|
||||
if (this.constructor._isLegacyPluginId(pluginId)) {
|
||||
const intelliJPluginData = await this.fetchIntelliJPluginData({
|
||||
pluginId,
|
||||
schema: intelliJschema,
|
||||
})
|
||||
rating =
|
||||
intelliJPluginData['plugin-repository'].category['idea-plugin'][0]
|
||||
.rating
|
||||
} else {
|
||||
const jetbrainsPluginData = await this._requestJson({
|
||||
schema: jetbrainsSchema,
|
||||
url: `https://plugins.jetbrains.com/api/plugins/${this.constructor._cleanPluginId(
|
||||
pluginId
|
||||
)}/rating`,
|
||||
errorMessages: { 400: 'not found' },
|
||||
})
|
||||
rating = jetbrainsPluginData.meanRating
|
||||
}
|
||||
|
||||
return this.constructor.render({ rating, format })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,10 +17,18 @@ t.create('rating number (number as a plugin id)')
|
||||
.get('/rating/11941.json')
|
||||
.expectBadge({ label: 'rating', message: isRating })
|
||||
|
||||
t.create('rating number for unknown plugin')
|
||||
t.create('rating number for unknown plugin (string)')
|
||||
.get('/rating/unknown-plugin.json')
|
||||
.expectBadge({ label: 'rating', message: 'not found' })
|
||||
|
||||
t.create('rating stars for unknown plugin (numeric)')
|
||||
.get('/stars/9999999999999.json')
|
||||
.expectBadge({ label: 'rating', message: 'not found' })
|
||||
|
||||
t.create('rating stars for unknown plugin (mixed)')
|
||||
.get('/stars/9999999999999-abc.json')
|
||||
.expectBadge({ label: 'rating', message: 'not found' })
|
||||
|
||||
t.create('rating stars (user friendly plugin id)')
|
||||
.get('/stars/11941-automatic-power-saver.json')
|
||||
.expectBadge({ label: 'rating', message: isStarRating })
|
||||
@@ -33,23 +41,42 @@ t.create('rating stars (number as a plugin id)')
|
||||
.get('/stars/11941.json')
|
||||
.expectBadge({ label: 'rating', message: isStarRating })
|
||||
|
||||
t.create('rating stars for unknown plugin')
|
||||
t.create('rating stars for unknown plugin (string id)')
|
||||
.get('/stars/unknown-plugin.json')
|
||||
.expectBadge({ label: 'rating', message: 'not found' })
|
||||
|
||||
t.create('rating number')
|
||||
t.create('rating stars for unknown plugin (numeric id)')
|
||||
.get('/stars/9999999999999.json')
|
||||
.expectBadge({ label: 'rating', message: 'not found' })
|
||||
|
||||
t.create('rating stars for unknown plugin (mixed id)')
|
||||
.get('/stars/9999999999999-abc.json')
|
||||
.expectBadge({ label: 'rating', message: 'not found' })
|
||||
|
||||
t.create('rating number (numeric id)')
|
||||
.get('/rating/11941.json')
|
||||
.intercept(nock =>
|
||||
nock('https://plugins.jetbrains.com')
|
||||
.get('/api/plugins/11941/rating')
|
||||
.reply(200, { meanRating: 4.4848 })
|
||||
)
|
||||
.expectBadge({ label: 'rating', message: '4.5/5' })
|
||||
|
||||
t.create('rating number (string id)')
|
||||
.get('/rating/com.chriscarini.jetbrains.jetbrains-auto-power-saver.json')
|
||||
.intercept(
|
||||
nock =>
|
||||
nock('https://plugins.jetbrains.com')
|
||||
.get('/plugins/list?pluginId=11941')
|
||||
.get(
|
||||
'/plugins/list?pluginId=com.chriscarini.jetbrains.jetbrains-auto-power-saver'
|
||||
)
|
||||
.reply(
|
||||
200,
|
||||
`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<plugin-repository>
|
||||
<category name="User Interface">
|
||||
<idea-plugin downloads="1714" size="208537" date="1586449109000" updatedDate="1586449109000" url="">
|
||||
<rating>4.5</rating>
|
||||
<rating>4.4848</rating>
|
||||
</idea-plugin>
|
||||
</category>
|
||||
</plugin-repository>`
|
||||
@@ -60,19 +87,30 @@ t.create('rating number')
|
||||
)
|
||||
.expectBadge({ label: 'rating', message: '4.5/5' })
|
||||
|
||||
t.create('rating stars')
|
||||
t.create('rating stars (numeric id)')
|
||||
.get('/stars/11941.json')
|
||||
.intercept(nock =>
|
||||
nock('https://plugins.jetbrains.com')
|
||||
.get('/api/plugins/11941/rating')
|
||||
.reply(200, { meanRating: 4.4848 })
|
||||
)
|
||||
.expectBadge({ label: 'rating', message: '★★★★½' })
|
||||
|
||||
t.create('rating stars (string id)')
|
||||
.get('/stars/com.chriscarini.jetbrains.jetbrains-auto-power-saver.json')
|
||||
.intercept(
|
||||
nock =>
|
||||
nock('https://plugins.jetbrains.com')
|
||||
.get('/plugins/list?pluginId=11941')
|
||||
.get(
|
||||
'/plugins/list?pluginId=com.chriscarini.jetbrains.jetbrains-auto-power-saver'
|
||||
)
|
||||
.reply(
|
||||
200,
|
||||
`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<plugin-repository>
|
||||
<category name="User Interface">
|
||||
<idea-plugin downloads="1714" size="208537" date="1586449109000" updatedDate="1586449109000" url="">
|
||||
<rating>4.5</rating>
|
||||
<rating>4.4848</rating>
|
||||
</idea-plugin>
|
||||
</category>
|
||||
</plugin-repository>`
|
||||
|
||||
@@ -4,7 +4,7 @@ const Joi = require('joi')
|
||||
const { renderVersionBadge } = require('../version')
|
||||
const JetbrainsBase = require('./jetbrains-base')
|
||||
|
||||
const schema = Joi.object({
|
||||
const intelliJschema = Joi.object({
|
||||
'plugin-repository': Joi.object({
|
||||
category: Joi.object({
|
||||
'idea-plugin': Joi.array()
|
||||
@@ -20,6 +20,15 @@ const schema = Joi.object({
|
||||
}).required(),
|
||||
}).required()
|
||||
|
||||
const jetbrainsSchema = Joi.array()
|
||||
.min(1)
|
||||
.items(
|
||||
Joi.object({
|
||||
version: Joi.string().required(),
|
||||
}).required()
|
||||
)
|
||||
.required()
|
||||
|
||||
module.exports = class JetbrainsVersion extends JetbrainsBase {
|
||||
static category = 'version'
|
||||
|
||||
@@ -30,9 +39,9 @@ module.exports = class JetbrainsVersion extends JetbrainsBase {
|
||||
|
||||
static examples = [
|
||||
{
|
||||
title: 'JetBrains IntelliJ Plugins',
|
||||
title: 'JetBrains Plugins',
|
||||
namedParams: {
|
||||
pluginId: '9630-a8translate',
|
||||
pluginId: '9630',
|
||||
},
|
||||
staticPreview: this.render({ version: 'v1.7' }),
|
||||
},
|
||||
@@ -45,9 +54,26 @@ module.exports = class JetbrainsVersion extends JetbrainsBase {
|
||||
}
|
||||
|
||||
async handle({ pluginId }) {
|
||||
const pluginData = await this.fetchPackageData({ pluginId, schema })
|
||||
const version =
|
||||
pluginData['plugin-repository'].category['idea-plugin'][0].version
|
||||
let version
|
||||
if (this.constructor._isLegacyPluginId(pluginId)) {
|
||||
const intelliJPluginData = await this.fetchIntelliJPluginData({
|
||||
pluginId,
|
||||
schema: intelliJschema,
|
||||
})
|
||||
version =
|
||||
intelliJPluginData['plugin-repository'].category['idea-plugin'][0]
|
||||
.version
|
||||
} else {
|
||||
const jetbrainsPluginData = await this._requestJson({
|
||||
schema: jetbrainsSchema,
|
||||
url: `https://plugins.jetbrains.com/api/plugins/${this.constructor._cleanPluginId(
|
||||
pluginId
|
||||
)}/updates`,
|
||||
errorMessages: { 400: 'not found' },
|
||||
})
|
||||
version = jetbrainsPluginData[0].version
|
||||
}
|
||||
|
||||
return this.constructor.render({ version })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,12 +22,21 @@ t.create('version (number as a plugin id)').get('/7495.json').expectBadge({
|
||||
message: isVPlusDottedVersionNClauses,
|
||||
})
|
||||
|
||||
t.create('version')
|
||||
t.create('version (numeric id)')
|
||||
.get('/9435.json')
|
||||
.intercept(nock =>
|
||||
nock('https://plugins.jetbrains.com')
|
||||
.get('/api/plugins/9435/updates')
|
||||
.reply(200, [{ version: '1.0' }])
|
||||
)
|
||||
.expectBadge({ label: 'jetbrains plugin', message: 'v1.0' })
|
||||
|
||||
t.create('version (strong id)')
|
||||
.get('/io.harply.plugin.json')
|
||||
.intercept(
|
||||
nock =>
|
||||
nock('https://plugins.jetbrains.com')
|
||||
.get('/plugins/list?pluginId=9435')
|
||||
.get('/plugins/list?pluginId=io.harply.plugin')
|
||||
.reply(
|
||||
200,
|
||||
`<?xml version="1.0" encoding="UTF-8"?>
|
||||
@@ -45,6 +54,14 @@ t.create('version')
|
||||
)
|
||||
.expectBadge({ label: 'jetbrains plugin', message: 'v1.0' })
|
||||
|
||||
t.create('version for unknown plugin')
|
||||
t.create('version for unknown plugin (string id)')
|
||||
.get('/unknown-plugin.json')
|
||||
.expectBadge({ label: 'jetbrains plugin', message: 'not found' })
|
||||
|
||||
t.create('version for unknown plugin (numeric id)')
|
||||
.get('/9999999999999.json')
|
||||
.expectBadge({ label: 'jetbrains plugin', message: 'not found' })
|
||||
|
||||
t.create('unknown plugin (mixed id)')
|
||||
.get('/9999999999999-abc.json')
|
||||
.expectBadge({ label: 'jetbrains plugin', message: 'not found' })
|
||||
|
||||
Reference in New Issue
Block a user