Compare commits
62 Commits
server-202
...
server-202
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d0c57c4aa1 | ||
|
|
814aa30da4 | ||
|
|
4ccee50ce2 | ||
|
|
d3ca453712 | ||
|
|
c602c1d07b | ||
|
|
e358cc54fe | ||
|
|
6e803367e0 | ||
|
|
9c2453df3f | ||
|
|
b23ea32088 | ||
|
|
b85beedd9e | ||
|
|
1370fc6087 | ||
|
|
4d860a19ed | ||
|
|
d7c1e98ea1 | ||
|
|
7ce3c0f528 | ||
|
|
88ff47920a | ||
|
|
b751cc6c57 | ||
|
|
3dc56134d9 | ||
|
|
d3638b1b97 | ||
|
|
59b42184f4 | ||
|
|
b7ddc1e24a | ||
|
|
64aad09d03 | ||
|
|
893a59f6af | ||
|
|
4a68590a23 | ||
|
|
bf39dba8d7 | ||
|
|
0666584b03 | ||
|
|
484e5a0559 | ||
|
|
14cbe2968e | ||
|
|
c88315f183 | ||
|
|
acf2f6de6b | ||
|
|
a1885cdd37 | ||
|
|
567e284ffb | ||
|
|
d16cc9c8ce | ||
|
|
0f1890be82 | ||
|
|
6f63341acb | ||
|
|
9f958a02ca | ||
|
|
060b65e3d5 | ||
|
|
805b80015f | ||
|
|
9c4656ad5e | ||
|
|
be1e4f639f | ||
|
|
ace5e03221 | ||
|
|
d8aab9895c | ||
|
|
68021e16a6 | ||
|
|
5fa18e173a | ||
|
|
e3854098d6 | ||
|
|
83f4548b9d | ||
|
|
5930b59a66 | ||
|
|
4163856357 | ||
|
|
449b8ed28f | ||
|
|
9e8f503150 | ||
|
|
9a8be6d3e8 | ||
|
|
745d2e6e55 | ||
|
|
138365f09a | ||
|
|
b356f8a140 | ||
|
|
d39b2094cc | ||
|
|
804003a37d | ||
|
|
b0ffb6e212 | ||
|
|
fb93a2b4d3 | ||
|
|
f2a14a0aca | ||
|
|
cc3b49232a | ||
|
|
779440bdbf | ||
|
|
d64ab08375 | ||
|
|
680353b5f7 |
5
.github/workflows/build-docker-image.yml
vendored
5
.github/workflows/build-docker-image.yml
vendored
@@ -12,6 +12,9 @@ jobs:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
- name: Set Git Short SHA
|
||||
run: echo "SHORT_SHA=${GITHUB_SHA::7}" >> $GITHUB_ENV
|
||||
|
||||
- name: Build
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
@@ -19,4 +22,4 @@ jobs:
|
||||
push: false
|
||||
tags: shieldsio/shields:pr-validation
|
||||
build-args: |
|
||||
version=${GITHUB_SHA::7}
|
||||
version=${{ env.SHORT_SHA }}
|
||||
|
||||
5
.github/workflows/publish-docker-next.yml
vendored
5
.github/workflows/publish-docker-next.yml
vendored
@@ -20,6 +20,9 @@ jobs:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Set Git Short SHA
|
||||
run: echo "SHORT_SHA=${GITHUB_SHA::7}" >> $GITHUB_ENV
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
@@ -27,4 +30,4 @@ jobs:
|
||||
push: true
|
||||
tags: shieldsio/shields:next
|
||||
build-args: |
|
||||
version=${GITHUB_SHA::7}
|
||||
version=${{ env.SHORT_SHA }}
|
||||
|
||||
16
CHANGELOG.md
16
CHANGELOG.md
@@ -4,6 +4,22 @@ Note: this changelog is for the shields.io server. The changelog for the badge-m
|
||||
|
||||
---
|
||||
|
||||
## server-2022-03-01
|
||||
|
||||
- Add [Conan] version service (#7460)
|
||||
- remove suspended [github] tokens from the pool [#7654](https://github.com/badges/shields/issues/7654)
|
||||
- generate links without trailing : if port not set [#7655](https://github.com/badges/shields/issues/7655)
|
||||
- Use the latest build status when checking docs.rs [#7613](https://github.com/badges/shields/issues/7613)
|
||||
- Remove no download handling and add API warning to [Wordpress] badges [#7606](https://github.com/badges/shields/issues/7606)
|
||||
- set a higher default cacheLength on rating/star category [#7587](https://github.com/badges/shields/issues/7587)
|
||||
- Update [amo] to use v4 API, set custom `cacheLength`s [#7586](https://github.com/badges/shields/issues/7586)
|
||||
- fix(amo): include trailing slash in API call [#7585](https://github.com/badges/shields/issues/7585)
|
||||
- fix docker image user agent [#7582](https://github.com/badges/shields/issues/7582)
|
||||
- Delete deprecated Codetally and continuousphp services [#7572](https://github.com/badges/shields/issues/7572)
|
||||
- Deprecate [Requires] service [#7571](https://github.com/badges/shields/issues/7571)
|
||||
- [AUR] Fix RPC URL [#7570](https://github.com/badges/shields/issues/7570)
|
||||
- Dependency updates
|
||||
|
||||
## server-2022-02-01
|
||||
|
||||
- [Depfu] Add support for Gitlab [#7475](https://github.com/badges/shields/issues/7475)
|
||||
|
||||
@@ -10,7 +10,7 @@ Please follow this guidance when reporting security issues affecting:
|
||||
- The [squint](https://github.com/badges/squint) raster proxy
|
||||
- The [badge-maker](https://www.npmjs.com/package/badge-maker) NPM package
|
||||
|
||||
The [gh-badges](https://www.npmjs.com/package/gh-badges) NPM package is now deprecated and will no longer receive fixes for bugs or security issues.
|
||||
The [gh-badges](https://www.npmjs.com/package/gh-badges) and [svg-to-image-proxy](https://www.npmjs.com/package/svg-to-image-proxy) NPM packages are now deprecated and will no longer receive fixes for bugs or security issues.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
|
||||
@@ -147,6 +147,7 @@ class BaseService {
|
||||
version: 300,
|
||||
debug: 60,
|
||||
downloads: 900,
|
||||
rating: 900,
|
||||
social: 900,
|
||||
}
|
||||
return cacheLengths[this.category]
|
||||
|
||||
@@ -94,6 +94,8 @@ Here is a listing of all deleted badges that were once part of the Shields.io se
|
||||
- Cauditor
|
||||
- CocoaPods Apps
|
||||
- CocoaPods Downloads
|
||||
- Codetally
|
||||
- continuousphp
|
||||
- Coverity
|
||||
- Dockbit
|
||||
- Dotnet Status
|
||||
|
||||
@@ -25,6 +25,9 @@ export function getBaseUrl(): string {
|
||||
if (['shields.io', 'www.shields.io'].includes(hostname)) {
|
||||
return 'https://img.shields.io'
|
||||
}
|
||||
if (!port) {
|
||||
return `${protocol}//${hostname}`
|
||||
}
|
||||
return `${protocol}//${hostname}:${port}`
|
||||
} catch (e) {
|
||||
// server-side rendering
|
||||
|
||||
3268
package-lock.json
generated
3268
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
51
package.json
51
package.json
@@ -21,9 +21,9 @@
|
||||
"url": "https://github.com/badges/shields"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource/lato": "^4.5.1",
|
||||
"@fontsource/lekton": "^4.5.2",
|
||||
"@sentry/node": "^6.17.3",
|
||||
"@fontsource/lato": "^4.5.2",
|
||||
"@fontsource/lekton": "^4.5.3",
|
||||
"@sentry/node": "^6.18.0",
|
||||
"@shields_io/camp": "^18.1.1",
|
||||
"badge-maker": "file:badge-maker",
|
||||
"bytes": "^3.1.2",
|
||||
@@ -36,13 +36,13 @@
|
||||
"decamelize": "^3.2.0",
|
||||
"emojic": "^1.1.16",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"fast-xml-parser": "^4.0.1",
|
||||
"fast-xml-parser": "^4.0.3",
|
||||
"glob": "^7.2.0",
|
||||
"global-agent": "^3.0.0",
|
||||
"got": "^12.0.1",
|
||||
"graphql": "^15.6.1",
|
||||
"graphql-tag": "^2.12.6",
|
||||
"ioredis": "4.28.3",
|
||||
"ioredis": "4.28.5",
|
||||
"joi": "17.6.0",
|
||||
"joi-extension-semver": "5.0.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
@@ -54,13 +54,13 @@
|
||||
"node-env-flag": "^0.1.0",
|
||||
"parse-link-header": "^2.0.0",
|
||||
"path-to-regexp": "^6.2.0",
|
||||
"pretty-bytes": "^5.6.0",
|
||||
"pretty-bytes": "^6.0.0",
|
||||
"priorityqueuejs": "^2.0.0",
|
||||
"prom-client": "^14.0.1",
|
||||
"qs": "^6.10.3",
|
||||
"query-string": "^7.1.0",
|
||||
"query-string": "^7.1.1",
|
||||
"semver": "~7.3.5",
|
||||
"simple-icons": "6.7.0",
|
||||
"simple-icons": "6.11.0",
|
||||
"webextension-store-meta": "^1.0.5",
|
||||
"xmldom": "~0.6.0",
|
||||
"xpath": "~0.0.32"
|
||||
@@ -140,9 +140,9 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.16.12",
|
||||
"@babel/core": "^7.17.5",
|
||||
"@babel/polyfill": "^7.12.1",
|
||||
"@babel/register": "7.16.9",
|
||||
"@babel/register": "7.17.0",
|
||||
"@istanbuljs/schema": "^0.1.3",
|
||||
"@mapbox/react-click-to-select": "^2.2.1",
|
||||
"@types/chai": "^4.3.0",
|
||||
@@ -153,8 +153,8 @@
|
||||
"@types/react-helmet": "^6.1.5",
|
||||
"@types/react-modal": "^3.13.1",
|
||||
"@types/react-select": "^4.0.17",
|
||||
"@types/styled-components": "5.1.21",
|
||||
"@typescript-eslint/eslint-plugin": "^5.10.0",
|
||||
"@types/styled-components": "5.1.23",
|
||||
"@typescript-eslint/eslint-plugin": "^5.12.1",
|
||||
"@typescript-eslint/parser": "^5.10.0",
|
||||
"babel-plugin-inline-react-svg": "^2.0.1",
|
||||
"babel-preset-gatsby": "^2.5.1",
|
||||
@@ -167,33 +167,33 @@
|
||||
"child-process-promise": "^2.2.1",
|
||||
"clipboard-copy": "^4.0.1",
|
||||
"concurrently": "^7.0.0",
|
||||
"cypress": "^9.3.1",
|
||||
"danger": "^10.8.0",
|
||||
"cypress": "^9.5.0",
|
||||
"danger": "^11.0.2",
|
||||
"danger-plugin-no-test-shortcuts": "^2.0.0",
|
||||
"deepmerge": "^4.2.2",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-config-prettier": "^8.4.0",
|
||||
"eslint-config-standard": "^16.0.3",
|
||||
"eslint-config-standard-jsx": "^10.0.0",
|
||||
"eslint-config-standard-react": "^11.0.1",
|
||||
"eslint-plugin-chai-friendly": "^0.7.2",
|
||||
"eslint-plugin-cypress": "^2.12.1",
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
"eslint-plugin-jsdoc": "^37.7.0",
|
||||
"eslint-plugin-jsdoc": "^37.9.4",
|
||||
"eslint-plugin-mocha": "^10.0.3",
|
||||
"eslint-plugin-no-extension-in-require": "^0.2.0",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^6.0.0",
|
||||
"eslint-plugin-react": "^7.28.0",
|
||||
"eslint-plugin-react": "^7.29.1",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"eslint-plugin-sort-class-members": "^1.14.1",
|
||||
"fetch-ponyfill": "^7.1.0",
|
||||
"form-data": "^4.0.0",
|
||||
"gatsby": "4.6.0",
|
||||
"gatsby": "4.6.2",
|
||||
"gatsby-plugin-catch-links": "^4.5.0",
|
||||
"gatsby-plugin-page-creator": "^4.3.0",
|
||||
"gatsby-plugin-page-creator": "^4.7.0",
|
||||
"gatsby-plugin-react-helmet": "^5.2.0",
|
||||
"gatsby-plugin-remove-trailing-slashes": "^4.2.0",
|
||||
"gatsby-plugin-remove-trailing-slashes": "^4.7.0",
|
||||
"gatsby-plugin-styled-components": "^5.2.0",
|
||||
"gatsby-plugin-typescript": "^4.2.0",
|
||||
"humanize-string": "^2.1.0",
|
||||
@@ -202,15 +202,15 @@
|
||||
"is-svg": "^4.3.2",
|
||||
"js-yaml-loader": "^1.2.2",
|
||||
"jsdoc": "^3.6.10",
|
||||
"lint-staged": "^12.3.2",
|
||||
"lint-staged": "^12.3.4",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"lodash.difference": "^4.5.0",
|
||||
"minimist": "^1.2.5",
|
||||
"mocha": "^9.2.0",
|
||||
"mocha": "^9.2.1",
|
||||
"mocha-env-reporter": "^4.0.0",
|
||||
"mocha-junit-reporter": "^2.0.2",
|
||||
"mocha-yaml-loader": "^1.0.3",
|
||||
"nock": "13.2.2",
|
||||
"nock": "13.2.4",
|
||||
"node-mocks-http": "^1.11.0",
|
||||
"nodemon": "^2.0.15",
|
||||
"npm-run-all": "^4.1.5",
|
||||
@@ -229,14 +229,15 @@
|
||||
"rimraf": "^3.0.2",
|
||||
"sazerac": "^2.0.0",
|
||||
"simple-git-hooks": "^2.7.0",
|
||||
"sinon": "^12.0.1",
|
||||
"sinon": "^13.0.1",
|
||||
"sinon-chai": "^3.7.0",
|
||||
"snap-shot-it": "^7.9.6",
|
||||
"start-server-and-test": "1.14.0",
|
||||
"styled-components": "^5.3.3",
|
||||
"ts-mocha": "^9.0.2",
|
||||
"tsd": "^0.19.1",
|
||||
"typescript": "^4.5.5"
|
||||
"typescript": "^4.5.5",
|
||||
"url": "^0.11.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.13.0",
|
||||
|
||||
@@ -21,7 +21,7 @@ class BaseAmoService extends BaseJsonService {
|
||||
async fetch({ addonId }) {
|
||||
return this._requestJson({
|
||||
schema,
|
||||
url: `https://addons.mozilla.org/api/v3/addons/addon/${addonId}`,
|
||||
url: `https://addons.mozilla.org/api/v4/addons/addon/${addonId}/`,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ class AmoWeeklyDownloads extends BaseAmoService {
|
||||
},
|
||||
]
|
||||
|
||||
static _cacheLength = 21600
|
||||
|
||||
static defaultBadgeData = { label: 'downloads' }
|
||||
|
||||
static render({ downloads }) {
|
||||
|
||||
@@ -23,6 +23,8 @@ export default class AmoRating extends BaseAmoService {
|
||||
},
|
||||
]
|
||||
|
||||
static _cacheLength = 7200
|
||||
|
||||
static render({ format, rating }) {
|
||||
rating = Math.round(rating)
|
||||
return {
|
||||
|
||||
@@ -14,6 +14,8 @@ export default class AmoUsers extends BaseAmoService {
|
||||
},
|
||||
]
|
||||
|
||||
static _cacheLength = 21600
|
||||
|
||||
static defaultBadgeData = { label: 'users' }
|
||||
|
||||
static render({ users: downloads }) {
|
||||
|
||||
@@ -42,7 +42,7 @@ class BaseAurService extends BaseJsonService {
|
||||
// https://wiki.archlinux.org/index.php/Aurweb_RPC_interface
|
||||
return this._requestJson({
|
||||
schema: aurSchema,
|
||||
url: 'https://aur.archlinux.org/rpc.php',
|
||||
url: 'https://aur.archlinux.org/rpc',
|
||||
options: { searchParams: { v: 5, type: 'info', arg: packageName } },
|
||||
})
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ t.create('license (no license)')
|
||||
.get('/license/vscodium-bin.json')
|
||||
.intercept(nock =>
|
||||
nock('https://aur.archlinux.org')
|
||||
.get('/rpc.php')
|
||||
.get('/rpc')
|
||||
.query({
|
||||
v: 5,
|
||||
type: 'info',
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
import { deprecatedService } from '../index.js'
|
||||
|
||||
export default [
|
||||
deprecatedService({
|
||||
category: 'funding',
|
||||
label: 'codetally',
|
||||
route: {
|
||||
base: 'codetally',
|
||||
pattern: ':owner/:repo',
|
||||
},
|
||||
dateAdded: new Date('2020-09-05'),
|
||||
}),
|
||||
]
|
||||
@@ -1,14 +0,0 @@
|
||||
import { ServiceTester } from '../tester.js'
|
||||
|
||||
export const t = new ServiceTester({
|
||||
id: 'Codetally',
|
||||
title: 'Codetally',
|
||||
pathPrefix: '/codetally',
|
||||
})
|
||||
|
||||
t.create('no longer available')
|
||||
.get('/triggerman722/colorstrap.json')
|
||||
.expectBadge({
|
||||
label: 'codetally',
|
||||
message: 'no longer available',
|
||||
})
|
||||
21
services/conan/conan-version-helpers.js
Normal file
21
services/conan/conan-version-helpers.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import yaml from 'js-yaml'
|
||||
import { NotFound, InvalidResponse } from '../index.js'
|
||||
import { latest } from '../version.js'
|
||||
|
||||
export function parseLatestVersionFromConfig(configYaml) {
|
||||
let versions
|
||||
try {
|
||||
const config = yaml.load(configYaml)
|
||||
versions = Object.keys(config.versions)
|
||||
} catch (err) {
|
||||
throw new InvalidResponse({
|
||||
prettyMessage: 'invalid config.yml',
|
||||
underlyingError: err,
|
||||
})
|
||||
}
|
||||
const version = latest(versions)
|
||||
if (version == null) {
|
||||
throw new NotFound({ prettyMessage: 'no versions found' })
|
||||
}
|
||||
return version
|
||||
}
|
||||
33
services/conan/conan-version-helpers.spec.js
Normal file
33
services/conan/conan-version-helpers.spec.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import { expect } from 'chai'
|
||||
import { NotFound, InvalidResponse } from '../index.js'
|
||||
import { parseLatestVersionFromConfig } from './conan-version-helpers.js'
|
||||
|
||||
describe('parseLatestVersionFromConfig', function () {
|
||||
it('returns latest available version', function () {
|
||||
expect(
|
||||
parseLatestVersionFromConfig(`
|
||||
versions:
|
||||
1.68.0:
|
||||
folder: all
|
||||
1.70.0:
|
||||
folder: all
|
||||
1.69.0:
|
||||
folder: all
|
||||
`)
|
||||
).to.equal('1.70.0')
|
||||
})
|
||||
|
||||
it('rejects invalid yaml', function () {
|
||||
expect(() => parseLatestVersionFromConfig('[')).to.throw(InvalidResponse)
|
||||
})
|
||||
it('treats no results array as invalid', function () {
|
||||
expect(() =>
|
||||
parseLatestVersionFromConfig('somethingElse: whatever')
|
||||
).to.throw(InvalidResponse)
|
||||
})
|
||||
it('treats empty results array as not found', function () {
|
||||
expect(() => parseLatestVersionFromConfig('versions: []')).to.throw(
|
||||
NotFound
|
||||
)
|
||||
})
|
||||
})
|
||||
34
services/conan/conan-version.service.js
Normal file
34
services/conan/conan-version.service.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import { renderVersionBadge } from '../version.js'
|
||||
import { ConditionalGithubAuthV3Service } from '../github/github-auth-service.js'
|
||||
import { fetchRepoContent } from '../github/github-common-fetch.js'
|
||||
import { parseLatestVersionFromConfig } from './conan-version-helpers.js'
|
||||
|
||||
export default class ConanVersion extends ConditionalGithubAuthV3Service {
|
||||
static category = 'version'
|
||||
|
||||
static route = { base: 'conan/v', pattern: ':packageName' }
|
||||
|
||||
static examples = [
|
||||
{
|
||||
title: 'Conan Center',
|
||||
namedParams: { packageName: 'boost' },
|
||||
staticPreview: renderVersionBadge({ version: '1.78.0' }),
|
||||
keywords: ['c++'],
|
||||
},
|
||||
]
|
||||
|
||||
static defaultBadgeData = { label: 'conan' }
|
||||
|
||||
async handle({ packageName }) {
|
||||
const configContent = await fetchRepoContent(this, {
|
||||
user: 'conan-io',
|
||||
repo: 'conan-center-index',
|
||||
branch: 'master',
|
||||
filename: `recipes/${packageName}/config.yml`,
|
||||
})
|
||||
|
||||
const version = parseLatestVersionFromConfig(configContent)
|
||||
|
||||
return renderVersionBadge({ version })
|
||||
}
|
||||
}
|
||||
17
services/conan/conan-version.tester.js
Normal file
17
services/conan/conan-version.tester.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import { isSemver } from '../test-validators.js'
|
||||
import { createServiceTester } from '../tester.js'
|
||||
|
||||
export const t = await createServiceTester()
|
||||
|
||||
t.create('gets the package version of zeromq')
|
||||
.get('/zeromq.json')
|
||||
.expectBadge({ label: 'conan', message: isSemver })
|
||||
|
||||
t.create('returns not found for invalid package')
|
||||
.get('/this package does not exist - shields test.json')
|
||||
.expectBadge({
|
||||
label: 'conan',
|
||||
color: 'red',
|
||||
message:
|
||||
'repo not found, branch not found, or recipes/this package does not exist - shields test/config.yml missing',
|
||||
})
|
||||
@@ -1,11 +0,0 @@
|
||||
import { deprecatedService } from '../index.js'
|
||||
|
||||
export default deprecatedService({
|
||||
category: 'build',
|
||||
route: {
|
||||
base: 'continuousphp',
|
||||
pattern: ':various+',
|
||||
},
|
||||
label: 'continuousphp',
|
||||
dateAdded: new Date('2020-12-12'),
|
||||
})
|
||||
@@ -1,20 +0,0 @@
|
||||
import { ServiceTester } from '../tester.js'
|
||||
|
||||
export const t = new ServiceTester({
|
||||
id: 'continuousphp',
|
||||
title: 'Continuousphp',
|
||||
})
|
||||
|
||||
t.create('no longer available (previously build status on default branch)')
|
||||
.get('/git-hub/doctrine/dbal.json')
|
||||
.expectBadge({
|
||||
label: 'continuousphp',
|
||||
message: 'no longer available',
|
||||
})
|
||||
|
||||
t.create('no longer available (previously build status on named branch)')
|
||||
.get('/git-hub/doctrine/dbal/develop.json')
|
||||
.expectBadge({
|
||||
label: 'continuousphp',
|
||||
message: 'no longer available',
|
||||
})
|
||||
@@ -52,9 +52,7 @@ export default class DocsRs extends BaseJsonService {
|
||||
}
|
||||
|
||||
async handle({ crate, version = 'latest' }) {
|
||||
const { build_status: buildStatus } = (
|
||||
await this.fetch({ crate, version })
|
||||
).pop()
|
||||
const [{ build_status: buildStatus }] = await this.fetch({ crate, version })
|
||||
return this.constructor.render({ version, buildStatus })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,10 @@ t.create('Failing docs')
|
||||
.get('/tensorflow/0.16.1.json')
|
||||
.expectBadge({ label: 'docs@0.16.1', message: 'failing' })
|
||||
|
||||
t.create('Multiple builds, latest passing')
|
||||
.get('/bevy_tweening/0.3.1.json')
|
||||
.expectBadge({ label: 'docs@0.3.1', message: 'passing' })
|
||||
|
||||
t.create('Getting latest version works')
|
||||
.get('/rand/latest.json')
|
||||
.expectBadge({
|
||||
|
||||
@@ -77,8 +77,7 @@ class GithubApiProvider {
|
||||
}
|
||||
|
||||
getV4RateLimitFromBody(body) {
|
||||
const parsedBody = JSON.parse(body)
|
||||
const b = Joi.attempt(parsedBody, bodySchema)
|
||||
const b = Joi.attempt(body, bodySchema)
|
||||
return {
|
||||
rateLimit: b.data.rateLimit.limit,
|
||||
totalUsesRemaining: b.data.rateLimit.remaining,
|
||||
@@ -90,8 +89,17 @@ class GithubApiProvider {
|
||||
let rateLimit, totalUsesRemaining, nextReset
|
||||
if (url.startsWith('/graphql')) {
|
||||
try {
|
||||
const parsedBody = JSON.parse(res.body)
|
||||
|
||||
if ('message' in parsedBody && !('data' in parsedBody)) {
|
||||
if (parsedBody.message === 'Sorry. Your account was suspended.') {
|
||||
this.invalidateToken(token)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
;({ rateLimit, totalUsesRemaining, nextReset } =
|
||||
this.getV4RateLimitFromBody(res.body))
|
||||
this.getV4RateLimitFromBody(parsedBody))
|
||||
} catch (e) {
|
||||
console.error(
|
||||
`Could not extract rate limit info from response body ${res.body}`
|
||||
|
||||
@@ -126,14 +126,35 @@ describe('Github API provider', function () {
|
||||
})
|
||||
})
|
||||
|
||||
context('an unauthorized response', function () {
|
||||
it('should invoke the callback and update the token with the expected values', async function () {
|
||||
context('unauthorized API responses', function () {
|
||||
it('should invoke the callback and update the token with the expected values (unauthorized, v3)', async function () {
|
||||
const mockResponse = { res: { statusCode: 401, headers: {} } }
|
||||
const mockRequest = sinon.stub().resolves(mockResponse)
|
||||
await provider.fetch(mockRequest, '/foo', {})
|
||||
expect(mockStandardToken.invalidate).to.have.been.calledOnce
|
||||
expect(mockStandardToken.update).not.to.have.been.called
|
||||
})
|
||||
|
||||
it('should invoke the callback and update the token with the expected values (unauthorized, v4)', async function () {
|
||||
const mockResponse = { res: { statusCode: 401, body: {} } }
|
||||
const mockRequest = sinon.stub().resolves(mockResponse)
|
||||
await provider.fetch(mockRequest, '/graphql', {})
|
||||
expect(mockGraphqlToken.invalidate).to.have.been.calledOnce
|
||||
expect(mockGraphqlToken.update).not.to.have.been.called
|
||||
})
|
||||
|
||||
it('should invoke the callback and update the token with the expected values (suspended, v4)', async function () {
|
||||
const mockResponse = {
|
||||
res: {
|
||||
statusCode: 200,
|
||||
body: '{ "message": "Sorry. Your account was suspended." }',
|
||||
},
|
||||
}
|
||||
const mockRequest = sinon.stub().resolves(mockResponse)
|
||||
await provider.fetch(mockRequest, '/graphql', {})
|
||||
expect(mockGraphqlToken.invalidate).to.have.been.calledOnce
|
||||
expect(mockGraphqlToken.update).not.to.have.been.called
|
||||
})
|
||||
})
|
||||
|
||||
context('a connection error', function () {
|
||||
|
||||
@@ -82,10 +82,8 @@ t.create('Locked version of unknown dependency')
|
||||
})
|
||||
|
||||
t.create('Locked version of VCS dependency')
|
||||
.get(
|
||||
'/locked/dependency-version/DemocracyClub/aggregator-api/dc-base-theme.json'
|
||||
)
|
||||
.get('/locked/dependency-version/GSS-Cogs/databaker-docker/databaker.json')
|
||||
.expectBadge({
|
||||
label: 'dc-base-theme',
|
||||
label: 'databaker',
|
||||
message: isShortSha,
|
||||
})
|
||||
|
||||
@@ -1,65 +1,11 @@
|
||||
import Joi from 'joi'
|
||||
import { BaseJsonService } from '../index.js'
|
||||
import { deprecatedService } from '../index.js'
|
||||
|
||||
const statusSchema = Joi.object({
|
||||
status: Joi.string().required(),
|
||||
}).required()
|
||||
|
||||
export default class RequiresIo extends BaseJsonService {
|
||||
static category = 'dependencies'
|
||||
|
||||
static route = {
|
||||
export default deprecatedService({
|
||||
category: 'dependencies',
|
||||
route: {
|
||||
base: 'requires',
|
||||
pattern: ':service/:user/:repo/:branch*',
|
||||
}
|
||||
|
||||
static examples = [
|
||||
{
|
||||
title: 'Requires.io',
|
||||
pattern: ':service/:user/:repo',
|
||||
namedParams: { service: 'github', user: 'zulip', repo: 'zulip' },
|
||||
staticPreview: this.render({ status: 'up-to-date' }),
|
||||
},
|
||||
{
|
||||
title: 'Requires.io (branch)',
|
||||
pattern: ':service/:user/:repo/:branch',
|
||||
namedParams: {
|
||||
service: 'github',
|
||||
user: 'zulip',
|
||||
repo: 'zulip',
|
||||
branch: 'master',
|
||||
},
|
||||
staticPreview: this.render({ status: 'up-to-date' }),
|
||||
},
|
||||
]
|
||||
|
||||
static defaultBadgeData = { label: 'requirements' }
|
||||
|
||||
static render({ status }) {
|
||||
let message = status
|
||||
let color = 'lightgrey'
|
||||
if (status === 'up-to-date') {
|
||||
message = 'up to date'
|
||||
color = 'brightgreen'
|
||||
} else if (status === 'outdated') {
|
||||
color = 'yellow'
|
||||
} else if (status === 'insecure') {
|
||||
color = 'red'
|
||||
}
|
||||
return { message, color }
|
||||
}
|
||||
|
||||
async fetch({ service, user, repo, branch }) {
|
||||
const url = `https://requires.io/api/v1/status/${service}/${user}/${repo}`
|
||||
return this._requestJson({
|
||||
url,
|
||||
schema: statusSchema,
|
||||
options: { searchParams: { branch } },
|
||||
})
|
||||
}
|
||||
|
||||
async handle({ service, user, repo, branch }) {
|
||||
const { status } = await this.fetch({ service, user, repo, branch })
|
||||
return this.constructor.render({ status })
|
||||
}
|
||||
}
|
||||
format: '(?:.+?)',
|
||||
},
|
||||
label: 'requirements',
|
||||
dateAdded: new Date('2022-02-05'),
|
||||
})
|
||||
|
||||
@@ -1,44 +1,20 @@
|
||||
import Joi from 'joi'
|
||||
import { createServiceTester } from '../tester.js'
|
||||
export const t = await createServiceTester()
|
||||
import { ServiceTester } from '../tester.js'
|
||||
|
||||
const isRequireStatus = Joi.string().regex(
|
||||
/^(up to date|outdated|insecure|unknown)$/
|
||||
)
|
||||
export const t = new ServiceTester({
|
||||
id: 'requires',
|
||||
title: 'Requires.io',
|
||||
})
|
||||
|
||||
// Package targets can be found at https://requires.io/public
|
||||
// However, there does seem to be some retention issues where
|
||||
// results for projects are purged after some number of days.
|
||||
// https://github.com/badges/shields/issues/7015
|
||||
// https://github.com/requires/api/issues/5
|
||||
t.create('requirements (valid GitHub, without branch)')
|
||||
.get('/github/Hongbo-Miao/hongbomiao.com.json')
|
||||
.expectBadge({
|
||||
label: 'requirements',
|
||||
message: isRequireStatus,
|
||||
})
|
||||
|
||||
t.create('requirements (valid GitHub, with branch)')
|
||||
.get('/github/Hongbo-Miao/hongbomiao.com/main.json')
|
||||
.expectBadge({
|
||||
label: 'requirements',
|
||||
message: isRequireStatus,
|
||||
})
|
||||
|
||||
t.create('requirements (valid Bitbucket, without branch)')
|
||||
t.create('no longer available (previously Bitbucket without branch)')
|
||||
.get('/bitbucket/code-orange/django-ispstack.json')
|
||||
.expectBadge({
|
||||
label: 'requirements',
|
||||
message: isRequireStatus,
|
||||
message: 'no longer available',
|
||||
})
|
||||
|
||||
t.create('requirements (valid Bitbucket, with branch)')
|
||||
.get('/bitbucket/code-orange/django-ispstack/master.json')
|
||||
t.create('no longer available (previously GitHub with branch)')
|
||||
.get('/github/Hongbo-Miao/hongbomiao.com/main.json')
|
||||
.expectBadge({
|
||||
label: 'requirements',
|
||||
message: isRequireStatus,
|
||||
message: 'no longer available',
|
||||
})
|
||||
|
||||
t.create('requirements (not found)')
|
||||
.get('/github/PyvesB/EmptyRepo.json')
|
||||
.expectBadge({ label: 'requirements', message: 'not found' })
|
||||
|
||||
@@ -2,9 +2,11 @@ import { createServiceTester } from '../tester.js'
|
||||
export const t = await createServiceTester()
|
||||
|
||||
t.create('grade of https://shields.io')
|
||||
.timeout(15000)
|
||||
.get('/security-headers.json?url=https://shields.io')
|
||||
.expectBadge({ label: 'security headers', message: 'F', color: 'red' })
|
||||
|
||||
t.create('grade of https://httpstat.us/301 as redirect')
|
||||
.timeout(15000)
|
||||
.get('/security-headers.json?ignoreRedirects&url=https://httpstat.us/301')
|
||||
.expectBadge({ label: 'security headers', message: 'R', color: 'blue' })
|
||||
|
||||
@@ -20,7 +20,7 @@ t.create('non existent repo')
|
||||
})
|
||||
|
||||
t.create('valid target manifest path')
|
||||
.get('/snyk/vulndb-fixtures/packages/cli/0.1.0/package.json.json')
|
||||
.get('/snyk/snyk-resolve-deps-fixtures/node_modules/debug/package.json.json')
|
||||
.timeout(20000)
|
||||
.expectBadge({
|
||||
label: 'vulnerabilities',
|
||||
|
||||
@@ -41,7 +41,7 @@ const notFoundSchema = Joi.object()
|
||||
const pluginSchemas = Joi.alternatives(pluginSchema, notFoundSchema)
|
||||
const themeSchemas = Joi.alternatives(themeSchema, notFoundSchema)
|
||||
|
||||
export default class BaseWordpress extends BaseJsonService {
|
||||
export class BaseWordpress extends BaseJsonService {
|
||||
async fetch({ extensionType, slug }) {
|
||||
const url = `https://api.wordpress.org/${extensionType}s/info/1.2/`
|
||||
let schemas
|
||||
@@ -84,3 +84,12 @@ export default class BaseWordpress extends BaseJsonService {
|
||||
return json
|
||||
}
|
||||
}
|
||||
|
||||
export const documentation = `
|
||||
<p>
|
||||
These badges rely on an API that is no longer supported by Wordpress. You are
|
||||
still free to use them, simply bear in mind that Shields.io cannot guarantee
|
||||
that they'll keep on working in the future. Please also double-check the
|
||||
provided slug, as an incorrect value may lead to unexpected results.
|
||||
</p>
|
||||
`
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import Joi from 'joi'
|
||||
import { renderDownloadsBadge } from '../downloads.js'
|
||||
import { NotFound } from '../index.js'
|
||||
import BaseWordpress from './wordpress-base.js'
|
||||
import { documentation, BaseWordpress } from './wordpress-base.js'
|
||||
|
||||
const dateSchema = Joi.object()
|
||||
.pattern(Joi.date().iso(), Joi.number().integer())
|
||||
@@ -58,6 +57,7 @@ function DownloadsForExtensionType(extensionType) {
|
||||
title: `WordPress ${capt} Downloads`,
|
||||
namedParams: { interval: 'dm', slug: exampleSlug },
|
||||
staticPreview: this.render({ interval: 'dm', downloads: 200000 }),
|
||||
documentation,
|
||||
},
|
||||
]
|
||||
|
||||
@@ -91,17 +91,9 @@ function DownloadsForExtensionType(extensionType) {
|
||||
},
|
||||
},
|
||||
})
|
||||
const size = Object.keys(json).length
|
||||
downloads = Object.values(json).reduce(
|
||||
(a, b) => parseInt(a) + parseInt(b)
|
||||
)
|
||||
// This check is for non-existent and brand-new plugins both having new stats.
|
||||
// Non-Existent plugins results are the same as a brandspanking new plugin with no downloads.
|
||||
if (downloads <= 0 && size <= 1) {
|
||||
throw new NotFound({
|
||||
prettyMessage: `${extensionType} not found or too new`,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return this.constructor.render({ interval, downloads })
|
||||
@@ -127,6 +119,7 @@ function InstallsForExtensionType(extensionType) {
|
||||
title: `WordPress ${capt} Active Installs`,
|
||||
namedParams: { slug: exampleSlug },
|
||||
staticPreview: renderDownloadsBadge({ downloads: 300000 }),
|
||||
documentation,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
@@ -98,34 +98,6 @@ t.create('Plugin Downloads - Active | Not Found')
|
||||
message: 'not found',
|
||||
})
|
||||
|
||||
t.create('Plugin Downloads - Day | Not Found')
|
||||
.get('/plugin/dd/100.json')
|
||||
.expectBadge({
|
||||
label: 'downloads',
|
||||
message: 'plugin not found or too new',
|
||||
})
|
||||
|
||||
t.create('Plugin Downloads - Week | Not Found')
|
||||
.get('/plugin/dw/100.json')
|
||||
.expectBadge({
|
||||
label: 'downloads',
|
||||
message: 'plugin not found or too new',
|
||||
})
|
||||
|
||||
t.create('Plugin Downloads - Month | Not Found')
|
||||
.get('/plugin/dm/100.json')
|
||||
.expectBadge({
|
||||
label: 'downloads',
|
||||
message: 'plugin not found or too new',
|
||||
})
|
||||
|
||||
t.create('Plugin Downloads - Year | Not Found')
|
||||
.get('/plugin/dy/100.json')
|
||||
.expectBadge({
|
||||
label: 'downloads',
|
||||
message: 'plugin not found or too new',
|
||||
})
|
||||
|
||||
t.create('Theme Downloads - Total | Not Found')
|
||||
.get('/theme/dt/100.json')
|
||||
.expectBadge({
|
||||
@@ -139,31 +111,3 @@ t.create('Theme Downloads - Active | Not Found')
|
||||
label: 'active installs',
|
||||
message: 'not found',
|
||||
})
|
||||
|
||||
t.create('Theme Downloads - Day | Not Found')
|
||||
.get('/theme/dd/100.json')
|
||||
.expectBadge({
|
||||
label: 'downloads',
|
||||
message: 'theme not found or too new',
|
||||
})
|
||||
|
||||
t.create('Theme Downloads - Week | Not Found')
|
||||
.get('/theme/dw/100.json')
|
||||
.expectBadge({
|
||||
label: 'downloads',
|
||||
message: 'theme not found or too new',
|
||||
})
|
||||
|
||||
t.create('Theme Downloads - Month | Not Found')
|
||||
.get('/theme/dm/100.json')
|
||||
.expectBadge({
|
||||
label: 'downloads',
|
||||
message: 'theme not found or too new',
|
||||
})
|
||||
|
||||
t.create('Theme Downloads - Year | Not Found')
|
||||
.get('/theme/dy/100.json')
|
||||
.expectBadge({
|
||||
label: 'downloads',
|
||||
message: 'theme not found or too new',
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@ import moment from 'moment'
|
||||
import { InvalidResponse } from '../index.js'
|
||||
import { formatDate } from '../text-formatters.js'
|
||||
import { age as ageColor } from '../color-formatters.js'
|
||||
import BaseWordpress from './wordpress-base.js'
|
||||
import { documentation, BaseWordpress } from './wordpress-base.js'
|
||||
|
||||
const extensionData = {
|
||||
plugin: {
|
||||
@@ -35,6 +35,7 @@ function LastUpdateForType(extensionType) {
|
||||
title: `WordPress ${capt} Last Updated`,
|
||||
namedParams: { slug: exampleSlug },
|
||||
staticPreview: this.render({ lastUpdated: '2020-08-11' }),
|
||||
documentation,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { NotFound } from '../index.js'
|
||||
import { addv } from '../text-formatters.js'
|
||||
import { version as versionColor } from '../color-formatters.js'
|
||||
import BaseWordpress from './wordpress-base.js'
|
||||
import { documentation, BaseWordpress } from './wordpress-base.js'
|
||||
import { versionColorForWordpressVersion } from './wordpress-version-color.js'
|
||||
|
||||
const extensionData = {
|
||||
@@ -33,6 +33,7 @@ function WordpressRequiresVersion(extensionType) {
|
||||
title: `WordPress ${capt}: Required WP Version`,
|
||||
namedParams: { slug: exampleSlug },
|
||||
staticPreview: this.render({ wordpressVersion: '4.8' }),
|
||||
documentation,
|
||||
},
|
||||
]
|
||||
|
||||
@@ -77,6 +78,7 @@ class WordpressPluginTestedVersion extends BaseWordpress {
|
||||
staticPreview: this.renderStaticPreview({
|
||||
testedVersion: '4.9.8',
|
||||
}),
|
||||
documentation,
|
||||
},
|
||||
]
|
||||
|
||||
@@ -128,6 +130,7 @@ function RequiresPHPVersionForType(extensionType) {
|
||||
title: `WordPress ${capt} Required PHP Version`,
|
||||
namedParams: { slug: exampleSlug },
|
||||
staticPreview: this.render({ version: '5.5' }),
|
||||
documentation,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { starRating, metric } from '../text-formatters.js'
|
||||
import { floorCount } from '../color-formatters.js'
|
||||
import BaseWordpress from './wordpress-base.js'
|
||||
import { documentation, BaseWordpress } from './wordpress-base.js'
|
||||
|
||||
const extensionData = {
|
||||
plugin: {
|
||||
@@ -38,6 +38,7 @@ function RatingForExtensionType(extensionType) {
|
||||
rating: 80,
|
||||
numRatings: 100,
|
||||
}),
|
||||
documentation,
|
||||
},
|
||||
]
|
||||
|
||||
@@ -78,7 +79,7 @@ function StarsForExtensionType(extensionType) {
|
||||
staticPreview: this.render({
|
||||
rating: 80,
|
||||
}),
|
||||
documentation: 'There is an alias <code>/r/:slug.svg</code> as well.',
|
||||
documentation,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { addv } from '../text-formatters.js'
|
||||
import { version as versionColor } from '../color-formatters.js'
|
||||
import BaseWordpress from './wordpress-base.js'
|
||||
import { documentation, BaseWordpress } from './wordpress-base.js'
|
||||
|
||||
function VersionForExtensionType(extensionType) {
|
||||
const { capt, exampleSlug } = {
|
||||
@@ -29,6 +29,7 @@ function VersionForExtensionType(extensionType) {
|
||||
title: `WordPress ${capt} Version`,
|
||||
namedParams: { slug: exampleSlug },
|
||||
staticPreview: this.render({ version: 2.5 }),
|
||||
documentation,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user