├── Procfile
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── config.yml
│ ├── 4_Feature_request.md
│ └── 1_Bug_report.md
├── workflows
│ └── auto-approve.yml
└── probot.js
├── .mocharc.yml
├── config
├── production.yml
├── development.yml
├── test.yml
├── local-shields-io-production.template.yml
├── local.template.yml
├── shields-io-production.yml
└── default.yml
├── frontend
├── constants.ts
├── pages
│ └── index.tsx
├── images
│ └── favicon.png
├── types
│ ├── assets.d.ts
│ └── mapbox__react-click-to-select
│ │ └── index.d.ts
├── mocha-ignore-pngs.js
├── enzyme-conf.spec.js
├── lib
│ ├── supported-features.ts
│ ├── redirect-legacy-routes.ts
│ └── service-definitions
│ │ └── index.spec.ts
└── components
│ ├── donate.tsx
│ └── header.tsx
├── cypress
└── .eslintrc.yml
├── doc
└── flamegraph.png
├── spec
└── proportions.png
├── badge-maker
├── .npmignore
├── index.d.ts
└── index.test-d.ts
├── core
├── base-service
│ ├── loader-test-fixtures
│ │ ├── empty-array.fixture.js
│ │ ├── empty-object.fixture.js
│ │ ├── empty-undefined.fixture.js
│ │ ├── empty-no-export.fixture.js
│ │ ├── invalid-no-base.fixture.js
│ │ ├── invalid-wrong-base.fixture.js
│ │ ├── invalid-mixed.fixture.js
│ │ ├── valid-class.fixture.js
│ │ ├── valid-array.fixture.js
│ │ └── valid-object.fixture.js
│ ├── coalesce.js
│ ├── to-array.js
│ ├── categories.js
│ ├── coalesce.spec.js
│ └── json.js
├── register-chai-plugins.spec.js
├── got-test-client.js
├── unhandled-rejection.spec.js
├── server
│ ├── instance-id-generator.js
│ ├── error-pages
│ │ ├── 500.html
│ │ └── 404.html
│ ├── secret-is-valid.js
│ └── in-process-server-test-helpers.js
├── badge-urls
│ └── path-helpers.js
└── service-test-runner
│ └── services-for-title.spec.js
├── .eslintignore
├── .prettierrc.yml
├── services
├── index.js
├── codacy
│ └── codacy-helpers.js
├── jira
│ ├── jira-common.js
│ ├── jira-sprint-redirect.tester.js
│ ├── jira-issue-redirect.tester.js
│ ├── jira-issue-redirect.service.js
│ ├── jira-sprint-redirect.service.js
│ └── jira-test-helpers.js
├── gitter
│ └── gitter.tester.js
├── node
│ ├── testUtils
│ │ ├── packageJsonTemplate.json
│ │ └── packageJsonVersionsTemplate.json
│ ├── node-lts.service.js
│ ├── node-current.service.js
│ ├── node-lts.spec.js
│ └── node-current.spec.js
├── github
│ ├── auth
│ │ └── is-valid-token.js
│ ├── github-labels.tester.js
│ ├── github-followers.tester.js
│ ├── github-license.spec.js
│ ├── github-search.tester.js
│ ├── github-repo-size.tester.js
│ ├── github-all-contributors.tester.js
│ ├── github-forks.tester.js
│ ├── github-watchers.tester.js
│ ├── github-language-count.tester.js
│ ├── github-hacktoberfest.spec.js
│ ├── github-issue-detail-redirect.service.js
│ ├── github-size.tester.js
│ ├── github-top-language.tester.js
│ ├── github-contributors.tester.js
│ ├── github-code-size.tester.js
│ ├── github-deployments.tester.js
│ ├── github-last-commit.tester.js
│ └── github-lerna-json.tester.js
├── nexus
│ ├── nexus-version.js
│ └── nexus-redirect.service.js
├── wordpress
│ ├── wordpress-platform-redirect.tester.js
│ └── wordpress-platform-redirect.service.js
├── response-fixtures.js
├── tester.js
├── bstats
│ ├── bstats-players.tester.js
│ └── bstats-servers.tester.js
├── deprecation-helpers.js
├── nsp
│ └── nsp.service.js
├── security-headers
│ └── security-headers.tester.js
├── dockbit
│ ├── dockbit.service.js
│ └── dockbit.tester.js
├── cauditor
│ ├── cauditor.service.js
│ └── cauditor.tester.js
├── libscore
│ ├── libscore.service.js
│ └── libscore.tester.js
├── bithound
│ ├── bithound.service.js
│ └── bithound.tester.js
├── endpoint
│ ├── endpoint-redirect.service.js
│ └── endpoint-redirect.tester.js
├── magnumci
│ ├── magnumci.service.js
│ └── magnumci.tester.js
├── gemnasium
│ ├── gemnasium.service.js
│ └── gemnasium.tester.js
├── imagelayers
│ ├── imagelayers.service.js
│ └── imagelayers.tester.js
├── waffle
│ ├── waffle-label.service.js
│ ├── waffle-label-redirect.tester.js
│ └── waffle-label.tester.js
├── issuestats
│ ├── issuestats.service.js
│ └── issuestats.tester.js
├── leanpub
│ ├── leanpub-book-summary.service.js
│ └── leanpub-book-summary.tester.js
├── versioneye
│ ├── versioneye.service.js
│ └── versioneye.tester.js
├── coverity
│ ├── coverity-on-demand.service.js
│ └── coverity-on-demand.tester.js
├── dotnetstatus
│ ├── dotnetstatus.service.js
│ └── dotnetstatus.tester.js
├── gratipay
│ ├── gratipay.tester.js
│ └── gratipay.service.js
├── jitpack
│ ├── jitpack-downloads.service.js
│ ├── jitpack-version-redirector.tester.js
│ ├── jitpack-version-redirector.service.js
│ ├── jitpack-version.tester.js
│ └── jitpack-downloads.tester.js
├── php-eye
│ ├── php-eye-hhvm.service.js
│ ├── php-eye-php-version.service.js
│ ├── php-eye-hhvm.tester.js
│ └── php-eye-php-version.tester.js
├── cocoapods
│ ├── cocoapods-apps.service.js
│ ├── cocoapods-downloads.service.js
│ ├── cocoapods-version.tester.js
│ ├── cocoapods-apps.tester.js
│ ├── cocoapods-license.tester.js
│ ├── cocoapods-docs.tester.js
│ └── cocoapods-base.js
├── dub
│ ├── dub-license.tester.js
│ └── dub-version.tester.js
├── cpan
│ ├── cpan-license.tester.js
│ ├── cpan.js
│ └── cpan-version.service.js
├── symfony
│ ├── sensiolabs-redirect.tester.js
│ ├── sensiolabs-redirect.service.js
│ ├── symfony-insight-base.spec.js
│ ├── symfony-insight-stars.tester.js
│ ├── symfony-insight-violations.tester.js
│ └── symfony-insight-grade.tester.js
├── snap-ci
│ ├── snap-ci.tester.js
│ └── snap-ci.service.js
├── amo
│ ├── amo-users.tester.js
│ ├── amo-version.tester.js
│ ├── amo-rating.tester.js
│ └── amo-downloads.tester.js
├── lgtm
│ ├── lgtm-test-helpers.js
│ ├── lgtm-redirector.tester.js
│ └── lgtm-redirector.service.js
├── crates
│ ├── crates-version.tester.js
│ ├── crates-license.tester.js
│ └── crates-version.spec.js
├── twitter
│ ├── twitter-redirect.tester.js
│ └── twitter-redirect.service.js
├── spiget
│ ├── spiget-downloads.tester.js
│ ├── spiget-download-size.tester.js
│ ├── spiget-latest-version.tester.js
│ └── spiget-rating.tester.js
├── conda
│ ├── conda-license.tester.js
│ ├── conda-version.tester.js
│ ├── conda-platform.tester.js
│ ├── conda-downloads.tester.js
│ └── conda-base.js
├── gem
│ ├── gem-owner.tester.js
│ └── gem-version.tester.js
├── sonar
│ ├── sonar-generic.tester.js
│ ├── sonar-quality-gate.spec.js
│ └── sonar-documented-api-density.spec.js
├── liberapay
│ ├── liberapay-patrons.tester.js
│ ├── liberapay-goal.tester.js
│ ├── liberapay-gives.tester.js
│ ├── liberapay-receives.tester.js
│ └── liberapay-goal.spec.js
├── appveyor
│ ├── appveyor-build-redirect.service.js
│ ├── appveyor-build-redirect.tester.js
│ └── appveyor-job-build.tester.js
├── cdnjs
│ └── cdnjs.tester.js
├── puppetforge
│ ├── puppetforge-user-module-count.tester.js
│ ├── puppetforge-user-release-count.tester.js
│ ├── puppetforge-module-downloads.tester.js
│ ├── puppetforge-module-version.tester.js
│ └── puppetforge-module-pdk-version.tester.js
├── bit
│ └── bit-components.tester.js
├── clojars
│ ├── clojars-downloads.tester.js
│ └── clojars-base.js
├── spack
│ └── spack.tester.js
├── codeclimate
│ ├── codeclimate-analysis-redirector.tester.js
│ └── codeclimate-analysis-redirector.service.js
├── teamcity
│ ├── teamcity-test-helpers.js
│ ├── teamcity-coverage-redirect.tester.js
│ └── teamcity-coverage-redirect.service.js
├── elm-package
│ └── elm-package.tester.js
├── hackage
│ ├── hackage-deps.tester.js
│ └── hackage-version.tester.js
├── check-services.spec.js
├── chocolatey
│ └── chocolatey.service.js
├── netlify
│ ├── netlify.tester.js
│ └── netlify.spec.js
├── maven-metadata
│ ├── maven-metadata-redirect.service.js
│ └── maven-metadata-redirect.tester.js
├── repology
│ └── repology-repositories.tester.js
├── debug
│ └── debug.tester.js
├── eclipse-marketplace
│ ├── eclipse-marketplace-favorites.tester.js
│ ├── eclipse-marketplace-update.tester.js
│ ├── eclipse-marketplace-base.js
│ └── eclipse-marketplace-version.tester.js
├── luarocks
│ └── luarocks.spec.js
├── stackexchange
│ ├── stackexchange-helpers.js
│ ├── stackexchange-taginfo.tester.js
│ ├── stackexchange-monthlyquestions.tester.js
│ └── stackexchange-reputation.tester.js
├── vaadin-directory
│ ├── vaadin-directory-status.tester.js
│ ├── vaadin-directory-rating-count.tester.js
│ ├── vaadin-directory-version.tester.js
│ └── vaadin-directory-release-date.tester.js
├── discourse
│ └── discourse-redirect.service.js
├── continuousphp
│ ├── continuousphp.spec.js
│ └── continuousphp.tester.js
├── date
│ └── date.tester.js
├── offset-earth
│ ├── offset-earth-carbon.tester.js
│ └── offset-earth-trees.tester.js
├── beerpay
│ └── beerpay.tester.js
├── cirrus
│ └── cirrus.tester.js
├── resharper
│ └── resharper.service.js
├── bugzilla
│ └── bugzilla.spec.js
├── deprecation-helpers.spec.js
├── ansible
│ ├── ansible-quality.tester.js
│ └── ansible-role.tester.js
├── swagger
│ └── swagger-redirect.service.js
├── contributor-count.js
├── bountysource
│ └── bountysource.tester.js
├── itunes
│ └── itunes.tester.js
├── npm
│ ├── npm-downloads.spec.js
│ └── npm-collaborators.tester.js
├── opm
│ └── opm-version.tester.js
├── static-badge
│ ├── static-badge.service.js
│ └── query-string-static.service.js
├── depfu
│ └── depfu.tester.js
├── dynamic
│ ├── dynamic-helpers.js
│ ├── dynamic-json.service.js
│ ├── dynamic-yaml.service.js
│ └── json-path.spec.js
├── pypi
│ ├── pypi-wheel.tester.js
│ ├── pypi-status.tester.js
│ ├── pypi-implementation.tester.js
│ └── pypi-format.tester.js
├── sourceforge
│ └── sourceforge-open-tickets.tester.js
├── codefactor
│ ├── codefactor-grade.tester.js
│ └── codefactor-helpers.js
├── codecov
│ ├── codecov.spec.js
│ └── codecov-redirect.service.js
├── docker
│ ├── docker-cloud-common-fetch.js
│ ├── docker-pulls.tester.js
│ └── docker-stars.tester.js
├── travis
│ ├── travis-php-version-redirect.tester.js
│ └── travis-php-version-redirect.service.js
├── librariesio
│ ├── librariesio-sourcerank.tester.js
│ ├── librariesio-dependents.tester.js
│ ├── librariesio-dependent-repos.tester.js
│ └── librariesio-dependencies-helpers.spec.js
├── bower
│ └── bower-license.tester.js
├── keybase
│ ├── keybase-pgp.tester.js
│ ├── keybase-zec.tester.js
│ ├── keybase-xlm.tester.js
│ └── keybase-btc.tester.js
├── fedora
│ └── fedora.tester.js
├── chrome-web-store
│ ├── chrome-web-store-price.tester.js
│ └── chrome-web-store-version.tester.js
├── jenkins
│ ├── jenkins-base.js
│ └── jenkins-tests-redirector.service.js
├── contributor-count.spec.js
├── youtube
│ ├── youtube-views.tester.js
│ └── youtube-comments.tester.js
├── homebrew
│ ├── homebrew-cask.tester.js
│ └── homebrew.tester.js
├── pkgreview
│ └── package-rating.tester.js
├── packagist
│ └── packagist-license.spec.js
├── requires
│ └── requires.tester.js
├── maintenance
│ └── maintenance.tester.js
├── website-status.spec.js
├── cran
│ └── cran.tester.js
├── sourcegraph
│ └── sourcegraph.tester.js
└── cookbook
│ └── cookbook.tester.js
├── .dockerignore
├── .vscode
├── extensions.json
└── launch.json
├── logo
├── npm.svg
├── stackexchange.svg
├── telegram.svg
├── dependabot.svg
├── gitlab.svg
└── serverfault.svg
├── .mocharc-frontend.yml
├── lib
├── svg-helpers.js
├── svg-helpers.spec.js
├── server-secrets.js
└── load-simple-icons.js
├── now.json
├── cypress.json
├── .editorconfig
├── .prettierignore
├── .nycrc-frontend.json
├── jsdoc.json
├── tsconfig.json
├── scripts
├── export-service-definitions-cli.js
├── github_token_backup.fish
├── export-supported-features-cli.js
├── redis-connectivity-test.js
└── benchmark-performance.js
├── gatsby-browser.js
├── .nycrc.json
├── Dockerfile
└── entrypoint.spec.js
/Procfile:
--------------------------------------------------------------------------------
1 | web: npm run start:server:prod
2 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | open_collective: shields
2 |
--------------------------------------------------------------------------------
/.mocharc.yml:
--------------------------------------------------------------------------------
1 | reporter: mocha-env-reporter
2 |
--------------------------------------------------------------------------------
/config/production.yml:
--------------------------------------------------------------------------------
1 | public:
2 | bind:
3 | address: '0.0.0.0'
4 |
--------------------------------------------------------------------------------
/frontend/constants.ts:
--------------------------------------------------------------------------------
1 | export const baseUrl = process.env.GATSBY_BASE_URL || ''
2 |
--------------------------------------------------------------------------------
/cypress/.eslintrc.yml:
--------------------------------------------------------------------------------
1 | plugins:
2 | - cypress
3 | env:
4 | cypress/globals: true
5 |
--------------------------------------------------------------------------------
/doc/flamegraph.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bs/shields/master/doc/flamegraph.png
--------------------------------------------------------------------------------
/spec/proportions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bs/shields/master/spec/proportions.png
--------------------------------------------------------------------------------
/frontend/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import Main from '../components/main'
2 | export default Main
3 |
--------------------------------------------------------------------------------
/badge-maker/.npmignore:
--------------------------------------------------------------------------------
1 | lib/make-badge-test-helpers.js
2 | lib/**/*.spec.js
3 | index.test-d.ts
4 |
--------------------------------------------------------------------------------
/frontend/images/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bs/shields/master/frontend/images/favicon.png
--------------------------------------------------------------------------------
/core/base-service/loader-test-fixtures/empty-array.fixture.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | module.exports = []
4 |
--------------------------------------------------------------------------------
/core/base-service/loader-test-fixtures/empty-object.fixture.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | module.exports = {}
4 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | /api-docs/
2 | /build
3 | /coverage
4 | /__snapshots__
5 | /public
6 | badge-maker/node_modules/
7 |
--------------------------------------------------------------------------------
/core/base-service/loader-test-fixtures/empty-undefined.fixture.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | module.exports = undefined
4 |
--------------------------------------------------------------------------------
/.prettierrc.yml:
--------------------------------------------------------------------------------
1 | semi: false
2 | singleQuote: true
3 | bracketSpacing: true
4 | endOfLine: lf
5 | arrowParens: avoid
6 |
--------------------------------------------------------------------------------
/core/base-service/loader-test-fixtures/empty-no-export.fixture.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | 'use strict'
3 |
4 | class BadService {}
5 |
--------------------------------------------------------------------------------
/services/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const base = require('../core/base-service')
4 |
5 | module.exports = {
6 | ...base,
7 | }
8 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | shields.env
3 | .git/
4 | .gitignore
5 | .vscode/
6 |
7 | # Improve layer cacheability.
8 | Dockerfile
9 |
--------------------------------------------------------------------------------
/core/base-service/loader-test-fixtures/invalid-no-base.fixture.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | class BadService {}
4 |
5 | module.exports = BadService
6 |
--------------------------------------------------------------------------------
/frontend/types/assets.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.svg'
2 | declare module '*.json'
3 |
4 | // Handled by js-yaml-loader.
5 | declare module '*.yml'
6 |
--------------------------------------------------------------------------------
/core/register-chai-plugins.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { use } = require('chai')
4 |
5 | use(require('chai-string'))
6 | use(require('sinon-chai'))
7 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "esbenp.prettier-vscode",
4 | "EditorConfig.EditorConfig",
5 | "dbaeumer.vscode-eslint"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/core/base-service/coalesce.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | module.exports = function coalesce(...candidates) {
4 | return candidates.find(c => c !== undefined && c !== null)
5 | }
6 |
--------------------------------------------------------------------------------
/core/got-test-client.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const got = require('got')
4 |
5 | // https://github.com/nock/nock/issues/1523
6 | module.exports = got.extend({ retry: 0 })
7 |
--------------------------------------------------------------------------------
/logo/npm.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.mocharc-frontend.yml:
--------------------------------------------------------------------------------
1 | reporter: mocha-env-reporter
2 | require:
3 | - '@babel/polyfill'
4 | - '@babel/register'
5 | - mocha-yaml-loader
6 | - frontend/mocha-ignore-pngs
7 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | contact_links:
2 | - name: Support Question
3 | url: https://github.com/badges/shields/discussions
4 | about: Ask a question about Shields.io
5 |
--------------------------------------------------------------------------------
/lib/svg-helpers.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | function svg2base64(svg) {
4 | return `data:image/svg+xml;base64,${Buffer.from(svg).toString('base64')}`
5 | }
6 |
7 | module.exports = { svg2base64 }
8 |
--------------------------------------------------------------------------------
/core/base-service/loader-test-fixtures/invalid-wrong-base.fixture.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | class BadBaseService {}
4 | class BadService extends BadBaseService {}
5 |
6 | module.exports = BadService
7 |
--------------------------------------------------------------------------------
/services/codacy/codacy-helpers.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 |
5 | const codacyGrade = Joi.equal('A', 'B', 'C', 'D', 'E', 'F')
6 |
7 | module.exports = { codacyGrade }
8 |
--------------------------------------------------------------------------------
/now.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 1,
3 | "name": "shields",
4 | "env": {
5 | "PERSISTENCE_DIR": "/tmp/persistence"
6 | },
7 | "type": "npm",
8 | "engines": {
9 | "node": "8.x"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/services/jira/jira-common.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const authConfig = {
4 | userKey: 'jira_user',
5 | passKey: 'jira_pass',
6 | serviceKey: 'jira',
7 | }
8 |
9 | module.exports = { authConfig }
10 |
--------------------------------------------------------------------------------
/config/development.yml:
--------------------------------------------------------------------------------
1 | public:
2 | bind:
3 | address: 'localhost'
4 |
5 | cors:
6 | allowedOrigin: ['http://localhost:3000']
7 |
8 | rateLimit: false
9 |
10 | handleInternalErrors: false
11 |
--------------------------------------------------------------------------------
/core/unhandled-rejection.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | // Cause unhandled promise rejections to fail unit tests, and print with stack
4 | // traces.
5 | process.on('unhandledRejection', error => {
6 | throw error
7 | })
8 |
--------------------------------------------------------------------------------
/frontend/mocha-ignore-pngs.js:
--------------------------------------------------------------------------------
1 | import requireHacker from 'require-hacker'
2 |
3 | // https://diessi.ca/blog/how-to-exclude-css-images-anything-from-unit-tests/
4 |
5 | requireHacker.hook('png', () => 'module.exports = ""')
6 |
--------------------------------------------------------------------------------
/cypress.json:
--------------------------------------------------------------------------------
1 | {
2 | "baseUrl": "http://localhost:3000",
3 | "fixturesFolder": false,
4 | "pluginsFile": false,
5 | "supportFile": false,
6 | "env": {
7 | "backend_url": "http://localhost:8080"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 |
2 | root = true
3 |
4 | [*]
5 | end_of_line = lf
6 | insert_final_newline = true
7 | trim_trailing_whitespace = true
8 | indent_style = space
9 |
10 | [*.{js,json,html,css}]
11 | charset = utf-8
12 | indent_size = 2
13 |
--------------------------------------------------------------------------------
/core/server/instance-id-generator.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | function generateInstanceId() {
4 | // from https://gist.github.com/gordonbrander/2230317
5 | return Math.random().toString(36).substr(2, 9)
6 | }
7 |
8 | module.exports = generateInstanceId
9 |
--------------------------------------------------------------------------------
/services/gitter/gitter.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 |
5 | t.create('on gitter').get('/nwjs/nw.js.json').expectBadge({
6 | label: 'chat',
7 | message: 'on gitter',
8 | })
9 |
--------------------------------------------------------------------------------
/services/node/testUtils/packageJsonTemplate.json:
--------------------------------------------------------------------------------
1 | {
2 | "engines": {
3 | "node": ">= 0.4.0"
4 | },
5 | "maintainers": [
6 | {
7 | "name": "jaredhanson",
8 | "email": "jaredhanson@gmail.com"
9 | }
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/core/server/error-pages/500.html:
--------------------------------------------------------------------------------
1 |
A server error occurred
2 |
3 | I have nothing to offer for this request
4 | … but blood, toil, tears and sweat.
5 |
6 | And trying again later.
7 |
--------------------------------------------------------------------------------
/services/github/auth/is-valid-token.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | // This is only used by the TokenProviders, though probably the acceptor
4 | // should use it too.
5 |
6 | const isValidToken = t => /^[0-9a-f]{40}$/.test(t)
7 |
8 | module.exports = isValidToken
9 |
--------------------------------------------------------------------------------
/services/nexus/nexus-version.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | function isSnapshotVersion(version) {
4 | const pattern = /(\d+\.)*\d-SNAPSHOT/
5 | return version && version.match(pattern)
6 | }
7 |
8 | module.exports = {
9 | isSnapshotVersion,
10 | }
11 |
--------------------------------------------------------------------------------
/frontend/enzyme-conf.spec.js:
--------------------------------------------------------------------------------
1 | import Enzyme from 'enzyme'
2 | import Adapter from 'enzyme-adapter-react-16'
3 | import chai from 'chai'
4 | import chaiEnzyme from 'chai-enzyme'
5 |
6 | Enzyme.configure({ adapter: new Adapter() })
7 |
8 | chai.use(chaiEnzyme())
9 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | package.json
2 | package-lock.json
3 | /__snapshots__
4 | /.next
5 | /.cache
6 | /api-docs
7 | /build
8 | /public
9 | /coverage
10 | private/*.json
11 | /.nyc_output
12 | analytics.json
13 | supported-features.json
14 | service-definitions.yml
15 |
--------------------------------------------------------------------------------
/config/test.yml:
--------------------------------------------------------------------------------
1 | public:
2 | bind:
3 | address: 'localhost'
4 | port: 1111
5 |
6 | rateLimit: false
7 |
8 | redirectUrl: 'http://frontend.example.test'
9 |
10 | rasterUrl: 'http://raster.example.test'
11 |
12 | handleInternalErrors: false
13 |
--------------------------------------------------------------------------------
/.nycrc-frontend.json:
--------------------------------------------------------------------------------
1 | {
2 | "reporter": ["lcov"],
3 | "all": false,
4 | "silent": true,
5 | "clean": false,
6 | "sourceMap": false,
7 | "instrument": false,
8 | "include": ["frontend/**/*.js"],
9 | "exclude": ["**/*.spec.js", "**/mocha-*.js"]
10 | }
11 |
--------------------------------------------------------------------------------
/core/base-service/to-array.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | module.exports = function toArray(val) {
4 | if (val === undefined) {
5 | return []
6 | } else if (Object(val) instanceof Array) {
7 | return val
8 | } else {
9 | return [val]
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/.github/workflows/auto-approve.yml:
--------------------------------------------------------------------------------
1 | name: Auto approve
2 | on: pull_request
3 |
4 | jobs:
5 | build:
6 | runs-on: ubuntu-latest
7 | steps:
8 | - uses: chris48s/approve-bot@1.0.0
9 | with:
10 | github-token: '${{ secrets.GITHUB_TOKEN }}'
11 |
--------------------------------------------------------------------------------
/services/wordpress/wordpress-platform-redirect.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 |
5 | t.create('Plugin Tested WP Version (Alias)')
6 | .get('/akismet.svg')
7 | .expectRedirect('/wordpress/plugin/tested/akismet.svg')
8 |
--------------------------------------------------------------------------------
/services/response-fixtures.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const invalidJSONString = '{{{{{invalid json}}'
4 |
5 | module.exports = {
6 | invalidJSON: () => [
7 | 200,
8 | invalidJSONString,
9 | { 'Content-Type': 'application/json' },
10 | ],
11 | invalidJSONString,
12 | }
13 |
--------------------------------------------------------------------------------
/services/tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const createServiceTester = require('../core/service-test-runner/create-service-tester')
4 | const ServiceTester = require('../core/service-test-runner/service-tester')
5 |
6 | module.exports = {
7 | createServiceTester,
8 | ServiceTester,
9 | }
10 |
--------------------------------------------------------------------------------
/services/bstats/bstats-players.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isMetric } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('Players').get('/1.json').expectBadge({
7 | label: 'players',
8 | message: isMetric,
9 | })
10 |
--------------------------------------------------------------------------------
/services/bstats/bstats-servers.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isMetric } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('Servers').get('/1.json').expectBadge({
7 | label: 'servers',
8 | message: isMetric,
9 | })
10 |
--------------------------------------------------------------------------------
/services/deprecation-helpers.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { Deprecated } = require('.')
4 |
5 | function enforceDeprecation(effectiveDate) {
6 | if (Date.now() >= effectiveDate.getTime()) {
7 | throw new Deprecated()
8 | }
9 | }
10 |
11 | module.exports = {
12 | enforceDeprecation,
13 | }
14 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "type": "node",
6 | "request": "attach",
7 | "name": "Node: Nodemon",
8 | "processId": "${command:PickProcess}",
9 | "restart": true,
10 | "protocol": "inspector"
11 | }
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/core/base-service/loader-test-fixtures/invalid-mixed.fixture.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const BaseJsonService = require('../base-json')
4 |
5 | class BadBaseService {}
6 | class GoodService extends BaseJsonService {}
7 | class BadService extends BadBaseService {}
8 |
9 | module.exports = [GoodService, BadService]
10 |
--------------------------------------------------------------------------------
/services/nsp/nsp.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { deprecatedService } = require('..')
4 |
5 | module.exports = deprecatedService({
6 | route: {
7 | base: 'nsp/npm',
8 | pattern: ':various*',
9 | },
10 | label: 'nsp',
11 | category: 'other',
12 | dateAdded: new Date('2018-12-13'),
13 | })
14 |
--------------------------------------------------------------------------------
/frontend/lib/supported-features.ts:
--------------------------------------------------------------------------------
1 | import supportedFeatures from '../../supported-features.json'
2 |
3 | export const shieldsLogos = supportedFeatures.shieldsLogos as string[]
4 | export const simpleIcons = supportedFeatures.simpleIcons as string[]
5 | export const advertisedStyles = supportedFeatures.advertisedStyles as string[]
6 |
--------------------------------------------------------------------------------
/services/security-headers/security-headers.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 |
5 | t.create('grade of http://shields.io')
6 | .get('/security-headers.json?url=https://shields.io')
7 | .expectBadge({ label: 'security headers', message: 'F', color: 'red' })
8 |
--------------------------------------------------------------------------------
/services/dockbit/dockbit.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { deprecatedService } = require('..')
4 |
5 | module.exports = deprecatedService({
6 | category: 'build',
7 | route: {
8 | base: 'dockbit',
9 | pattern: ':various+',
10 | },
11 | label: 'dockbit',
12 | dateAdded: new Date('2017-12-31'),
13 | })
14 |
--------------------------------------------------------------------------------
/services/cauditor/cauditor.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { deprecatedService } = require('..')
4 |
5 | module.exports = deprecatedService({
6 | category: 'other',
7 | route: {
8 | base: 'cauditor',
9 | pattern: ':various*',
10 | },
11 | label: 'cauditor',
12 | dateAdded: new Date('2018-02-15'),
13 | })
14 |
--------------------------------------------------------------------------------
/services/libscore/libscore.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { deprecatedService } = require('..')
4 |
5 | module.exports = deprecatedService({
6 | category: 'rating',
7 | route: {
8 | base: 'libscore/s',
9 | pattern: ':various+',
10 | },
11 | label: 'libscore',
12 | dateAdded: new Date('2018-09-22'),
13 | })
14 |
--------------------------------------------------------------------------------
/services/bithound/bithound.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { deprecatedService } = require('..')
4 |
5 | module.exports = deprecatedService({
6 | category: 'dependencies',
7 | route: {
8 | base: 'bithound',
9 | pattern: ':various*',
10 | },
11 | label: 'bithound',
12 | dateAdded: new Date('2018-07-08'),
13 | })
14 |
--------------------------------------------------------------------------------
/services/endpoint/endpoint-redirect.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { redirector } = require('..')
4 |
5 | module.exports = redirector({
6 | category: 'other',
7 | route: {
8 | base: 'badge/endpoint',
9 | pattern: '',
10 | },
11 | transformPath: () => '/endpoint',
12 | dateAdded: new Date('2019-02-19'),
13 | })
14 |
--------------------------------------------------------------------------------
/services/magnumci/magnumci.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { deprecatedService } = require('..')
4 |
5 | module.exports = deprecatedService({
6 | category: 'build',
7 | route: {
8 | base: 'magnumci/ci',
9 | pattern: ':various+',
10 | },
11 | label: 'magnum ci',
12 | dateAdded: new Date('2018-07-08'),
13 | })
14 |
--------------------------------------------------------------------------------
/services/gemnasium/gemnasium.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { deprecatedService } = require('..')
4 |
5 | module.exports = deprecatedService({
6 | category: 'dependencies',
7 | route: {
8 | base: 'gemnasium',
9 | pattern: ':various+',
10 | },
11 | label: 'gemnasium',
12 | dateAdded: new Date('2018-05-15'),
13 | })
14 |
--------------------------------------------------------------------------------
/services/imagelayers/imagelayers.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { deprecatedService } = require('..')
4 |
5 | module.exports = deprecatedService({
6 | category: 'size',
7 | route: {
8 | base: 'imagelayers',
9 | pattern: ':various+',
10 | },
11 | label: 'imagelayers',
12 | dateAdded: new Date('2018-11-18'),
13 | })
14 |
--------------------------------------------------------------------------------
/services/waffle/waffle-label.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { deprecatedService } = require('..')
4 |
5 | module.exports = deprecatedService({
6 | route: {
7 | base: 'waffle/label',
8 | pattern: ':various*',
9 | },
10 | label: 'waffle',
11 | category: 'issue-tracking',
12 | dateAdded: new Date('2019-05-21'),
13 | })
14 |
--------------------------------------------------------------------------------
/badge-maker/index.d.ts:
--------------------------------------------------------------------------------
1 | interface Format {
2 | label?: string
3 | message: string
4 | labelColor?: string
5 | color?: string
6 | style?: 'plastic' | 'flat' | 'flat-square' | 'for-the-badge' | 'social'
7 | }
8 |
9 | export declare class ValidationError extends Error {}
10 |
11 | export declare function makeBadge(format: Format): string
12 |
--------------------------------------------------------------------------------
/services/issuestats/issuestats.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { deprecatedService } = require('..')
4 |
5 | module.exports = deprecatedService({
6 | category: 'issue-tracking',
7 | route: {
8 | base: 'issuestats',
9 | format: '(?:.*?)',
10 | },
11 | label: 'issue stats',
12 | dateAdded: new Date('2018-09-01'),
13 | })
14 |
--------------------------------------------------------------------------------
/services/leanpub/leanpub-book-summary.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { deprecatedService } = require('..')
4 |
5 | module.exports = deprecatedService({
6 | route: {
7 | base: 'leanpub/book',
8 | pattern: ':various+',
9 | },
10 | category: 'funding',
11 | label: 'leanpub',
12 | dateAdded: new Date('2019-12-30'),
13 | })
14 |
--------------------------------------------------------------------------------
/services/versioneye/versioneye.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { deprecatedService } = require('..')
4 |
5 | module.exports = deprecatedService({
6 | category: 'downloads',
7 | route: {
8 | base: 'versioneye/d',
9 | pattern: ':various+',
10 | },
11 | label: 'versioneye',
12 | dateAdded: new Date('2018-08-20'),
13 | })
14 |
--------------------------------------------------------------------------------
/services/coverity/coverity-on-demand.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { deprecatedService } = require('..')
4 |
5 | module.exports = deprecatedService({
6 | route: {
7 | base: 'coverity/ondemand',
8 | pattern: ':various+',
9 | },
10 | label: 'coverity',
11 | category: 'analysis',
12 | dateAdded: new Date('2018-12-18'),
13 | })
14 |
--------------------------------------------------------------------------------
/services/dotnetstatus/dotnetstatus.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { deprecatedService } = require('..')
4 |
5 | module.exports = deprecatedService({
6 | category: 'dependencies',
7 | route: {
8 | base: 'dotnetstatus',
9 | pattern: ':various+',
10 | },
11 | label: 'dotnet status',
12 | dateAdded: new Date('2018-04-01'),
13 | })
14 |
--------------------------------------------------------------------------------
/services/gratipay/gratipay.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = (module.exports = new ServiceTester({
6 | id: 'gratipay',
7 | title: 'Gratipay',
8 | }))
9 |
10 | t.create('Receiving').get('/Gratipay.json').expectBadge({
11 | label: 'gratipay',
12 | message: 'no longer available',
13 | })
14 |
--------------------------------------------------------------------------------
/services/jitpack/jitpack-downloads.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { deprecatedService } = require('..')
4 |
5 | module.exports = deprecatedService({
6 | route: {
7 | base: 'jitpack',
8 | pattern: ':interval(dw|dm)/:various*',
9 | },
10 | label: 'jitpack',
11 | category: 'downloads',
12 | dateAdded: new Date('2020-04-05'),
13 | })
14 |
--------------------------------------------------------------------------------
/services/php-eye/php-eye-hhvm.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { deprecatedService } = require('..')
4 |
5 | module.exports = [
6 | deprecatedService({
7 | category: 'platform-support',
8 | label: 'hhvm',
9 | route: {
10 | base: 'hhvm',
11 | pattern: ':various*',
12 | },
13 | dateAdded: new Date('2018-04-20'),
14 | }),
15 | ]
16 |
--------------------------------------------------------------------------------
/services/cocoapods/cocoapods-apps.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { deprecatedService } = require('..')
4 |
5 | module.exports = deprecatedService({
6 | name: 'CocoapodsApps',
7 | category: 'other',
8 | route: {
9 | base: 'cocoapods',
10 | pattern: ':interval(aw|at)/:spec',
11 | },
12 | label: 'apps',
13 | dateAdded: new Date('2018-01-06'),
14 | })
15 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/4_Feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 💡 Feature Request
3 | about: Ideas for other new features or improvements
4 | ---
5 |
6 | :clipboard: **Description**
7 |
8 |
9 |
10 |
12 |
--------------------------------------------------------------------------------
/frontend/types/mapbox__react-click-to-select/index.d.ts:
--------------------------------------------------------------------------------
1 | declare module '@mapbox/react-click-to-select' {
2 | import * as React from 'react'
3 |
4 | export type ContainerElementType = 'span' | 'div'
5 |
6 | export interface Props {
7 | containerElement?: ContainerElementType
8 | }
9 |
10 | export default class ClickToSelect extends React.Component {}
11 | }
12 |
--------------------------------------------------------------------------------
/services/dub/dub-license.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 |
5 | t.create('license (valid)')
6 | .get('/vibe-d.json')
7 | .expectBadge({ label: 'license', message: 'MIT' })
8 |
9 | t.create('license (not found)')
10 | .get('/not-a-package.json')
11 | .expectBadge({ label: 'license', message: 'not found' })
12 |
--------------------------------------------------------------------------------
/services/php-eye/php-eye-php-version.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { deprecatedService } = require('..')
4 |
5 | module.exports = [
6 | deprecatedService({
7 | category: 'platform-support',
8 | label: 'php tested',
9 | route: {
10 | base: 'php-eye',
11 | pattern: ':various*',
12 | },
13 | dateAdded: new Date('2018-04-20'),
14 | }),
15 | ]
16 |
--------------------------------------------------------------------------------
/services/wordpress/wordpress-platform-redirect.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { redirector } = require('..')
4 |
5 | module.exports = redirector({
6 | category: 'platform-support',
7 | route: {
8 | base: 'wordpress/v',
9 | pattern: ':slug',
10 | },
11 | transformPath: ({ slug }) => `/wordpress/plugin/tested/${slug}`,
12 | dateAdded: new Date('2019-04-17'),
13 | })
14 |
--------------------------------------------------------------------------------
/services/cocoapods/cocoapods-downloads.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { deprecatedService } = require('..')
4 |
5 | module.exports = deprecatedService({
6 | name: 'CocoapodsDownloads',
7 | category: 'downloads',
8 | route: {
9 | base: 'cocoapods',
10 | pattern: ':interval(dm|dw|dt)/:spec',
11 | },
12 | label: 'downloads',
13 | dateAdded: new Date('2018-01-06'),
14 | })
15 |
--------------------------------------------------------------------------------
/services/magnumci/magnumci.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = new ServiceTester({ id: 'magnumci', title: 'Magnum CI' })
6 | module.exports = t
7 |
8 | t.create('no longer available')
9 | .get('/ci/96ffb83fa700f069024921b0702e76ff.json')
10 | .expectBadge({
11 | label: 'magnum ci',
12 | message: 'no longer available',
13 | })
14 |
--------------------------------------------------------------------------------
/lib/svg-helpers.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { test, given } = require('sazerac')
4 | const { svg2base64 } = require('./svg-helpers')
5 |
6 | describe('SVG helpers', function () {
7 | test(svg2base64, () => {
8 | given('').expect(
9 | 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciLz4='
10 | )
11 | })
12 | })
13 |
--------------------------------------------------------------------------------
/services/cpan/cpan-license.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 |
5 | t.create('license (valid)').get('/Config-Augeas.json').expectBadge({
6 | label: 'license',
7 | message: 'lgpl_2_1',
8 | })
9 |
10 | t.create('license (not found)').get('/not-a-package.json').expectBadge({
11 | label: 'cpan',
12 | message: 'not found',
13 | })
14 |
--------------------------------------------------------------------------------
/services/libscore/libscore.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = new ServiceTester({ id: 'libscore', title: 'libscore' })
6 | module.exports = t
7 |
8 | t.create('no longer available (previously usage statistics)')
9 | .get('/s/jQuery.json')
10 | .expectBadge({
11 | label: 'libscore',
12 | message: 'no longer available',
13 | })
14 |
--------------------------------------------------------------------------------
/core/base-service/loader-test-fixtures/valid-class.fixture.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const BaseJsonService = require('../base-json')
4 |
5 | class GoodService extends BaseJsonService {
6 | static get category() {
7 | return 'build'
8 | }
9 |
10 | static get route() {
11 | return {
12 | base: 'it/is',
13 | pattern: 'good',
14 | }
15 | }
16 | }
17 |
18 | module.exports = GoodService
19 |
--------------------------------------------------------------------------------
/services/cauditor/cauditor.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = (module.exports = new ServiceTester({
6 | id: 'cauditor',
7 | title: 'Cauditor',
8 | }))
9 |
10 | t.create('no longer available')
11 | .get('/mi/matthiasmullie/scrapbook/master.json')
12 | .expectBadge({
13 | label: 'cauditor',
14 | message: 'no longer available',
15 | })
16 |
--------------------------------------------------------------------------------
/services/symfony/sensiolabs-redirect.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = (module.exports = new ServiceTester({
6 | id: 'sensiolabs',
7 | title: 'SensioLabs',
8 | }))
9 |
10 | t.create('sensiolabs insight')
11 | .get('/i/45afb680-d4e6-4e66-93ea-bcfa79eb8a87.svg')
12 | .expectRedirect('/symfony/i/grade/45afb680-d4e6-4e66-93ea-bcfa79eb8a87.svg')
13 |
--------------------------------------------------------------------------------
/config/local-shields-io-production.template.yml:
--------------------------------------------------------------------------------
1 | private:
2 | # These are the keys which are set on the production servers.
3 | gh_client_id: ...
4 | gh_client_secret: ...
5 | redis_url: ...
6 | sentry_dsn: ...
7 | shields_secret: ...
8 | sl_insight_userUuid: ...
9 | sl_insight_apiToken: ...
10 | twitch_client_id: ...
11 | twitch_client_secret: ...
12 | wheelmap_token: ...
13 | youtube_api_key: ...
14 |
--------------------------------------------------------------------------------
/jsdoc.json:
--------------------------------------------------------------------------------
1 | {
2 | "source": {
3 | "exclude": [
4 | "__snapshots__",
5 | "build",
6 | "coverage",
7 | "logo",
8 | "node_modules",
9 | "private",
10 | "public"
11 | ]
12 | },
13 | "plugins": ["plugins/markdown"],
14 | "opts": {
15 | "destination": "api-docs/",
16 | "readme": "README.md",
17 | "recurse": true,
18 | "tutorials": "doc/"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/services/versioneye/versioneye.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = new ServiceTester({ id: 'versioneye', title: 'VersionEye' })
6 | module.exports = t
7 |
8 | t.create('no longer available (previously dependencies status)')
9 | .get('/d/ruby/rails.json')
10 | .expectBadge({
11 | label: 'versioneye',
12 | message: 'no longer available',
13 | })
14 |
--------------------------------------------------------------------------------
/services/gemnasium/gemnasium.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = (module.exports = new ServiceTester({
6 | id: 'gemnasium',
7 | title: 'gemnasium',
8 | }))
9 |
10 | t.create('no longer available (previously dependencies)')
11 | .get('/mathiasbynens/he.json')
12 | .expectBadge({
13 | label: 'gemnasium',
14 | message: 'no longer available',
15 | })
16 |
--------------------------------------------------------------------------------
/services/snap-ci/snap-ci.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = new ServiceTester({ id: 'snap-ci', title: 'Snap CI' })
6 | module.exports = t
7 |
8 | t.create('no longer available (previously build state)')
9 | .get('/snap-ci/ThoughtWorksStudios/eb_deployer/master.json')
10 | .expectBadge({
11 | label: 'snap ci',
12 | message: 'no longer available',
13 | })
14 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "include": ["frontend/**/*"],
3 | "exclude": [],
4 | "compilerOptions": {
5 | "target": "esnext",
6 | "module": "commonjs",
7 | "declaration": true,
8 | "outDir": "unused_ts_output",
9 | "strict": true,
10 | "allowSyntheticDefaultImports": true,
11 | "esModuleInterop": true,
12 | "jsx": "react",
13 | "typeRoots": ["node_modules/@types", "frontend/types"]
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/services/waffle/waffle-label-redirect.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = (module.exports = new ServiceTester({
6 | id: 'WaffleLabelRedirect',
7 | title: 'WaffleLabelRedirect',
8 | pathPrefix: '/waffle/label',
9 | }))
10 |
11 | t.create('waffle label redirect')
12 | .get('/waffleio/waffle.io.svg')
13 | .expectRedirect('/waffle/label/waffleio/waffle.io/ready.svg')
14 |
--------------------------------------------------------------------------------
/services/amo/amo-users.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isMetric } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('Users')
7 | .get('/IndieGala-Helper.json')
8 | .expectBadge({ label: 'users', message: isMetric })
9 |
10 | t.create('Users (not found)')
11 | .get('/not-a-real-plugin.json')
12 | .expectBadge({ label: 'users', message: 'not found' })
13 |
--------------------------------------------------------------------------------
/services/lgtm/lgtm-test-helpers.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const data = {
4 | alerts: 0,
5 | languages: [
6 | { lang: 'cpp', grade: 'A+' },
7 | { lang: 'javascript', grade: 'A' },
8 | { lang: 'java', grade: 'B' },
9 | { lang: 'python', grade: 'C' },
10 | { lang: 'csharp', grade: 'D' },
11 | { lang: 'other', grade: 'E' },
12 | { lang: 'foo' },
13 | ],
14 | }
15 |
16 | module.exports = {
17 | data,
18 | }
19 |
--------------------------------------------------------------------------------
/frontend/components/donate.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from 'styled-components'
3 |
4 | const Donate = styled.div`
5 | padding: 25px 50px;
6 | `
7 |
8 | export default function DonateBox(): JSX.Element {
9 | return (
10 |
11 | Love Shields? Please consider{' '}
12 | donating to sustain our
13 | activities
14 |
15 | )
16 | }
17 |
--------------------------------------------------------------------------------
/logo/stackexchange.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/services/crates/crates-version.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isSemver } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('version')
7 | .get('/libc.json')
8 | .expectBadge({ label: 'crates.io', message: isSemver })
9 |
10 | t.create('version (not found)')
11 | .get('/not-a-real-package.json')
12 | .expectBadge({ label: 'crates.io', message: 'not found' })
13 |
--------------------------------------------------------------------------------
/services/endpoint/endpoint-redirect.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = (module.exports = new ServiceTester({
6 | id: 'EndpointRedirect',
7 | title: 'EndpointRedirect',
8 | pathPrefix: '/badge/endpoint',
9 | }))
10 |
11 | t.create('Build: default branch')
12 | .get('.svg?url=https://example.com/badge.json')
13 | .expectRedirect('/endpoint.svg?url=https://example.com/badge.json')
14 |
--------------------------------------------------------------------------------
/services/jitpack/jitpack-version-redirector.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = (module.exports = new ServiceTester({
6 | id: 'JitpackVersionRedirect',
7 | title: 'JitpackVersionRedirect',
8 | pathPrefix: '/jitpack/v',
9 | }))
10 |
11 | t.create('jitpack version redirect')
12 | .get('/jitpack/maven-simple.svg')
13 | .expectRedirect('/jitpack/v/github/jitpack/maven-simple.svg')
14 |
--------------------------------------------------------------------------------
/services/waffle/waffle-label.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = (module.exports = new ServiceTester({
6 | id: 'Waffle',
7 | title: 'WaffleLabel',
8 | pathPrefix: '/waffle/label',
9 | }))
10 |
11 | t.create('no longer available')
12 | .get('/ritwickdey/vscode-live-server/bug.json')
13 | .expectBadge({
14 | label: 'waffle',
15 | message: 'no longer available',
16 | })
17 |
--------------------------------------------------------------------------------
/scripts/export-service-definitions-cli.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const yaml = require('js-yaml')
4 | const { collectDefinitions } = require('../core/base-service/loader')
5 |
6 | const definitions = collectDefinitions()
7 |
8 | // Omit undefined
9 | // https://github.com/nodeca/js-yaml/issues/356#issuecomment-312430599
10 | const cleaned = JSON.parse(JSON.stringify(definitions))
11 |
12 | process.stdout.write(yaml.safeDump(cleaned, { flowLevel: 5 }))
13 |
--------------------------------------------------------------------------------
/services/twitter/twitter-redirect.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = (module.exports = new ServiceTester({
6 | id: 'TwitterUrlRedirect',
7 | title: 'TwitterUrlRedirect',
8 | pathPrefix: '/twitter/url',
9 | }))
10 |
11 | t.create('twitter')
12 | .get('/https/shields.io.svg')
13 | .expectRedirect(
14 | `/twitter/url.svg?url=${encodeURIComponent('https://shields.io')}`
15 | )
16 |
--------------------------------------------------------------------------------
/services/jitpack/jitpack-version-redirector.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { redirector } = require('..')
4 |
5 | module.exports = [
6 | redirector({
7 | category: 'version',
8 | route: {
9 | base: 'jitpack/v',
10 | pattern: ':groupId/:artifactId',
11 | },
12 | transformPath: ({ groupId, artifactId }) =>
13 | `/jitpack/v/github/${groupId}/${artifactId}`,
14 | dateAdded: new Date('2019-03-31'),
15 | }),
16 | ]
17 |
--------------------------------------------------------------------------------
/services/spiget/spiget-downloads.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isMetric } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('EssentialsX (id 9089)').get('/9089.json').expectBadge({
7 | label: 'downloads',
8 | message: isMetric,
9 | })
10 |
11 | t.create('Invalid Resource (id 1)').get('/1.json').expectBadge({
12 | label: 'downloads',
13 | message: 'not found',
14 | })
15 |
--------------------------------------------------------------------------------
/config/local.template.yml:
--------------------------------------------------------------------------------
1 | # Copy this file to `config/local.yml` and fill it in! It will be gitignored.
2 |
3 | private:
4 | # The possible values are documented in `doc/server-secrets.md`. Note that
5 | # you can also set these values through environment variables, which may be
6 | # preferable for self hosting.
7 | gh_token: '...'
8 | twitch_client_id: '...'
9 | twitch_client_secret: '...'
10 | wheelmap_token: '...'
11 | youtube_api_key: '...'
12 |
--------------------------------------------------------------------------------
/services/conda/conda-license.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 |
5 | t.create('license')
6 | .get('/l/conda-forge/setuptools.json')
7 | .expectBadge({ label: 'license', message: 'MIT', color: 'green' })
8 |
9 | t.create('license (invalid)')
10 | .get('/l/conda-forge/some-bogus-package-that-never-exists.json')
11 | .expectBadge({ label: 'license', message: 'not found', color: 'red' })
12 |
--------------------------------------------------------------------------------
/services/dotnetstatus/dotnetstatus.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = (module.exports = new ServiceTester({
6 | id: 'dotnetstatus',
7 | title: 'dotnet-status',
8 | }))
9 |
10 | t.create('no longer available (previously get package status)')
11 | .get('/gh/jaredcnance/dotnet-status/API.json')
12 | .expectBadge({
13 | label: 'dotnet status',
14 | message: 'no longer available',
15 | })
16 |
--------------------------------------------------------------------------------
/services/gem/gem-owner.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('users (valid)')
7 | .get('/raphink.json')
8 | .expectBadge({
9 | label: 'gems',
10 | message: Joi.string().regex(/^[0-9]+$/),
11 | })
12 |
13 | t.create('users (not found)')
14 | .get('/not-a-package.json')
15 | .expectBadge({ label: 'gems', message: 'not found' })
16 |
--------------------------------------------------------------------------------
/services/github/github-labels.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 |
5 | t.create('labels').get('/badges/shields/bug.json').expectBadge({
6 | message: 'bug',
7 | color: '#e11d21',
8 | })
9 |
10 | t.create('labels (repo or label not found)')
11 | .get('/badges/shields/somenonexistentlabelthatwouldneverexist.json')
12 | .expectBadge({
13 | message: 'repo or label not found',
14 | })
15 |
--------------------------------------------------------------------------------
/services/sonar/sonar-generic.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isMetric } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('Security Rating')
7 | .timeout(10000)
8 | .get(
9 | '/security_rating/com.luckybox:luckybox.json?server=https://sonarcloud.io'
10 | )
11 | .expectBadge({
12 | label: 'security rating',
13 | message: isMetric,
14 | color: 'blue',
15 | })
16 |
--------------------------------------------------------------------------------
/services/github/github-followers.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isMetric } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('Followers').get('/webcaetano.json').expectBadge({
7 | label: 'followers',
8 | message: isMetric,
9 | })
10 |
11 | t.create('Followers (user not found)').get('/PyvesB2.json').expectBadge({
12 | label: 'followers',
13 | message: 'user not found',
14 | })
15 |
--------------------------------------------------------------------------------
/services/github/github-license.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { test, given } = require('sazerac')
4 | const GithubLicense = require('./github-license.service')
5 |
6 | test(GithubLicense.render, () => {
7 | given({ license: undefined }).expect({ message: 'not specified' })
8 | given({ license: 'NOASSERTION' }).expect({
9 | message: 'not identifiable by github',
10 | })
11 | given({ license: 'MIT' }).expect({ message: 'MIT', color: 'green' })
12 | })
13 |
--------------------------------------------------------------------------------
/services/liberapay/liberapay-patrons.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isMetric } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('Patrons (valid)').get('/Liberapay.json').expectBadge({
7 | label: 'patrons',
8 | message: isMetric,
9 | })
10 |
11 | t.create('Patrons (not found)')
12 | .get('/does-not-exist.json')
13 | .expectBadge({ label: 'liberapay', message: 'not found' })
14 |
--------------------------------------------------------------------------------
/services/appveyor/appveyor-build-redirect.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { redirector } = require('..')
4 |
5 | module.exports = [
6 | redirector({
7 | category: 'build',
8 | route: {
9 | base: 'appveyor/ci',
10 | pattern: ':user/:repo/:branch*',
11 | },
12 | transformPath: ({ user, repo, branch }) =>
13 | `/appveyor/build/${user}/${repo}${branch ? `/${branch}` : ''}`,
14 | dateAdded: new Date('2019-12-10'),
15 | }),
16 | ]
17 |
--------------------------------------------------------------------------------
/services/cdnjs/cdnjs.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isVPlusTripleDottedVersion } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('cdnjs (valid)').get('/jquery.json').expectBadge({
7 | label: 'cdnjs',
8 | message: isVPlusTripleDottedVersion,
9 | })
10 |
11 | t.create('cdnjs (not found)')
12 | .get('/not-a-library.json')
13 | .expectBadge({ label: 'cdnjs', message: 'not found' })
14 |
--------------------------------------------------------------------------------
/logo/telegram.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/services/puppetforge/puppetforge-user-module-count.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isMetric } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('modules by user').get('/camptocamp.json').expectBadge({
7 | label: 'modules',
8 | message: isMetric,
9 | })
10 |
11 | t.create('modules by user').get('/not-a-real-user.json').expectBadge({
12 | label: 'modules',
13 | message: 'not found',
14 | })
15 |
--------------------------------------------------------------------------------
/services/bit/bit-components.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 | const { isMetric } = require('../test-validators')
5 |
6 | t.create('collection (valid)').get('/ramda/ramda.json').expectBadge({
7 | label: 'components',
8 | message: isMetric,
9 | })
10 |
11 | t.create('collection (valid)')
12 | .get('/bit/no-collection-test.json')
13 | .expectBadge({ label: 'components', message: 'collection not found' })
14 |
--------------------------------------------------------------------------------
/services/clojars/clojars-downloads.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isMetric } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('clojars downloads (valid)').get('/prismic.json').expectBadge({
7 | label: 'downloads',
8 | message: isMetric,
9 | })
10 |
11 | t.create('clojars downloads (not found)')
12 | .get('/not-a-package.json')
13 | .expectBadge({ label: 'downloads', message: 'not found' })
14 |
--------------------------------------------------------------------------------
/services/puppetforge/puppetforge-user-release-count.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isMetric } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('releases by user').get('/camptocamp.json').expectBadge({
7 | label: 'releases',
8 | message: isMetric,
9 | })
10 |
11 | t.create('releases by user').get('/not-a-real-user.json').expectBadge({
12 | label: 'releases',
13 | message: 'not found',
14 | })
15 |
--------------------------------------------------------------------------------
/frontend/lib/redirect-legacy-routes.ts:
--------------------------------------------------------------------------------
1 | import { navigate } from 'gatsby'
2 |
3 | export default function redirectLegacyRoutes(): void {
4 | const { hash } = window.location
5 | if (hash && hash.startsWith('#/examples/')) {
6 | const category = hash.replace('#/examples/', '')
7 | navigate(`category/${category}`, {
8 | replace: true,
9 | })
10 | } else if (hash === '#/endpoint') {
11 | navigate('endpoint', {
12 | replace: true,
13 | })
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/services/gem/gem-version.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isVPlusDottedVersionAtLeastOne } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('version (valid)').get('/formatador.json').expectBadge({
7 | label: 'gem',
8 | message: isVPlusDottedVersionAtLeastOne,
9 | })
10 |
11 | t.create('version (not found)')
12 | .get('/not-a-package.json')
13 | .expectBadge({ label: 'gem', message: 'not found' })
14 |
--------------------------------------------------------------------------------
/services/spack/spack.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isVPlusDottedVersionAtLeastOne } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('version (valid)').get('/adios2.json').expectBadge({
7 | label: 'spack',
8 | message: isVPlusDottedVersionAtLeastOne,
9 | })
10 |
11 | t.create('version (not found)')
12 | .get('/not-a-package.json')
13 | .expectBadge({ label: 'spack', message: 'package not found' })
14 |
--------------------------------------------------------------------------------
/services/codeclimate/codeclimate-analysis-redirector.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = (module.exports = new ServiceTester({
6 | id: 'CodeclimateCoverageRedirector',
7 | title: 'Code Climate Coverage Redirector',
8 | pathPrefix: '/codeclimate',
9 | }))
10 |
11 | t.create('Maintainability letter alias')
12 | .get('/maintainability-letter/jekyll/jekyll.svg')
13 | .expectRedirect('/codeclimate/maintainability/jekyll/jekyll.svg')
14 |
--------------------------------------------------------------------------------
/services/jira/jira-sprint-redirect.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = (module.exports = new ServiceTester({
6 | id: 'JiraSprintRedirect',
7 | title: 'JiraSprintRedirect',
8 | pathPrefix: '/jira/sprint',
9 | }))
10 |
11 | t.create('jira sprint')
12 | .get('/https/jira.spring.io/94.svg')
13 | .expectRedirect(
14 | `/jira/sprint/94.svg?baseUrl=${encodeURIComponent(
15 | 'https://jira.spring.io'
16 | )}`
17 | )
18 |
--------------------------------------------------------------------------------
/services/cocoapods/cocoapods-version.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isVPlusDottedVersionAtLeastOne } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('version (valid)').get('/AFNetworking.json').expectBadge({
7 | label: 'pod',
8 | message: isVPlusDottedVersionAtLeastOne,
9 | })
10 |
11 | t.create('version (not found)')
12 | .get('/not-a-package.json')
13 | .expectBadge({ label: 'pod', message: 'not found' })
14 |
--------------------------------------------------------------------------------
/services/liberapay/liberapay-goal.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isIntegerPercentage } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('Goal Progress (valid)').get('/Liberapay.json').expectBadge({
7 | label: 'goal progress',
8 | message: isIntegerPercentage,
9 | })
10 |
11 | t.create('Goal Progress (not found)')
12 | .get('/does-not-exist.json')
13 | .expectBadge({ label: 'liberapay', message: 'not found' })
14 |
--------------------------------------------------------------------------------
/services/teamcity/teamcity-test-helpers.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const user = 'admin'
4 | const pass = 'password'
5 | const host = 'mycompany.teamcity.com'
6 | const config = {
7 | public: {
8 | services: {
9 | teamcity: {
10 | authorizedOrigins: [`https://${host}`],
11 | },
12 | },
13 | },
14 | private: {
15 | teamcity_user: user,
16 | teamcity_pass: pass,
17 | },
18 | }
19 |
20 | module.exports = {
21 | user,
22 | pass,
23 | host,
24 | config,
25 | }
26 |
--------------------------------------------------------------------------------
/services/amo/amo-version.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isVPlusDottedVersionAtLeastOne } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('Version').get('/IndieGala-Helper.json').expectBadge({
7 | label: 'mozilla add-on',
8 | message: isVPlusDottedVersionAtLeastOne,
9 | })
10 |
11 | t.create('Version (not found)')
12 | .get('/not-a-real-plugin.json')
13 | .expectBadge({ label: 'mozilla add-on', message: 'not found' })
14 |
--------------------------------------------------------------------------------
/services/elm-package/elm-package.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isSemver } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('gets the package version of elm/core')
7 | .get('/elm/core.json')
8 | .expectBadge({ label: 'elm package', message: isSemver })
9 |
10 | t.create('invalid package name')
11 | .get('/elm-community/frodo-is-not-a-package.json')
12 | .expectBadge({ label: 'elm package', message: 'package not found' })
13 |
--------------------------------------------------------------------------------
/services/github/github-search.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isMetric } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('hit counter')
7 | .get('/badges/shields/async%20handle.json')
8 | .expectBadge({ label: 'async handle counter', message: isMetric })
9 |
10 | t.create('hit counter for nonexistent repo')
11 | .get('/badges/puppets/async%20handle.json')
12 | .expectBadge({ label: 'counter', message: 'repo not found' })
13 |
--------------------------------------------------------------------------------
/services/hackage/hackage-deps.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('hackage deps (valid)')
7 | .get('/lens.json')
8 | .expectBadge({
9 | label: 'dependencies',
10 | message: Joi.string().regex(/^(up to date|outdated)$/),
11 | })
12 |
13 | t.create('hackage deps (not found)')
14 | .get('/not-a-package.json')
15 | .expectBadge({ label: 'dependencies', message: 'not found' })
16 |
--------------------------------------------------------------------------------
/services/check-services.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const {
4 | checkNames,
5 | collectDefinitions,
6 | } = require('../core/base-service/loader')
7 |
8 | // When these tests fail, they will throw AssertionErrors. Wrapping them in an
9 | // `expect().not.to.throw()` makes the error output unreadable.
10 |
11 | it('Services have unique names', function () {
12 | this.timeout(30000)
13 | checkNames()
14 | })
15 |
16 | it('Can collect the service definitions', function () {
17 | collectDefinitions()
18 | })
19 |
--------------------------------------------------------------------------------
/services/chocolatey/chocolatey.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { createServiceFamily } = require('../nuget/nuget-v2-service-family')
4 |
5 | module.exports = createServiceFamily({
6 | defaultLabel: 'chocolatey',
7 | serviceBaseUrl: 'chocolatey',
8 | apiBaseUrl: 'https://www.chocolatey.org/api/v2',
9 | odataFormat: 'json',
10 | title: 'Chocolatey',
11 | examplePackageName: 'git',
12 | exampleVersion: '2.19.2',
13 | examplePrereleaseVersion: '2.19.2',
14 | exampleDownloadCount: 2.2e6,
15 | })
16 |
--------------------------------------------------------------------------------
/services/github/github-repo-size.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isFileSize } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('repository size').get('/badges/shields.json').expectBadge({
7 | label: 'repo size',
8 | message: isFileSize,
9 | })
10 |
11 | t.create('repository size (repo not found)')
12 | .get('/badges/helmets.json')
13 | .expectBadge({
14 | label: 'repo size',
15 | message: 'repo not found',
16 | })
17 |
--------------------------------------------------------------------------------
/services/netlify/netlify.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isBuildStatus } = require('../build-status')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('netlify (valid, no branch)')
7 | .get('/e6d5a4e0-dee1-4261-833e-2f47f509c68f.json')
8 | .expectBadge({
9 | label: 'netlify',
10 | message: isBuildStatus,
11 | })
12 |
13 | t.create('netlify (repo not found)')
14 | .get('/not-a-repo.json')
15 | .expectBadge({ label: 'netlify', message: 'not found' })
16 |
--------------------------------------------------------------------------------
/scripts/github_token_backup.fish:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env fish
2 | #
3 | # Back up the GitHub tokens from each production server.
4 | #
5 |
6 | if test (count $argv) -lt 1
7 | echo Usage: (basename (status -f)) shields_secret
8 | end
9 |
10 | set shields_secret $argv[1]
11 |
12 | function do_backup
13 | set server $argv[1]
14 | curl --insecure -u ":$shields_secret" "https://$server.servers.shields.io/\$github-auth/tokens" > "$server""_tokens.json"
15 | end
16 |
17 | for server in s0 s1 s2
18 | do_backup $server
19 | end
20 |
--------------------------------------------------------------------------------
/services/jira/jira-issue-redirect.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = (module.exports = new ServiceTester({
6 | id: 'JiraIssueRedirect',
7 | title: 'JiraIssueRedirect',
8 | pathPrefix: '/jira/issue',
9 | }))
10 |
11 | t.create('jira issue')
12 | .get('/https/issues.apache.org/jira/kafka-2896.svg')
13 | .expectRedirect(
14 | `/jira/issue/kafka-2896.svg?baseUrl=${encodeURIComponent(
15 | 'https://issues.apache.org/jira'
16 | )}`
17 | )
18 |
--------------------------------------------------------------------------------
/services/maven-metadata/maven-metadata-redirect.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { redirector } = require('..')
4 |
5 | module.exports = redirector({
6 | category: 'version',
7 | route: {
8 | base: 'maven-metadata/v',
9 | pattern: ':protocol(http|https)/:hostAndPath+',
10 | },
11 | transformPath: () => '/maven-metadata/v',
12 | transformQueryParams: ({ protocol, hostAndPath }) => ({
13 | metadataUrl: `${protocol}://${hostAndPath}`,
14 | }),
15 | dateAdded: new Date('2019-09-16'),
16 | })
17 |
--------------------------------------------------------------------------------
/services/sonar/sonar-quality-gate.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { test, given } = require('sazerac')
4 | const SonarQualityGate = require('./sonar-quality-gate.service')
5 |
6 | describe('SonarQualityGate', function () {
7 | test(SonarQualityGate.render, () => {
8 | given({ qualityState: 'OK' }).expect({
9 | message: 'passed',
10 | color: 'success',
11 | })
12 | given({ qualityState: 'ERROR' }).expect({
13 | message: 'failed',
14 | color: 'critical',
15 | })
16 | })
17 | })
18 |
--------------------------------------------------------------------------------
/services/repology/repology-repositories.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 | const { nonNegativeInteger } = require('../validators')
5 |
6 | t.create('Existing project').get('/starship.json').expectBadge({
7 | label: 'repositories',
8 | message: nonNegativeInteger,
9 | })
10 |
11 | t.create('Non-existent project')
12 | .get('/invalidprojectthatshouldnotexist.json')
13 | .expectBadge({
14 | label: 'repositories',
15 | message: '0',
16 | })
17 |
--------------------------------------------------------------------------------
/services/conda/conda-version.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isVPlusTripleDottedVersion } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('version').get('/v/conda-forge/zlib.json').expectBadge({
7 | label: 'conda|conda-forge',
8 | message: isVPlusTripleDottedVersion,
9 | })
10 |
11 | t.create('version (skip prefix)').get('/vn/conda-forge/zlib.json').expectBadge({
12 | label: 'conda-forge',
13 | message: isVPlusTripleDottedVersion,
14 | })
15 |
--------------------------------------------------------------------------------
/lib/server-secrets.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const fs = require('fs')
4 | const path = require('path')
5 | const config = require('config').util.toObject()
6 |
7 | const legacySecretsPath = path.join(__dirname, '..', 'private', 'secret.json')
8 | if (fs.existsSync(legacySecretsPath)) {
9 | console.error(
10 | `Legacy secrets file found at ${legacySecretsPath}. It should be deleted and secrets replaced with environment variables or config/local.yml`
11 | )
12 | process.exit(1)
13 | }
14 |
15 | module.exports = config.private
16 |
--------------------------------------------------------------------------------
/services/puppetforge/puppetforge-module-downloads.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isMetric } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('module downloads').get('/camptocamp/openssl.json').expectBadge({
7 | label: 'downloads',
8 | message: isMetric,
9 | })
10 |
11 | t.create('module downloads (not found)')
12 | .get('/notarealuser/notarealpackage.json')
13 | .expectBadge({
14 | label: 'downloads',
15 | message: 'not found',
16 | })
17 |
--------------------------------------------------------------------------------
/services/puppetforge/puppetforge-module-version.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isSemver } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('module version').get('/camptocamp/openssl.json').expectBadge({
7 | label: 'puppetforge',
8 | message: isSemver,
9 | })
10 |
11 | t.create('module version (not found)')
12 | .get('/notarealuser/notarealpackage.json')
13 | .expectBadge({
14 | label: 'puppetforge',
15 | message: 'not found',
16 | })
17 |
--------------------------------------------------------------------------------
/services/debug/debug.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('start time')
7 | .get('/starttime.json')
8 | .expectBadge({ label: 'start time', message: Joi.date().required() })
9 |
10 | t.create('Flip: first request')
11 | .get('/flip.json')
12 | .expectBadge({ label: 'flip', message: 'on' })
13 |
14 | t.create('Flip: second request')
15 | .get('/flip.json')
16 | .expectBadge({ label: 'flip', message: 'off' })
17 |
--------------------------------------------------------------------------------
/services/lgtm/lgtm-redirector.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = (module.exports = new ServiceTester({
6 | id: 'LgtmRedirect',
7 | title: 'LgtmRedirect',
8 | pathPrefix: '/lgtm',
9 | }))
10 |
11 | t.create('alerts')
12 | .get('/alerts/g/badges/shields.svg')
13 | .expectRedirect('/lgtm/alerts/github/badges/shields.svg')
14 |
15 | t.create('grade')
16 | .get('/grade/java/g/apache/cloudstack.svg')
17 | .expectRedirect('/lgtm/grade/java/github/apache/cloudstack.svg')
18 |
--------------------------------------------------------------------------------
/services/eclipse-marketplace/eclipse-marketplace-favorites.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('favorites count').get('/notepad4e.json').expectBadge({
7 | label: 'favorites',
8 | message: Joi.number().integer().positive(),
9 | })
10 |
11 | t.create('favorites for unknown solution')
12 | .get('/this-does-not-exist.json')
13 | .expectBadge({
14 | label: 'favorites',
15 | message: 'solution not found',
16 | })
17 |
--------------------------------------------------------------------------------
/services/luarocks/luarocks.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { test, given } = require('sazerac')
4 | const Luarocks = require('./luarocks.service')
5 |
6 | test(Luarocks.render, () => {
7 | given({ version: 'dev-1' }).expect({ message: 'dev-1', color: 'yellow' })
8 | given({ version: 'scm-1' }).expect({ message: 'scm-1', color: 'orange' })
9 | given({ version: 'cvs-1' }).expect({ message: 'cvs-1', color: 'orange' })
10 | given({ version: '0.1-1' }).expect({
11 | message: 'v0.1-1',
12 | color: 'brightgreen',
13 | })
14 | })
15 |
--------------------------------------------------------------------------------
/services/stackexchange/stackexchange-helpers.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { metric } = require('../text-formatters')
4 | const { floorCount: floorCountColor } = require('../color-formatters')
5 |
6 | module.exports = function renderQuestionsBadge({
7 | suffix,
8 | stackexchangesite,
9 | query,
10 | numValue,
11 | }) {
12 | const label = `${stackexchangesite} ${query} questions`
13 | return {
14 | label,
15 | message: `${metric(numValue)}${suffix}`,
16 | color: floorCountColor(numValue, 1000, 10000, 20000),
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/services/vaadin-directory/vaadin-directory-status.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('publish status of the component')
7 | .get('/vaadinvaadin-grid.json')
8 | .expectBadge({
9 | label: 'vaadin directory',
10 | message: Joi.equal('published', 'unpublished'),
11 | })
12 |
13 | t.create('not found').get('/does-not-exist.json').expectBadge({
14 | label: 'vaadin directory',
15 | message: 'not found',
16 | })
17 |
--------------------------------------------------------------------------------
/core/server/secret-is-valid.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const serverSecrets = require('../../lib/server-secrets')
4 |
5 | function constEq(a, b) {
6 | if (a.length !== b.length) {
7 | return false
8 | }
9 | let zero = 0
10 | for (let i = 0; i < a.length; i++) {
11 | zero |= a.charCodeAt(i) ^ b.charCodeAt(i)
12 | }
13 | return zero === 0
14 | }
15 |
16 | module.exports = function secretIsValid(secret = '') {
17 | return (
18 | serverSecrets.shields_secret &&
19 | constEq(secret, serverSecrets.shields_secret)
20 | )
21 | }
22 |
--------------------------------------------------------------------------------
/services/eclipse-marketplace/eclipse-marketplace-update.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isFormattedDate } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('last update date').get('/notepad4e.json').expectBadge({
7 | label: 'updated',
8 | message: isFormattedDate,
9 | })
10 |
11 | t.create('last update for unknown solution')
12 | .get('/this-does-not-exist.json')
13 | .expectBadge({
14 | label: 'updated',
15 | message: 'solution not found',
16 | })
17 |
--------------------------------------------------------------------------------
/services/discourse/discourse-redirect.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { redirector } = require('..')
4 |
5 | module.exports = [
6 | redirector({
7 | category: 'chat',
8 | route: {
9 | base: 'discourse',
10 | pattern: ':protocol(http|https)/:hostAndPath(.+)/:metric',
11 | },
12 | transformPath: ({ metric }) => `/discourse/${metric}`,
13 | transformQueryParams: ({ protocol, hostAndPath }) => ({
14 | server: `${protocol}://${hostAndPath}`,
15 | }),
16 | dateAdded: new Date('2019-09-15'),
17 | }),
18 | ]
19 |
--------------------------------------------------------------------------------
/services/continuousphp/continuousphp.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { test, given } = require('sazerac')
4 | const ContinuousPhp = require('./continuousphp.service')
5 |
6 | describe('ContinuousPhp', function () {
7 | test(ContinuousPhp.render, () => {
8 | given({ status: 'unstable' }).expect({
9 | label: 'build',
10 | message: 'unstable',
11 | color: 'yellow',
12 | })
13 | given({ status: 'running' }).expect({
14 | label: 'build',
15 | message: 'running',
16 | color: 'blue',
17 | })
18 | })
19 | })
20 |
--------------------------------------------------------------------------------
/services/eclipse-marketplace/eclipse-marketplace-base.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { BaseXmlService } = require('..')
4 |
5 | module.exports = class EclipseMarketplaceBase extends BaseXmlService {
6 | static buildRoute(base) {
7 | return {
8 | base,
9 | pattern: ':name',
10 | }
11 | }
12 |
13 | async fetch({ name, schema }) {
14 | return this._requestXml({
15 | schema,
16 | url: `https://marketplace.eclipse.org/content/${name}/api/p`,
17 | errorMessages: { 404: 'solution not found' },
18 | })
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/services/twitter/twitter-redirect.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { redirector } = require('..')
4 |
5 | module.exports = [
6 | redirector({
7 | category: 'social',
8 | name: 'TwitterUrlRedirect',
9 | route: {
10 | base: 'twitter/url',
11 | pattern: ':protocol(https|http)/:hostAndPath+',
12 | },
13 | transformPath: () => `/twitter/url`,
14 | transformQueryParams: ({ protocol, hostAndPath }) => ({
15 | url: `${protocol}://${hostAndPath}`,
16 | }),
17 | dateAdded: new Date('2019-09-17'),
18 | }),
19 | ]
20 |
--------------------------------------------------------------------------------
/services/date/date.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 | const { isRelativeFormattedDate } = require('../test-validators')
5 |
6 | const t = (module.exports = new ServiceTester({
7 | id: 'date',
8 | title: 'Relative Date Tests',
9 | }))
10 |
11 | t.create('Relative date')
12 | .get('/1540814400.json')
13 | .expectBadge({ label: 'date', message: isRelativeFormattedDate })
14 |
15 | t.create('Relative date - Invalid')
16 | .get('/9999999999999.json')
17 | .expectBadge({ label: 'date', message: 'invalid date' })
18 |
--------------------------------------------------------------------------------
/services/snap-ci/snap-ci.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { deprecatedService } = require('..')
4 |
5 | const commonAttrs = {
6 | category: 'build',
7 | label: 'snap ci',
8 | dateAdded: new Date('2018-01-23'),
9 | }
10 |
11 | module.exports = [
12 | deprecatedService({
13 | route: {
14 | base: 'snap',
15 | pattern: ':various*',
16 | },
17 | ...commonAttrs,
18 | }),
19 | deprecatedService({
20 | route: {
21 | base: 'snap-ci',
22 | pattern: ':various*',
23 | },
24 | ...commonAttrs,
25 | }),
26 | ]
27 |
--------------------------------------------------------------------------------
/core/server/error-pages/404.html:
--------------------------------------------------------------------------------
1 | These aren't the pages you're looking
2 | for
3 |
4 | I have nothing to offer for this request
5 | … but blood, toil, tears and sweat.
6 |
7 | Fortunately, the main page can offer rainbows instead!
8 |
9 |
10 |
11 | (You probably landed on this page because a link was broken, because someone
12 | mistyped its URL, or because of an irrelevant mistake. Don't worry, though:
13 | there is all of the rest of the Web to explore!)
14 |
15 |
--------------------------------------------------------------------------------
/services/gratipay/gratipay.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { deprecatedService } = require('..')
4 |
5 | const commonAttrs = {
6 | category: 'funding',
7 | label: 'gratipay',
8 | dateAdded: new Date('2017-12-29'),
9 | }
10 |
11 | module.exports = [
12 | deprecatedService({
13 | route: {
14 | base: 'gittip',
15 | pattern: ':various*',
16 | },
17 | ...commonAttrs,
18 | }),
19 | deprecatedService({
20 | route: {
21 | base: 'gratipay',
22 | pattern: ':various*',
23 | },
24 | ...commonAttrs,
25 | }),
26 | ]
27 |
--------------------------------------------------------------------------------
/services/jira/jira-issue-redirect.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { redirector } = require('..')
4 |
5 | module.exports = [
6 | redirector({
7 | category: 'issue-tracking',
8 | route: {
9 | base: 'jira/issue',
10 | pattern: ':protocol(http|https)/:hostAndPath(.+)/:issueKey',
11 | },
12 | transformPath: ({ issueKey }) => `/jira/issue/${issueKey}`,
13 | transformQueryParams: ({ protocol, hostAndPath }) => ({
14 | baseUrl: `${protocol}://${hostAndPath}`,
15 | }),
16 | dateAdded: new Date('2019-09-14'),
17 | }),
18 | ]
19 |
--------------------------------------------------------------------------------
/services/symfony/sensiolabs-redirect.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { redirector } = require('..')
4 |
5 | module.exports = [
6 | // The SymfonyInsight service was previously branded as SensioLabs, and
7 | // accordingly the badge path used to be /sensiolabs/i/projectUuid'.
8 | redirector({
9 | category: 'analysis',
10 | route: {
11 | base: 'sensiolabs/i',
12 | pattern: ':projectUuid',
13 | },
14 | transformPath: ({ projectUuid }) => `/symfony/i/grade/${projectUuid}`,
15 | dateAdded: new Date('2019-02-08'),
16 | }),
17 | ]
18 |
--------------------------------------------------------------------------------
/gatsby-browser.js:
--------------------------------------------------------------------------------
1 | import redirectLegacyRoutes from './frontend/lib/redirect-legacy-routes'
2 |
3 | // Adapted from https://github.com/gatsbyjs/gatsby/issues/8413
4 | function scrollToElementId(id) {
5 | const el = document.querySelector(id)
6 | if (el) {
7 | return window.scrollTo(0, el.offsetTop - 20)
8 | } else {
9 | return false
10 | }
11 | }
12 |
13 | export function onRouteUpdate({ location: { hash } }) {
14 | if (hash) {
15 | if (!redirectLegacyRoutes()) {
16 | window.setTimeout(() => scrollToElementId(hash), 10)
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/services/conda/conda-platform.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const isCondaPlatform = Joi.string().regex(/^\w+-[\w\d]+( \| \w+-[\w\d]+)*$/)
5 | const t = (module.exports = require('../tester').createServiceTester())
6 |
7 | t.create('platform').get('/p/conda-forge/zlib.json').expectBadge({
8 | label: 'conda|platform',
9 | message: isCondaPlatform,
10 | })
11 |
12 | t.create('platform (skip prefix)')
13 | .get('/pn/conda-forge/zlib.json')
14 | .expectBadge({
15 | label: 'platform',
16 | message: isCondaPlatform,
17 | })
18 |
--------------------------------------------------------------------------------
/services/jira/jira-sprint-redirect.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { redirector } = require('..')
4 |
5 | module.exports = [
6 | redirector({
7 | category: 'issue-tracking',
8 | route: {
9 | base: 'jira/sprint',
10 | pattern: ':protocol(http|https)/:hostAndPath(.+)/:sprintId',
11 | },
12 | transformPath: ({ sprintId }) => `/jira/sprint/${sprintId}`,
13 | transformQueryParams: ({ protocol, hostAndPath }) => ({
14 | baseUrl: `${protocol}://${hostAndPath}`,
15 | }),
16 | dateAdded: new Date('2019-09-14'),
17 | }),
18 | ]
19 |
--------------------------------------------------------------------------------
/services/offset-earth/offset-earth-carbon.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 | const { withRegex } = require('../test-validators')
5 |
6 | t.create('request for existing username')
7 | .get('/offsetearth.json')
8 | .expectBadge({
9 | label: 'carbon offset',
10 | message: withRegex(/[\d.]+ tonnes/),
11 | })
12 |
13 | t.create('invalid username').get('/non-existent-username.json').expectBadge({
14 | label: 'carbon offset',
15 | message: 'username not found',
16 | color: 'red',
17 | })
18 |
--------------------------------------------------------------------------------
/services/teamcity/teamcity-coverage-redirect.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = (module.exports = new ServiceTester({
6 | id: 'TeamCityCoverageRedirect',
7 | title: 'TeamCityCoverageRedirect',
8 | pathPrefix: '/teamcity/coverage',
9 | }))
10 |
11 | t.create('coverage')
12 | .get('/https/teamcity.jetbrains.com/ReactJSNet_PullRequests.svg')
13 | .expectRedirect(
14 | `/teamcity/coverage/ReactJSNet_PullRequests.svg?server=${encodeURIComponent(
15 | 'https://teamcity.jetbrains.com'
16 | )}`
17 | )
18 |
--------------------------------------------------------------------------------
/core/server/in-process-server-test-helpers.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const merge = require('deepmerge')
4 | const config = require('config').util.toObject()
5 | const portfinder = require('portfinder')
6 | const Server = require('./server')
7 |
8 | async function createTestServer(customConfig = {}) {
9 | const mergedConfig = merge(config, customConfig)
10 | if (!mergedConfig.public.bind.port) {
11 | mergedConfig.public.bind.port = await portfinder.getPortPromise()
12 | }
13 | return new Server(mergedConfig)
14 | }
15 |
16 | module.exports = {
17 | createTestServer,
18 | }
19 |
--------------------------------------------------------------------------------
/services/jitpack/jitpack-version.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | // Github allows versions with chars, etc.
7 | const isAnyV = Joi.string().regex(/^v.+$/)
8 |
9 | t.create('version (groupId)')
10 | .get('/github/erayerdin/kappdirs.json')
11 | .expectBadge({ label: 'jitpack', message: isAnyV })
12 |
13 | t.create('unknown package')
14 | .get('/github/some-bogus-user/project.json')
15 | .expectBadge({ label: 'jitpack', message: 'project not found or private' })
16 |
--------------------------------------------------------------------------------
/services/teamcity/teamcity-coverage-redirect.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { redirector } = require('..')
4 |
5 | module.exports = [
6 | redirector({
7 | category: 'coverage',
8 | route: {
9 | base: 'teamcity/coverage',
10 | pattern: ':protocol(http|https)/:hostAndPath(.+)/:buildId',
11 | },
12 | transformPath: ({ buildId }) => `/teamcity/coverage/${buildId}`,
13 | transformQueryParams: ({ protocol, hostAndPath }) => ({
14 | server: `${protocol}://${hostAndPath}`,
15 | }),
16 | dateAdded: new Date('2019-09-15'),
17 | }),
18 | ]
19 |
--------------------------------------------------------------------------------
/services/beerpay/beerpay.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { withRegex } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | const amountOfMoney = withRegex(/^\$[0-9]+(\.[0-9]+)?/)
7 |
8 | t.create('funding').get('/hashdog/scrapfy-chrome-extension.json').expectBadge({
9 | label: 'beerpay',
10 | message: amountOfMoney,
11 | })
12 |
13 | t.create('funding (unknown project)')
14 | .get('/hashdog/not-a-real-project.json')
15 | .expectBadge({
16 | label: 'beerpay',
17 | message: 'project not found',
18 | })
19 |
--------------------------------------------------------------------------------
/services/cirrus/cirrus.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const { isBuildStatus } = require('../build-status')
5 | const t = (module.exports = require('../tester').createServiceTester())
6 |
7 | t.create('cirrus bad repo')
8 | .get('/github/unknown-identifier/unknown-repo.json')
9 | .expectBadge({ label: 'build', message: 'unknown' })
10 |
11 | t.create('cirrus fully.valid')
12 | .get('/github/flutter/flutter.json')
13 | .expectBadge({
14 | label: 'build',
15 | message: Joi.alternatives().try(isBuildStatus, Joi.equal('unknown')),
16 | })
17 |
--------------------------------------------------------------------------------
/services/stackexchange/stackexchange-taginfo.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isMetric } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('JavaScript Questions')
7 | .get('/stackoverflow/t/javascript.json')
8 | .expectBadge({
9 | label: 'stackoverflow javascript questions',
10 | message: isMetric,
11 | })
12 |
13 | t.create('Tex Programming Questions')
14 | .get('/tex/t/programming.json')
15 | .expectBadge({
16 | label: 'tex programming questions',
17 | message: isMetric,
18 | })
19 |
--------------------------------------------------------------------------------
/services/resharper/resharper.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { createServiceFamily } = require('../nuget/nuget-v2-service-family')
4 |
5 | module.exports = createServiceFamily({
6 | name: 'ResharperPlugin',
7 | defaultLabel: 'resharper',
8 | serviceBaseUrl: 'resharper',
9 | apiBaseUrl: 'https://resharper-plugins.jetbrains.com/api/v2',
10 | odataFormat: 'xml',
11 | title: 'JetBrains ReSharper plugins',
12 | examplePackageName: 'StyleCop.StyleCop',
13 | exampleVersion: '2017.2.0',
14 | examplePrereleaseVersion: '2017.3.0-pre0001',
15 | exampleDownloadCount: 9e4,
16 | })
17 |
--------------------------------------------------------------------------------
/core/base-service/categories.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const categories = require('../../services/categories')
5 |
6 | const isRealCategory = Joi.equal(...categories.map(({ id }) => id)).required()
7 |
8 | const isValidCategory = Joi.alternatives()
9 | .try(isRealCategory, Joi.equal('debug', 'dynamic', 'static').required())
10 | .required()
11 |
12 | function assertValidCategory(category, message = undefined) {
13 | Joi.assert(category, isValidCategory, message)
14 | }
15 |
16 | module.exports = {
17 | isValidCategory,
18 | assertValidCategory,
19 | }
20 |
--------------------------------------------------------------------------------
/frontend/lib/service-definitions/index.spec.ts:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai'
2 | import { test, given } from 'sazerac'
3 | import { findCategory, getDefinitionsForCategory } from '.'
4 |
5 | describe('Service definition helpers', function () {
6 | test(findCategory, () => {
7 | given('build').expect({ id: 'build', name: 'Build', keywords: ['build'] })
8 | given('foo').expect(undefined)
9 | })
10 |
11 | it('getDefinitionsForCategory', function () {
12 | expect(getDefinitionsForCategory('build'))
13 | .to.have.length.greaterThan(10)
14 | .and.lessThan(75)
15 | })
16 | })
17 |
--------------------------------------------------------------------------------
/services/github/github-all-contributors.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 | const { isMetric } = require('../test-validators')
5 |
6 | t.create('all-contributors repo')
7 | .get('/all-contributors/all-contributors.json')
8 | .expectBadge({
9 | label: 'all contributors',
10 | message: isMetric,
11 | })
12 |
13 | t.create('shields repo (not found)').get('/badges/shields.json').expectBadge({
14 | label: 'all contributors',
15 | message: 'repo not found, branch not found, or .all-contributorsrc missing',
16 | })
17 |
--------------------------------------------------------------------------------
/services/eclipse-marketplace/eclipse-marketplace-version.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isVPlusDottedVersionAtLeastOne } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('marketplace version').get('/notepad4e.json').expectBadge({
7 | label: 'eclipse marketplace',
8 | message: isVPlusDottedVersionAtLeastOne,
9 | })
10 |
11 | t.create('last update for unknown solution')
12 | .get('/this-does-not-exist.json')
13 | .expectBadge({
14 | label: 'eclipse marketplace',
15 | message: 'solution not found',
16 | })
17 |
--------------------------------------------------------------------------------
/services/bugzilla/bugzilla.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { test, given } = require('sazerac')
4 | const Bugzilla = require('./bugzilla.service')
5 |
6 | describe('getDisplayStatus function', function () {
7 | it('formats status correctly', async function () {
8 | test(Bugzilla.getDisplayStatus, () => {
9 | given({ status: 'RESOLVED', resolution: 'WORKSFORME' }).expect(
10 | 'works for me'
11 | )
12 | given({ status: 'RESOLVED', resolution: 'WONTFIX' }).expect("won't fix")
13 | given({ status: 'ASSIGNED', resolution: '' }).expect('assigned')
14 | })
15 | })
16 | })
17 |
--------------------------------------------------------------------------------
/services/github/github-forks.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isMetric } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('Forks')
7 | .get('/badges/shields.json')
8 | .expectBadge({
9 | label: 'forks',
10 | message: isMetric,
11 | link: [
12 | 'https://github.com/badges/shields/fork',
13 | 'https://github.com/badges/shields/network',
14 | ],
15 | })
16 |
17 | t.create('Forks (repo not found)').get('/badges/helmets.json').expectBadge({
18 | label: 'forks',
19 | message: 'repo not found',
20 | })
21 |
--------------------------------------------------------------------------------
/services/spiget/spiget-download-size.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isFileSize } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('EssentialsX (id 9089)')
7 | .get('/9089.json')
8 | .expectBadge({ label: 'size', message: isFileSize })
9 |
10 | t.create('Advanced Achievements (id 6239)').get('/6239.json').expectBadge({
11 | lavel: 'size',
12 | message: 'resource hosted externally',
13 | })
14 |
15 | t.create('Invalid Resource (id 1)').get('/1.json').expectBadge({
16 | label: 'size',
17 | message: 'not found',
18 | })
19 |
--------------------------------------------------------------------------------
/core/badge-urls/path-helpers.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | // Escapes `t` using the format specified in
4 | //
5 | function escapeFormat(t) {
6 | return (
7 | t
8 | // Inline single underscore.
9 | .replace(/([^_])_([^_])/g, '$1 $2')
10 | // Leading or trailing underscore.
11 | .replace(/([^_])_$/, '$1 ')
12 | .replace(/^_([^_])/, ' $1')
13 | // Double underscore and double dash.
14 | .replace(/__/g, '_')
15 | .replace(/--/g, '-')
16 | )
17 | }
18 |
19 | module.exports = {
20 | escapeFormat,
21 | }
22 |
--------------------------------------------------------------------------------
/services/deprecation-helpers.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { expect } = require('chai')
4 | const { Deprecated } = require('../core/base-service/errors')
5 | const { enforceDeprecation } = require('./deprecation-helpers')
6 |
7 | describe('enforceDeprecation', function () {
8 | it('throws Deprecated for a date in the past', function () {
9 | expect(() => enforceDeprecation(new Date())).to.throw(Deprecated)
10 | })
11 |
12 | it('does not throw for a date in the future', function () {
13 | expect(() =>
14 | enforceDeprecation(new Date(Date.now() + 10000))
15 | ).not.to.throw()
16 | })
17 | })
18 |
--------------------------------------------------------------------------------
/services/ansible/ansible-quality.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { nonNegativeInteger } = require('../validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('quality score (valid)')
7 | .get('/432.json')
8 | .expectBadge({ label: 'quality', message: nonNegativeInteger })
9 |
10 | t.create('quality score (project not found)')
11 | .get('/0101.json')
12 | .expectBadge({ label: 'quality', message: 'not found' })
13 |
14 | t.create('quality score (no score available)')
15 | .get('/2504.json')
16 | .expectBadge({ label: 'quality', message: 'no score available' })
17 |
--------------------------------------------------------------------------------
/services/dub/dub-version.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const {
5 | isVPlusDottedVersionNClausesWithOptionalSuffix,
6 | } = require('../test-validators')
7 | const t = (module.exports = require('../tester').createServiceTester())
8 |
9 | t.create('version (valid)')
10 | .get('/vibe-d.json')
11 | .expectBadge({
12 | label: 'dub',
13 | message: isVPlusDottedVersionNClausesWithOptionalSuffix,
14 | color: Joi.equal('blue', 'orange'),
15 | })
16 |
17 | t.create('version (not found)')
18 | .get('/not-a-package.json')
19 | .expectBadge({ label: 'dub', message: 'not found' })
20 |
--------------------------------------------------------------------------------
/services/spiget/spiget-latest-version.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { withRegex } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | // Note that Spigot versions can be anything (including just a string), so we'll make sure it's not returning 'not found'
7 |
8 | t.create('EssentialsX (id 9089)')
9 | .get('/9089.json')
10 | .expectBadge({
11 | label: 'spiget',
12 | message: withRegex(/^(?!not found$)/),
13 | })
14 |
15 | t.create('Invalid Resource (id 1)').get('/1.json').expectBadge({
16 | label: 'spiget',
17 | message: 'not found',
18 | })
19 |
--------------------------------------------------------------------------------
/services/swagger/swagger-redirect.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { redirector } = require('..')
4 |
5 | module.exports = [
6 | redirector({
7 | category: 'other',
8 | name: 'SwaggerRedirect',
9 | route: {
10 | base: 'swagger/valid/2.0',
11 | pattern: ':scheme(http|https)/:url*',
12 | },
13 | transformPath: () => `/swagger/valid/3.0`,
14 | transformQueryParams: ({ scheme, url }) => {
15 | const suffix = /(yaml|yml|json)$/.test(url) ? '' : '.json'
16 | return { specUrl: `${scheme}://${url}${suffix}` }
17 | },
18 | dateAdded: new Date('2019-11-03'),
19 | }),
20 | ]
21 |
--------------------------------------------------------------------------------
/services/dockbit/dockbit.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = (module.exports = new ServiceTester({
6 | id: 'dockbit',
7 | title: 'Dockbit',
8 | }))
9 |
10 | t.create('no longer available (previously image size)')
11 | .get('/image-size/_/ubuntu/latest.json')
12 | .expectBadge({
13 | label: 'dockbit',
14 | message: 'no longer available',
15 | })
16 |
17 | t.create('no longer available (previously number of layers)')
18 | .get('/layers/_/ubuntu/latest.json')
19 | .expectBadge({
20 | label: 'dockbit',
21 | message: 'no longer available',
22 | })
23 |
--------------------------------------------------------------------------------
/services/github/github-watchers.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('Watchers')
7 | .get('/badges/shields.json')
8 | .expectBadge({
9 | label: 'watchers',
10 | message: Joi.number().integer().positive(),
11 | link: [
12 | 'https://github.com/badges/shields',
13 | 'https://github.com/badges/shields/watchers',
14 | ],
15 | })
16 |
17 | t.create('Watchers (repo not found)').get('/badges/helmets.json').expectBadge({
18 | label: 'watchers',
19 | message: 'repo not found',
20 | })
21 |
--------------------------------------------------------------------------------
/services/contributor-count.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { metric } = require('./text-formatters')
4 |
5 | function contributorColor(contributorCount) {
6 | if (contributorCount > 2) {
7 | return 'brightgreen'
8 | } else if (contributorCount === 2) {
9 | return 'yellow'
10 | } else {
11 | return 'red'
12 | }
13 | }
14 |
15 | function renderContributorBadge({ label, contributorCount }) {
16 | return {
17 | label,
18 | message: metric(contributorCount),
19 | color: contributorColor(contributorCount),
20 | }
21 | }
22 |
23 | module.exports = {
24 | contributorColor,
25 | renderContributorBadge,
26 | }
27 |
--------------------------------------------------------------------------------
/services/github/github-language-count.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('language count').get('/badges/shields.json').expectBadge({
7 | label: 'languages',
8 | message: Joi.number().integer().positive(),
9 | })
10 |
11 | t.create('language count (empty repo)')
12 | .get('/pyvesb/emptyrepo.json')
13 | .expectBadge({ label: 'languages', message: '0' })
14 |
15 | t.create('language count (repo not found)')
16 | .get('/badges/helmets.json')
17 | .expectBadge({ label: 'languages', message: 'repo not found' })
18 |
--------------------------------------------------------------------------------
/services/php-eye/php-eye-hhvm.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = (module.exports = new ServiceTester({
6 | id: 'hhvm',
7 | title: 'hhvm',
8 | pathPrefix: '/hhvm',
9 | }))
10 |
11 | t.create('no longer available (previously default branch)')
12 | .get('/symfony/symfony.json')
13 | .expectBadge({
14 | label: 'hhvm',
15 | message: 'no longer available',
16 | })
17 |
18 | t.create('no longer available (get specific branch)')
19 | .get('/yiisoft/yii/1.1.19.json')
20 | .expectBadge({
21 | label: 'hhvm',
22 | message: 'no longer available',
23 | })
24 |
--------------------------------------------------------------------------------
/services/bountysource/bountysource.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isMetric } = require('../test-validators')
4 | const { ServiceTester } = require('../tester')
5 |
6 | const t = (module.exports = new ServiceTester({
7 | id: 'bountysource',
8 | title: 'Bountysource',
9 | }))
10 |
11 | t.create('bounties (valid)')
12 | .get('/team/mozilla-core/activity.json')
13 | .expectBadge({
14 | label: 'bounties',
15 | message: isMetric,
16 | })
17 |
18 | t.create('bounties (invalid team)')
19 | .get('/team/not-a-real-team/activity.json')
20 | .expectBadge({
21 | label: 'bounties',
22 | message: 'not found',
23 | })
24 |
--------------------------------------------------------------------------------
/services/itunes/itunes.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isVPlusDottedVersionAtLeastOne } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('iTunes version (valid)').get('/324684580.json').expectBadge({
7 | label: 'itunes app store',
8 | message: isVPlusDottedVersionAtLeastOne,
9 | })
10 |
11 | t.create('iTunes version (not found)')
12 | .get('/9.json')
13 | .expectBadge({ label: 'itunes app store', message: 'not found' })
14 |
15 | t.create('iTunes version (invalid)')
16 | .get('/x.json')
17 | .expectBadge({ label: 'itunes app store', message: 'invalid' })
18 |
--------------------------------------------------------------------------------
/services/github/github-hacktoberfest.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { test, given } = require('sazerac')
4 | const GitHubHacktoberfest = require('./github-hacktoberfest.service')
5 |
6 | describe('GitHubHacktoberfest', function () {
7 | test(GitHubHacktoberfest.render, () => {
8 | given({
9 | daysLeft: -1,
10 | contributionCount: 12,
11 | }).expect({
12 | message: 'is over! (12 PRs opened)',
13 | })
14 | given({
15 | daysLeft: 10,
16 | contributionCount: 27,
17 | suggestedIssueCount: 54,
18 | }).expect({
19 | message: '54 open issues, 27 PRs, 10 days left',
20 | })
21 | })
22 | })
23 |
--------------------------------------------------------------------------------
/services/github/github-issue-detail-redirect.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { redirector } = require('..')
4 |
5 | const variantMap = {
6 | s: 'state',
7 | u: 'author',
8 | }
9 |
10 | module.exports = [
11 | redirector({
12 | category: 'issue-tracking',
13 | route: {
14 | base: 'github',
15 | pattern:
16 | ':issueKind(issues|pulls)/detail/:variant(s|u)/:user/:repo/:number([0-9]+)',
17 | },
18 | transformPath: ({ issueKind, variant, user, repo, number }) =>
19 | `/github/${issueKind}/detail/${variantMap[variant]}/${user}/${repo}/${number}`,
20 | dateAdded: new Date('2019-04-04'),
21 | }),
22 | ]
23 |
--------------------------------------------------------------------------------
/services/imagelayers/imagelayers.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = (module.exports = new ServiceTester({
6 | id: 'imagelayers',
7 | title: 'ImageLayers',
8 | }))
9 |
10 | t.create('no longer available (previously image size)')
11 | .get('/image-size/_/ubuntu/latest.json')
12 | .expectBadge({
13 | label: 'imagelayers',
14 | message: 'no longer available',
15 | })
16 |
17 | t.create('no longer available (previously number of layers)')
18 | .get('/layers/_/ubuntu/latest.json')
19 | .expectBadge({
20 | label: 'imagelayers',
21 | message: 'no longer available',
22 | })
23 |
--------------------------------------------------------------------------------
/services/node/testUtils/packageJsonVersionsTemplate.json:
--------------------------------------------------------------------------------
1 | {
2 | "dist-tags": {
3 | "latest": "0.0.91"
4 | },
5 | "versions": {
6 | "0.0.90": {
7 | "engines": {
8 | "node": ">= 0.4.0"
9 | },
10 | "maintainers": [
11 | {
12 | "name": "jaredhanson",
13 | "email": "jaredhanson@gmail.com"
14 | }
15 | ]
16 | },
17 | "0.0.91": {
18 | "engines": {
19 | "node": ">= 0.4.0"
20 | },
21 | "maintainers": [
22 | {
23 | "name": "jaredhanson",
24 | "email": "jaredhanson@gmail.com"
25 | }
26 | ]
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/.nycrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "reporter": ["lcov"],
3 | "all": true,
4 | "silent": true,
5 | "clean": false,
6 | "exclude": [
7 | "**/*.spec.js",
8 | "**/*.integration.js",
9 | "**/test-helpers.js",
10 | "**/*-test-helpers.js",
11 | "**/*-fixtures.js",
12 | "**/mocha-*.js",
13 | "dangerfile.js",
14 | "gatsby-*.js",
15 | "core/service-test-runner",
16 | "core/got-test-client.js",
17 | "services/**/*.tester.js",
18 | "services/test-validators.js",
19 | "services/tester.js",
20 | "core/base-service/loader-test-fixtures",
21 | "scripts",
22 | "coverage",
23 | "build",
24 | ".github"
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/services/cpan/cpan.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const { BaseJsonService } = require('..')
5 |
6 | const schema = Joi.object({
7 | version: Joi.alternatives(Joi.string().required(), Joi.number().required()),
8 | license: Joi.array().items(Joi.string()).min(1).required(),
9 | }).required()
10 |
11 | module.exports = class BaseCpanService extends BaseJsonService {
12 | static get defaultBadgeData() {
13 | return { label: 'cpan' }
14 | }
15 |
16 | async fetch({ packageName }) {
17 | const url = `https://fastapi.metacpan.org/v1/release/${packageName}`
18 | return this._requestJson({ schema, url })
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/services/jitpack/jitpack-downloads.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = (module.exports = new ServiceTester({
6 | id: 'JitPackDownloads',
7 | title: 'JitPackDownloads',
8 | pathPrefix: '/jitpack',
9 | }))
10 |
11 | t.create('no longer available (dw)')
12 | .get('/dw/github/jitpack/maven-simple.json')
13 | .expectBadge({
14 | label: 'jitpack',
15 | message: 'no longer available',
16 | })
17 |
18 | t.create('no longer available (dm)')
19 | .get('/dm/github/jitpack/maven-simple.json')
20 | .expectBadge({
21 | label: 'jitpack',
22 | message: 'no longer available',
23 | })
24 |
--------------------------------------------------------------------------------
/services/leanpub/leanpub-book-summary.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = (module.exports = new ServiceTester({
6 | id: 'LeanPub',
7 | title: 'LeanPub',
8 | pathPrefix: '/leanpub/book',
9 | }))
10 |
11 | t.create('no longer available (previously book pages)')
12 | .get('/pages/juice-shop.json')
13 | .expectBadge({
14 | label: 'leanpub',
15 | message: 'no longer available',
16 | })
17 |
18 | t.create('no longer available (previously books sold)')
19 | .get('/sold/juice-shop.json')
20 | .expectBadge({
21 | label: 'leanpub',
22 | message: 'no longer available',
23 | })
24 |
--------------------------------------------------------------------------------
/services/npm/npm-downloads.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { test, given } = require('sazerac')
4 | const NpmDownloads = require('./npm-downloads.service')
5 |
6 | describe('NpmDownloads', function () {
7 | test(NpmDownloads._intervalMap.dt.transform, () => {
8 | given({
9 | downloads: [
10 | { downloads: 2, day: '2018-01-01' },
11 | { downloads: 3, day: '2018-01-02' },
12 | ],
13 | }).expect(5)
14 | })
15 |
16 | test(NpmDownloads.render, () => {
17 | given({
18 | interval: 'dt',
19 | downloadCount: 0,
20 | }).expect({
21 | message: '0',
22 | color: 'red',
23 | })
24 | })
25 | })
26 |
--------------------------------------------------------------------------------
/services/php-eye/php-eye-php-version.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = (module.exports = new ServiceTester({
6 | id: 'php-eye',
7 | title: 'php-eye',
8 | pathPrefix: '/php-eye',
9 | }))
10 |
11 | t.create('no longer available (previously default branch)')
12 | .get('/symfony/symfony.json')
13 | .expectBadge({
14 | label: 'php tested',
15 | message: 'no longer available',
16 | })
17 |
18 | t.create('no longer available (get specific branch)')
19 | .get('/yiisoft/yii/1.1.19.json')
20 | .expectBadge({
21 | label: 'php tested',
22 | message: 'no longer available',
23 | })
24 |
--------------------------------------------------------------------------------
/services/stackexchange/stackexchange-monthlyquestions.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isMetricOverTimePeriod } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('Monthly Questions for StackOverflow Momentjs')
7 | .get('/stackoverflow/qm/momentjs.json')
8 | .expectBadge({
9 | label: 'stackoverflow momentjs questions',
10 | message: isMetricOverTimePeriod,
11 | })
12 |
13 | t.create('Monthly Questions for Tex Spacing')
14 | .get('/tex/qm/spacing.json')
15 | .expectBadge({
16 | label: 'tex spacing questions',
17 | message: isMetricOverTimePeriod,
18 | })
19 |
--------------------------------------------------------------------------------
/services/codeclimate/codeclimate-analysis-redirector.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { redirector } = require('..')
4 |
5 | module.exports = [
6 | // http://github.com/badges/shields/issues/1387
7 | // https://github.com/badges/shields/pull/3320#issuecomment-483795000
8 | redirector({
9 | name: 'CodeclimateCoverageMaintainabilityRedirect',
10 | category: 'analysis',
11 | route: {
12 | base: 'codeclimate/maintainability-letter',
13 | pattern: ':user/:repo',
14 | },
15 | transformPath: ({ user, repo }) =>
16 | `/codeclimate/maintainability/${user}/${repo}`,
17 | dateAdded: new Date('2019-04-16'),
18 | }),
19 | ]
20 |
--------------------------------------------------------------------------------
/services/issuestats/issuestats.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = new ServiceTester({ id: 'issuestats', title: 'Issue Stats' })
6 | module.exports = t
7 |
8 | t.create('no longer available (previously issue analysis)')
9 | .get('/i/github/expressjs/express.json')
10 | .expectBadge({
11 | label: 'issue stats',
12 | message: 'no longer available',
13 | })
14 |
15 | t.create('no longer available (previously pull request analysis, long form)')
16 | .get('/p/long/github/expressjs/express.json')
17 | .expectBadge({
18 | label: 'issue stats',
19 | message: 'no longer available',
20 | })
21 |
--------------------------------------------------------------------------------
/services/crates/crates-license.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = (module.exports = new ServiceTester({
6 | id: 'crates',
7 | title: 'crates.io',
8 | pathPrefix: '/crates/l',
9 | }))
10 |
11 | t.create('license')
12 | .get('/libc.json')
13 | .expectBadge({ label: 'license', message: 'MIT OR Apache-2.0' })
14 |
15 | t.create('license (with version)')
16 | .get('/libc/0.2.44.json')
17 | .expectBadge({ label: 'license', message: 'MIT OR Apache-2.0' })
18 |
19 | t.create('license (not found)')
20 | .get('/not-a-real-package.json')
21 | .expectBadge({ label: 'crates.io', message: 'not found' })
22 |
--------------------------------------------------------------------------------
/services/netlify/netlify.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { test, given } = require('sazerac')
4 | const Netlify = require('./netlify.service')
5 |
6 | const building = { message: 'building', label: undefined, color: 'yellow' }
7 | const notBuilt = { message: 'not built', label: undefined, color: undefined }
8 |
9 | describe('Netlify', function () {
10 | test(Netlify.render, () => {
11 | given({ status: 'building' }).expect(building)
12 | given({ status: 'stopped' }).expect(notBuilt)
13 | given({ status: 'infrastructure_failure' }).expect({
14 | message: 'failing',
15 | color: 'red',
16 | label: undefined,
17 | })
18 | })
19 | })
20 |
--------------------------------------------------------------------------------
/core/base-service/loader-test-fixtures/valid-array.fixture.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const BaseJsonService = require('../base-json')
4 |
5 | class GoodServiceOne extends BaseJsonService {
6 | static get category() {
7 | return 'build'
8 | }
9 |
10 | static get route() {
11 | return {
12 | base: 'good',
13 | pattern: 'one',
14 | }
15 | }
16 | }
17 | class GoodServiceTwo extends BaseJsonService {
18 | static get category() {
19 | return 'build'
20 | }
21 |
22 | static get route() {
23 | return {
24 | base: 'good',
25 | pattern: 'two',
26 | }
27 | }
28 | }
29 |
30 | module.exports = [GoodServiceOne, GoodServiceTwo]
31 |
--------------------------------------------------------------------------------
/core/base-service/loader-test-fixtures/valid-object.fixture.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const BaseJsonService = require('../base-json')
4 |
5 | class GoodServiceOne extends BaseJsonService {
6 | static get category() {
7 | return 'build'
8 | }
9 |
10 | static get route() {
11 | return {
12 | base: 'good',
13 | pattern: 'one',
14 | }
15 | }
16 | }
17 | class GoodServiceTwo extends BaseJsonService {
18 | static get category() {
19 | return 'build'
20 | }
21 |
22 | static get route() {
23 | return {
24 | base: 'good',
25 | pattern: 'two',
26 | }
27 | }
28 | }
29 |
30 | module.exports = { GoodServiceOne, GoodServiceTwo }
31 |
--------------------------------------------------------------------------------
/services/github/github-size.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isFileSize } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('File size')
7 | .get('/webcaetano/craft/build/phaser-craft.min.js.json')
8 | .expectBadge({ label: 'size', message: isFileSize })
9 |
10 | t.create('File size 404')
11 | .get('/webcaetano/craft/build/does-not-exist.min.js.json')
12 | .expectBadge({ label: 'size', message: 'repo or file not found' })
13 |
14 | t.create('File size for "not a regular file"')
15 | .get('/webcaetano/craft/build.json')
16 | .expectBadge({ label: 'size', message: 'not a regular file' })
17 |
--------------------------------------------------------------------------------
/services/nexus/nexus-redirect.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { redirector } = require('..')
4 |
5 | module.exports = [
6 | redirector({
7 | category: 'version',
8 | route: {
9 | base: 'nexus',
10 | pattern:
11 | ':repo(r|s|[^/]+)/:scheme(http|https)/:hostAndPath+/:groupId/:artifactId([^/:]+?):queryOpt(:.+?)?',
12 | },
13 | transformPath: ({ repo, groupId, artifactId }) =>
14 | `/nexus/${repo}/${groupId}/${artifactId}`,
15 | transformQueryParams: ({ scheme, hostAndPath, queryOpt }) => ({
16 | server: `${scheme}://${hostAndPath}`,
17 | queryOpt,
18 | }),
19 | dateAdded: new Date('2019-07-26'),
20 | }),
21 | ]
22 |
--------------------------------------------------------------------------------
/services/amo/amo-rating.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const { isStarRating } = require('../test-validators')
5 | const t = (module.exports = require('../tester').createServiceTester())
6 |
7 | t.create('Rating')
8 | .get('/rating/IndieGala-Helper.json')
9 | .expectBadge({
10 | label: 'rating',
11 | message: Joi.string().regex(/^\d\/\d$/),
12 | })
13 |
14 | t.create('Stars')
15 | .get('/stars/IndieGala-Helper.json')
16 | .expectBadge({ label: 'stars', message: isStarRating })
17 |
18 | t.create('Rating (not found)')
19 | .get('/rating/not-a-real-plugin.json')
20 | .expectBadge({ label: 'mozilla add-on', message: 'not found' })
21 |
--------------------------------------------------------------------------------
/services/coverity/coverity-on-demand.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = (module.exports = new ServiceTester({
6 | id: 'CoverityOnDemand',
7 | title: 'Coverity On Demand',
8 | pathPrefix: '/coverity/ondemand',
9 | }))
10 |
11 | t.create('no longer available (streams)')
12 | .get('/streams/44b25sjc9l3ntc2ngfi29tngro.json')
13 | .expectBadge({
14 | label: 'coverity',
15 | message: 'no longer available',
16 | })
17 |
18 | t.create('no longer available (jobs)')
19 | .get('/jobs/p4tmm8031t4i971r0im4s7lckk.json')
20 | .expectBadge({
21 | label: 'coverity',
22 | message: 'no longer available',
23 | })
24 |
--------------------------------------------------------------------------------
/services/opm/opm-version.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | const isValidVersion = Joi.string()
7 | .regex(/^v[\d+.]+$/)
8 | .required()
9 |
10 | t.create('version').get('/openresty/lua-resty-lrucache.json').expectBadge({
11 | label: 'opm',
12 | message: isValidVersion,
13 | })
14 |
15 | t.create('unknown module')
16 | .get('/openresty/does-not-exist.json')
17 | .expectBadge({ label: 'opm', message: 'module not found' })
18 |
19 | t.create('unknown user')
20 | .get('/nil/does-not-exist.json')
21 | .expectBadge({ label: 'opm', message: 'module not found' })
22 |
--------------------------------------------------------------------------------
/services/static-badge/static-badge.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { escapeFormat } = require('../../core/badge-urls/path-helpers')
4 | const { BaseStaticService } = require('..')
5 |
6 | module.exports = class StaticBadge extends BaseStaticService {
7 | static get category() {
8 | return 'static'
9 | }
10 |
11 | static get route() {
12 | return {
13 | base: '',
14 | format: '(?::|badge/)((?:[^-]|--)*?)-?((?:[^-]|--)*)-((?:[^-.]|--)+)',
15 | capture: ['label', 'message', 'color'],
16 | }
17 | }
18 |
19 | handle({ label, message, color }) {
20 | return { label: escapeFormat(label), message: escapeFormat(message), color }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/frontend/components/header.tsx:
--------------------------------------------------------------------------------
1 | import { Link } from 'gatsby'
2 | import React from 'react'
3 | import styled from 'styled-components'
4 | import Logo from '../images/logo.svg'
5 | import { VerticalSpace } from './common'
6 |
7 | const Highlights = styled.p`
8 | font-style: italic;
9 | `
10 |
11 | export default function Header(): JSX.Element {
12 | return (
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | Pixel-perfect Retina-ready Fast Consistent
22 | Hackable No tracking
23 |
24 |
25 | )
26 | }
27 |
--------------------------------------------------------------------------------
/services/github/github-top-language.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('top language')
7 | .get('/badges/shields.json')
8 | .expectBadge({
9 | label: 'javascript',
10 | message: Joi.string().regex(/^([1-9]?[0-9]\.[0-9]|100\.0)%$/),
11 | })
12 |
13 | t.create('top language (empty repo)')
14 | .get('/pyvesb/emptyrepo.json')
15 | .expectBadge({ label: 'language', message: 'none' })
16 |
17 | t.create('top language (repo not found)')
18 | .get('/not-a-real-user/not-a-real-repo.json')
19 | .expectBadge({ label: 'language', message: 'repo not found' })
20 |
--------------------------------------------------------------------------------
/config/shields-io-production.yml:
--------------------------------------------------------------------------------
1 | public:
2 | metrics:
3 | prometheus:
4 | enabled: true
5 | influx:
6 | enabled: true
7 | url: https://metrics.shields.io/telegraf
8 | instanceIdFrom: env-var
9 | instanceIdEnvVarName: HEROKU_DYNO_ID
10 | envLabel: shields-production
11 |
12 | ssl:
13 | isSecure: true
14 |
15 | cors:
16 | allowedOrigin: ['http://shields.io', 'https://shields.io']
17 |
18 | redirectUrl: 'https://shields.io/'
19 |
20 | rasterUrl: 'https://raster.shields.io'
21 |
22 | private:
23 | # These are not really private; they should be moved to `public`.
24 | shields_ips: ['192.99.59.72', '51.254.114.150', '149.56.96.133']
25 |
--------------------------------------------------------------------------------
/services/node/node-lts.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const NodeVersionBase = require('./node-base')
4 | const { versionColorForRangeLts } = require('./node-version-color')
5 |
6 | module.exports = class NodeLtsVersion extends NodeVersionBase {
7 | static get path() {
8 | return 'v-lts'
9 | }
10 |
11 | static get defaultBadgeData() {
12 | return { label: 'node-lts' }
13 | }
14 |
15 | static get type() {
16 | return 'lts'
17 | }
18 |
19 | static get colorResolver() {
20 | return versionColorForRangeLts
21 | }
22 |
23 | static get documentation() {
24 | return `This badge indicates whether the package supports all LTS node versions`
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/scripts/export-supported-features-cli.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const logos = require('../lib/load-logos')()
4 | const simpleIcons = require('../lib/load-simple-icons')()
5 |
6 | const shieldsLogos = Object.keys(logos)
7 |
8 | const simpleIconSet = new Set(Object.keys(simpleIcons))
9 | shieldsLogos.forEach(logo => simpleIconSet.delete(logo))
10 | const simpleIconNames = Array.from(simpleIconSet)
11 |
12 | const supportedFeatures = {
13 | shieldsLogos,
14 | simpleIcons: simpleIconNames,
15 | advertisedStyles: [
16 | 'plastic',
17 | 'flat',
18 | 'flat-square',
19 | 'for-the-badge',
20 | 'social',
21 | ],
22 | }
23 |
24 | console.log(JSON.stringify(supportedFeatures, null, 2))
25 |
--------------------------------------------------------------------------------
/services/cocoapods/cocoapods-apps.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 | const t = (module.exports = new ServiceTester({
5 | id: 'CocoapodsApps',
6 | title: 'CocoapodsApps',
7 | pathPrefix: '/cocoapods',
8 | }))
9 |
10 | t.create('apps (valid, weekly)')
11 | .get('/aw/AFNetworking.json')
12 | .expectBadge({ label: 'apps', message: 'no longer available' })
13 |
14 | t.create('apps (valid, total)')
15 | .get('/at/AFNetworking.json')
16 | .expectBadge({ label: 'apps', message: 'no longer available' })
17 |
18 | t.create('apps (not found)')
19 | .get('/at/not-a-package.json')
20 | .expectBadge({ label: 'apps', message: 'no longer available' })
21 |
--------------------------------------------------------------------------------
/services/depfu/depfu.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const { ServiceTester } = require('../tester')
5 |
6 | const isDependencyStatus = Joi.string().valid(
7 | 'insecure',
8 | 'latest',
9 | 'recent',
10 | 'stale'
11 | )
12 |
13 | const t = (module.exports = new ServiceTester({ id: 'depfu', title: 'Depfu' }))
14 |
15 | t.create('depfu dependencies (valid)')
16 | .get('/depfu/example-ruby.json')
17 | .expectBadge({
18 | label: 'dependencies',
19 | message: isDependencyStatus,
20 | })
21 |
22 | t.create('depfu dependencies (repo not found)')
23 | .get('/pyvesb/emptyrepo.json')
24 | .expectBadge({ label: 'dependencies', message: 'not found' })
25 |
--------------------------------------------------------------------------------
/services/jira/jira-test-helpers.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const sprintId = 8
4 | const sprintQueryString = {
5 | jql: `sprint=${sprintId} AND type IN (Bug,Improvement,Story,"Technical task")`,
6 | fields: 'resolution',
7 | maxResults: 500,
8 | }
9 |
10 | const user = 'admin'
11 | const pass = 'password'
12 | const host = 'myprivatejira.test'
13 | const config = {
14 | public: {
15 | services: {
16 | jira: {
17 | authorizedOrigins: [`https://${host}`],
18 | },
19 | },
20 | },
21 | private: { jira_user: user, jira_pass: pass },
22 | }
23 |
24 | module.exports = {
25 | sprintId,
26 | sprintQueryString,
27 | user,
28 | pass,
29 | host,
30 | config,
31 | }
32 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:10-alpine
2 |
3 | RUN mkdir -p /usr/src/app
4 | RUN mkdir /usr/src/app/private
5 | WORKDIR /usr/src/app
6 |
7 | COPY package.json package-lock.json /usr/src/app/
8 | # Without the badge-maker package.json and CLI script in place, `npm ci` will fail.
9 | COPY badge-maker /usr/src/app/badge-maker/
10 |
11 | # We need dev deps to build the front end. We don't need Cypress, though.
12 | RUN NODE_ENV=development CYPRESS_INSTALL_BINARY=0 npm ci
13 |
14 | COPY . /usr/src/app
15 | RUN npm run build
16 | RUN npm prune --production
17 | RUN npm cache clean --force
18 |
19 | # Run the server using production configs.
20 | ENV NODE_ENV production
21 |
22 | CMD node server
23 |
24 | EXPOSE 80
25 |
--------------------------------------------------------------------------------
/core/base-service/coalesce.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { test, given } = require('sazerac')
4 | const coalesce = require('./coalesce')
5 |
6 | // Sticking with our one-line spread implementation, and defaulting to
7 | // `undefined` instead of `null`, though h/t to
8 | // https://github.com/royriojas/coalescy for these tests!
9 |
10 | describe('coalesce', function () {
11 | test(coalesce, function () {
12 | given().expect(undefined)
13 | given(null, []).expect([])
14 | given(null, [], {}).expect([])
15 | given(null, undefined, 0, {}).expect(0)
16 |
17 | const a = null
18 | const c = 0
19 | const d = 1
20 | let b
21 | given(a, b, c, d).expect(0)
22 | })
23 | })
24 |
--------------------------------------------------------------------------------
/services/dynamic/dynamic-helpers.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const { optionalUrl } = require('../validators')
5 |
6 | const queryParamSchema = Joi.object({
7 | url: optionalUrl.required(),
8 | query: Joi.string().required(),
9 | prefix: Joi.alternatives().try(Joi.string(), Joi.number()),
10 | suffix: Joi.alternatives().try(Joi.string(), Joi.number()),
11 | })
12 | .rename('uri', 'url', { ignoreUndefined: true, override: true })
13 | .required()
14 |
15 | function createRoute(which) {
16 | return {
17 | base: `badge/dynamic/${which}`,
18 | pattern: '',
19 | queryParamSchema,
20 | }
21 | }
22 |
23 | module.exports = {
24 | createRoute,
25 | }
26 |
--------------------------------------------------------------------------------
/services/dynamic/dynamic-json.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { MetricNames } = require('../../core/base-service/metric-helper')
4 | const { BaseJsonService } = require('..')
5 | const { createRoute } = require('./dynamic-helpers')
6 | const jsonPath = require('./json-path')
7 |
8 | module.exports = class DynamicJson extends jsonPath(BaseJsonService) {
9 | static get enabledMetrics() {
10 | return [MetricNames.SERVICE_RESPONSE_SIZE]
11 | }
12 |
13 | static get route() {
14 | return createRoute('json')
15 | }
16 |
17 | async fetch({ schema, url, errorMessages }) {
18 | return this._requestJson({
19 | schema,
20 | url,
21 | errorMessages,
22 | })
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/services/dynamic/dynamic-yaml.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { MetricNames } = require('../../core/base-service/metric-helper')
4 | const { BaseYamlService } = require('..')
5 | const { createRoute } = require('./dynamic-helpers')
6 | const jsonPath = require('./json-path')
7 |
8 | module.exports = class DynamicYaml extends jsonPath(BaseYamlService) {
9 | static get enabledMetrics() {
10 | return [MetricNames.SERVICE_RESPONSE_SIZE]
11 | }
12 |
13 | static get route() {
14 | return createRoute('yaml')
15 | }
16 |
17 | async fetch({ schema, url, errorMessages }) {
18 | return this._requestYaml({
19 | schema,
20 | url,
21 | errorMessages,
22 | })
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/services/node/node-current.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const NodeVersionBase = require('./node-base')
4 | const { versionColorForRangeCurrent } = require('./node-version-color')
5 |
6 | module.exports = class NodeCurrentVersion extends NodeVersionBase {
7 | static get path() {
8 | return 'v'
9 | }
10 |
11 | static get defaultBadgeData() {
12 | return { label: 'node' }
13 | }
14 |
15 | static get type() {
16 | return 'current'
17 | }
18 |
19 | static get colorResolver() {
20 | return versionColorForRangeCurrent
21 | }
22 |
23 | static get documentation() {
24 | return `This badge indicates whether the package supports the latest release of node`
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/services/pypi/pypi-wheel.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 |
5 | t.create('wheel (has wheel, package version in request)')
6 | .get('/requests/2.18.4.json')
7 | .expectBadge({ label: 'wheel', message: 'yes' })
8 |
9 | t.create('wheel (has wheel, no package version specified)')
10 | .get('/requests.json')
11 | .expectBadge({ label: 'wheel', message: 'yes' })
12 |
13 | t.create('wheel (no wheel)')
14 | .get('/chai/1.1.2.json')
15 | .expectBadge({ label: 'wheel', message: 'no' })
16 |
17 | t.create('wheel (invalid)')
18 | .get('/not-a-package.json')
19 | .expectBadge({ label: 'wheel', message: 'package or version not found' })
20 |
--------------------------------------------------------------------------------
/services/appveyor/appveyor-build-redirect.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = (module.exports = new ServiceTester({
6 | id: 'AppveyorBuildRedirect',
7 | title: 'AppveyorBuildRedirect',
8 | pathPrefix: '/appveyor/ci',
9 | }))
10 |
11 | t.create('Appveyor CI')
12 | .get('/gruntjs/grunt', {
13 | followRedirect: false,
14 | })
15 | .expectStatus(301)
16 | .expectHeader('Location', '/appveyor/build/gruntjs/grunt.svg')
17 |
18 | t.create('Appveyor CI (branch)')
19 | .get('/gruntjs/grunt/develop', {
20 | followRedirect: false,
21 | })
22 | .expectStatus(301)
23 | .expectHeader('Location', '/appveyor/build/gruntjs/grunt/develop.svg')
24 |
--------------------------------------------------------------------------------
/services/github/github-contributors.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 | const { isMetric } = require('../test-validators')
5 |
6 | t.create('Contributors').get('/contributors/badges/shields.json').expectBadge({
7 | label: 'contributors',
8 | message: isMetric,
9 | })
10 |
11 | t.create('1 contributor')
12 | .get('/contributors/badges/shields-tests.json')
13 | .expectBadge({
14 | label: 'contributors',
15 | message: '1',
16 | })
17 |
18 | t.create('Contributors (repo not found)')
19 | .get('/contributors/badges/helmets.json')
20 | .expectBadge({
21 | label: 'contributors',
22 | message: 'repo not found',
23 | })
24 |
--------------------------------------------------------------------------------
/services/puppetforge/puppetforge-module-pdk-version.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isSemver } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('PDK version').get('/tragiccode/azure_key_vault.json').expectBadge({
7 | label: 'pdk version',
8 | message: isSemver,
9 | })
10 |
11 | t.create("PDK version (library doesn't use the PDK)")
12 | .get('/puppet/yum.json')
13 | .expectBadge({
14 | label: 'pdk version',
15 | message: 'none',
16 | })
17 |
18 | t.create('PDK version (not found)')
19 | .get('/notarealuser/notarealpackage.json')
20 | .expectBadge({
21 | label: 'pdk version',
22 | message: 'not found',
23 | })
24 |
--------------------------------------------------------------------------------
/services/sourceforge/sourceforge-open-tickets.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isMetric } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('bugs')
7 | .get('/sevenzip/bugs.json')
8 | .expectBadge({
9 | label: 'open tickets',
10 | message: isMetric,
11 | })
12 | .timeout(10000)
13 |
14 | t.create('feature requests')
15 | .get('/sevenzip/feature-requests.json')
16 | .expectBadge({
17 | label: 'open tickets',
18 | message: isMetric,
19 | })
20 | .timeout(10000)
21 |
22 | t.create('invalid project').get('/invalid/bugs.json').expectBadge({
23 | label: 'open tickets',
24 | message: 'project not found',
25 | })
26 |
--------------------------------------------------------------------------------
/scripts/redis-connectivity-test.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const config = require('config').util.toObject()
4 | console.log(config)
5 | const GithubConstellation = require('../services/github/github-constellation')
6 |
7 | const { persistence } = new GithubConstellation({
8 | persistence: config.public.persistence,
9 | service: config.public.services.github,
10 | private: config.private,
11 | })
12 |
13 | async function main() {
14 | const tokens = await persistence.initialize()
15 | console.log(`${tokens.length} tokens loaded`)
16 | await persistence.stop()
17 | }
18 |
19 | ;(async () => {
20 | try {
21 | await main()
22 | } catch (e) {
23 | console.error(e)
24 | process.exit(1)
25 | }
26 | })()
27 |
--------------------------------------------------------------------------------
/services/codefactor/codefactor-grade.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 | const { isValidGrade } = require('./codefactor-helpers')
5 |
6 | t.create('Grade').get('/github/google/guava.json').expectBadge({
7 | label: 'code quality',
8 | message: isValidGrade,
9 | })
10 |
11 | t.create('Grade (branch)')
12 | .get('/github/pallets/flask/master.json')
13 | .expectBadge({
14 | label: 'code quality',
15 | message: isValidGrade,
16 | })
17 |
18 | t.create('Grade (nonexistent repo)')
19 | .get('/github/badges/asdfasdfasdfasdfasfae.json')
20 | .expectBadge({
21 | label: 'code quality',
22 | message: 'repo or branch not found',
23 | })
24 |
--------------------------------------------------------------------------------
/services/stackexchange/stackexchange-reputation.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isMetric } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('Invalid parameters')
7 | .get('/stackoverflow/r/invalidimage.json')
8 | .expectBadge({ label: 'stackoverflow', message: 'invalid parameters' })
9 |
10 | t.create('Reputation for StackOverflow user 22656')
11 | .get('/stackoverflow/r/22656.json')
12 | .expectBadge({
13 | label: 'stackoverflow reputation',
14 | message: isMetric,
15 | })
16 |
17 | t.create('Reputation for Tex user 22656').get('/tex/r/226.json').expectBadge({
18 | label: 'tex reputation',
19 | message: isMetric,
20 | })
21 |
--------------------------------------------------------------------------------
/scripts/benchmark-performance.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const config = require('config').util.toObject()
4 | const got = require('got')
5 | const minimist = require('minimist')
6 | const Server = require('../core/server/server')
7 |
8 | async function main() {
9 | const server = new Server(config)
10 | await server.start()
11 | const args = minimist(process.argv)
12 | const iterations = parseInt(args.iterations) || 10000
13 | for (let i = 0; i < iterations; ++i) {
14 | await got(`${server.baseUrl}badge/coverage-${i}-green.svg`)
15 | }
16 | await server.stop()
17 | }
18 |
19 | ;(async () => {
20 | try {
21 | await main()
22 | } catch (e) {
23 | console.error(e)
24 | process.exit(1)
25 | }
26 | })()
27 |
--------------------------------------------------------------------------------
/services/pypi/pypi-status.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 |
5 | t.create('status (valid, stable, package version in request)')
6 | .get('/django/1.11.json')
7 | .expectBadge({ label: 'status', message: 'stable' })
8 |
9 | t.create('status (valid, no package version specified)')
10 | .get('/typing.json')
11 | .expectBadge({ label: 'status', message: 'stable' })
12 |
13 | t.create('status (valid, beta)')
14 | .get('/django/2.0rc1.json')
15 | .expectBadge({ label: 'status', message: 'beta' })
16 |
17 | t.create('status (invalid)')
18 | .get('/not-a-package.json')
19 | .expectBadge({ label: 'status', message: 'package or version not found' })
20 |
--------------------------------------------------------------------------------
/services/symfony/symfony-insight-base.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { expect } = require('chai')
4 | const { NotFound } = require('..')
5 | const { SymfonyInsightBase } = require('./symfony-insight-base')
6 |
7 | describe('SymfonyInsightBase', function () {
8 | context('transform()', function () {
9 | it('throws NotFound error when there is no coverage data', function () {
10 | try {
11 | SymfonyInsightBase.prototype.transform({
12 | data: { project: {} },
13 | })
14 | expect.fail('Expected to throw')
15 | } catch (e) {
16 | expect(e).to.be.an.instanceof(NotFound)
17 | expect(e.prettyMessage).to.equal('no analyses found')
18 | }
19 | })
20 | })
21 | })
22 |
--------------------------------------------------------------------------------
/services/amo/amo-downloads.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 | const { isMetricOverTimePeriod } = require('../test-validators')
5 | const t = (module.exports = new ServiceTester({
6 | id: 'AmoDownloads',
7 | title: 'AmoDownloads',
8 | pathPrefix: '/amo',
9 | }))
10 |
11 | t.create('Weekly Downloads')
12 | .get('/dw/dustman.json')
13 | .expectBadge({ label: 'downloads', message: isMetricOverTimePeriod })
14 |
15 | t.create('Weekly Downloads (not found)')
16 | .get('/dw/not-a-real-plugin.json')
17 | .expectBadge({ label: 'downloads', message: 'not found' })
18 |
19 | t.create('/d URL should redirect to /dw')
20 | .get('/d/dustman.svg')
21 | .expectRedirect('/amo/dw/dustman.svg')
22 |
--------------------------------------------------------------------------------
/services/codecov/codecov.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { test, forCases, given } = require('sazerac')
4 | const Codecov = require('./codecov.service')
5 |
6 | describe('Codecov', function () {
7 | test(Codecov.prototype.legacyTransform, () => {
8 | forCases([given({ json: {} }), given({ json: { commit: {} } })]).expect({
9 | coverage: 'unknown',
10 | })
11 | })
12 |
13 | test(Codecov.prototype.transform, () => {
14 | forCases([given({ data: { message: 'unknown' } })]).expect({
15 | coverage: 'unknown',
16 | })
17 | })
18 |
19 | test(Codecov.render, () => {
20 | given({ coverage: 'unknown' }).expect({
21 | message: 'unknown',
22 | color: 'lightgrey',
23 | })
24 | })
25 | })
26 |
--------------------------------------------------------------------------------
/services/crates/crates-version.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { test, given } = require('sazerac')
4 | const { expect } = require('chai')
5 | const { InvalidResponse } = require('..')
6 | const CratesVersion = require('./crates-version.service')
7 |
8 | describe('CratesVersion', function () {
9 | test(CratesVersion.prototype.transform, () => {
10 | given({ version: { num: '1.0.0' } }).expect({ version: '1.0.0' })
11 | given({ crate: { max_version: '1.1.0' } }).expect({ version: '1.1.0' })
12 | })
13 |
14 | it('throws InvalidResponse on error response', function () {
15 | expect(() =>
16 | CratesVersion.prototype.transform({ errors: [{ detail: 'idk how...' }] })
17 | ).to.throw(InvalidResponse)
18 | })
19 | })
20 |
--------------------------------------------------------------------------------
/services/docker/docker-cloud-common-fetch.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 |
5 | const cloudBuildSchema = Joi.object({
6 | objects: Joi.array()
7 | .items(
8 | Joi.object({
9 | state: Joi.string(),
10 | build_settings: Joi.array(),
11 | }).required()
12 | )
13 | .required(),
14 | }).required()
15 |
16 | async function fetchBuild(serviceInstance, { user, repo }) {
17 | return serviceInstance._requestJson({
18 | schema: cloudBuildSchema,
19 | url: `https://cloud.docker.com/api/build/v1/source`,
20 | options: { qs: { image: `${user}/${repo}` } },
21 | errorMessages: { 404: 'repo not found' },
22 | })
23 | }
24 |
25 | module.exports = {
26 | fetchBuild,
27 | }
28 |
--------------------------------------------------------------------------------
/services/dynamic/json-path.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const chai = require('chai')
4 | const { expect } = chai
5 | const jsonPath = require('./json-path')
6 |
7 | chai.use(require('chai-as-promised'))
8 |
9 | describe('JSON Path service factory', function () {
10 | describe('fetch()', function () {
11 | it('should throw error if it is not overridden', function () {
12 | class BaseService {}
13 | class JsonPathService extends jsonPath(BaseService) {}
14 | const jsonPathServiceInstance = new JsonPathService()
15 |
16 | return expect(jsonPathServiceInstance.fetch({})).to.be.rejectedWith(
17 | Error,
18 | 'fetch() function not implemented for JsonPathService'
19 | )
20 | })
21 | })
22 | })
23 |
--------------------------------------------------------------------------------
/services/lgtm/lgtm-redirector.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { redirector } = require('..')
4 |
5 | const commonAttrs = {
6 | category: 'analysis',
7 | dateAdded: new Date('2019-04-30'),
8 | }
9 |
10 | module.exports = [
11 | redirector({
12 | route: {
13 | base: 'lgtm/alerts/g',
14 | pattern: ':user/:repo',
15 | },
16 | transformPath: ({ user, repo }) => `/lgtm/alerts/github/${user}/${repo}`,
17 | ...commonAttrs,
18 | }),
19 | redirector({
20 | route: {
21 | base: 'lgtm/grade',
22 | pattern: ':language/g/:user/:repo',
23 | },
24 | transformPath: ({ language, user, repo }) =>
25 | `/lgtm/grade/${language}/github/${user}/${repo}`,
26 | ...commonAttrs,
27 | }),
28 | ]
29 |
--------------------------------------------------------------------------------
/services/travis/travis-php-version-redirect.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = (module.exports = new ServiceTester({
6 | id: 'TravisPhpVersionRedirect',
7 | title: 'TravisPhpVersionRedirect',
8 | pathPrefix: '/',
9 | }))
10 |
11 | t.create('travis-ci no branch')
12 | .get('travis-ci/php-v/symfony/symfony.svg')
13 | .expectRedirect('/travis/php-v/symfony/symfony/master.svg')
14 |
15 | t.create('travis-ci branch')
16 | .get('travis-ci/php-v/symfony/symfony/2.8.svg')
17 | .expectRedirect('/travis/php-v/symfony/symfony/2.8.svg')
18 |
19 | t.create('travis no branch')
20 | .get('travis/php-v/symfony/symfony.svg')
21 | .expectRedirect('/travis/php-v/symfony/symfony/master.svg')
22 |
--------------------------------------------------------------------------------
/logo/dependabot.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/services/librariesio/librariesio-sourcerank.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { anyInteger } = require('../validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('sourcerank').timeout(10000).get('/npm/got.json').expectBadge({
7 | label: 'sourcerank',
8 | message: anyInteger,
9 | })
10 |
11 | t.create('sourcerank (scoped npm package)')
12 | .timeout(10000)
13 | .get('/npm/@babel/core.json')
14 | .expectBadge({
15 | label: 'sourcerank',
16 | message: anyInteger,
17 | })
18 |
19 | t.create('sourcerank (not a package)')
20 | .timeout(10000)
21 | .get('/npm/foobar-is-not-package.json')
22 | .expectBadge({
23 | label: 'sourcerank',
24 | message: 'package not found',
25 | })
26 |
--------------------------------------------------------------------------------
/services/bower/bower-license.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 |
5 | t.create('licence')
6 | .timeout(10000)
7 | .get('/bootstrap.json')
8 | .expectBadge({ label: 'license', message: 'MIT' })
9 |
10 | t.create('license not declared')
11 | .get('/bootstrap.json')
12 | .intercept(nock =>
13 | nock('https://libraries.io')
14 | .get('/api/bower/bootstrap')
15 | .reply(200, { normalized_licenses: [] })
16 | )
17 | .expectBadge({ label: 'license', message: 'missing' })
18 |
19 | t.create('licence for Invalid Package')
20 | .timeout(10000)
21 | .get('/it-is-a-invalid-package-should-error.json')
22 | .expectBadge({ label: 'license', message: 'package not found' })
23 |
--------------------------------------------------------------------------------
/services/vaadin-directory/vaadin-directory-rating-count.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('rating count of component')
7 | .get('/rating-count/vaadinvaadin-grid.json')
8 | .expectBadge({
9 | label: 'rating count',
10 | message: Joi.string().regex(/^\d+?\stotal$/),
11 | })
12 |
13 | t.create('rating count of component')
14 | .get('/rc/vaadinvaadin-grid.json')
15 | .expectBadge({
16 | label: 'rating count',
17 | message: Joi.string().regex(/^\d+?\stotal$/),
18 | })
19 |
20 | t.create('not found').get('/rating-count/does-not-exist.json').expectBadge({
21 | label: 'rating count',
22 | message: 'not found',
23 | })
24 |
--------------------------------------------------------------------------------
/services/keybase/keybase-pgp.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('existing key fingerprint')
7 | .get('/skyplabs.json')
8 | .expectBadge({
9 | label: 'pgp',
10 | message: Joi.string().hex().length(16),
11 | })
12 |
13 | t.create('unknown username').get('/skyplabsssssss.json').expectBadge({
14 | label: 'pgp',
15 | message: 'profile not found',
16 | })
17 |
18 | t.create('invalid username').get('/s.json').expectBadge({
19 | label: 'pgp',
20 | message: 'invalid username',
21 | })
22 |
23 | t.create('missing key fingerprint').get('/skyp.json').expectBadge({
24 | label: 'pgp',
25 | message: 'no key fingerprint found',
26 | })
27 |
--------------------------------------------------------------------------------
/services/fedora/fedora.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const {
4 | isVPlusDottedVersionNClausesWithOptionalSuffixAndEpoch,
5 | } = require('../test-validators')
6 | const t = (module.exports = require('../tester').createServiceTester())
7 |
8 | t.create('Fedora package (default branch, valid)')
9 | .get('/rpm.json')
10 | .expectBadge({
11 | label: 'fedora',
12 | message: isVPlusDottedVersionNClausesWithOptionalSuffixAndEpoch,
13 | })
14 |
15 | t.create('Fedora package (not found)')
16 | .get('/not-a-package/rawhide.json')
17 | .expectBadge({ label: 'fedora', message: 'not found' })
18 |
19 | t.create('Fedora package (branch not found)')
20 | .get('/not-a-package/not-a-branch.json')
21 | .expectBadge({ label: 'fedora', message: 'branch not found' })
22 |
--------------------------------------------------------------------------------
/services/clojars/clojars-base.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const { nonNegativeInteger } = require('../validators')
5 | const { BaseJsonService } = require('..')
6 |
7 | const clojarsSchema = Joi.object({
8 | downloads: nonNegativeInteger,
9 | latest_release: Joi.string().allow(null),
10 | latest_version: Joi.string().required(),
11 | }).required()
12 |
13 | class BaseClojarsService extends BaseJsonService {
14 | async fetch({ clojar }) {
15 | // Clojars API Doc: https://github.com/clojars/clojars-web/wiki/Data
16 | const url = `https://clojars.org/api/artifacts/${clojar}`
17 | return this._requestJson({
18 | url,
19 | schema: clojarsSchema,
20 | })
21 | }
22 | }
23 |
24 | module.exports = { BaseClojarsService }
25 |
--------------------------------------------------------------------------------
/services/docker/docker-pulls.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isMetric } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 | const { dockerBlue } = require('./docker-helpers')
6 |
7 | t.create('docker pulls (valid, library)')
8 | .get('/_/ubuntu.json')
9 | .expectBadge({
10 | label: 'docker pulls',
11 | message: isMetric,
12 | color: `#${dockerBlue}`,
13 | })
14 |
15 | t.create('docker pulls (valid, user)')
16 | .get('/jrottenberg/ffmpeg.json')
17 | .expectBadge({
18 | label: 'docker pulls',
19 | message: isMetric,
20 | })
21 |
22 | t.create('docker pulls (not found)')
23 | .get('/_/not-a-real-repo.json')
24 | .expectBadge({ label: 'docker pulls', message: 'repo not found' })
25 |
--------------------------------------------------------------------------------
/services/docker/docker-stars.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isMetric } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 | const { dockerBlue } = require('./docker-helpers')
6 |
7 | t.create('docker stars (valid, library)')
8 | .get('/_/ubuntu.json')
9 | .expectBadge({
10 | label: 'docker stars',
11 | message: isMetric,
12 | color: `#${dockerBlue}`,
13 | })
14 |
15 | t.create('docker stars (valid, user)')
16 | .get('/jrottenberg/ffmpeg.json')
17 | .expectBadge({
18 | label: 'docker stars',
19 | message: isMetric,
20 | })
21 |
22 | t.create('docker stars (not found)')
23 | .get('/_/not-a-real-repo.json')
24 | .expectBadge({ label: 'docker stars', message: 'repo not found' })
25 |
--------------------------------------------------------------------------------
/services/keybase/keybase-zec.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { withRegex } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('existing zcash address')
7 | .get('/skyplabs.json')
8 | .expectBadge({
9 | label: 'zec',
10 | message: withRegex(/^(?!not found$)/),
11 | })
12 |
13 | t.create('unknown username').get('/skyplabsssssss.json').expectBadge({
14 | label: 'zec',
15 | message: 'profile not found',
16 | })
17 |
18 | t.create('invalid username').get('/s.json').expectBadge({
19 | label: 'zec',
20 | message: 'invalid username',
21 | })
22 |
23 | t.create('missing zcash address').get('/test.json').expectBadge({
24 | label: 'zec',
25 | message: 'no zcash addresses found',
26 | })
27 |
--------------------------------------------------------------------------------
/services/librariesio/librariesio-dependents.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isMetric } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('dependent count').timeout(10000).get('/npm/got.json').expectBadge({
7 | label: 'dependents',
8 | message: isMetric,
9 | })
10 |
11 | t.create('dependent count (scoped npm package)')
12 | .timeout(10000)
13 | .get('/npm/@babel/core.json')
14 | .expectBadge({
15 | label: 'dependents',
16 | message: isMetric,
17 | })
18 |
19 | t.create('dependent count (nonexistent package)')
20 | .timeout(10000)
21 | .get('/npm/foobar-is-not-package.json')
22 | .expectBadge({
23 | label: 'dependents',
24 | message: 'package not found',
25 | })
26 |
--------------------------------------------------------------------------------
/services/github/github-code-size.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isFileSize } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('code size in bytes for all languages')
7 | .get('/badges/shields.json')
8 | .expectBadge({
9 | label: 'code size',
10 | message: isFileSize,
11 | })
12 |
13 | t.create('code size in bytes for all languages (empty repo)')
14 | .get('/pyvesb/emptyrepo.json')
15 | .expectBadge({
16 | label: 'code size',
17 | message: '0 B',
18 | })
19 |
20 | t.create('code size in bytes for all languages (repo not found)')
21 | .get('/not-a-real-user/not-a-real-repo.json')
22 | .expectBadge({
23 | label: 'code size',
24 | message: 'repo not found',
25 | })
26 |
--------------------------------------------------------------------------------
/services/github/github-deployments.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | const validMessages = [
7 | 'success',
8 | 'error',
9 | 'failure',
10 | 'inactive',
11 | 'in progress',
12 | 'queued',
13 | 'pending',
14 | ]
15 | const isValidMessages = Joi.equal(...validMessages).required()
16 |
17 | t.create('Deployments')
18 | .get('/badges/shields/shields-staging.json')
19 | .expectBadge({
20 | label: 'state',
21 | message: isValidMessages,
22 | })
23 |
24 | t.create('Deployments (environment not found)')
25 | .get('/badges/shields/does-not-exist.json')
26 | .expectBadge({
27 | label: 'state',
28 | message: 'environment not found',
29 | })
30 |
--------------------------------------------------------------------------------
/services/keybase/keybase-xlm.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { withRegex } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('existing stellar address')
7 | .get('/skyplabs.json')
8 | .expectBadge({
9 | label: 'xlm',
10 | message: withRegex(/^(?!not found$)/),
11 | })
12 |
13 | t.create('unknown username').get('/skyplabsssssss.json').expectBadge({
14 | label: 'xlm',
15 | message: 'profile not found',
16 | })
17 |
18 | t.create('invalid username').get('/s.json').expectBadge({
19 | label: 'xlm',
20 | message: 'invalid username',
21 | })
22 |
23 | t.create('missing stellar address').get('/test.json').expectBadge({
24 | label: 'xlm',
25 | message: 'no stellar address found',
26 | })
27 |
--------------------------------------------------------------------------------
/entrypoint.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { expect } = require('chai')
4 | const isSvg = require('is-svg')
5 | const got = require('./core/got-test-client')
6 |
7 | let server
8 | before(function () {
9 | this.timeout('5s')
10 | // remove args coming from mocha
11 | // https://github.com/badges/shields/issues/3365
12 | process.argv = []
13 | server = require('./server')
14 | })
15 |
16 | after('shut down the server', async function () {
17 | await server.stop()
18 | })
19 |
20 | it('should render a badge', async function () {
21 | const { statusCode, body } = await got(
22 | 'http://localhost:1111/badge/fruit-apple-green.svg'
23 | )
24 | expect(statusCode).to.equal(200)
25 | expect(body).to.satisfy(isSvg).and.to.include('fruit').and.to.include('apple')
26 | })
27 |
--------------------------------------------------------------------------------
/services/cocoapods/cocoapods-license.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 |
5 | t.create('license (valid)')
6 | .get('/AFNetworking.json')
7 | .expectBadge({ label: 'license', message: 'MIT' })
8 |
9 | t.create('missing license')
10 | .get('/TespoTextField.json')
11 | .intercept(nock =>
12 | nock('https://trunk.cocoapods.org')
13 | .get('/api/v1/pods/TespoTextField/specs/latest')
14 | .reply(200, {
15 | version: '1.0.7',
16 | platforms: { ios: '8.0' },
17 | })
18 | )
19 | .expectBadge({ label: 'license', message: 'not specified' })
20 |
21 | t.create('license (not found)')
22 | .get('/not-a-package.json')
23 | .expectBadge({ label: 'license', message: 'not found' })
24 |
--------------------------------------------------------------------------------
/services/npm/npm-collaborators.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { nonNegativeInteger } = require('../validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('gets the contributor count')
7 | .get('/prettier.json')
8 | .expectBadge({ label: 'npm collaborators', message: nonNegativeInteger })
9 |
10 | t.create('gets the contributor count from a custom registry')
11 | .get('/prettier.json?registry_uri=https://registry.npmjs.com')
12 | .expectBadge({ label: 'npm collaborators', message: nonNegativeInteger })
13 |
14 | t.create('contributor count for unknown package')
15 | .get('/npm-registry-does-not-have-this-package.json')
16 | .expectBadge({
17 | label: 'npm collaborators',
18 | message: 'package not found',
19 | })
20 |
--------------------------------------------------------------------------------
/services/symfony/symfony-insight-stars.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 | const { withRegex } = require('../test-validators')
5 | const { sampleProjectUuid, noSymfonyToken } = require('./symfony-test-helpers')
6 |
7 | t.create('valid project stars')
8 | .skipWhen(noSymfonyToken)
9 | .get(`/${sampleProjectUuid}.json`)
10 | .timeout(15000)
11 | .expectBadge({
12 | label: 'stars',
13 | message: withRegex(
14 | /^(?=.{4}$)(\u2605{0,4}[\u00BC\u00BD\u00BE]?\u2606{0,4})$/
15 | ),
16 | })
17 |
18 | t.create('stars: nonexistent project')
19 | .skipWhen(noSymfonyToken)
20 | .get('/abc.json')
21 | .expectBadge({
22 | label: 'symfony insight',
23 | message: 'project not found',
24 | })
25 |
--------------------------------------------------------------------------------
/services/chrome-web-store/chrome-web-store-price.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('Price')
7 | .get('/alhjnofcnnpeaphgeakdhkebafjcpeae.json')
8 | .expectBadge({
9 | label: 'price',
10 | message: Joi.string().regex(/^\$\d+(.\d{1,2})?$/),
11 | })
12 |
13 | t.create('Price (not found)')
14 | .get('/invalid-name-of-addon.json')
15 | .expectBadge({ label: 'price', message: 'not found' })
16 |
17 | // Keep this "inaccessible" test, since this service does not use BaseService#_request.
18 | t.create('Price (inaccessible)')
19 | .get('/alhjnofcnnpeaphgeakdhkebafjcpeae.json')
20 | .networkOff()
21 | .expectBadge({ label: 'price', message: 'inaccessible' })
22 |
--------------------------------------------------------------------------------
/services/codecov/codecov-redirect.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { redirector } = require('..')
4 |
5 | const vcsSNameShortFormMap = {
6 | bb: 'bitbucket',
7 | gh: 'github',
8 | gl: 'gitlab',
9 | }
10 |
11 | module.exports = [
12 | redirector({
13 | category: 'coverage',
14 | route: {
15 | base: 'codecov/c',
16 | pattern:
17 | 'token/:token/:vcsName(github|gh|bitbucket|bb|gl|gitlab)/:user/:repo/:branch*',
18 | },
19 | transformPath: ({ vcsName, user, repo, branch }) => {
20 | const vcs = vcsSNameShortFormMap[vcsName] || vcsName
21 | return `/codecov/c/${vcs}/${user}/${repo}${branch ? `/${branch}` : ''}`
22 | },
23 | transformQueryParams: ({ token }) => ({ token }),
24 | dateAdded: new Date('2019-03-04'),
25 | }),
26 | ]
27 |
--------------------------------------------------------------------------------
/services/jenkins/jenkins-base.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { BaseJsonService } = require('..')
4 |
5 | module.exports = class JenkinsBase extends BaseJsonService {
6 | static get auth() {
7 | return {
8 | userKey: 'jenkins_user',
9 | passKey: 'jenkins_pass',
10 | serviceKey: 'jenkins',
11 | }
12 | }
13 |
14 | async fetch({
15 | url,
16 | schema,
17 | qs,
18 | errorMessages = { 404: 'instance or job not found' },
19 | disableStrictSSL,
20 | }) {
21 | return this._requestJson(
22 | this.authHelper.withBasicAuth({
23 | url,
24 | options: {
25 | qs,
26 | strictSSL: disableStrictSSL === undefined,
27 | },
28 | schema,
29 | errorMessages,
30 | })
31 | )
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/services/vaadin-directory/vaadin-directory-version.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isSemver } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('latest version of the component (can have v prefixed or without)')
7 | .get('/v/vaadinvaadin-grid.json')
8 | .expectBadge({
9 | label: 'vaadin directory',
10 | message: isSemver,
11 | })
12 |
13 | t.create('latest version of the component (can have v prefixed or without)')
14 | .get('/version/vaadinvaadin-grid.json')
15 | .expectBadge({
16 | label: 'vaadin directory',
17 | message: isSemver,
18 | })
19 |
20 | t.create('not found').get('/v/does-not-exist.json').expectBadge({
21 | label: 'vaadin directory',
22 | message: 'not found',
23 | })
24 |
--------------------------------------------------------------------------------
/services/cocoapods/cocoapods-docs.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isIntegerPercentage } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('doc percent (valid)').get('/AFNetworking.json').expectBadge({
7 | label: 'docs',
8 | message: isIntegerPercentage,
9 | })
10 |
11 | t.create('doc percent (null)')
12 | .get('/AFNetworking.json')
13 | .intercept(nock =>
14 | nock('https://metrics.cocoapods.org')
15 | .get('/api/v1/pods/AFNetworking')
16 | .reply(200, '{"cocoadocs": {"doc_percent": null}}')
17 | )
18 | .expectBadge({ label: 'docs', message: '0%' })
19 |
20 | t.create('doc percent (not found)')
21 | .get('/not-a-package.json')
22 | .expectBadge({ label: 'docs', message: 'not found' })
23 |
--------------------------------------------------------------------------------
/services/contributor-count.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { test, given } = require('sazerac')
4 | const { renderContributorBadge } = require('./contributor-count')
5 |
6 | describe('Contributor count helpers', function () {
7 | test(renderContributorBadge, () => {
8 | given({ label: 'maintainers', contributorCount: 1 }).expect({
9 | label: 'maintainers',
10 | message: '1',
11 | color: 'red',
12 | })
13 | given({ label: 'collaborators', contributorCount: 2 }).expect({
14 | label: 'collaborators',
15 | message: '2',
16 | color: 'yellow',
17 | })
18 | given({ label: 'collaborators', contributorCount: 3000 }).expect({
19 | label: 'collaborators',
20 | message: '3k',
21 | color: 'brightgreen',
22 | })
23 | })
24 | })
25 |
--------------------------------------------------------------------------------
/services/youtube/youtube-views.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 | const { noToken } = require('../test-helpers')
5 | const { isMetric } = require('../test-validators')
6 | const noYouTubeToken = noToken(require('./youtube-views.service'))
7 |
8 | t.create('video view count')
9 | .skipWhen(noYouTubeToken)
10 | .get('/abBdk8bSPKU.json')
11 | .expectBadge({
12 | label: 'views',
13 | message: isMetric,
14 | color: 'red',
15 | link: ['https://www.youtube.com/watch?v=abBdk8bSPKU'],
16 | })
17 |
18 | t.create('video not found')
19 | .skipWhen(noYouTubeToken)
20 | .get('/doesnotexist.json')
21 | .expectBadge({
22 | label: 'youtube',
23 | message: 'video not found',
24 | color: 'red',
25 | })
26 |
--------------------------------------------------------------------------------
/core/base-service/json.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | // See available emoji at http://emoji.muan.co/
4 | const emojic = require('emojic')
5 | const { InvalidResponse } = require('./errors')
6 | const trace = require('./trace')
7 |
8 | function parseJson(buffer) {
9 | const logTrace = (...args) => trace.logTrace('fetch', ...args)
10 | let json
11 | try {
12 | json = JSON.parse(buffer)
13 | } catch (err) {
14 | logTrace(emojic.dart, 'Response JSON (unparseable)', buffer)
15 | throw new InvalidResponse({
16 | prettyMessage: 'unparseable json response',
17 | underlyingError: err,
18 | })
19 | }
20 | logTrace(emojic.dart, 'Response JSON (before validation)', json, {
21 | deep: true,
22 | })
23 | return json
24 | }
25 |
26 | module.exports = {
27 | parseJson,
28 | }
29 |
--------------------------------------------------------------------------------
/services/keybase/keybase-btc.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { withRegex } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('existing bitcoin address')
7 | .get('/skyplabs.json')
8 | .expectBadge({
9 | label: 'btc',
10 | message: withRegex(/^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$/),
11 | })
12 |
13 | t.create('unknown username').get('/skyplabsssssss.json').expectBadge({
14 | label: 'btc',
15 | message: 'profile not found',
16 | })
17 |
18 | t.create('invalid username').get('/s.json').expectBadge({
19 | label: 'btc',
20 | message: 'invalid username',
21 | })
22 |
23 | t.create('missing bitcoin address').get('/test.json').expectBadge({
24 | label: 'btc',
25 | message: 'no bitcoin addresses found',
26 | })
27 |
--------------------------------------------------------------------------------
/badge-maker/index.test-d.ts:
--------------------------------------------------------------------------------
1 | import { expectType, expectError, expectAssignable } from 'tsd'
2 | import { makeBadge, ValidationError } from '.'
3 |
4 | expectError(makeBadge('string is invalid'))
5 | expectError(makeBadge({}))
6 | expectError(
7 | makeBadge({
8 | message: 'passed',
9 | style: 'invalid style',
10 | })
11 | )
12 |
13 | expectType(
14 | makeBadge({
15 | message: 'passed',
16 | })
17 | )
18 | expectType(
19 | makeBadge({
20 | label: 'build',
21 | message: 'passed',
22 | })
23 | )
24 | expectType(
25 | makeBadge({
26 | label: 'build',
27 | message: 'passed',
28 | labelColor: 'green',
29 | color: 'red',
30 | style: 'flat',
31 | })
32 | )
33 |
34 | const error = new ValidationError()
35 | expectAssignable(error)
36 |
--------------------------------------------------------------------------------
/services/conda/conda-downloads.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isMetric } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('downloads').get('/d/conda-forge/zlib.json').expectBadge({
7 | label: 'conda|downloads',
8 | message: isMetric,
9 | })
10 |
11 | t.create('downloads (skip prefix)')
12 | .get('/dn/conda-forge/zlib.json')
13 | .expectBadge({ label: 'downloads', message: isMetric })
14 |
15 | t.create('unknown package')
16 | .get('/d/conda-forge/some-bogus-package-that-never-exists.json')
17 | .expectBadge({ label: 'conda', message: 'not found' })
18 |
19 | t.create('unknown channel')
20 | .get('/d/some-bogus-channel-that-never-exists/zlib.json')
21 | .expectBadge({ label: 'conda', message: 'not found' })
22 |
--------------------------------------------------------------------------------
/services/github/github-last-commit.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isFormattedDate } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('last commit (recent)')
7 | .get('/eslint/eslint.json')
8 | .expectBadge({ label: 'last commit', message: isFormattedDate })
9 |
10 | t.create('last commit (ancient)')
11 | .get('/badges/badgr.co.json')
12 | .expectBadge({ label: 'last commit', message: 'january 2014' })
13 |
14 | t.create('last commit (on branch)')
15 | .get('/badges/badgr.co/shielded.json')
16 | .expectBadge({ label: 'last commit', message: 'july 2013' })
17 |
18 | t.create('last commit (repo not found)')
19 | .get('/badges/helmets.json')
20 | .expectBadge({ label: 'last commit', message: 'repo not found' })
21 |
--------------------------------------------------------------------------------
/services/homebrew/homebrew-cask.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isVPlusTripleDottedVersion } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('homebrew cask (valid)').get('/iterm2.json').expectBadge({
7 | label: 'homebrew cask',
8 | message: isVPlusTripleDottedVersion,
9 | })
10 |
11 | t.create('homebrew cask (valid)')
12 | .get('/iterm2.json')
13 | .intercept(nock =>
14 | nock('https://formulae.brew.sh')
15 | .get('/api/cask/iterm2.json')
16 | .reply(200, { version: '3.3.6' })
17 | )
18 | .expectBadge({ label: 'homebrew cask', message: 'v3.3.6' })
19 |
20 | t.create('homebrew cask (not found)')
21 | .get('/not-a-package.json')
22 | .expectBadge({ label: 'homebrew cask', message: 'not found' })
23 |
--------------------------------------------------------------------------------
/services/homebrew/homebrew.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isVPlusTripleDottedVersion } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('homebrew (valid)').get('/cake.json').expectBadge({
7 | label: 'homebrew',
8 | message: isVPlusTripleDottedVersion,
9 | })
10 |
11 | t.create('homebrew (valid)')
12 | .get('/cake.json')
13 | .intercept(nock =>
14 | nock('https://formulae.brew.sh')
15 | .get('/api/formula/cake.json')
16 | .reply(200, { versions: { stable: '0.23.0', devel: null, head: null } })
17 | )
18 | .expectBadge({ label: 'homebrew', message: 'v0.23.0' })
19 |
20 | t.create('homebrew (not found)')
21 | .get('/not-a-package.json')
22 | .expectBadge({ label: 'homebrew', message: 'not found' })
23 |
--------------------------------------------------------------------------------
/services/symfony/symfony-insight-violations.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 | const { withRegex } = require('../test-validators')
5 | const { sampleProjectUuid, noSymfonyToken } = require('./symfony-test-helpers')
6 |
7 | t.create('valid project violations')
8 | .skipWhen(noSymfonyToken)
9 | .get(`/${sampleProjectUuid}.json`)
10 | .timeout(15000)
11 | .expectBadge({
12 | label: 'violations',
13 | message: withRegex(
14 | /\d* critical|\d* critical, \d* major|\d* critical, \d* major, \d* minor|\d* critical, \d* major, \d* minor, \d* info|\d* critical, \d* minor|\d* critical, \d* info|\d* major|\d* major, \d* minor|\d* major, \d* minor, \d* info|\d* major, \d* info|\d* minor|\d* minor, \d* info/
15 | ),
16 | })
17 |
--------------------------------------------------------------------------------
/services/youtube/youtube-comments.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 | const { noToken } = require('../test-helpers')
5 | const { isMetric } = require('../test-validators')
6 | const noYouTubeToken = noToken(require('./youtube-comments.service'))
7 |
8 | t.create('video comment count')
9 | .skipWhen(noYouTubeToken)
10 | .get('/wGJHwc5ksMA.json')
11 | .expectBadge({
12 | label: 'comments',
13 | message: isMetric,
14 | color: 'red',
15 | link: ['https://www.youtube.com/watch?v=wGJHwc5ksMA'],
16 | })
17 |
18 | t.create('video not found')
19 | .skipWhen(noYouTubeToken)
20 | .get('/doesnotexist.json')
21 | .expectBadge({
22 | label: 'youtube',
23 | message: 'video not found',
24 | color: 'red',
25 | })
26 |
--------------------------------------------------------------------------------
/services/pypi/pypi-implementation.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 |
5 | t.create('implementation (valid, package version in request)')
6 | .get('/beehive/1.0.json')
7 | .expectBadge({ label: 'implementation', message: 'cpython | jython | pypy' })
8 |
9 | t.create('implementation (valid, no package version specified)')
10 | .get('/numpy.json')
11 | .expectBadge({ label: 'implementation', message: 'cpython' })
12 |
13 | t.create('implementation (not specified)')
14 | .get('/chai/1.1.2.json')
15 | .expectBadge({ label: 'implementation', message: 'cpython' })
16 |
17 | t.create('implementation (invalid)').get('/not-a-package.json').expectBadge({
18 | label: 'implementation',
19 | message: 'package or version not found',
20 | })
21 |
--------------------------------------------------------------------------------
/config/default.yml:
--------------------------------------------------------------------------------
1 | public:
2 | bind:
3 | address: '::'
4 |
5 | metrics:
6 | prometheus:
7 | enabled: false
8 | endpointEnabled: false
9 | influx:
10 | enabled: false
11 | timeoutMilliseconds: 1000
12 | intervalSeconds: 15
13 | ssl:
14 | isSecure: false
15 |
16 | cors:
17 | allowedOrigin: []
18 |
19 | persistence:
20 | dir: './private'
21 |
22 | services:
23 | github:
24 | baseUri: 'https://api.github.com/'
25 | debug:
26 | enabled: false
27 | intervalSeconds: 200
28 | trace: false
29 |
30 | cacheHeaders:
31 | defaultCacheLengthSeconds: 120
32 |
33 | rateLimit: true
34 |
35 | handleInternalErrors: true
36 |
37 | fetchLimit: '10MB'
38 |
39 | shieldsProductionHerokuHacks: false
40 |
41 | private: {}
42 |
--------------------------------------------------------------------------------
/services/appveyor/appveyor-job-build.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isBuildStatus } = require('../build-status')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('Job CI status')
7 | .timeout(10000)
8 | .get('/wpmgprostotema/voicetranscoder/Windows.json')
9 | .expectBadge({ label: 'build', message: isBuildStatus })
10 |
11 | t.create('Job CI status on branch')
12 | .timeout(10000)
13 | .get('/wpmgprostotema/voicetranscoder/Linux/master.json')
14 | .expectBadge({ label: 'build', message: isBuildStatus })
15 |
16 | t.create('Job CI status on nonexistent project')
17 | .timeout(10000)
18 | .get('/somerandomproject/thatdoesntexist/foo.json')
19 | .expectBadge({
20 | label: 'build',
21 | message: 'project not found or access denied',
22 | })
23 |
--------------------------------------------------------------------------------
/services/hackage/hackage-version.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isVPlusDottedVersionAtLeastOne } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('hackage version (valid)').get('/lens.json').expectBadge({
7 | label: 'hackage',
8 | message: isVPlusDottedVersionAtLeastOne,
9 | })
10 |
11 | t.create('hackage version (not found)')
12 | .get('/not-a-package.json')
13 | .expectBadge({ label: 'hackage', message: 'not found' })
14 |
15 | t.create('hackage version (unexpected response)')
16 | .get('/lens.json')
17 | .intercept(nock =>
18 | nock('https://hackage.haskell.org')
19 | .get('/package/lens/lens.cabal')
20 | .reply(200, '')
21 | )
22 | .expectBadge({ label: 'hackage', message: 'invalid response data' })
23 |
--------------------------------------------------------------------------------
/services/node/node-lts.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { test, given } = require('sazerac')
4 | const NodeVersion = require('./node-lts.service')
5 |
6 | describe('node-lts renderStaticPreview', function () {
7 | it('should have parity with render()', async function () {
8 | const nodeVersionRange = '>= 6.0.0'
9 |
10 | const expectedNoTag = await NodeVersion.renderStaticPreview({
11 | nodeVersionRange,
12 | })
13 | const expectedLatestTag = await NodeVersion.renderStaticPreview({
14 | nodeVersionRange,
15 | tag: 'latest',
16 | })
17 |
18 | test(NodeVersion.renderStaticPreview.bind(NodeVersion), () => {
19 | given({ nodeVersionRange }).expect(expectedNoTag)
20 | given({ nodeVersionRange, tag: 'latest' }).expect(expectedLatestTag)
21 | })
22 | })
23 | })
24 |
--------------------------------------------------------------------------------
/services/pkgreview/package-rating.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { withRegex, isStarRating } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | const isRatingWithReviews = withRegex(
7 | /^(([0-4](.?([0-9]))?)|5)\/5?\s*\([0-9]*\)$/
8 | )
9 |
10 | t.create('Stars Badge renders')
11 | .get('/stars/npm/react.json')
12 | .expectBadge({ label: 'stars', message: isStarRating })
13 |
14 | t.create('Rating Badge renders')
15 | .get('/rating/npm/react.json')
16 | .expectBadge({ label: 'rating', message: isRatingWithReviews })
17 |
18 | t.create('nonexistent package')
19 | .get('/rating/npm/ohlolweallknowthispackagewontexist.json')
20 | .expectBadge({
21 | label: 'rating',
22 | message: 'package not found',
23 | color: 'red',
24 | })
25 |
--------------------------------------------------------------------------------
/services/node/node-current.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { test, given } = require('sazerac')
4 | const NodeVersion = require('./node-current.service')
5 |
6 | describe('node static renderStaticPreview', function () {
7 | it('should have parity with render()', async function () {
8 | const nodeVersionRange = '>= 6.0.0'
9 |
10 | const expectedNoTag = await NodeVersion.renderStaticPreview({
11 | nodeVersionRange,
12 | })
13 | const expectedLatestTag = await NodeVersion.renderStaticPreview({
14 | nodeVersionRange,
15 | tag: 'latest',
16 | })
17 |
18 | test(NodeVersion.renderStaticPreview.bind(NodeVersion), () => {
19 | given({ nodeVersionRange }).expect(expectedNoTag)
20 | given({ nodeVersionRange, tag: 'latest' }).expect(expectedLatestTag)
21 | })
22 | })
23 | })
24 |
--------------------------------------------------------------------------------
/services/packagist/packagist-license.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { expect } = require('chai')
4 | const { NotFound } = require('..')
5 | const PackagistLicense = require('./packagist-license.service')
6 |
7 | describe('PackagistLicense', function () {
8 | it('should throw NotFound when default branch is missing', function () {
9 | const json = {
10 | packages: {
11 | 'doctrine/orm': {},
12 | 'elhadraoui/doctrine-orm': {
13 | 'dev-master': { license: 'MIT' },
14 | },
15 | },
16 | }
17 | expect(() =>
18 | PackagistLicense.prototype.transform({
19 | json,
20 | user: 'doctrine',
21 | repo: 'orm',
22 | })
23 | )
24 | .to.throw(NotFound)
25 | .with.property('prettyMessage', 'default branch not found')
26 | })
27 | })
28 |
--------------------------------------------------------------------------------
/services/requires/requires.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | const isRequireStatus = Joi.string().regex(
7 | /^(up to date|outdated|insecure|unknown)$/
8 | )
9 |
10 | t.create('requirements (valid, without branch)')
11 | .get('/github/celery/celery.json')
12 | .expectBadge({
13 | label: 'requirements',
14 | message: isRequireStatus,
15 | })
16 |
17 | t.create('requirements (valid, with branch)')
18 | .get('/github/celery/celery/master.json')
19 | .expectBadge({
20 | label: 'requirements',
21 | message: isRequireStatus,
22 | })
23 |
24 | t.create('requirements (not found)')
25 | .get('/github/PyvesB/EmptyRepo.json')
26 | .expectBadge({ label: 'requirements', message: 'not found' })
27 |
--------------------------------------------------------------------------------
/services/static-badge/query-string-static.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const { BaseStaticService } = require('..')
5 |
6 | const queryParamSchema = Joi.object({
7 | message: Joi.string().required(),
8 | }).required()
9 |
10 | module.exports = class QueryStringStaticBadge extends BaseStaticService {
11 | static get category() {
12 | return 'static'
13 | }
14 |
15 | static get route() {
16 | return {
17 | base: '',
18 | pattern: 'static/:schemaVersion(v1)',
19 | // All but one of the parameters are parsed via coalesceBadge. This
20 | // reuses what is the override behaviour for other badges.
21 | queryParamSchema,
22 | }
23 | }
24 |
25 | handle(namedParams, queryParams) {
26 | return { message: queryParams.message }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/services/vaadin-directory/vaadin-directory-release-date.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isFormattedDate } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('latest release date of the component (format: yyyy-mm-dd)')
7 | .get('/rd/vaadinvaadin-grid.json')
8 | .expectBadge({
9 | label: 'latest release date',
10 | message: isFormattedDate,
11 | })
12 |
13 | t.create('latest release date of the component (format: yyyy-mm-dd)')
14 | .get('/release-date/vaadinvaadin-grid.json')
15 | .expectBadge({
16 | label: 'latest release date',
17 | message: isFormattedDate,
18 | })
19 |
20 | t.create('not found')
21 | .get('/release-date/does-not-exist.json')
22 | .expectBadge({ label: 'latest release date', message: 'not found' })
23 |
--------------------------------------------------------------------------------
/lib/load-simple-icons.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const originalSimpleIcons = require('simple-icons')
4 | const { svg2base64 } = require('./svg-helpers')
5 |
6 | function loadSimpleIcons() {
7 | const simpleIcons = {}
8 | Object.keys(originalSimpleIcons).forEach(key => {
9 | const k = key.toLowerCase().replace(/ /g, '-')
10 | simpleIcons[k] = originalSimpleIcons[key]
11 | simpleIcons[k].base64 = {
12 | default: svg2base64(
13 | simpleIcons[k].svg.replace('
--------------------------------------------------------------------------------
/services/cocoapods/cocoapods-base.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const { BaseJsonService } = require('..')
5 |
6 | const schema = Joi.object({
7 | version: Joi.string().required(),
8 | // https://github.com/badges/shields/issues/4688
9 | license: Joi.alternatives(
10 | Joi.string().required(),
11 | Joi.object({
12 | type: Joi.string().required(),
13 | }).required()
14 | ),
15 | // https://github.com/badges/shields/pull/209
16 | platforms: Joi.object().default({ ios: '5.0', osx: '10.7' }),
17 | }).required()
18 |
19 | module.exports = class BaseCocoaPodsService extends BaseJsonService {
20 | async fetch({ spec }) {
21 | return this._requestJson({
22 | schema,
23 | url: `https://trunk.cocoapods.org/api/v1/pods/${spec}/specs/latest`,
24 | })
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/services/librariesio/librariesio-dependent-repos.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isMetric } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('dependent repo count')
7 | .timeout(10000)
8 | .get('/npm/got.json')
9 | .expectBadge({
10 | label: 'dependent repos',
11 | message: isMetric,
12 | })
13 |
14 | t.create('dependent repo count (scoped npm package)')
15 | .timeout(10000)
16 | .get('/npm/@babel/core.json')
17 | .expectBadge({
18 | label: 'dependent repos',
19 | message: isMetric,
20 | })
21 |
22 | t.create('dependent repo count (not a package)')
23 | .timeout(10000)
24 | .get('/npm/foobar-is-not-package.json')
25 | .expectBadge({
26 | label: 'dependent repos',
27 | message: 'package not found',
28 | })
29 |
--------------------------------------------------------------------------------
/core/service-test-runner/services-for-title.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { test, given } = require('sazerac')
4 | const servicesForTitle = require('./services-for-title')
5 |
6 | describe('Services from PR title', function () {
7 | test(servicesForTitle, () => {
8 | given('[Travis] Fix timeout issues').expect(['travis'])
9 | given('[Travis Sonar] Support user token authentication').expect([
10 | 'travis',
11 | 'sonar',
12 | ])
13 | given('[CRAN CPAN CTAN] Add test coverage').expect(['cran', 'cpan', 'ctan'])
14 | given(
15 | '[RFC] Add Joi-based request validation to BaseJsonService and rewrite [NPM] badges'
16 | ).expect(['npm'])
17 | given('make changes to [CRAN] and [CPAN]').expect(['cran', 'cpan'])
18 | given('[github appveyor ]').expect(['github', 'appveyor'])
19 | })
20 | })
21 |
--------------------------------------------------------------------------------
/services/maintenance/maintenance.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 |
5 | const currentYear = new Date().getUTCFullYear()
6 |
7 | t.create('yes last maintained 2016 (no)')
8 | .get('/yes/2016.json')
9 | .expectBadge({ label: 'maintained', message: 'no! (as of 2016)' })
10 |
11 | t.create('no longer maintained 2017 (no)')
12 | .get('/no/2017.json')
13 | .expectBadge({ label: 'maintained', message: 'no! (as of 2017)' })
14 |
15 | t.create('yes this year (yes)')
16 | .get(`/yes/${currentYear}.json`)
17 | .expectBadge({ label: 'maintained', message: 'yes' })
18 |
19 | t.create(`until end of ${currentYear} (yes)`)
20 | .get(`/until end of ${currentYear}/${currentYear}.json`)
21 | .expectBadge({ label: 'maintained', message: `until end of ${currentYear}` })
22 |
--------------------------------------------------------------------------------
/services/chrome-web-store/chrome-web-store-version.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isVPlusDottedVersionAtLeastOne } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('Version').get('/alhjnofcnnpeaphgeakdhkebafjcpeae.json').expectBadge({
7 | label: 'chrome web store',
8 | message: isVPlusDottedVersionAtLeastOne,
9 | })
10 |
11 | t.create('Version (not found)')
12 | .get('/invalid-name-of-addon.json')
13 | .expectBadge({ label: 'chrome web store', message: 'not found' })
14 |
15 | // Keep this "inaccessible" test, since this service does not use BaseService#_request.
16 | t.create('Version (inaccessible)')
17 | .get('/alhjnofcnnpeaphgeakdhkebafjcpeae.json')
18 | .networkOff()
19 | .expectBadge({ label: 'chrome web store', message: 'inaccessible' })
20 |
--------------------------------------------------------------------------------
/services/liberapay/liberapay-gives.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 | const { isCurrencyOverTime } = require('./liberapay-base')
5 |
6 | t.create('Giving (valid)').get('/Changaco.json').expectBadge({
7 | label: 'gives',
8 | message: isCurrencyOverTime,
9 | })
10 |
11 | t.create('Giving (not found)')
12 | .get('/does-not-exist.json')
13 | .expectBadge({ label: 'liberapay', message: 'not found' })
14 |
15 | t.create('Giving (null)')
16 | .get('/Liberapay.json')
17 | .intercept(nock =>
18 | nock('https://liberapay.com').get('/Liberapay/public.json').reply(200, {
19 | npatrons: 0,
20 | giving: null,
21 | receiving: null,
22 | goal: null,
23 | })
24 | )
25 | .expectBadge({ label: 'liberapay', message: 'no public giving stats' })
26 |
--------------------------------------------------------------------------------
/services/symfony/symfony-insight-grade.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 | const { sampleProjectUuid, noSymfonyToken } = require('./symfony-test-helpers')
6 |
7 | t.create('valid project grade')
8 | .skipWhen(noSymfonyToken)
9 | .get(`/${sampleProjectUuid}.json`)
10 | .timeout(15000)
11 | .expectBadge({
12 | label: 'grade',
13 | message: Joi.equal(
14 | 'platinum',
15 | 'gold',
16 | 'silver',
17 | 'bronze',
18 | 'no medal'
19 | ).required(),
20 | })
21 |
22 | t.create('nonexistent project')
23 | .skipWhen(noSymfonyToken)
24 | .get('/45afb680-d4e6-4e66-93ea-bcfa79eb8a88.json')
25 | .expectBadge({
26 | label: 'symfony insight',
27 | message: 'project not found',
28 | })
29 |
--------------------------------------------------------------------------------
/services/website-status.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { test, given } = require('sazerac')
4 | const { renderWebsiteStatus } = require('./website-status')
5 |
6 | describe('Website status helpers', function () {
7 | const customOptions = {
8 | upMessage: 'groovy',
9 | upColor: 'papayawhip',
10 | downMessage: 'no good',
11 | downColor: 'gray',
12 | }
13 |
14 | test(renderWebsiteStatus, () => {
15 | given({ isUp: true }).expect({ message: 'up', color: 'brightgreen' })
16 | given({ isUp: false }).expect({ message: 'down', color: 'red' })
17 | given({ isUp: true, ...customOptions }).expect({
18 | message: 'groovy',
19 | color: 'papayawhip',
20 | })
21 | given({ isUp: false, ...customOptions }).expect({
22 | message: 'no good',
23 | color: 'gray',
24 | })
25 | })
26 | })
27 |
--------------------------------------------------------------------------------
/services/cran/cran.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 | const { isVPlusTripleDottedVersion } = require('../test-validators')
5 |
6 | const t = (module.exports = new ServiceTester({
7 | id: 'cran',
8 | title: 'CRAN/METACRAN',
9 | }))
10 |
11 | t.create('version (valid)').get('/v/devtools.json').expectBadge({
12 | label: 'cran',
13 | message: isVPlusTripleDottedVersion,
14 | })
15 |
16 | t.create('version (not found)')
17 | .get('/v/some-bogus-package.json')
18 | .expectBadge({ label: 'cran', message: 'not found' })
19 |
20 | t.create('license (valid)')
21 | .get('/l/devtools.json')
22 | .expectBadge({ label: 'license', message: 'GPL (>= 2)' })
23 |
24 | t.create('license (not found)')
25 | .get('/l/some-bogus-package.json')
26 | .expectBadge({ label: 'cran', message: 'not found' })
27 |
--------------------------------------------------------------------------------
/services/pypi/pypi-format.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 |
5 | t.create('format (wheel, package version in request)')
6 | .get('/requests/2.18.4.json')
7 | .expectBadge({ label: 'format', message: 'wheel' })
8 |
9 | t.create('format (wheel, no package version specified)')
10 | .get('/requests.json')
11 | .expectBadge({ label: 'format', message: 'wheel' })
12 |
13 | t.create('format (source)')
14 | .get('/chai/1.1.2.json')
15 | .expectBadge({ label: 'format', message: 'source' })
16 |
17 | t.create('format (egg)')
18 | .get('/virtualenv/0.8.2.json')
19 | .expectBadge({ label: 'format', message: 'egg' })
20 |
21 | t.create('format (invalid)')
22 | .get('/not-a-package.json')
23 | .expectBadge({ label: 'format', message: 'package or version not found' })
24 |
--------------------------------------------------------------------------------
/services/spiget/spiget-rating.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isStarRating, withRegex } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('Stars - EssentialsX (id 9089)').get('/stars/9089.json').expectBadge({
7 | label: 'rating',
8 | message: isStarRating,
9 | })
10 |
11 | t.create('Stars - Invalid Resource (id 1)').get('/stars/1.json').expectBadge({
12 | label: 'rating',
13 | message: 'not found',
14 | })
15 |
16 | t.create('Rating - EssentialsX (id 9089)')
17 | .get('/rating/9089.json')
18 | .expectBadge({
19 | label: 'rating',
20 | message: withRegex(/^(\d*\.\d+)(\/5 \()(\d+)(\))$/),
21 | })
22 |
23 | t.create('Rating - Invalid Resource (id 1)').get('/rating/1.json').expectBadge({
24 | label: 'rating',
25 | message: 'not found',
26 | })
27 |
--------------------------------------------------------------------------------
/services/bithound/bithound.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 |
5 | const t = (module.exports = new ServiceTester({
6 | id: 'bithound',
7 | title: 'BitHound',
8 | }))
9 |
10 | t.create('no longer available (code)')
11 | .get('/code/github/rexxars/sse-channel.json')
12 | .expectBadge({
13 | label: 'bithound',
14 | message: 'no longer available',
15 | })
16 |
17 | t.create('no longer available (dependencies)')
18 | .get('/dependencies/github/rexxars/sse-channel.json')
19 | .expectBadge({
20 | label: 'bithound',
21 | message: 'no longer available',
22 | })
23 |
24 | t.create('no longer available (devDpendencies)')
25 | .get('/devDependencies/github/rexxars/sse-channel.json')
26 | .expectBadge({
27 | label: 'bithound',
28 | message: 'no longer available',
29 | })
30 |
--------------------------------------------------------------------------------
/services/offset-earth/offset-earth-trees.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 | const { isMetric } = require('../test-validators')
5 |
6 | t.create('request for existing username').get('/offsetearth.json').expectBadge({
7 | label: 'trees',
8 | message: isMetric,
9 | })
10 |
11 | t.create('request for existing username')
12 | .get('/offsetearth.json')
13 | .intercept(nock =>
14 | nock('https://public.offset.earth')
15 | .get('/users/offsetearth/trees')
16 | .reply(200, { total: 50 })
17 | )
18 | .expectBadge({
19 | label: 'trees',
20 | message: '50',
21 | color: 'green',
22 | })
23 |
24 | t.create('invalid username')
25 | .get('/non-existent-username.json')
26 | .expectBadge({ label: 'trees', message: 'username not found', color: 'red' })
27 |
--------------------------------------------------------------------------------
/services/continuousphp/continuousphp.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const { isBuildStatus } = require('../build-status')
5 | const t = (module.exports = require('../tester').createServiceTester())
6 |
7 | t.create('build status on default branch')
8 | .get('/git-hub/doctrine/dbal.json')
9 | .expectBadge({
10 | label: 'build',
11 | message: Joi.alternatives().try(isBuildStatus, Joi.equal('unknown')),
12 | })
13 |
14 | t.create('build status on named branch')
15 | .get('/git-hub/doctrine/dbal/develop.json')
16 | .expectBadge({
17 | label: 'build',
18 | message: Joi.alternatives().try(isBuildStatus, Joi.equal('unknown')),
19 | })
20 |
21 | t.create('unknown repo')
22 | .get('/git-hub/this-repo/does-not-exist.json')
23 | .expectBadge({ label: 'continuousphp', message: 'project not found' })
24 |
--------------------------------------------------------------------------------
/services/sourcegraph/sourcegraph.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { withRegex } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | // Matches API responses such as "0 projects", "1 projects", "182 projects", "14.0k projects".
7 | // There may be other cases not covered by this regex, but hopefully the tested projects won't vary much.
8 | const projectsCount = withRegex(/^[0-9]*(\.[0-9]k)?\sprojects$/)
9 |
10 | t.create('project usage count')
11 | .get('/github.com/theupdateframework/notary.json')
12 | .expectBadge({
13 | label: 'used by',
14 | message: projectsCount,
15 | })
16 |
17 | t.create('project without any available information')
18 | .get('/github.com/badges/daily-tests.json')
19 | .expectBadge({
20 | label: 'used by',
21 | message: '0 projects',
22 | })
23 |
--------------------------------------------------------------------------------
/services/liberapay/liberapay-receives.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 | const { isCurrencyOverTime } = require('./liberapay-base')
5 |
6 | t.create('Receiving (valid)').get('/Changaco.json').expectBadge({
7 | label: 'receives',
8 | message: isCurrencyOverTime,
9 | })
10 |
11 | t.create('Receiving (not found)')
12 | .get('/does-not-exist.json')
13 | .expectBadge({ label: 'liberapay', message: 'not found' })
14 |
15 | t.create('Receiving (null)')
16 | .get('/Liberapay.json')
17 | .intercept(nock =>
18 | nock('https://liberapay.com').get('/Liberapay/public.json').reply(200, {
19 | npatrons: 0,
20 | giving: null,
21 | receiving: null,
22 | goal: null,
23 | })
24 | )
25 | .expectBadge({ label: 'liberapay', message: 'no public receiving stats' })
26 |
--------------------------------------------------------------------------------
/services/travis/travis-php-version-redirect.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { redirector } = require('..')
4 |
5 | const ciRedirect = redirector({
6 | category: 'platform-support',
7 | route: {
8 | base: 'travis-ci/php-v',
9 | pattern: ':user/:repo/:branch*',
10 | },
11 | transformPath: ({ user, repo, branch }) =>
12 | branch
13 | ? `/travis/php-v/${user}/${repo}/${branch}`
14 | : `/travis/php-v/${user}/${repo}/master`,
15 | dateAdded: new Date('2019-04-22'),
16 | })
17 |
18 | const branchRedirect = redirector({
19 | category: 'platform-support',
20 | route: {
21 | base: 'travis/php-v',
22 | pattern: ':user/:repo',
23 | },
24 | transformPath: ({ user, repo }) => `/travis/php-v/${user}/${repo}/master`,
25 | dateAdded: new Date('2020-07-12'),
26 | })
27 |
28 | module.exports = { ciRedirect, branchRedirect }
29 |
--------------------------------------------------------------------------------
/services/sonar/sonar-documented-api-density.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { test, given } = require('sazerac')
4 | const SonarDocumentedApiDensity = require('./sonar-documented-api-density.service')
5 |
6 | describe('SonarDocumentedApiDensity', function () {
7 | test(SonarDocumentedApiDensity.render, () => {
8 | given({ density: 0 }).expect({
9 | message: '0%',
10 | color: 'red',
11 | })
12 | given({ density: 10 }).expect({
13 | message: '10%',
14 | color: 'orange',
15 | })
16 | given({ density: 20 }).expect({
17 | message: '20%',
18 | color: 'yellow',
19 | })
20 | given({ density: 50 }).expect({
21 | message: '50%',
22 | color: 'yellowgreen',
23 | })
24 | given({ density: 100 }).expect({
25 | message: '100%',
26 | color: 'brightgreen',
27 | })
28 | })
29 | })
30 |
--------------------------------------------------------------------------------
/services/ansible/ansible-role.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { ServiceTester } = require('../tester')
4 | const { isMetric } = require('../test-validators')
5 |
6 | const t = (module.exports = new ServiceTester({
7 | id: 'AnsibleRole',
8 | title: 'AnsibleRole',
9 | pathPrefix: '/ansible/role',
10 | }))
11 |
12 | t.create('role name (valid)')
13 | .get('/14542.json')
14 | .expectBadge({ label: 'role', message: 'openwisp.openwisp2' })
15 |
16 | t.create('role name (not found)')
17 | .get('/000.json')
18 | .expectBadge({ label: 'role', message: 'not found' })
19 |
20 | t.create('role downloads (valid)')
21 | .get('/d/14542.json')
22 | .expectBadge({ label: 'role downloads', message: isMetric })
23 |
24 | t.create('role downloads (not found)')
25 | .get('/d/does-not-exist.json')
26 | .expectBadge({ label: 'role downloads', message: 'not found' })
27 |
--------------------------------------------------------------------------------
/services/github/github-lerna-json.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isSemver } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('Lerna version').get('/babel/babel.json').expectBadge({
7 | label: 'lerna',
8 | message: isSemver,
9 | })
10 |
11 | t.create('Lerna version (independent)')
12 | .get('/jneander/jneander.json')
13 | .expectBadge({
14 | label: 'lerna',
15 | message: 'independent',
16 | })
17 |
18 | t.create('Lerna version (branch)').get('/babel/babel/master.json').expectBadge({
19 | label: 'lerna@master',
20 | message: isSemver,
21 | })
22 |
23 | t.create('Lerna version (lerna.json missing)')
24 | .get('/PyvesB/empty-repo.json')
25 | .expectBadge({
26 | label: 'lerna',
27 | message: 'repo not found, branch not found, or lerna.json missing',
28 | })
29 |
--------------------------------------------------------------------------------
/services/jenkins/jenkins-tests-redirector.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { redirector } = require('..')
4 | const { buildRedirectUrl } = require('./jenkins-common')
5 |
6 | const commonProps = {
7 | category: 'build',
8 | transformPath: () => '/jenkins/tests',
9 | transformQueryParams: ({ protocol, host, job }) => ({
10 | jobUrl: buildRedirectUrl({ protocol, host, job }),
11 | }),
12 | }
13 |
14 | module.exports = [
15 | redirector({
16 | route: {
17 | base: 'jenkins/t',
18 | pattern: ':protocol(http|https)/:host/:job+',
19 | },
20 | dateAdded: new Date('2019-04-20'),
21 | ...commonProps,
22 | }),
23 | redirector({
24 | route: {
25 | base: 'jenkins/tests',
26 | pattern: ':protocol(http|https)/:host/:job+',
27 | },
28 | dateAdded: new Date('2019-11-29'),
29 | ...commonProps,
30 | }),
31 | ]
32 |
--------------------------------------------------------------------------------
/services/liberapay/liberapay-goal.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { expect } = require('chai')
4 | const { test, given } = require('sazerac')
5 | const { InvalidResponse } = require('..')
6 | const LiberapayGoal = require('./liberapay-goal.service')
7 |
8 | describe('LiberapayGoal', function () {
9 | test(LiberapayGoal.prototype.transform, () => {
10 | given({ goal: {}, receiving: null }).expect({
11 | percentAchieved: 0,
12 | })
13 | given({ goal: { amount: 100 }, receiving: { amount: 89 } }).expect({
14 | percentAchieved: 89,
15 | })
16 | })
17 |
18 | it('throws InvalidResponse on missing goals', function () {
19 | expect(() =>
20 | LiberapayGoal.prototype.transform({ goal: null, receiving: null })
21 | )
22 | .to.throw(InvalidResponse)
23 | .with.property('prettyMessage', 'no public goals')
24 | })
25 | })
26 |
--------------------------------------------------------------------------------
/services/librariesio/librariesio-dependencies-helpers.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { test, given, forCases } = require('sazerac')
4 | const {
5 | renderDependenciesBadge,
6 | } = require('./librariesio-dependencies-helpers')
7 |
8 | describe('Libraries.io dependency helpers', function () {
9 | test(renderDependenciesBadge, () => {
10 | forCases([
11 | given({ deprecatedCount: 10, outdatedCount: 0 }),
12 | given({ deprecatedCount: 10, outdatedCount: 5 }),
13 | ]).expect({
14 | message: '10 deprecated',
15 | color: 'red',
16 | })
17 | given({ deprecatedCount: 0, outdatedCount: 5 }).expect({
18 | message: '5 out of date',
19 | color: 'orange',
20 | })
21 | given({ deprecatedCount: 0, outdatedCount: 0 }).expect({
22 | message: 'up to date',
23 | color: 'brightgreen',
24 | })
25 | })
26 | })
27 |
--------------------------------------------------------------------------------
/services/maven-metadata/maven-metadata-redirect.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const t = (module.exports = require('../tester').createServiceTester())
4 |
5 | t.create('maven metadata (badge extension)')
6 | .get(
7 | '/http/central.maven.org/maven2/com/google/code/gson/gson/maven-metadata.xml.json'
8 | )
9 | .expectRedirect(
10 | `/maven-metadata/v.json?metadataUrl=${encodeURIComponent(
11 | 'http://central.maven.org/maven2/com/google/code/gson/gson/maven-metadata.xml'
12 | )}`
13 | )
14 |
15 | t.create('maven metadata (no badge extension)')
16 | .get(
17 | '/http/central.maven.org/maven2/com/google/code/gson/gson/maven-metadata.xml'
18 | )
19 | .expectRedirect(
20 | `/maven-metadata/v.svg?metadataUrl=${encodeURIComponent(
21 | 'http://central.maven.org/maven2/com/google/code/gson/gson/maven-metadata.xml'
22 | )}`
23 | )
24 |
--------------------------------------------------------------------------------
/.github/probot.js:
--------------------------------------------------------------------------------
1 | on('pull_request.closed')
2 | .filter(context => context.payload.pull_request.merged)
3 | .filter(
4 | context =>
5 | context.payload.pull_request.head.ref.slice(0, 11) !== 'dependabot/'
6 | )
7 | .filter(context => context.payload.pull_request.base.ref === 'master')
8 | .comment(`This pull request was merged to [{{ pull_request.base.ref }}]({{ repository.html_url }}/tree/{{ pull_request.base.ref }}) branch. This change is now waiting for deployment, which will usually happen within a few days. Stay tuned by joining our \`#ops\` channel on [Discord](https://discordapp.com/invite/HjJCwm5)!
9 |
10 | After deployment, changes are copied to [gh-pages]({{ repository.html_url }}/tree/gh-pages) branch: `)
11 |
--------------------------------------------------------------------------------
/logo/serverfault.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/services/codefactor/codefactor-helpers.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 |
5 | // https://support.codefactor.io/i14-glossary
6 | // https://github.com/badges/shields/issues/4269
7 | const colorMap = {
8 | 'A+': 'brightgreen',
9 | A: 'brightgreen',
10 | 'A-': 'green',
11 | 'B+': 'yellowgreen',
12 | B: 'yellowgreen',
13 | 'B-': 'yellowgreen',
14 | 'C+': 'yellow',
15 | C: 'yellow',
16 | 'C-': 'yellow',
17 | 'D+': 'orange',
18 | D: 'orange',
19 | 'D-': 'orange',
20 | F: 'red',
21 | '-': 'lightgrey',
22 | }
23 |
24 | const isValidGrade = Joi.valid(...Object.keys(colorMap)).required()
25 |
26 | function gradeColor(grade) {
27 | const color = colorMap[grade]
28 | if (color === undefined) {
29 | throw Error(`Unknown grade: ${grade}`)
30 | }
31 | return color
32 | }
33 |
34 | module.exports = { isValidGrade, gradeColor }
35 |
--------------------------------------------------------------------------------
/services/conda/conda-base.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Joi = require('@hapi/joi')
4 | const { nonNegativeInteger } = require('../validators')
5 | const { BaseJsonService } = require('..')
6 |
7 | const condaSchema = Joi.object({
8 | latest_version: Joi.string().required(),
9 | conda_platforms: Joi.array().items(Joi.string()).required(),
10 | files: Joi.array()
11 | .items(
12 | Joi.object({
13 | ndownloads: nonNegativeInteger,
14 | })
15 | )
16 | .required(),
17 | }).required()
18 |
19 | module.exports = class BaseCondaService extends BaseJsonService {
20 | static get defaultBadgeData() {
21 | return { label: 'conda' }
22 | }
23 |
24 | async fetch({ channel, pkg }) {
25 | return this._requestJson({
26 | schema: condaSchema,
27 | url: `https://api.anaconda.org/package/${channel}/${pkg}`,
28 | })
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/services/cookbook/cookbook.tester.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { isVPlusDottedVersionAtLeastOne } = require('../test-validators')
4 | const t = (module.exports = require('../tester').createServiceTester())
5 |
6 | t.create('version').get('/chef-sugar.json').expectBadge({
7 | label: 'cookbook',
8 | message: isVPlusDottedVersionAtLeastOne,
9 | })
10 |
11 | t.create('version')
12 | .get('/chef-sugar.json')
13 | .intercept(nock =>
14 | nock('https://supermarket.getchef.com')
15 | .get('/api/v1/cookbooks/chef-sugar/versions/latest')
16 | .reply(200, {
17 | version: '4.1.0',
18 | })
19 | )
20 | .expectBadge({
21 | label: 'cookbook',
22 | message: 'v4.1.0',
23 | color: 'blue',
24 | })
25 |
26 | t.create('version (not found)')
27 | .get('/not-a-cookbook.json')
28 | .expectBadge({ label: 'cookbook', message: 'not found' })
29 |
--------------------------------------------------------------------------------
/services/cpan/cpan-version.service.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { renderVersionBadge } = require('../version')
4 | const BaseCpanService = require('./cpan')
5 |
6 | module.exports = class CpanVersion extends BaseCpanService {
7 | static get category() {
8 | return 'version'
9 | }
10 |
11 | static get route() {
12 | return {
13 | base: 'cpan/v',
14 | pattern: ':packageName',
15 | }
16 | }
17 |
18 | static get examples() {
19 | return [
20 | {
21 | title: 'CPAN',
22 | namedParams: { packageName: 'Config-Augeas' },
23 | staticPreview: renderVersionBadge({ version: '1.000' }),
24 | keywords: ['perl'],
25 | },
26 | ]
27 | }
28 |
29 | async handle({ packageName }) {
30 | const { version } = await this.fetch({ packageName })
31 | return renderVersionBadge({ version })
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/1_Bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 🐛 Bug Report
3 | about: Report errors and problems
4 | labels: 'question'
5 | ---
6 |
7 | Are you experiencing an issue with...
8 |
9 | - [ ] [shields.io](https://shields.io/#/)
10 | - [ ] My own instance
11 | - [ ] [badge-maker NPM package](https://www.npmjs.com/package/badge-maker)
12 |
13 | :beetle: **Description**
14 |
15 |
16 |
17 | :link: **Link to the badge**
18 |
19 |
23 |
24 | :bulb: **Possible Solution**
25 |
26 |
27 |
28 |
30 |
--------------------------------------------------------------------------------