Compare commits
5 Commits
missing-sp
...
ua-debug
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
046856c056 | ||
|
|
851a30be39 | ||
|
|
785ee090a9 | ||
|
|
0002d6749e | ||
|
|
fb379c0556 |
384
.circleci/config.yml
Normal file
384
.circleci/config.yml
Normal file
@@ -0,0 +1,384 @@
|
|||||||
|
version: 2
|
||||||
|
|
||||||
|
main_steps: &main_steps
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Install dependencies
|
||||||
|
command: |
|
||||||
|
npm install --dry-run
|
||||||
|
npm ci
|
||||||
|
environment:
|
||||||
|
# https://docs.cypress.io/guides/getting-started/installing-cypress.html#Skipping-installation
|
||||||
|
# We don't need to install the Cypress binary in jobs that aren't actually running Cypress.
|
||||||
|
CYPRESS_INSTALL_BINARY: 0
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Linter
|
||||||
|
when: always
|
||||||
|
command: npm run lint
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Core tests
|
||||||
|
when: always
|
||||||
|
environment:
|
||||||
|
mocha_reporter: mocha-junit-reporter
|
||||||
|
MOCHA_FILE: junit/core/results.xml
|
||||||
|
command: npm run test:core
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Entrypoint tests
|
||||||
|
when: always
|
||||||
|
environment:
|
||||||
|
mocha_reporter: mocha-junit-reporter
|
||||||
|
MOCHA_FILE: junit/entrypoint/results.xml
|
||||||
|
command: npm run test:entrypoint
|
||||||
|
|
||||||
|
- store_test_results:
|
||||||
|
path: junit
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: 'Prettier check (quick fix: `npm run prettier`)'
|
||||||
|
when: always
|
||||||
|
command: npm run prettier:check
|
||||||
|
|
||||||
|
integration_steps: &integration_steps
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Install dependencies
|
||||||
|
command: |
|
||||||
|
npm install --dry-run
|
||||||
|
npm ci
|
||||||
|
environment:
|
||||||
|
CYPRESS_INSTALL_BINARY: 0
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Integration tests
|
||||||
|
when: always
|
||||||
|
environment:
|
||||||
|
mocha_reporter: mocha-junit-reporter
|
||||||
|
MOCHA_FILE: junit/integration/results.xml
|
||||||
|
command: npm run test:integration
|
||||||
|
|
||||||
|
- store_test_results:
|
||||||
|
path: junit
|
||||||
|
|
||||||
|
services_steps: &services_steps
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Install dependencies
|
||||||
|
command: |
|
||||||
|
npm install --dry-run
|
||||||
|
npm ci
|
||||||
|
environment:
|
||||||
|
CYPRESS_INSTALL_BINARY: 0
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Identify services tagged in the PR title
|
||||||
|
command: npm run test:services:pr:prepare
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Run tests for tagged services
|
||||||
|
environment:
|
||||||
|
mocha_reporter: mocha-junit-reporter
|
||||||
|
MOCHA_FILE: junit/services/results.xml
|
||||||
|
command: RETRY_COUNT=3 npm run test:services:pr:run
|
||||||
|
|
||||||
|
- store_test_results:
|
||||||
|
path: junit
|
||||||
|
|
||||||
|
package_steps: &package_steps
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Install node and npm
|
||||||
|
command: |
|
||||||
|
set +e
|
||||||
|
export NVM_DIR="/opt/circleci/.nvm"
|
||||||
|
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
||||||
|
nvm install v14
|
||||||
|
nvm use v14
|
||||||
|
npm install -g npm
|
||||||
|
|
||||||
|
# Run the package tests on each currently supported node version. See:
|
||||||
|
# https://github.com/badges/shields/blob/master/badge-maker/README.md#node-version-support
|
||||||
|
# https://nodejs.org/en/about/releases/
|
||||||
|
|
||||||
|
- run:
|
||||||
|
environment:
|
||||||
|
mocha_reporter: mocha-junit-reporter
|
||||||
|
MOCHA_FILE: junit/badge-maker/v12/results.xml
|
||||||
|
NODE_VERSION: v12
|
||||||
|
CYPRESS_INSTALL_BINARY: 0
|
||||||
|
name: Run package tests on Node 12
|
||||||
|
command: scripts/run_package_tests.sh
|
||||||
|
|
||||||
|
- run:
|
||||||
|
environment:
|
||||||
|
mocha_reporter: mocha-junit-reporter
|
||||||
|
MOCHA_FILE: junit/badge-maker/v14/results.xml
|
||||||
|
NODE_VERSION: v14
|
||||||
|
CYPRESS_INSTALL_BINARY: 0
|
||||||
|
name: Run package tests on Node 14
|
||||||
|
command: scripts/run_package_tests.sh
|
||||||
|
|
||||||
|
- run:
|
||||||
|
environment:
|
||||||
|
mocha_reporter: mocha-junit-reporter
|
||||||
|
MOCHA_FILE: junit/badge-maker/v16/results.xml
|
||||||
|
NODE_VERSION: v16
|
||||||
|
CYPRESS_INSTALL_BINARY: 0
|
||||||
|
name: Run package tests on Node 16
|
||||||
|
command: scripts/run_package_tests.sh
|
||||||
|
|
||||||
|
- store_test_results:
|
||||||
|
path: junit
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
main:
|
||||||
|
docker:
|
||||||
|
- image: circleci/node:16
|
||||||
|
environment:
|
||||||
|
NPM_CONFIG_ENGINE_STRICT: 'true'
|
||||||
|
NPM_CONFIG_STRICT_PEER_DEPS: 'true'
|
||||||
|
|
||||||
|
<<: *main_steps
|
||||||
|
|
||||||
|
main@node-17:
|
||||||
|
docker:
|
||||||
|
- image: circleci/node:17
|
||||||
|
|
||||||
|
<<: *main_steps
|
||||||
|
|
||||||
|
integration:
|
||||||
|
docker:
|
||||||
|
- image: circleci/node:16
|
||||||
|
environment:
|
||||||
|
NPM_CONFIG_ENGINE_STRICT: 'true'
|
||||||
|
NPM_CONFIG_STRICT_PEER_DEPS: 'true'
|
||||||
|
- image: redis
|
||||||
|
|
||||||
|
<<: *integration_steps
|
||||||
|
|
||||||
|
integration@node-17:
|
||||||
|
docker:
|
||||||
|
- image: circleci/node:17
|
||||||
|
- image: redis
|
||||||
|
|
||||||
|
<<: *integration_steps
|
||||||
|
|
||||||
|
danger:
|
||||||
|
docker:
|
||||||
|
- image: circleci/node:16
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Install dependencies
|
||||||
|
command: npm ci
|
||||||
|
environment:
|
||||||
|
CYPRESS_INSTALL_BINARY: 0
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Danger
|
||||||
|
when: always
|
||||||
|
environment:
|
||||||
|
# https://github.com/gatsbyjs/gatsby/pull/11555
|
||||||
|
NODE_ENV: test
|
||||||
|
command: npm run danger ci
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
docker:
|
||||||
|
- image: circleci/node:16
|
||||||
|
environment:
|
||||||
|
NPM_CONFIG_ENGINE_STRICT: 'true'
|
||||||
|
NPM_CONFIG_STRICT_PEER_DEPS: 'true'
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Install dependencies
|
||||||
|
command: |
|
||||||
|
npm install --dry-run
|
||||||
|
npm ci
|
||||||
|
environment:
|
||||||
|
CYPRESS_INSTALL_BINARY: 0
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Prepare frontend tests
|
||||||
|
command: npm run defs && npm run features
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Check types
|
||||||
|
command: npm run check-types:frontend
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Frontend unit tests
|
||||||
|
environment:
|
||||||
|
mocha_reporter: mocha-junit-reporter
|
||||||
|
MOCHA_FILE: junit/frontend/results.xml
|
||||||
|
when: always
|
||||||
|
command: npm run test:frontend
|
||||||
|
|
||||||
|
- store_test_results:
|
||||||
|
path: junit
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Frontend build completes successfully
|
||||||
|
when: always
|
||||||
|
command: npm run build
|
||||||
|
|
||||||
|
package:
|
||||||
|
machine: true
|
||||||
|
|
||||||
|
<<: *package_steps
|
||||||
|
|
||||||
|
services:
|
||||||
|
docker:
|
||||||
|
- image: circleci/node:16
|
||||||
|
environment:
|
||||||
|
NPM_CONFIG_ENGINE_STRICT: 'true'
|
||||||
|
NPM_CONFIG_STRICT_PEER_DEPS: 'true'
|
||||||
|
|
||||||
|
<<: *services_steps
|
||||||
|
|
||||||
|
services@node-17:
|
||||||
|
docker:
|
||||||
|
- image: circleci/node:17
|
||||||
|
|
||||||
|
<<: *services_steps
|
||||||
|
|
||||||
|
e2e:
|
||||||
|
docker:
|
||||||
|
- image: cypress/base:16.13.0
|
||||||
|
environment:
|
||||||
|
NPM_CONFIG_ENGINE_STRICT: 'true'
|
||||||
|
NPM_CONFIG_STRICT_PEER_DEPS: 'true'
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
|
||||||
|
- restore_cache:
|
||||||
|
name: Restore Cypress binary
|
||||||
|
keys:
|
||||||
|
- v2-cypress-dependencies-{{ checksum "package-lock.json" }}
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Install dependencies
|
||||||
|
command: |
|
||||||
|
npm install --dry-run
|
||||||
|
npm ci
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Frontend build
|
||||||
|
command: GATSBY_BASE_URL=http://localhost:8080 npm run build
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Run tests
|
||||||
|
environment:
|
||||||
|
CYPRESS_REPORTER: junit
|
||||||
|
MOCHA_FILE: junit/e2e/results.xml
|
||||||
|
command: npm run e2e-on-build
|
||||||
|
|
||||||
|
- store_test_results:
|
||||||
|
path: junit
|
||||||
|
|
||||||
|
- store_artifacts:
|
||||||
|
path: cypress/videos
|
||||||
|
|
||||||
|
- store_artifacts:
|
||||||
|
path: cypress/screenshots
|
||||||
|
|
||||||
|
- save_cache:
|
||||||
|
name: Cache Cypress binary
|
||||||
|
paths:
|
||||||
|
# https://docs.cypress.io/guides/getting-started/installing-cypress.html#Binary-cache
|
||||||
|
- ~/.cache/Cypress
|
||||||
|
key: v2-cypress-dependencies-{{ checksum "package-lock.json" }}
|
||||||
|
|
||||||
|
workflows:
|
||||||
|
version: 2
|
||||||
|
|
||||||
|
on-commit:
|
||||||
|
jobs:
|
||||||
|
- main:
|
||||||
|
filters:
|
||||||
|
branches:
|
||||||
|
ignore: gh-pages
|
||||||
|
- main@node-17:
|
||||||
|
filters:
|
||||||
|
branches:
|
||||||
|
ignore: gh-pages
|
||||||
|
- integration@node-17:
|
||||||
|
filters:
|
||||||
|
branches:
|
||||||
|
ignore: gh-pages
|
||||||
|
- frontend:
|
||||||
|
filters:
|
||||||
|
branches:
|
||||||
|
ignore: gh-pages
|
||||||
|
- package:
|
||||||
|
filters:
|
||||||
|
branches:
|
||||||
|
ignore: gh-pages
|
||||||
|
- services:
|
||||||
|
filters:
|
||||||
|
branches:
|
||||||
|
ignore:
|
||||||
|
- master
|
||||||
|
- gh-pages
|
||||||
|
- services@node-17:
|
||||||
|
filters:
|
||||||
|
branches:
|
||||||
|
ignore:
|
||||||
|
- master
|
||||||
|
- gh-pages
|
||||||
|
- danger:
|
||||||
|
filters:
|
||||||
|
branches:
|
||||||
|
ignore:
|
||||||
|
- master
|
||||||
|
- gh-pages
|
||||||
|
- /dependabot\/.*/
|
||||||
|
- e2e:
|
||||||
|
filters:
|
||||||
|
branches:
|
||||||
|
ignore: gh-pages
|
||||||
|
# on-commit-with-cache:
|
||||||
|
# jobs:
|
||||||
|
# - npm-install:
|
||||||
|
# filters:
|
||||||
|
# branches:
|
||||||
|
# ignore: gh-pages
|
||||||
|
# - main:
|
||||||
|
# requires:
|
||||||
|
# - npm-install
|
||||||
|
# - main@node-latest:
|
||||||
|
# requires:
|
||||||
|
# - npm-install
|
||||||
|
# - frontend:
|
||||||
|
# requires:
|
||||||
|
# - npm-install
|
||||||
|
# - services:
|
||||||
|
# requires:
|
||||||
|
# - npm-install
|
||||||
|
# filters:
|
||||||
|
# branches:
|
||||||
|
# ignore: master
|
||||||
|
# - services@node-latest:
|
||||||
|
# requires:
|
||||||
|
# - npm-install
|
||||||
|
# filters:
|
||||||
|
# branches:
|
||||||
|
# ignore: master
|
||||||
|
# - danger:
|
||||||
|
# requires:
|
||||||
|
# - npm-install
|
||||||
|
# filters:
|
||||||
|
# branches:
|
||||||
|
# ignore: /dependabot\/.*/
|
||||||
@@ -3,7 +3,6 @@ shields.env
|
|||||||
.git/
|
.git/
|
||||||
.gitignore
|
.gitignore
|
||||||
.vscode/
|
.vscode/
|
||||||
fly.toml
|
|
||||||
|
|
||||||
# Improve layer cacheability.
|
# Improve layer cacheability.
|
||||||
Dockerfile
|
Dockerfile
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ extends:
|
|||||||
- standard
|
- standard
|
||||||
- standard-jsx
|
- standard-jsx
|
||||||
- standard-react
|
- standard-react
|
||||||
|
- plugin:@typescript-eslint/recommended
|
||||||
- prettier
|
- prettier
|
||||||
- eslint:recommended
|
- eslint:recommended
|
||||||
|
|
||||||
@@ -17,13 +18,12 @@ settings:
|
|||||||
react:
|
react:
|
||||||
version: '16.8'
|
version: '16.8'
|
||||||
jsdoc:
|
jsdoc:
|
||||||
mode: typescript
|
mode: jsdoc
|
||||||
|
|
||||||
plugins:
|
plugins:
|
||||||
- chai-friendly
|
- chai-friendly
|
||||||
- jsdoc
|
- jsdoc
|
||||||
- mocha
|
- mocha
|
||||||
- icedfrisby
|
|
||||||
- no-extension-in-require
|
- no-extension-in-require
|
||||||
- sort-class-members
|
- sort-class-members
|
||||||
- import
|
- import
|
||||||
@@ -35,34 +35,40 @@ overrides:
|
|||||||
# list of rules, even if they only apply to certain files. That way the
|
# list of rules, even if they only apply to certain files. That way the
|
||||||
# rules listed here are only ones which conflict.
|
# rules listed here are only ones which conflict.
|
||||||
|
|
||||||
- files:
|
|
||||||
- 'badge-maker/**/*.js'
|
|
||||||
- '**/*.cjs'
|
|
||||||
env:
|
|
||||||
node: true
|
|
||||||
es6: true
|
|
||||||
|
|
||||||
- files:
|
- files:
|
||||||
- '**/*.js'
|
- '**/*.js'
|
||||||
- '!frontend/**/*.js'
|
- '!frontend/**/*.js'
|
||||||
- '!badge-maker/**/*.js'
|
|
||||||
env:
|
env:
|
||||||
node: true
|
node: true
|
||||||
es6: true
|
es6: true
|
||||||
|
rules:
|
||||||
|
no-console: 'off'
|
||||||
|
'@typescript-eslint/explicit-module-boundary-types': 'off'
|
||||||
|
|
||||||
|
- files:
|
||||||
|
- '**/*.@(ts|tsx)'
|
||||||
parserOptions:
|
parserOptions:
|
||||||
sourceType: 'module'
|
sourceType: 'module'
|
||||||
parser: '@typescript-eslint/parser'
|
parser: '@typescript-eslint/parser'
|
||||||
rules:
|
rules:
|
||||||
no-console: 'off'
|
# Argh.
|
||||||
|
'@typescript-eslint/explicit-function-return-type':
|
||||||
|
['error', { 'allowExpressions': true }]
|
||||||
|
'@typescript-eslint/no-empty-function': 'error'
|
||||||
|
'@typescript-eslint/no-var-requires': 'error'
|
||||||
|
'@typescript-eslint/no-object-literal-type-assertion': 'off'
|
||||||
|
'@typescript-eslint/no-explicit-any': 'error'
|
||||||
|
'@typescript-eslint/ban-ts-ignore': 'off'
|
||||||
|
'@typescript-eslint/explicit-module-boundary-types': 'off'
|
||||||
|
|
||||||
- files:
|
- files:
|
||||||
- '**/*.ts'
|
- core/**/*.ts
|
||||||
parserOptions:
|
parserOptions:
|
||||||
sourceType: 'module'
|
sourceType: 'module'
|
||||||
parser: '@typescript-eslint/parser'
|
parser: '@typescript-eslint/parser'
|
||||||
|
|
||||||
- files:
|
- files:
|
||||||
- 'frontend/**/*.js'
|
- gatsby-browser.js
|
||||||
|
- 'frontend/**/*.@(js|ts|tsx)'
|
||||||
parserOptions:
|
parserOptions:
|
||||||
sourceType: 'module'
|
sourceType: 'module'
|
||||||
env:
|
env:
|
||||||
@@ -107,20 +113,21 @@ overrides:
|
|||||||
mocha: true
|
mocha: true
|
||||||
rules:
|
rules:
|
||||||
mocha/no-exclusive-tests: 'error'
|
mocha/no-exclusive-tests: 'error'
|
||||||
mocha/no-skipped-tests: 'error'
|
|
||||||
mocha/no-mocha-arrows: 'error'
|
mocha/no-mocha-arrows: 'error'
|
||||||
mocha/prefer-arrow-callback: 'error'
|
mocha/prefer-arrow-callback: 'error'
|
||||||
|
|
||||||
- files:
|
|
||||||
- 'services/**/*.tester.js'
|
|
||||||
rules:
|
|
||||||
icedfrisby/no-exclusive-tests: 'error'
|
|
||||||
icedfrisby/no-skipped-tests: 'error'
|
|
||||||
|
|
||||||
rules:
|
rules:
|
||||||
# Disable some rules from eslint:recommended.
|
# Disable some rules from eslint:recommended.
|
||||||
no-empty: ['error', { 'allowEmptyCatch': true }]
|
no-empty: ['error', { 'allowEmptyCatch': true }]
|
||||||
|
|
||||||
|
# Allow unused parameters. In callbacks, removing them seems to obscure
|
||||||
|
# what the functions are doing.
|
||||||
|
'@typescript-eslint/no-unused-vars': ['error', { 'args': 'none' }]
|
||||||
|
no-unused-vars: 'off'
|
||||||
|
|
||||||
|
'@typescript-eslint/no-var-requires': 'off'
|
||||||
|
|
||||||
|
'@typescript-eslint/no-use-before-define': 'error'
|
||||||
no-use-before-define: 'off'
|
no-use-before-define: 'off'
|
||||||
|
|
||||||
# These should be disabled by eslint-config-prettier, but are not.
|
# These should be disabled by eslint-config-prettier, but are not.
|
||||||
@@ -137,8 +144,6 @@ rules:
|
|||||||
func-style: ['error', 'declaration', { 'allowArrowFunctions': true }]
|
func-style: ['error', 'declaration', { 'allowArrowFunctions': true }]
|
||||||
new-cap: ['error', { 'capIsNew': true }]
|
new-cap: ['error', { 'capIsNew': true }]
|
||||||
import/order: ['error', { 'newlines-between': 'never' }]
|
import/order: ['error', { 'newlines-between': 'never' }]
|
||||||
quotes:
|
|
||||||
['error', 'single', { 'avoidEscape': true, 'allowTemplateLiterals': false }]
|
|
||||||
|
|
||||||
# Account for destructuring responses from upstream services,
|
# Account for destructuring responses from upstream services,
|
||||||
# many of which do not follow camelcase
|
# many of which do not follow camelcase
|
||||||
@@ -171,7 +176,7 @@ rules:
|
|||||||
jsdoc/check-tag-names: 'error'
|
jsdoc/check-tag-names: 'error'
|
||||||
jsdoc/check-types: 'error'
|
jsdoc/check-types: 'error'
|
||||||
jsdoc/implements-on-classes: 'error'
|
jsdoc/implements-on-classes: 'error'
|
||||||
jsdoc/tag-lines: ['error', 'any', { 'startLines': 1 }]
|
jsdoc/newline-after-description: 'error'
|
||||||
jsdoc/require-param: 'error'
|
jsdoc/require-param: 'error'
|
||||||
jsdoc/require-param-description: 'error'
|
jsdoc/require-param-description: 'error'
|
||||||
jsdoc/require-param-name: 'error'
|
jsdoc/require-param-name: 'error'
|
||||||
@@ -182,7 +187,11 @@ rules:
|
|||||||
jsdoc/require-returns-type: 'error'
|
jsdoc/require-returns-type: 'error'
|
||||||
jsdoc/valid-types: 'error'
|
jsdoc/valid-types: 'error'
|
||||||
|
|
||||||
react/prop-types: 'off'
|
# Disable some from TypeScript.
|
||||||
|
'@typescript-eslint/camelcase': off
|
||||||
|
'@typescript-eslint/explicit-function-return-type': 'off'
|
||||||
|
'@typescript-eslint/no-empty-function': 'off'
|
||||||
|
|
||||||
react/jsx-sort-props: 'error'
|
react/jsx-sort-props: 'error'
|
||||||
react-hooks/rules-of-hooks: 'error'
|
react-hooks/rules-of-hooks: 'error'
|
||||||
react-hooks/exhaustive-deps: 'error'
|
react-hooks/exhaustive-deps: 'error'
|
||||||
|
|||||||
37
.github/ISSUE_TEMPLATE/3_Badge_request.md
vendored
Normal file
37
.github/ISSUE_TEMPLATE/3_Badge_request.md
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
---
|
||||||
|
name: 💡 Badge Request
|
||||||
|
about: Ideas for new badges
|
||||||
|
labels: 'service-badge'
|
||||||
|
---
|
||||||
|
|
||||||
|
:clipboard: **Description**
|
||||||
|
|
||||||
|
<!--
|
||||||
|
A clear and concise description of the new badge.
|
||||||
|
|
||||||
|
- Which service is this badge for e.g: GitHub, Travis CI
|
||||||
|
- What sort of information should this badge show?
|
||||||
|
Provide an example in plain text e.g: "version | v1.01" or as a static badge
|
||||||
|
(static badge generator can be found at https://shields.io)
|
||||||
|
-->
|
||||||
|
|
||||||
|
:link: **Data**
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Where can we get the data from?
|
||||||
|
|
||||||
|
- Is there a public API?
|
||||||
|
- Does the API requires an API key?
|
||||||
|
- Link to the API documentation.
|
||||||
|
-->
|
||||||
|
|
||||||
|
:microphone: **Motivation**
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Please explain why this feature should be implemented and how it would be used.
|
||||||
|
|
||||||
|
- What is the specific use case?
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Love Shields? Please consider donating $10 to sustain our activities:
|
||||||
|
👉 https://opencollective.com/shields -->
|
||||||
62
.github/ISSUE_TEMPLATE/3_Badge_request.yml
vendored
62
.github/ISSUE_TEMPLATE/3_Badge_request.yml
vendored
@@ -1,62 +0,0 @@
|
|||||||
name: '💡 Badge Request'
|
|
||||||
description: Ideas for new badges
|
|
||||||
labels: ['service-badge']
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: >
|
|
||||||
## Ideas for new badges
|
|
||||||
|
|
||||||
|
|
||||||
This issue template is for suggesting new badges which
|
|
||||||
**fetch and display data from an upstream service**.
|
|
||||||
If your suggestion is for a static badge
|
|
||||||
(which shows the same information every time it is requested), it is
|
|
||||||
[already possible to make these](https://github.com/badges/shields/blob/master/doc/static-badges.md).
|
|
||||||
We don't add specific routes for badges which only show static information.
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: description
|
|
||||||
attributes:
|
|
||||||
label: '📋 Description'
|
|
||||||
description: |
|
|
||||||
A clear and concise description of the new badge.
|
|
||||||
|
|
||||||
- Which service is this badge for e.g: GitHub, Travis CI
|
|
||||||
- What sort of information should this badge show?
|
|
||||||
Provide an example in plain text e.g: "version | v1.01" or as a static badge
|
|
||||||
(static badge generator can be found at https://shields.io/#your-badge )
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: data
|
|
||||||
attributes:
|
|
||||||
label: '🔗 Data'
|
|
||||||
description: |
|
|
||||||
Where can we get the data from?
|
|
||||||
|
|
||||||
Please consider and cover details like:
|
|
||||||
- Is there a public API?
|
|
||||||
- Does the API require authentication or an API key?
|
|
||||||
If so, please review our documentation on [Badges Requiring Authentication](https://github.com/badges/shields/blob/master/doc/authentication.md)
|
|
||||||
- Link to the API documentation.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: motivation
|
|
||||||
attributes:
|
|
||||||
label: '🎤 Motivation'
|
|
||||||
description: |
|
|
||||||
Please explain why this feature should be implemented and how it would be used.
|
|
||||||
|
|
||||||
- What is the specific use case?
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
## :heart: Love Shields?
|
|
||||||
Please consider donating $10 to sustain our activities: [https://opencollective.com/shields](https://opencollective.com/shields)
|
|
||||||
2
.github/actions/close-bot/action.yml
vendored
2
.github/actions/close-bot/action.yml
vendored
@@ -8,5 +8,5 @@ inputs:
|
|||||||
description: 'The GITHUB_TOKEN secret'
|
description: 'The GITHUB_TOKEN secret'
|
||||||
required: true
|
required: true
|
||||||
runs:
|
runs:
|
||||||
using: 'node16'
|
using: 'node12'
|
||||||
main: 'index.js'
|
main: 'index.js'
|
||||||
|
|||||||
1
.github/actions/close-bot/helpers.js
vendored
1
.github/actions/close-bot/helpers.js
vendored
@@ -35,6 +35,7 @@ function allChangelogLinesAreVersionBump(changelogLines) {
|
|||||||
|
|
||||||
function isPointlessVersionBump(body) {
|
function isPointlessVersionBump(body) {
|
||||||
const pointlessBumpLinks = [
|
const pointlessBumpLinks = [
|
||||||
|
'https://github.com/gatsbyjs/gatsby',
|
||||||
'https://github.com/typescript-eslint/typescript-eslint',
|
'https://github.com/typescript-eslint/typescript-eslint',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
2
.github/actions/close-bot/index.js
vendored
2
.github/actions/close-bot/index.js
vendored
@@ -27,7 +27,7 @@ async function run() {
|
|||||||
state: 'closed',
|
state: 'closed',
|
||||||
})
|
})
|
||||||
|
|
||||||
core.debug('Done.')
|
core.debug(`Done.`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
243
.github/actions/close-bot/package-lock.json
generated
vendored
243
.github/actions/close-bot/package-lock.json
generated
vendored
@@ -9,54 +9,53 @@
|
|||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"license": "CC0",
|
"license": "CC0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.10.0",
|
"@actions/core": "^1.6.0",
|
||||||
"@actions/github": "^5.1.1"
|
"@actions/github": "^5.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@actions/core": {
|
"node_modules/@actions/core": {
|
||||||
"version": "1.10.0",
|
"version": "1.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.6.0.tgz",
|
||||||
"integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==",
|
"integrity": "sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/http-client": "^2.0.1",
|
"@actions/http-client": "^1.0.11"
|
||||||
"uuid": "^8.3.2"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@actions/github": {
|
"node_modules/@actions/github": {
|
||||||
"version": "5.1.1",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@actions/github/-/github-5.0.0.tgz",
|
||||||
"integrity": "sha512-Nk59rMDoJaV+mHCOJPXuvB1zIbomlKS0dmSIqPGxd0enAXBnOfn4VWF+CGtRCwXZG9Epa54tZA7VIRlJDS8A6g==",
|
"integrity": "sha512-QvE9eAAfEsS+yOOk0cylLBIO/d6WyWIOvsxxzdrPFaud39G6BOkUwScXZn1iBzQzHyu9SBkkLSWlohDWdsasAQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/http-client": "^2.0.1",
|
"@actions/http-client": "^1.0.11",
|
||||||
"@octokit/core": "^3.6.0",
|
"@octokit/core": "^3.4.0",
|
||||||
"@octokit/plugin-paginate-rest": "^2.17.0",
|
"@octokit/plugin-paginate-rest": "^2.13.3",
|
||||||
"@octokit/plugin-rest-endpoint-methods": "^5.13.0"
|
"@octokit/plugin-rest-endpoint-methods": "^5.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@actions/http-client": {
|
"node_modules/@actions/http-client": {
|
||||||
"version": "2.0.1",
|
"version": "1.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
|
||||||
"integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
|
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tunnel": "^0.0.6"
|
"tunnel": "0.0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@octokit/auth-token": {
|
"node_modules/@octokit/auth-token": {
|
||||||
"version": "2.5.0",
|
"version": "2.4.5",
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.5.tgz",
|
||||||
"integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
|
"integrity": "sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@octokit/types": "^6.0.3"
|
"@octokit/types": "^6.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@octokit/core": {
|
"node_modules/@octokit/core": {
|
||||||
"version": "3.6.0",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.4.0.tgz",
|
||||||
"integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==",
|
"integrity": "sha512-6/vlKPP8NF17cgYXqucdshWqmMZGXkuvtcrWCgU5NOI0Pl2GjlmZyWgBMrU8zJ3v2MJlM6++CiB45VKYmhiWWg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@octokit/auth-token": "^2.4.4",
|
"@octokit/auth-token": "^2.4.4",
|
||||||
"@octokit/graphql": "^4.5.8",
|
"@octokit/graphql": "^4.5.8",
|
||||||
"@octokit/request": "^5.6.3",
|
"@octokit/request": "^5.4.12",
|
||||||
"@octokit/request-error": "^2.0.5",
|
"@octokit/request-error": "^2.0.5",
|
||||||
"@octokit/types": "^6.0.3",
|
"@octokit/types": "^6.0.3",
|
||||||
"before-after-hook": "^2.2.0",
|
"before-after-hook": "^2.2.0",
|
||||||
@@ -64,9 +63,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@octokit/endpoint": {
|
"node_modules/@octokit/endpoint": {
|
||||||
"version": "6.0.12",
|
"version": "6.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.11.tgz",
|
||||||
"integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
|
"integrity": "sha512-fUIPpx+pZyoLW4GCs3yMnlj2LfoXTWDUVPTC4V3MUEKZm48W+XYpeWSZCv+vYF1ZABUm2CqnDVf1sFtIYrj7KQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@octokit/types": "^6.0.3",
|
"@octokit/types": "^6.0.3",
|
||||||
"is-plain-object": "^5.0.0",
|
"is-plain-object": "^5.0.0",
|
||||||
@@ -74,37 +73,37 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@octokit/graphql": {
|
"node_modules/@octokit/graphql": {
|
||||||
"version": "4.8.0",
|
"version": "4.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.6.2.tgz",
|
||||||
"integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
|
"integrity": "sha512-WmsIR1OzOr/3IqfG9JIczI8gMJUMzzyx5j0XXQ4YihHtKlQc+u35VpVoOXhlKAlaBntvry1WpAzPl/a+s3n89Q==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@octokit/request": "^5.6.0",
|
"@octokit/request": "^5.3.0",
|
||||||
"@octokit/types": "^6.0.3",
|
"@octokit/types": "^6.0.3",
|
||||||
"universal-user-agent": "^6.0.0"
|
"universal-user-agent": "^6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@octokit/openapi-types": {
|
"node_modules/@octokit/openapi-types": {
|
||||||
"version": "11.2.0",
|
"version": "7.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-7.0.0.tgz",
|
||||||
"integrity": "sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA=="
|
"integrity": "sha512-gV/8DJhAL/04zjTI95a7FhQwS6jlEE0W/7xeYAzuArD0KVAVWDLP2f3vi98hs3HLTczxXdRK/mF0tRoQPpolEw=="
|
||||||
},
|
},
|
||||||
"node_modules/@octokit/plugin-paginate-rest": {
|
"node_modules/@octokit/plugin-paginate-rest": {
|
||||||
"version": "2.17.0",
|
"version": "2.13.3",
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.13.3.tgz",
|
||||||
"integrity": "sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw==",
|
"integrity": "sha512-46lptzM9lTeSmIBt/sVP/FLSTPGx6DCzAdSX3PfeJ3mTf4h9sGC26WpaQzMEq/Z44cOcmx8VsOhO+uEgE3cjYg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@octokit/types": "^6.34.0"
|
"@octokit/types": "^6.11.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@octokit/core": ">=2"
|
"@octokit/core": ">=2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@octokit/plugin-rest-endpoint-methods": {
|
"node_modules/@octokit/plugin-rest-endpoint-methods": {
|
||||||
"version": "5.13.0",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.1.1.tgz",
|
||||||
"integrity": "sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA==",
|
"integrity": "sha512-u4zy0rVA8darm/AYsIeWkRalhQR99qPL1D/EXHejV2yaECMdHfxXiTXtba8NMBSajOJe8+C9g+EqMKSvysx0dg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@octokit/types": "^6.34.0",
|
"@octokit/types": "^6.14.1",
|
||||||
"deprecation": "^2.3.1"
|
"deprecation": "^2.3.1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
@@ -112,22 +111,22 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@octokit/request": {
|
"node_modules/@octokit/request": {
|
||||||
"version": "5.6.3",
|
"version": "5.4.15",
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.15.tgz",
|
||||||
"integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==",
|
"integrity": "sha512-6UnZfZzLwNhdLRreOtTkT9n57ZwulCve8q3IT/Z477vThu6snfdkBuhxnChpOKNGxcQ71ow561Qoa6uqLdPtag==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@octokit/endpoint": "^6.0.1",
|
"@octokit/endpoint": "^6.0.1",
|
||||||
"@octokit/request-error": "^2.1.0",
|
"@octokit/request-error": "^2.0.0",
|
||||||
"@octokit/types": "^6.16.1",
|
"@octokit/types": "^6.7.1",
|
||||||
"is-plain-object": "^5.0.0",
|
"is-plain-object": "^5.0.0",
|
||||||
"node-fetch": "^2.6.7",
|
"node-fetch": "^2.6.1",
|
||||||
"universal-user-agent": "^6.0.0"
|
"universal-user-agent": "^6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@octokit/request-error": {
|
"node_modules/@octokit/request-error": {
|
||||||
"version": "2.1.0",
|
"version": "2.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.5.tgz",
|
||||||
"integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
|
"integrity": "sha512-T/2wcCFyM7SkXzNoyVNWjyVlUwBvW3igM3Btr/eKYiPmucXTtkxt2RBsf6gn3LTzaLSLTQtNmvg+dGsOxQrjZg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@octokit/types": "^6.0.3",
|
"@octokit/types": "^6.0.3",
|
||||||
"deprecation": "^2.0.0",
|
"deprecation": "^2.0.0",
|
||||||
@@ -135,17 +134,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@octokit/types": {
|
"node_modules/@octokit/types": {
|
||||||
"version": "6.34.0",
|
"version": "6.14.2",
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.14.2.tgz",
|
||||||
"integrity": "sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw==",
|
"integrity": "sha512-wiQtW9ZSy4OvgQ09iQOdyXYNN60GqjCL/UdMsepDr1Gr0QzpW6irIKbH3REuAHXAhxkEk9/F2a3Gcs1P6kW5jA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@octokit/openapi-types": "^11.2.0"
|
"@octokit/openapi-types": "^7.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/before-after-hook": {
|
"node_modules/before-after-hook": {
|
||||||
"version": "2.2.2",
|
"version": "2.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.1.tgz",
|
||||||
"integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ=="
|
"integrity": "sha512-/6FKxSTWoJdbsLDF8tdIjaRiFXiE6UHsEHE3OPI/cwPURCVi1ukP0gmLn7XWEiFk5TcwQjjY5PWsU+j+tgXgmw=="
|
||||||
},
|
},
|
||||||
"node_modules/deprecation": {
|
"node_modules/deprecation": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
@@ -205,14 +204,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
|
||||||
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
|
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
|
||||||
},
|
},
|
||||||
"node_modules/uuid": {
|
|
||||||
"version": "8.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
|
||||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
|
||||||
"bin": {
|
|
||||||
"uuid": "dist/bin/uuid"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/webidl-conversions": {
|
"node_modules/webidl-conversions": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||||
@@ -235,49 +226,48 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": {
|
"@actions/core": {
|
||||||
"version": "1.10.0",
|
"version": "1.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.6.0.tgz",
|
||||||
"integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==",
|
"integrity": "sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@actions/http-client": "^2.0.1",
|
"@actions/http-client": "^1.0.11"
|
||||||
"uuid": "^8.3.2"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@actions/github": {
|
"@actions/github": {
|
||||||
"version": "5.1.1",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@actions/github/-/github-5.0.0.tgz",
|
||||||
"integrity": "sha512-Nk59rMDoJaV+mHCOJPXuvB1zIbomlKS0dmSIqPGxd0enAXBnOfn4VWF+CGtRCwXZG9Epa54tZA7VIRlJDS8A6g==",
|
"integrity": "sha512-QvE9eAAfEsS+yOOk0cylLBIO/d6WyWIOvsxxzdrPFaud39G6BOkUwScXZn1iBzQzHyu9SBkkLSWlohDWdsasAQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@actions/http-client": "^2.0.1",
|
"@actions/http-client": "^1.0.11",
|
||||||
"@octokit/core": "^3.6.0",
|
"@octokit/core": "^3.4.0",
|
||||||
"@octokit/plugin-paginate-rest": "^2.17.0",
|
"@octokit/plugin-paginate-rest": "^2.13.3",
|
||||||
"@octokit/plugin-rest-endpoint-methods": "^5.13.0"
|
"@octokit/plugin-rest-endpoint-methods": "^5.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@actions/http-client": {
|
"@actions/http-client": {
|
||||||
"version": "2.0.1",
|
"version": "1.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
|
||||||
"integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
|
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"tunnel": "^0.0.6"
|
"tunnel": "0.0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@octokit/auth-token": {
|
"@octokit/auth-token": {
|
||||||
"version": "2.5.0",
|
"version": "2.4.5",
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.5.tgz",
|
||||||
"integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
|
"integrity": "sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@octokit/types": "^6.0.3"
|
"@octokit/types": "^6.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@octokit/core": {
|
"@octokit/core": {
|
||||||
"version": "3.6.0",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.4.0.tgz",
|
||||||
"integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==",
|
"integrity": "sha512-6/vlKPP8NF17cgYXqucdshWqmMZGXkuvtcrWCgU5NOI0Pl2GjlmZyWgBMrU8zJ3v2MJlM6++CiB45VKYmhiWWg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@octokit/auth-token": "^2.4.4",
|
"@octokit/auth-token": "^2.4.4",
|
||||||
"@octokit/graphql": "^4.5.8",
|
"@octokit/graphql": "^4.5.8",
|
||||||
"@octokit/request": "^5.6.3",
|
"@octokit/request": "^5.4.12",
|
||||||
"@octokit/request-error": "^2.0.5",
|
"@octokit/request-error": "^2.0.5",
|
||||||
"@octokit/types": "^6.0.3",
|
"@octokit/types": "^6.0.3",
|
||||||
"before-after-hook": "^2.2.0",
|
"before-after-hook": "^2.2.0",
|
||||||
@@ -285,9 +275,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@octokit/endpoint": {
|
"@octokit/endpoint": {
|
||||||
"version": "6.0.12",
|
"version": "6.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.11.tgz",
|
||||||
"integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
|
"integrity": "sha512-fUIPpx+pZyoLW4GCs3yMnlj2LfoXTWDUVPTC4V3MUEKZm48W+XYpeWSZCv+vYF1ZABUm2CqnDVf1sFtIYrj7KQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@octokit/types": "^6.0.3",
|
"@octokit/types": "^6.0.3",
|
||||||
"is-plain-object": "^5.0.0",
|
"is-plain-object": "^5.0.0",
|
||||||
@@ -295,54 +285,54 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@octokit/graphql": {
|
"@octokit/graphql": {
|
||||||
"version": "4.8.0",
|
"version": "4.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.6.2.tgz",
|
||||||
"integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
|
"integrity": "sha512-WmsIR1OzOr/3IqfG9JIczI8gMJUMzzyx5j0XXQ4YihHtKlQc+u35VpVoOXhlKAlaBntvry1WpAzPl/a+s3n89Q==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@octokit/request": "^5.6.0",
|
"@octokit/request": "^5.3.0",
|
||||||
"@octokit/types": "^6.0.3",
|
"@octokit/types": "^6.0.3",
|
||||||
"universal-user-agent": "^6.0.0"
|
"universal-user-agent": "^6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@octokit/openapi-types": {
|
"@octokit/openapi-types": {
|
||||||
"version": "11.2.0",
|
"version": "7.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-7.0.0.tgz",
|
||||||
"integrity": "sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA=="
|
"integrity": "sha512-gV/8DJhAL/04zjTI95a7FhQwS6jlEE0W/7xeYAzuArD0KVAVWDLP2f3vi98hs3HLTczxXdRK/mF0tRoQPpolEw=="
|
||||||
},
|
},
|
||||||
"@octokit/plugin-paginate-rest": {
|
"@octokit/plugin-paginate-rest": {
|
||||||
"version": "2.17.0",
|
"version": "2.13.3",
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.13.3.tgz",
|
||||||
"integrity": "sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw==",
|
"integrity": "sha512-46lptzM9lTeSmIBt/sVP/FLSTPGx6DCzAdSX3PfeJ3mTf4h9sGC26WpaQzMEq/Z44cOcmx8VsOhO+uEgE3cjYg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@octokit/types": "^6.34.0"
|
"@octokit/types": "^6.11.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@octokit/plugin-rest-endpoint-methods": {
|
"@octokit/plugin-rest-endpoint-methods": {
|
||||||
"version": "5.13.0",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.1.1.tgz",
|
||||||
"integrity": "sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA==",
|
"integrity": "sha512-u4zy0rVA8darm/AYsIeWkRalhQR99qPL1D/EXHejV2yaECMdHfxXiTXtba8NMBSajOJe8+C9g+EqMKSvysx0dg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@octokit/types": "^6.34.0",
|
"@octokit/types": "^6.14.1",
|
||||||
"deprecation": "^2.3.1"
|
"deprecation": "^2.3.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@octokit/request": {
|
"@octokit/request": {
|
||||||
"version": "5.6.3",
|
"version": "5.4.15",
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.15.tgz",
|
||||||
"integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==",
|
"integrity": "sha512-6UnZfZzLwNhdLRreOtTkT9n57ZwulCve8q3IT/Z477vThu6snfdkBuhxnChpOKNGxcQ71ow561Qoa6uqLdPtag==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@octokit/endpoint": "^6.0.1",
|
"@octokit/endpoint": "^6.0.1",
|
||||||
"@octokit/request-error": "^2.1.0",
|
"@octokit/request-error": "^2.0.0",
|
||||||
"@octokit/types": "^6.16.1",
|
"@octokit/types": "^6.7.1",
|
||||||
"is-plain-object": "^5.0.0",
|
"is-plain-object": "^5.0.0",
|
||||||
"node-fetch": "^2.6.7",
|
"node-fetch": "^2.6.1",
|
||||||
"universal-user-agent": "^6.0.0"
|
"universal-user-agent": "^6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@octokit/request-error": {
|
"@octokit/request-error": {
|
||||||
"version": "2.1.0",
|
"version": "2.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.5.tgz",
|
||||||
"integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
|
"integrity": "sha512-T/2wcCFyM7SkXzNoyVNWjyVlUwBvW3igM3Btr/eKYiPmucXTtkxt2RBsf6gn3LTzaLSLTQtNmvg+dGsOxQrjZg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@octokit/types": "^6.0.3",
|
"@octokit/types": "^6.0.3",
|
||||||
"deprecation": "^2.0.0",
|
"deprecation": "^2.0.0",
|
||||||
@@ -350,17 +340,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@octokit/types": {
|
"@octokit/types": {
|
||||||
"version": "6.34.0",
|
"version": "6.14.2",
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.14.2.tgz",
|
||||||
"integrity": "sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw==",
|
"integrity": "sha512-wiQtW9ZSy4OvgQ09iQOdyXYNN60GqjCL/UdMsepDr1Gr0QzpW6irIKbH3REuAHXAhxkEk9/F2a3Gcs1P6kW5jA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@octokit/openapi-types": "^11.2.0"
|
"@octokit/openapi-types": "^7.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"before-after-hook": {
|
"before-after-hook": {
|
||||||
"version": "2.2.2",
|
"version": "2.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.1.tgz",
|
||||||
"integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ=="
|
"integrity": "sha512-/6FKxSTWoJdbsLDF8tdIjaRiFXiE6UHsEHE3OPI/cwPURCVi1ukP0gmLn7XWEiFk5TcwQjjY5PWsU+j+tgXgmw=="
|
||||||
},
|
},
|
||||||
"deprecation": {
|
"deprecation": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
@@ -403,11 +393,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
|
||||||
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
|
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
|
||||||
},
|
},
|
||||||
"uuid": {
|
|
||||||
"version": "8.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
|
||||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
|
|
||||||
},
|
|
||||||
"webidl-conversions": {
|
"webidl-conversions": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||||
|
|||||||
4
.github/actions/close-bot/package.json
vendored
4
.github/actions/close-bot/package.json
vendored
@@ -10,7 +10,7 @@
|
|||||||
"author": "chris48s",
|
"author": "chris48s",
|
||||||
"license": "CC0",
|
"license": "CC0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.10.0",
|
"@actions/core": "^1.6.0",
|
||||||
"@actions/github": "^5.1.1"
|
"@actions/github": "^5.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
21
.github/actions/core-tests/action.yml
vendored
21
.github/actions/core-tests/action.yml
vendored
@@ -1,21 +0,0 @@
|
|||||||
name: 'Core tests'
|
|
||||||
description: 'Run core and entrypoint tests'
|
|
||||||
runs:
|
|
||||||
using: 'composite'
|
|
||||||
steps:
|
|
||||||
- name: Core tests
|
|
||||||
if: always()
|
|
||||||
run: npm run test:core -- --reporter json --reporter-option 'output=reports/core.json'
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- name: Entrypoint tests
|
|
||||||
if: always()
|
|
||||||
run: npm run test:entrypoint -- --reporter json --reporter-option 'output=reports/entrypoint.json'
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- name: Write Markdown Summary
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
node scripts/mocha2md.js Core reports/core.json >> $GITHUB_STEP_SUMMARY
|
|
||||||
node scripts/mocha2md.js Entrypoint reports/entrypoint.json >> $GITHUB_STEP_SUMMARY
|
|
||||||
shell: bash
|
|
||||||
28
.github/actions/integration-tests/action.yml
vendored
28
.github/actions/integration-tests/action.yml
vendored
@@ -1,28 +0,0 @@
|
|||||||
name: 'Integration tests'
|
|
||||||
description: 'Run integration tests'
|
|
||||||
inputs:
|
|
||||||
github-token:
|
|
||||||
description: 'The GITHUB_TOKEN secret'
|
|
||||||
required: true
|
|
||||||
runs:
|
|
||||||
using: 'composite'
|
|
||||||
steps:
|
|
||||||
- name: Migrate DB
|
|
||||||
if: always()
|
|
||||||
run: npm run migrate up
|
|
||||||
env:
|
|
||||||
POSTGRES_URL: postgresql://postgres:postgres@localhost:5432/ci_test
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- name: Integration Tests
|
|
||||||
if: always()
|
|
||||||
run: npm run test:integration -- --reporter json --reporter-option 'output=reports/integration-tests.json'
|
|
||||||
env:
|
|
||||||
GH_TOKEN: '${{ inputs.github-token }}'
|
|
||||||
POSTGRES_URL: postgresql://postgres:postgres@localhost:5432/ci_test
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- name: Write Markdown Summary
|
|
||||||
if: always()
|
|
||||||
run: node scripts/mocha2md.js Integration reports/integration-tests.json >> $GITHUB_STEP_SUMMARY
|
|
||||||
shell: bash
|
|
||||||
26
.github/actions/package-tests/action.yml
vendored
26
.github/actions/package-tests/action.yml
vendored
@@ -1,26 +0,0 @@
|
|||||||
name: 'Package tests'
|
|
||||||
description: 'Run package tests and check types'
|
|
||||||
runs:
|
|
||||||
using: 'composite'
|
|
||||||
steps:
|
|
||||||
- name: Tests
|
|
||||||
if: always()
|
|
||||||
run: npm run test:package -- --reporter json --reporter-option 'output=reports/package-tests.json'
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- name: Type Checks
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
set -o pipefail
|
|
||||||
npm run check-types:package 2>&1 | tee reports/package-types.txt
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- name: Write Markdown Summary
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
node scripts/mocha2md.js 'Package Tests' reports/package-tests.json >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo '# Package Types' >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
|
||||||
cat reports/package-types.txt >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
|
||||||
shell: bash
|
|
||||||
86
.github/actions/service-tests/action.yml
vendored
86
.github/actions/service-tests/action.yml
vendored
@@ -1,86 +0,0 @@
|
|||||||
name: 'Service tests'
|
|
||||||
description: 'Run tests for selected services'
|
|
||||||
inputs:
|
|
||||||
github-token:
|
|
||||||
description: 'The GITHUB_TOKEN secret'
|
|
||||||
required: true
|
|
||||||
librariesio-tokens:
|
|
||||||
description: 'The SERVICETESTS_LIBRARIESIO_TOKENS secret'
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
obs-user:
|
|
||||||
description: 'The SERVICETESTS_OBS_USER secret'
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
obs-pass:
|
|
||||||
description: 'The SERVICETESTS_OBS_PASS secret'
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
sl-insight-user-uuid:
|
|
||||||
description: 'The SERVICETESTS_SL_INSIGHT_USER_UUID secret'
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
sl-insight-api-token:
|
|
||||||
description: 'The SERVICETESTS_SL_INSIGHT_API_TOKEN secret'
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
twitch-client-id:
|
|
||||||
description: 'The SERVICETESTS_TWITCH_CLIENT_ID secret'
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
twitch-client-secret:
|
|
||||||
description: 'The SERVICETESTS_TWITCH_CLIENT_SECRET secret'
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
wheelmap-token:
|
|
||||||
description: 'The SERVICETESTS_WHEELMAP_TOKEN secret'
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
youtube-api-key:
|
|
||||||
description: 'The SERVICETESTS_YOUTUBE_API_KEY secret'
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: 'composite'
|
|
||||||
steps:
|
|
||||||
- name: Derive list of service tests to run
|
|
||||||
# Note: In this step we are using an intermediate env var instead of
|
|
||||||
# passing github.event.pull_request.title as an argument
|
|
||||||
# to prevent a shell injection attack. Further reading:
|
|
||||||
# https://securitylab.github.com/research/github-actions-untrusted-input/#exploitability-and-impact
|
|
||||||
# https://securitylab.github.com/research/github-actions-untrusted-input/#remediation
|
|
||||||
if: always()
|
|
||||||
env:
|
|
||||||
TITLE: ${{ github.event.pull_request.title }}
|
|
||||||
run: npm run test:services:pr:prepare "$TITLE"
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- name: Run service tests
|
|
||||||
if: always()
|
|
||||||
run: npm run test:services:pr:run -- --reporter json --reporter-option 'output=reports/service-tests.json'
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
RETRY_COUNT: 3
|
|
||||||
GH_TOKEN: '${{ inputs.github-token }}'
|
|
||||||
LIBRARIESIO_TOKENS: '${{ inputs.librariesio-tokens }}'
|
|
||||||
OBS_USER: '${{ inputs.obs-user }}'
|
|
||||||
OBS_PASS: '${{ inputs.obs-pass }}'
|
|
||||||
SL_INSIGHT_USER_UUID: '${{ inputs.sl-insight-user-uuid }}'
|
|
||||||
SL_INSIGHT_API_TOKEN: '${{ inputs.sl-insight-api-token }}'
|
|
||||||
TWITCH_CLIENT_ID: '${{ inputs.twitch-client-id }}'
|
|
||||||
TWITCH_CLIENT_SECRET: '${{ inputs.twitch-client-secret }}'
|
|
||||||
WHEELMAP_TOKEN: '${{ inputs.wheelmap-token }}'
|
|
||||||
YOUTUBE_API_KEY: '${{ inputs.youtube-api-key }}'
|
|
||||||
|
|
||||||
- name: Write Markdown Summary
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
if test -f 'reports/service-tests.json'; then
|
|
||||||
echo '# Services' >> $GITHUB_STEP_SUMMARY
|
|
||||||
sed -e 's/^/- /' pull-request-services.log >> $GITHUB_STEP_SUMMARY
|
|
||||||
node scripts/mocha2md.js Report reports/service-tests.json >> $GITHUB_STEP_SUMMARY
|
|
||||||
else
|
|
||||||
echo 'No services found. Nothing to do.' >> $GITHUB_STEP_SUMMARY
|
|
||||||
fi
|
|
||||||
shell: bash
|
|
||||||
36
.github/actions/setup/action.yml
vendored
36
.github/actions/setup/action.yml
vendored
@@ -1,36 +0,0 @@
|
|||||||
name: 'Set up project'
|
|
||||||
description: 'Set up project'
|
|
||||||
inputs:
|
|
||||||
node-version:
|
|
||||||
description: 'Version Spec of the version to use. Examples: 12.x, 10.15.1, >=10.15.0.'
|
|
||||||
required: true
|
|
||||||
cypress:
|
|
||||||
description: 'Install Cypress binary (boolean)'
|
|
||||||
type: boolean
|
|
||||||
# https://docs.cypress.io/guides/getting-started/installing-cypress.html#Skipping-installation
|
|
||||||
# We don't need to install the Cypress binary in jobs that aren't actually running Cypress.
|
|
||||||
required: false
|
|
||||||
default: false
|
|
||||||
runs:
|
|
||||||
using: 'composite'
|
|
||||||
steps:
|
|
||||||
- name: Install Node JS ${{ inputs.node-version }}
|
|
||||||
uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: ${{ inputs.node-version }}
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
if: ${{ inputs.cypress == 'false' }}
|
|
||||||
env:
|
|
||||||
CYPRESS_INSTALL_BINARY: 0
|
|
||||||
run: |
|
|
||||||
echo "skipping cypress binary"
|
|
||||||
npm ci
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- name: Install dependencies (including cypress binary)
|
|
||||||
if: ${{ inputs.cypress == 'true' }}
|
|
||||||
run: |
|
|
||||||
echo "installing cypress binary"
|
|
||||||
npm ci
|
|
||||||
shell: bash
|
|
||||||
12
.github/actions/tester/action.yml
vendored
Normal file
12
.github/actions/tester/action.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
name: 'Tester'
|
||||||
|
description: 'Just for debugging purposes'
|
||||||
|
branding:
|
||||||
|
icon: 'check-circle'
|
||||||
|
color: 'green'
|
||||||
|
inputs:
|
||||||
|
build-args:
|
||||||
|
description: 'List of build-time variables'
|
||||||
|
required: true
|
||||||
|
runs:
|
||||||
|
using: 'node12'
|
||||||
|
main: 'index.js'
|
||||||
10
.github/actions/tester/index.js
vendored
Normal file
10
.github/actions/tester/index.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const core = require('@actions/core')
|
||||||
|
|
||||||
|
async function run() {
|
||||||
|
const buildArgs = await core.getInput('build-args', true)
|
||||||
|
console.log(buildArgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
run()
|
||||||
416
.github/actions/tester/package-lock.json
generated
vendored
Normal file
416
.github/actions/tester/package-lock.json
generated
vendored
Normal file
@@ -0,0 +1,416 @@
|
|||||||
|
{
|
||||||
|
"name": "close-bot",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"lockfileVersion": 2,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "close-bot",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"license": "CC0",
|
||||||
|
"dependencies": {
|
||||||
|
"@actions/core": "^1.6.0",
|
||||||
|
"@actions/github": "^5.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@actions/core": {
|
||||||
|
"version": "1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.6.0.tgz",
|
||||||
|
"integrity": "sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@actions/http-client": "^1.0.11"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@actions/github": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@actions/github/-/github-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-QvE9eAAfEsS+yOOk0cylLBIO/d6WyWIOvsxxzdrPFaud39G6BOkUwScXZn1iBzQzHyu9SBkkLSWlohDWdsasAQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@actions/http-client": "^1.0.11",
|
||||||
|
"@octokit/core": "^3.4.0",
|
||||||
|
"@octokit/plugin-paginate-rest": "^2.13.3",
|
||||||
|
"@octokit/plugin-rest-endpoint-methods": "^5.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@actions/http-client": {
|
||||||
|
"version": "1.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
|
||||||
|
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
|
||||||
|
"dependencies": {
|
||||||
|
"tunnel": "0.0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@octokit/auth-token": {
|
||||||
|
"version": "2.4.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.5.tgz",
|
||||||
|
"integrity": "sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@octokit/types": "^6.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@octokit/core": {
|
||||||
|
"version": "3.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.4.0.tgz",
|
||||||
|
"integrity": "sha512-6/vlKPP8NF17cgYXqucdshWqmMZGXkuvtcrWCgU5NOI0Pl2GjlmZyWgBMrU8zJ3v2MJlM6++CiB45VKYmhiWWg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@octokit/auth-token": "^2.4.4",
|
||||||
|
"@octokit/graphql": "^4.5.8",
|
||||||
|
"@octokit/request": "^5.4.12",
|
||||||
|
"@octokit/request-error": "^2.0.5",
|
||||||
|
"@octokit/types": "^6.0.3",
|
||||||
|
"before-after-hook": "^2.2.0",
|
||||||
|
"universal-user-agent": "^6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@octokit/endpoint": {
|
||||||
|
"version": "6.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.11.tgz",
|
||||||
|
"integrity": "sha512-fUIPpx+pZyoLW4GCs3yMnlj2LfoXTWDUVPTC4V3MUEKZm48W+XYpeWSZCv+vYF1ZABUm2CqnDVf1sFtIYrj7KQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@octokit/types": "^6.0.3",
|
||||||
|
"is-plain-object": "^5.0.0",
|
||||||
|
"universal-user-agent": "^6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@octokit/graphql": {
|
||||||
|
"version": "4.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.6.2.tgz",
|
||||||
|
"integrity": "sha512-WmsIR1OzOr/3IqfG9JIczI8gMJUMzzyx5j0XXQ4YihHtKlQc+u35VpVoOXhlKAlaBntvry1WpAzPl/a+s3n89Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"@octokit/request": "^5.3.0",
|
||||||
|
"@octokit/types": "^6.0.3",
|
||||||
|
"universal-user-agent": "^6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@octokit/openapi-types": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-gV/8DJhAL/04zjTI95a7FhQwS6jlEE0W/7xeYAzuArD0KVAVWDLP2f3vi98hs3HLTczxXdRK/mF0tRoQPpolEw=="
|
||||||
|
},
|
||||||
|
"node_modules/@octokit/plugin-paginate-rest": {
|
||||||
|
"version": "2.13.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.13.3.tgz",
|
||||||
|
"integrity": "sha512-46lptzM9lTeSmIBt/sVP/FLSTPGx6DCzAdSX3PfeJ3mTf4h9sGC26WpaQzMEq/Z44cOcmx8VsOhO+uEgE3cjYg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@octokit/types": "^6.11.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@octokit/core": ">=2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@octokit/plugin-rest-endpoint-methods": {
|
||||||
|
"version": "5.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.1.1.tgz",
|
||||||
|
"integrity": "sha512-u4zy0rVA8darm/AYsIeWkRalhQR99qPL1D/EXHejV2yaECMdHfxXiTXtba8NMBSajOJe8+C9g+EqMKSvysx0dg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@octokit/types": "^6.14.1",
|
||||||
|
"deprecation": "^2.3.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@octokit/core": ">=3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@octokit/request": {
|
||||||
|
"version": "5.4.15",
|
||||||
|
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.15.tgz",
|
||||||
|
"integrity": "sha512-6UnZfZzLwNhdLRreOtTkT9n57ZwulCve8q3IT/Z477vThu6snfdkBuhxnChpOKNGxcQ71ow561Qoa6uqLdPtag==",
|
||||||
|
"dependencies": {
|
||||||
|
"@octokit/endpoint": "^6.0.1",
|
||||||
|
"@octokit/request-error": "^2.0.0",
|
||||||
|
"@octokit/types": "^6.7.1",
|
||||||
|
"is-plain-object": "^5.0.0",
|
||||||
|
"node-fetch": "^2.6.1",
|
||||||
|
"universal-user-agent": "^6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@octokit/request-error": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-T/2wcCFyM7SkXzNoyVNWjyVlUwBvW3igM3Btr/eKYiPmucXTtkxt2RBsf6gn3LTzaLSLTQtNmvg+dGsOxQrjZg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@octokit/types": "^6.0.3",
|
||||||
|
"deprecation": "^2.0.0",
|
||||||
|
"once": "^1.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@octokit/types": {
|
||||||
|
"version": "6.14.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.14.2.tgz",
|
||||||
|
"integrity": "sha512-wiQtW9ZSy4OvgQ09iQOdyXYNN60GqjCL/UdMsepDr1Gr0QzpW6irIKbH3REuAHXAhxkEk9/F2a3Gcs1P6kW5jA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@octokit/openapi-types": "^7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/before-after-hook": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.1.tgz",
|
||||||
|
"integrity": "sha512-/6FKxSTWoJdbsLDF8tdIjaRiFXiE6UHsEHE3OPI/cwPURCVi1ukP0gmLn7XWEiFk5TcwQjjY5PWsU+j+tgXgmw=="
|
||||||
|
},
|
||||||
|
"node_modules/deprecation": {
|
||||||
|
"version": "2.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
|
||||||
|
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
|
||||||
|
},
|
||||||
|
"node_modules/is-plain-object": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/node-fetch": {
|
||||||
|
"version": "2.6.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
||||||
|
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"whatwg-url": "^5.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "4.x || >=6.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"encoding": "^0.1.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"encoding": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/once": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||||
|
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||||
|
"dependencies": {
|
||||||
|
"wrappy": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tr46": {
|
||||||
|
"version": "0.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||||
|
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
|
||||||
|
},
|
||||||
|
"node_modules/tunnel": {
|
||||||
|
"version": "0.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
|
||||||
|
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/universal-user-agent": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
|
||||||
|
},
|
||||||
|
"node_modules/webidl-conversions": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||||
|
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
|
||||||
|
},
|
||||||
|
"node_modules/whatwg-url": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||||
|
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
|
||||||
|
"dependencies": {
|
||||||
|
"tr46": "~0.0.3",
|
||||||
|
"webidl-conversions": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/wrappy": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
|
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@actions/core": {
|
||||||
|
"version": "1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.6.0.tgz",
|
||||||
|
"integrity": "sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw==",
|
||||||
|
"requires": {
|
||||||
|
"@actions/http-client": "^1.0.11"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@actions/github": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@actions/github/-/github-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-QvE9eAAfEsS+yOOk0cylLBIO/d6WyWIOvsxxzdrPFaud39G6BOkUwScXZn1iBzQzHyu9SBkkLSWlohDWdsasAQ==",
|
||||||
|
"requires": {
|
||||||
|
"@actions/http-client": "^1.0.11",
|
||||||
|
"@octokit/core": "^3.4.0",
|
||||||
|
"@octokit/plugin-paginate-rest": "^2.13.3",
|
||||||
|
"@octokit/plugin-rest-endpoint-methods": "^5.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@actions/http-client": {
|
||||||
|
"version": "1.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
|
||||||
|
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
|
||||||
|
"requires": {
|
||||||
|
"tunnel": "0.0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@octokit/auth-token": {
|
||||||
|
"version": "2.4.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.5.tgz",
|
||||||
|
"integrity": "sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA==",
|
||||||
|
"requires": {
|
||||||
|
"@octokit/types": "^6.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@octokit/core": {
|
||||||
|
"version": "3.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.4.0.tgz",
|
||||||
|
"integrity": "sha512-6/vlKPP8NF17cgYXqucdshWqmMZGXkuvtcrWCgU5NOI0Pl2GjlmZyWgBMrU8zJ3v2MJlM6++CiB45VKYmhiWWg==",
|
||||||
|
"requires": {
|
||||||
|
"@octokit/auth-token": "^2.4.4",
|
||||||
|
"@octokit/graphql": "^4.5.8",
|
||||||
|
"@octokit/request": "^5.4.12",
|
||||||
|
"@octokit/request-error": "^2.0.5",
|
||||||
|
"@octokit/types": "^6.0.3",
|
||||||
|
"before-after-hook": "^2.2.0",
|
||||||
|
"universal-user-agent": "^6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@octokit/endpoint": {
|
||||||
|
"version": "6.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.11.tgz",
|
||||||
|
"integrity": "sha512-fUIPpx+pZyoLW4GCs3yMnlj2LfoXTWDUVPTC4V3MUEKZm48W+XYpeWSZCv+vYF1ZABUm2CqnDVf1sFtIYrj7KQ==",
|
||||||
|
"requires": {
|
||||||
|
"@octokit/types": "^6.0.3",
|
||||||
|
"is-plain-object": "^5.0.0",
|
||||||
|
"universal-user-agent": "^6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@octokit/graphql": {
|
||||||
|
"version": "4.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.6.2.tgz",
|
||||||
|
"integrity": "sha512-WmsIR1OzOr/3IqfG9JIczI8gMJUMzzyx5j0XXQ4YihHtKlQc+u35VpVoOXhlKAlaBntvry1WpAzPl/a+s3n89Q==",
|
||||||
|
"requires": {
|
||||||
|
"@octokit/request": "^5.3.0",
|
||||||
|
"@octokit/types": "^6.0.3",
|
||||||
|
"universal-user-agent": "^6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@octokit/openapi-types": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-gV/8DJhAL/04zjTI95a7FhQwS6jlEE0W/7xeYAzuArD0KVAVWDLP2f3vi98hs3HLTczxXdRK/mF0tRoQPpolEw=="
|
||||||
|
},
|
||||||
|
"@octokit/plugin-paginate-rest": {
|
||||||
|
"version": "2.13.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.13.3.tgz",
|
||||||
|
"integrity": "sha512-46lptzM9lTeSmIBt/sVP/FLSTPGx6DCzAdSX3PfeJ3mTf4h9sGC26WpaQzMEq/Z44cOcmx8VsOhO+uEgE3cjYg==",
|
||||||
|
"requires": {
|
||||||
|
"@octokit/types": "^6.11.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@octokit/plugin-rest-endpoint-methods": {
|
||||||
|
"version": "5.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.1.1.tgz",
|
||||||
|
"integrity": "sha512-u4zy0rVA8darm/AYsIeWkRalhQR99qPL1D/EXHejV2yaECMdHfxXiTXtba8NMBSajOJe8+C9g+EqMKSvysx0dg==",
|
||||||
|
"requires": {
|
||||||
|
"@octokit/types": "^6.14.1",
|
||||||
|
"deprecation": "^2.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@octokit/request": {
|
||||||
|
"version": "5.4.15",
|
||||||
|
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.15.tgz",
|
||||||
|
"integrity": "sha512-6UnZfZzLwNhdLRreOtTkT9n57ZwulCve8q3IT/Z477vThu6snfdkBuhxnChpOKNGxcQ71ow561Qoa6uqLdPtag==",
|
||||||
|
"requires": {
|
||||||
|
"@octokit/endpoint": "^6.0.1",
|
||||||
|
"@octokit/request-error": "^2.0.0",
|
||||||
|
"@octokit/types": "^6.7.1",
|
||||||
|
"is-plain-object": "^5.0.0",
|
||||||
|
"node-fetch": "^2.6.1",
|
||||||
|
"universal-user-agent": "^6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@octokit/request-error": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-T/2wcCFyM7SkXzNoyVNWjyVlUwBvW3igM3Btr/eKYiPmucXTtkxt2RBsf6gn3LTzaLSLTQtNmvg+dGsOxQrjZg==",
|
||||||
|
"requires": {
|
||||||
|
"@octokit/types": "^6.0.3",
|
||||||
|
"deprecation": "^2.0.0",
|
||||||
|
"once": "^1.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@octokit/types": {
|
||||||
|
"version": "6.14.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.14.2.tgz",
|
||||||
|
"integrity": "sha512-wiQtW9ZSy4OvgQ09iQOdyXYNN60GqjCL/UdMsepDr1Gr0QzpW6irIKbH3REuAHXAhxkEk9/F2a3Gcs1P6kW5jA==",
|
||||||
|
"requires": {
|
||||||
|
"@octokit/openapi-types": "^7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"before-after-hook": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.1.tgz",
|
||||||
|
"integrity": "sha512-/6FKxSTWoJdbsLDF8tdIjaRiFXiE6UHsEHE3OPI/cwPURCVi1ukP0gmLn7XWEiFk5TcwQjjY5PWsU+j+tgXgmw=="
|
||||||
|
},
|
||||||
|
"deprecation": {
|
||||||
|
"version": "2.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
|
||||||
|
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
|
||||||
|
},
|
||||||
|
"is-plain-object": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
|
||||||
|
},
|
||||||
|
"node-fetch": {
|
||||||
|
"version": "2.6.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
||||||
|
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
|
||||||
|
"requires": {
|
||||||
|
"whatwg-url": "^5.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"once": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||||
|
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||||
|
"requires": {
|
||||||
|
"wrappy": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tr46": {
|
||||||
|
"version": "0.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||||
|
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
|
||||||
|
},
|
||||||
|
"tunnel": {
|
||||||
|
"version": "0.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
|
||||||
|
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
|
||||||
|
},
|
||||||
|
"universal-user-agent": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
|
||||||
|
},
|
||||||
|
"webidl-conversions": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||||
|
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
|
||||||
|
},
|
||||||
|
"whatwg-url": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||||
|
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
|
||||||
|
"requires": {
|
||||||
|
"tr46": "~0.0.3",
|
||||||
|
"webidl-conversions": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"wrappy": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
|
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
.github/actions/tester/package.json
vendored
Normal file
16
.github/actions/tester/package.json
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "close-bot",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "chris48s",
|
||||||
|
"license": "CC0",
|
||||||
|
"dependencies": {
|
||||||
|
"@actions/core": "^1.6.0",
|
||||||
|
"@actions/github": "^5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
11
.github/dependabot.yml
vendored
11
.github/dependabot.yml
vendored
@@ -8,7 +8,6 @@ updates:
|
|||||||
day: friday
|
day: friday
|
||||||
time: '12:00'
|
time: '12:00'
|
||||||
open-pull-requests-limit: 99
|
open-pull-requests-limit: 99
|
||||||
rebase-strategy: disabled
|
|
||||||
ignore:
|
ignore:
|
||||||
# https://github.com/badges/shields/issues/7324
|
# https://github.com/badges/shields/issues/7324
|
||||||
# https://github.com/badges/shields/issues/7447
|
# https://github.com/badges/shields/issues/7447
|
||||||
@@ -28,7 +27,6 @@ updates:
|
|||||||
day: friday
|
day: friday
|
||||||
time: '12:00'
|
time: '12:00'
|
||||||
open-pull-requests-limit: 99
|
open-pull-requests-limit: 99
|
||||||
rebase-strategy: disabled
|
|
||||||
|
|
||||||
# close-bot package dependencies
|
# close-bot package dependencies
|
||||||
- package-ecosystem: npm
|
- package-ecosystem: npm
|
||||||
@@ -38,12 +36,3 @@ updates:
|
|||||||
day: friday
|
day: friday
|
||||||
time: '12:00'
|
time: '12:00'
|
||||||
open-pull-requests-limit: 99
|
open-pull-requests-limit: 99
|
||||||
rebase-strategy: disabled
|
|
||||||
|
|
||||||
# GH actions
|
|
||||||
- package-ecosystem: 'github-actions'
|
|
||||||
directory: '/'
|
|
||||||
schedule:
|
|
||||||
interval: weekly
|
|
||||||
open-pull-requests-limit: 99
|
|
||||||
rebase-strategy: disabled
|
|
||||||
|
|||||||
10
.github/scripts/cleanup-review-apps.sh
vendored
10
.github/scripts/cleanup-review-apps.sh
vendored
@@ -1,10 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -euxo pipefail
|
|
||||||
|
|
||||||
apps=$(flyctl apps list --json | jq -r .[].ID | grep -E "pr-[0-9]+-badges-shields") || exit 0
|
|
||||||
|
|
||||||
for app in $apps
|
|
||||||
do
|
|
||||||
flyctl apps destroy "$app" -y
|
|
||||||
done
|
|
||||||
35
.github/scripts/deploy-review-app.sh
vendored
35
.github/scripts/deploy-review-app.sh
vendored
@@ -1,35 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -euxo pipefail
|
|
||||||
|
|
||||||
app="pr-$PR_NUMBER-badges-shields"
|
|
||||||
region="ewr"
|
|
||||||
org="shields-io"
|
|
||||||
|
|
||||||
# Get PR JSON from the API
|
|
||||||
# This will fail if $PR_NUMBER is not a valid PR
|
|
||||||
pr_json=$(curl --fail "https://api.github.com/repos/badges/shields/pulls/$PR_NUMBER")
|
|
||||||
|
|
||||||
# Attempt to apply the PR diff to the target branch
|
|
||||||
# This will fail if it does not merge cleanly
|
|
||||||
git config user.name "actions[bot]"
|
|
||||||
git config user.email "actions@users.noreply.github.com"
|
|
||||||
git fetch origin "pull/$PR_NUMBER/head:pr-$PR_NUMBER"
|
|
||||||
git merge "pr-$PR_NUMBER"
|
|
||||||
|
|
||||||
# If the app does not already exist, create it
|
|
||||||
if ! flyctl status --app "$app"; then
|
|
||||||
flyctl launch --no-deploy --copy-config --name "$app" --region "$region" --org "$org"
|
|
||||||
echo $SECRETS | tr " " "\n" | flyctl secrets import --app "$app"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Deploy
|
|
||||||
flyctl deploy --app "$app" --region "$region"
|
|
||||||
|
|
||||||
# Post a comment on the PR
|
|
||||||
app_url=$(flyctl status --app "$app" --json | jq -r .Hostname)
|
|
||||||
comment_url=$(echo "$pr_json" | jq .comments_url -r)
|
|
||||||
curl "$comment_url" \
|
|
||||||
-X POST \
|
|
||||||
-H "Authorization: token $GITHUB_TOKEN" \
|
|
||||||
--data "{\"body\":\"🚀 Updated review app: https://$app_url\"}"
|
|
||||||
8
.github/workflows/auto-close.yml
vendored
8
.github/workflows/auto-close.yml
vendored
@@ -1,18 +1,16 @@
|
|||||||
name: Auto close
|
name: Auto close
|
||||||
on:
|
on: pull_request_target
|
||||||
pull_request_target:
|
|
||||||
types: [opened]
|
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
auto-close:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: github.actor == 'dependabot[bot]'
|
if: github.actor == 'dependabot[bot]'
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Install action dependencies
|
- name: Install action dependencies
|
||||||
run: cd .github/actions/close-bot && npm ci
|
run: cd .github/actions/close-bot && npm ci
|
||||||
|
|||||||
17
.github/workflows/build-docker-image.yml
vendored
17
.github/workflows/build-docker-image.yml
vendored
@@ -3,25 +3,20 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-docker-image:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v1
|
||||||
with:
|
|
||||||
version: v0.9.1
|
|
||||||
|
|
||||||
- name: Set Git Short SHA
|
|
||||||
run: echo "SHORT_SHA=${GITHUB_SHA::7}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
uses: docker/build-push-action@v4
|
uses: docker/build-push-action@v2
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
push: false
|
push: false
|
||||||
tags: ghcr.io/badges/shields:pr-validation
|
tags: shieldsio/shields:pr-validation
|
||||||
build-args: |
|
build-args: |
|
||||||
version=${{ env.SHORT_SHA }}
|
version=${GITHUB_SHA::7}
|
||||||
|
|||||||
24
.github/workflows/cleanup-review-apps.yml
vendored
24
.github/workflows/cleanup-review-apps.yml
vendored
@@ -1,24 +0,0 @@
|
|||||||
name: Cleanup Review Apps
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: '0 7 * * *'
|
|
||||||
# At 07:00, daily
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
cleanup-review-apps:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
environment: 'Review Apps'
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: superfly/flyctl-actions/setup-flyctl@master
|
|
||||||
|
|
||||||
- name: install jq
|
|
||||||
run: |
|
|
||||||
sudo apt-get -qq update
|
|
||||||
sudo apt-get install -y jq
|
|
||||||
|
|
||||||
- run: .github/scripts/cleanup-review-apps.sh
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
|
|
||||||
30
.github/workflows/create-release.yml
vendored
30
.github/workflows/create-release.yml
vendored
@@ -4,10 +4,6 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
types: [closed]
|
types: [closed]
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
packages: write
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
create-release:
|
create-release:
|
||||||
if: |
|
if: |
|
||||||
@@ -24,7 +20,7 @@ jobs:
|
|||||||
run: echo "::set-output name=date::$(date --rfc-3339=date)"
|
run: echo "::set-output name=date::$(date --rfc-3339=date)"
|
||||||
|
|
||||||
- name: Checkout branch "master"
|
- name: Checkout branch "master"
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
ref: 'master'
|
ref: 'master'
|
||||||
|
|
||||||
@@ -35,37 +31,19 @@ jobs:
|
|||||||
tag: server-${{ steps.date.outputs.date }}
|
tag: server-${{ steps.date.outputs.date }}
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v1
|
||||||
with:
|
|
||||||
version: v0.9.1
|
|
||||||
|
|
||||||
- name: Login to DockerHub
|
- name: Login to DockerHub
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v1
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Build and push snapshot release to DockerHub
|
- name: Build and push snapshot release to DockerHub
|
||||||
uses: docker/build-push-action@v4
|
uses: docker/build-push-action@v2
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
push: true
|
push: true
|
||||||
tags: shieldsio/shields:server-${{ steps.date.outputs.date }}
|
tags: shieldsio/shields:server-${{ steps.date.outputs.date }}
|
||||||
build-args: |
|
build-args: |
|
||||||
version=server-${{ steps.date.outputs.date }}
|
version=server-${{ steps.date.outputs.date }}
|
||||||
|
|
||||||
- name: Login to GHCR
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Build and push snapshot release to GHCR
|
|
||||||
uses: docker/build-push-action@v4
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
push: true
|
|
||||||
tags: ghcr.io/badges/shields:server-${{ steps.date.outputs.date }}
|
|
||||||
build-args: |
|
|
||||||
version=server-${{ steps.date.outputs.date }}
|
|
||||||
|
|||||||
29
.github/workflows/danger.yml
vendored
29
.github/workflows/danger.yml
vendored
@@ -1,29 +0,0 @@
|
|||||||
name: Danger
|
|
||||||
on:
|
|
||||||
pull_request_target:
|
|
||||||
types: [opened, reopened, synchronize]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
checks: write
|
|
||||||
pull-requests: write
|
|
||||||
statuses: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
danger:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.actor != 'dependabot[bot]' && github.actor != 'repo-ranger[bot]'
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Setup
|
|
||||||
uses: ./.github/actions/setup
|
|
||||||
with:
|
|
||||||
node-version: 16
|
|
||||||
|
|
||||||
- name: Danger
|
|
||||||
run: npm run danger ci
|
|
||||||
env:
|
|
||||||
# https://github.com/gatsbyjs/gatsby/pull/11555
|
|
||||||
NODE_ENV: test
|
|
||||||
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
|
|
||||||
26
.github/workflows/deploy-docs.yml
vendored
26
.github/workflows/deploy-docs.yml
vendored
@@ -3,30 +3,24 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
deploy-docs:
|
build-and-deploy:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2.3.1
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Setup
|
|
||||||
uses: ./.github/actions/setup
|
|
||||||
with:
|
|
||||||
node-version: 16
|
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: npm run build-docs
|
run: |
|
||||||
|
npm ci
|
||||||
|
npm run build-docs
|
||||||
|
|
||||||
- name: Deploy
|
- name: Deploy
|
||||||
uses: JamesIves/github-pages-deploy-action@v4
|
uses: JamesIves/github-pages-deploy-action@3.7.1
|
||||||
with:
|
with:
|
||||||
branch: gh-pages
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
folder: api-docs
|
BRANCH: gh-pages
|
||||||
clean: true
|
FOLDER: api-docs
|
||||||
|
CLEAN: true
|
||||||
|
|||||||
43
.github/workflows/deploy-review-app.yml
vendored
43
.github/workflows/deploy-review-app.yml
vendored
@@ -1,43 +0,0 @@
|
|||||||
name: Create/Update Review App
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
pr_number:
|
|
||||||
description: 'PR Number to deploy e.g: 1234'
|
|
||||||
required: true
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
deploy-review-app:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
environment: 'Review Apps'
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- uses: superfly/flyctl-actions/setup-flyctl@master
|
|
||||||
|
|
||||||
- name: install jq
|
|
||||||
run: |
|
|
||||||
sudo apt-get -qq update
|
|
||||||
sudo apt-get install -y jq
|
|
||||||
|
|
||||||
- run: .github/scripts/deploy-review-app.sh
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
|
|
||||||
PR_NUMBER: ${{ github.event.inputs.pr_number }}
|
|
||||||
# credentials to set when we create the review app
|
|
||||||
SECRETS: |
|
|
||||||
GH_TOKEN=${{ secrets.GH_PAT }}
|
|
||||||
LIBRARIESIO_TOKENS=${{ secrets.SERVICETESTS_LIBRARIESIO_TOKENS }}
|
|
||||||
OBS_USER=${{ secrets.SERVICETESTS_OBS_USER }}
|
|
||||||
OBS_PASS=${{ secrets.SERVICETESTS_OBS_PASS }}
|
|
||||||
SL_INSIGHT_API_TOKEN=${{ secrets.SERVICETESTS_SL_INSIGHT_USER_UUID }}
|
|
||||||
SL_INSIGHT_USER_UUID=${{ secrets.SERVICETESTS_SL_INSIGHT_API_TOKEN }}
|
|
||||||
TWITCH_CLIENT_ID=${{ secrets.SERVICETESTS_TWITCH_CLIENT_ID }}
|
|
||||||
TWITCH_CLIENT_SECRET=${{ secrets.SERVICETESTS_TWITCH_CLIENT_SECRET }}
|
|
||||||
WHEELMAP_TOKEN=${{ secrets.SERVICETESTS_WHEELMAP_TOKEN }}
|
|
||||||
YOUTUBE_API_KEY=${{ secrets.SERVICETESTS_YOUTUBE_API_KEY }}
|
|
||||||
8
.github/workflows/draft-release.yml
vendored
8
.github/workflows/draft-release.yml
vendored
@@ -5,16 +5,12 @@ on:
|
|||||||
# At 01:00 on the first day of every month
|
# At 01:00 on the first day of every month
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
|
||||||
pull-requests: write
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
draft-release:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Draft Release
|
- name: Draft Release
|
||||||
uses: ./.github/actions/draft-release
|
uses: ./.github/actions/draft-release
|
||||||
|
|||||||
13
.github/workflows/enforce-dependency-review.yml
vendored
13
.github/workflows/enforce-dependency-review.yml
vendored
@@ -1,13 +0,0 @@
|
|||||||
name: 'Dependency Review'
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [opened, reopened, synchronize]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
enforce-dependency-review:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: 'Checkout Repository'
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
- name: 'Dependency Review'
|
|
||||||
uses: actions/dependency-review-action@v3
|
|
||||||
38
.github/workflows/publish-docker-next.yml
vendored
38
.github/workflows/publish-docker-next.yml
vendored
@@ -4,51 +4,27 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
|
|
||||||
permissions:
|
|
||||||
packages: write
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
publish-docker-next:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v1
|
||||||
with:
|
|
||||||
version: v0.9.1
|
|
||||||
|
|
||||||
- name: Login to DockerHub
|
- name: Login to DockerHub
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v1
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Set Git Short SHA
|
- name: Build and push
|
||||||
run: echo "SHORT_SHA=${GITHUB_SHA::7}" >> $GITHUB_ENV
|
uses: docker/build-push-action@v2
|
||||||
|
|
||||||
- name: Build and push to DockerHub
|
|
||||||
uses: docker/build-push-action@v4
|
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
push: true
|
push: true
|
||||||
tags: shieldsio/shields:next
|
tags: shieldsio/shields:next
|
||||||
build-args: |
|
build-args: |
|
||||||
version=${{ env.SHORT_SHA }}
|
version=${GITHUB_SHA::7}
|
||||||
|
|
||||||
- name: Login to GHCR
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Build and push to GHCR
|
|
||||||
uses: docker/build-push-action@v4
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
push: true
|
|
||||||
tags: ghcr.io/badges/shields:next
|
|
||||||
build-args: |
|
|
||||||
version=${{ env.SHORT_SHA }}
|
|
||||||
|
|||||||
20
.github/workflows/test-build-args.yml
vendored
Normal file
20
.github/workflows/test-build-args.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
name: Tester
|
||||||
|
on: push
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Install action dependencies
|
||||||
|
run: cd .github/actions/tester && npm ci
|
||||||
|
|
||||||
|
- name: Set Git Short SHA
|
||||||
|
run: echo "SHORT_SHA=${GITHUB_SHA::7}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- uses: ./.github/actions/tester
|
||||||
|
with:
|
||||||
|
build-args: |
|
||||||
|
version=${{ env.SHORT_SHA }}
|
||||||
49
.github/workflows/test-e2e.yml
vendored
49
.github/workflows/test-e2e.yml
vendored
@@ -1,49 +0,0 @@
|
|||||||
name: E2E
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [opened, reopened, synchronize]
|
|
||||||
push:
|
|
||||||
branches-ignore:
|
|
||||||
- 'gh-pages'
|
|
||||||
- 'dependabot/**'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test-e2e:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Cache Cypress binary
|
|
||||||
id: cache-cypress
|
|
||||||
uses: actions/cache@v3
|
|
||||||
env:
|
|
||||||
cache-name: cache-cypress
|
|
||||||
with:
|
|
||||||
path: ~/.cache/Cypress
|
|
||||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
|
||||||
|
|
||||||
- name: Setup
|
|
||||||
uses: ./.github/actions/setup
|
|
||||||
with:
|
|
||||||
node-version: 16
|
|
||||||
cypress: true
|
|
||||||
|
|
||||||
- name: Run tests
|
|
||||||
env:
|
|
||||||
GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
|
|
||||||
run: npm run e2e
|
|
||||||
|
|
||||||
- name: Archive videos
|
|
||||||
if: always()
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: videos
|
|
||||||
path: cypress/videos
|
|
||||||
|
|
||||||
- name: Archive screenshots
|
|
||||||
if: always()
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: screenshots
|
|
||||||
path: cypress/screenshots
|
|
||||||
52
.github/workflows/test-integration-17.yml
vendored
52
.github/workflows/test-integration-17.yml
vendored
@@ -1,52 +0,0 @@
|
|||||||
name: Integration@node 17
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [opened, reopened, synchronize]
|
|
||||||
push:
|
|
||||||
branches-ignore:
|
|
||||||
- 'gh-pages'
|
|
||||||
- 'dependabot/**'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test-integration-17:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
env:
|
|
||||||
PAT_EXISTS: ${{ secrets.GH_PAT != '' }}
|
|
||||||
|
|
||||||
services:
|
|
||||||
postgres:
|
|
||||||
image: postgres
|
|
||||||
env:
|
|
||||||
POSTGRES_USER: postgres
|
|
||||||
POSTGRES_PASSWORD: postgres
|
|
||||||
POSTGRES_DB: ci_test
|
|
||||||
options: >-
|
|
||||||
--health-cmd pg_isready
|
|
||||||
--health-interval 10s
|
|
||||||
--health-timeout 5s
|
|
||||||
--health-retries 5
|
|
||||||
ports:
|
|
||||||
- 5432:5432
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Setup
|
|
||||||
uses: ./.github/actions/setup
|
|
||||||
with:
|
|
||||||
node-version: 17
|
|
||||||
env:
|
|
||||||
NPM_CONFIG_ENGINE_STRICT: 'false'
|
|
||||||
|
|
||||||
- name: Integration Tests (with PAT)
|
|
||||||
if: ${{ env.PAT_EXISTS == 'true' }}
|
|
||||||
uses: ./.github/actions/integration-tests
|
|
||||||
with:
|
|
||||||
github-token: '${{ secrets.GH_PAT }}'
|
|
||||||
|
|
||||||
- name: Integration Tests (with workflow token)
|
|
||||||
if: ${{ env.PAT_EXISTS == 'false' }}
|
|
||||||
uses: ./.github/actions/integration-tests
|
|
||||||
with:
|
|
||||||
github-token: '${{ secrets.GITHUB_TOKEN }}'
|
|
||||||
50
.github/workflows/test-integration.yml
vendored
50
.github/workflows/test-integration.yml
vendored
@@ -1,50 +0,0 @@
|
|||||||
name: Integration
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [opened, reopened, synchronize]
|
|
||||||
push:
|
|
||||||
branches-ignore:
|
|
||||||
- 'gh-pages'
|
|
||||||
- 'dependabot/**'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test-integration:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
env:
|
|
||||||
PAT_EXISTS: ${{ secrets.GH_PAT != '' }}
|
|
||||||
|
|
||||||
services:
|
|
||||||
postgres:
|
|
||||||
image: postgres
|
|
||||||
env:
|
|
||||||
POSTGRES_USER: postgres
|
|
||||||
POSTGRES_PASSWORD: postgres
|
|
||||||
POSTGRES_DB: ci_test
|
|
||||||
options: >-
|
|
||||||
--health-cmd pg_isready
|
|
||||||
--health-interval 10s
|
|
||||||
--health-timeout 5s
|
|
||||||
--health-retries 5
|
|
||||||
ports:
|
|
||||||
- 5432:5432
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Setup
|
|
||||||
uses: ./.github/actions/setup
|
|
||||||
with:
|
|
||||||
node-version: 16
|
|
||||||
|
|
||||||
- name: Integration Tests (with PAT)
|
|
||||||
if: ${{ env.PAT_EXISTS == 'true' }}
|
|
||||||
uses: ./.github/actions/integration-tests
|
|
||||||
with:
|
|
||||||
github-token: '${{ secrets.GH_PAT }}'
|
|
||||||
|
|
||||||
- name: Integration Tests (with workflow token)
|
|
||||||
if: ${{ env.PAT_EXISTS == 'false' }}
|
|
||||||
uses: ./.github/actions/integration-tests
|
|
||||||
with:
|
|
||||||
github-token: '${{ secrets.GITHUB_TOKEN }}'
|
|
||||||
28
.github/workflows/test-lint.yml
vendored
28
.github/workflows/test-lint.yml
vendored
@@ -1,28 +0,0 @@
|
|||||||
name: Lint
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [opened, reopened, synchronize]
|
|
||||||
push:
|
|
||||||
branches-ignore:
|
|
||||||
- 'gh-pages'
|
|
||||||
- 'dependabot/**'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test-lint:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Setup
|
|
||||||
uses: ./.github/actions/setup
|
|
||||||
with:
|
|
||||||
node-version: 16
|
|
||||||
|
|
||||||
- name: ESLint
|
|
||||||
if: always()
|
|
||||||
run: npm run lint
|
|
||||||
|
|
||||||
- name: 'Prettier check (quick fix: `npm run prettier`)'
|
|
||||||
if: always()
|
|
||||||
run: npm run prettier:check
|
|
||||||
25
.github/workflows/test-main-17.yml
vendored
25
.github/workflows/test-main-17.yml
vendored
@@ -1,25 +0,0 @@
|
|||||||
name: Main@node 17
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [opened, reopened, synchronize]
|
|
||||||
push:
|
|
||||||
branches-ignore:
|
|
||||||
- 'gh-pages'
|
|
||||||
- 'dependabot/**'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test-main-17:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Setup
|
|
||||||
uses: ./.github/actions/setup
|
|
||||||
with:
|
|
||||||
node-version: 17
|
|
||||||
env:
|
|
||||||
NPM_CONFIG_ENGINE_STRICT: 'false'
|
|
||||||
|
|
||||||
- name: Core tests
|
|
||||||
uses: ./.github/actions/core-tests
|
|
||||||
28
.github/workflows/test-main.yml
vendored
28
.github/workflows/test-main.yml
vendored
@@ -1,28 +0,0 @@
|
|||||||
name: Main
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [opened, reopened, synchronize]
|
|
||||||
push:
|
|
||||||
branches-ignore:
|
|
||||||
- 'gh-pages'
|
|
||||||
- 'dependabot/**'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test-main:
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: ['ubuntu-latest', 'windows-latest']
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Setup
|
|
||||||
uses: ./.github/actions/setup
|
|
||||||
with:
|
|
||||||
node-version: 16
|
|
||||||
|
|
||||||
- name: Core tests
|
|
||||||
uses: ./.github/actions/core-tests
|
|
||||||
46
.github/workflows/test-package-cli.yml
vendored
46
.github/workflows/test-package-cli.yml
vendored
@@ -1,46 +0,0 @@
|
|||||||
name: Package CLI
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [opened, reopened, synchronize]
|
|
||||||
push:
|
|
||||||
branches-ignore:
|
|
||||||
- 'gh-pages'
|
|
||||||
- 'dependabot/**'
|
|
||||||
|
|
||||||
# Smoke test (render a badge with the CLI) with only the package
|
|
||||||
# dependencies installed.
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test-package-cli:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- node: '14'
|
|
||||||
engine-strict: 'false'
|
|
||||||
- node: '16'
|
|
||||||
engine-strict: 'false'
|
|
||||||
- node: '18'
|
|
||||||
engine-strict: 'true'
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Install Node JS ${{ inputs.node-version }}
|
|
||||||
uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: ${{ matrix.node }}
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
env:
|
|
||||||
CYPRESS_INSTALL_BINARY: 0
|
|
||||||
NPM_CONFIG_ENGINE_STRICT: ${{ matrix.engine-strict }}
|
|
||||||
run: |
|
|
||||||
cd badge-maker
|
|
||||||
npm install
|
|
||||||
npm link
|
|
||||||
|
|
||||||
- name: Render a badge with the CLI
|
|
||||||
run: |
|
|
||||||
cd badge-maker
|
|
||||||
badge cactus grown :green @flat
|
|
||||||
34
.github/workflows/test-package-lib.yml
vendored
34
.github/workflows/test-package-lib.yml
vendored
@@ -1,34 +0,0 @@
|
|||||||
name: Package Library
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [opened, reopened, synchronize]
|
|
||||||
push:
|
|
||||||
branches-ignore:
|
|
||||||
- 'gh-pages'
|
|
||||||
- 'dependabot/**'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test-package-lib:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- node: '14'
|
|
||||||
engine-strict: 'false'
|
|
||||||
- node: '16'
|
|
||||||
engine-strict: 'true'
|
|
||||||
- node: '18'
|
|
||||||
engine-strict: 'false'
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Setup
|
|
||||||
uses: ./.github/actions/setup
|
|
||||||
with:
|
|
||||||
node-version: ${{ matrix.node }}
|
|
||||||
env:
|
|
||||||
NPM_CONFIG_ENGINE_STRICT: ${{ matrix.engine-strict }}
|
|
||||||
|
|
||||||
- name: Package tests
|
|
||||||
uses: ./.github/actions/package-tests
|
|
||||||
40
.github/workflows/test-services-17.yml
vendored
40
.github/workflows/test-services-17.yml
vendored
@@ -1,40 +0,0 @@
|
|||||||
name: Services@node 17
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [opened, edited, reopened, synchronize]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test-services-17:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Setup
|
|
||||||
uses: ./.github/actions/setup
|
|
||||||
with:
|
|
||||||
node-version: 17
|
|
||||||
env:
|
|
||||||
NPM_CONFIG_ENGINE_STRICT: 'false'
|
|
||||||
|
|
||||||
- name: Service tests (triggered from local branch)
|
|
||||||
if: github.event.pull_request.head.repo.full_name == github.repository
|
|
||||||
uses: ./.github/actions/service-tests
|
|
||||||
with:
|
|
||||||
github-token: '${{ secrets.GH_PAT }}'
|
|
||||||
librariesio-tokens: '${{ secrets.SERVICETESTS_LIBRARIESIO_TOKENS }}'
|
|
||||||
obs-user: '${{ secrets.SERVICETESTS_OBS_USER }}'
|
|
||||||
obs-pass: '${{ secrets.SERVICETESTS_OBS_PASS }}'
|
|
||||||
sl-insight-user-uuid: '${{ secrets.SERVICETESTS_SL_INSIGHT_USER_UUID }}'
|
|
||||||
sl-insight-api-token: '${{ secrets.SERVICETESTS_SL_INSIGHT_API_TOKEN }}'
|
|
||||||
twitch-client-id: '${{ secrets.SERVICETESTS_TWITCH_CLIENT_ID }}'
|
|
||||||
twitch-client-secret: '${{ secrets.SERVICETESTS_TWITCH_CLIENT_SECRET }}'
|
|
||||||
wheelmap-token: '${{ secrets.SERVICETESTS_WHEELMAP_TOKEN }}'
|
|
||||||
youtube-api-key: '${{ secrets.SERVICETESTS_YOUTUBE_API_KEY }}'
|
|
||||||
|
|
||||||
- name: Service tests (triggered from fork)
|
|
||||||
if: github.event.pull_request.head.repo.full_name != github.repository
|
|
||||||
uses: ./.github/actions/service-tests
|
|
||||||
with:
|
|
||||||
github-token: '${{ secrets.GITHUB_TOKEN }}'
|
|
||||||
38
.github/workflows/test-services.yml
vendored
38
.github/workflows/test-services.yml
vendored
@@ -1,38 +0,0 @@
|
|||||||
name: Services
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [opened, edited, reopened, synchronize]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test-services:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Setup
|
|
||||||
uses: ./.github/actions/setup
|
|
||||||
with:
|
|
||||||
node-version: 16
|
|
||||||
|
|
||||||
- name: Service tests (triggered from local branch)
|
|
||||||
if: github.event.pull_request.head.repo.full_name == github.repository
|
|
||||||
uses: ./.github/actions/service-tests
|
|
||||||
with:
|
|
||||||
github-token: '${{ secrets.GH_PAT }}'
|
|
||||||
librariesio-tokens: '${{ secrets.SERVICETESTS_LIBRARIESIO_TOKENS }}'
|
|
||||||
obs-user: '${{ secrets.SERVICETESTS_OBS_USER }}'
|
|
||||||
obs-pass: '${{ secrets.SERVICETESTS_OBS_PASS }}'
|
|
||||||
sl-insight-user-uuid: '${{ secrets.SERVICETESTS_SL_INSIGHT_USER_UUID }}'
|
|
||||||
sl-insight-api-token: '${{ secrets.SERVICETESTS_SL_INSIGHT_API_TOKEN }}'
|
|
||||||
twitch-client-id: '${{ secrets.SERVICETESTS_TWITCH_CLIENT_ID }}'
|
|
||||||
twitch-client-secret: '${{ secrets.SERVICETESTS_TWITCH_CLIENT_SECRET }}'
|
|
||||||
wheelmap-token: '${{ secrets.SERVICETESTS_WHEELMAP_TOKEN }}'
|
|
||||||
youtube-api-key: '${{ secrets.SERVICETESTS_YOUTUBE_API_KEY }}'
|
|
||||||
|
|
||||||
- name: Service tests (triggered from fork)
|
|
||||||
if: github.event.pull_request.head.repo.full_name != github.repository
|
|
||||||
uses: ./.github/actions/service-tests
|
|
||||||
with:
|
|
||||||
github-token: '${{ secrets.GITHUB_TOKEN }}'
|
|
||||||
33
.github/workflows/update-github-api.yml
vendored
33
.github/workflows/update-github-api.yml
vendored
@@ -1,33 +0,0 @@
|
|||||||
name: Update GitHub API Version
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: '0 7 * * 6'
|
|
||||||
# At 07:00 on Saturday
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
pull-requests: write
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
update-github-api:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Setup
|
|
||||||
uses: ./.github/actions/setup
|
|
||||||
with:
|
|
||||||
node-version: 16
|
|
||||||
|
|
||||||
- name: Check for new GitHub API version
|
|
||||||
run: node scripts/update-github-api.js
|
|
||||||
|
|
||||||
- name: Create Pull Request if config has changed
|
|
||||||
uses: peter-evans/create-pull-request@v5
|
|
||||||
with:
|
|
||||||
token: '${{ secrets.GITHUB_TOKEN }}'
|
|
||||||
commit-message: Update GitHub API Version
|
|
||||||
title: Update [GitHub] API Version
|
|
||||||
branch-suffix: random
|
|
||||||
18
.gitignore
vendored
18
.gitignore
vendored
@@ -92,7 +92,10 @@ typings/
|
|||||||
|
|
||||||
# Temporary build artifacts.
|
# Temporary build artifacts.
|
||||||
/build
|
/build
|
||||||
frontend/categories/*.yaml
|
.next
|
||||||
|
badge-examples.json
|
||||||
|
supported-features.json
|
||||||
|
service-definitions.yml
|
||||||
|
|
||||||
# Local runtime configuration.
|
# Local runtime configuration.
|
||||||
/config/local*.yml
|
/config/local*.yml
|
||||||
@@ -100,6 +103,11 @@ frontend/categories/*.yaml
|
|||||||
# Template for the local runtime configuration.
|
# Template for the local runtime configuration.
|
||||||
!/config/local*.template.yml
|
!/config/local*.template.yml
|
||||||
|
|
||||||
|
# Gatsby
|
||||||
|
/frontend/.cache
|
||||||
|
/frontend/public
|
||||||
|
/public
|
||||||
|
|
||||||
# Cypress
|
# Cypress
|
||||||
/cypress/videos/
|
/cypress/videos/
|
||||||
/cypress/screenshots/
|
/cypress/screenshots/
|
||||||
@@ -109,11 +117,3 @@ frontend/categories/*.yaml
|
|||||||
|
|
||||||
# Flamebearer
|
# Flamebearer
|
||||||
flamegraph.html
|
flamegraph.html
|
||||||
|
|
||||||
# config file for node-pg-migrate
|
|
||||||
migrations-config.json
|
|
||||||
|
|
||||||
# Frontend/Docusaurus
|
|
||||||
frontend/.docusaurus
|
|
||||||
frontend/.cache-loader
|
|
||||||
/public
|
|
||||||
|
|||||||
5
.mocharc-frontend.yml
Normal file
5
.mocharc-frontend.yml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
reporter: mocha-env-reporter
|
||||||
|
require:
|
||||||
|
- '@babel/polyfill'
|
||||||
|
- '@babel/register'
|
||||||
|
- mocha-yaml-loader
|
||||||
10
.nycrc-frontend.json
Normal file
10
.nycrc-frontend.json
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"reporter": ["lcov"],
|
||||||
|
"all": false,
|
||||||
|
"silent": true,
|
||||||
|
"clean": false,
|
||||||
|
"sourceMap": false,
|
||||||
|
"instrument": false,
|
||||||
|
"include": ["frontend/**/*.js"],
|
||||||
|
"exclude": ["**/*.spec.js", "**/mocha-*.js"]
|
||||||
|
}
|
||||||
@@ -10,5 +10,5 @@ public
|
|||||||
private/*.json
|
private/*.json
|
||||||
/.nyc_output
|
/.nyc_output
|
||||||
analytics.json
|
analytics.json
|
||||||
frontend/.docusaurus
|
supported-features.json
|
||||||
frontend/categories
|
service-definitions.yml
|
||||||
|
|||||||
224
CHANGELOG.md
224
CHANGELOG.md
@@ -4,230 +4,6 @@ Note: this changelog is for the shields.io server. The changelog for the badge-m
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## server-2023-06-01
|
|
||||||
|
|
||||||
- feat: Add total commits to [GitHubCommitActivity] [#9196](https://github.com/badges/shields/issues/9196)
|
|
||||||
- set a custom error on 429 [#9159](https://github.com/badges/shields/issues/9159)
|
|
||||||
- deprecate [travis].org badges [#9171](https://github.com/badges/shields/issues/9171)
|
|
||||||
- count private sponsors on [GithubSponsors] badge [#9170](https://github.com/badges/shields/issues/9170)
|
|
||||||
- Dependency updates
|
|
||||||
|
|
||||||
## server-2023-05-01
|
|
||||||
|
|
||||||
** Removal:** For users who need to maintain a Github Token pool, storage has been provided via the `RedisTokenPersistence` and `REDIS_URL` settings. This feature was deprecated in `server-2023-03-01`. As of this release, the `RedisTokenPersistence` backend is now removed. If you are using this feature, you will need to migrate to using the `SQLTokenPersistence` backend for storage and provide a postgres connection string via the `POSTGRES_URL` setting. [#8922](https://github.com/badges/shields/issues/8922)
|
|
||||||
|
|
||||||
- fail to start server if there are duplicate service names [#9099](https://github.com/badges/shields/issues/9099)
|
|
||||||
- [SourceForge] Added badges for SourceForge [#9078](https://github.com/badges/shields/issues/9078) [#9102](https://github.com/badges/shields/issues/9102)
|
|
||||||
- crates: Use `?include=` to reduce crates.io backend load [#9081](https://github.com/badges/shields/issues/9081)
|
|
||||||
- Dependency updates
|
|
||||||
|
|
||||||
## server-2023-04-02
|
|
||||||
|
|
||||||
- [JenkinsCoverage] Update Jenkins Code Coverage API for new plugin version [#9010](https://github.com/badges/shields/issues/9010)
|
|
||||||
- [CTAN] fallback to date if version is empty [#9036](https://github.com/badges/shields/issues/9036)
|
|
||||||
- Update to [CTAN] API version 2.0 [#9016](https://github.com/badges/shields/issues/9016)
|
|
||||||
- handle missing statistics array in [VisualStudioMarketplace] badges [#8985](https://github.com/badges/shields/issues/8985)
|
|
||||||
- [Netlify] upgrade colors for SVG parsing [#8971](https://github.com/badges/shields/issues/8971)
|
|
||||||
- Fix [Vcpkg] version service for different version fields [#8945](https://github.com/badges/shields/issues/8945)
|
|
||||||
- only try to close pool if one exists [#8947](https://github.com/badges/shields/issues/8947)
|
|
||||||
- misc minor fixes to [githubsize node pypi] [#8946](https://github.com/badges/shields/issues/8946)
|
|
||||||
- Dependency updates
|
|
||||||
|
|
||||||
## server-2023-03-01
|
|
||||||
|
|
||||||
**Deprecation:** For users who need to maintain a Github Token pool, storage has been provided via the `RedisTokenPersistence` and `REDIS_URL` settings. As of this release, the `RedisTokenPersistence` backend is now deprecated and will be removed in a future release. If you are using this feature, you will need to migrate to using the `SQLTokenPersistence` backend for storage and provide a postgres connection string via the `POSTGRES_URL` setting. [#8922](https://github.com/badges/shields/issues/8922)
|
|
||||||
|
|
||||||
- fix: for crates.io versions, use max_stable_version if it exists [#8687](https://github.com/badges/shields/issues/8687)
|
|
||||||
- don't autofocus search [#8927](https://github.com/badges/shields/issues/8927)
|
|
||||||
- Add [Vcpkg] version service [#8923](https://github.com/badges/shields/issues/8923)
|
|
||||||
- fix: Set uid/gid in docker image to 0 [#8908](https://github.com/badges/shields/issues/8908)
|
|
||||||
- expose port 443 in Dockerfile [#8889](https://github.com/badges/shields/issues/8889)
|
|
||||||
- Dependency updates
|
|
||||||
|
|
||||||
## server-2023-02-01
|
|
||||||
|
|
||||||
- replace [twitter] badge with static fallback [#8842](https://github.com/badges/shields/issues/8842)
|
|
||||||
- Add various [Polymart] badges [#8811](https://github.com/badges/shields/issues/8811)
|
|
||||||
- update [githubpipenv] tests/examples [#8797](https://github.com/badges/shields/issues/8797)
|
|
||||||
- deprecate [apm] service [#8773](https://github.com/badges/shields/issues/8773)
|
|
||||||
- deprecate lgtm [#8771](https://github.com/badges/shields/issues/8771)
|
|
||||||
- Dependency updates
|
|
||||||
|
|
||||||
## server-2023-01-01
|
|
||||||
|
|
||||||
- Breaking change: Routes for GitHub workflows badge have changed. See https://github.com/badges/shields/issues/8671 for more details
|
|
||||||
- Behaviour change: In this release we fixed a long standing bug. GitHub badges were previously not reading the base URL from the `config.service.baseUri`.
|
|
||||||
This release fixes that bug, bringing the code into line with the documented behaviour. This should not cause a behaviour change for most users,
|
|
||||||
but users who had previously set a value in `config.service.baseUri` which was previously ignored could see this now have an effect.
|
|
||||||
Users who configure their instance using env vars rather than yaml should see no change.
|
|
||||||
- Send `X-GitHub-Api-Version` when calling [GitHub] v3 API [#8669](https://github.com/badges/shields/issues/8669)
|
|
||||||
- add [VpmVersion] badge [#8755](https://github.com/badges/shields/issues/8755)
|
|
||||||
- Add [modrinth] game versions [#8673](https://github.com/badges/shields/issues/8673)
|
|
||||||
- fix debug logging of undefined query params [#8540](https://github.com/badges/shields/issues/8540), [#8757](https://github.com/badges/shields/issues/8757)
|
|
||||||
- fall back to classifiers if [pypi] license text is really long [#8690](https://github.com/badges/shields/issues/8690)
|
|
||||||
- allow passing key to [stackexchange] [#8539](https://github.com/badges/shields/issues/8539)
|
|
||||||
- Dependency updates
|
|
||||||
|
|
||||||
## server-2022-12-01
|
|
||||||
|
|
||||||
- fix: support logoColor to shield icons. [#8263](https://github.com/badges/shields/issues/8263)
|
|
||||||
- handle missing properties array in [VisualStudioMarketplaceVersion] [#8603](https://github.com/badges/shields/issues/8603)
|
|
||||||
- deprecate [wercker] service [#8642](https://github.com/badges/shields/issues/8642)
|
|
||||||
- Add [Coincap] Cryptocurrency badges [#8623](https://github.com/badges/shields/issues/8623)
|
|
||||||
- Add [modrinth] version [#8604](https://github.com/badges/shields/issues/8604)
|
|
||||||
- [factorio-mod-portal] services [#8625](https://github.com/badges/shields/issues/8625)
|
|
||||||
- [Coveralls] for GitLab [#8584](https://github.com/badges/shields/issues/8584), [#8644](https://github.com/badges/shields/issues/8644)
|
|
||||||
- Remove 'suggest badges' feature [#8311](https://github.com/badges/shields/issues/8311)
|
|
||||||
- Add [modrinth] followers [#8601](https://github.com/badges/shields/issues/8601)
|
|
||||||
- Update the [modrinth] API to v2 [#8600](https://github.com/badges/shields/issues/8600)
|
|
||||||
- tidy up [GitHubGist] routes [#8510](https://github.com/badges/shields/issues/8510)
|
|
||||||
- fix [flathub] version error handling [#8500](https://github.com/badges/shields/issues/8500)
|
|
||||||
- Dependency updates
|
|
||||||
|
|
||||||
## server-2022-11-01
|
|
||||||
|
|
||||||
- [Ansible] Add collection badge [#8578](https://github.com/badges/shields/issues/8578)
|
|
||||||
- [VisualStudioMarketplace] Add support to prerelease extensions version (Issue #8207) [#8561](https://github.com/badges/shields/issues/8561)
|
|
||||||
- feat: add [GitlabLastCommit] service [#8508](https://github.com/badges/shields/issues/8508)
|
|
||||||
- fix [swagger] service tests (allow 0 items in array) [#8564](https://github.com/badges/shields/issues/8564)
|
|
||||||
- fix codecov badge for non-default branch [#8565](https://github.com/badges/shields/issues/8565)
|
|
||||||
- Add [GitHubLastCommit] by committer badge [#8537](https://github.com/badges/shields/issues/8537)
|
|
||||||
- [GitHubReleaseDate] - published_at field [#8543](https://github.com/badges/shields/issues/8543)
|
|
||||||
- Fix [Testspace] with new "untested" value in case_counts array [#8544](https://github.com/badges/shields/issues/8544)
|
|
||||||
- fix: Support WAITING status for GitHub deployments [#8521](https://github.com/badges/shields/issues/8521)
|
|
||||||
- [Whatpulse] badge for a user and for a team [#8466](https://github.com/badges/shields/issues/8466)
|
|
||||||
- deprecate [pkgreview] service [#8499](https://github.com/badges/shields/issues/8499)
|
|
||||||
- Dependency updates
|
|
||||||
|
|
||||||
## server-2022-10-08
|
|
||||||
|
|
||||||
- deprecate [criterion] service [#8501](https://github.com/badges/shields/issues/8501)
|
|
||||||
- fix formatRelativeDate error handling; run [date] [#8497](https://github.com/badges/shields/issues/8497)
|
|
||||||
- allow/validate bitbucket_username / bitbucket_password in private config schema [#8472](https://github.com/badges/shields/issues/8472)
|
|
||||||
- fix [pub] points badge test and example [#8498](https://github.com/badges/shields/issues/8498)
|
|
||||||
- feat: add [GitlabLanguageCount] service [#8377](https://github.com/badges/shields/issues/8377)
|
|
||||||
- [GitHubGistStars] add GitHub Gist Stars [#8471](https://github.com/badges/shields/issues/8471)
|
|
||||||
- fix display/search of CII badge examples [#8473](https://github.com/badges/shields/issues/8473)
|
|
||||||
- feat: add 2022 support to GitHub Hacktoberfest [#8468](https://github.com/badges/shields/issues/8468)
|
|
||||||
- fix [GitLabCoverage] subgroup bug [#8401](https://github.com/badges/shields/issues/8401)
|
|
||||||
- implement ruby gems-specific version sort/color functions [#8434](https://github.com/badges/shields/issues/8434)
|
|
||||||
- Add `rc` to pre-release identifiers [#8435](https://github.com/badges/shields/issues/8435)
|
|
||||||
- add [GitHub] Number of commits between branches/tags/commits [#8394](https://github.com/badges/shields/issues/8394)
|
|
||||||
- add [Packagist] dependency version [#8371](https://github.com/badges/shields/issues/8371)
|
|
||||||
- fix Docker build status invalid response data bug [#8392](https://github.com/badges/shields/issues/8392)
|
|
||||||
- Dependency updates
|
|
||||||
|
|
||||||
## server-2022-09-04
|
|
||||||
|
|
||||||
- fix frontend compile for users running on Windows [#8350](https://github.com/badges/shields/issues/8350)
|
|
||||||
- [DockerSize] Docker image size multi arch [#8290](https://github.com/badges/shields/issues/8290)
|
|
||||||
- upgrade gatsby [#8334](https://github.com/badges/shields/issues/8334)
|
|
||||||
- Custom domains for [JitPack] artifacts [#8333](https://github.com/badges/shields/issues/8333)
|
|
||||||
- fix [dockerstars] service [#8316](https://github.com/badges/shields/issues/8316)
|
|
||||||
- [BountySource] Fix: Broken Badge generation for decimal activity values [#8315](https://github.com/badges/shields/issues/8315)
|
|
||||||
- feat: add [gitlabmergerequests] service [#8166](https://github.com/badges/shields/issues/8166)
|
|
||||||
- Fix terminology for [ROS] version service [#8292](https://github.com/badges/shields/issues/8292)
|
|
||||||
- feat: add [GitlabStars] service [#8209](https://github.com/badges/shields/issues/8209)
|
|
||||||
- Fix invalid `rst` format when `alt` or `target` is present [#8275](https://github.com/badges/shields/issues/8275)
|
|
||||||
- [GithubGistLastCommit] GitHub gist last commit [#8272](https://github.com/badges/shields/issues/8272)
|
|
||||||
- [GitHub] GitHub file size for a specific branch [#8262](https://github.com/badges/shields/issues/8262)
|
|
||||||
- Dependency updates
|
|
||||||
|
|
||||||
## server-2022-08-01
|
|
||||||
|
|
||||||
- [pypi] Add Framework Version Badges support [#8261](https://github.com/badges/shields/issues/8261)
|
|
||||||
- feat: add [GitlabForks] server [#8208](https://github.com/badges/shields/issues/8208)
|
|
||||||
- Update PyPI api according to https://warehouse.pypa.io/api-reference/json.html [#8251](https://github.com/badges/shields/issues/8251)
|
|
||||||
- Add [galaxytoolshed] Activity [#8164](https://github.com/badges/shields/issues/8164)
|
|
||||||
- [greasyfork] Add Greasy Fork rating badges [#8087](https://github.com/badges/shields/issues/8087)
|
|
||||||
- refactor(deps): Replace moment with dayjs [#8192](https://github.com/badges/shields/issues/8192)
|
|
||||||
- add spaces round pipe in [conda] badge [#8189](https://github.com/badges/shields/issues/8189)
|
|
||||||
- Add [ROS] version service [#8169](https://github.com/badges/shields/issues/8169)
|
|
||||||
- feat: add [gitlabissues] service [#8108](https://github.com/badges/shields/issues/8108)
|
|
||||||
- Dependency updates
|
|
||||||
|
|
||||||
## server-2022-07-03
|
|
||||||
|
|
||||||
- Add [galaxytoolshed] services [#8114](https://github.com/badges/shields/issues/8114)
|
|
||||||
- fix [gitlab] auth [#8145](https://github.com/badges/shields/issues/8145) [#8162](https://github.com/badges/shields/issues/8162)
|
|
||||||
- increase cache length on AUR version badge, run [AUR] [#8110](https://github.com/badges/shields/issues/8110)
|
|
||||||
- Use GraphQL to fix GitHub file count badges [github] [#8112](https://github.com/badges/shields/issues/8112)
|
|
||||||
- feat: add [gitlab] contributors service [#8084](https://github.com/badges/shields/issues/8084)
|
|
||||||
- [greasyfork] Add Greasy Fork service badges [#8080](https://github.com/badges/shields/issues/8080)
|
|
||||||
- Add [gitlablicense] services [#8024](https://github.com/badges/shields/issues/8024)
|
|
||||||
- [Spack] Package Manager: Update Domain [#8046](https://github.com/badges/shields/issues/8046)
|
|
||||||
- switch [jitpack] to use latestOk endpoint [#8041](https://github.com/badges/shields/issues/8041)
|
|
||||||
- Dependency updates
|
|
||||||
|
|
||||||
## server-2022-06-01
|
|
||||||
|
|
||||||
- Update GitLab logo (2022) [#7984](https://github.com/badges/shields/issues/7984)
|
|
||||||
- [GitHub] Added milestone property to GitHub issue details service [#7864](https://github.com/badges/shields/issues/7864)
|
|
||||||
- [Spack] Package Manager: Update Endpoint [#7957](https://github.com/badges/shields/issues/7957)
|
|
||||||
- Update Chocolatey API endpoint URL [#7952](https://github.com/badges/shields/issues/7952)
|
|
||||||
- [Flathub]Add downloads badge [#7724](https://github.com/badges/shields/issues/7724)
|
|
||||||
- replace the outdated Telegram logo with the newest [#7831](https://github.com/badges/shields/issues/7831)
|
|
||||||
- add [PUB] points badge [#7918](https://github.com/badges/shields/issues/7918)
|
|
||||||
- add [PUB] popularity badge [#7920](https://github.com/badges/shields/issues/7920)
|
|
||||||
- add [PUB] likes badge [#7916](https://github.com/badges/shields/issues/7916)
|
|
||||||
- Dependency updates
|
|
||||||
|
|
||||||
## server-2022-05-03
|
|
||||||
|
|
||||||
- [OSSFScorecard] Create scorecard badge service [#7687](https://github.com/badges/shields/issues/7687)
|
|
||||||
- Stringify [githublanguagecount] message [#7881](https://github.com/badges/shields/issues/7881)
|
|
||||||
- Stringify and trim whitespace from a few services [#7880](https://github.com/badges/shields/issues/7880)
|
|
||||||
- add labels to Dockerfile [#7862](https://github.com/badges/shields/issues/7862)
|
|
||||||
- handle missing 'fly-client-ip' [#7814](https://github.com/badges/shields/issues/7814)
|
|
||||||
- Dependency updates
|
|
||||||
|
|
||||||
## server-2022-04-03
|
|
||||||
|
|
||||||
- Breaking change: This release updates ioredis from v4 to v5.
|
|
||||||
If you are using redis for GitHub token pooling, redis connection strings of the form
|
|
||||||
`redis://junkusername:authpassword@example.com:1234` will need to be updated to
|
|
||||||
`redis://:authpassword@example.com:1234`. See the
|
|
||||||
[ioredis upgrade guide](https://github.com/luin/ioredis/wiki/Upgrading-from-v4-to-v5)
|
|
||||||
for further details.
|
|
||||||
- fix installation issue on npm >= 8.5.5 [#7809](https://github.com/badges/shields/issues/7809)
|
|
||||||
- two fixes for [packagist] schemas [#7782](https://github.com/badges/shields/issues/7782)
|
|
||||||
- allow requireCloudflare setting to work when hosted on fly.io [#7781](https://github.com/badges/shields/issues/7781)
|
|
||||||
- fix [pypi] badges when package has null license [#7761](https://github.com/badges/shields/issues/7761)
|
|
||||||
- Add a [pub] publisher badge [#7715](https://github.com/badges/shields/issues/7715)
|
|
||||||
- Switch Steam file size badge to informational color [#7722](https://github.com/badges/shields/issues/7722)
|
|
||||||
- Make W3C and Youtube documentation links clickable [#7721](https://github.com/badges/shields/issues/7721)
|
|
||||||
- Improve Wercker examples [#7720](https://github.com/badges/shields/issues/7720)
|
|
||||||
- Improve Cirrus CI examples [#7719](https://github.com/badges/shields/issues/7719)
|
|
||||||
- Support [CodeClimate] responses with multiple data items [#7716](https://github.com/badges/shields/issues/7716)
|
|
||||||
- Delete [TeamCityCoverage] and [BowerVersion] redirectors [#7718](https://github.com/badges/shields/issues/7718)
|
|
||||||
- Deprecate [Shippable] service [#7717](https://github.com/badges/shields/issues/7717)
|
|
||||||
- fix: restore version comparison updates from #4173 [#4254](https://github.com/badges/shields/issues/4254)
|
|
||||||
- [piwheels], filter out versions with no files [#7696](https://github.com/badges/shields/issues/7696)
|
|
||||||
- set a longer cacheLength on [librariesio] badges [#7692](https://github.com/badges/shields/issues/7692)
|
|
||||||
- improve python version formatting [#7682](https://github.com/badges/shields/issues/7682)
|
|
||||||
- Clarify GitHub All Contributors badge [#7690](https://github.com/badges/shields/issues/7690)
|
|
||||||
- Support [HexPM] packages with no stable release [#7685](https://github.com/badges/shields/issues/7685)
|
|
||||||
- Add Test at Scale Badge [#7612](https://github.com/badges/shields/issues/7612)
|
|
||||||
- [packagist] api v2 support [#7681](https://github.com/badges/shields/issues/7681)
|
|
||||||
- Add [piwheels] version badge [#7656](https://github.com/badges/shields/issues/7656)
|
|
||||||
- Dependency updates
|
|
||||||
|
|
||||||
## server-2022-03-01
|
|
||||||
|
|
||||||
- Add [Conan] version service (#7460)
|
|
||||||
- remove suspended [github] tokens from the pool [#7654](https://github.com/badges/shields/issues/7654)
|
|
||||||
- generate links without trailing : if port not set [#7655](https://github.com/badges/shields/issues/7655)
|
|
||||||
- Use the latest build status when checking docs.rs [#7613](https://github.com/badges/shields/issues/7613)
|
|
||||||
- Remove no download handling and add API warning to [Wordpress] badges [#7606](https://github.com/badges/shields/issues/7606)
|
|
||||||
- set a higher default cacheLength on rating/star category [#7587](https://github.com/badges/shields/issues/7587)
|
|
||||||
- Update [amo] to use v4 API, set custom `cacheLength`s [#7586](https://github.com/badges/shields/issues/7586)
|
|
||||||
- fix(amo): include trailing slash in API call [#7585](https://github.com/badges/shields/issues/7585)
|
|
||||||
- fix docker image user agent [#7582](https://github.com/badges/shields/issues/7582)
|
|
||||||
- Delete deprecated Codetally and continuousphp services [#7572](https://github.com/badges/shields/issues/7572)
|
|
||||||
- Deprecate [Requires] service [#7571](https://github.com/badges/shields/issues/7571)
|
|
||||||
- [AUR] Fix RPC URL [#7570](https://github.com/badges/shields/issues/7570)
|
|
||||||
- Dependency updates
|
|
||||||
|
|
||||||
## server-2022-02-01
|
## server-2022-02-01
|
||||||
|
|
||||||
- [Depfu] Add support for Gitlab [#7475](https://github.com/badges/shields/issues/7475)
|
- [Depfu] Add support for Gitlab [#7475](https://github.com/badges/shields/issues/7475)
|
||||||
|
|||||||
@@ -134,19 +134,9 @@ Prettier before a commit by default.
|
|||||||
When adding or changing a service [please write tests][service-tests], and ensure the [title of your Pull Requests follows the required conventions](#running-service-tests-in-pull-requests) to ensure your tests are executed.
|
When adding or changing a service [please write tests][service-tests], and ensure the [title of your Pull Requests follows the required conventions](#running-service-tests-in-pull-requests) to ensure your tests are executed.
|
||||||
When changing other code, please add unit tests.
|
When changing other code, please add unit tests.
|
||||||
|
|
||||||
The integration tests are not run by default. For most contributions it is OK to skip these unless you're working directly on the code for storing the GitHub token pool in postgres.
|
To run the integration tests, you must have redis installed and in your PATH.
|
||||||
|
Use `brew install redis`, `yum install redis`, etc. The test runner will
|
||||||
To run the integration tests:
|
start the server automatically.
|
||||||
|
|
||||||
- You must have PostgreSQL installed. Use `brew install postgresql`, `apt-get install postgresql`, etc.
|
|
||||||
- Set a connection string either with an env var `POSTGRES_URL=postgresql://user:pass@127.0.0.1:5432/db_name` or by using
|
|
||||||
```yaml
|
|
||||||
private:
|
|
||||||
postgres_url: 'postgresql://user:pass@127.0.0.1:5432/db_name'
|
|
||||||
```
|
|
||||||
in a yaml config file.
|
|
||||||
- Run `npm run migrate up` to apply DB migrations
|
|
||||||
- Run `npm run test:integration` to run the tests
|
|
||||||
|
|
||||||
[service-tests]: https://github.com/badges/shields/blob/master/doc/service-tests.md
|
[service-tests]: https://github.com/badges/shields/blob/master/doc/service-tests.md
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ COPY package.json package-lock.json /usr/src/app/
|
|||||||
COPY badge-maker /usr/src/app/badge-maker/
|
COPY badge-maker /usr/src/app/badge-maker/
|
||||||
|
|
||||||
RUN apk add python3 make g++
|
RUN apk add python3 make g++
|
||||||
RUN npm install -g "npm@>=8"
|
RUN npm install -g "npm@>=7"
|
||||||
# We need dev deps to build the front end. We don't need Cypress, though.
|
# We need dev deps to build the front end. We don't need Cypress, though.
|
||||||
RUN NODE_ENV=development CYPRESS_INSTALL_BINARY=0 npm ci
|
RUN NODE_ENV=development CYPRESS_INSTALL_BINARY=0 npm ci
|
||||||
|
|
||||||
@@ -23,15 +23,13 @@ FROM node:16-alpine
|
|||||||
|
|
||||||
ARG version=dev
|
ARG version=dev
|
||||||
ENV DOCKER_SHIELDS_VERSION=$version
|
ENV DOCKER_SHIELDS_VERSION=$version
|
||||||
LABEL version=$version
|
|
||||||
LABEL fly.version=$version
|
|
||||||
|
|
||||||
# Run the server using production configs.
|
# Run the server using production configs.
|
||||||
ENV NODE_ENV production
|
ENV NODE_ENV production
|
||||||
|
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/app
|
||||||
COPY --from=Builder --chown=0:0 /usr/src/app /usr/src/app
|
COPY --from=Builder /usr/src/app /usr/src/app
|
||||||
|
|
||||||
CMD node server
|
CMD node server
|
||||||
|
|
||||||
EXPOSE 80 443
|
EXPOSE 80
|
||||||
|
|||||||
@@ -19,6 +19,9 @@
|
|||||||
<a href="https://coveralls.io/github/badges/shields">
|
<a href="https://coveralls.io/github/badges/shields">
|
||||||
<img src="https://img.shields.io/coveralls/github/badges/shields"
|
<img src="https://img.shields.io/coveralls/github/badges/shields"
|
||||||
alt="coverage"></a>
|
alt="coverage"></a>
|
||||||
|
<a href="https://lgtm.com/projects/g/badges/shields/alerts/">
|
||||||
|
<img src="https://img.shields.io/lgtm/alerts/g/badges/shields"
|
||||||
|
alt="Total alerts"/></a>
|
||||||
<a href="https://discord.gg/HjJCwm5">
|
<a href="https://discord.gg/HjJCwm5">
|
||||||
<img src="https://img.shields.io/discord/308323056592486420?logo=discord"
|
<img src="https://img.shields.io/discord/308323056592486420?logo=discord"
|
||||||
alt="chat on Discord"></a>
|
alt="chat on Discord"></a>
|
||||||
@@ -32,7 +35,7 @@ and legible badges in SVG and raster format, which can easily be included in
|
|||||||
GitHub readmes or any other web page. The service supports dozens of
|
GitHub readmes or any other web page. The service supports dozens of
|
||||||
continuous integration services, package registries, distributions, app
|
continuous integration services, package registries, distributions, app
|
||||||
stores, social networks, code coverage services, and code analysis services.
|
stores, social networks, code coverage services, and code analysis services.
|
||||||
Every month it serves over 870 million images and is used by some of the
|
Every month it serves over 770 million images and is used by some of the
|
||||||
world's most popular open-source projects, [VS Code][vscode], [Vue.js][vue]
|
world's most popular open-source projects, [VS Code][vscode], [Vue.js][vue]
|
||||||
and [Bootstrap][bootstrap] to name a few.
|
and [Bootstrap][bootstrap] to name a few.
|
||||||
|
|
||||||
@@ -107,7 +110,7 @@ You can read a [tutorial on how to add a badge][tutorial].
|
|||||||
|
|
||||||
When server source files change, the badge server should automatically restart
|
When server source files change, the badge server should automatically restart
|
||||||
itself (using [nodemon][]). When the frontend files change, the frontend dev
|
itself (using [nodemon][]). When the frontend files change, the frontend dev
|
||||||
server (`docusaurus start`) should also automatically reload. However the badge
|
server (`gatsby dev`) should also automatically reload. However the badge
|
||||||
definitions are built only before the server first starts. To regenerate those,
|
definitions are built only before the server first starts. To regenerate those,
|
||||||
either run `npm run defs` or manually restart the server.
|
either run `npm run defs` or manually restart the server.
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ Please follow this guidance when reporting security issues affecting:
|
|||||||
- The [squint](https://github.com/badges/squint) raster proxy
|
- The [squint](https://github.com/badges/squint) raster proxy
|
||||||
- The [badge-maker](https://www.npmjs.com/package/badge-maker) NPM package
|
- The [badge-maker](https://www.npmjs.com/package/badge-maker) NPM package
|
||||||
|
|
||||||
The [gh-badges](https://www.npmjs.com/package/gh-badges) and [svg-to-image-proxy](https://www.npmjs.com/package/svg-to-image-proxy) NPM packages are now deprecated and will no longer receive fixes for bugs or security issues.
|
The [gh-badges](https://www.npmjs.com/package/gh-badges) NPM package is now deprecated and will no longer receive fixes for bugs or security issues.
|
||||||
|
|
||||||
## Reporting a Vulnerability
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
|||||||
10
app.json
10
app.json
@@ -35,16 +35,6 @@
|
|||||||
"WEBLATE_API_KEY": {
|
"WEBLATE_API_KEY": {
|
||||||
"description": "Configure the API key to be used for the Weblate service.",
|
"description": "Configure the API key to be used for the Weblate service.",
|
||||||
"required": false
|
"required": false
|
||||||
},
|
|
||||||
"METRICS_INFLUX_ENABLED": {
|
|
||||||
"description": "Disable influx metrics",
|
|
||||||
"value": "false",
|
|
||||||
"required": false
|
|
||||||
},
|
|
||||||
"REQUIRE_CLOUDFLARE": {
|
|
||||||
"description": "Allow direct traffic",
|
|
||||||
"value": "false",
|
|
||||||
"required": false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"formation": {
|
"formation": {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## 4.0.0 [WIP]
|
## 4.0.0 [WIP]
|
||||||
|
|
||||||
- Drop compatibility with Node < 14
|
- Drop compatibility with Node 10
|
||||||
|
|
||||||
## 3.3.1
|
## 3.3.1
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
const isSvg = require('is-svg')
|
||||||
const { spawn } = require('child-process-promise')
|
const { spawn } = require('child-process-promise')
|
||||||
const { expect, use } = require('chai')
|
const { expect, use } = require('chai')
|
||||||
use(require('chai-string'))
|
use(require('chai-string'))
|
||||||
@@ -19,7 +20,6 @@ describe('The CLI', function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should produce default badges', async function () {
|
it('should produce default badges', async function () {
|
||||||
const { default: isSvg } = await import('is-svg')
|
|
||||||
const { stdout } = await runCli(['cactus', 'grown'])
|
const { stdout } = await runCli(['cactus', 'grown'])
|
||||||
expect(stdout)
|
expect(stdout)
|
||||||
.to.satisfy(isSvg)
|
.to.satisfy(isSvg)
|
||||||
@@ -28,13 +28,11 @@ describe('The CLI', function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should produce colorschemed badges', async function () {
|
it('should produce colorschemed badges', async function () {
|
||||||
const { default: isSvg } = await import('is-svg')
|
|
||||||
const { stdout } = await runCli(['cactus', 'grown', ':green'])
|
const { stdout } = await runCli(['cactus', 'grown', ':green'])
|
||||||
expect(stdout).to.satisfy(isSvg)
|
expect(stdout).to.satisfy(isSvg)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should produce right-color badges', async function () {
|
it('should produce right-color badges', async function () {
|
||||||
const { default: isSvg } = await import('is-svg')
|
|
||||||
const { stdout } = await runCli(['cactus', 'grown', '#abcdef'])
|
const { stdout } = await runCli(['cactus', 'grown', '#abcdef'])
|
||||||
expect(stdout).to.satisfy(isSvg).and.to.include('#abcdef')
|
expect(stdout).to.satisfy(isSvg).and.to.include('#abcdef')
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const { expect } = require('chai')
|
const { expect } = require('chai')
|
||||||
|
const isSvg = require('is-svg')
|
||||||
const { makeBadge, ValidationError } = require('.')
|
const { makeBadge, ValidationError } = require('.')
|
||||||
|
|
||||||
describe('makeBadge function', function () {
|
describe('makeBadge function', function () {
|
||||||
it('should produce badge with valid input', async function () {
|
it('should produce badge with valid input', function () {
|
||||||
const { default: isSvg } = await import('is-svg')
|
|
||||||
expect(
|
expect(
|
||||||
makeBadge({
|
makeBadge({
|
||||||
label: 'build',
|
label: 'build',
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
const { test, given, forCases } = require('sazerac')
|
const { test, given, forCases } = require('sazerac')
|
||||||
const { expect } = require('chai')
|
const { expect } = require('chai')
|
||||||
const snapshot = require('snap-shot-it')
|
const snapshot = require('snap-shot-it')
|
||||||
|
const isSvg = require('is-svg')
|
||||||
const prettier = require('prettier')
|
const prettier = require('prettier')
|
||||||
const makeBadge = require('./make-badge')
|
const makeBadge = require('./make-badge')
|
||||||
|
|
||||||
@@ -79,8 +80,7 @@ describe('The badge generator', function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('SVG', function () {
|
describe('SVG', function () {
|
||||||
it('should produce SVG', async function () {
|
it('should produce SVG', function () {
|
||||||
const { default: isSvg } = await import('is-svg')
|
|
||||||
expect(makeBadge({ label: 'cactus', message: 'grown', format: 'svg' }))
|
expect(makeBadge({ label: 'cactus', message: 'grown', format: 'svg' }))
|
||||||
.to.satisfy(isSvg)
|
.to.satisfy(isSvg)
|
||||||
.and.to.include('cactus')
|
.and.to.include('cactus')
|
||||||
@@ -113,8 +113,7 @@ describe('The badge generator', function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should replace undefined svg badge style with "flat"', async function () {
|
it('should replace undefined svg badge style with "flat"', function () {
|
||||||
const { default: isSvg } = await import('is-svg')
|
|
||||||
const jsonBadgeWithUnknownStyle = makeBadge({
|
const jsonBadgeWithUnknownStyle = makeBadge({
|
||||||
label: 'name',
|
label: 'name',
|
||||||
message: 'Bob',
|
message: 'Bob',
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
"badge": "lib/badge-cli.js"
|
"badge": "lib/badge-cli.js"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 14",
|
"node": ">= 12",
|
||||||
"npm": ">= 6"
|
"npm": ">= 6"
|
||||||
},
|
},
|
||||||
"collective": {
|
"collective": {
|
||||||
|
|||||||
@@ -94,12 +94,10 @@ private:
|
|||||||
obs_user: 'OBS_USER'
|
obs_user: 'OBS_USER'
|
||||||
obs_pass: 'OBS_PASS'
|
obs_pass: 'OBS_PASS'
|
||||||
redis_url: 'REDIS_URL'
|
redis_url: 'REDIS_URL'
|
||||||
postgres_url: 'POSTGRES_URL'
|
|
||||||
sentry_dsn: 'SENTRY_DSN'
|
sentry_dsn: 'SENTRY_DSN'
|
||||||
sl_insight_userUuid: 'SL_INSIGHT_USER_UUID'
|
sl_insight_userUuid: 'SL_INSIGHT_USER_UUID'
|
||||||
sl_insight_apiToken: 'SL_INSIGHT_API_TOKEN'
|
sl_insight_apiToken: 'SL_INSIGHT_API_TOKEN'
|
||||||
sonarqube_token: 'SONARQUBE_TOKEN'
|
sonarqube_token: 'SONARQUBE_TOKEN'
|
||||||
stackapps_api_key: 'STACKAPPS_API_KEY'
|
|
||||||
teamcity_user: 'TEAMCITY_USER'
|
teamcity_user: 'TEAMCITY_USER'
|
||||||
teamcity_pass: 'TEAMCITY_PASS'
|
teamcity_pass: 'TEAMCITY_PASS'
|
||||||
twitch_client_id: 'TWITCH_CLIENT_ID'
|
twitch_client_id: 'TWITCH_CLIENT_ID'
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
public:
|
public:
|
||||||
bind:
|
bind:
|
||||||
address: '::'
|
address: '::'
|
||||||
|
|
||||||
metrics:
|
metrics:
|
||||||
prometheus:
|
prometheus:
|
||||||
enabled: false
|
enabled: false
|
||||||
@@ -11,26 +12,33 @@ public:
|
|||||||
intervalSeconds: 15
|
intervalSeconds: 15
|
||||||
ssl:
|
ssl:
|
||||||
isSecure: false
|
isSecure: false
|
||||||
|
|
||||||
cors:
|
cors:
|
||||||
allowedOrigin: []
|
allowedOrigin: []
|
||||||
|
|
||||||
services:
|
services:
|
||||||
github:
|
github:
|
||||||
baseUri: 'https://api.github.com'
|
baseUri: 'https://api.github.com/'
|
||||||
debug:
|
debug:
|
||||||
enabled: false
|
enabled: false
|
||||||
intervalSeconds: 200
|
intervalSeconds: 200
|
||||||
restApiVersion: '2022-11-28'
|
|
||||||
obs:
|
obs:
|
||||||
authorizedOrigins: 'https://api.opensuse.org'
|
authorizedOrigins: 'https://api.opensuse.org'
|
||||||
weblate:
|
weblate:
|
||||||
authorizedOrigins: 'https://hosted.weblate.org'
|
authorizedOrigins: 'https://hosted.weblate.org'
|
||||||
trace: false
|
trace: false
|
||||||
|
|
||||||
cacheHeaders:
|
cacheHeaders:
|
||||||
defaultCacheLengthSeconds: 120
|
defaultCacheLengthSeconds: 120
|
||||||
|
|
||||||
handleInternalErrors: true
|
handleInternalErrors: true
|
||||||
|
|
||||||
fetchLimit: '10MB'
|
fetchLimit: '10MB'
|
||||||
userAgentBase: 'shields (self-hosted)'
|
userAgentBase: 'shields (self-hosted)'
|
||||||
|
|
||||||
requestTimeoutSeconds: 120
|
requestTimeoutSeconds: 120
|
||||||
requestTimeoutMaxAgeSeconds: 30
|
requestTimeoutMaxAgeSeconds: 30
|
||||||
|
|
||||||
requireCloudflare: false
|
requireCloudflare: false
|
||||||
|
|
||||||
private: {}
|
private: {}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ private:
|
|||||||
gh_client_id: ...
|
gh_client_id: ...
|
||||||
gh_client_secret: ...
|
gh_client_secret: ...
|
||||||
gitlab_token: ...
|
gitlab_token: ...
|
||||||
|
redis_url: ...
|
||||||
sentry_dsn: ...
|
sentry_dsn: ...
|
||||||
shields_secret: ...
|
shields_secret: ...
|
||||||
sl_insight_userUuid: ...
|
sl_insight_userUuid: ...
|
||||||
|
|||||||
@@ -6,20 +6,13 @@ public:
|
|||||||
enabled: true
|
enabled: true
|
||||||
url: https://metrics.shields.io/telegraf
|
url: https://metrics.shields.io/telegraf
|
||||||
instanceIdFrom: env-var
|
instanceIdFrom: env-var
|
||||||
instanceIdEnvVarName: FLY_ALLOC_ID
|
instanceIdEnvVarName: HEROKU_DYNO_ID
|
||||||
envLabel: shields-production
|
envLabel: shields-production
|
||||||
|
|
||||||
ssl:
|
ssl:
|
||||||
isSecure: false
|
isSecure: true
|
||||||
|
|
||||||
cors:
|
cors:
|
||||||
allowedOrigin: ['http://shields.io', 'https://shields.io']
|
allowedOrigin: ['http://shields.io', 'https://shields.io']
|
||||||
|
|
||||||
services:
|
|
||||||
gitlab:
|
|
||||||
authorizedOrigins: 'https://gitlab.com'
|
|
||||||
|
|
||||||
rasterUrl: 'https://raster.shields.io'
|
rasterUrl: 'https://raster.shields.io'
|
||||||
userAgentBase: 'Shields.io'
|
|
||||||
requireCloudflare: true
|
|
||||||
requestTimeoutSeconds: 20
|
|
||||||
|
|||||||
112
core/badge-urls/make-badge-url.d.ts
vendored
Normal file
112
core/badge-urls/make-badge-url.d.ts
vendored
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
export function badgeUrlFromPath({
|
||||||
|
baseUrl,
|
||||||
|
path,
|
||||||
|
queryParams,
|
||||||
|
style,
|
||||||
|
format,
|
||||||
|
longCache,
|
||||||
|
}: {
|
||||||
|
baseUrl?: string
|
||||||
|
path: string
|
||||||
|
queryParams: { [k: string]: string | number | boolean }
|
||||||
|
style?: string
|
||||||
|
format?: string
|
||||||
|
longCache?: boolean
|
||||||
|
}): string
|
||||||
|
|
||||||
|
export function badgeUrlFromPattern({
|
||||||
|
baseUrl,
|
||||||
|
pattern,
|
||||||
|
namedParams,
|
||||||
|
queryParams,
|
||||||
|
style,
|
||||||
|
format,
|
||||||
|
longCache,
|
||||||
|
}: {
|
||||||
|
baseUrl?: string
|
||||||
|
pattern: string
|
||||||
|
namedParams: { [k: string]: string }
|
||||||
|
queryParams: { [k: string]: string | number | boolean }
|
||||||
|
style?: string
|
||||||
|
format?: string
|
||||||
|
longCache?: boolean
|
||||||
|
}): string
|
||||||
|
|
||||||
|
export function encodeField(s: string): string
|
||||||
|
|
||||||
|
export function staticBadgeUrl({
|
||||||
|
baseUrl,
|
||||||
|
label,
|
||||||
|
message,
|
||||||
|
labelColor,
|
||||||
|
color,
|
||||||
|
style,
|
||||||
|
namedLogo,
|
||||||
|
format,
|
||||||
|
links,
|
||||||
|
}: {
|
||||||
|
baseUrl?: string
|
||||||
|
label: string
|
||||||
|
message: string
|
||||||
|
labelColor?: string
|
||||||
|
color?: string
|
||||||
|
style?: string
|
||||||
|
namedLogo?: string
|
||||||
|
format?: string
|
||||||
|
links?: string[]
|
||||||
|
}): string
|
||||||
|
|
||||||
|
export function queryStringStaticBadgeUrl({
|
||||||
|
baseUrl,
|
||||||
|
label,
|
||||||
|
message,
|
||||||
|
color,
|
||||||
|
labelColor,
|
||||||
|
style,
|
||||||
|
namedLogo,
|
||||||
|
logoColor,
|
||||||
|
logoWidth,
|
||||||
|
logoPosition,
|
||||||
|
format,
|
||||||
|
}: {
|
||||||
|
baseUrl?: string
|
||||||
|
label: string
|
||||||
|
message: string
|
||||||
|
color?: string
|
||||||
|
labelColor?: string
|
||||||
|
style?: string
|
||||||
|
namedLogo?: string
|
||||||
|
logoColor?: string
|
||||||
|
logoWidth?: number
|
||||||
|
logoPosition?: number
|
||||||
|
format?: string
|
||||||
|
}): string
|
||||||
|
|
||||||
|
export function dynamicBadgeUrl({
|
||||||
|
baseUrl,
|
||||||
|
datatype,
|
||||||
|
label,
|
||||||
|
dataUrl,
|
||||||
|
query,
|
||||||
|
prefix,
|
||||||
|
suffix,
|
||||||
|
color,
|
||||||
|
style,
|
||||||
|
format,
|
||||||
|
}: {
|
||||||
|
baseUrl?: string
|
||||||
|
datatype: string
|
||||||
|
label: string
|
||||||
|
dataUrl: string
|
||||||
|
query: string
|
||||||
|
prefix: string
|
||||||
|
suffix: string
|
||||||
|
color?: string
|
||||||
|
style?: string
|
||||||
|
format?: string
|
||||||
|
}): string
|
||||||
|
|
||||||
|
export function rasterRedirectUrl(
|
||||||
|
{ rasterUrl }: { rasterUrl: string },
|
||||||
|
badgeUrl: string
|
||||||
|
): string
|
||||||
@@ -1,5 +1,147 @@
|
|||||||
// Avoid "Attempted import error: 'URL' is not exported from 'url'" in frontend.
|
// Avoid "Attempted import error: 'URL' is not exported from 'url'" in frontend.
|
||||||
import url from 'url'
|
import url from 'url'
|
||||||
|
import queryString from 'query-string'
|
||||||
|
import { compile } from 'path-to-regexp'
|
||||||
|
|
||||||
|
function badgeUrlFromPath({
|
||||||
|
baseUrl = '',
|
||||||
|
path,
|
||||||
|
queryParams,
|
||||||
|
style,
|
||||||
|
format = '',
|
||||||
|
longCache = false,
|
||||||
|
}) {
|
||||||
|
const outExt = format.length ? `.${format}` : ''
|
||||||
|
|
||||||
|
const outQueryString = queryString.stringify({
|
||||||
|
cacheSeconds: longCache ? '2592000' : undefined,
|
||||||
|
style,
|
||||||
|
...queryParams,
|
||||||
|
})
|
||||||
|
const suffix = outQueryString ? `?${outQueryString}` : ''
|
||||||
|
|
||||||
|
return `${baseUrl}${path}${outExt}${suffix}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function badgeUrlFromPattern({
|
||||||
|
baseUrl = '',
|
||||||
|
pattern,
|
||||||
|
namedParams,
|
||||||
|
queryParams,
|
||||||
|
style,
|
||||||
|
format = '',
|
||||||
|
longCache = false,
|
||||||
|
}) {
|
||||||
|
const toPath = compile(pattern, {
|
||||||
|
strict: true,
|
||||||
|
sensitive: true,
|
||||||
|
encode: encodeURIComponent,
|
||||||
|
})
|
||||||
|
|
||||||
|
const path = toPath(namedParams)
|
||||||
|
|
||||||
|
return badgeUrlFromPath({
|
||||||
|
baseUrl,
|
||||||
|
path,
|
||||||
|
queryParams,
|
||||||
|
style,
|
||||||
|
format,
|
||||||
|
longCache,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function encodeField(s) {
|
||||||
|
return encodeURIComponent(s.replace(/-/g, '--').replace(/_/g, '__'))
|
||||||
|
}
|
||||||
|
|
||||||
|
function staticBadgeUrl({
|
||||||
|
baseUrl = '',
|
||||||
|
label,
|
||||||
|
message,
|
||||||
|
labelColor,
|
||||||
|
color = 'lightgray',
|
||||||
|
style,
|
||||||
|
namedLogo,
|
||||||
|
format = '',
|
||||||
|
links = [],
|
||||||
|
}) {
|
||||||
|
const path = [label, message, color].map(encodeField).join('-')
|
||||||
|
const outQueryString = queryString.stringify({
|
||||||
|
labelColor,
|
||||||
|
style,
|
||||||
|
logo: namedLogo,
|
||||||
|
link: links,
|
||||||
|
})
|
||||||
|
const outExt = format.length ? `.${format}` : ''
|
||||||
|
const suffix = outQueryString ? `?${outQueryString}` : ''
|
||||||
|
return `${baseUrl}/badge/${path}${outExt}${suffix}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function queryStringStaticBadgeUrl({
|
||||||
|
baseUrl = '',
|
||||||
|
label,
|
||||||
|
message,
|
||||||
|
color,
|
||||||
|
labelColor,
|
||||||
|
style,
|
||||||
|
namedLogo,
|
||||||
|
logoColor,
|
||||||
|
logoWidth,
|
||||||
|
logoPosition,
|
||||||
|
format = '',
|
||||||
|
}) {
|
||||||
|
// schemaVersion could be a parameter if we iterate on it,
|
||||||
|
// for now it's hardcoded to the only supported version.
|
||||||
|
const schemaVersion = '1'
|
||||||
|
const suffix = `?${queryString.stringify({
|
||||||
|
label,
|
||||||
|
message,
|
||||||
|
color,
|
||||||
|
labelColor,
|
||||||
|
style,
|
||||||
|
logo: namedLogo,
|
||||||
|
logoColor,
|
||||||
|
logoWidth,
|
||||||
|
logoPosition,
|
||||||
|
})}`
|
||||||
|
const outExt = format.length ? `.${format}` : ''
|
||||||
|
return `${baseUrl}/static/v${schemaVersion}${outExt}${suffix}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function dynamicBadgeUrl({
|
||||||
|
baseUrl,
|
||||||
|
datatype,
|
||||||
|
label,
|
||||||
|
dataUrl,
|
||||||
|
query,
|
||||||
|
prefix,
|
||||||
|
suffix,
|
||||||
|
color,
|
||||||
|
style,
|
||||||
|
format = '',
|
||||||
|
}) {
|
||||||
|
const outExt = format.length ? `.${format}` : ''
|
||||||
|
|
||||||
|
const queryParams = {
|
||||||
|
label,
|
||||||
|
url: dataUrl,
|
||||||
|
query,
|
||||||
|
style,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (color) {
|
||||||
|
queryParams.color = color
|
||||||
|
}
|
||||||
|
if (prefix) {
|
||||||
|
queryParams.prefix = prefix
|
||||||
|
}
|
||||||
|
if (suffix) {
|
||||||
|
queryParams.suffix = suffix
|
||||||
|
}
|
||||||
|
|
||||||
|
const outQueryString = queryString.stringify(queryParams)
|
||||||
|
return `${baseUrl}/badge/dynamic/${datatype}${outExt}?${outQueryString}`
|
||||||
|
}
|
||||||
|
|
||||||
function rasterRedirectUrl({ rasterUrl }, badgeUrl) {
|
function rasterRedirectUrl({ rasterUrl }, badgeUrl) {
|
||||||
// Ensure we're always using the `rasterUrl` by using just the path from
|
// Ensure we're always using the `rasterUrl` by using just the path from
|
||||||
@@ -10,4 +152,12 @@ function rasterRedirectUrl({ rasterUrl }, badgeUrl) {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
export { rasterRedirectUrl }
|
export {
|
||||||
|
badgeUrlFromPath,
|
||||||
|
badgeUrlFromPattern,
|
||||||
|
encodeField,
|
||||||
|
staticBadgeUrl,
|
||||||
|
queryStringStaticBadgeUrl,
|
||||||
|
dynamicBadgeUrl,
|
||||||
|
rasterRedirectUrl,
|
||||||
|
}
|
||||||
|
|||||||
155
core/badge-urls/make-badge-url.spec.js
Normal file
155
core/badge-urls/make-badge-url.spec.js
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
import { test, given } from 'sazerac'
|
||||||
|
import {
|
||||||
|
badgeUrlFromPath,
|
||||||
|
badgeUrlFromPattern,
|
||||||
|
encodeField,
|
||||||
|
staticBadgeUrl,
|
||||||
|
queryStringStaticBadgeUrl,
|
||||||
|
dynamicBadgeUrl,
|
||||||
|
} from './make-badge-url.js'
|
||||||
|
|
||||||
|
describe('Badge URL generation functions', function () {
|
||||||
|
test(badgeUrlFromPath, () => {
|
||||||
|
given({
|
||||||
|
baseUrl: 'http://example.com',
|
||||||
|
path: '/npm/v/gh-badges',
|
||||||
|
style: 'flat-square',
|
||||||
|
longCache: true,
|
||||||
|
}).expect(
|
||||||
|
'http://example.com/npm/v/gh-badges?cacheSeconds=2592000&style=flat-square'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test(badgeUrlFromPattern, () => {
|
||||||
|
given({
|
||||||
|
baseUrl: 'http://example.com',
|
||||||
|
pattern: '/npm/v/:packageName',
|
||||||
|
namedParams: { packageName: 'gh-badges' },
|
||||||
|
style: 'flat-square',
|
||||||
|
longCache: true,
|
||||||
|
}).expect(
|
||||||
|
'http://example.com/npm/v/gh-badges?cacheSeconds=2592000&style=flat-square'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test(encodeField, () => {
|
||||||
|
given('foo').expect('foo')
|
||||||
|
given('').expect('')
|
||||||
|
given('happy go lucky').expect('happy%20go%20lucky')
|
||||||
|
given('do-right').expect('do--right')
|
||||||
|
given('it_is_a_snake').expect('it__is__a__snake')
|
||||||
|
})
|
||||||
|
|
||||||
|
test(staticBadgeUrl, () => {
|
||||||
|
given({
|
||||||
|
label: 'foo',
|
||||||
|
message: 'bar',
|
||||||
|
color: 'blue',
|
||||||
|
style: 'flat-square',
|
||||||
|
}).expect('/badge/foo-bar-blue?style=flat-square')
|
||||||
|
given({
|
||||||
|
label: 'foo',
|
||||||
|
message: 'bar',
|
||||||
|
color: 'blue',
|
||||||
|
style: 'flat-square',
|
||||||
|
format: 'png',
|
||||||
|
namedLogo: 'github',
|
||||||
|
}).expect('/badge/foo-bar-blue.png?logo=github&style=flat-square')
|
||||||
|
given({
|
||||||
|
label: 'Hello World',
|
||||||
|
message: 'Привет Мир',
|
||||||
|
color: '#aabbcc',
|
||||||
|
}).expect(
|
||||||
|
'/badge/Hello%20World-%D0%9F%D1%80%D0%B8%D0%B2%D0%B5%D1%82%20%D0%9C%D0%B8%D1%80-%23aabbcc'
|
||||||
|
)
|
||||||
|
given({
|
||||||
|
label: '123-123',
|
||||||
|
message: 'abc-abc',
|
||||||
|
color: 'blue',
|
||||||
|
}).expect('/badge/123--123-abc--abc-blue')
|
||||||
|
given({
|
||||||
|
label: '123-123',
|
||||||
|
message: '',
|
||||||
|
color: 'blue',
|
||||||
|
style: 'social',
|
||||||
|
}).expect('/badge/123--123--blue?style=social')
|
||||||
|
given({
|
||||||
|
label: '',
|
||||||
|
message: 'blue',
|
||||||
|
color: 'blue',
|
||||||
|
}).expect('/badge/-blue-blue')
|
||||||
|
})
|
||||||
|
|
||||||
|
test(queryStringStaticBadgeUrl, () => {
|
||||||
|
// the query-string library sorts parameters by name
|
||||||
|
given({
|
||||||
|
label: 'foo',
|
||||||
|
message: 'bar',
|
||||||
|
color: 'blue',
|
||||||
|
style: 'flat-square',
|
||||||
|
}).expect('/static/v1?color=blue&label=foo&message=bar&style=flat-square')
|
||||||
|
given({
|
||||||
|
label: 'foo Bar',
|
||||||
|
message: 'bar Baz',
|
||||||
|
color: 'blue',
|
||||||
|
style: 'flat-square',
|
||||||
|
format: 'png',
|
||||||
|
namedLogo: 'github',
|
||||||
|
}).expect(
|
||||||
|
'/static/v1.png?color=blue&label=foo%20Bar&logo=github&message=bar%20Baz&style=flat-square'
|
||||||
|
)
|
||||||
|
given({
|
||||||
|
label: 'Hello World',
|
||||||
|
message: 'Привет Мир',
|
||||||
|
color: '#aabbcc',
|
||||||
|
}).expect(
|
||||||
|
'/static/v1?color=%23aabbcc&label=Hello%20World&message=%D0%9F%D1%80%D0%B8%D0%B2%D0%B5%D1%82%20%D0%9C%D0%B8%D1%80'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test(dynamicBadgeUrl, () => {
|
||||||
|
const dataUrl = 'http://example.com/foo.json'
|
||||||
|
const query = '$.bar'
|
||||||
|
const prefix = 'value: '
|
||||||
|
given({
|
||||||
|
baseUrl: 'http://img.example.com',
|
||||||
|
datatype: 'json',
|
||||||
|
label: 'foo',
|
||||||
|
dataUrl,
|
||||||
|
query,
|
||||||
|
prefix,
|
||||||
|
style: 'plastic',
|
||||||
|
}).expect(
|
||||||
|
[
|
||||||
|
'http://img.example.com/badge/dynamic/json',
|
||||||
|
'?label=foo',
|
||||||
|
`&prefix=${encodeURIComponent(prefix)}`,
|
||||||
|
`&query=${encodeURIComponent(query)}`,
|
||||||
|
'&style=plastic',
|
||||||
|
`&url=${encodeURIComponent(dataUrl)}`,
|
||||||
|
].join('')
|
||||||
|
)
|
||||||
|
const suffix = '<- value'
|
||||||
|
const color = 'blue'
|
||||||
|
given({
|
||||||
|
baseUrl: 'http://img.example.com',
|
||||||
|
datatype: 'json',
|
||||||
|
label: 'foo',
|
||||||
|
dataUrl,
|
||||||
|
query,
|
||||||
|
suffix,
|
||||||
|
color,
|
||||||
|
style: 'plastic',
|
||||||
|
}).expect(
|
||||||
|
[
|
||||||
|
'http://img.example.com/badge/dynamic/json',
|
||||||
|
'?color=blue',
|
||||||
|
'&label=foo',
|
||||||
|
`&query=${encodeURIComponent(query)}`,
|
||||||
|
'&style=plastic',
|
||||||
|
`&suffix=${encodeURIComponent(suffix)}`,
|
||||||
|
`&url=${encodeURIComponent(dataUrl)}`,
|
||||||
|
].join('')
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -44,12 +44,6 @@ class BaseGraphqlService extends BaseService {
|
|||||||
* and custom error messages e.g: `{ 404: 'package not found' }`.
|
* and custom error messages e.g: `{ 404: 'package not found' }`.
|
||||||
* This can be used to extend or override the
|
* This can be used to extend or override the
|
||||||
* [default](https://github.com/badges/shields/blob/master/core/base-service/check-error-response.js#L5)
|
* [default](https://github.com/badges/shields/blob/master/core/base-service/check-error-response.js#L5)
|
||||||
* @param {object} [attrs.systemErrors={}] Key-value map of got network exception codes
|
|
||||||
* and an object of params to pass when we construct an Inaccessible exception object
|
|
||||||
* e.g: `{ ECONNRESET: { prettyMessage: 'connection reset' } }`.
|
|
||||||
* See {@link https://github.com/sindresorhus/got/blob/main/documentation/7-retry.md#errorcodes got error codes}
|
|
||||||
* for allowed keys
|
|
||||||
* and {@link module:core/base-service/errors~RuntimeErrorProps} for allowed values
|
|
||||||
* @param {Function} [attrs.transformJson=data => data] Function which takes the raw json and transforms it before
|
* @param {Function} [attrs.transformJson=data => data] Function which takes the raw json and transforms it before
|
||||||
* further procesing. In case of multiple query in a single graphql call and few of them
|
* further procesing. In case of multiple query in a single graphql call and few of them
|
||||||
* throw error, partial data might be used ignoring the error.
|
* throw error, partial data might be used ignoring the error.
|
||||||
@@ -68,7 +62,6 @@ class BaseGraphqlService extends BaseService {
|
|||||||
variables = {},
|
variables = {},
|
||||||
options = {},
|
options = {},
|
||||||
httpErrorMessages = {},
|
httpErrorMessages = {},
|
||||||
systemErrors = {},
|
|
||||||
transformJson = data => data,
|
transformJson = data => data,
|
||||||
transformErrors = defaultTransformErrors,
|
transformErrors = defaultTransformErrors,
|
||||||
}) {
|
}) {
|
||||||
@@ -81,8 +74,7 @@ class BaseGraphqlService extends BaseService {
|
|||||||
const { buffer } = await this._request({
|
const { buffer } = await this._request({
|
||||||
url,
|
url,
|
||||||
options: mergedOptions,
|
options: mergedOptions,
|
||||||
httpErrors: httpErrorMessages,
|
errorMessages: httpErrorMessages,
|
||||||
systemErrors,
|
|
||||||
})
|
})
|
||||||
const json = transformJson(this._parseJson(buffer))
|
const json = transformJson(this._parseJson(buffer))
|
||||||
if (json.errors) {
|
if (json.errors) {
|
||||||
|
|||||||
@@ -30,26 +30,14 @@ class BaseJsonService extends BaseService {
|
|||||||
* @param {string} attrs.url URL to request
|
* @param {string} attrs.url URL to request
|
||||||
* @param {object} [attrs.options={}] Options to pass to got. See
|
* @param {object} [attrs.options={}] Options to pass to got. See
|
||||||
* [documentation](https://github.com/sindresorhus/got/blob/main/documentation/2-options.md)
|
* [documentation](https://github.com/sindresorhus/got/blob/main/documentation/2-options.md)
|
||||||
* @param {object} [attrs.httpErrors={}] Key-value map of status codes
|
* @param {object} [attrs.errorMessages={}] Key-value map of status codes
|
||||||
* and custom error messages e.g: `{ 404: 'package not found' }`.
|
* and custom error messages e.g: `{ 404: 'package not found' }`.
|
||||||
* This can be used to extend or override the
|
* This can be used to extend or override the
|
||||||
* [default](https://github.com/badges/shields/blob/master/core/base-service/check-error-response.js#L5)
|
* [default](https://github.com/badges/shields/blob/master/core/base-service/check-error-response.js#L5)
|
||||||
* @param {object} [attrs.systemErrors={}] Key-value map of got network exception codes
|
|
||||||
* and an object of params to pass when we construct an Inaccessible exception object
|
|
||||||
* e.g: `{ ECONNRESET: { prettyMessage: 'connection reset' } }`.
|
|
||||||
* See {@link https://github.com/sindresorhus/got/blob/main/documentation/7-retry.md#errorcodes got error codes}
|
|
||||||
* for allowed keys
|
|
||||||
* and {@link module:core/base-service/errors~RuntimeErrorProps} for allowed values
|
|
||||||
* @returns {object} Parsed response
|
* @returns {object} Parsed response
|
||||||
* @see https://github.com/sindresorhus/got/blob/main/documentation/2-options.md
|
* @see https://github.com/sindresorhus/got/blob/main/documentation/2-options.md
|
||||||
*/
|
*/
|
||||||
async _requestJson({
|
async _requestJson({ schema, url, options = {}, errorMessages = {} }) {
|
||||||
schema,
|
|
||||||
url,
|
|
||||||
options = {},
|
|
||||||
httpErrors = {},
|
|
||||||
systemErrors = {},
|
|
||||||
}) {
|
|
||||||
const mergedOptions = {
|
const mergedOptions = {
|
||||||
...{ headers: { Accept: 'application/json' } },
|
...{ headers: { Accept: 'application/json' } },
|
||||||
...options,
|
...options,
|
||||||
@@ -57,8 +45,7 @@ class BaseJsonService extends BaseService {
|
|||||||
const { buffer } = await this._request({
|
const { buffer } = await this._request({
|
||||||
url,
|
url,
|
||||||
options: mergedOptions,
|
options: mergedOptions,
|
||||||
httpErrors,
|
errorMessages,
|
||||||
systemErrors,
|
|
||||||
})
|
})
|
||||||
const json = this._parseJson(buffer)
|
const json = this._parseJson(buffer)
|
||||||
return this.constructor._validate(json, schema)
|
return this.constructor._validate(json, schema)
|
||||||
|
|||||||
@@ -53,16 +53,10 @@ class BaseSvgScrapingService extends BaseService {
|
|||||||
* @param {string} attrs.url URL to request
|
* @param {string} attrs.url URL to request
|
||||||
* @param {object} [attrs.options={}] Options to pass to got. See
|
* @param {object} [attrs.options={}] Options to pass to got. See
|
||||||
* [documentation](https://github.com/sindresorhus/got/blob/main/documentation/2-options.md)
|
* [documentation](https://github.com/sindresorhus/got/blob/main/documentation/2-options.md)
|
||||||
* @param {object} [attrs.httpErrors={}] Key-value map of status codes
|
* @param {object} [attrs.errorMessages={}] Key-value map of status codes
|
||||||
* and custom error messages e.g: `{ 404: 'package not found' }`.
|
* and custom error messages e.g: `{ 404: 'package not found' }`.
|
||||||
* This can be used to extend or override the
|
* This can be used to extend or override the
|
||||||
* [default](https://github.com/badges/shields/blob/master/core/base-service/check-error-response.js#L5)
|
* [default](https://github.com/badges/shields/blob/master/core/base-service/check-error-response.js#L5)
|
||||||
* @param {object} [attrs.systemErrors={}] Key-value map of got network exception codes
|
|
||||||
* and an object of params to pass when we construct an Inaccessible exception object
|
|
||||||
* e.g: `{ ECONNRESET: { prettyMessage: 'connection reset' } }`.
|
|
||||||
* See {@link https://github.com/sindresorhus/got/blob/main/documentation/7-retry.md#errorcodes got error codes}
|
|
||||||
* for allowed keys
|
|
||||||
* and {@link module:core/base-service/errors~RuntimeErrorProps} for allowed values
|
|
||||||
* @returns {object} Parsed response
|
* @returns {object} Parsed response
|
||||||
* @see https://github.com/sindresorhus/got/blob/main/documentation/2-options.md
|
* @see https://github.com/sindresorhus/got/blob/main/documentation/2-options.md
|
||||||
*/
|
*/
|
||||||
@@ -71,8 +65,7 @@ class BaseSvgScrapingService extends BaseService {
|
|||||||
valueMatcher,
|
valueMatcher,
|
||||||
url,
|
url,
|
||||||
options = {},
|
options = {},
|
||||||
httpErrors = {},
|
errorMessages = {},
|
||||||
systemErrors = {},
|
|
||||||
}) {
|
}) {
|
||||||
const logTrace = (...args) => trace.logTrace('fetch', ...args)
|
const logTrace = (...args) => trace.logTrace('fetch', ...args)
|
||||||
const mergedOptions = {
|
const mergedOptions = {
|
||||||
@@ -82,8 +75,7 @@ class BaseSvgScrapingService extends BaseService {
|
|||||||
const { buffer } = await this._request({
|
const { buffer } = await this._request({
|
||||||
url,
|
url,
|
||||||
options: mergedOptions,
|
options: mergedOptions,
|
||||||
httpErrors,
|
errorMessages,
|
||||||
systemErrors,
|
|
||||||
})
|
})
|
||||||
logTrace(emojic.dart, 'Response SVG', buffer)
|
logTrace(emojic.dart, 'Response SVG', buffer)
|
||||||
const data = {
|
const data = {
|
||||||
|
|||||||
@@ -24,16 +24,10 @@ class BaseXmlService extends BaseService {
|
|||||||
* @param {string} attrs.url URL to request
|
* @param {string} attrs.url URL to request
|
||||||
* @param {object} [attrs.options={}] Options to pass to got. See
|
* @param {object} [attrs.options={}] Options to pass to got. See
|
||||||
* [documentation](https://github.com/sindresorhus/got/blob/main/documentation/2-options.md)
|
* [documentation](https://github.com/sindresorhus/got/blob/main/documentation/2-options.md)
|
||||||
* @param {object} [attrs.httpErrors={}] Key-value map of status codes
|
* @param {object} [attrs.errorMessages={}] Key-value map of status codes
|
||||||
* and custom error messages e.g: `{ 404: 'package not found' }`.
|
* and custom error messages e.g: `{ 404: 'package not found' }`.
|
||||||
* This can be used to extend or override the
|
* This can be used to extend or override the
|
||||||
* [default](https://github.com/badges/shields/blob/master/core/base-service/check-error-response.js#L5)
|
* [default](https://github.com/badges/shields/blob/master/core/base-service/check-error-response.js#L5)
|
||||||
* @param {object} [attrs.systemErrors={}] Key-value map of got network exception codes
|
|
||||||
* and an object of params to pass when we construct an Inaccessible exception object
|
|
||||||
* e.g: `{ ECONNRESET: { prettyMessage: 'connection reset' } }`.
|
|
||||||
* See {@link https://github.com/sindresorhus/got/blob/main/documentation/7-retry.md#errorcodes got error codes}
|
|
||||||
* for allowed keys
|
|
||||||
* and {@link module:core/base-service/errors~RuntimeErrorProps} for allowed values
|
|
||||||
* @param {object} [attrs.parserOptions={}] Options to pass to fast-xml-parser. See
|
* @param {object} [attrs.parserOptions={}] Options to pass to fast-xml-parser. See
|
||||||
* [documentation](https://github.com/NaturalIntelligence/fast-xml-parser#xml-to-json)
|
* [documentation](https://github.com/NaturalIntelligence/fast-xml-parser#xml-to-json)
|
||||||
* @returns {object} Parsed response
|
* @returns {object} Parsed response
|
||||||
@@ -44,8 +38,7 @@ class BaseXmlService extends BaseService {
|
|||||||
schema,
|
schema,
|
||||||
url,
|
url,
|
||||||
options = {},
|
options = {},
|
||||||
httpErrors = {},
|
errorMessages = {},
|
||||||
systemErrors = {},
|
|
||||||
parserOptions = {},
|
parserOptions = {},
|
||||||
}) {
|
}) {
|
||||||
const logTrace = (...args) => trace.logTrace('fetch', ...args)
|
const logTrace = (...args) => trace.logTrace('fetch', ...args)
|
||||||
@@ -56,8 +49,7 @@ class BaseXmlService extends BaseService {
|
|||||||
const { buffer } = await this._request({
|
const { buffer } = await this._request({
|
||||||
url,
|
url,
|
||||||
options: mergedOptions,
|
options: mergedOptions,
|
||||||
httpErrors,
|
errorMessages,
|
||||||
systemErrors,
|
|
||||||
})
|
})
|
||||||
const validateResult = XMLValidator.validate(buffer)
|
const validateResult = XMLValidator.validate(buffer)
|
||||||
if (validateResult !== true) {
|
if (validateResult !== true) {
|
||||||
|
|||||||
@@ -23,16 +23,10 @@ class BaseYamlService extends BaseService {
|
|||||||
* @param {string} attrs.url URL to request
|
* @param {string} attrs.url URL to request
|
||||||
* @param {object} [attrs.options={}] Options to pass to got. See
|
* @param {object} [attrs.options={}] Options to pass to got. See
|
||||||
* [documentation](https://github.com/sindresorhus/got/blob/main/documentation/2-options.md)
|
* [documentation](https://github.com/sindresorhus/got/blob/main/documentation/2-options.md)
|
||||||
* @param {object} [attrs.httpErrors={}] Key-value map of status codes
|
* @param {object} [attrs.errorMessages={}] Key-value map of status codes
|
||||||
* and custom error messages e.g: `{ 404: 'package not found' }`.
|
* and custom error messages e.g: `{ 404: 'package not found' }`.
|
||||||
* This can be used to extend or override the
|
* This can be used to extend or override the
|
||||||
* [default](https://github.com/badges/shields/blob/master/core/base-service/check-error-response.js#L5)
|
* [default](https://github.com/badges/shields/blob/master/core/base-service/check-error-response.js#L5)
|
||||||
* @param {object} [attrs.systemErrors={}] Key-value map of got network exception codes
|
|
||||||
* and an object of params to pass when we construct an Inaccessible exception object
|
|
||||||
* e.g: `{ ECONNRESET: { prettyMessage: 'connection reset' } }`.
|
|
||||||
* See {@link https://github.com/sindresorhus/got/blob/main/documentation/7-retry.md#errorcodes got error codes}
|
|
||||||
* for allowed keys
|
|
||||||
* and {@link module:core/base-service/errors~RuntimeErrorProps} for allowed values
|
|
||||||
* @param {object} [attrs.encoding='utf8'] Character encoding
|
* @param {object} [attrs.encoding='utf8'] Character encoding
|
||||||
* @returns {object} Parsed response
|
* @returns {object} Parsed response
|
||||||
* @see https://github.com/sindresorhus/got/blob/main/documentation/2-options.md
|
* @see https://github.com/sindresorhus/got/blob/main/documentation/2-options.md
|
||||||
@@ -41,8 +35,7 @@ class BaseYamlService extends BaseService {
|
|||||||
schema,
|
schema,
|
||||||
url,
|
url,
|
||||||
options = {},
|
options = {},
|
||||||
httpErrors = {},
|
errorMessages = {},
|
||||||
systemErrors = {},
|
|
||||||
encoding = 'utf8',
|
encoding = 'utf8',
|
||||||
}) {
|
}) {
|
||||||
const logTrace = (...args) => trace.logTrace('fetch', ...args)
|
const logTrace = (...args) => trace.logTrace('fetch', ...args)
|
||||||
@@ -58,8 +51,7 @@ class BaseYamlService extends BaseService {
|
|||||||
const { buffer } = await this._request({
|
const { buffer } = await this._request({
|
||||||
url,
|
url,
|
||||||
options: mergedOptions,
|
options: mergedOptions,
|
||||||
httpErrors,
|
errorMessages,
|
||||||
systemErrors,
|
|
||||||
})
|
})
|
||||||
let parsed
|
let parsed
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -140,15 +140,6 @@ class BaseService {
|
|||||||
*/
|
*/
|
||||||
static examples = []
|
static examples = []
|
||||||
|
|
||||||
/**
|
|
||||||
* Optional: an OpenAPI Paths Object describing this service's
|
|
||||||
* route or routes in OpenAPI format.
|
|
||||||
*
|
|
||||||
* @see https://swagger.io/specification/#paths-object
|
|
||||||
* @abstract
|
|
||||||
*/
|
|
||||||
static openApi = undefined
|
|
||||||
|
|
||||||
static get _cacheLength() {
|
static get _cacheLength() {
|
||||||
const cacheLengths = {
|
const cacheLengths = {
|
||||||
build: 30,
|
build: 30,
|
||||||
@@ -156,7 +147,6 @@ class BaseService {
|
|||||||
version: 300,
|
version: 300,
|
||||||
debug: 60,
|
debug: 60,
|
||||||
downloads: 900,
|
downloads: 900,
|
||||||
rating: 900,
|
|
||||||
social: 900,
|
social: 900,
|
||||||
}
|
}
|
||||||
return cacheLengths[this.category]
|
return cacheLengths[this.category]
|
||||||
@@ -192,7 +182,7 @@ class BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static getDefinition() {
|
static getDefinition() {
|
||||||
const { category, name, isDeprecated, openApi } = this
|
const { category, name, isDeprecated } = this
|
||||||
const { base, format, pattern } = this.route
|
const { base, format, pattern } = this.route
|
||||||
const queryParams = getQueryParamNames(this.route)
|
const queryParams = getQueryParamNames(this.route)
|
||||||
|
|
||||||
@@ -209,7 +199,7 @@ class BaseService {
|
|||||||
route = undefined
|
route = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = { category, name, isDeprecated, route, examples, openApi }
|
const result = { category, name, isDeprecated, route, examples }
|
||||||
|
|
||||||
assertValidServiceDefinition(result, `getDefinition() for ${this.name}`)
|
assertValidServiceDefinition(result, `getDefinition() for ${this.name}`)
|
||||||
|
|
||||||
@@ -226,18 +216,12 @@ class BaseService {
|
|||||||
this._metricHelper = metricHelper
|
this._metricHelper = metricHelper
|
||||||
}
|
}
|
||||||
|
|
||||||
async _request({ url, options = {}, httpErrors = {}, systemErrors = {} }) {
|
async _request({ url, options = {}, errorMessages = {} }) {
|
||||||
const logTrace = (...args) => trace.logTrace('fetch', ...args)
|
const logTrace = (...args) => trace.logTrace('fetch', ...args)
|
||||||
let logUrl = url
|
let logUrl = url
|
||||||
const logOptions = Object.assign({}, options)
|
const logOptions = Object.assign({}, options)
|
||||||
if ('searchParams' in options && options.searchParams != null) {
|
if ('searchParams' in options) {
|
||||||
const params = new URLSearchParams(
|
const params = new URLSearchParams(options.searchParams)
|
||||||
Object.fromEntries(
|
|
||||||
Object.entries(options.searchParams).filter(
|
|
||||||
([k, v]) => v !== undefined
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
logUrl = `${url}?${params.toString()}`
|
logUrl = `${url}?${params.toString()}`
|
||||||
delete logOptions.searchParams
|
delete logOptions.searchParams
|
||||||
}
|
}
|
||||||
@@ -246,14 +230,10 @@ class BaseService {
|
|||||||
'Request',
|
'Request',
|
||||||
`${logUrl}\n${JSON.stringify(logOptions, null, 2)}`
|
`${logUrl}\n${JSON.stringify(logOptions, null, 2)}`
|
||||||
)
|
)
|
||||||
const { res, buffer } = await this._requestFetcher(
|
const { res, buffer } = await this._requestFetcher(url, options)
|
||||||
url,
|
|
||||||
options,
|
|
||||||
systemErrors
|
|
||||||
)
|
|
||||||
await this._meterResponse(res, buffer)
|
await this._meterResponse(res, buffer)
|
||||||
logTrace(emojic.dart, 'Response status code', res.statusCode)
|
logTrace(emojic.dart, 'Response status code', res.statusCode)
|
||||||
return checkErrorResponse(httpErrors)({ buffer, res })
|
return checkErrorResponse(errorMessages)({ buffer, res })
|
||||||
}
|
}
|
||||||
|
|
||||||
static enabledMetrics = []
|
static enabledMetrics = []
|
||||||
@@ -332,15 +312,11 @@ class BaseService {
|
|||||||
error instanceof Deprecated
|
error instanceof Deprecated
|
||||||
) {
|
) {
|
||||||
trace.logTrace('outbound', emojic.noGoodWoman, 'Handled error', error)
|
trace.logTrace('outbound', emojic.noGoodWoman, 'Handled error', error)
|
||||||
const serviceData = {
|
return {
|
||||||
isError: true,
|
isError: true,
|
||||||
message: error.prettyMessage,
|
message: error.prettyMessage,
|
||||||
color: 'lightgray',
|
color: 'lightgray',
|
||||||
}
|
}
|
||||||
if (error.cacheSeconds !== undefined) {
|
|
||||||
serviceData.cacheSeconds = error.cacheSeconds
|
|
||||||
}
|
|
||||||
return serviceData
|
|
||||||
} else if (this._handleInternalErrors) {
|
} else if (this._handleInternalErrors) {
|
||||||
if (
|
if (
|
||||||
!trace.logTrace(
|
!trace.logTrace(
|
||||||
|
|||||||
@@ -440,21 +440,14 @@ describe('BaseService', function () {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const url = 'some-url'
|
const url = 'some-url'
|
||||||
const options = {
|
const options = { headers: { Cookie: 'some-cookie' } }
|
||||||
headers: { Cookie: 'some-cookie' },
|
|
||||||
searchParams: { param1: 'foobar', param2: undefined },
|
|
||||||
}
|
|
||||||
await serviceInstance._request({ url, options })
|
await serviceInstance._request({ url, options })
|
||||||
|
|
||||||
expect(trace.logTrace).to.be.calledWithMatch(
|
expect(trace.logTrace).to.be.calledWithMatch(
|
||||||
'fetch',
|
'fetch',
|
||||||
sinon.match.string,
|
sinon.match.string,
|
||||||
'Request',
|
'Request',
|
||||||
`${url}?param1=foobar\n${JSON.stringify(
|
`${url}\n${JSON.stringify(options, null, 2)}`
|
||||||
{ headers: options.headers },
|
|
||||||
null,
|
|
||||||
2
|
|
||||||
)}`
|
|
||||||
)
|
)
|
||||||
expect(trace.logTrace).to.be.calledWithMatch(
|
expect(trace.logTrace).to.be.calledWithMatch(
|
||||||
'fetch',
|
'fetch',
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ function coalesceCacheLength({
|
|||||||
assert(defaultCacheLengthSeconds !== undefined)
|
assert(defaultCacheLengthSeconds !== undefined)
|
||||||
|
|
||||||
const cacheLength = coalesce(
|
const cacheLength = coalesce(
|
||||||
serviceOverrideCacheLengthSeconds,
|
|
||||||
serviceDefaultCacheLengthSeconds,
|
serviceDefaultCacheLengthSeconds,
|
||||||
defaultCacheLengthSeconds
|
defaultCacheLengthSeconds
|
||||||
)
|
)
|
||||||
@@ -47,6 +46,7 @@ function coalesceCacheLength({
|
|||||||
// Overrides can apply _more_ caching, but not less. Query param overriding
|
// Overrides can apply _more_ caching, but not less. Query param overriding
|
||||||
// can request more overriding than service override, but not less.
|
// can request more overriding than service override, but not less.
|
||||||
const candidateOverrides = [
|
const candidateOverrides = [
|
||||||
|
serviceOverrideCacheLengthSeconds,
|
||||||
overrideCacheLengthFromQueryParams(queryParams),
|
overrideCacheLengthFromQueryParams(queryParams),
|
||||||
].filter(x => x !== undefined)
|
].filter(x => x !== undefined)
|
||||||
|
|
||||||
|
|||||||
@@ -74,12 +74,12 @@ describe('Cache header functions', function () {
|
|||||||
serviceDefaultCacheLengthSeconds: 900,
|
serviceDefaultCacheLengthSeconds: 900,
|
||||||
serviceOverrideCacheLengthSeconds: 400,
|
serviceOverrideCacheLengthSeconds: 400,
|
||||||
queryParams: {},
|
queryParams: {},
|
||||||
}).expect(400)
|
}).expect(900)
|
||||||
given({
|
given({
|
||||||
cacheHeaderConfig,
|
cacheHeaderConfig,
|
||||||
serviceOverrideCacheLengthSeconds: 400,
|
serviceOverrideCacheLengthSeconds: 400,
|
||||||
queryParams: {},
|
queryParams: {},
|
||||||
}).expect(400)
|
}).expect(777)
|
||||||
given({
|
given({
|
||||||
cacheHeaderConfig,
|
cacheHeaderConfig,
|
||||||
serviceOverrideCacheLengthSeconds: 900,
|
serviceOverrideCacheLengthSeconds: 900,
|
||||||
|
|||||||
@@ -2,22 +2,21 @@ import { NotFound, InvalidResponse, Inaccessible } from './errors.js'
|
|||||||
|
|
||||||
const defaultErrorMessages = {
|
const defaultErrorMessages = {
|
||||||
404: 'not found',
|
404: 'not found',
|
||||||
429: 'rate limited by upstream service',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function checkErrorResponse(httpErrors = {}) {
|
export default function checkErrorResponse(errorMessages = {}) {
|
||||||
return async function ({ buffer, res }) {
|
return async function ({ buffer, res }) {
|
||||||
let error
|
let error
|
||||||
httpErrors = { ...defaultErrorMessages, ...httpErrors }
|
errorMessages = { ...defaultErrorMessages, ...errorMessages }
|
||||||
if (res.statusCode === 404) {
|
if (res.statusCode === 404) {
|
||||||
error = new NotFound({ prettyMessage: httpErrors[404] })
|
error = new NotFound({ prettyMessage: errorMessages[404] })
|
||||||
} else if (res.statusCode !== 200) {
|
} else if (res.statusCode !== 200) {
|
||||||
const underlying = Error(
|
const underlying = Error(
|
||||||
`Got status code ${res.statusCode} (expected 200)`
|
`Got status code ${res.statusCode} (expected 200)`
|
||||||
)
|
)
|
||||||
const props = { underlyingError: underlying }
|
const props = { underlyingError: underlying }
|
||||||
if (httpErrors[res.statusCode] !== undefined) {
|
if (errorMessages[res.statusCode] !== undefined) {
|
||||||
props.prettyMessage = httpErrors[res.statusCode]
|
props.prettyMessage = errorMessages[res.statusCode]
|
||||||
}
|
}
|
||||||
if (res.statusCode >= 500) {
|
if (res.statusCode >= 500) {
|
||||||
error = new Inaccessible(props)
|
error = new Inaccessible(props)
|
||||||
|
|||||||
@@ -45,42 +45,6 @@ describe('async error handler', function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
context('when status is 429', function () {
|
|
||||||
const buffer = Buffer.from('some stuff')
|
|
||||||
const res = { statusCode: 429 }
|
|
||||||
|
|
||||||
it('throws InvalidResponse', async function () {
|
|
||||||
try {
|
|
||||||
await checkErrorResponse()({ res, buffer })
|
|
||||||
expect.fail('Expected to throw')
|
|
||||||
} catch (e) {
|
|
||||||
expect(e).to.be.an.instanceof(InvalidResponse)
|
|
||||||
expect(e.message).to.equal(
|
|
||||||
'Invalid Response: Got status code 429 (expected 200)'
|
|
||||||
)
|
|
||||||
expect(e.prettyMessage).to.equal('rate limited by upstream service')
|
|
||||||
expect(e.response).to.equal(res)
|
|
||||||
expect(e.buffer).to.equal(buffer)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
it('displays the custom too many requests', async function () {
|
|
||||||
const notFoundMessage = "terribly sorry but that's one too many requests"
|
|
||||||
try {
|
|
||||||
await checkErrorResponse({ 429: notFoundMessage })({ res, buffer })
|
|
||||||
expect.fail('Expected to throw')
|
|
||||||
} catch (e) {
|
|
||||||
expect(e).to.be.an.instanceof(InvalidResponse)
|
|
||||||
expect(e.message).to.equal(
|
|
||||||
'Invalid Response: Got status code 429 (expected 200)'
|
|
||||||
)
|
|
||||||
expect(e.prettyMessage).to.equal(
|
|
||||||
"terribly sorry but that's one too many requests"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
context('when status is 4xx', function () {
|
context('when status is 4xx', function () {
|
||||||
it('throws InvalidResponse', async function () {
|
it('throws InvalidResponse', async function () {
|
||||||
const res = { statusCode: 499 }
|
const res = { statusCode: 499 }
|
||||||
|
|||||||
@@ -16,15 +16,16 @@ import toArray from './to-array.js'
|
|||||||
//
|
//
|
||||||
// Logos are resolved in this manner:
|
// Logos are resolved in this manner:
|
||||||
//
|
//
|
||||||
// 1. When `?logo=` contains a named logo or the name of one of the Shields
|
// 1. When `?logo=` contains the name of one of the Shields logos, or contains
|
||||||
// logos or contains base64-encoded SVG, that logo is used. When a
|
// base64-encoded SVG, that logo is used. In the case of a named logo, when
|
||||||
// `&logoColor=` is specified, that color is used (except for the
|
// a `&logoColor=` is specified, that color is used. Otherwise the default
|
||||||
// base64-encoded logos). Otherwise the default color is used. If the color
|
// color is used. `logoColor` will not be applied to a custom
|
||||||
// is specified for a multicolor Shield logo, the named logo will be used and
|
// (base64-encoded) logo; if a custom color is desired the logo should be
|
||||||
// colored. The appearance of the logo can be customized using `logoWidth`,
|
// recolored prior to making the request. The appearance of the logo can be
|
||||||
// and in the case of the popout badge, `logoPosition`. When `?logo=` is
|
// customized using `logoWidth`, and in the case of the popout badge,
|
||||||
// specified, any logo-related parameters specified dynamically by the
|
// `logoPosition`. When `?logo=` is specified, any logo-related parameters
|
||||||
// service, or by default in the service, are ignored.
|
// specified dynamically by the service, or by default in the service, are
|
||||||
|
// ignored.
|
||||||
// 2. The second precedence is the dynamic logo returned by a service. This is
|
// 2. The second precedence is the dynamic logo returned by a service. This is
|
||||||
// used only by the Endpoint badge. The `logoColor` can be overridden by the
|
// used only by the Endpoint badge. The `logoColor` can be overridden by the
|
||||||
// query string.
|
// query string.
|
||||||
|
|||||||
@@ -153,18 +153,10 @@ describe('coalesceBadge', function () {
|
|||||||
).and.not.to.be.empty
|
).and.not.to.be.empty
|
||||||
})
|
})
|
||||||
|
|
||||||
it('applies the named monochrome logo with color', function () {
|
it('applies the named logo with color', function () {
|
||||||
expect(
|
|
||||||
coalesceBadge({}, { namedLogo: 'dependabot', logoColor: 'blue' }, {})
|
|
||||||
.logo
|
|
||||||
).to.equal(getShieldsIcon({ name: 'dependabot', color: 'blue' })).and.not
|
|
||||||
.to.be.empty
|
|
||||||
})
|
|
||||||
|
|
||||||
it('applies the named multicolored logo with color', function () {
|
|
||||||
expect(
|
expect(
|
||||||
coalesceBadge({}, { namedLogo: 'npm', logoColor: 'blue' }, {}).logo
|
coalesceBadge({}, { namedLogo: 'npm', logoColor: 'blue' }, {}).logo
|
||||||
).to.equal(getSimpleIcon({ name: 'npm', color: 'blue' })).and.not.to.be
|
).to.equal(getShieldsIcon({ name: 'npm', color: 'blue' })).and.not.to.be
|
||||||
.empty
|
.empty
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -174,25 +166,15 @@ describe('coalesceBadge', function () {
|
|||||||
).to.equal(getShieldsIcon({ name: 'npm' })).and.not.be.empty
|
).to.equal(getShieldsIcon({ name: 'npm' })).and.not.be.empty
|
||||||
})
|
})
|
||||||
|
|
||||||
it('overrides the monochrome logo with a color', function () {
|
it('overrides the logo with a color', function () {
|
||||||
expect(
|
|
||||||
coalesceBadge(
|
|
||||||
{ logo: 'dependabot', logoColor: 'blue' },
|
|
||||||
{ namedLogo: 'appveyor' },
|
|
||||||
{}
|
|
||||||
).logo
|
|
||||||
).to.equal(getShieldsIcon({ name: 'dependabot', color: 'blue' })).and.not
|
|
||||||
.be.empty
|
|
||||||
})
|
|
||||||
|
|
||||||
it('overrides multicolored logo with a color', function () {
|
|
||||||
expect(
|
expect(
|
||||||
coalesceBadge(
|
coalesceBadge(
|
||||||
{ logo: 'npm', logoColor: 'blue' },
|
{ logo: 'npm', logoColor: 'blue' },
|
||||||
{ namedLogo: 'appveyor' },
|
{ namedLogo: 'appveyor' },
|
||||||
{}
|
{}
|
||||||
).logo
|
).logo
|
||||||
).to.equal(getSimpleIcon({ name: 'npm', color: 'blue' })).and.not.be.empty
|
).to.equal(getShieldsIcon({ name: 'npm', color: 'blue' })).and.not.be
|
||||||
|
.empty
|
||||||
})
|
})
|
||||||
|
|
||||||
it("when the logo is overridden, it ignores the service's logo color, position, and width", function () {
|
it("when the logo is overridden, it ignores the service's logo color, position, and width", function () {
|
||||||
@@ -210,25 +192,15 @@ describe('coalesceBadge', function () {
|
|||||||
).to.equal(getShieldsIcon({ name: 'npm' })).and.not.be.empty
|
).to.equal(getShieldsIcon({ name: 'npm' })).and.not.be.empty
|
||||||
})
|
})
|
||||||
|
|
||||||
it("overrides the service monochome logo's color", function () {
|
it("overrides the service logo's color", function () {
|
||||||
expect(
|
|
||||||
coalesceBadge(
|
|
||||||
{ logoColor: 'blue' },
|
|
||||||
{ namedLogo: 'dependabot', logoColor: 'red' },
|
|
||||||
{}
|
|
||||||
).logo
|
|
||||||
).to.equal(getShieldsIcon({ name: 'dependabot', color: 'blue' })).and.not
|
|
||||||
.be.empty
|
|
||||||
})
|
|
||||||
|
|
||||||
it("overrides the service multicolored logo's color", function () {
|
|
||||||
expect(
|
expect(
|
||||||
coalesceBadge(
|
coalesceBadge(
|
||||||
{ logoColor: 'blue' },
|
{ logoColor: 'blue' },
|
||||||
{ namedLogo: 'npm', logoColor: 'red' },
|
{ namedLogo: 'npm', logoColor: 'red' },
|
||||||
{}
|
{}
|
||||||
).logo
|
).logo
|
||||||
).to.equal(getSimpleIcon({ name: 'npm', color: 'blue' })).and.not.be.empty
|
).to.equal(getShieldsIcon({ name: 'npm', color: 'blue' })).and.not.be
|
||||||
|
.empty
|
||||||
})
|
})
|
||||||
|
|
||||||
// https://github.com/badges/shields/issues/2998
|
// https://github.com/badges/shields/issues/2998
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ class ShieldsRuntimeError extends Error {
|
|||||||
if (props.underlyingError) {
|
if (props.underlyingError) {
|
||||||
this.stack = props.underlyingError.stack
|
this.stack = props.underlyingError.stack
|
||||||
}
|
}
|
||||||
this.cacheSeconds = props.cacheSeconds
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,9 +206,6 @@ class Deprecated extends ShieldsRuntimeError {
|
|||||||
* @property {string} prettyMessage User-facing error message to override the
|
* @property {string} prettyMessage User-facing error message to override the
|
||||||
* value of `defaultPrettyMessage()`. This is the text that will appear on the
|
* value of `defaultPrettyMessage()`. This is the text that will appear on the
|
||||||
* badge when we catch and render the exception (Optional)
|
* badge when we catch and render the exception (Optional)
|
||||||
* @property {number} cacheSeconds Length of time to cache this error response
|
|
||||||
* for. Defaults to the cacheLength of the service class throwing the error
|
|
||||||
* (Optional)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
|||||||
@@ -129,7 +129,6 @@ function transformExample(inExample, index, ServiceClass) {
|
|||||||
ServiceClass
|
ServiceClass
|
||||||
)
|
)
|
||||||
|
|
||||||
const category = categories.find(c => c.id === ServiceClass.category)
|
|
||||||
return {
|
return {
|
||||||
title,
|
title,
|
||||||
example: {
|
example: {
|
||||||
@@ -147,7 +146,9 @@ function transformExample(inExample, index, ServiceClass) {
|
|||||||
style: style === 'flat' ? undefined : style,
|
style: style === 'flat' ? undefined : style,
|
||||||
namedLogo,
|
namedLogo,
|
||||||
},
|
},
|
||||||
keywords: category ? keywords.concat(category.keywords) : keywords,
|
keywords: keywords.concat(
|
||||||
|
categories.find(c => c.id === ServiceClass.category).keywords
|
||||||
|
),
|
||||||
documentation: documentation ? { __html: documentation } : undefined,
|
documentation: documentation ? { __html: documentation } : undefined,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
|
|
||||||
const userAgent = getUserAgent()
|
const userAgent = getUserAgent()
|
||||||
|
|
||||||
async function sendRequest(gotWrapper, url, options = {}, systemErrors = {}) {
|
async function sendRequest(gotWrapper, url, options) {
|
||||||
const gotOptions = Object.assign({}, options)
|
const gotOptions = Object.assign({}, options)
|
||||||
gotOptions.throwHttpErrors = false
|
gotOptions.throwHttpErrors = false
|
||||||
gotOptions.retry = { limit: 0 }
|
gotOptions.retry = { limit: 0 }
|
||||||
@@ -22,12 +22,6 @@ async function sendRequest(gotWrapper, url, options = {}, systemErrors = {}) {
|
|||||||
underlyingError: new Error('Maximum response size exceeded'),
|
underlyingError: new Error('Maximum response size exceeded'),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (err.code in systemErrors) {
|
|
||||||
throw new Inaccessible({
|
|
||||||
...systemErrors[err.code],
|
|
||||||
underlyingError: err,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
throw new Inaccessible({ underlyingError: err })
|
throw new Inaccessible({ underlyingError: err })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,36 +45,6 @@ describe('got wrapper', function () {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should throw a custom error if provided', async function () {
|
|
||||||
const sendRequest = _fetchFactory(1024)
|
|
||||||
return (
|
|
||||||
expect(
|
|
||||||
sendRequest(
|
|
||||||
'https://www.google.com/foo/bar',
|
|
||||||
{ timeout: { request: 1 } },
|
|
||||||
{
|
|
||||||
ETIMEDOUT: {
|
|
||||||
prettyMessage: 'Oh no! A terrible thing has happened',
|
|
||||||
cacheSeconds: 10,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.to.be.rejectedWith(
|
|
||||||
Inaccessible,
|
|
||||||
"Inaccessible: Timeout awaiting 'request' for 1ms"
|
|
||||||
)
|
|
||||||
// eslint-disable-next-line promise/prefer-await-to-then
|
|
||||||
.then(error => {
|
|
||||||
expect(error).to.have.property(
|
|
||||||
'prettyMessage',
|
|
||||||
'Oh no! A terrible thing has happened'
|
|
||||||
)
|
|
||||||
expect(error).to.have.property('cacheSeconds', 10)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should pass a custom user agent header', async function () {
|
it('should pass a custom user agent header', async function () {
|
||||||
nock('https://www.google.com', {
|
nock('https://www.google.com', {
|
||||||
reqheaders: {
|
reqheaders: {
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ function handleRequest(cacheHeaderConfig, handlerOptions) {
|
|||||||
*/
|
*/
|
||||||
if (match[0] === '/endpoint' && Object.keys(queryParams).length === 0) {
|
if (match[0] === '/endpoint' && Object.keys(queryParams).length === 0) {
|
||||||
ask.res.statusCode = 301
|
ask.res.statusCode = 301
|
||||||
ask.res.setHeader('Location', '/badges/endpoint-badge')
|
ask.res.setHeader('Location', '/endpoint/')
|
||||||
ask.res.end()
|
ask.res.end()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -73,9 +73,11 @@ function handleRequest(cacheHeaderConfig, handlerOptions) {
|
|||||||
// `defaultCacheLengthSeconds` can be overridden by
|
// `defaultCacheLengthSeconds` can be overridden by
|
||||||
// `serviceDefaultCacheLengthSeconds` (either by category or on a badge-
|
// `serviceDefaultCacheLengthSeconds` (either by category or on a badge-
|
||||||
// by-badge basis). Then in turn that can be overridden by
|
// by-badge basis). Then in turn that can be overridden by
|
||||||
// `serviceOverrideCacheLengthSeconds`.
|
// `serviceOverrideCacheLengthSeconds` (which we expect to be used only in
|
||||||
// Then the `cacheSeconds` query param can also override both of those
|
// the dynamic badge) but only if `serviceOverrideCacheLengthSeconds` is
|
||||||
// but only if `cacheSeconds` is longer.
|
// longer than `serviceDefaultCacheLengthSeconds` and then the `cacheSeconds`
|
||||||
|
// query param can also override both of those but again only if `cacheSeconds`
|
||||||
|
// is longer.
|
||||||
//
|
//
|
||||||
// When the legacy services have been rewritten, all the code in here
|
// When the legacy services have been rewritten, all the code in here
|
||||||
// will go away, which should achieve this goal in a simpler way.
|
// will go away, which should achieve this goal in a simpler way.
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ describe('The request handler', function () {
|
|||||||
expect(headers['cache-control']).to.equal('max-age=900, s-maxage=900')
|
expect(headers['cache-control']).to.equal('max-age=900, s-maxage=900')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should allow serviceData to override the default cache headers with longer value', async function () {
|
it('should let live service data override the default cache headers with longer value', async function () {
|
||||||
camp.route(
|
camp.route(
|
||||||
/^\/testing\/([^/]+)\.(svg|png|gif|jpg|json)$/,
|
/^\/testing\/([^/]+)\.(svg|png|gif|jpg|json)$/,
|
||||||
handleRequest(
|
handleRequest(
|
||||||
@@ -168,7 +168,7 @@ describe('The request handler', function () {
|
|||||||
expect(headers['cache-control']).to.equal('max-age=400, s-maxage=400')
|
expect(headers['cache-control']).to.equal('max-age=400, s-maxage=400')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should allow serviceData to override the default cache headers with shorter value', async function () {
|
it('should not let live service data override the default cache headers with shorter value', async function () {
|
||||||
camp.route(
|
camp.route(
|
||||||
/^\/testing\/([^/]+)\.(svg|png|gif|jpg|json)$/,
|
/^\/testing\/([^/]+)\.(svg|png|gif|jpg|json)$/,
|
||||||
handleRequest(
|
handleRequest(
|
||||||
@@ -185,7 +185,7 @@ describe('The request handler', function () {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const { headers } = await got(`${baseUrl}/testing/123.json`)
|
const { headers } = await got(`${baseUrl}/testing/123.json`)
|
||||||
expect(headers['cache-control']).to.equal('max-age=200, s-maxage=200')
|
expect(headers['cache-control']).to.equal('max-age=300, s-maxage=300')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should set the expires header to current time + cacheSeconds', async function () {
|
it('should set the expires header to current time + cacheSeconds', async function () {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import BaseJsonService from '../base-json.js'
|
import BaseJsonService from '../base-json.js'
|
||||||
|
|
||||||
class BadBaseService {}
|
class BadBaseService {}
|
||||||
class GoodMixedService extends BaseJsonService {
|
class GoodService extends BaseJsonService {
|
||||||
static category = 'build'
|
static category = 'build'
|
||||||
static route = { base: 'it/is', pattern: 'good' }
|
static route = { base: 'it/is', pattern: 'good' }
|
||||||
}
|
}
|
||||||
class BadMixedService extends BadBaseService {}
|
class BadService extends BadBaseService {}
|
||||||
|
|
||||||
export default [GoodMixedService, BadMixedService]
|
export default [GoodService, BadService]
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
class BadNoBaseService {}
|
class BadService {}
|
||||||
|
|
||||||
export default BadNoBaseService
|
export default BadService
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
class BadBaseService {}
|
class BadBaseService {}
|
||||||
class BadChildService extends BadBaseService {}
|
class BadService extends BadBaseService {}
|
||||||
|
|
||||||
export default BadChildService
|
export default BadService
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import BaseJsonService from '../base-json.js'
|
import BaseJsonService from '../base-json.js'
|
||||||
|
|
||||||
class GoodServiceArrayOne extends BaseJsonService {
|
class GoodServiceOne extends BaseJsonService {
|
||||||
static category = 'build'
|
static category = 'build'
|
||||||
static route = { base: 'good', pattern: 'one' }
|
static route = { base: 'good', pattern: 'one' }
|
||||||
}
|
}
|
||||||
class GoodServiceArrayTwo extends BaseJsonService {
|
class GoodServiceTwo extends BaseJsonService {
|
||||||
static category = 'build'
|
static category = 'build'
|
||||||
static route = { base: 'good', pattern: 'two' }
|
static route = { base: 'good', pattern: 'two' }
|
||||||
}
|
}
|
||||||
|
|
||||||
export default [GoodServiceArrayOne, GoodServiceArrayTwo]
|
export default [GoodServiceOne, GoodServiceTwo]
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import BaseJsonService from '../base-json.js'
|
import BaseJsonService from '../base-json.js'
|
||||||
|
|
||||||
class GoodServiceObjectOne extends BaseJsonService {
|
class GoodServiceOne extends BaseJsonService {
|
||||||
static category = 'build'
|
static category = 'build'
|
||||||
static route = { base: 'good', pattern: 'one' }
|
static route = { base: 'good', pattern: 'one' }
|
||||||
}
|
}
|
||||||
class GoodServiceObjectTwo extends BaseJsonService {
|
class GoodServiceTwo extends BaseJsonService {
|
||||||
static category = 'build'
|
static category = 'build'
|
||||||
static route = { base: 'good', pattern: 'two' }
|
static route = { base: 'good', pattern: 'two' }
|
||||||
}
|
}
|
||||||
|
|
||||||
export { GoodServiceObjectOne, GoodServiceObjectTwo }
|
export { GoodServiceOne, GoodServiceTwo }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { fileURLToPath } from 'url'
|
import { fileURLToPath } from 'url'
|
||||||
import { globSync } from 'glob'
|
import glob from 'glob'
|
||||||
import countBy from 'lodash.countby'
|
import countBy from 'lodash.countby'
|
||||||
import categories from '../../services/categories.js'
|
import categories from '../../services/categories.js'
|
||||||
import BaseService from './base.js'
|
import BaseService from './base.js'
|
||||||
@@ -13,13 +13,6 @@ const serviceDir = path.join(
|
|||||||
'services'
|
'services'
|
||||||
)
|
)
|
||||||
|
|
||||||
function toUnixPath(path) {
|
|
||||||
// glob does not allow \ as a path separator
|
|
||||||
// see https://github.com/isaacs/node-glob/blob/main/changelog.md#80
|
|
||||||
// so we need to convert to use / for use with glob
|
|
||||||
return path.replace(/\\/g, '/')
|
|
||||||
}
|
|
||||||
|
|
||||||
class InvalidService extends Error {
|
class InvalidService extends Error {
|
||||||
constructor(message) {
|
constructor(message) {
|
||||||
super(message)
|
super(message)
|
||||||
@@ -27,25 +20,9 @@ class InvalidService extends Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getServicePaths(pattern) {
|
|
||||||
return globSync(toUnixPath(path.join(serviceDir, '**', pattern))).sort()
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertNamesUnique(names, { message }) {
|
|
||||||
const duplicates = {}
|
|
||||||
Object.entries(countBy(names))
|
|
||||||
.filter(([name, count]) => count > 1)
|
|
||||||
.forEach(([name, count]) => {
|
|
||||||
duplicates[name] = count
|
|
||||||
})
|
|
||||||
if (Object.keys(duplicates).length) {
|
|
||||||
throw new Error(`${message}: ${JSON.stringify(duplicates, undefined, 2)}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadServiceClasses(servicePaths) {
|
async function loadServiceClasses(servicePaths) {
|
||||||
if (!servicePaths) {
|
if (!servicePaths) {
|
||||||
servicePaths = getServicePaths('*.service.js')
|
servicePaths = glob.sync(path.join(serviceDir, '**', '*.service.js'))
|
||||||
}
|
}
|
||||||
|
|
||||||
const serviceClasses = []
|
const serviceClasses = []
|
||||||
@@ -76,14 +53,29 @@ async function loadServiceClasses(servicePaths) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return serviceClasses
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertNamesUnique(names, { message }) {
|
||||||
|
const duplicates = {}
|
||||||
|
Object.entries(countBy(names))
|
||||||
|
.filter(([name, count]) => count > 1)
|
||||||
|
.forEach(([name, count]) => {
|
||||||
|
duplicates[name] = count
|
||||||
|
})
|
||||||
|
if (Object.keys(duplicates).length) {
|
||||||
|
throw new Error(`${message}: ${JSON.stringify(duplicates, undefined, 2)}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkNames() {
|
||||||
|
const services = await loadServiceClasses()
|
||||||
assertNamesUnique(
|
assertNamesUnique(
|
||||||
serviceClasses.map(({ name }) => name),
|
services.map(({ name }) => name),
|
||||||
{
|
{
|
||||||
message: 'Duplicate service names found',
|
message: 'Duplicate service names found',
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
return serviceClasses
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function collectDefinitions() {
|
async function collectDefinitions() {
|
||||||
@@ -101,16 +93,16 @@ async function collectDefinitions() {
|
|||||||
|
|
||||||
async function loadTesters() {
|
async function loadTesters() {
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
getServicePaths('*.tester.js').map(
|
glob
|
||||||
async path => await import(`file://${path}`)
|
.sync(path.join(serviceDir, '**', '*.tester.js'))
|
||||||
)
|
.map(async path => await import(`file://${path}`))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
InvalidService,
|
InvalidService,
|
||||||
loadServiceClasses,
|
loadServiceClasses,
|
||||||
getServicePaths,
|
checkNames,
|
||||||
collectDefinitions,
|
collectDefinitions,
|
||||||
loadTesters,
|
loadTesters,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,7 @@ import path from 'path'
|
|||||||
import { fileURLToPath } from 'url'
|
import { fileURLToPath } from 'url'
|
||||||
import chai from 'chai'
|
import chai from 'chai'
|
||||||
import chaiAsPromised from 'chai-as-promised'
|
import chaiAsPromised from 'chai-as-promised'
|
||||||
import {
|
import { loadServiceClasses, InvalidService } from './loader.js'
|
||||||
loadServiceClasses,
|
|
||||||
getServicePaths,
|
|
||||||
InvalidService,
|
|
||||||
} from './loader.js'
|
|
||||||
chai.use(chaiAsPromised)
|
chai.use(chaiAsPromised)
|
||||||
|
|
||||||
const { expect } = chai
|
const { expect } = chai
|
||||||
@@ -69,15 +65,3 @@ describe('loadServiceClasses function', function () {
|
|||||||
).to.eventually.have.length(5)
|
).to.eventually.have.length(5)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('getServicePaths', function () {
|
|
||||||
// these tests just make sure we discover a
|
|
||||||
// plausibly large number of .service and .tester files
|
|
||||||
it('finds a non-zero number of services in the project', function () {
|
|
||||||
expect(getServicePaths('*.service.js')).to.have.length.above(400)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('finds a non-zero number of testers in the project', function () {
|
|
||||||
expect(getServicePaths('*.tester.js')).to.have.length.above(400)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|||||||
@@ -1,335 +0,0 @@
|
|||||||
const baseUrl = process.env.BASE_URL
|
|
||||||
const globalParamRefs = [
|
|
||||||
{ $ref: '#/components/parameters/style' },
|
|
||||||
{ $ref: '#/components/parameters/logo' },
|
|
||||||
{ $ref: '#/components/parameters/logoColor' },
|
|
||||||
{ $ref: '#/components/parameters/label' },
|
|
||||||
{ $ref: '#/components/parameters/labelColor' },
|
|
||||||
{ $ref: '#/components/parameters/color' },
|
|
||||||
{ $ref: '#/components/parameters/cacheSeconds' },
|
|
||||||
{ $ref: '#/components/parameters/link' },
|
|
||||||
]
|
|
||||||
|
|
||||||
function getCodeSamples(altText) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
lang: 'URL',
|
|
||||||
label: 'URL',
|
|
||||||
source: '$url',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
lang: 'Markdown',
|
|
||||||
label: 'Markdown',
|
|
||||||
source: ``,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
lang: 'reStructuredText',
|
|
||||||
label: 'rSt',
|
|
||||||
source: `.. image:: $url\n: alt: ${altText}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
lang: 'AsciiDoc',
|
|
||||||
label: 'AsciiDoc',
|
|
||||||
source: `image:$url[${altText}]`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
lang: 'HTML',
|
|
||||||
label: 'HTML',
|
|
||||||
source: `<img alt="${altText}" src="$url">`,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
function pattern2openapi(pattern) {
|
|
||||||
return pattern
|
|
||||||
.replace(/:([A-Za-z0-9_\-.]+)(?=[/]?)/g, (matches, grp1) => `{${grp1}}`)
|
|
||||||
.replace(/\([^)]*\)/g, '')
|
|
||||||
.replace(/\+$/, '')
|
|
||||||
}
|
|
||||||
|
|
||||||
function getEnum(pattern, paramName) {
|
|
||||||
const re = new RegExp(`${paramName}\\(([A-Za-z0-9_\\-|]+)\\)`)
|
|
||||||
const match = pattern.match(re)
|
|
||||||
if (match === null) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
if (!match[1].includes('|')) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
return match[1].split('|')
|
|
||||||
}
|
|
||||||
|
|
||||||
function param2openapi(pattern, paramName, exampleValue, paramType) {
|
|
||||||
const outParam = {}
|
|
||||||
outParam.name = paramName
|
|
||||||
// We don't have description if we are building the OpenAPI spec from examples[]
|
|
||||||
outParam.in = paramType
|
|
||||||
if (paramType === 'path') {
|
|
||||||
outParam.required = true
|
|
||||||
} else {
|
|
||||||
/* Occasionally we do have required query params, but we can't
|
|
||||||
detect this if we are building the OpenAPI spec from examples[]
|
|
||||||
so just assume all query params are optional */
|
|
||||||
outParam.required = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exampleValue === null && paramType === 'query') {
|
|
||||||
outParam.schema = { type: 'boolean' }
|
|
||||||
outParam.allowEmptyValue = true
|
|
||||||
} else {
|
|
||||||
outParam.schema = { type: 'string' }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (paramType === 'path') {
|
|
||||||
outParam.schema.enum = getEnum(pattern, paramName)
|
|
||||||
}
|
|
||||||
|
|
||||||
outParam.example = exampleValue
|
|
||||||
return outParam
|
|
||||||
}
|
|
||||||
|
|
||||||
function getVariants(pattern) {
|
|
||||||
/*
|
|
||||||
given a URL pattern (which may include '/one/or/:more?/:optional/:parameters*')
|
|
||||||
return an array of all possible permutations:
|
|
||||||
[
|
|
||||||
'/one/or/:more/:optional/:parameters',
|
|
||||||
'/one/or/:optional/:parameters',
|
|
||||||
'/one/or/:more/:optional',
|
|
||||||
'/one/or/:optional',
|
|
||||||
]
|
|
||||||
*/
|
|
||||||
const patterns = [pattern.split('/')]
|
|
||||||
while (patterns.flat().find(p => p.endsWith('?') || p.endsWith('*'))) {
|
|
||||||
for (let i = 0; i < patterns.length; i++) {
|
|
||||||
const pattern = patterns[i]
|
|
||||||
for (let j = 0; j < pattern.length; j++) {
|
|
||||||
const path = pattern[j]
|
|
||||||
if (path.endsWith('?') || path.endsWith('*')) {
|
|
||||||
pattern[j] = path.slice(0, -1)
|
|
||||||
patterns.push(patterns[i].filter(p => p !== pattern[j]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (let i = 0; i < patterns.length; i++) {
|
|
||||||
patterns[i] = patterns[i].join('/')
|
|
||||||
}
|
|
||||||
return patterns
|
|
||||||
}
|
|
||||||
|
|
||||||
function examples2openapi(examples) {
|
|
||||||
const paths = {}
|
|
||||||
for (const example of examples) {
|
|
||||||
const patterns = getVariants(example.example.pattern)
|
|
||||||
|
|
||||||
for (const pattern of patterns) {
|
|
||||||
const openApiPattern = pattern2openapi(pattern)
|
|
||||||
if (
|
|
||||||
openApiPattern.includes('*') ||
|
|
||||||
openApiPattern.includes('?') ||
|
|
||||||
openApiPattern.includes('+') ||
|
|
||||||
openApiPattern.includes('(')
|
|
||||||
) {
|
|
||||||
throw new Error(`unexpected characters in pattern '${openApiPattern}'`)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
There's several things going on in this block:
|
|
||||||
1. Filter out any examples for params that don't appear
|
|
||||||
in this variant of the route
|
|
||||||
2. Make sure we add params to the array
|
|
||||||
in the same order they appear in the route
|
|
||||||
3. If there are any params we don't have an example value for,
|
|
||||||
make sure they still appear in the pathParams array with
|
|
||||||
exampleValue == undefined anyway
|
|
||||||
*/
|
|
||||||
const pathParams = []
|
|
||||||
for (const param of openApiPattern
|
|
||||||
.split('/')
|
|
||||||
.filter(p => p.startsWith('{') && p.endsWith('}'))) {
|
|
||||||
const paramName = param.slice(1, -1)
|
|
||||||
const exampleValue = example.example.namedParams[paramName]
|
|
||||||
pathParams.push(param2openapi(pattern, paramName, exampleValue, 'path'))
|
|
||||||
}
|
|
||||||
|
|
||||||
const queryParams = example.example.queryParams || {}
|
|
||||||
|
|
||||||
const parameters = [
|
|
||||||
...pathParams,
|
|
||||||
...Object.entries(queryParams).map(([paramName, exampleValue]) =>
|
|
||||||
param2openapi(pattern, paramName, exampleValue, 'query')
|
|
||||||
),
|
|
||||||
...globalParamRefs,
|
|
||||||
]
|
|
||||||
paths[openApiPattern] = {
|
|
||||||
get: {
|
|
||||||
summary: example.title,
|
|
||||||
description: example?.documentation?.__html
|
|
||||||
.replace(/<br>/g, '<br />') // react does not like <br>
|
|
||||||
.replace(/{/g, '{')
|
|
||||||
.replace(/}/g, '}')
|
|
||||||
.replace(/<style>(.|\n)*?<\/style>/, ''), // workaround for w3c-validation TODO: remove later
|
|
||||||
parameters,
|
|
||||||
'x-code-samples': getCodeSamples(example.title),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return paths
|
|
||||||
}
|
|
||||||
|
|
||||||
function addGlobalProperties(endpoints) {
|
|
||||||
const paths = {}
|
|
||||||
for (const key of Object.keys(endpoints)) {
|
|
||||||
paths[key] = endpoints[key]
|
|
||||||
paths[key].get.parameters = [
|
|
||||||
...paths[key].get.parameters,
|
|
||||||
...globalParamRefs,
|
|
||||||
]
|
|
||||||
paths[key].get['x-code-samples'] = getCodeSamples(paths[key].get.summary)
|
|
||||||
}
|
|
||||||
return paths
|
|
||||||
}
|
|
||||||
|
|
||||||
function services2openapi(services) {
|
|
||||||
const paths = {}
|
|
||||||
for (const service of services) {
|
|
||||||
if (service.openApi) {
|
|
||||||
// if the service declares its own OpenAPI definition, use that...
|
|
||||||
for (const [key, value] of Object.entries(
|
|
||||||
addGlobalProperties(service.openApi)
|
|
||||||
)) {
|
|
||||||
if (key in paths) {
|
|
||||||
throw new Error(`Conflicting route: ${key}`)
|
|
||||||
}
|
|
||||||
paths[key] = value
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// ...otherwise do our best to build one from examples[]
|
|
||||||
for (const [key, value] of Object.entries(
|
|
||||||
examples2openapi(service.examples)
|
|
||||||
)) {
|
|
||||||
// allow conflicting routes for legacy examples
|
|
||||||
paths[key] = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return paths
|
|
||||||
}
|
|
||||||
|
|
||||||
function category2openapi(category, services) {
|
|
||||||
const spec = {
|
|
||||||
openapi: '3.0.0',
|
|
||||||
info: {
|
|
||||||
version: '1.0.0',
|
|
||||||
title: category.name,
|
|
||||||
license: {
|
|
||||||
name: 'CC0',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
servers: baseUrl ? [{ url: baseUrl }] : undefined,
|
|
||||||
components: {
|
|
||||||
parameters: {
|
|
||||||
style: {
|
|
||||||
name: 'style',
|
|
||||||
in: 'query',
|
|
||||||
required: false,
|
|
||||||
description:
|
|
||||||
'One of: flat (default), flat-square, plastic, for-the-badge, social',
|
|
||||||
schema: {
|
|
||||||
type: 'string',
|
|
||||||
},
|
|
||||||
example: 'flat',
|
|
||||||
},
|
|
||||||
logo: {
|
|
||||||
name: 'logo',
|
|
||||||
in: 'query',
|
|
||||||
required: false,
|
|
||||||
description:
|
|
||||||
'One of the named logos (bitcoin, dependabot, gitlab, npm, paypal, serverfault, stackexchange, superuser, telegram, travis) or simple-icons. All simple-icons are referenced using icon slugs. You can click the icon title on <a href="https://simpleicons.org/" rel="noopener noreferrer" target="_blank">simple-icons</a> to copy the slug or they can be found in the <a href="https://github.com/simple-icons/simple-icons/blob/master/slugs.md">slugs.md file</a> in the simple-icons repository.',
|
|
||||||
schema: {
|
|
||||||
type: 'string',
|
|
||||||
},
|
|
||||||
example: 'appveyor',
|
|
||||||
},
|
|
||||||
logoColor: {
|
|
||||||
name: 'logoColor',
|
|
||||||
in: 'query',
|
|
||||||
required: false,
|
|
||||||
description:
|
|
||||||
'The color of the logo (hex, rgb, rgba, hsl, hsla and css named colors supported). Supported for named logos and Shields logos but not for custom logos. For multicolor Shields logos, the corresponding named logo will be used and colored.',
|
|
||||||
schema: {
|
|
||||||
type: 'string',
|
|
||||||
},
|
|
||||||
example: 'violet',
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
name: 'label',
|
|
||||||
in: 'query',
|
|
||||||
required: false,
|
|
||||||
description:
|
|
||||||
'Override the default left-hand-side text (<a href="https://developer.mozilla.org/en-US/docs/Glossary/percent-encoding">URL-Encoding</a> needed for spaces or special characters!)',
|
|
||||||
schema: {
|
|
||||||
type: 'string',
|
|
||||||
},
|
|
||||||
example: 'healthiness',
|
|
||||||
},
|
|
||||||
labelColor: {
|
|
||||||
name: 'labelColor',
|
|
||||||
in: 'query',
|
|
||||||
required: false,
|
|
||||||
description:
|
|
||||||
'Background color of the left part (hex, rgb, rgba, hsl, hsla and css named colors supported).',
|
|
||||||
schema: {
|
|
||||||
type: 'string',
|
|
||||||
},
|
|
||||||
example: 'abcdef',
|
|
||||||
},
|
|
||||||
color: {
|
|
||||||
name: 'color',
|
|
||||||
in: 'query',
|
|
||||||
required: false,
|
|
||||||
description:
|
|
||||||
'Background color of the right part (hex, rgb, rgba, hsl, hsla and css named colors supported).',
|
|
||||||
schema: {
|
|
||||||
type: 'string',
|
|
||||||
},
|
|
||||||
example: 'fedcba',
|
|
||||||
},
|
|
||||||
cacheSeconds: {
|
|
||||||
name: 'cacheSeconds',
|
|
||||||
in: 'query',
|
|
||||||
required: false,
|
|
||||||
description:
|
|
||||||
'HTTP cache lifetime (rules are applied to infer a default value on a per-badge basis, any values specified below the default will be ignored).',
|
|
||||||
schema: {
|
|
||||||
type: 'string',
|
|
||||||
},
|
|
||||||
example: '3600',
|
|
||||||
},
|
|
||||||
link: {
|
|
||||||
name: 'link',
|
|
||||||
in: 'query',
|
|
||||||
required: false,
|
|
||||||
description:
|
|
||||||
'Specify what clicking on the left/right of a badge should do. Note that this only works when integrating your badge in an `<object>` HTML tag, but not an `<img>` tag or a markup language.',
|
|
||||||
style: 'form',
|
|
||||||
explode: true,
|
|
||||||
schema: {
|
|
||||||
type: 'array',
|
|
||||||
maxItems: 2,
|
|
||||||
items: {
|
|
||||||
type: 'string',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
paths: services2openapi(services),
|
|
||||||
}
|
|
||||||
|
|
||||||
return spec
|
|
||||||
}
|
|
||||||
|
|
||||||
export { category2openapi }
|
|
||||||
@@ -1,378 +0,0 @@
|
|||||||
import chai from 'chai'
|
|
||||||
import { category2openapi } from './openapi.js'
|
|
||||||
import BaseJsonService from './base-json.js'
|
|
||||||
const { expect } = chai
|
|
||||||
|
|
||||||
class OpenApiService extends BaseJsonService {
|
|
||||||
static category = 'build'
|
|
||||||
static route = { base: 'openapi/service', pattern: ':packageName/:distTag*' }
|
|
||||||
|
|
||||||
// this service defines its own API Paths Object
|
|
||||||
static openApi = {
|
|
||||||
'/openapi/service/{packageName}': {
|
|
||||||
get: {
|
|
||||||
summary: 'OpenApiService Summary',
|
|
||||||
description: 'OpenApiService Description',
|
|
||||||
parameters: [
|
|
||||||
{
|
|
||||||
name: 'packageName',
|
|
||||||
description: 'packageName description',
|
|
||||||
in: 'path',
|
|
||||||
required: true,
|
|
||||||
schema: { type: 'string' },
|
|
||||||
example: 'badge-maker',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'/openapi/service/{packageName}/{distTag}': {
|
|
||||||
get: {
|
|
||||||
summary: 'OpenApiService Summary (with Tag)',
|
|
||||||
description: 'OpenApiService Description (with Tag)',
|
|
||||||
parameters: [
|
|
||||||
{
|
|
||||||
name: 'packageName',
|
|
||||||
description: 'packageName description',
|
|
||||||
in: 'path',
|
|
||||||
required: true,
|
|
||||||
schema: { type: 'string' },
|
|
||||||
example: 'badge-maker',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'distTag',
|
|
||||||
description: 'distTag description',
|
|
||||||
in: 'path',
|
|
||||||
required: true,
|
|
||||||
schema: { type: 'string' },
|
|
||||||
example: 'latest',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class LegacyService extends BaseJsonService {
|
|
||||||
static category = 'build'
|
|
||||||
static route = { base: 'legacy/service', pattern: ':packageName/:distTag*' }
|
|
||||||
|
|
||||||
// this service defines an Examples Array
|
|
||||||
static examples = [
|
|
||||||
{
|
|
||||||
title: 'LegacyService Title',
|
|
||||||
namedParams: { packageName: 'badge-maker' },
|
|
||||||
staticPreview: { label: 'build', message: 'passing' },
|
|
||||||
documentation: 'LegacyService Description',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'LegacyService Title (with Tag)',
|
|
||||||
namedParams: { packageName: 'badge-maker', distTag: 'latest' },
|
|
||||||
staticPreview: { label: 'build', message: 'passing' },
|
|
||||||
documentation: 'LegacyService Description (with Tag)',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
const expected = {
|
|
||||||
openapi: '3.0.0',
|
|
||||||
info: { version: '1.0.0', title: 'build', license: { name: 'CC0' } },
|
|
||||||
components: {
|
|
||||||
parameters: {
|
|
||||||
style: {
|
|
||||||
name: 'style',
|
|
||||||
in: 'query',
|
|
||||||
required: false,
|
|
||||||
description:
|
|
||||||
'One of: flat (default), flat-square, plastic, for-the-badge, social',
|
|
||||||
schema: { type: 'string' },
|
|
||||||
example: 'flat',
|
|
||||||
},
|
|
||||||
logo: {
|
|
||||||
name: 'logo',
|
|
||||||
in: 'query',
|
|
||||||
required: false,
|
|
||||||
description:
|
|
||||||
'One of the named logos (bitcoin, dependabot, gitlab, npm, paypal, serverfault, stackexchange, superuser, telegram, travis) or simple-icons. All simple-icons are referenced using icon slugs. You can click the icon title on <a href="https://simpleicons.org/" rel="noopener noreferrer" target="_blank">simple-icons</a> to copy the slug or they can be found in the <a href="https://github.com/simple-icons/simple-icons/blob/master/slugs.md">slugs.md file</a> in the simple-icons repository.',
|
|
||||||
schema: { type: 'string' },
|
|
||||||
example: 'appveyor',
|
|
||||||
},
|
|
||||||
logoColor: {
|
|
||||||
name: 'logoColor',
|
|
||||||
in: 'query',
|
|
||||||
required: false,
|
|
||||||
description:
|
|
||||||
'The color of the logo (hex, rgb, rgba, hsl, hsla and css named colors supported). Supported for named logos and Shields logos but not for custom logos. For multicolor Shields logos, the corresponding named logo will be used and colored.',
|
|
||||||
schema: { type: 'string' },
|
|
||||||
example: 'violet',
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
name: 'label',
|
|
||||||
in: 'query',
|
|
||||||
required: false,
|
|
||||||
description:
|
|
||||||
'Override the default left-hand-side text (<a href="https://developer.mozilla.org/en-US/docs/Glossary/percent-encoding">URL-Encoding</a> needed for spaces or special characters!)',
|
|
||||||
schema: { type: 'string' },
|
|
||||||
example: 'healthiness',
|
|
||||||
},
|
|
||||||
labelColor: {
|
|
||||||
name: 'labelColor',
|
|
||||||
in: 'query',
|
|
||||||
required: false,
|
|
||||||
description:
|
|
||||||
'Background color of the left part (hex, rgb, rgba, hsl, hsla and css named colors supported).',
|
|
||||||
schema: { type: 'string' },
|
|
||||||
example: 'abcdef',
|
|
||||||
},
|
|
||||||
color: {
|
|
||||||
name: 'color',
|
|
||||||
in: 'query',
|
|
||||||
required: false,
|
|
||||||
description:
|
|
||||||
'Background color of the right part (hex, rgb, rgba, hsl, hsla and css named colors supported).',
|
|
||||||
schema: { type: 'string' },
|
|
||||||
example: 'fedcba',
|
|
||||||
},
|
|
||||||
cacheSeconds: {
|
|
||||||
name: 'cacheSeconds',
|
|
||||||
in: 'query',
|
|
||||||
required: false,
|
|
||||||
description:
|
|
||||||
'HTTP cache lifetime (rules are applied to infer a default value on a per-badge basis, any values specified below the default will be ignored).',
|
|
||||||
schema: { type: 'string' },
|
|
||||||
example: '3600',
|
|
||||||
},
|
|
||||||
link: {
|
|
||||||
name: 'link',
|
|
||||||
in: 'query',
|
|
||||||
required: false,
|
|
||||||
description:
|
|
||||||
'Specify what clicking on the left/right of a badge should do. Note that this only works when integrating your badge in an `<object>` HTML tag, but not an `<img>` tag or a markup language.',
|
|
||||||
style: 'form',
|
|
||||||
explode: true,
|
|
||||||
schema: { type: 'array', maxItems: 2, items: { type: 'string' } },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
paths: {
|
|
||||||
'/openapi/service/{packageName}': {
|
|
||||||
get: {
|
|
||||||
summary: 'OpenApiService Summary',
|
|
||||||
description: 'OpenApiService Description',
|
|
||||||
parameters: [
|
|
||||||
{
|
|
||||||
name: 'packageName',
|
|
||||||
description: 'packageName description',
|
|
||||||
in: 'path',
|
|
||||||
required: true,
|
|
||||||
schema: { type: 'string' },
|
|
||||||
example: 'badge-maker',
|
|
||||||
},
|
|
||||||
{ $ref: '#/components/parameters/style' },
|
|
||||||
{ $ref: '#/components/parameters/logo' },
|
|
||||||
{ $ref: '#/components/parameters/logoColor' },
|
|
||||||
{ $ref: '#/components/parameters/label' },
|
|
||||||
{ $ref: '#/components/parameters/labelColor' },
|
|
||||||
{ $ref: '#/components/parameters/color' },
|
|
||||||
{ $ref: '#/components/parameters/cacheSeconds' },
|
|
||||||
{ $ref: '#/components/parameters/link' },
|
|
||||||
],
|
|
||||||
'x-code-samples': [
|
|
||||||
{ lang: 'URL', label: 'URL', source: '$url' },
|
|
||||||
{
|
|
||||||
lang: 'Markdown',
|
|
||||||
label: 'Markdown',
|
|
||||||
source: '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
lang: 'reStructuredText',
|
|
||||||
label: 'rSt',
|
|
||||||
source: '.. image:: $url\n: alt: OpenApiService Summary',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
lang: 'AsciiDoc',
|
|
||||||
label: 'AsciiDoc',
|
|
||||||
source: 'image:$url[OpenApiService Summary]',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
lang: 'HTML',
|
|
||||||
label: 'HTML',
|
|
||||||
source: '<img alt="OpenApiService Summary" src="$url">',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'/openapi/service/{packageName}/{distTag}': {
|
|
||||||
get: {
|
|
||||||
summary: 'OpenApiService Summary (with Tag)',
|
|
||||||
description: 'OpenApiService Description (with Tag)',
|
|
||||||
parameters: [
|
|
||||||
{
|
|
||||||
name: 'packageName',
|
|
||||||
description: 'packageName description',
|
|
||||||
in: 'path',
|
|
||||||
required: true,
|
|
||||||
schema: { type: 'string' },
|
|
||||||
example: 'badge-maker',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'distTag',
|
|
||||||
description: 'distTag description',
|
|
||||||
in: 'path',
|
|
||||||
required: true,
|
|
||||||
schema: { type: 'string' },
|
|
||||||
example: 'latest',
|
|
||||||
},
|
|
||||||
{ $ref: '#/components/parameters/style' },
|
|
||||||
{ $ref: '#/components/parameters/logo' },
|
|
||||||
{ $ref: '#/components/parameters/logoColor' },
|
|
||||||
{ $ref: '#/components/parameters/label' },
|
|
||||||
{ $ref: '#/components/parameters/labelColor' },
|
|
||||||
{ $ref: '#/components/parameters/color' },
|
|
||||||
{ $ref: '#/components/parameters/cacheSeconds' },
|
|
||||||
{ $ref: '#/components/parameters/link' },
|
|
||||||
],
|
|
||||||
'x-code-samples': [
|
|
||||||
{ lang: 'URL', label: 'URL', source: '$url' },
|
|
||||||
{
|
|
||||||
lang: 'Markdown',
|
|
||||||
label: 'Markdown',
|
|
||||||
source: '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
lang: 'reStructuredText',
|
|
||||||
label: 'rSt',
|
|
||||||
source:
|
|
||||||
'.. image:: $url\n: alt: OpenApiService Summary (with Tag)',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
lang: 'AsciiDoc',
|
|
||||||
label: 'AsciiDoc',
|
|
||||||
source: 'image:$url[OpenApiService Summary (with Tag)]',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
lang: 'HTML',
|
|
||||||
label: 'HTML',
|
|
||||||
source: '<img alt="OpenApiService Summary (with Tag)" src="$url">',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'/legacy/service/{packageName}/{distTag}': {
|
|
||||||
get: {
|
|
||||||
summary: 'LegacyService Title (with Tag)',
|
|
||||||
description: 'LegacyService Description (with Tag)',
|
|
||||||
parameters: [
|
|
||||||
{
|
|
||||||
name: 'packageName',
|
|
||||||
in: 'path',
|
|
||||||
required: true,
|
|
||||||
schema: { type: 'string' },
|
|
||||||
example: 'badge-maker',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'distTag',
|
|
||||||
in: 'path',
|
|
||||||
required: true,
|
|
||||||
schema: { type: 'string' },
|
|
||||||
example: 'latest',
|
|
||||||
},
|
|
||||||
{ $ref: '#/components/parameters/style' },
|
|
||||||
{ $ref: '#/components/parameters/logo' },
|
|
||||||
{ $ref: '#/components/parameters/logoColor' },
|
|
||||||
{ $ref: '#/components/parameters/label' },
|
|
||||||
{ $ref: '#/components/parameters/labelColor' },
|
|
||||||
{ $ref: '#/components/parameters/color' },
|
|
||||||
{ $ref: '#/components/parameters/cacheSeconds' },
|
|
||||||
{ $ref: '#/components/parameters/link' },
|
|
||||||
],
|
|
||||||
'x-code-samples': [
|
|
||||||
{ lang: 'URL', label: 'URL', source: '$url' },
|
|
||||||
{
|
|
||||||
lang: 'Markdown',
|
|
||||||
label: 'Markdown',
|
|
||||||
source: '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
lang: 'reStructuredText',
|
|
||||||
label: 'rSt',
|
|
||||||
source: '.. image:: $url\n: alt: LegacyService Title (with Tag)',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
lang: 'AsciiDoc',
|
|
||||||
label: 'AsciiDoc',
|
|
||||||
source: 'image:$url[LegacyService Title (with Tag)]',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
lang: 'HTML',
|
|
||||||
label: 'HTML',
|
|
||||||
source: '<img alt="LegacyService Title (with Tag)" src="$url">',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'/legacy/service/{packageName}': {
|
|
||||||
get: {
|
|
||||||
summary: 'LegacyService Title (with Tag)',
|
|
||||||
description: 'LegacyService Description (with Tag)',
|
|
||||||
parameters: [
|
|
||||||
{
|
|
||||||
name: 'packageName',
|
|
||||||
in: 'path',
|
|
||||||
required: true,
|
|
||||||
schema: { type: 'string' },
|
|
||||||
example: 'badge-maker',
|
|
||||||
},
|
|
||||||
{ $ref: '#/components/parameters/style' },
|
|
||||||
{ $ref: '#/components/parameters/logo' },
|
|
||||||
{ $ref: '#/components/parameters/logoColor' },
|
|
||||||
{ $ref: '#/components/parameters/label' },
|
|
||||||
{ $ref: '#/components/parameters/labelColor' },
|
|
||||||
{ $ref: '#/components/parameters/color' },
|
|
||||||
{ $ref: '#/components/parameters/cacheSeconds' },
|
|
||||||
{ $ref: '#/components/parameters/link' },
|
|
||||||
],
|
|
||||||
'x-code-samples': [
|
|
||||||
{ lang: 'URL', label: 'URL', source: '$url' },
|
|
||||||
{
|
|
||||||
lang: 'Markdown',
|
|
||||||
label: 'Markdown',
|
|
||||||
source: '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
lang: 'reStructuredText',
|
|
||||||
label: 'rSt',
|
|
||||||
source: '.. image:: $url\n: alt: LegacyService Title (with Tag)',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
lang: 'AsciiDoc',
|
|
||||||
label: 'AsciiDoc',
|
|
||||||
source: 'image:$url[LegacyService Title (with Tag)]',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
lang: 'HTML',
|
|
||||||
label: 'HTML',
|
|
||||||
source: '<img alt="LegacyService Title (with Tag)" src="$url">',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
function clean(obj) {
|
|
||||||
// remove any undefined values in the object
|
|
||||||
return JSON.parse(JSON.stringify(obj))
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('category2openapi', function () {
|
|
||||||
it('generates an Open API spec', function () {
|
|
||||||
expect(
|
|
||||||
clean(
|
|
||||||
category2openapi({ name: 'build' }, [
|
|
||||||
OpenApiService.getDefinition(),
|
|
||||||
LegacyService.getDefinition(),
|
|
||||||
])
|
|
||||||
)
|
|
||||||
).to.deep.equal(expected)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -14,16 +14,14 @@ let resourceCache = Object.create(null)
|
|||||||
/**
|
/**
|
||||||
* Make a HTTP request using an in-memory cache
|
* Make a HTTP request using an in-memory cache
|
||||||
*
|
*
|
||||||
* @async
|
* @param {object} attrs Refer to individual attrs
|
||||||
* @param {object} attrs - Refer to individual attrs
|
* @param {string} attrs.url URL to request
|
||||||
* @param {string} attrs.url - URL to request
|
* @param {number} attrs.ttl Number of milliseconds to keep cached value for
|
||||||
* @param {number} attrs.ttl - Number of milliseconds to keep cached value for
|
* @param {boolean} [attrs.json=true] True if we expect to parse the response as JSON
|
||||||
* @param {boolean} [attrs.json=true] - True if we expect to parse the response as JSON
|
* @param {Function} [attrs.scraper=buffer => buffer] Function to extract value from the response
|
||||||
* @param {Function} [attrs.scraper=buffer => buffer] - Function to extract value from the response
|
* @param {object} [attrs.options={}] Options to pass to got
|
||||||
* @param {object} [attrs.options={}] - Options to pass to got
|
* @param {Function} [attrs.requestFetcher=fetch] Custom fetch function
|
||||||
* @param {Function} [attrs.requestFetcher=fetch] - Custom fetch function
|
* @returns {*} Parsed response
|
||||||
* @throws {InvalidResponse} - Error if unable to parse response
|
|
||||||
* @returns {Promise<*>} Promise that resolves to parsed response
|
|
||||||
*/
|
*/
|
||||||
async function getCachedResource({
|
async function getCachedResource({
|
||||||
url,
|
url,
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
import Joi from 'joi'
|
import Joi from 'joi'
|
||||||
|
|
||||||
|
// This should be kept in sync with the schema in
|
||||||
|
// `frontend/lib/service-definitions/index.ts`.
|
||||||
|
|
||||||
const arrayOfStrings = Joi.array().items(Joi.string()).min(0).required()
|
const arrayOfStrings = Joi.array().items(Joi.string()).min(0).required()
|
||||||
|
|
||||||
const objectOfKeyValues = Joi.object()
|
const objectOfKeyValues = Joi.object()
|
||||||
@@ -43,28 +46,6 @@ const serviceDefinition = Joi.object({
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
.default([]),
|
.default([]),
|
||||||
openApi: Joi.object().pattern(
|
|
||||||
/./,
|
|
||||||
Joi.object({
|
|
||||||
get: Joi.object({
|
|
||||||
summary: Joi.string().required(),
|
|
||||||
description: Joi.string().required(),
|
|
||||||
parameters: Joi.array()
|
|
||||||
.items(
|
|
||||||
Joi.object({
|
|
||||||
name: Joi.string().required(),
|
|
||||||
description: Joi.string(),
|
|
||||||
in: Joi.string().valid('query', 'path').required(),
|
|
||||||
required: Joi.boolean().required(),
|
|
||||||
schema: Joi.object({ type: Joi.string().required() }).required(),
|
|
||||||
example: Joi.string(),
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.min(1)
|
|
||||||
.required(),
|
|
||||||
}).required(),
|
|
||||||
}).required()
|
|
||||||
),
|
|
||||||
}).required()
|
}).required()
|
||||||
|
|
||||||
function assertValidServiceDefinition(example, message = undefined) {
|
function assertValidServiceDefinition(example, message = undefined) {
|
||||||
@@ -89,4 +70,9 @@ function assertValidServiceDefinitionExport(examples, message = undefined) {
|
|||||||
Joi.assert(examples, serviceDefinitionExport, message)
|
Joi.assert(examples, serviceDefinitionExport, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
export { assertValidServiceDefinition, assertValidServiceDefinitionExport }
|
export {
|
||||||
|
serviceDefinition,
|
||||||
|
assertValidServiceDefinition,
|
||||||
|
serviceDefinitionExport,
|
||||||
|
assertValidServiceDefinitionExport,
|
||||||
|
}
|
||||||
|
|||||||
66
core/server/public/monitor.html
Normal file
66
core/server/public/monitor.html
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
<!doctype html><meta charset=utf-8>
|
||||||
|
<title> Shields.io Admin Monitoring Interface </title>
|
||||||
|
<style>
|
||||||
|
#monitorPlatform { display: none; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div id=passwordRequest>
|
||||||
|
<p> Please enter your admin secret here:
|
||||||
|
<input type=password id=secretInput>
|
||||||
|
</div>
|
||||||
|
<div id=monitorPlatform>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
let network;
|
||||||
|
const onLoad = function() {
|
||||||
|
const secretInput = document.getElementById('secretInput');
|
||||||
|
const onSecretChange = function() {
|
||||||
|
const secret = secretInput.value;
|
||||||
|
const authentication = `monitor:${secret}`;
|
||||||
|
const headers = new Headers({
|
||||||
|
Authorization: `Basic ${btoa(authentication)}`
|
||||||
|
})
|
||||||
|
fetch('/sys/network', {headers})
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(networkData => {
|
||||||
|
network = networkData;
|
||||||
|
// Show monitor platform.
|
||||||
|
monitorPlatform.style.display = 'block';
|
||||||
|
passwordRequest.parentNode.removeChild(passwordRequest);
|
||||||
|
|
||||||
|
// Show logs for each server.
|
||||||
|
network.ips.forEach(ip => {
|
||||||
|
const logger = document.createElement('div');
|
||||||
|
const pre = document.createElement('pre');
|
||||||
|
logger.textContent = ip;
|
||||||
|
logger.appendChild(pre);
|
||||||
|
monitorPlatform.appendChild(logger);
|
||||||
|
|
||||||
|
// Set up the websocket.
|
||||||
|
const setUpWebsocket = () => {
|
||||||
|
const websocket = new WebSocket(
|
||||||
|
(window.location.protocol === 'http:' ? 'ws' : 'wss') + '://' +
|
||||||
|
ip + ':' + window.location.port + '/sys/logs');
|
||||||
|
websocket.addEventListener('message', event => {
|
||||||
|
pre.textContent += event.data + '\n';
|
||||||
|
});
|
||||||
|
websocket.addEventListener('close', () => {
|
||||||
|
setTimeout(setUpWebsocket, 100);
|
||||||
|
});
|
||||||
|
websocket.addEventListener('open', () => {
|
||||||
|
websocket.send(JSON.stringify({secret}));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
setUpWebsocket();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(alert)
|
||||||
|
};
|
||||||
|
secretInput.addEventListener('change', onSecretChange);
|
||||||
|
};
|
||||||
|
|
||||||
|
addEventListener('DOMContentLoaded', onLoad);
|
||||||
|
}());
|
||||||
|
</script>
|
||||||
@@ -11,6 +11,7 @@ import originalJoi from 'joi'
|
|||||||
import makeBadge from '../../badge-maker/lib/make-badge.js'
|
import makeBadge from '../../badge-maker/lib/make-badge.js'
|
||||||
import GithubConstellation from '../../services/github/github-constellation.js'
|
import GithubConstellation from '../../services/github/github-constellation.js'
|
||||||
import LibrariesIoConstellation from '../../services/librariesio/librariesio-constellation.js'
|
import LibrariesIoConstellation from '../../services/librariesio/librariesio-constellation.js'
|
||||||
|
import { setRoutes } from '../../services/suggest.js'
|
||||||
import { loadServiceClasses } from '../base-service/loader.js'
|
import { loadServiceClasses } from '../base-service/loader.js'
|
||||||
import { makeSend } from '../base-service/legacy-result-sender.js'
|
import { makeSend } from '../base-service/legacy-result-sender.js'
|
||||||
import { handleRequest } from '../base-service/legacy-request-handler.js'
|
import { handleRequest } from '../base-service/legacy-request-handler.js'
|
||||||
@@ -112,9 +113,6 @@ const publicConfigSchema = Joi.object({
|
|||||||
redirectUrl: optionalUrl,
|
redirectUrl: optionalUrl,
|
||||||
rasterUrl: optionalUrl,
|
rasterUrl: optionalUrl,
|
||||||
cors: {
|
cors: {
|
||||||
// This doesn't actually do anything
|
|
||||||
// TODO: maybe remove in future?
|
|
||||||
// https://github.com/badges/shields/pull/8311#discussion_r945337530
|
|
||||||
allowedOrigin: Joi.array().items(optionalUrl).required(),
|
allowedOrigin: Joi.array().items(optionalUrl).required(),
|
||||||
},
|
},
|
||||||
services: Joi.object({
|
services: Joi.object({
|
||||||
@@ -126,7 +124,6 @@ const publicConfigSchema = Joi.object({
|
|||||||
enabled: Joi.boolean().required(),
|
enabled: Joi.boolean().required(),
|
||||||
intervalSeconds: Joi.number().integer().min(1).required(),
|
intervalSeconds: Joi.number().integer().min(1).required(),
|
||||||
},
|
},
|
||||||
restApiVersion: Joi.date().raw().required(),
|
|
||||||
},
|
},
|
||||||
gitlab: defaultService,
|
gitlab: defaultService,
|
||||||
jira: defaultService,
|
jira: defaultService,
|
||||||
@@ -172,8 +169,6 @@ const privateConfigSchema = Joi.object({
|
|||||||
jenkins_pass: Joi.string(),
|
jenkins_pass: Joi.string(),
|
||||||
jira_user: Joi.string(),
|
jira_user: Joi.string(),
|
||||||
jira_pass: Joi.string(),
|
jira_pass: Joi.string(),
|
||||||
bitbucket_username: Joi.string(),
|
|
||||||
bitbucket_password: Joi.string(),
|
|
||||||
bitbucket_server_username: Joi.string(),
|
bitbucket_server_username: Joi.string(),
|
||||||
bitbucket_server_password: Joi.string(),
|
bitbucket_server_password: Joi.string(),
|
||||||
librariesio_tokens: Joi.arrayFromString().items(Joi.string()),
|
librariesio_tokens: Joi.arrayFromString().items(Joi.string()),
|
||||||
@@ -183,12 +178,10 @@ const privateConfigSchema = Joi.object({
|
|||||||
obs_user: Joi.string(),
|
obs_user: Joi.string(),
|
||||||
obs_pass: Joi.string(),
|
obs_pass: Joi.string(),
|
||||||
redis_url: Joi.string().uri({ scheme: ['redis', 'rediss'] }),
|
redis_url: Joi.string().uri({ scheme: ['redis', 'rediss'] }),
|
||||||
postgres_url: Joi.string().uri({ scheme: 'postgresql' }),
|
|
||||||
sentry_dsn: Joi.string(),
|
sentry_dsn: Joi.string(),
|
||||||
sl_insight_userUuid: Joi.string(),
|
sl_insight_userUuid: Joi.string(),
|
||||||
sl_insight_apiToken: Joi.string(),
|
sl_insight_apiToken: Joi.string(),
|
||||||
sonarqube_token: Joi.string(),
|
sonarqube_token: Joi.string(),
|
||||||
stackapps_api_key: Joi.string(),
|
|
||||||
teamcity_user: Joi.string(),
|
teamcity_user: Joi.string(),
|
||||||
teamcity_pass: Joi.string(),
|
teamcity_pass: Joi.string(),
|
||||||
twitch_client_id: Joi.string(),
|
twitch_client_id: Joi.string(),
|
||||||
@@ -208,14 +201,6 @@ function addHandlerAtIndex(camp, index, handlerFn) {
|
|||||||
camp.stack.splice(index, 0, handlerFn)
|
camp.stack.splice(index, 0, handlerFn)
|
||||||
}
|
}
|
||||||
|
|
||||||
function isOnHeroku() {
|
|
||||||
return !!process.env.DYNO
|
|
||||||
}
|
|
||||||
|
|
||||||
function isOnFly() {
|
|
||||||
return !!process.env.FLY_APP_NAME
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Server is based on the web framework Scoutcamp. It creates
|
* The Server is based on the web framework Scoutcamp. It creates
|
||||||
* an http server, sets up helpers for token persistence and monitoring.
|
* an http server, sets up helpers for token persistence and monitoring.
|
||||||
@@ -316,21 +301,13 @@ class Server {
|
|||||||
// Set `req.ip`, which is expected by `cloudflareMiddleware()`. This is set
|
// Set `req.ip`, which is expected by `cloudflareMiddleware()`. This is set
|
||||||
// by Express but not Scoutcamp.
|
// by Express but not Scoutcamp.
|
||||||
addHandlerAtIndex(this.camp, 0, function (req, res, next) {
|
addHandlerAtIndex(this.camp, 0, function (req, res, next) {
|
||||||
if (isOnHeroku()) {
|
// On Heroku, `req.socket.remoteAddress` is the Heroku router. However,
|
||||||
// On Heroku, `req.socket.remoteAddress` is the Heroku router. However,
|
// the router ensures that the last item in the `X-Forwarded-For` header
|
||||||
// the router ensures that the last item in the `X-Forwarded-For` header
|
// is the real origin.
|
||||||
// is the real origin.
|
// https://stackoverflow.com/a/18517550/893113
|
||||||
// https://stackoverflow.com/a/18517550/893113
|
req.ip = process.env.DYNO
|
||||||
req.ip = req.headers['x-forwarded-for'].split(', ').pop()
|
? req.headers['x-forwarded-for'].split(', ').pop()
|
||||||
} else if (isOnFly()) {
|
: req.socket.remoteAddress
|
||||||
// On Fly we can use the Fly-Client-IP header
|
|
||||||
// https://fly.io/docs/reference/runtime-environment/#request-headers
|
|
||||||
req.ip = req.headers['fly-client-ip']
|
|
||||||
? req.headers['fly-client-ip']
|
|
||||||
: req.socket.remoteAddress
|
|
||||||
} else {
|
|
||||||
req.ip = req.socket.remoteAddress
|
|
||||||
}
|
|
||||||
next()
|
next()
|
||||||
})
|
})
|
||||||
addHandlerAtIndex(this.camp, 1, cloudflareMiddleware())
|
addHandlerAtIndex(this.camp, 1, cloudflareMiddleware())
|
||||||
@@ -362,7 +339,7 @@ class Server {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (!rasterUrl) {
|
if (!rasterUrl) {
|
||||||
camp.route(/^\/((?!img\/)).*\.png$/, (query, match, end, request) => {
|
camp.route(/\.png$/, (query, match, end, request) => {
|
||||||
makeSend(
|
makeSend(
|
||||||
'svg',
|
'svg',
|
||||||
request.res,
|
request.res,
|
||||||
@@ -412,7 +389,7 @@ class Server {
|
|||||||
|
|
||||||
if (rasterUrl) {
|
if (rasterUrl) {
|
||||||
// Redirect to the raster server for raster versions of modern badges.
|
// Redirect to the raster server for raster versions of modern badges.
|
||||||
camp.route(/^\/((?!img\/)).*\.png$/, (queryParams, match, end, ask) => {
|
camp.route(/\.png$/, (queryParams, match, end, ask) => {
|
||||||
ask.res.statusCode = 301
|
ask.res.statusCode = 301
|
||||||
ask.res.setHeader(
|
ask.res.setHeader(
|
||||||
'Location',
|
'Location',
|
||||||
@@ -493,6 +470,7 @@ class Server {
|
|||||||
const {
|
const {
|
||||||
bind: { port, address: hostname },
|
bind: { port, address: hostname },
|
||||||
ssl: { isSecure: secure, cert, key },
|
ssl: { isSecure: secure, cert, key },
|
||||||
|
cors: { allowedOrigin },
|
||||||
requireCloudflare,
|
requireCloudflare,
|
||||||
} = this.config.public
|
} = this.config.public
|
||||||
|
|
||||||
@@ -525,6 +503,9 @@ class Server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { apiProvider: githubApiProvider } = this.githubConstellation
|
||||||
|
setRoutes(allowedOrigin, githubApiProvider, camp)
|
||||||
|
|
||||||
// https://github.com/badges/shields/issues/3273
|
// https://github.com/badges/shields/issues/3273
|
||||||
camp.handle((req, res, next) => {
|
camp.handle((req, res, next) => {
|
||||||
res.setHeader('Access-Control-Allow-Origin', '*')
|
res.setHeader('Access-Control-Allow-Origin', '*')
|
||||||
|
|||||||
@@ -60,14 +60,12 @@ describe('The server', function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should serve badges with custom maxAge', async function () {
|
it('should serve badges with custom maxAge', async function () {
|
||||||
const { headers } = await got(`${baseUrl}badge/foo-bar-blue`)
|
const { headers } = await got(`${baseUrl}npm/l/express`)
|
||||||
expect(headers['cache-control']).to.equal('max-age=86400, s-maxage=86400')
|
expect(headers['cache-control']).to.equal('max-age=3600, s-maxage=3600')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should return cors header for the request', async function () {
|
it('should return cors header for the request', async function () {
|
||||||
const { statusCode, headers } = await got(
|
const { statusCode, headers } = await got(`${baseUrl}npm/v/express.svg`)
|
||||||
`${baseUrl}badge/foo-bar-blue.svg`
|
|
||||||
)
|
|
||||||
expect(statusCode).to.equal(200)
|
expect(statusCode).to.equal(200)
|
||||||
expect(headers['access-control-allow-origin']).to.equal('*')
|
expect(headers['access-control-allow-origin']).to.equal('*')
|
||||||
})
|
})
|
||||||
@@ -86,23 +84,15 @@ describe('The server', function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should redirect modern PNG badges as configured', async function () {
|
it('should redirect modern PNG badges as configured', async function () {
|
||||||
const { statusCode, headers } = await got(
|
const { statusCode, headers } = await got(`${baseUrl}npm/v/express.png`, {
|
||||||
`${baseUrl}badge/foo-bar-blue.png`,
|
followRedirect: false,
|
||||||
{
|
})
|
||||||
followRedirect: false,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
expect(statusCode).to.equal(301)
|
expect(statusCode).to.equal(301)
|
||||||
expect(headers.location).to.equal(
|
expect(headers.location).to.equal(
|
||||||
'http://raster.example.test/badge/foo-bar-blue.png'
|
'http://raster.example.test/npm/v/express.png'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should not redirect for PNG requests in /img', async function () {
|
|
||||||
const { statusCode } = await got(`${baseUrl}img/frontend-image.png`)
|
|
||||||
expect(statusCode).to.equal(200)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should produce SVG badges with expected headers', async function () {
|
it('should produce SVG badges with expected headers', async function () {
|
||||||
const { statusCode, headers } = await got(
|
const { statusCode, headers } = await got(
|
||||||
`${baseUrl}:fruit-apple-green.svg`
|
`${baseUrl}:fruit-apple-green.svg`
|
||||||
@@ -207,12 +197,9 @@ describe('The server', function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should return the 410 badge for obsolete formats', async function () {
|
it('should return the 410 badge for obsolete formats', async function () {
|
||||||
const { statusCode, body } = await got(
|
const { statusCode, body } = await got(`${baseUrl}npm/v/express.jpg`, {
|
||||||
`${baseUrl}badge/foo-bar-blue.jpg`,
|
throwHttpErrors: false,
|
||||||
{
|
})
|
||||||
throwHttpErrors: false,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
// TODO It would be nice if this were 404 or 410.
|
// TODO It would be nice if this were 404 or 410.
|
||||||
expect(statusCode).to.equal(200)
|
expect(statusCode).to.equal(200)
|
||||||
expect(body)
|
expect(body)
|
||||||
@@ -220,6 +207,12 @@ describe('The server', function () {
|
|||||||
.and.to.include('410')
|
.and.to.include('410')
|
||||||
.and.to.include('jpg no longer available')
|
.and.to.include('jpg no longer available')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should return cors header for the request', async function () {
|
||||||
|
const { statusCode, headers } = await got(`${baseUrl}npm/v/express.svg`)
|
||||||
|
expect(statusCode).to.equal(200)
|
||||||
|
expect(headers['access-control-allow-origin']).to.equal('*')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
context('`requireCloudflare` is enabled', function () {
|
context('`requireCloudflare` is enabled', function () {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user