Added [VisualStudioAppCenter] badges 🎉 (#4108)

* VisualStudioAppCenterBuilds

* [vsacb] Add schema, documentation and use buildStatus for rendering

* Add VSACReleasesVersion badge and test

* Make tests green again, add another nock test and fix category

* Add VSAC Releases Size badge and test

* Add VSAC Base class

* [vsacb] use base fetch function

* Add VSACR OSVersion service and tests

* Finishing touches

* Change slug from VSAC to Visual-Studio-App-Center

* Use prettyBytes for rendering

* CQ

* Use bytes response directly

* Remove superfluous required statement

* Improve os version badge format

* Switch to nock for build test

Co-authored-by: Pierre-Yves B. <PyvesDev@gmail.com>
Co-authored-by: Caleb Cartwright <calebcartwright@users.noreply.github.com>
This commit is contained in:
James Cahill
2020-02-04 19:43:15 +00:00
committed by GitHub
parent d80636b101
commit 9868025154
9 changed files with 443 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
'use strict'
const { BaseJsonService } = require('..')
const keywords = [
'visual-studio',
'vsac',
'visual-studio-app-center',
'app-center',
]
const documentation =
"You will need to create a <b>read-only</b> API token <a target='_blank' href='https://appcenter.ms/settings/apitokens'>here</a>."
class BaseVisualStudioAppCenterService extends BaseJsonService {
async fetch({
owner,
app,
token,
schema,
url = `https://api.appcenter.ms/v0.1/apps/${owner}/${app}/releases/latest`,
}) {
return this._requestJson({
schema,
options: {
headers: {
'X-API-Token': token,
},
},
errorMessages: {
401: 'invalid token',
403: 'project not found',
404: 'project not found',
},
url,
})
}
}
module.exports = { keywords, documentation, BaseVisualStudioAppCenterService }

View File

@@ -0,0 +1,62 @@
'use strict'
const Joi = require('@hapi/joi')
const { isBuildStatus, renderBuildStatusBadge } = require('../build-status')
const {
BaseVisualStudioAppCenterService,
keywords,
documentation,
} = require('./visual-studio-app-center-base')
const { NotFound } = require('..')
const schema = Joi.array().items({
result: isBuildStatus.required(),
})
module.exports = class VisualStudioAppCenterBuilds extends BaseVisualStudioAppCenterService {
static get category() {
return 'build'
}
static get route() {
return {
base: 'visual-studio-app-center/builds',
pattern: ':owner/:app/:branch/:token',
}
}
static get examples() {
return [
{
title: 'Visual Studio App Center Builds',
namedParams: {
owner: 'jct',
app: 'my-amazing-app',
branch: 'master',
token: 'ac70cv...',
},
staticPreview: renderBuildStatusBadge({ status: 'succeeded' }),
keywords,
documentation,
},
]
}
static get defaultBadgeData() {
return {
label: 'build',
}
}
async handle({ owner, app, branch, token }) {
const json = await this.fetch({
token,
schema,
url: `https://api.appcenter.ms/v0.1/apps/${owner}/${app}/branches/${branch}/builds`,
})
if (json[0] == undefined)
// Fetch will return a 200 with no data if no builds were found.
throw new NotFound({ prettyMessage: 'no builds found' })
return renderBuildStatusBadge({ status: json[0].result })
}
}

View File

@@ -0,0 +1,34 @@
'use strict'
const t = (module.exports = require('../tester').createServiceTester())
// Mocked response rather than real data as old builds are deleted after some time.
t.create('Valid Build')
.get('/nock/nock/master/token.json')
.intercept(nock =>
nock('https://api.appcenter.ms/v0.1/apps/')
.get('/nock/nock/branches/master/builds')
.reply(200, [
{
result: 'succeeded',
},
])
)
.expectBadge({
label: 'build',
message: 'passing',
})
t.create('Invalid Branch')
.get('/jct/test-1/invalid/8c9b519a0750095b9fea3d40b2645d8a0c24a2f3.json')
.expectBadge({
label: 'build',
message: 'no builds found',
})
t.create('Invalid API Token')
.get('/jct/test-1/master/invalid.json')
.expectBadge({
label: 'build',
message: 'invalid token',
})

View File

@@ -0,0 +1,61 @@
'use strict'
const Joi = require('@hapi/joi')
const {
BaseVisualStudioAppCenterService,
keywords,
documentation,
} = require('./visual-studio-app-center-base')
const schema = Joi.object({
app_os: Joi.string().required(),
min_os: Joi.string().required(),
}).required()
module.exports = class VisualStudioAppCenterReleasesOSVersion extends BaseVisualStudioAppCenterService {
static get category() {
return 'version'
}
static get route() {
return {
base: 'visual-studio-app-center/releases/osver',
pattern: ':owner/:app/:token',
}
}
static get examples() {
return [
{
title: 'Visual Studio App Center (Minimum) OS Version',
namedParams: {
owner: 'jct',
app: 'my-amazing-app',
token: 'ac70cv...',
},
staticPreview: this.render({ min_os: '4.1', app_os: 'Android' }),
keywords,
documentation,
},
]
}
static get defaultBadgeData() {
return {
label: 'min version',
color: 'blue',
}
}
static render({ app_os, min_os }) {
return {
label: `${app_os.toLowerCase()}`,
message: `${min_os}+`,
}
}
async handle({ owner, app, token }) {
const { app_os, min_os } = await this.fetch({ owner, app, token, schema })
return this.constructor.render({ app_os, min_os })
}
}

View File

@@ -0,0 +1,38 @@
'use strict'
const t = (module.exports = require('../tester').createServiceTester())
// Note:
// Unfortunately an Invalid user, invalid project, valid API token test is not possible due to the way Microsoft cache their responses.
// For this reason 404 and 403 will instead both display 'project not found'
t.create('[fixed] Example Release')
// This application will never have a new release created.
.get(
'/jct/test-fixed-android-react/8c9b519a0750095b9fea3d40b2645d8a0c24a2f3.json'
)
.expectBadge({
label: 'android',
message: '4.1+',
})
t.create('Valid user, invalid project, valid API token')
.get('/jcx/invalid/8c9b519a0750095b9fea3d40b2645d8a0c24a2f3.json')
.expectBadge({
label: 'min version',
message: 'project not found',
})
t.create('Invalid user, invalid project, valid API token')
.get('/invalid/invalid/8c9b519a0750095b9fea3d40b2645d8a0c24a2f3.json')
.expectBadge({
label: 'min version',
message: 'project not found',
})
t.create('Invalid API Token')
.get('/invalid/invalid/invalid.json')
.expectBadge({
label: 'min version',
message: 'invalid token',
})

View File

@@ -0,0 +1,61 @@
'use strict'
const Joi = require('@hapi/joi')
const prettyBytes = require('pretty-bytes')
const { nonNegativeInteger } = require('../validators')
const {
BaseVisualStudioAppCenterService,
keywords,
documentation,
} = require('./visual-studio-app-center-base')
const schema = Joi.object({
size: nonNegativeInteger,
}).required()
module.exports = class VisualStudioAppCenterReleasesSize extends BaseVisualStudioAppCenterService {
static get category() {
return 'size'
}
static get route() {
return {
base: 'visual-studio-app-center/releases/size',
pattern: ':owner/:app/:token',
}
}
static get examples() {
return [
{
title: 'Visual Studio App Center Size',
namedParams: {
owner: 'jct',
app: 'my-amazing-app',
token: 'ac70cv...',
},
staticPreview: this.render({ size: 8368844 }),
keywords,
documentation,
},
]
}
static get defaultBadgeData() {
return {
label: 'size',
color: 'blue',
}
}
static render({ size }) {
return {
message: prettyBytes(size),
}
}
async handle({ owner, app, token }) {
const { size } = await this.fetch({ owner, app, token, schema })
return this.constructor.render({ size })
}
}

View File

@@ -0,0 +1,48 @@
'use strict'
const t = (module.exports = require('../tester').createServiceTester())
const { isFileSize } = require('../test-validators')
t.create('8368844 bytes to 8.37 megabytes')
.get('/nock/nock/nock.json')
.intercept(nock =>
nock('https://api.appcenter.ms/v0.1/apps/')
.get('/nock/nock/releases/latest')
.reply(200, {
size: 8368844,
})
)
.expectBadge({
label: 'size',
message: '8.37 MB',
})
t.create('Valid Release')
.get(
'/jct/test-fixed-android-react/8c9b519a0750095b9fea3d40b2645d8a0c24a2f3.json'
)
.expectBadge({
label: 'size',
message: isFileSize,
})
t.create('Valid user, invalid project, valid API token')
.get('/jcx/invalid/8c9b519a0750095b9fea3d40b2645d8a0c24a2f3.json')
.expectBadge({
label: 'size',
message: 'project not found',
})
t.create('Invalid user, invalid project, valid API token')
.get('/invalid/invalid/8c9b519a0750095b9fea3d40b2645d8a0c24a2f3.json')
.expectBadge({
label: 'size',
message: 'project not found',
})
t.create('Invalid API Token')
.get('/invalid/invalid/invalid.json')
.expectBadge({
label: 'size',
message: 'invalid token',
})

View File

@@ -0,0 +1,61 @@
'use strict'
const Joi = require('@hapi/joi')
const { renderVersionBadge } = require('../version')
const {
BaseVisualStudioAppCenterService,
keywords,
documentation,
} = require('./visual-studio-app-center-base')
const schema = Joi.object({
version: Joi.string().required(),
short_version: Joi.string().required(),
}).required()
module.exports = class VisualStudioAppCenterReleasesVersion extends BaseVisualStudioAppCenterService {
static get category() {
return 'version'
}
static get route() {
return {
base: 'visual-studio-app-center/releases/version',
pattern: ':owner/:app/:token',
}
}
static get examples() {
return [
{
title: 'Visual Studio App Center Releases',
namedParams: {
owner: 'jct',
app: 'my-amazing-app',
token: 'ac70cv...',
},
staticPreview: renderVersionBadge({ version: '1.0 (4)' }),
keywords,
documentation,
},
]
}
static get defaultBadgeData() {
return {
label: 'release',
}
}
async handle({ owner, app, token }) {
const { version, short_version } = await this.fetch({
owner,
app,
token,
schema,
})
return renderVersionBadge({
version: `${short_version} (${version})`,
})
}
}

View File

@@ -0,0 +1,38 @@
'use strict'
const t = (module.exports = require('../tester').createServiceTester())
// Note:
// Unfortunately an Invalid user, invalid project, valid API token test is not possible due to the way Microsoft cache their responses.
// For this reason 404 and 403 will instead both display 'project not found'
t.create('[fixed] Example Release')
// This application will never have a new release created.
.get(
'/jct/test-fixed-android-react/8c9b519a0750095b9fea3d40b2645d8a0c24a2f3.json'
)
.expectBadge({
label: 'release',
message: 'v1.0 (1)',
})
t.create('Valid user, invalid project, valid API token')
.get('/jcx/invalid/8c9b519a0750095b9fea3d40b2645d8a0c24a2f3.json')
.expectBadge({
label: 'release',
message: 'project not found',
})
t.create('Invalid user, invalid project, valid API token')
.get('/invalid/invalid/8c9b519a0750095b9fea3d40b2645d8a0c24a2f3.json')
.expectBadge({
label: 'release',
message: 'project not found',
})
t.create('Invalid API Token')
.get('/invalid/invalid/invalid.json')
.expectBadge({
label: 'release',
message: 'invalid token',
})