1
0
mirror of https://github.com/badges/shields.git synced 2025-04-18 19:44:04 +03:00

Add ability to format bytes as metric or IEC; affects [bundlejs bundlephobia ChromeWebStoreSize CratesSize DockerSize GithubRepoSize GithubCodeSize GithubSize NpmUnpackedSize SpigetDownloadSize steam VisualStudioAppCenterReleasesSize whatpulse] (#10547)

* add renderSizeBadge helper, use it everywhere

- switch from pretty-bytes to byte-size
- add renderSizeBadge() helper function
- match upstream conventions for metric/IEC units
- add new test helpers and use them in service tests

* unrelated: fix npm unpacked size query param schema

not strictly related to this PR
but I noticed it was broken

* chromewebstore: reformat size string, test against isIecFileSize
This commit is contained in:
chris48s 2024-12-01 19:53:26 +00:00 committed by GitHub
parent b7d7f4545d
commit 151c70dd17
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 142 additions and 144 deletions

21
package-lock.json generated
View File

@ -15,6 +15,7 @@
"@shields_io/camp": "^18.1.2",
"@xmldom/xmldom": "0.9.5",
"badge-maker": "file:badge-maker",
"byte-size": "^9.0.0",
"bytes": "^3.1.2",
"camelcase": "^8.0.0",
"chalk": "^5.3.0",
@ -45,7 +46,6 @@
"parse-link-header": "^2.0.0",
"path-to-regexp": "^6.3.0",
"pg": "^8.13.1",
"pretty-bytes": "^6.1.1",
"priorityqueuejs": "^2.0.0",
"prom-client": "^15.1.3",
"qs": "^6.13.1",
@ -8132,6 +8132,14 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/byte-size": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/byte-size/-/byte-size-9.0.0.tgz",
"integrity": "sha512-xrJ8Hki7eQ6xew55mM6TG9zHI852OoAHcPfduWWtR6yxk2upTuIZy13VioRBDyHReHDdbeDPifUboeNkK/sXXA==",
"engines": {
"node": ">=12.17"
}
},
"node_modules/bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@ -24578,17 +24586,6 @@
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/pretty-bytes": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.1.tgz",
"integrity": "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==",
"engines": {
"node": "^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/pretty-error": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz",

View File

@ -27,6 +27,7 @@
"@shields_io/camp": "^18.1.2",
"@xmldom/xmldom": "0.9.5",
"badge-maker": "file:badge-maker",
"byte-size": "^9.0.0",
"bytes": "^3.1.2",
"camelcase": "^8.0.0",
"chalk": "^5.3.0",
@ -57,7 +58,6 @@
"parse-link-header": "^2.0.0",
"path-to-regexp": "^6.3.0",
"pg": "^8.13.1",
"pretty-bytes": "^6.1.1",
"priorityqueuejs": "^2.0.0",
"prom-client": "^15.1.3",
"qs": "^6.13.1",

View File

@ -1,9 +1,11 @@
import Joi from 'joi'
import { BaseJsonService, pathParam, queryParam } from '../index.js'
import { renderSizeBadge } from '../size.js'
import { nonNegativeInteger } from '../validators.js'
const schema = Joi.object({
size: Joi.object({
compressedSize: Joi.string().required(),
rawCompressedSize: nonNegativeInteger,
}).required(),
}).required()
@ -76,13 +78,6 @@ export default class BundlejsPackage extends BaseJsonService {
static defaultBadgeData = { label: 'bundlejs', color: 'informational' }
static render({ size }) {
return {
label: 'minified size (gzip)',
message: size,
}
}
async fetch({ scope, packageName, exports }) {
const searchParams = {
q: `${scope ? `${scope}/` : ''}${packageName}`,
@ -110,7 +105,7 @@ export default class BundlejsPackage extends BaseJsonService {
async handle({ scope, packageName }, { exports }) {
const json = await this.fetch({ scope, packageName, exports })
const size = json.size.compressedSize
return this.constructor.render({ size })
const size = json.size.rawCompressedSize
return renderSizeBadge(size, 'metric', 'minified size (gzip)')
}
}

View File

@ -1,26 +1,26 @@
import { isFileSize } from '../test-validators.js'
import { isMetricFileSize } from '../test-validators.js'
import { createServiceTester } from '../tester.js'
export const t = await createServiceTester()
t.create('bundlejs/package (packageName)')
.get('/jquery.json')
.expectBadge({ label: 'minified size (gzip)', message: isFileSize })
.expectBadge({ label: 'minified size (gzip)', message: isMetricFileSize })
t.create('bundlejs/package (version)')
.get('/react@18.2.0.json')
.expectBadge({ label: 'minified size (gzip)', message: isFileSize })
.expectBadge({ label: 'minified size (gzip)', message: isMetricFileSize })
t.create('bundlejs/package (scoped)')
.get('/@cycle/rx-run.json')
.expectBadge({ label: 'minified size (gzip)', message: isFileSize })
.expectBadge({ label: 'minified size (gzip)', message: isMetricFileSize })
t.create('bundlejs/package (select exports)')
.get('/value-enhancer.json?exports=isVal,val')
.expectBadge({ label: 'minified size (gzip)', message: isFileSize })
.expectBadge({ label: 'minified size (gzip)', message: isMetricFileSize })
t.create('bundlejs/package (scoped version select exports)')
.get('/@ngneat/falso@6.4.0.json?exports=randEmail,randFullName')
.expectBadge({ label: 'minified size (gzip)', message: isFileSize })
.expectBadge({ label: 'minified size (gzip)', message: isMetricFileSize })
t.create('bundlejs/package (not found)')
.get('/react@18.2.0.json')

View File

@ -1,5 +1,5 @@
import Joi from 'joi'
import prettyBytes from 'pretty-bytes'
import { renderSizeBadge } from '../size.js'
import { nonNegativeInteger } from '../validators.js'
import { BaseJsonService, pathParams } from '../index.js'
@ -112,10 +112,7 @@ export default class Bundlephobia extends BaseJsonService {
static render({ format, size }) {
const label = format === 'min' ? 'minified size' : 'minzipped size'
return {
label,
message: prettyBytes(size),
}
return renderSizeBadge(size, 'iec', label)
}
async fetch({ scope, packageName, version }) {

View File

@ -1,4 +1,4 @@
import { isFileSize } from '../test-validators.js'
import { isIecFileSize } from '../test-validators.js'
import { createServiceTester } from '../tester.js'
export const t = await createServiceTester()
@ -13,42 +13,42 @@ const data = [
{
format: formats.A,
get: '/min/preact.json',
expect: { label: 'minified size', message: isFileSize },
expect: { label: 'minified size', message: isIecFileSize },
},
{
format: formats.B,
get: '/min/preact/8.0.0.json',
expect: { label: 'minified size', message: isFileSize },
expect: { label: 'minified size', message: isIecFileSize },
},
{
format: formats.C,
get: '/min/@cycle/core.json',
expect: { label: 'minified size', message: isFileSize },
expect: { label: 'minified size', message: isIecFileSize },
},
{
format: formats.D,
get: '/min/@cycle/core/7.0.0.json',
expect: { label: 'minified size', message: isFileSize },
expect: { label: 'minified size', message: isIecFileSize },
},
{
format: formats.A,
get: '/minzip/preact.json',
expect: { label: 'minzipped size', message: isFileSize },
expect: { label: 'minzipped size', message: isIecFileSize },
},
{
format: formats.B,
get: '/minzip/preact/8.0.0.json',
expect: { label: 'minzipped size', message: isFileSize },
expect: { label: 'minzipped size', message: isIecFileSize },
},
{
format: formats.C,
get: '/minzip/@cycle/core.json',
expect: { label: 'minzipped size', message: isFileSize },
expect: { label: 'minzipped size', message: isIecFileSize },
},
{
format: formats.D,
get: '/minzip/@cycle/core/7.0.0.json',
expect: { label: 'minzipped size', message: isFileSize },
expect: { label: 'minzipped size', message: isIecFileSize },
},
{
format: formats.A,

View File

@ -1,4 +1,4 @@
import { NotFound, pathParams } from '../index.js'
import { InvalidResponse, NotFound, pathParams } from '../index.js'
import BaseChromeWebStoreService from './chrome-web-store-base.js'
export default class ChromeWebStoreSize extends BaseChromeWebStoreService {
@ -22,6 +22,17 @@ export default class ChromeWebStoreSize extends BaseChromeWebStoreService {
color: 'blue',
}
transform(sizeStr) {
const match = sizeStr.match(/^(\d+)([a-zA-Z]+)$/)
if (!match) {
throw new InvalidResponse({
prettyMessage: 'size does not match expected format',
})
}
const [, size, units] = match
return `${size} ${units}`
}
async handle({ storeId }) {
const chromeWebStore = await this.fetch({ storeId })
const size = chromeWebStore.size()
@ -30,6 +41,6 @@ export default class ChromeWebStoreSize extends BaseChromeWebStoreService {
throw new NotFound({ prettyMessage: 'not found' })
}
return { message: size }
return { message: this.transform(size) }
}
}

View File

@ -1,11 +1,11 @@
import { createServiceTester } from '../tester.js'
import { isIecFileSize } from '../test-validators.js'
export const t = await createServiceTester()
const isFileSize = /^\d+(\.\d+)?(MiB|KiB)$/
t.create('Size').get('/nccfelhkfpbnefflolffkclhenplhiab.json').expectBadge({
label: 'extension size',
message: isFileSize,
message: isIecFileSize,
})
t.create('Size (not found)')

View File

@ -1,5 +1,5 @@
import prettyBytes from 'pretty-bytes'
import { pathParams } from '../index.js'
import { renderSizeBadge } from '../size.js'
import { BaseCratesService, description } from './crates-base.js'
export default class CratesSize extends BaseCratesService {
@ -38,17 +38,9 @@ export default class CratesSize extends BaseCratesService {
},
}
render({ size }) {
return {
label: 'size',
message: prettyBytes(size),
color: 'blue',
}
}
async handle({ crate, version }) {
const json = await this.fetch({ crate, version })
const size = this.constructor.getVersionObj(json).crate_size
return this.render({ size })
return renderSizeBadge(size, 'iec')
}
}

View File

@ -1,14 +1,14 @@
import { createServiceTester } from '../tester.js'
import { isFileSize } from '../test-validators.js'
import { isIecFileSize } from '../test-validators.js'
export const t = await createServiceTester()
t.create('size')
.get('/tokio.json')
.expectBadge({ label: 'size', message: isFileSize })
.expectBadge({ label: 'size', message: isIecFileSize })
t.create('size (with version)')
.get('/tokio/1.32.0.json')
.expectBadge({ label: 'size', message: '725 kB' })
.expectBadge({ label: 'size', message: '708 KiB' })
t.create('size (not found)')
.get('/not-a-crate.json')

View File

@ -1,5 +1,5 @@
import Joi from 'joi'
import prettyBytes from 'pretty-bytes'
import { renderSizeBadge } from '../size.js'
import { nonNegativeInteger } from '../validators.js'
import { latest } from '../version.js'
import { BaseJsonService, NotFound, pathParams, queryParams } from '../index.js'
@ -124,10 +124,6 @@ export default class DockerSize extends BaseJsonService {
static defaultBadgeData = { label: 'image size', color: 'blue' }
static render({ size }) {
return { message: prettyBytes(size) }
}
async fetch({ user, repo, tag, page }) {
page = page ? `&page=${page}` : ''
return await fetch(this, {
@ -233,6 +229,6 @@ export default class DockerSize extends BaseJsonService {
}
const { size } = await this.transform({ tag, sort, data, arch })
return this.constructor.render({ size })
return renderSizeBadge(size, 'iec', 'image size')
}
}

View File

@ -1,4 +1,4 @@
import { isFileSize } from '../test-validators.js'
import { isIecFileSize } from '../test-validators.js'
import { createServiceTester } from '../tester.js'
export const t = await createServiceTester()
@ -6,35 +6,35 @@ t.create('docker image size (valid, library)')
.get('/_/alpine.json')
.expectBadge({
label: 'image size',
message: isFileSize,
message: isIecFileSize,
})
t.create('docker image size (valid, library, arch parameter )')
.get('/_/mysql.json?arch=amd64')
.expectBadge({
label: 'image size',
message: isFileSize,
message: isIecFileSize,
})
t.create('docker image size (valid, library with tag)')
.get('/_/alpine/latest.json')
.expectBadge({
label: 'image size',
message: isFileSize,
message: isIecFileSize,
})
t.create('docker image size (valid, user)')
.get('/jrottenberg/ffmpeg.json')
.expectBadge({
label: 'image size',
message: isFileSize,
message: isIecFileSize,
})
t.create('docker image size (valid, user with tag)')
.get('/jrottenberg/ffmpeg/3.2-alpine.json')
.expectBadge({
label: 'image size',
message: isFileSize,
message: isIecFileSize,
})
t.create('docker image size (invalid, incorrect tag)')

View File

@ -1,5 +1,5 @@
import prettyBytes from 'pretty-bytes'
import { pathParams } from '../index.js'
import { renderSizeBadge } from '../size.js'
import { BaseGithubLanguage } from './github-languages-base.js'
import { documentation } from './github-helpers.js'
@ -31,15 +31,8 @@ export default class GithubCodeSize extends BaseGithubLanguage {
static defaultBadgeData = { label: 'code size' }
static render({ size }) {
return {
message: prettyBytes(size),
color: 'blue',
}
}
async handle({ user, repo }) {
const data = await this.fetch({ user, repo })
return this.constructor.render({ size: this.getTotalSize(data) })
return renderSizeBadge(this.getTotalSize(data), 'iec', 'code size')
}
}

View File

@ -1,4 +1,4 @@
import { isFileSize } from '../test-validators.js'
import { isIecFileSize } from '../test-validators.js'
import { createServiceTester } from '../tester.js'
export const t = await createServiceTester()
@ -6,7 +6,7 @@ t.create('code size in bytes for all languages')
.get('/badges/shields.json')
.expectBadge({
label: 'code size',
message: isFileSize,
message: isIecFileSize,
})
t.create('code size in bytes for all languages (empty repo)')

View File

@ -1,6 +1,6 @@
import Joi from 'joi'
import prettyBytes from 'pretty-bytes'
import { pathParams } from '../index.js'
import { renderSizeBadge } from '../size.js'
import { nonNegativeInteger } from '../validators.js'
import { GithubAuthV3Service } from './github-auth-service.js'
import { documentation, httpErrorsFor } from './github-helpers.js'
@ -33,14 +33,6 @@ export default class GithubRepoSize extends GithubAuthV3Service {
static defaultBadgeData = { label: 'repo size' }
static render({ size }) {
return {
// note the GH API returns size in Kb
message: prettyBytes(size * 1024),
color: 'blue',
}
}
async fetch({ user, repo }) {
return this._requestJson({
url: `/repos/${user}/${repo}`,
@ -51,6 +43,8 @@ export default class GithubRepoSize extends GithubAuthV3Service {
async handle({ user, repo }) {
const { size } = await this.fetch({ user, repo })
return this.constructor.render({ size })
// note the GH API returns size in KiB
// so we multiply by 1024 to get a size in bytes and then format that in IEC bytes
return renderSizeBadge(size * 1024, 'iec', 'repo size')
}
}

View File

@ -1,10 +1,10 @@
import { isFileSize } from '../test-validators.js'
import { isIecFileSize } from '../test-validators.js'
import { createServiceTester } from '../tester.js'
export const t = await createServiceTester()
t.create('repository size').get('/badges/shields.json').expectBadge({
label: 'repo size',
message: isFileSize,
message: isIecFileSize,
})
t.create('repository size (repo not found)')

View File

@ -1,5 +1,5 @@
import Joi from 'joi'
import prettyBytes from 'pretty-bytes'
import { renderSizeBadge } from '../size.js'
import { nonNegativeInteger } from '../validators.js'
import { NotFound, pathParam, queryParam } from '../index.js'
import { GithubAuthV3Service } from './github-auth-service.js'
@ -44,13 +44,6 @@ export default class GithubSize extends GithubAuthV3Service {
},
}
static render({ size }) {
return {
message: prettyBytes(size),
color: 'blue',
}
}
async fetch({ user, repo, path, branch }) {
if (branch) {
return this._requestJson({
@ -73,6 +66,6 @@ export default class GithubSize extends GithubAuthV3Service {
if (Array.isArray(body)) {
throw new NotFound({ prettyMessage: 'not a regular file' })
}
return this.constructor.render({ size: body.size })
return renderSizeBadge(body.size, 'iec')
}
}

View File

@ -1,10 +1,10 @@
import { isFileSize } from '../test-validators.js'
import { isIecFileSize } from '../test-validators.js'
import { createServiceTester } from '../tester.js'
export const t = await createServiceTester()
t.create('File size')
.get('/webcaetano/craft/build/phaser-craft.min.js.json')
.expectBadge({ label: 'size', message: isFileSize })
.expectBadge({ label: 'size', message: isIecFileSize })
t.create('File size 404')
.get('/webcaetano/craft/build/does-not-exist.min.js.json')
@ -20,12 +20,12 @@ t.create('File size for "not a regular file"')
t.create('File size for a specified branch')
.get('/webcaetano/craft/build/craft.min.js.json?branch=version-2')
.expectBadge({ label: 'size', message: isFileSize })
.expectBadge({ label: 'size', message: isIecFileSize })
t.create('File size for a specified tag')
.get('/webcaetano/craft/build/phaser-craft.min.js.json?branch=2.1.2')
.expectBadge({ label: 'size', message: isFileSize })
.expectBadge({ label: 'size', message: isIecFileSize })
t.create('File size for a specified commit')
.get('/webcaetano/craft/build/phaser-craft.min.js.json?branch=b848dbb')
.expectBadge({ label: 'size', message: isFileSize })
.expectBadge({ label: 'size', message: isIecFileSize })

View File

@ -1,8 +1,11 @@
import Joi from 'joi'
import prettyBytes from 'pretty-bytes'
import { pathParam, queryParam } from '../index.js'
import { renderSizeBadge } from '../size.js'
import { optionalNonNegativeInteger } from '../validators.js'
import NpmBase, { packageNameDescription } from './npm-base.js'
import NpmBase, {
packageNameDescription,
queryParamSchema,
} from './npm-base.js'
const schema = Joi.object({
dist: Joi.object({
@ -16,6 +19,7 @@ export default class NpmUnpackedSize extends NpmBase {
static route = {
base: 'npm/unpacked-size',
pattern: ':scope(@[^/]+)?/:packageName/:version*',
queryParamSchema,
}
static openApi = {
@ -78,10 +82,13 @@ export default class NpmUnpackedSize extends NpmBase {
})
const { unpackedSize } = dist
if (unpackedSize) {
return renderSizeBadge(unpackedSize, 'metric', 'unpacked size')
}
return {
label: 'unpacked size',
message: unpackedSize ? prettyBytes(unpackedSize) : 'unknown',
color: unpackedSize ? 'blue' : 'lightgray',
message: 'unknown',
color: 'lightgray',
}
}
}

View File

@ -1,11 +1,11 @@
import { isFileSize } from '../test-validators.js'
import { isMetricFileSize } from '../test-validators.js'
import { createServiceTester } from '../tester.js'
export const t = await createServiceTester()
t.create('Latest unpacked size')
.get('/firereact.json')
.expectBadge({ label: 'unpacked size', message: isFileSize })
.expectBadge({ label: 'unpacked size', message: isMetricFileSize })
t.create('Nonexistent unpacked size with version')
.get('/express/4.16.0.json')
@ -13,15 +13,15 @@ t.create('Nonexistent unpacked size with version')
t.create('Unpacked size with version')
.get('/firereact/0.7.0.json')
.expectBadge({ label: 'unpacked size', message: '147 kB' })
.expectBadge({ label: 'unpacked size', message: '147.2 kB' })
t.create('Unpacked size for scoped package')
.get('/@testing-library/react.json')
.expectBadge({ label: 'unpacked size', message: isFileSize })
.expectBadge({ label: 'unpacked size', message: isMetricFileSize })
t.create('Unpacked size for scoped package with version')
.get('/@testing-library/react/14.2.1.json')
.expectBadge({ label: 'unpacked size', message: '5.41 MB' })
.expectBadge({ label: 'unpacked size', message: '5.4 MB' })
t.create('Nonexistent unpacked size for scoped package with version')
.get('/@cycle/rx-run/7.2.0.json')

25
services/size.js Normal file
View File

@ -0,0 +1,25 @@
/**
* @module
*/
import byteSize from 'byte-size'
/**
* Creates a badge object that displays information about a size in bytes number.
* It should usually be used to output a size badge.
*
* @param {number} bytes - Raw number of bytes to be formatted
* @param {'metric'|'iec'} units - Either 'metric' (multiples of 1000) or 'iec' (multiples of 1024).
* This should align with how the upstream displays sizes.
* @param {string} [label='size'] - Custom label
* @returns {object} A badge object that has three properties: label, message, and color
*/
function renderSizeBadge(bytes, units, label = 'size') {
return {
label,
message: byteSize(bytes, { units }).toString(),
color: 'blue',
}
}
export { renderSizeBadge }

View File

@ -1,10 +1,10 @@
import { isFileSize } from '../test-validators.js'
import { isMetricFileSize } from '../test-validators.js'
import { createServiceTester } from '../tester.js'
export const t = await createServiceTester()
t.create('EssentialsX (hosted resource)')
.get('/771.json')
.expectBadge({ label: 'size', message: isFileSize })
.expectBadge({ label: 'size', message: isMetricFileSize })
t.create('external resource').get('/9089.json').expectBadge({
label: 'size',

View File

@ -1,6 +1,6 @@
import Joi from 'joi'
import prettyBytes from 'pretty-bytes'
import { renderDateBadge } from '../date.js'
import { renderSizeBadge } from '../size.js'
import { renderDownloadsBadge } from '../downloads.js'
import { metric } from '../text-formatters.js'
import { NotFound, pathParams } from '../index.js'
@ -208,12 +208,8 @@ class SteamFileSize extends SteamFileService {
label: 'size',
}
static render({ fileSize }) {
return { message: prettyBytes(fileSize), color: 'informational' }
}
async onRequest({ response }) {
return this.constructor.render({ fileSize: response.file_size })
return renderSizeBadge(response.file_size, 'metric')
}
}

View File

@ -1,5 +1,9 @@
import { ServiceTester } from '../tester.js'
import { isMetric, isFileSize, isFormattedDate } from '../test-validators.js'
import {
isMetric,
isMetricFileSize,
isFormattedDate,
} from '../test-validators.js'
export const t = new ServiceTester({
id: 'steam',
@ -12,7 +16,7 @@ t.create('Collection Files')
t.create('File Size')
.get('/size/1523924535.json')
.expectBadge({ label: 'size', message: isFileSize })
.expectBadge({ label: 'size', message: isMetricFileSize })
t.create('Release Date')
.get('/release-date/1523924535.json')

View File

@ -106,9 +106,12 @@ const isPercentage = Joi.alternatives().try(
isDecimalPercentageNegative,
)
const isFileSize = withRegex(
const isMetricFileSize = withRegex(
/^[0-9]*[.]?[0-9]+\s(B|kB|KB|MB|GB|TB|PB|EB|ZB|YB)$/,
)
const isIecFileSize = withRegex(
/^[0-9]*[.]?[0-9]+\s(B|KiB|MiB|GiB|TiB|PiB|EiB|ZiB|YiB)$/,
)
const isFormattedDate = Joi.alternatives().try(
Joi.equal('today', 'yesterday'),
@ -202,7 +205,8 @@ export {
isPercentage,
isIntegerPercentage,
isDecimalPercentage,
isFileSize,
isMetricFileSize,
isIecFileSize,
isFormattedDate,
isRelativeFormattedDate,
isDependencyState,

View File

@ -1,6 +1,6 @@
import Joi from 'joi'
import prettyBytes from 'pretty-bytes'
import { pathParams } from '../index.js'
import { renderSizeBadge } from '../size.js'
import { nonNegativeInteger } from '../validators.js'
import {
BaseVisualStudioAppCenterService,
@ -47,14 +47,8 @@ export default class VisualStudioAppCenterReleasesSize extends BaseVisualStudioA
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 })
return renderSizeBadge(size, 'metric')
}
}

View File

@ -1,5 +1,5 @@
import { createServiceTester } from '../tester.js'
import { isFileSize } from '../test-validators.js'
import { isMetricFileSize } from '../test-validators.js'
export const t = await createServiceTester()
t.create('8368844 bytes to 8.37 megabytes')
@ -13,7 +13,7 @@ t.create('8368844 bytes to 8.37 megabytes')
)
.expectBadge({
label: 'size',
message: '8.37 MB',
message: '8.4 MB',
})
t.create('Valid Release')
@ -22,7 +22,7 @@ t.create('Valid Release')
)
.expectBadge({
label: 'size',
message: isFileSize,
message: isMetricFileSize,
})
t.create('Valid user, invalid project, valid API token')

View File

@ -1,6 +1,6 @@
import { createServiceTester } from '../tester.js'
import {
isFileSize,
isMetricFileSize,
isHumanized,
isMetric,
isOrdinalNumber,
@ -21,11 +21,11 @@ t.create('WhatPulse team as team id, clicks')
t.create('WhatPulse team as team id, download')
.get('/download/team/1295.json')
.expectBadge({ label: 'download', message: isFileSize })
.expectBadge({ label: 'download', message: isMetricFileSize })
t.create('WhatPulse team as team id, upload')
.get('/upload/team/1295.json')
.expectBadge({ label: 'upload', message: isFileSize })
.expectBadge({ label: 'upload', message: isMetricFileSize })
t.create('WhatPulse team as team name, keys - from Ranks')
.get('/keys/team/dutch power cows.json?rank')