From 49ee68fcb30e9fccb086d7b83f1e39e363661c71 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 7 Feb 2019 20:11:04 -0500 Subject: [PATCH 1/3] Bump babel-preset-gatsby from 0.1.6 to 0.1.7 (#2949) Bumps babel-preset-gatsby from 0.1.6 to 0.1.7. Signed-off-by: dependabot[bot] --- package-lock.json | 23 ++++++++++++----------- package.json | 2 +- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index 80283ccd44506..86170c055ee19 100644 --- a/package-lock.json +++ b/package-lock.json @@ -669,9 +669,9 @@ } }, "@babel/plugin-syntax-dynamic-import": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.0.0.tgz", - "integrity": "sha512-Gt9xNyRrCHCiyX/ZxDGOcBnlJl0I3IWicpZRC4CdC0P5a/I07Ya2OAMEBU+J7GmRFVmIetqEYRko6QYRuKOESw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.2.0.tgz", + "integrity": "sha512-mVxuJ0YroI/h/tbFTPGZR8cv6ai+STMKNBq0f8hFxsxWjl94qqhsb+wXbpNMDPU3cfR1TIsVFzU3nXyZMqyK4w==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0" @@ -1011,14 +1011,15 @@ } }, "@babel/plugin-transform-runtime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.0.0.tgz", - "integrity": "sha512-yECRVxRu25Nsf6IY5v5XrXhcW9ZHomUQiq30VO8H7r3JYPcBJDTcxZmT+6v1O3QKKrDp1Wp40LinGbcd+jlp9A==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.2.0.tgz", + "integrity": "sha512-jIgkljDdq4RYDnJyQsiWbdvGeei/0MOTtSHKO/rfbd/mXBxNpdlulMx49L0HQ4pug1fXannxoqCI+fYSle9eSw==", "dev": true, "requires": { "@babel/helper-module-imports": "^7.0.0", "@babel/helper-plugin-utils": "^7.0.0", - "resolve": "^1.8.1" + "resolve": "^1.8.1", + "semver": "^5.5.1" } }, "@babel/plugin-transform-shorthand-properties": { @@ -2735,9 +2736,9 @@ } }, "babel-preset-gatsby": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/babel-preset-gatsby/-/babel-preset-gatsby-0.1.6.tgz", - "integrity": "sha512-DHRBQI9QDdZ51A/bKfkr+nvREttRFST0AmD0zBcKOrERlPbwlOBP+IgUOo76kSJx5z9EDhRCwkvraT6ZGzeQ6Q==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/babel-preset-gatsby/-/babel-preset-gatsby-0.1.7.tgz", + "integrity": "sha512-vgzATIBl4V27QC4O9oEEv3oWcgFLw614oqSoEcMd0BaYkAtX8c6LPHN7TXDTA3EwMu+qQLyCtv7/K00liYvytA==", "dev": true, "requires": { "@babel/plugin-proposal-class-properties": "^7.0.0", @@ -15213,7 +15214,7 @@ }, "p-is-promise": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=", "dev": true }, diff --git a/package.json b/package.json index d7247ef648294..2cf2d3b586459 100644 --- a/package.json +++ b/package.json @@ -126,7 +126,7 @@ "babel-eslint": "^10.0.0", "babel-plugin-inline-react-svg": "^1.0.1", "babel-plugin-istanbul": "^5.1.0", - "babel-preset-gatsby": "^0.1.6", + "babel-preset-gatsby": "^0.1.7", "caller": "^1.0.1", "chai": "^4.1.2", "chai-datetime": "^1.5.0", From 2ee1327eed9410142c13bc5afc607ddc11f62ef9 Mon Sep 17 00:00:00 2001 From: Paul Melnikow Date: Thu, 7 Feb 2019 21:14:04 -0500 Subject: [PATCH 2/3] Refactor the NuGet v2 badges; switch Resharper to XML (#2934) This closes #2921 by switching ReSharper to the XML API used by Powershell, and refactors the powershell code back into the common nuget v2 service class. It also removes mocked tests of the color logic, replacing them with smaller-bracket tests that accomplish the same thing more concisely. --- services/chocolatey/chocolatey.service.js | 1 + services/chocolatey/chocolatey.tester.js | 95 ----------- services/nuget-fixtures.js | 21 --- services/nuget/nuget-helpers.js | 14 ++ services/nuget/nuget-helpers.spec.js | 31 ++++ services/nuget/nuget-v2-service-family.js | 77 +++++++-- .../powershellgallery.service.js | 154 +++--------------- services/resharper/resharper.service.js | 1 + services/resharper/resharper.tester.js | 101 +----------- 9 files changed, 134 insertions(+), 361 deletions(-) create mode 100644 services/nuget/nuget-helpers.spec.js diff --git a/services/chocolatey/chocolatey.service.js b/services/chocolatey/chocolatey.service.js index 495c494a6ba14..c03f3d1a7cda8 100644 --- a/services/chocolatey/chocolatey.service.js +++ b/services/chocolatey/chocolatey.service.js @@ -6,6 +6,7 @@ module.exports = createServiceFamily({ defaultLabel: 'chocolatey', serviceBaseUrl: 'chocolatey', apiBaseUrl: 'https://www.chocolatey.org/api/v2', + odataFormat: 'json', title: 'Chocolatey', examplePackageName: 'git', exampleVersion: '2.19.2', diff --git a/services/chocolatey/chocolatey.tester.js b/services/chocolatey/chocolatey.tester.js index 693fba22a8503..981924470de8e 100644 --- a/services/chocolatey/chocolatey.tester.js +++ b/services/chocolatey/chocolatey.tester.js @@ -6,11 +6,6 @@ const { isVPlusDottedVersionNClauses, isVPlusDottedVersionNClausesWithOptionalSuffix, } = require('../test-validators') -const { - nuGetV2VersionJsonWithDash, - nuGetV2VersionJsonFirstCharZero, - nuGetV2VersionJsonFirstCharNotZero, -} = require('../nuget-fixtures') const { ServiceTester } = require('../tester') const t = (module.exports = new ServiceTester({ @@ -44,51 +39,6 @@ t.create('version (valid)') }) ) -t.create('version (mocked, yellow badge)') - .get('/v/scriptcs.json?style=_shields_test') - .intercept(nock => - nock('https://www.chocolatey.org') - .get( - '/api/v2/Packages()?%24filter=Id%20eq%20%27scriptcs%27%20and%20IsLatestVersion%20eq%20true' - ) - .reply(200, nuGetV2VersionJsonWithDash) - ) - .expectJSON({ - name: 'chocolatey', - value: 'v1.2-beta', - color: 'yellow', - }) - -t.create('version (mocked, orange badge)') - .get('/v/scriptcs.json?style=_shields_test') - .intercept(nock => - nock('https://www.chocolatey.org') - .get( - '/api/v2/Packages()?%24filter=Id%20eq%20%27scriptcs%27%20and%20IsLatestVersion%20eq%20true' - ) - .reply(200, nuGetV2VersionJsonFirstCharZero) - ) - .expectJSON({ - name: 'chocolatey', - value: 'v0.35', - color: 'orange', - }) - -t.create('version (mocked, blue badge)') - .get('/v/scriptcs.json?style=_shields_test') - .intercept(nock => - nock('https://www.chocolatey.org') - .get( - '/api/v2/Packages()?%24filter=Id%20eq%20%27scriptcs%27%20and%20IsLatestVersion%20eq%20true' - ) - .reply(200, nuGetV2VersionJsonFirstCharNotZero) - ) - .expectJSON({ - name: 'chocolatey', - value: 'v1.2.7', - color: 'blue', - }) - t.create('version (not found)') .get('/v/not-a-real-package.json') .expectJSON({ name: 'chocolatey', value: 'not found' }) @@ -104,51 +54,6 @@ t.create('version (pre) (valid)') }) ) -t.create('version (pre) (mocked, yellow badge)') - .get('/vpre/scriptcs.json?style=_shields_test') - .intercept(nock => - nock('https://www.chocolatey.org') - .get( - '/api/v2/Packages()?%24filter=Id%20eq%20%27scriptcs%27%20and%20IsAbsoluteLatestVersion%20eq%20true' - ) - .reply(200, nuGetV2VersionJsonWithDash) - ) - .expectJSON({ - name: 'chocolatey', - value: 'v1.2-beta', - color: 'yellow', - }) - -t.create('version (pre) (mocked, orange badge)') - .get('/vpre/scriptcs.json?style=_shields_test') - .intercept(nock => - nock('https://www.chocolatey.org') - .get( - '/api/v2/Packages()?%24filter=Id%20eq%20%27scriptcs%27%20and%20IsAbsoluteLatestVersion%20eq%20true' - ) - .reply(200, nuGetV2VersionJsonFirstCharZero) - ) - .expectJSON({ - name: 'chocolatey', - value: 'v0.35', - color: 'orange', - }) - -t.create('version (pre) (mocked, blue badge)') - .get('/vpre/scriptcs.json?style=_shields_test') - .intercept(nock => - nock('https://www.chocolatey.org') - .get( - '/api/v2/Packages()?%24filter=Id%20eq%20%27scriptcs%27%20and%20IsAbsoluteLatestVersion%20eq%20true' - ) - .reply(200, nuGetV2VersionJsonFirstCharNotZero) - ) - .expectJSON({ - name: 'chocolatey', - value: 'v1.2.7', - color: 'blue', - }) - t.create('version (pre) (not found)') .get('/vpre/not-a-real-package.json') .expectJSON({ name: 'chocolatey', value: 'not found' }) diff --git a/services/nuget-fixtures.js b/services/nuget-fixtures.js index d5842ea5c7732..ece84319c9f92 100644 --- a/services/nuget-fixtures.js +++ b/services/nuget-fixtures.js @@ -9,24 +9,6 @@ const queryIndex = JSON.stringify({ ], }) -const nuGetV2VersionJsonWithDash = JSON.stringify({ - d: { - results: [ - { NormalizedVersion: '1.2-beta', Version: 'xxx', DownloadCount: 0 }, - ], - }, -}) -const nuGetV2VersionJsonFirstCharZero = JSON.stringify({ - d: { - results: [{ NormalizedVersion: '0.35', Version: 'xxx', DownloadCount: 0 }], - }, -}) -const nuGetV2VersionJsonFirstCharNotZero = JSON.stringify({ - d: { - results: [{ NormalizedVersion: '1.2.7', Version: 'xxx', DownloadCount: 0 }], - }, -}) - const nuGetV3VersionJsonWithDash = JSON.stringify({ data: [ { @@ -54,9 +36,6 @@ const nuGetV3VersionJsonFirstCharNotZero = JSON.stringify({ module.exports = { queryIndex, - nuGetV2VersionJsonWithDash, - nuGetV2VersionJsonFirstCharZero, - nuGetV2VersionJsonFirstCharNotZero, nuGetV3VersionJsonWithDash, nuGetV3VersionJsonFirstCharZero, nuGetV3VersionJsonFirstCharNotZero, diff --git a/services/nuget/nuget-helpers.js b/services/nuget/nuget-helpers.js index 59731824bf126..8fefd7291c31a 100644 --- a/services/nuget/nuget-helpers.js +++ b/services/nuget/nuget-helpers.js @@ -29,7 +29,21 @@ function renderDownloadBadge({ downloads }) { } } +function odataToObject(odata) { + if (odata === undefined) { + return undefined + } + + const result = {} + Object.entries(odata['m:properties']).forEach(([key, value]) => { + const newKey = key.replace(/^d:/, '') + result[newKey] = value + }) + return result +} + module.exports = { renderVersionBadge, renderDownloadBadge, + odataToObject, } diff --git a/services/nuget/nuget-helpers.spec.js b/services/nuget/nuget-helpers.spec.js new file mode 100644 index 0000000000000..0026e6b51da04 --- /dev/null +++ b/services/nuget/nuget-helpers.spec.js @@ -0,0 +1,31 @@ +'use strict' + +const { renderVersionBadge, odataToObject } = require('./nuget-helpers') +const { test, given } = require('sazerac') + +describe('NuGet helpers', function() { + test(renderVersionBadge, () => { + given({ version: '1.2-beta' }).expect({ + label: undefined, + message: 'v1.2-beta', + color: 'yellow', + }) + given({ version: '0.35' }).expect({ + label: undefined, + message: 'v0.35', + color: 'orange', + }) + given({ version: '1.2.7' }).expect({ + label: undefined, + message: 'v1.2.7', + color: 'blue', + }) + }) + + test(odataToObject, () => { + given({ 'm:properties': { 'd:Version': '1.2.3' } }).expect({ + Version: '1.2.3', + }) + given(undefined).expect(undefined) + }) +}) diff --git a/services/nuget/nuget-v2-service-family.js b/services/nuget/nuget-v2-service-family.js index 523837e0aff81..1d7704c193426 100644 --- a/services/nuget/nuget-v2-service-family.js +++ b/services/nuget/nuget-v2-service-family.js @@ -1,9 +1,13 @@ 'use strict' const Joi = require('joi') -const { BaseJsonService, NotFound } = require('..') +const { BaseJsonService, BaseXmlService, NotFound } = require('..') const { nonNegativeInteger } = require('../validators') -const { renderVersionBadge, renderDownloadBadge } = require('./nuget-helpers') +const { + renderVersionBadge, + renderDownloadBadge, + odataToObject, +} = require('./nuget-helpers') function createFilter({ packageName, includePrereleases }) { const releaseTypeFilter = includePrereleases @@ -12,7 +16,7 @@ function createFilter({ packageName, includePrereleases }) { return `Id eq '${packageName}' and ${releaseTypeFilter}` } -const schema = Joi.object({ +const jsonSchema = Joi.object({ d: Joi.object({ results: Joi.array() .items( @@ -27,25 +31,53 @@ const schema = Joi.object({ }).required(), }).required() +const xmlSchema = Joi.object({ + feed: Joi.object({ + entry: Joi.object({ + 'm:properties': Joi.object({ + 'd:Version': Joi.string(), + 'd:NormalizedVersion': Joi.string(), + 'd:DownloadCount': nonNegativeInteger, + 'd:Tags': Joi.string(), + }), + }), + }).required(), +}).required() + async function fetch( serviceInstance, - { baseUrl, packageName, includePrereleases = false } + { odataFormat, baseUrl, packageName, includePrereleases = false } ) { - const data = await serviceInstance._requestJson({ - schema, - url: `${baseUrl}/Packages()`, - options: { - headers: { Accept: 'application/atom+json,application/json' }, - qs: { $filter: createFilter({ packageName, includePrereleases }) }, - }, - }) - - const packageData = data.d.results[0] + const url = `${baseUrl}/Packages()` + const qs = { $filter: createFilter({ packageName, includePrereleases }) } + + let packageData + if (odataFormat === 'xml') { + const data = await serviceInstance._requestXml({ + schema: xmlSchema, + url, + options: { qs }, + }) + packageData = odataToObject(data.feed.entry) + } else if (odataFormat === 'json') { + const data = await serviceInstance._requestJson({ + schema: jsonSchema, + url, + options: { + headers: { Accept: 'application/atom+json,application/json' }, + qs, + }, + }) + packageData = data.d.results[0] + } else { + throw Error(`Unsupported Atom OData format: ${odataFormat}`) + } if (packageData) { return packageData } else if (!includePrereleases) { return fetch(serviceInstance, { + odataFormat, baseUrl, packageName, includePrereleases: true, @@ -67,13 +99,23 @@ function createServiceFamily({ defaultLabel, serviceBaseUrl, apiBaseUrl, + odataFormat, title, examplePackageName, exampleVersion, examplePrereleaseVersion, exampleDownloadCount, }) { - class NugetVersionService extends BaseJsonService { + let Base + if (odataFormat === 'xml') { + Base = BaseXmlService + } else if (odataFormat === 'json') { + Base = BaseJsonService + } else { + throw Error(`Unsupported Atom OData format: ${odataFormat}`) + } + + class NugetVersionService extends Base { static get category() { return 'version' } @@ -116,6 +158,7 @@ function createServiceFamily({ async handle({ which, packageName }) { const packageData = await fetch(this, { + odataFormat, baseUrl: apiBaseUrl, packageName, includePrereleases: which === 'vpre', @@ -125,7 +168,7 @@ function createServiceFamily({ } } - class NugetDownloadService extends BaseJsonService { + class NugetDownloadService extends Base { static get category() { return 'downloads' } @@ -155,6 +198,7 @@ function createServiceFamily({ async handle({ packageName }) { const packageData = await fetch(this, { + odataFormat, baseUrl: apiBaseUrl, packageName, }) @@ -168,5 +212,6 @@ function createServiceFamily({ module.exports = { createFilter, + fetch, createServiceFamily, } diff --git a/services/powershellgallery/powershellgallery.service.js b/services/powershellgallery/powershellgallery.service.js index 2b3ba59409854..d053bd6bf74f5 100644 --- a/services/powershellgallery/powershellgallery.service.js +++ b/services/powershellgallery/powershellgallery.service.js @@ -1,142 +1,31 @@ 'use strict' -const Joi = require('joi') -const { createFilter } = require('../nuget/nuget-v2-service-family') const { - renderVersionBadge, - renderDownloadBadge, -} = require('../nuget/nuget-helpers') -const { BaseXmlService, NotFound } = require('..') -const { nonNegativeInteger } = require('../validators') + fetch, + createServiceFamily, +} = require('../nuget/nuget-v2-service-family') +const { BaseXmlService } = require('..') const WINDOWS_TAG_NAME = 'windows' const MACOS_TAG_NAME = 'macos' const LINUX_TAG_NAME = 'linux' -const schema = Joi.object({ - feed: Joi.object({ - entry: Joi.object({ - 'm:properties': Joi.object({ - 'd:Version': Joi.string(), - 'd:NormalizedVersion': Joi.string(), - 'd:DownloadCount': nonNegativeInteger, - 'd:Tags': Joi.string(), - }), - }), - }).required(), -}).required() - -async function fetch( - serviceInstance, - { packageName, includePrereleases = false } -) { - const data = await serviceInstance._requestXml({ - schema, - url: `https://www.powershellgallery.com/api/v2/Search()`, - options: { - qs: { $filter: createFilter({ packageName, includePrereleases }) }, - }, - }) - - const packageData = - 'entry' in data.feed ? data.feed.entry['m:properties'] : undefined - - if (packageData) { - return packageData - } else if (!includePrereleases) { - return fetch(serviceInstance, { - packageName, - includePrereleases: true, - }) - } else { - throw new NotFound() - } -} - -class PowershellGalleryVersion extends BaseXmlService { - static get category() { - return 'version' - } - - static get route() { - return { - base: 'powershellgallery', - pattern: ':which(v|vpre)/:packageName', - } - } - - static get examples() { - return [ - { - title: 'PowerShell Gallery', - pattern: 'v/:packageName', - namedParams: { packageName: 'Azure.Storage' }, - staticPreview: this.render({ version: '4.4.0' }), - }, - { - title: 'PowerShell Gallery (with prereleases)', - pattern: 'vpre/:packageName', - namedParams: { packageName: 'Azure.Storage' }, - staticPreview: this.render({ version: '4.4.1-preview' }), - }, - ] - } +const apiBaseUrl = 'https://www.powershellgallery.com/api/v2' - static get defaultBadgeData() { - return { - label: 'powershell gallery', - } - } - - static render(props) { - return renderVersionBadge(props) - } - - async handle({ which, packageName }) { - const packageData = await fetch(this, { - packageName, - includePrereleases: which === 'vpre', - }) - const version = - packageData['d:NormalizedVersion'] || packageData['d:Version'] - return this.constructor.render({ version }) - } -} - -class PowershellGalleryDownloads extends BaseXmlService { - static get category() { - return 'downloads' - } - - static get route() { - return { - base: 'powershellgallery/dt', - pattern: ':packageName', - } - } - - static get examples() { - return [ - { - title: 'PowerShell Gallery', - namedParams: { packageName: 'Azure.Storage' }, - staticPreview: this.render({ downloads: 1.2e7 }), - }, - ] - } - - static render(props) { - return renderDownloadBadge(props) - } - - async handle({ packageName }) { - const packageData = await fetch(this, { - packageName, - }) - const { 'd:DownloadCount': downloads } = packageData - return this.constructor.render({ downloads }) - } -} +const { + NugetVersionService: PowershellGalleryVersion, + NugetDownloadService: PowershellGalleryDownloads, +} = createServiceFamily({ + defaultLabel: 'powershell gallery', + serviceBaseUrl: 'powershellgallery', + apiBaseUrl, + odataFormat: 'xml', + title: 'PowerShell Gallery', + examplePackageName: 'Azure.Storage', + exampleVersion: '4.4.0', + examplePrereleaseVersion: '4.4.1-preview', + exampleDownloadCount: 1.2e7, +}) class PowershellGalleryPlatformSupport extends BaseXmlService { static get category() { @@ -175,10 +64,11 @@ class PowershellGalleryPlatformSupport extends BaseXmlService { } async handle({ packageName }) { - const packageData = await fetch(this, { + const { Tags: tagStr } = await fetch(this, { + baseUrl: apiBaseUrl, + odataFormat: 'xml', packageName, }) - const { 'd:Tags': tagStr } = packageData const platforms = new Set() const tagArr = tagStr.split(' ') diff --git a/services/resharper/resharper.service.js b/services/resharper/resharper.service.js index 0bd3f2117d89c..86fb7a96f0783 100644 --- a/services/resharper/resharper.service.js +++ b/services/resharper/resharper.service.js @@ -6,6 +6,7 @@ module.exports = createServiceFamily({ defaultLabel: 'resharper', serviceBaseUrl: 'resharper', apiBaseUrl: 'https://resharper-plugins.jetbrains.com/api/v2', + odataFormat: 'xml', title: 'JetBrains ReSharper plugins', examplePackageName: 'StyleCop.StyleCop', exampleVersion: '2017.2.0', diff --git a/services/resharper/resharper.tester.js b/services/resharper/resharper.tester.js index 2ff327a186b13..9f0d4461873da 100644 --- a/services/resharper/resharper.tester.js +++ b/services/resharper/resharper.tester.js @@ -7,14 +7,11 @@ const { isVPlusDottedVersionNClauses, isVPlusDottedVersionNClausesWithOptionalSuffix, } = require('../test-validators') -const { - nuGetV2VersionJsonWithDash, - nuGetV2VersionJsonFirstCharZero, - nuGetV2VersionJsonFirstCharNotZero, -} = require('../nuget-fixtures') -const t = new ServiceTester({ id: 'resharper', title: 'ReSharper' }) -module.exports = t +const t = (module.exports = new ServiceTester({ + id: 'resharper', + title: 'ReSharper', +})) // downloads @@ -42,51 +39,6 @@ t.create('version (valid)') }) ) -t.create('version (mocked, yellow badge)') - .get('/v/ReSharper.Nuke.json?style=_shields_test') - .intercept(nock => - nock('https://resharper-plugins.jetbrains.com') - .get( - '/api/v2/Packages()?%24filter=Id%20eq%20%27ReSharper.Nuke%27%20and%20IsLatestVersion%20eq%20true' - ) - .reply(200, nuGetV2VersionJsonWithDash) - ) - .expectJSON({ - name: 'resharper', - value: 'v1.2-beta', - color: 'yellow', - }) - -t.create('version (mocked, orange badge)') - .get('/v/ReSharper.Nuke.json?style=_shields_test') - .intercept(nock => - nock('https://resharper-plugins.jetbrains.com') - .get( - '/api/v2/Packages()?%24filter=Id%20eq%20%27ReSharper.Nuke%27%20and%20IsLatestVersion%20eq%20true' - ) - .reply(200, nuGetV2VersionJsonFirstCharZero) - ) - .expectJSON({ - name: 'resharper', - value: 'v0.35', - color: 'orange', - }) - -t.create('version (mocked, blue badge)') - .get('/v/ReSharper.Nuke.json?style=_shields_test') - .intercept(nock => - nock('https://resharper-plugins.jetbrains.com') - .get( - '/api/v2/Packages()?%24filter=Id%20eq%20%27ReSharper.Nuke%27%20and%20IsLatestVersion%20eq%20true' - ) - .reply(200, nuGetV2VersionJsonFirstCharNotZero) - ) - .expectJSON({ - name: 'resharper', - value: 'v1.2.7', - color: 'blue', - }) - t.create('version (not found)') .get('/v/not-a-real-package.json') .expectJSON({ name: 'resharper', value: 'not found' }) @@ -102,51 +54,6 @@ t.create('version (pre) (valid)') }) ) -t.create('version (pre) (mocked, yellow badge)') - .get('/vpre/ReSharper.Nuke.json?style=_shields_test') - .intercept(nock => - nock('https://resharper-plugins.jetbrains.com') - .get( - '/api/v2/Packages()?%24filter=Id%20eq%20%27ReSharper.Nuke%27%20and%20IsAbsoluteLatestVersion%20eq%20true' - ) - .reply(200, nuGetV2VersionJsonWithDash) - ) - .expectJSON({ - name: 'resharper', - value: 'v1.2-beta', - color: 'yellow', - }) - -t.create('version (pre) (mocked, orange badge)') - .get('/vpre/ReSharper.Nuke.json?style=_shields_test') - .intercept(nock => - nock('https://resharper-plugins.jetbrains.com') - .get( - '/api/v2/Packages()?%24filter=Id%20eq%20%27ReSharper.Nuke%27%20and%20IsAbsoluteLatestVersion%20eq%20true' - ) - .reply(200, nuGetV2VersionJsonFirstCharZero) - ) - .expectJSON({ - name: 'resharper', - value: 'v0.35', - color: 'orange', - }) - -t.create('version (pre) (mocked, blue badge)') - .get('/vpre/ReSharper.Nuke.json?style=_shields_test') - .intercept(nock => - nock('https://resharper-plugins.jetbrains.com') - .get( - '/api/v2/Packages()?%24filter=Id%20eq%20%27ReSharper.Nuke%27%20and%20IsAbsoluteLatestVersion%20eq%20true' - ) - .reply(200, nuGetV2VersionJsonFirstCharNotZero) - ) - .expectJSON({ - name: 'resharper', - value: 'v1.2.7', - color: 'blue', - }) - t.create('version (pre) (not found)') .get('/vpre/not-a-real-package.json') .expectJSON({ name: 'resharper', value: 'not found' }) From c46d2f9dae2ceac35ae54430943ce5671c83ac3e Mon Sep 17 00:00:00 2001 From: Andrew Marcuse Date: Thu, 7 Feb 2019 21:24:40 -0500 Subject: [PATCH 3/3] [NodePing] support for NodePing uptime monitoring service (#2910) * [NodePing] support for NodePing uptime monitoring service * NodePing test tweaks --- services/nodeping/nodeping-status.service.js | 105 +++++++++++++++++++ services/nodeping/nodeping-status.tester.js | 75 +++++++++++++ services/nodeping/nodeping-uptime.service.js | 100 ++++++++++++++++++ services/nodeping/nodeping-uptime.tester.js | 87 +++++++++++++++ 4 files changed, 367 insertions(+) create mode 100644 services/nodeping/nodeping-status.service.js create mode 100644 services/nodeping/nodeping-status.tester.js create mode 100644 services/nodeping/nodeping-uptime.service.js create mode 100644 services/nodeping/nodeping-uptime.tester.js diff --git a/services/nodeping/nodeping-status.service.js b/services/nodeping/nodeping-status.service.js new file mode 100644 index 0000000000000..987e3fb6dc55e --- /dev/null +++ b/services/nodeping/nodeping-status.service.js @@ -0,0 +1,105 @@ +'use strict' + +const { BaseJsonService } = require('..') +const Joi = require('joi') + +const rowSchema = Joi.object().keys({ su: Joi.boolean() }) + +const schema = Joi.array() + .items(rowSchema) + .min(1) + +/* + * this is the checkUuid for the NodePing.com (as used on the [example page](https://nodeping.com/reporting.html#results)) + */ +const sampleCheckUuid = 'jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei' + +class NodePingStatus extends BaseJsonService { + static get category() { + return 'monitoring' + } + + static get defaultBadgeData() { + return { + label: 'Status', + } + } + + static get route() { + return { + base: 'nodeping/status', + pattern: ':checkUuid', + queryParams: ['up_message', 'down_message', 'up_color', 'down_color'], + } + } + + static get examples() { + return [ + { + title: 'NodePing status', + namedParams: { + checkUuid: sampleCheckUuid, + }, + staticPreview: this.render({ status: true }), + }, + { + title: 'NodePing status (customized)', + namedParams: { + checkUuid: sampleCheckUuid, + }, + queryParams: { + up_message: 'Online', + up_color: 'blue', + down_message: 'Offline', + down_color: 'lightgrey', + }, + staticPreview: this.render({ + status: true, + upMessage: 'Online', + upColor: 'blue', + }), + }, + ] + } + + async fetch({ checkUuid }) { + const rows = await this._requestJson({ + schema, + url: `https://nodeping.com/reports/results/${checkUuid}/1`, + options: { + qs: { format: 'json' }, + headers: { + 'cache-control': 'no-cache', + }, + }, + }) + return { status: rows[0].su } + } + + async handle( + { checkUuid }, + { + up_message: upMessage, + down_message: downMessage, + up_color: upColor, + down_color: downColor, + } + ) { + const { status } = await this.fetch({ checkUuid }) + return this.constructor.render({ + status, + upMessage, + downMessage, + upColor, + downColor, + }) + } + + static render({ status, upMessage, downMessage, upColor, downColor }) { + return status + ? { message: upMessage || 'up', color: upColor || 'brightgreen' } + : { message: downMessage || 'down', color: downColor || 'red' } + } +} + +module.exports = NodePingStatus diff --git a/services/nodeping/nodeping-status.tester.js b/services/nodeping/nodeping-status.tester.js new file mode 100644 index 0000000000000..17ee03b0b092f --- /dev/null +++ b/services/nodeping/nodeping-status.tester.js @@ -0,0 +1,75 @@ +'use strict' + +const Joi = require('joi') + +const t = (module.exports = require('../tester').createServiceTester()) + +t.create('NodePing status - live').get( + '/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei.json' +) +Joi.object().keys({ + name: 'Status', + value: Joi.equal('up', 'down').required(), +}) + +t.create('NodePing status - up (mock)') + .get('/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei.json') + .intercept(nock => + nock('https://nodeping.com') + .get( + '/reports/results/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei/1?format=json' + ) + .reply(200, [{ su: true }]) + ) + .expectJSON({ + name: 'Status', + value: 'up', + }) + +t.create('NodePing status - down (mock)') + .get('/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei.json') + .intercept(nock => + nock('https://nodeping.com') + .get( + '/reports/results/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei/1?format=json' + ) + .reply(200, [{ su: false }]) + ) + .expectJSON({ + name: 'Status', + value: 'down', + }) + +t.create('NodePing status - custom up color/message') + .get( + '/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei.json?style=_shields_test&up_color=blue&up_message=happy' + ) + .intercept(nock => + nock('https://nodeping.com') + .get( + '/reports/results/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei/1?format=json' + ) + .reply(200, [{ su: true }]) + ) + .expectJSON({ + name: 'Status', + value: 'happy', + color: 'blue', + }) + +t.create('NodePing status - custom down color/message') + .get( + '/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei.json?style=_shields_test&down_color=yellow&down_message=sad' + ) + .intercept(nock => + nock('https://nodeping.com') + .get( + '/reports/results/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei/1?format=json' + ) + .reply(200, [{ su: false }]) + ) + .expectJSON({ + name: 'Status', + value: 'sad', + color: 'yellow', + }) diff --git a/services/nodeping/nodeping-uptime.service.js b/services/nodeping/nodeping-uptime.service.js new file mode 100644 index 0000000000000..3b1c8ff5108c8 --- /dev/null +++ b/services/nodeping/nodeping-uptime.service.js @@ -0,0 +1,100 @@ +'use strict' + +const { BaseJsonService } = require('..') +const Joi = require('joi') +const { colorScale } = require('../../lib/color-formatters') +const colorFormatter = colorScale([99, 99.5, 100]) + +const rowSchema = Joi.object().keys({ + uptime: Joi.number() + .precision(3) + .min(0) + .max(100), +}) + +const schema = Joi.array() + .items(rowSchema) + .min(1) + +/* + * this is the checkUuid for the NodePing.com (as used on the [example page](https://nodeping.com/reporting.html#results)) + */ +const sampleCheckUuid = 'jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei' + +// TODO: support for custom # of days +// TODO: support for custom color thresholds +// TODO: support for custom colors +// TODO: support for custom '100%' label +// TODO: support for custom # of decimal places + +class NodePingUptime extends BaseJsonService { + static get category() { + return 'monitoring' + } + + static get defaultBadgeData() { + return { + label: 'Uptime', + } + } + + static get route() { + return { + base: 'nodeping/uptime', + pattern: ':checkUuid', + } + } + + static get examples() { + return [ + { + title: 'NodePing uptime', + namedParams: { + checkUuid: sampleCheckUuid, + }, + staticPreview: this.render({ uptime: 99.999 }), + }, + ] + } + + async fetch({ checkUuid }) { + const thirtyDaysAgo = new Date( + new Date().getTime() - 30 * 24 * 60 * 60 * 1000 + ) + .toISOString() + .slice(0, 10) + + const rows = await this._requestJson({ + schema, + url: `https://nodeping.com/reports/uptime/${checkUuid}`, + options: { + qs: { format: 'json', interval: 'days', start: thirtyDaysAgo }, + headers: { + 'cache-control': 'no-cache', + }, + }, + }) + return { uptime: rows[rows.length - 1].uptime } + } + + async handle({ checkUuid }) { + const { uptime } = await this.fetch({ checkUuid }) + return this.constructor.render({ uptime }) + } + + static formatPercentage(uptime) { + if (uptime === 100.0) { + return '100%' + } + return `${uptime.toFixed(3)}%` + } + + static render({ uptime }) { + return { + message: NodePingUptime.formatPercentage(uptime), + color: colorFormatter(uptime), + } + } +} + +module.exports = NodePingUptime diff --git a/services/nodeping/nodeping-uptime.tester.js b/services/nodeping/nodeping-uptime.tester.js new file mode 100644 index 0000000000000..7ba3021bd38c4 --- /dev/null +++ b/services/nodeping/nodeping-uptime.tester.js @@ -0,0 +1,87 @@ +'use strict' + +const t = (module.exports = require('../tester').createServiceTester()) +const { isPercentage } = require('../test-validators') + +t.create('NodePing uptime - live') + .get('/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei.json') + .expectJSONTypes({ + name: 'Uptime', + value: isPercentage, + }) + +t.create('NodePing uptime - 100% (mock)') + .get('/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei.json?style=_shields_test') + .intercept(nock => + nock('https://nodeping.com') + .get( + `/reports/uptime/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei?format=json&interval=days&start=${new Date( + new Date().getTime() - 30 * 24 * 60 * 60 * 1000 + ) + .toISOString() + .slice(0, 10)}` + ) + .reply(200, [{ uptime: 100 }]) + ) + .expectJSON({ + name: 'Uptime', + value: '100%', + color: 'brightgreen', + }) + +t.create('NodePing uptime - 99.999% (mock)') + .get('/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei.json?style=_shields_test') + .intercept(nock => + nock('https://nodeping.com') + .get( + `/reports/uptime/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei?format=json&interval=days&start=${new Date( + new Date().getTime() - 30 * 24 * 60 * 60 * 1000 + ) + .toISOString() + .slice(0, 10)}` + ) + .reply(200, [{ uptime: 99.999 }]) + ) + .expectJSON({ + name: 'Uptime', + value: '99.999%', + color: 'green', + }) + +t.create('NodePing uptime - 99.001% (mock)') + .get('/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei.json?style=_shields_test') + .intercept(nock => + nock('https://nodeping.com') + .get( + `/reports/uptime/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei?format=json&interval=days&start=${new Date( + new Date().getTime() - 30 * 24 * 60 * 60 * 1000 + ) + .toISOString() + .slice(0, 10)}` + ) + .reply(200, [{ uptime: 99.001 }]) + ) + .expectJSON({ + name: 'Uptime', + value: '99.001%', + color: 'yellow', + }) + +t.create('NodePing uptime - 90.001% (mock)') + .get('/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei.json?style=_shields_test') + .intercept(nock => + nock('https://nodeping.com') + .get( + `/reports/uptime/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei?format=json&interval=days&start=${new Date( + new Date().getTime() - 30 * 24 * 60 * 60 * 1000 + ) + .toISOString() + .slice(0, 10)}` + ) + .reply(200, [{ uptime: 90.001 }]) + ) + .expectJSON({ + name: 'Uptime', + value: '90.001%', + color: 'red', + })