Compare commits

..

5 Commits

Author SHA1 Message Date
chris48s
046856c056 fix 2022-02-08 19:36:56 +00:00
chris48s
851a30be39 test 2022-02-08 19:29:56 +00:00
chris48s
785ee090a9 test 2022-02-08 19:28:19 +00:00
chris48s
0002d6749e fix 2022-02-08 19:24:22 +00:00
chris48s
fb379c0556 lets not pretend this commit history is going to be meaningful 2022-02-08 19:22:47 +00:00
138 changed files with 3000 additions and 5105 deletions

View File

@@ -7,6 +7,7 @@ main_steps: &main_steps
- run:
name: Install dependencies
command: |
npm install --dry-run
npm ci
environment:
# https://docs.cypress.io/guides/getting-started/installing-cypress.html#Skipping-installation
@@ -49,6 +50,7 @@ integration_steps: &integration_steps
- run:
name: Install dependencies
command: |
npm install --dry-run
npm ci
environment:
CYPRESS_INSTALL_BINARY: 0
@@ -71,6 +73,7 @@ services_steps: &services_steps
- run:
name: Install dependencies
command: |
npm install --dry-run
npm ci
environment:
CYPRESS_INSTALL_BINARY: 0
@@ -113,7 +116,6 @@ package_steps: &package_steps
MOCHA_FILE: junit/badge-maker/v12/results.xml
NODE_VERSION: v12
CYPRESS_INSTALL_BINARY: 0
NPM_CONFIG_ENGINE_STRICT: 'false'
name: Run package tests on Node 12
command: scripts/run_package_tests.sh
@@ -123,7 +125,6 @@ package_steps: &package_steps
MOCHA_FILE: junit/badge-maker/v14/results.xml
NODE_VERSION: v14
CYPRESS_INSTALL_BINARY: 0
NPM_CONFIG_ENGINE_STRICT: 'false'
name: Run package tests on Node 14
command: scripts/run_package_tests.sh
@@ -142,33 +143,39 @@ package_steps: &package_steps
jobs:
main:
docker:
- image: cimg/node:16.15
- image: circleci/node:16
environment:
NPM_CONFIG_ENGINE_STRICT: 'true'
NPM_CONFIG_STRICT_PEER_DEPS: 'true'
<<: *main_steps
main@node-17:
docker:
- image: cimg/node:17.9
- image: circleci/node:17
<<: *main_steps
integration:
docker:
- image: cimg/node:16.15
- 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: cimg/node:17.9
- image: circleci/node:17
- image: redis
<<: *integration_steps
danger:
docker:
- image: cimg/node:16.15
- image: circleci/node:16
steps:
- checkout
@@ -188,14 +195,17 @@ jobs:
frontend:
docker:
- image: cimg/node:16.15
- 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
@@ -225,27 +235,31 @@ jobs:
command: npm run build
package:
machine:
image: 'ubuntu-2004:202111-02'
machine: true
<<: *package_steps
services:
docker:
- image: cimg/node:16.15
- image: circleci/node:16
environment:
NPM_CONFIG_ENGINE_STRICT: 'true'
NPM_CONFIG_STRICT_PEER_DEPS: 'true'
<<: *services_steps
services@node-17:
docker:
- image: cimg/node:17.9
- image: circleci/node:17
<<: *services_steps
e2e:
docker:
- image: cypress/base:16.14.0
- image: cypress/base:16.13.0
environment:
NPM_CONFIG_ENGINE_STRICT: 'true'
NPM_CONFIG_STRICT_PEER_DEPS: 'true'
steps:
- checkout
@@ -257,6 +271,7 @@ jobs:
- run:
name: Install dependencies
command: |
npm install --dry-run
npm ci
- run:

View File

@@ -9,53 +9,53 @@
"version": "0.0.0",
"license": "CC0",
"dependencies": {
"@actions/core": "^1.8.2",
"@actions/github": "^5.0.3"
"@actions/core": "^1.6.0",
"@actions/github": "^5.0.0"
}
},
"node_modules/@actions/core": {
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.2.tgz",
"integrity": "sha512-FXcBL7nyik8K5ODeCKlxi+vts7torOkoDAKfeh61EAkAy1HAvwn9uVzZBY0f15YcQTcZZ2/iSGBFHEuioZWfDA==",
"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": "^2.0.1"
"@actions/http-client": "^1.0.11"
}
},
"node_modules/@actions/github": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/@actions/github/-/github-5.0.3.tgz",
"integrity": "sha512-myjA/pdLQfhUGLtRZC/J4L1RXOG4o6aYdiEq+zr5wVVKljzbFld+xv10k1FX6IkIJtNxbAq44BdwSNpQ015P0A==",
"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": "^2.0.1",
"@octokit/core": "^3.6.0",
"@octokit/plugin-paginate-rest": "^2.17.0",
"@octokit/plugin-rest-endpoint-methods": "^5.13.0"
"@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": "2.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
"integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"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"
"tunnel": "0.0.6"
}
},
"node_modules/@octokit/auth-token": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
"integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
"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.6.0",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz",
"integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==",
"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.6.3",
"@octokit/request": "^5.4.12",
"@octokit/request-error": "^2.0.5",
"@octokit/types": "^6.0.3",
"before-after-hook": "^2.2.0",
@@ -63,9 +63,9 @@
}
},
"node_modules/@octokit/endpoint": {
"version": "6.0.12",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
"integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
"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",
@@ -73,37 +73,37 @@
}
},
"node_modules/@octokit/graphql": {
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
"integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
"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.6.0",
"@octokit/request": "^5.3.0",
"@octokit/types": "^6.0.3",
"universal-user-agent": "^6.0.0"
}
},
"node_modules/@octokit/openapi-types": {
"version": "11.2.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.2.0.tgz",
"integrity": "sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA=="
"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.17.0",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz",
"integrity": "sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw==",
"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.34.0"
"@octokit/types": "^6.11.0"
},
"peerDependencies": {
"@octokit/core": ">=2"
}
},
"node_modules/@octokit/plugin-rest-endpoint-methods": {
"version": "5.13.0",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz",
"integrity": "sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA==",
"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.34.0",
"@octokit/types": "^6.14.1",
"deprecation": "^2.3.1"
},
"peerDependencies": {
@@ -111,22 +111,22 @@
}
},
"node_modules/@octokit/request": {
"version": "5.6.3",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz",
"integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==",
"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.1.0",
"@octokit/types": "^6.16.1",
"@octokit/request-error": "^2.0.0",
"@octokit/types": "^6.7.1",
"is-plain-object": "^5.0.0",
"node-fetch": "^2.6.7",
"node-fetch": "^2.6.1",
"universal-user-agent": "^6.0.0"
}
},
"node_modules/@octokit/request-error": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
"integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
"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",
@@ -134,17 +134,17 @@
}
},
"node_modules/@octokit/types": {
"version": "6.34.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.34.0.tgz",
"integrity": "sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw==",
"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": "^11.2.0"
"@octokit/openapi-types": "^7.0.0"
}
},
"node_modules/before-after-hook": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz",
"integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ=="
"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",
@@ -226,48 +226,48 @@
},
"dependencies": {
"@actions/core": {
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.2.tgz",
"integrity": "sha512-FXcBL7nyik8K5ODeCKlxi+vts7torOkoDAKfeh61EAkAy1HAvwn9uVzZBY0f15YcQTcZZ2/iSGBFHEuioZWfDA==",
"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": "^2.0.1"
"@actions/http-client": "^1.0.11"
}
},
"@actions/github": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/@actions/github/-/github-5.0.3.tgz",
"integrity": "sha512-myjA/pdLQfhUGLtRZC/J4L1RXOG4o6aYdiEq+zr5wVVKljzbFld+xv10k1FX6IkIJtNxbAq44BdwSNpQ015P0A==",
"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": "^2.0.1",
"@octokit/core": "^3.6.0",
"@octokit/plugin-paginate-rest": "^2.17.0",
"@octokit/plugin-rest-endpoint-methods": "^5.13.0"
"@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": "2.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
"integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"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"
"tunnel": "0.0.6"
}
},
"@octokit/auth-token": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
"integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
"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.6.0",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz",
"integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==",
"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.6.3",
"@octokit/request": "^5.4.12",
"@octokit/request-error": "^2.0.5",
"@octokit/types": "^6.0.3",
"before-after-hook": "^2.2.0",
@@ -275,9 +275,9 @@
}
},
"@octokit/endpoint": {
"version": "6.0.12",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
"integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
"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",
@@ -285,54 +285,54 @@
}
},
"@octokit/graphql": {
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
"integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
"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.6.0",
"@octokit/request": "^5.3.0",
"@octokit/types": "^6.0.3",
"universal-user-agent": "^6.0.0"
}
},
"@octokit/openapi-types": {
"version": "11.2.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.2.0.tgz",
"integrity": "sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA=="
"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.17.0",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz",
"integrity": "sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw==",
"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.34.0"
"@octokit/types": "^6.11.0"
}
},
"@octokit/plugin-rest-endpoint-methods": {
"version": "5.13.0",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz",
"integrity": "sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA==",
"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.34.0",
"@octokit/types": "^6.14.1",
"deprecation": "^2.3.1"
}
},
"@octokit/request": {
"version": "5.6.3",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz",
"integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==",
"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.1.0",
"@octokit/types": "^6.16.1",
"@octokit/request-error": "^2.0.0",
"@octokit/types": "^6.7.1",
"is-plain-object": "^5.0.0",
"node-fetch": "^2.6.7",
"node-fetch": "^2.6.1",
"universal-user-agent": "^6.0.0"
}
},
"@octokit/request-error": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
"integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
"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",
@@ -340,17 +340,17 @@
}
},
"@octokit/types": {
"version": "6.34.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.34.0.tgz",
"integrity": "sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw==",
"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": "^11.2.0"
"@octokit/openapi-types": "^7.0.0"
}
},
"before-after-hook": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz",
"integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ=="
"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",

View File

@@ -10,7 +10,7 @@
"author": "chris48s",
"license": "CC0",
"dependencies": {
"@actions/core": "^1.8.2",
"@actions/github": "^5.0.3"
"@actions/core": "^1.6.0",
"@actions/github": "^5.0.0"
}
}

12
.github/actions/tester/action.yml vendored Normal file
View 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
View 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
View 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
View 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"
}
}

View File

@@ -36,8 +36,3 @@ updates:
day: friday
time: '12:00'
open-pull-requests-limit: 99
- package-ecosystem: 'github-actions'
directory: '/'
schedule:
interval: weekly
open-pull-requests-limit: 99

View File

@@ -10,7 +10,7 @@ jobs:
if: github.actor == 'dependabot[bot]'
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Install action dependencies
run: cd .github/actions/close-bot && npm ci

View File

@@ -7,19 +7,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Set Git Short SHA
run: echo "SHORT_SHA=${GITHUB_SHA::7}" >> $GITHUB_ENV
uses: docker/setup-buildx-action@v1
- name: Build
uses: docker/build-push-action@v3
uses: docker/build-push-action@v2
with:
context: .
push: false
tags: shieldsio/shields:pr-validation
build-args: |
version=${{ env.SHORT_SHA }}
version=${GITHUB_SHA::7}

View File

@@ -4,9 +4,6 @@ on:
pull_request:
types: [closed]
permissions:
contents: write
jobs:
create-release:
if: |
@@ -23,7 +20,7 @@ jobs:
run: echo "::set-output name=date::$(date --rfc-3339=date)"
- name: Checkout branch "master"
uses: actions/checkout@v3
uses: actions/checkout@v2
with:
ref: 'master'
@@ -34,16 +31,16 @@ jobs:
tag: server-${{ steps.date.outputs.date }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
uses: docker/setup-buildx-action@v1
- name: Login to DockerHub
uses: docker/login-action@v2
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push snapshot release to DockerHub
uses: docker/build-push-action@v3
uses: docker/build-push-action@v2
with:
context: .
push: true

View File

@@ -3,16 +3,12 @@ on:
push:
branches:
- master
permissions:
contents: write
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v2.3.1
with:
persist-credentials: false
@@ -22,8 +18,9 @@ jobs:
npm run build-docs
- name: Deploy
uses: JamesIves/github-pages-deploy-action@v4
uses: JamesIves/github-pages-deploy-action@3.7.1
with:
branch: gh-pages
folder: api-docs
clean: true
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BRANCH: gh-pages
FOLDER: api-docs
CLEAN: true

View File

@@ -5,16 +5,12 @@ on:
# At 01:00 on the first day of every month
workflow_dispatch:
permissions:
pull-requests: write
contents: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Draft Release
uses: ./.github/actions/draft-release

View File

@@ -1,11 +0,0 @@
name: 'Dependency Review'
on: [pull_request]
jobs:
dependency-review:
runs-on: ubuntu-latest
steps:
- name: 'Checkout Repository'
uses: actions/checkout@v3
- name: 'Dependency Review'
uses: actions/dependency-review-action@v1

View File

@@ -9,25 +9,22 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
uses: docker/setup-buildx-action@v1
- name: Login to DockerHub
uses: docker/login-action@v2
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set Git Short SHA
run: echo "SHORT_SHA=${GITHUB_SHA::7}" >> $GITHUB_ENV
- name: Build and push
uses: docker/build-push-action@v3
uses: docker/build-push-action@v2
with:
context: .
push: true
tags: shieldsio/shields:next
build-args: |
version=${{ env.SHORT_SHA }}
version=${GITHUB_SHA::7}

20
.github/workflows/test-build-args.yml vendored Normal file
View 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 }}

2
.npmrc
View File

@@ -1,2 +0,0 @@
engine-strict=true
strict-peer-deps=true

View File

@@ -4,75 +4,6 @@ Note: this changelog is for the shields.io server. The changelog for the badge-m
---
## 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
- [Depfu] Add support for Gitlab [#7475](https://github.com/badges/shields/issues/7475)

View File

@@ -9,7 +9,7 @@ COPY package.json package-lock.json /usr/src/app/
COPY badge-maker /usr/src/app/badge-maker/
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.
RUN NODE_ENV=development CYPRESS_INSTALL_BINARY=0 npm ci
@@ -23,8 +23,6 @@ FROM node:16-alpine
ARG version=dev
ENV DOCKER_SHIELDS_VERSION=$version
LABEL version=$version
LABEL fly.version=$version
# Run the server using production configs.
ENV NODE_ENV production

View File

@@ -35,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
continuous integration services, package registries, distributions, app
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]
and [Bootstrap][bootstrap] to name a few.

View File

@@ -10,7 +10,7 @@ Please follow this guidance when reporting security issues affecting:
- The [squint](https://github.com/badges/squint) raster proxy
- The [badge-maker](https://www.npmjs.com/package/badge-maker) NPM package
The [gh-badges](https://www.npmjs.com/package/gh-badges) 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

View File

@@ -6,20 +6,13 @@ public:
enabled: true
url: https://metrics.shields.io/telegraf
instanceIdFrom: env-var
instanceIdEnvVarName: FLY_ALLOC_ID
instanceIdEnvVarName: HEROKU_DYNO_ID
envLabel: shields-production
ssl:
isSecure: false
isSecure: true
cors:
allowedOrigin: ['http://shields.io', 'https://shields.io']
services:
gitlab:
authorizedOrigins: 'https://gitlab.com'
rasterUrl: 'https://raster.shields.io'
userAgentBase: 'Shields.io'
requireCloudflare: true
requestTimeoutSeconds: 20

View File

@@ -147,7 +147,6 @@ class BaseService {
version: 300,
debug: 60,
downloads: 900,
rating: 900,
social: 900,
}
return cacheLengths[this.category]

View 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>

View File

@@ -201,14 +201,6 @@ function addHandlerAtIndex(camp, index, 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
* an http server, sets up helpers for token persistence and monitoring.
@@ -309,21 +301,13 @@ class Server {
// Set `req.ip`, which is expected by `cloudflareMiddleware()`. This is set
// by Express but not Scoutcamp.
addHandlerAtIndex(this.camp, 0, function (req, res, next) {
if (isOnHeroku()) {
// On Heroku, `req.socket.remoteAddress` is the Heroku router. However,
// the router ensures that the last item in the `X-Forwarded-For` header
// is the real origin.
// https://stackoverflow.com/a/18517550/893113
req.ip = req.headers['x-forwarded-for'].split(', ').pop()
} else if (isOnFly()) {
// 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
}
// On Heroku, `req.socket.remoteAddress` is the Heroku router. However,
// the router ensures that the last item in the `X-Forwarded-For` header
// is the real origin.
// https://stackoverflow.com/a/18517550/893113
req.ip = process.env.DYNO
? req.headers['x-forwarded-for'].split(', ').pop()
: req.socket.remoteAddress
next()
})
addHandlerAtIndex(this.camp, 1, cloudflareMiddleware())

View File

@@ -25,7 +25,7 @@ and learn about the [GitHub workflow](http://try.github.io/).
#### Node, NPM
Node >=16 and NPM >=8 is required. If you don't already have them,
Node >=16 and NPM >=7 is required. If you don't already have them,
install node and npm: https://nodejs.org/en/download/
### Setup a dev install

View File

@@ -40,7 +40,7 @@ If you are submitting a pull request for a custom logo, please:
- Install SVGO
- With npm: `npm install -g svgo`
- With Homebrew: `brew install svgo`
- Run the following command `svgo --precision=3 icon.svg -o icon.min.svg`
- Run the following command `svgo --precision=3 icon.svg icon.min.svg`
- Check if there is a loss of quality in the output, if so increase the precision.
- The [SVGOMG Online Tool][svgomg]
- Click "Open SVG" and select an SVG file.

View File

@@ -16,8 +16,9 @@ Production hosting is managed by the Shields ops team:
| Component | Subcomponent | People with access |
| ----------------------------- | ------------------------------- | --------------------------------------------------------------- |
| shields-io-production | Full access | @calebcartwright, @chris48s, @paulmelnikow |
| shields-io-production | Access management | @calebcartwright, @chris48s, @paulmelnikow |
| shields-production-us | Account owner | @calebcartwright, @paulmelnikow |
| shields-production-us | Full access | @calebcartwright, @chris48s, @paulmelnikow, @pyvesb |
| shields-production-us | Access management | @calebcartwright, @chris48s, @paulmelnikow, @pyvesb |
| Compose.io Redis | Account owner | @paulmelnikow |
| Compose.io Redis | Account access | @paulmelnikow |
| Compose.io Redis | Database connection credentials | @calebcartwright, @chris48s, @paulmelnikow, @pyvesb |
@@ -94,10 +95,13 @@ The raster server `raster.shields.io` (a.k.a. the rasterizing proxy) is
hosted on Heroku. It's managed in the
[squint](https://github.com/badges/squint/) repo.
### Fly.io Deployment
### Heroku Deployment
Both the badge server and frontend are served from Fly.io. Deployments are
triggered using GitHub actions in a private repo.
Both the badge server and frontend are served from Heroku.
After merging a commit to master, heroku should create a staging deploy. Check this has deployed correctly in the `shields-staging` pipeline and review https://shields-staging.herokuapp.com/
If we're happy with it, "promote to production". This will deploy what's on staging to the `shields-production-eu` and `shields-production-us` pieplines.
## DNS
@@ -105,15 +109,19 @@ DNS is registered with [DNSimple][].
[dnsimple]: https://dnsimple.com/
## Logs
Logs can be retrieved [from heroku](https://devcenter.heroku.com/articles/logging#log-retrieval).
## Error reporting
[Error reporting][sentry] is one of the most useful tools we have for monitoring
the server. It's generously donated by [Sentry][sentry home]. We bundle
[`@sentry/node`][sentry-node] into the application, and the Sentry DSN is configured
via `local-shields-io-production.yml` (see [documentation][sentry configuration]).
[`raven`][raven] into the application, and the Sentry DSN is configured via
`local-shields-io-production.yml` (see [documentation][sentry configuration]).
[sentry]: https://sentry.io/shields/
[sentry-node]: https://www.npmjs.com/package/@sentry/node
[raven]: https://www.npmjs.com/package/raven
[sentry home]: https://sentry.io/shields/
[sentry configuration]: https://github.com/badges/shields/blob/master/doc/self-hosting.md#sentry

View File

@@ -119,7 +119,7 @@ machine.
If you want to host PNG badges, you can also self-host a [raster server][]
which points to your badge server. It's a docker container. We host it on
Fly.io but should be possible to host on a wide variety of platforms.
Heroku but should be possible to host on a wide variety of platforms.
- In your raster instance, set `BASE_URL` to your Shields instance, e.g.
`https://shields.example.co`.

View File

@@ -25,9 +25,6 @@ export function getBaseUrl(): string {
if (['shields.io', 'www.shields.io'].includes(hostname)) {
return 'https://img.shields.io'
}
if (!port) {
return `${protocol}//${hostname}`
}
return `${protocol}//${hostname}:${port}`
} catch (e) {
// server-side rendering

View File

@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="93 93 194 194"><defs><style>.b{fill:#fc6d26}</style></defs><path style="fill:#e24329" d="m282.83 170.73-.27-.69-26.14-68.22a6.81 6.81 0 0 0-2.69-3.24 7 7 0 0 0-8 .43 7 7 0 0 0-2.32 3.52l-17.65 54h-71.47l-17.65-54a6.86 6.86 0 0 0-2.32-3.53 7 7 0 0 0-8-.43 6.87 6.87 0 0 0-2.69 3.24L97.44 170l-.26.69a48.54 48.54 0 0 0 16.1 56.1l.09.07.24.17 39.82 29.82 19.7 14.91 12 9.06a8.07 8.07 0 0 0 9.76 0l12-9.06 19.7-14.91 40.06-30 .1-.08a48.56 48.56 0 0 0 16.08-56.04Z"/><path class="b" d="m282.83 170.73-.27-.69a88.3 88.3 0 0 0-35.15 15.8L190 229.25c19.55 14.79 36.57 27.64 36.57 27.64l40.06-30 .1-.08a48.56 48.56 0 0 0 16.1-56.08Z"/><path style="fill:#fca326" d="m153.43 256.89 19.7 14.91 12 9.06a8.07 8.07 0 0 0 9.76 0l12-9.06 19.7-14.91S209.55 244 190 229.25c-19.55 14.75-36.57 27.64-36.57 27.64Z"/><path class="b" d="M132.58 185.84A88.19 88.19 0 0 0 97.44 170l-.26.69a48.54 48.54 0 0 0 16.1 56.1l.09.07.24.17 39.82 29.82L190 229.21Z"/></svg>
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M23.956 13.587l-1.344-4.133a4549.814 4549.814 0 0 0-2.663-8.189.456.456 0 0 0-.87 0l-2.658 8.189H7.585L4.92 1.265a.456.456 0 0 0-.87 0A4549.814 4549.814 0 0 0 .044 13.587a.908.908 0 0 0 .336 1.02L12 23.054l11.62-8.447a.908.908 0 0 0 .336-1.02" fill="#fc6d26"/><path d="M12 23.054l4.421-13.6H7.58z" fill="#e24329"/><path d="M7.579 9.454H1.388L12 23.054z" fill="#fc6d26"/><path d="M1.388 9.454L.044 13.587a.908.908 0 0 0 .336 1.02L12 23.054z" fill="#fca326"/><path d="M7.579 9.454L4.92 1.265a.456.456 0 0 0-.87 0L1.388 9.454z" fill="#e24329"/><path d="M16.421 9.454h6.191L12 23.054z" fill="#fc6d26"/><path d="M22.612 9.454l1.344 4.133a.908.908 0 0 1-.336 1.02L12 23.054z" fill="#fca326"/><path d="M16.421 9.454l2.658-8.189a.456.456 0 0 1 .87 0l2.663 8.189z" fill="#e24329"/></svg>

Before

Width:  |  Height:  |  Size: 986 B

After

Width:  |  Height:  |  Size: 847 B

View File

@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 24c6.627 0 12-5.373 12-12S18.627 0 12 0 0 5.373 0 12s5.373 12 12 12Z" fill="url(#a)"/><path fill-rule="evenodd" clip-rule="evenodd" d="M5.425 11.871a796.414 796.414 0 0 1 6.994-3.018c3.328-1.388 4.027-1.628 4.477-1.638.1 0 .32.02.47.14.12.1.15.23.17.33.02.1.04.31.02.47-.18 1.898-.96 6.504-1.36 8.622-.17.9-.5 1.199-.819 1.229-.7.06-1.229-.46-1.898-.9-1.06-.689-1.649-1.119-2.678-1.798-1.19-.78-.42-1.209.26-1.908.18-.18 3.247-2.978 3.307-3.228.01-.03.01-.15-.06-.21-.07-.06-.17-.04-.25-.02-.11.02-1.788 1.14-5.056 3.348-.48.33-.909.49-1.299.48-.43-.01-1.248-.24-1.868-.44-.75-.24-1.349-.37-1.299-.79.03-.22.33-.44.89-.669Z" fill="#fff"/><defs><linearGradient id="a" x1="11.99" y1="0" x2="11.99" y2="23.81" gradientUnits="userSpaceOnUse"><stop stop-color="#2AABEE"/><stop offset="1" stop-color="#229ED9"/></linearGradient></defs></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><circle cx="12" cy="12" r="12" fill="#2ca5e0"/><path d="M9.8 17.5c-.389 0-.323-.147-.457-.517L8.2 13.221 17 8" fill="#a9c9dd"/><path d="M9.8 17.5c.3 0 .433-.137.6-.3l1.6-1.556-1.996-1.203" fill="#c8daea"/><path d="M10.004 14.441l4.836 3.573c.552.304.95.147 1.088-.512l1.968-9.277c.202-.808-.308-1.174-.836-.935L5.501 11.748c-.789.316-.784.756-.144.952l2.967.926 6.867-4.332c.324-.197.622-.091.377.125" fill="#fff"/></svg>

Before

Width:  |  Height:  |  Size: 909 B

After

Width:  |  Height:  |  Size: 481 B

4487
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -21,29 +21,28 @@
"url": "https://github.com/badges/shields"
},
"dependencies": {
"@fontsource/lato": "^4.5.8",
"@fontsource/lekton": "^4.5.9",
"@renovate/pep440": "^1.0.0",
"@sentry/node": "^6.19.7",
"@fontsource/lato": "^4.5.1",
"@fontsource/lekton": "^4.5.2",
"@sentry/node": "^6.17.4",
"@shields_io/camp": "^18.1.1",
"badge-maker": "file:badge-maker",
"bytes": "^3.1.2",
"camelcase": "^6.3.0",
"chalk": "^5.0.1",
"chalk": "^5.0.0",
"check-node-version": "^4.2.1",
"cloudflare-middleware": "^1.0.4",
"config": "^3.3.7",
"cross-env": "^7.0.3",
"decamelize": "^3.2.0",
"emojic": "^1.1.17",
"emojic": "^1.1.16",
"escape-string-regexp": "^4.0.0",
"fast-xml-parser": "^4.0.7",
"glob": "^8.0.3",
"fast-xml-parser": "^4.0.2",
"glob": "^7.2.0",
"global-agent": "^3.0.0",
"got": "^12.1.0",
"got": "^12.0.1",
"graphql": "^15.6.1",
"graphql-tag": "^2.12.6",
"ioredis": "5.0.5",
"ioredis": "4.28.4",
"joi": "17.6.0",
"joi-extension-semver": "5.0.0",
"js-yaml": "^4.1.0",
@@ -51,17 +50,17 @@
"lodash.countby": "^4.6.0",
"lodash.groupby": "^4.6.0",
"lodash.times": "^4.3.2",
"moment": "^2.29.3",
"moment": "^2.29.1",
"node-env-flag": "^0.1.0",
"parse-link-header": "^2.0.0",
"path-to-regexp": "^6.2.1",
"pretty-bytes": "^6.0.0",
"path-to-regexp": "^6.2.0",
"pretty-bytes": "^5.6.0",
"priorityqueuejs": "^2.0.0",
"prom-client": "^14.0.1",
"qs": "^6.10.3",
"query-string": "^7.1.1",
"semver": "~7.3.7",
"simple-icons": "6.23.0",
"semver": "~7.3.5",
"simple-icons": "6.8.0",
"webextension-store-meta": "^1.0.5",
"xmldom": "~0.6.0",
"xpath": "~0.0.32"
@@ -141,88 +140,88 @@
]
},
"devDependencies": {
"@babel/core": "^7.18.2",
"@babel/core": "^7.17.0",
"@babel/polyfill": "^7.12.1",
"@babel/register": "7.17.7",
"@babel/register": "7.17.0",
"@istanbuljs/schema": "^0.1.3",
"@mapbox/react-click-to-select": "^2.2.1",
"@types/chai": "^4.3.1",
"@types/lodash.debounce": "^4.0.7",
"@types/lodash.groupby": "^4.6.7",
"@types/mocha": "^9.1.1",
"@types/chai": "^4.3.0",
"@types/lodash.debounce": "^4.0.6",
"@types/lodash.groupby": "^4.6.6",
"@types/mocha": "^9.1.0",
"@types/node": "^16.7.10",
"@types/react-helmet": "^6.1.5",
"@types/react-modal": "^3.13.1",
"@types/react-select": "^4.0.17",
"@types/styled-components": "5.1.25",
"@typescript-eslint/eslint-plugin": "^5.26.0",
"@typescript-eslint/parser": "^5.15.0",
"@types/styled-components": "5.1.22",
"@typescript-eslint/eslint-plugin": "^5.10.2",
"@typescript-eslint/parser": "^5.10.0",
"babel-plugin-inline-react-svg": "^2.0.1",
"babel-preset-gatsby": "^2.14.0",
"c8": "^7.11.3",
"caller": "^1.1.0",
"babel-preset-gatsby": "^2.5.1",
"c8": "^7.11.0",
"caller": "^1.0.1",
"chai": "^4.3.6",
"chai-as-promised": "^7.1.1",
"chai-datetime": "^1.8.0",
"chai-string": "^1.4.0",
"child-process-promise": "^2.2.1",
"clipboard-copy": "^4.0.1",
"concurrently": "^7.2.1",
"cypress": "^9.7.0",
"danger": "^11.0.7",
"concurrently": "^7.0.0",
"cypress": "^9.4.1",
"danger": "^11.0.2",
"danger-plugin-no-test-shortcuts": "^2.0.0",
"deepmerge": "^4.2.2",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.5.0",
"eslint-config-prettier": "^8.3.0",
"eslint-config-standard": "^16.0.3",
"eslint-config-standard-jsx": "^10.0.0",
"eslint-config-standard-react": "^11.0.1",
"eslint-plugin-chai-friendly": "^0.7.2",
"eslint-plugin-cypress": "^2.12.1",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsdoc": "^39.3.2",
"eslint-plugin-mocha": "^10.0.5",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-jsdoc": "^37.7.1",
"eslint-plugin-mocha": "^10.0.3",
"eslint-plugin-no-extension-in-require": "^0.2.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^5.2.0",
"eslint-plugin-react": "^7.30.0",
"eslint-plugin-react-hooks": "^4.5.0",
"eslint-plugin-promise": "^6.0.0",
"eslint-plugin-react": "^7.28.0",
"eslint-plugin-react-hooks": "^4.3.0",
"eslint-plugin-sort-class-members": "^1.14.1",
"fetch-ponyfill": "^7.1.0",
"form-data": "^4.0.0",
"gatsby": "4.6.2",
"gatsby-plugin-catch-links": "^4.11.0",
"gatsby-plugin-page-creator": "^4.7.0",
"gatsby-plugin-react-helmet": "^5.10.0",
"gatsby-plugin-remove-trailing-slashes": "^4.9.0",
"gatsby-plugin-styled-components": "^5.11.0",
"gatsby-plugin-typescript": "^4.11.1",
"gatsby-plugin-catch-links": "^4.5.0",
"gatsby-plugin-page-creator": "^4.3.0",
"gatsby-plugin-react-helmet": "^5.2.0",
"gatsby-plugin-remove-trailing-slashes": "^4.2.0",
"gatsby-plugin-styled-components": "^5.2.0",
"gatsby-plugin-typescript": "^4.2.0",
"humanize-string": "^2.1.0",
"icedfrisby": "4.0.0",
"icedfrisby-nock": "^2.1.0",
"is-svg": "^4.3.2",
"js-yaml-loader": "^1.2.2",
"jsdoc": "^3.6.10",
"lint-staged": "^12.4.2",
"lint-staged": "^12.3.3",
"lodash.debounce": "^4.0.8",
"lodash.difference": "^4.5.0",
"minimist": "^1.2.6",
"mocha": "^9.2.2",
"minimist": "^1.2.5",
"mocha": "^9.2.0",
"mocha-env-reporter": "^4.0.0",
"mocha-junit-reporter": "^2.0.2",
"mocha-yaml-loader": "^1.0.3",
"nock": "13.2.4",
"node-mocks-http": "^1.11.0",
"nodemon": "^2.0.16",
"nodemon": "^2.0.15",
"npm-run-all": "^4.1.5",
"open-cli": "^7.0.1",
"portfinder": "^1.0.28",
"prettier": "2.6.2",
"prettier": "2.5.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-error-overlay": "^6.0.11",
"react-error-overlay": "^6.0.10",
"react-helmet": "^6.1.0",
"react-modal": "^3.15.1",
"react-modal": "^3.14.4",
"react-pose": "^4.0.10",
"react-select": "^4.3.1",
"read-all-stdin-sync": "^1.0.5",
@@ -230,19 +229,19 @@
"rimraf": "^3.0.2",
"sazerac": "^2.0.0",
"simple-git-hooks": "^2.7.0",
"sinon": "^14.0.0",
"sinon": "^13.0.1",
"sinon-chai": "^3.7.0",
"snap-shot-it": "^7.9.6",
"start-server-and-test": "1.14.0",
"styled-components": "^5.3.5",
"ts-mocha": "^10.0.0",
"tsd": "^0.20.0",
"typescript": "^4.7.2",
"styled-components": "^5.3.3",
"ts-mocha": "^9.0.2",
"tsd": "^0.19.1",
"typescript": "^4.5.5",
"url": "^0.11.0"
},
"engines": {
"node": ">=16.13.0",
"npm": ">=8.0.0"
"node": "^16.13.0",
"npm": ">=7.0.0"
},
"type": "module",
"collective": {

View File

@@ -21,7 +21,7 @@ class BaseAmoService extends BaseJsonService {
async fetch({ addonId }) {
return this._requestJson({
schema,
url: `https://addons.mozilla.org/api/v4/addons/addon/${addonId}/`,
url: `https://addons.mozilla.org/api/v3/addons/addon/${addonId}`,
})
}
}

View File

@@ -24,8 +24,6 @@ class AmoWeeklyDownloads extends BaseAmoService {
},
]
static _cacheLength = 21600
static defaultBadgeData = { label: 'downloads' }
static render({ downloads }) {

View File

@@ -23,8 +23,6 @@ export default class AmoRating extends BaseAmoService {
},
]
static _cacheLength = 7200
static render({ format, rating }) {
rating = Math.round(rating)
return {

View File

@@ -14,8 +14,6 @@ export default class AmoUsers extends BaseAmoService {
},
]
static _cacheLength = 21600
static defaultBadgeData = { label: 'users' }
static render({ users: downloads }) {

View File

@@ -21,8 +21,8 @@ export default class Bitrise extends BaseJsonService {
static examples = [
{
title: 'Bitrise',
namedParams: { appId: '3ff11fe8457bd304', branch: 'master' },
queryParams: { token: 'lESRN9rEFFfDq92JtXs_jw' },
namedParams: { appId: 'cde737473028420d', branch: 'master' },
queryParams: { token: 'GCIdEzacE4GW32jLVrZb7A' },
staticPreview: this.render({ status: 'success' }),
},
]

View File

@@ -3,14 +3,14 @@ import { createServiceTester } from '../tester.js'
export const t = await createServiceTester()
t.create('deploy status')
.get('/3ff11fe8457bd304.json?token=lESRN9rEFFfDq92JtXs_jw')
.get('/cde737473028420d.json?token=GCIdEzacE4GW32jLVrZb7A')
.expectBadge({
label: 'bitrise',
message: isBuildStatus,
})
t.create('deploy status with branch')
.get('/3ff11fe8457bd304/master.json?token=lESRN9rEFFfDq92JtXs_jw')
.get('/cde737473028420d/master.json?token=GCIdEzacE4GW32jLVrZb7A')
.expectBadge({
label: 'bitrise',
message: isBuildStatus,

View File

@@ -1,13 +1,13 @@
import Joi from 'joi'
import { renderVersionBadge } from '../version.js'
import { InvalidResponse } from '../index.js'
import { InvalidResponse, redirector } from '../index.js'
import BaseBowerService from './bower-base.js'
const queryParamSchema = Joi.object({
include_prereleases: Joi.equal(''),
}).required()
export default class BowerVersion extends BaseBowerService {
class BowerVersion extends BaseBowerService {
static category = 'version'
static route = { base: 'bower/v', pattern: ':packageName', queryParamSchema }
@@ -47,3 +47,18 @@ export default class BowerVersion extends BaseBowerService {
return renderVersionBadge({ version })
}
}
const BowerVersionRedirect = redirector({
category: 'version',
route: {
base: 'bower/vpre',
pattern: ':packageName',
},
transformPath: ({ packageName }) => `/bower/v/${packageName}`,
transformQueryParams: params => ({
include_prereleases: null,
}),
dateAdded: new Date('2019-12-15'),
})
export { BowerVersion, BowerVersionRedirect }

View File

@@ -4,7 +4,7 @@ import nock from 'nock'
import { cleanUpNockAfterEach, defaultContext } from '../test-helpers.js'
import { InvalidResponse } from '../index.js'
import LibrariesIoApiProvider from '../librariesio/librariesio-api-provider.js'
import BowerVersion from './bower-version.service.js'
import { BowerVersion } from './bower-version.service.js'
describe('BowerVersion', function () {
test(BowerVersion.transform, () => {

View File

@@ -33,3 +33,7 @@ t.create('Pre Version for Invalid Package')
.timeout(10000)
.get('/v/it-is-a-invalid-package-should-error.json?include_prereleases')
.expectBadge({ label: 'bower', message: 'package not found' })
t.create('Version (legacy redirect: vpre)')
.get('/vpre/bootstrap.svg')
.expectRedirect('/bower/v/bootstrap.svg?include_prereleases')

View File

@@ -1,9 +1,3 @@
/**
* Common functions and schemas for tasks related to build status.
*
* @module
*/
import Joi from 'joi'
const greenStatuses = [
@@ -56,23 +50,8 @@ const allStatuses = greenStatuses
.concat(redStatuses)
.concat(otherStatuses)
/**
* Joi schema for validating Build Status.
* Checks if the build status is present in the list of allowed build status.
*
* @type {object}
*/
const isBuildStatus = Joi.equal(...allStatuses)
/**
* Handles rendering concerns of badges that display build status.
* Determines the message and color of the badge according to the build status.
*
* @param {object} attrs Refer to individual attributes
* @param {string} [attrs.label] If provided then badge label is set to this value
* @param {string} attrs.status Build status
* @returns {object} Badge with label, message and color properties
*/
function renderBuildStatusBadge({ label, status }) {
let message
let color

View File

@@ -3,7 +3,7 @@ import { createServiceFamily } from '../nuget/nuget-v2-service-family.js'
export default createServiceFamily({
defaultLabel: 'chocolatey',
serviceBaseUrl: 'chocolatey',
apiBaseUrl: 'https://community.chocolatey.org/api/v2',
apiBaseUrl: 'https://www.chocolatey.org/api/v2',
odataFormat: 'json',
title: 'Chocolatey',
examplePackageName: 'git',

View File

@@ -26,29 +26,31 @@ export default class Cirrus extends BaseJsonService {
title: 'Cirrus CI - Base Branch Build Status',
namedParams: { user: 'flutter', repo: 'flutter' },
pattern: 'github/:user/:repo',
queryParams: { task: 'analyze', script: 'test' },
staticPreview: this.render({ status: 'passing' }),
},
{
title: 'Cirrus CI - Specific Branch Build Status',
pattern: 'github/:user/:repo/:branch',
namedParams: { user: 'flutter', repo: 'flutter', branch: 'master' },
queryParams: { task: 'analyze', script: 'test' },
staticPreview: this.render({ status: 'passing' }),
},
{
title: 'Cirrus CI - Specific Task Build Status',
pattern: 'github/:user/:repo',
queryParams: { task: 'build_docker' },
namedParams: { user: 'flutter', repo: 'cocoon' },
staticPreview: this.render({
subject: 'build_docker',
status: 'passing',
}),
queryParams: { task: 'analyze' },
namedParams: { user: 'flutter', repo: 'flutter' },
staticPreview: this.render({ subject: 'analyze', status: 'passing' }),
},
{
title: 'Cirrus CI - Task and Script Build Status',
pattern: 'github/:user/:repo',
queryParams: { task: 'build_docker', script: 'test' },
namedParams: { user: 'flutter', repo: 'cocoon' },
queryParams: { task: 'analyze', script: 'test' },
namedParams: {
user: 'flutter',
repo: 'flutter',
},
staticPreview: this.render({ subject: 'test', status: 'passing' }),
},
]

View File

@@ -138,19 +138,15 @@ export default class CodeclimateAnalysis extends BaseJsonService {
}
async fetch({ user, repo }) {
const repoInfos = await fetchRepo(this, { user, repo })
const repoInfosWithSnapshot = repoInfos.filter(
repoInfo => repoInfo.relationships.latest_default_branch_snapshot.data
)
if (repoInfosWithSnapshot.length === 0) {
throw new NotFound({ prettyMessage: 'snapshot not found' })
}
const {
id: repoId,
relationships: {
latest_default_branch_snapshot: { data: snapshotInfo },
},
} = repoInfosWithSnapshot[0]
} = await fetchRepo(this, { user, repo })
if (snapshotInfo === null) {
throw new NotFound({ prettyMessage: 'snapshot not found' })
}
const { data } = await this._requestJson({
schema,
url: `https://api.codeclimate.com/v1/repos/${repoId}/snapshots/${snapshotInfo.id}`,

View File

@@ -32,47 +32,6 @@ t.create('maintainability letter')
message: Joi.equal('A', 'B', 'C', 'D', 'E', 'F'),
})
t.create('issues when outer user repos query returns multiple items')
.get('/issues/angular/angular.json')
.intercept(nock =>
nock('https://api.codeclimate.com', { allowUnmocked: true })
.get('/v1/repos?github_slug=angular%2Fangular')
.reply(200, {
data: [
{
id: '54fd4e6b6956804a10003df4',
relationships: {
latest_default_branch_snapshot: {
data: null,
},
latest_default_branch_test_report: {
data: null,
},
},
},
{
id: '54fd4e6b6956804a10003df3',
relationships: {
latest_default_branch_snapshot: {
data: {
id: '620e2b491b6a72000100ca1d',
type: 'snapshots',
},
},
latest_default_branch_test_report: {
data: null,
},
},
},
],
})
)
.networkOn() // Combined with allowUnmocked: true, this allows the inner snapshots query to go through.
.expectBadge({
label: 'issues',
message: Joi.number().integer().positive(),
})
t.create('maintainability letter for non-existent repo')
.get('/maintainability/unknown/unknown.json')
.expectBadge({

View File

@@ -7,6 +7,7 @@ const isLetterGrade = Joi.equal('A', 'B', 'C', 'D', 'E', 'F').required()
const repoSchema = Joi.object({
data: Joi.array()
.max(1)
.items(
Joi.object({
id: Joi.string().required(),
@@ -28,15 +29,17 @@ const repoSchema = Joi.object({
}).required()
async function fetchRepo(serviceInstance, { user, repo }) {
const { data: repoInfos } = await serviceInstance._requestJson({
const {
data: [repoInfo],
} = await serviceInstance._requestJson({
schema: repoSchema,
url: 'https://api.codeclimate.com/v1/repos',
options: { searchParams: { github_slug: `${user}/${repo}` } },
})
if (repoInfos.length === 0) {
if (repoInfo === undefined) {
throw new NotFound({ prettyMessage: 'repo not found' })
}
return repoInfos
return repoInfo
}
export { keywords, isLetterGrade, fetchRepo }

View File

@@ -53,19 +53,15 @@ export default class CodeclimateCoverage extends BaseJsonService {
}
async fetch({ user, repo }) {
const repoInfos = await fetchRepo(this, { user, repo })
const repoInfosWithTestReport = repoInfos.filter(
repoInfo => repoInfo.relationships.latest_default_branch_test_report.data
)
if (repoInfosWithTestReport.length === 0) {
throw new NotFound({ prettyMessage: 'test report not found' })
}
const {
id: repoId,
relationships: {
latest_default_branch_test_report: { data: testReportInfo },
},
} = repoInfosWithTestReport[0]
} = await fetchRepo(this, { user, repo })
if (testReportInfo === null) {
throw new NotFound({ prettyMessage: 'test report not found' })
}
const { data } = await this._requestJson({
schema,
url: `https://api.codeclimate.com/v1/repos/${repoId}/test_reports/${testReportInfo.id}`,

View File

@@ -20,47 +20,6 @@ t.create('test coverage letter')
message: Joi.equal('A', 'B', 'C', 'D', 'E', 'F'),
})
t.create('test coverage when outer user repos query returns multiple items')
.get('/coverage/codeclimate/codeclimate.json')
.intercept(nock =>
nock('https://api.codeclimate.com', { allowUnmocked: true })
.get('/v1/repos?github_slug=codeclimate%2Fcodeclimate')
.reply(200, {
data: [
{
id: '558479d6e30ba034120008a8',
relationships: {
latest_default_branch_snapshot: {
data: null,
},
latest_default_branch_test_report: {
data: null,
},
},
},
{
id: '558479d6e30ba034120008a9',
relationships: {
latest_default_branch_snapshot: {
data: null,
},
latest_default_branch_test_report: {
data: {
id: '62110434a7160b00010b4b59',
type: 'test_reports',
},
},
},
},
],
})
)
.networkOn() // Combined with allowUnmocked: true, this allows the inner test reports query to go through.
.expectBadge({
label: 'coverage',
message: isIntegerPercentage,
})
t.create('test coverage percentage for non-existent repo')
.get('/coverage/unknown/unknown.json')
.expectBadge({

View File

@@ -1,19 +1,9 @@
/**
* Commonly-used functions for determining the colour to use for a badge,
* including colours based off download count, version number, etc.
*
* @module
*/
import moment from 'moment'
import pep440 from '@renovate/pep440'
/**
* Determines the color used for a badge based on version.
*
* @param {string|number} version Version used for determining badge color
* @returns {string} Badge color
*/
function version(version) {
if (typeof version !== 'string' && typeof version !== 'number') {
throw new Error(`Can't generate a version color for ${version}`)
@@ -30,35 +20,6 @@ function version(version) {
}
}
/**
* Determines the color used for a badge based on PEP440 versioning.
*
* @param {string|number} version Version used for determining badge color
* @returns {string} Badge color
*/
function pep440VersionColor(version) {
if (!pep440.valid(version)) {
return 'lightgrey'
}
const parsedVersion = pep440.explain(version)
if (parsedVersion.is_prerelease || parsedVersion.public.startsWith('0.')) {
return 'orange'
}
return 'blue'
}
/**
* Determines the color used for a badge by comparing the value and floor count values.
* The color can vary from red to bright green depending on the range the value lies in.
* Decreasing the value will shift the color towards red.
* Increasing the value will shift the color towards bright green.
*
* @param {number} value Current value
* @param {number} yellow Yellow color threshold, should be greater than 0
* @param {number} yellowgreen Yellowgreen color threshold, should be greater than yellow
* @param {number} green Green color threshold, should be greater than yellowgreen
* @returns {string} Badge color
*/
function floorCount(value, yellow, yellowgreen, green) {
if (value <= 0) {
return 'red'
@@ -73,37 +34,14 @@ function floorCount(value, yellow, yellowgreen, green) {
}
}
/**
* Determines the color used for a badge by comparing the download count and floor values.
* The color varies from red to bright green as the download count increases.
*
* @param {number} downloads Download count
* @returns {string} Badge color
*/
function downloadCount(downloads) {
return floorCount(downloads, 10, 100, 1000)
}
/**
* Determines the color used for a badge by comparing percentage and floor values.
* The color varies from red to bright green as the percentage increases.
*
* @param {number} percentage Percentage value
* @returns {string} Badge color
*/
function coveragePercentage(percentage) {
return floorCount(percentage, 80, 90, 100)
}
/**
* Determines the color used for a badge by matching score with grade values.
* The color varies from bright green to red as the score decreases.
* The score can be one of the following grade value: ['A', 'B', 'C', 'D', 'E'].
* The color defaults to red if the score does not matches with any of the grade values.
*
* @param {string} score Score value
* @returns {string} Badge color
*/
function letterScore(score) {
if (score === 'A') {
return 'brightgreen'
@@ -120,18 +58,6 @@ function letterScore(score) {
}
}
/**
* Creates a callback function that determines badge color from the colors array.
* If the colors array is provided then for n steps, there should be n + 1 color.
* If the colors array is not provided then it is chosen from the default colors array
* according to the size of the steps array.
*
* @param {number[]} steps Steps array
* @param {string[]} colors Colors array. If provided, should be of length steps.length + 1
* @param {boolean} reversed If true then the colors array will be considered in reverse order
* @returns {function(number): string} Function that finds the step index by comparing value
* with steps array and returns color from colors array for the corresponding step index
*/
function colorScale(steps, colors, reversed) {
if (steps === undefined) {
throw Error('When invoking colorScale, steps should be provided.')
@@ -172,14 +98,6 @@ function colorScale(steps, colors, reversed) {
}
}
/**
* Determines the color used for a badge according to the age.
* Age is calculated as days elapsed till current date.
* The color varies from bright green to red as the age increases.
*
* @param {string} date Date string
* @returns {string} Badge color
*/
function age(date) {
const colorByAge = colorScale([7, 30, 180, 365, 730], undefined, true)
const daysElapsed = moment().diff(moment(date), 'days')
@@ -188,7 +106,6 @@ function age(date) {
export {
version,
pep440VersionColor,
downloadCount,
coveragePercentage,
floorCount,

View File

@@ -6,7 +6,6 @@ import {
letterScore,
age,
version,
pep440VersionColor,
} from './color-formatters.js'
describe('Color formatters', function () {
@@ -107,45 +106,4 @@ describe('Color formatters', function () {
"Can't generate a version color for [object Object]"
)
})
test(pep440VersionColor, () => {
forCases([
given('1.0.1'),
given('v2.1.6'),
given('1.0.1+abcd'),
given('1.0'),
given('v1'),
given(9),
given(1.0),
]).expect('blue')
forCases([
given('1.0.1-rc1'),
given('1.0.1rc1'),
given('1.0.0-Beta'),
given('1.0.0Beta'),
given('1.1.0-alpha'),
given('1.1.0alpha'),
given('1.0.1-dev'),
given('1.0.1dev'),
given('2.1.6-b1'),
given('2.1.6b1'),
given('0.1.0'),
given('v0.1.0'),
given('v2.1.6-b1'),
given('0.1.0+abcd'),
given('2.1.6-b1+abcd'),
given('0.0.0'),
given(0.1),
given('0.9'),
]).expect('orange')
forCases([
given('6.0.0-SNAPSHOT'),
given('2.1.6-prerelease'),
given(true),
given(null),
given('cheese'),
]).expect('lightgrey')
})
})

View File

@@ -1,21 +0,0 @@
import yaml from 'js-yaml'
import { NotFound, InvalidResponse } from '../index.js'
import { latest } from '../version.js'
export function parseLatestVersionFromConfig(configYaml) {
let versions
try {
const config = yaml.load(configYaml)
versions = Object.keys(config.versions)
} catch (err) {
throw new InvalidResponse({
prettyMessage: 'invalid config.yml',
underlyingError: err,
})
}
const version = latest(versions)
if (version == null) {
throw new NotFound({ prettyMessage: 'no versions found' })
}
return version
}

View File

@@ -1,33 +0,0 @@
import { expect } from 'chai'
import { NotFound, InvalidResponse } from '../index.js'
import { parseLatestVersionFromConfig } from './conan-version-helpers.js'
describe('parseLatestVersionFromConfig', function () {
it('returns latest available version', function () {
expect(
parseLatestVersionFromConfig(`
versions:
1.68.0:
folder: all
1.70.0:
folder: all
1.69.0:
folder: all
`)
).to.equal('1.70.0')
})
it('rejects invalid yaml', function () {
expect(() => parseLatestVersionFromConfig('[')).to.throw(InvalidResponse)
})
it('treats no results array as invalid', function () {
expect(() =>
parseLatestVersionFromConfig('somethingElse: whatever')
).to.throw(InvalidResponse)
})
it('treats empty results array as not found', function () {
expect(() => parseLatestVersionFromConfig('versions: []')).to.throw(
NotFound
)
})
})

View File

@@ -1,34 +0,0 @@
import { renderVersionBadge } from '../version.js'
import { ConditionalGithubAuthV3Service } from '../github/github-auth-service.js'
import { fetchRepoContent } from '../github/github-common-fetch.js'
import { parseLatestVersionFromConfig } from './conan-version-helpers.js'
export default class ConanVersion extends ConditionalGithubAuthV3Service {
static category = 'version'
static route = { base: 'conan/v', pattern: ':packageName' }
static examples = [
{
title: 'Conan Center',
namedParams: { packageName: 'boost' },
staticPreview: renderVersionBadge({ version: '1.78.0' }),
keywords: ['c++'],
},
]
static defaultBadgeData = { label: 'conan' }
async handle({ packageName }) {
const configContent = await fetchRepoContent(this, {
user: 'conan-io',
repo: 'conan-center-index',
branch: 'master',
filename: `recipes/${packageName}/config.yml`,
})
const version = parseLatestVersionFromConfig(configContent)
return renderVersionBadge({ version })
}
}

View File

@@ -1,17 +0,0 @@
import { isSemver } from '../test-validators.js'
import { createServiceTester } from '../tester.js'
export const t = await createServiceTester()
t.create('gets the package version of zeromq')
.get('/zeromq.json')
.expectBadge({ label: 'conan', message: isSemver })
t.create('returns not found for invalid package')
.get('/this package does not exist - shields test.json')
.expectBadge({
label: 'conan',
color: 'red',
message:
'repo not found, branch not found, or recipes/this package does not exist - shields test/config.yml missing',
})

View File

@@ -1,18 +1,5 @@
/**
* Common functions and utilities for tasks related to contributor count.
*
* @module
*/
import { metric } from './text-formatters.js'
/**
* Determines the color used for a badge based on the contributor count.
* The color varies from red to bright green as the contributor count increases.
*
* @param {number} contributorCount Contributor count
* @returns {string} Badge color
*/
function contributorColor(contributorCount) {
if (contributorCount > 2) {
return 'brightgreen'
@@ -23,15 +10,6 @@ function contributorColor(contributorCount) {
}
}
/**
* Handles rendering concerns of badges that display contributor count.
* Determines the message and color of the badge according to the contributor count.
*
* @param {object} attrs Refer to individual attributes
* @param {string} [attrs.label] If provided then badge label is set to this value
* @param {number} attrs.contributorCount Contributor count
* @returns {object} Badge with label, message and color properties
*/
function renderContributorBadge({ label, contributorCount }) {
return {
label,

View File

@@ -0,0 +1,9 @@
import { Deprecated } from './index.js'
function enforceDeprecation(effectiveDate) {
if (Date.now() >= effectiveDate.getTime()) {
throw new Deprecated()
}
}
export { enforceDeprecation }

View File

@@ -0,0 +1,15 @@
import { expect } from 'chai'
import { Deprecated } from '../core/base-service/errors.js'
import { enforceDeprecation } from './deprecation-helpers.js'
describe('enforceDeprecation', function () {
it('throws Deprecated for a date in the past', function () {
expect(() => enforceDeprecation(new Date())).to.throw(Deprecated)
})
it('does not throw for a date in the future', function () {
expect(() =>
enforceDeprecation(new Date(Date.now() + 10000))
).not.to.throw()
})
})

View File

@@ -52,7 +52,9 @@ export default class DocsRs extends BaseJsonService {
}
async handle({ crate, version = 'latest' }) {
const [{ build_status: buildStatus }] = await this.fetch({ crate, version })
const { build_status: buildStatus } = (
await this.fetch({ crate, version })
).pop()
return this.constructor.render({ version, buildStatus })
}
}

View File

@@ -10,10 +10,6 @@ t.create('Failing docs')
.get('/tensorflow/0.16.1.json')
.expectBadge({ label: 'docs@0.16.1', message: 'failing' })
t.create('Multiple builds, latest passing')
.get('/bevy_tweening/0.3.1.json')
.expectBadge({ label: 'docs@0.3.1', message: 'passing' })
t.create('Getting latest version works')
.get('/rand/latest.json')
.expectBadge({

View File

@@ -1,33 +0,0 @@
import Joi from 'joi'
import { BaseJsonService } from '../index.js'
import { renderDownloadsBadge } from '../downloads.js'
const schema = Joi.object({
installs_total: Joi.number().integer().required(),
}).required()
export default class FlathubDownloads extends BaseJsonService {
static category = 'downloads'
static route = { base: 'flathub/downloads', pattern: ':packageName' }
static examples = [
{
title: 'Flathub',
namedParams: {
packageName: 'org.mozilla.firefox',
},
staticPreview: renderDownloadsBadge({ downloads: '277136' }),
},
]
static defaultBadgeData = { label: 'installs' }
async handle({ packageName }) {
const data = await this._requestJson({
schema,
url: `https://flathub.org/api/v2/stats/${encodeURIComponent(
packageName
)}`,
})
return renderDownloadsBadge({ downloads: data.installs_total })
}
}

View File

@@ -1,14 +0,0 @@
import { isMetric } from '../test-validators.js'
import { createServiceTester } from '../tester.js'
export const t = await createServiceTester()
t.create('Flathub Downloads (valid)')
.get('/org.mozilla.firefox.json')
.expectBadge({
label: 'installs',
message: isMetric,
})
t.create('Flathub Downloads (not found)')
.get('/not.a.package.json')
.expectBadge({ label: 'installs', message: 'not found' })

View File

@@ -1,6 +1,5 @@
import Joi from 'joi'
import { floorCount as floorCountColor } from '../color-formatters.js'
import { metric } from '../text-formatters.js'
import { BaseJsonService } from '../index.js'
const ownerSchema = Joi.array().required()
@@ -21,7 +20,7 @@ export default class GemOwner extends BaseJsonService {
static render({ count }) {
return {
message: metric(count),
message: count,
color: floorCountColor(count, 10, 50, 100),
}
}

View File

@@ -2,17 +2,7 @@ import Joi from 'joi'
import { renderContributorBadge } from '../contributor-count.js'
import { ConditionalGithubAuthV3Service } from './github-auth-service.js'
import { fetchJsonFromRepo } from './github-common-fetch.js'
import { documentation as commonDocumentation } from './github-helpers.js'
const documentation = `
<p>
The All Contributors service allows you to recognize all your project
contributors, including those that don't push code. See
<a href="https://allcontributors.org">https://allcontributors.org</a>
for more information.
</p>
${commonDocumentation}
`
import { documentation } from './github-helpers.js'
const schema = Joi.object({
contributors: Joi.array().required(),
@@ -27,7 +17,7 @@ export default class GithubAllContributorsService extends ConditionalGithubAuthV
static examples = [
{
title: 'GitHub contributors (via allcontributors.org)',
title: 'Github All Contributors',
namedParams: {
repo: 'all-contributors',
user: 'all-contributors',

View File

@@ -77,7 +77,8 @@ class GithubApiProvider {
}
getV4RateLimitFromBody(body) {
const b = Joi.attempt(body, bodySchema)
const parsedBody = JSON.parse(body)
const b = Joi.attempt(parsedBody, bodySchema)
return {
rateLimit: b.data.rateLimit.limit,
totalUsesRemaining: b.data.rateLimit.remaining,
@@ -89,17 +90,8 @@ class GithubApiProvider {
let rateLimit, totalUsesRemaining, nextReset
if (url.startsWith('/graphql')) {
try {
const parsedBody = JSON.parse(res.body)
if ('message' in parsedBody && !('data' in parsedBody)) {
if (parsedBody.message === 'Sorry. Your account was suspended.') {
this.invalidateToken(token)
return
}
}
;({ rateLimit, totalUsesRemaining, nextReset } =
this.getV4RateLimitFromBody(parsedBody))
this.getV4RateLimitFromBody(res.body))
} catch (e) {
console.error(
`Could not extract rate limit info from response body ${res.body}`

View File

@@ -126,35 +126,14 @@ describe('Github API provider', function () {
})
})
context('unauthorized API responses', function () {
it('should invoke the callback and update the token with the expected values (unauthorized, v3)', async function () {
context('an unauthorized response', function () {
it('should invoke the callback and update the token with the expected values', async function () {
const mockResponse = { res: { statusCode: 401, headers: {} } }
const mockRequest = sinon.stub().resolves(mockResponse)
await provider.fetch(mockRequest, '/foo', {})
expect(mockStandardToken.invalidate).to.have.been.calledOnce
expect(mockStandardToken.update).not.to.have.been.called
})
it('should invoke the callback and update the token with the expected values (unauthorized, v4)', async function () {
const mockResponse = { res: { statusCode: 401, body: {} } }
const mockRequest = sinon.stub().resolves(mockResponse)
await provider.fetch(mockRequest, '/graphql', {})
expect(mockGraphqlToken.invalidate).to.have.been.calledOnce
expect(mockGraphqlToken.update).not.to.have.been.called
})
it('should invoke the callback and update the token with the expected values (suspended, v4)', async function () {
const mockResponse = {
res: {
statusCode: 200,
body: '{ "message": "Sorry. Your account was suspended." }',
},
}
const mockRequest = sinon.stub().resolves(mockResponse)
await provider.fetch(mockRequest, '/graphql', {})
expect(mockGraphqlToken.invalidate).to.have.been.calledOnce
expect(mockGraphqlToken.update).not.to.have.been.called
})
})
context('a connection error', function () {

View File

@@ -58,7 +58,7 @@ export default class GithubDeployments extends GithubAuthV4Service {
environment: 'shields-staging',
},
staticPreview: this.render({
state: 'SUCCESS',
state: 'success',
}),
documentation,
},

View File

@@ -140,26 +140,6 @@ const ageUpdateMap = {
}),
}
const milestoneMap = {
schema: Joi.object({
...commonSchemaFields,
milestone: Joi.object({
title: Joi.string().required(),
}).allow(null),
}).required(),
transform: ({ json }) => {
if (!json.milestone) {
throw new InvalidResponse({ prettyMessage: 'no milestone' })
}
return json.milestone.title
},
render: ({ value }) => ({
label: 'milestone',
message: value,
color: 'informational',
}),
}
const propertyMap = {
state: stateMap,
title: titleMap,
@@ -168,7 +148,6 @@ const propertyMap = {
comments: commentsMap,
age: ageUpdateMap,
'last-update': ageUpdateMap,
milestone: milestoneMap,
}
export default class GithubIssueDetail extends GithubAuthV3Service {
@@ -176,7 +155,7 @@ export default class GithubIssueDetail extends GithubAuthV3Service {
static route = {
base: 'github',
pattern:
':issueKind(issues|pulls)/detail/:property(state|title|author|label|comments|age|last-update|milestone)/:user/:repo/:number([0-9]+)',
':issueKind(issues|pulls)/detail/:property(state|title|author|label|comments|age|last-update)/:user/:repo/:number([0-9]+)',
}
static examples = [
@@ -203,7 +182,6 @@ export default class GithubIssueDetail extends GithubAuthV3Service {
'comments',
'age',
'last update',
'milestone',
],
documentation,
},

View File

@@ -90,14 +90,6 @@ describe('GithubIssueDetail', function () {
message: formatDate('2019-04-02T20:09:31Z'),
color: age('2019-04-02T20:09:31Z'),
})
given({
property: 'milestone',
value: 'MS 1',
}).expect({
label: 'milestone',
message: 'MS 1',
color: 'informational',
})
})
test(GithubIssueDetail.prototype.transform, () => {
@@ -186,13 +178,6 @@ describe('GithubIssueDetail', function () {
value: '2019-04-02T20:09:31Z',
isPR: false,
})
given({
property: 'milestone',
json: { milestone: { title: 'MS 1' } },
}).expect({
value: 'MS 1',
isPR: false,
})
})
context('transform()', function () {
@@ -209,19 +194,4 @@ describe('GithubIssueDetail', function () {
}
})
})
context('transform()', function () {
it('throws InvalidResponse error when issue has no milestone', function () {
try {
GithubIssueDetail.prototype.transform({
property: 'milestone',
json: { milestone: null },
})
expect.fail('Expected to throw')
} catch (e) {
expect(e).to.be.an.instanceof(InvalidResponse)
expect(e.prettyMessage).to.equal('no milestone')
}
})
})
})

View File

@@ -64,16 +64,3 @@ t.create('github pull request merge state (pull request not found)')
label: 'issue/pull request',
message: 'issue, pull request or repo not found',
})
t.create('github issue milestone')
.get('/issues/detail/milestone/badges/shields/4949.json')
.expectBadge({
label: 'milestone',
message: 'badge-maker v3.4',
})
t.create('github issue milestone (without milestone)')
.get('/issues/detail/milestone/badges/shields/979.json')
.expectBadge({
message: 'no milestone',
})

View File

@@ -307,9 +307,7 @@ export default class GithubIssues extends GithubAuthV4Service {
return {
label: `${labelPrefix}${labelText}${labelSuffix}`,
message: `${metric(issueCount)}${
messageSuffix ? ' ' : ''
}${messageSuffix}`,
message: `${metric(issueCount)} ${messageSuffix}`,
color: issueCount > 0 ? 'yellow' : 'brightgreen',
}
}

View File

@@ -1,4 +1,3 @@
import { metric } from '../text-formatters.js'
import { BaseGithubLanguage } from './github-languages-base.js'
import { documentation } from './github-helpers.js'
@@ -21,7 +20,7 @@ export default class GithubLanguageCount extends BaseGithubLanguage {
static render({ count }) {
return {
message: metric(count),
message: count,
color: 'blue',
}
}

View File

@@ -75,7 +75,7 @@ export default class GithubMilestoneDetail extends GithubAuthV3Service {
}
return {
label: `${milestone.title}${label ? ' ' : ''}${label}`,
label: `${milestone.title} ${label}`,
message: metric(milestoneMetric),
color,
}

View File

@@ -43,7 +43,7 @@ export default class GithubMilestone extends GithubAuthV3Service {
static render({ user, repo, variant, milestones }) {
const milestoneLength = milestones.length
let color
let qualifier = ''
let label = ''
switch (variant) {
case 'all':
@@ -51,16 +51,16 @@ export default class GithubMilestone extends GithubAuthV3Service {
break
case 'open':
color = 'red'
qualifier = 'active'
label = 'active'
break
case 'closed':
color = 'green'
qualifier = 'completed'
label = 'completed'
break
}
return {
label: `${qualifier}${qualifier ? ' ' : ''}milestones`,
label: `${label} milestones`,
message: metric(milestoneLength),
color,
}

View File

@@ -1,4 +1,3 @@
import { pep440VersionColor } from '../color-formatters.js'
import { renderVersionBadge } from '../version.js'
import { isLockfile, getDependencyVersion } from '../pipenv-helpers.js'
import { addv } from '../text-formatters.js'
@@ -81,7 +80,6 @@ class GithubPipenvLockedPythonVersion extends ConditionalGithubAuthV3Service {
version,
tag: branch,
defaultLabel: 'python',
versionFormatter: pep440VersionColor,
})
}
@@ -149,7 +147,7 @@ class GithubPipenvLockedDependencyVersion extends ConditionalGithubAuthV3Service
return {
label: dependency,
message: version ? addv(version) : ref,
color: version ? pep440VersionColor(version) : 'blue',
color: 'blue',
}
}

View File

@@ -82,8 +82,10 @@ t.create('Locked version of unknown dependency')
})
t.create('Locked version of VCS dependency')
.get('/locked/dependency-version/GSS-Cogs/databaker-docker/databaker.json')
.get(
'/locked/dependency-version/DemocracyClub/aggregator-api/dc-base-theme.json'
)
.expectBadge({
label: 'databaker',
label: 'dc-base-theme',
message: isShortSha,
})

View File

@@ -1,7 +1,7 @@
import Joi from 'joi'
import { renderDownloadsBadge } from '../downloads.js'
import { maybePluralize } from '../text-formatters.js'
import { renderVersionBadge } from '../version.js'
import { addv, maybePluralize } from '../text-formatters.js'
import { version as versionColor } from '../color-formatters.js'
import { BaseJsonService } from '../index.js'
const hexSchema = Joi.object({
@@ -14,8 +14,7 @@ const hexSchema = Joi.object({
meta: Joi.object({
licenses: Joi.array().required(),
}).required(),
latest_stable_version: Joi.string(),
latest_version: Joi.string().required(),
latest_stable_version: Joi.string().required(),
}).required()
class BaseHexPmService extends BaseJsonService {
@@ -85,14 +84,12 @@ class HexPmVersion extends BaseHexPmService {
]
static render({ version }) {
return renderVersionBadge({ version })
return { message: addv(version), color: versionColor(version) }
}
async handle({ packageName }) {
const json = await this.fetch({ packageName })
return this.constructor.render({
version: json.latest_stable_version || json.latest_version,
})
return this.constructor.render({ version: json.latest_stable_version })
}
}

View File

@@ -1,10 +1,8 @@
import Joi from 'joi'
import { ServiceTester } from '../tester.js'
import {
isMetric,
isMetricOverTimePeriod,
isVPlusDottedVersionNClausesWithOptionalSuffix,
} from '../test-validators.js'
import { isMetric, isMetricOverTimePeriod } from '../test-validators.js'
const isHexpmVersion = Joi.string().regex(/^v\d+.\d+.?\d?$/)
export const t = new ServiceTester({ id: 'hexpm', title: 'Hex.pm' })
@@ -24,7 +22,6 @@ t.create('downloads (zero for period)')
.reply(200, {
downloads: { all: 100 }, // there is no 'day' key here
latest_stable_version: '1.0',
latest_version: '1.0',
meta: { licenses: ['MIT'] },
})
)
@@ -38,26 +35,9 @@ t.create('downloads (not found)')
.get('/dt/this-package-does-not-exist.json')
.expectBadge({ label: 'downloads', message: 'not found' })
t.create('version').get('/v/cowboy.json').expectBadge({
label: 'hex',
message: isVPlusDottedVersionNClausesWithOptionalSuffix,
})
t.create('version (no stable version)')
.get('/v/prima_opentelemetry_ex.json')
.intercept(nock =>
nock('https://hex.pm/')
.get('/api/packages/prima_opentelemetry_ex')
.reply(200, {
downloads: { all: 100 },
latest_version: '1.0.0-rc.3',
meta: { licenses: ['MIT'] },
})
)
.expectBadge({
label: 'hex',
message: isVPlusDottedVersionNClausesWithOptionalSuffix,
})
t.create('version')
.get('/v/cowboy.json')
.expectBadge({ label: 'hex', message: isHexpmVersion })
t.create('version (not found)')
.get('/v/this-package-does-not-exist.json')
@@ -77,7 +57,6 @@ t.create('license (multiple licenses)')
.reply(200, {
downloads: { all: 100 },
latest_stable_version: '1.0',
latest_version: '1.0',
meta: { licenses: ['GPLv2', 'MIT'] },
})
)
@@ -95,7 +74,6 @@ t.create('license (no license)')
.reply(200, {
downloads: { all: 100 },
latest_stable_version: '1.0',
latest_version: '1.0',
meta: { licenses: [] },
})
)

View File

@@ -81,8 +81,6 @@ class LibrariesIoProjectDependencies extends LibrariesIoBase {
},
]
static _cacheLength = 900
async handle({ platform, scope, packageName, version = 'latest' }) {
const url = `/${encodeURIComponent(platform)}/${
scope ? encodeURIComponent(`${scope}/`) : ''
@@ -118,8 +116,6 @@ class LibrariesIoRepoDependencies extends LibrariesIoBase {
},
]
static _cacheLength = 900
async handle({ user, repo }) {
const url = `/github/${encodeURIComponent(user)}/${encodeURIComponent(
repo

View File

@@ -32,8 +32,6 @@ export default class LibrariesIoDependentRepos extends LibrariesIoBase {
},
]
static _cacheLength = 900
static defaultBadgeData = {
label: 'dependent repos',
}

View File

@@ -32,8 +32,6 @@ export default class LibrariesIoDependents extends LibrariesIoBase {
},
]
static _cacheLength = 900
static defaultBadgeData = {
label: 'dependents',
}

View File

@@ -1,7 +1,6 @@
import Joi from 'joi'
import { nonNegativeInteger } from '../validators.js'
import { BaseJsonService } from '../index.js'
import { metric } from '../text-formatters.js'
// https://developer.opencollective.com/#/api/collectives?id=get-info
const collectiveDetailsSchema = Joi.object().keys({
@@ -31,11 +30,12 @@ export default class OpencollectiveBase extends BaseJsonService {
}
static render(backersCount, label) {
return {
label,
message: metric(backersCount),
const badge = {
message: backersCount,
color: backersCount > 0 ? 'brightgreen' : 'lightgrey',
}
if (label) badge.label = label
return badge
}
async fetchCollectiveInfo(collective) {

View File

@@ -1,55 +0,0 @@
import Joi from 'joi'
import { BaseJsonService } from '../index.js'
import { colorScale } from '../color-formatters.js'
const schema = Joi.object({
score: Joi.number().min(0).required(),
}).required()
const ossfScorecardColorScale = colorScale(
[2, 5, 8, 10],
['red', 'yellow', 'yellowgreen', 'green', 'brightgreen']
)
export default class OSSFScorecard extends BaseJsonService {
static category = 'analysis'
static route = { base: 'ossf-scorecard', pattern: ':host/:orgName/:repoName' }
static examples = [
{
title: 'OSSF-Scorecard Score',
namedParams: {
host: 'github.com',
orgName: 'rohankh532',
repoName: 'org-workflow-add',
},
staticPreview: this.render({ score: '7.5' }),
},
]
static defaultBadgeData = { label: 'score' }
static render({ score }) {
return {
message: score,
color: ossfScorecardColorScale(score),
}
}
async fetch({ host, orgName, repoName }) {
return this._requestJson({
schema,
url: `https://api.securityscorecards.dev/projects/${host}/${orgName}/${repoName}`,
errorMessages: {
404: 'invalid repo path',
},
})
}
async handle({ host, orgName, repoName }) {
const { score } = await this.fetch({ host, orgName, repoName })
return this.constructor.render({ score })
}
}

View File

@@ -1,25 +0,0 @@
import Joi from 'joi'
import { createServiceTester } from '../tester.js'
export const t = await createServiceTester()
t.create('score valid')
.get('/github.com/rohankh532/org-workflow-add.json')
.expectBadge({
label: 'score',
message: Joi.number().min(0),
color: Joi.string().allow(
'red',
'yellow',
'yellowgreen',
'green',
'brightgreen'
),
})
t.create('score ivalid')
.get('/github.com/invalid-user/invalid-repo.json')
.expectBadge({
label: 'score',
message: 'invalid repo path',
color: 'red',
})

View File

@@ -1,18 +1,18 @@
import Joi from 'joi'
import { BaseJsonService, NotFound } from '../index.js'
import { isStable, latest } from '../php-version.js'
import { BaseJsonService } from '../index.js'
const packageSchema = Joi.array().items(
Joi.object({
version: Joi.string().required(),
require: Joi.alternatives(
Joi.object({
const packageSchema = Joi.object()
.pattern(
/^/,
Joi.object({
'default-branch': Joi.bool(),
version: Joi.string(),
require: Joi.object({
php: Joi.string(),
}).required(),
Joi.string().valid('__unset')
),
})
)
}),
}).required()
)
.required()
const allVersionsSchema = Joi.object({
packages: Joi.object().pattern(/^/, packageSchema).required(),
@@ -36,31 +36,7 @@ class BasePackagistService extends BaseJsonService {
* @returns {object} Parsed response
*/
async fetch({ user, repo, schema, server = 'https://packagist.org' }) {
const url = `${server}/p2/${user.toLowerCase()}/${repo.toLowerCase()}.json`
return this._requestJson({
schema,
url,
})
}
/**
* Fetch dev releases method.
*
* This method utilize composer metadata API which
* "... is the preferred way to access the data as it is always up to date,
* and dumped to static files so it is very efficient on our end." (comment from official documentation).
* For more information please refer to https://packagist.org/apidoc#get-package-data.
*
* @param {object} attrs Refer to individual attrs
* @param {string} attrs.user package user
* @param {string} attrs.repo package repository
* @param {Joi} attrs.schema Joi schema to validate the response transformed to JSON
* @param {string} attrs.server URL for the packagist registry server (Optional)
* @returns {object} Parsed response
*/
async fetchDev({ user, repo, schema, server = 'https://packagist.org' }) {
const url = `${server}/p2/${user.toLowerCase()}/${repo.toLowerCase()}~dev.json`
const url = `${server}/p/${user.toLowerCase()}/${repo.toLowerCase()}.json`
return this._requestJson({
schema,
@@ -97,74 +73,16 @@ class BasePackagistService extends BaseJsonService {
})
}
getDefaultBranch(json, user, repo) {
const packageName = this.getPackageName(user, repo)
return Object.values(json.packages[packageName]).find(
b => b['default-branch'] === true
)
}
getPackageName(user, repo) {
return `${user.toLowerCase()}/${repo.toLowerCase()}`
}
/**
* Extract the array of minified versions of the given packageName,
* expand them back to their original format then return.
*
* @param {object} json The response of Packagist v2 API.
* @param {string} packageName The package name.
*
* @returns {object[]} An array of version metadata object.
*
* @see https://github.com/composer/metadata-minifier/blob/c549d23829536f0d0e984aaabbf02af91f443207/src/MetadataMinifier.php#L16-L46
*/
static expandPackageVersions(json, packageName) {
const versions = json.packages[packageName]
const expanded = []
let expandedVersion = null
for (const i in versions) {
const versionData = versions[i]
if (!expandedVersion) {
expandedVersion = { ...versionData }
expanded.push(expandedVersion)
continue
}
expandedVersion = { ...expandedVersion, ...versionData }
for (const key in expandedVersion) {
if (expandedVersion[key] === '__unset') {
delete expandedVersion[key]
}
}
expanded.push(expandedVersion)
}
return expanded
}
/**
* Find the object representation of the latest release.
*
* @param {object[]} versions An array of object representing a version.
* @param {boolean} includePrereleases Includes pre-release semver for the search.
*
* @returns {object} The object of the latest version.
* @throws {NotFound} Thrown if there is no item from the version array.
*/
findLatestRelease(versions, includePrereleases = false) {
// Find the latest version string, if not found, throw NotFound.
const versionStrings = versions
.filter(
version =>
typeof version.version === 'string' ||
version.version instanceof String
)
.map(version => version.version)
if (versionStrings.length < 1) {
throw new NotFound({ prettyMessage: 'no released version found' })
}
let release = latest(versionStrings)
if (!includePrereleases) {
release = latest(versionStrings.filter(isStable)) || release
}
return versions.filter(version => version.version === release)[0]
}
}
const customServerDocumentationFragment = `

View File

@@ -1,77 +0,0 @@
import { strict as assert } from 'assert'
import { describe, it } from 'mocha'
import { BasePackagistService } from './packagist-base.js'
// @reference: https://github.com/composer/metadata-minifier/blob/c549d23829536f0d0e984aaabbf02af91f443207/tests/MetadataMinifierTest.php#L36-L40
const minifiedSample = [
{
name: 'foo/bar',
version: '2.0.0',
version_normalized: '2.0.0.0',
type: 'library',
scripts: {
foo: 'bar',
},
license: ['MIT'],
},
{
version: '1.2.0',
version_normalized: '1.2.0.0',
license: ['GPL'],
homepage: 'https://example.org',
scripts: '__unset',
},
{
version: '1.0.0',
version_normalized: '1.0.0.0',
homepage: '__unset',
},
]
const expandedSample = [
{
name: 'foo/bar',
version: '2.0.0',
version_normalized: '2.0.0.0',
type: 'library',
scripts: {
foo: 'bar',
},
license: ['MIT'],
},
{
name: 'foo/bar',
version: '1.2.0',
version_normalized: '1.2.0.0',
type: 'library',
license: ['GPL'],
homepage: 'https://example.org',
},
{
name: 'foo/bar',
version: '1.0.0',
version_normalized: '1.0.0.0',
type: 'library',
license: ['GPL'],
},
]
describe('BasePackagistService', function () {
describe('expandPackageVersions', function () {
const expanded = BasePackagistService.expandPackageVersions(
{
packages: {
'foobar/foobar': minifiedSample,
},
},
'foobar/foobar'
)
it('should expand the minified package array to match the expanded sample', function () {
assert.deepStrictEqual(
expanded,
expandedSample,
'The expanded array should match the sample'
)
})
})
})

View File

@@ -8,11 +8,12 @@ import {
customServerDocumentationFragment,
} from './packagist-base.js'
const packageSchema = Joi.array()
.items(
const packageSchema = Joi.object()
.pattern(
/^/,
Joi.object({
version: Joi.string(),
license: Joi.array(),
'default-branch': Joi.bool(),
license: Joi.array().required(),
}).required()
)
.required()
@@ -56,27 +57,17 @@ export default class PackagistLicense extends BasePackagistService {
}
transform({ json, user, repo }) {
const packageName = this.getPackageName(user, repo)
const versions = BasePackagistService.expandPackageVersions(
json,
packageName
)
const version = this.findLatestRelease(versions)
const license = version.license
if (!license) {
throw new NotFound({ prettyMessage: 'license not found' })
const branch = this.getDefaultBranch(json, user, repo)
if (!branch) {
throw new NotFound({ prettyMessage: 'default branch not found' })
}
const { license } = branch
return { license }
}
async handle({ user, repo }, { server }) {
const json = await this.fetch({ user, repo, schema, server })
const { license } = this.transform({ json, user, repo })
return renderLicenseBadge({ license })
}
}

View File

@@ -3,101 +3,17 @@ import { NotFound } from '../index.js'
import PackagistLicense from './packagist-license.service.js'
describe('PackagistLicense', function () {
it('should return the license of the most recent release', function () {
it('should throw NotFound when default branch is missing', function () {
const json = {
packages: {
'frodo/the-one-package': [
{
version: '1.2.4',
license: 'MIT-latest',
},
{
version: '1.2.3',
license: 'MIT',
},
],
'frodo/the-one-package': {
'1.0.x-dev': { license: 'MIT' },
'1.1.x-dev': { license: 'MIT' },
'2.0.x-dev': { license: 'MIT' },
'2.1.x-dev': { license: 'MIT' },
},
},
}
expect(
PackagistLicense.prototype.transform({
json,
user: 'frodo',
repo: 'the-one-package',
})
)
.to.have.property('license')
.that.equals('MIT-latest')
})
it('should return the license of the most recent stable release', function () {
const json = {
packages: {
'frodo/the-one-package': [
{
version: '1.2.4-RC1', // Pre-release
license: 'MIT-latest',
},
{
version: '1.2.3', // Stable release
license: 'MIT',
},
],
},
}
expect(
PackagistLicense.prototype.transform({
json,
user: 'frodo',
repo: 'the-one-package',
})
)
.to.have.property('license')
.that.equals('MIT')
})
it('should return the license of the most recent pre-release if no stable releases', function () {
const json = {
packages: {
'frodo/the-one-package': [
{
version: '1.2.4-RC2',
license: 'MIT-latest',
},
{
version: '1.2.4-RC1',
license: 'MIT',
},
],
},
}
expect(
PackagistLicense.prototype.transform({
json,
user: 'frodo',
repo: 'the-one-package',
})
)
.to.have.property('license')
.that.equals('MIT-latest')
})
it('should throw NotFound when license key not in response', function () {
const json = {
packages: {
'frodo/the-one-package': [
{
version: '1.2.4',
},
{
version: '1.2.3',
},
],
},
}
expect(() =>
PackagistLicense.prototype.transform({
json,
@@ -106,6 +22,31 @@ describe('PackagistLicense', function () {
})
)
.to.throw(NotFound)
.with.property('prettyMessage', 'license not found')
.with.property('prettyMessage', 'default branch not found')
})
it('should return default branch when default branch is found', function () {
const json = {
packages: {
'frodo/the-one-package': {
'1.0.x-dev': { license: 'MIT' },
'1.1.x-dev': { license: 'MIT' },
'2.0.x-dev': {
license: 'MIT-default-branch',
'default-branch': true,
},
'2.1.x-dev': { license: 'MIT' },
},
},
}
expect(
PackagistLicense.prototype.transform({
json,
user: 'frodo',
repo: 'the-one-package',
})
)
.to.have.property('license')
.that.equals('MIT-default-branch')
})
})

View File

@@ -66,58 +66,11 @@ export default class PackagistPhpVersion extends BasePackagistService {
}
}
findVersionIndex(json, version) {
return json.findIndex(v => v.version === version)
}
async findSpecifiedVersion(json, user, repo, version, server) {
let release
if ((release = json[this.findVersionIndex(json, version)])) {
return release
} else {
try {
const allData = await this.fetchDev({
user,
repo,
schema: allVersionsSchema,
server,
})
const versions = BasePackagistService.expandPackageVersions(
allData,
this.getPackageName(user, repo)
)
return versions[this.findVersionIndex(versions, version)]
} catch (e) {
return release
}
}
}
async getPhpVersion({ json, user, repo, version = '', server }) {
let packageVersion
const versions = BasePackagistService.expandPackageVersions(
json,
this.getPackageName(user, repo)
)
if (version === '') {
packageVersion = this.findLatestRelease(versions)
} else {
try {
packageVersion = await this.findSpecifiedVersion(
versions,
user,
repo,
version,
server
)
} catch (e) {
packageVersion = null
}
}
transform({ json, user, repo, version = '' }) {
const packageVersion =
version === ''
? this.getDefaultBranch(json, user, repo)
: json.packages[this.getPackageName(user, repo)][version]
if (!packageVersion) {
throw new NotFound({ prettyMessage: 'invalid version' })
@@ -137,12 +90,11 @@ export default class PackagistPhpVersion extends BasePackagistService {
schema: allVersionsSchema,
server,
})
const { phpVersion } = await this.getPhpVersion({
const { phpVersion } = this.transform({
json: allData,
user,
repo,
version,
server,
})
return this.constructor.render({ php: phpVersion })
}

View File

@@ -1,115 +1,99 @@
import { expect } from 'chai'
import { NotFound } from '../index.js'
import PackagistPhpVersion from './packagist-php-version.service.js'
describe('PackagistPhpVersion', function () {
const json = {
packages: {
'frodo/the-one-package': [
{
version: '3.0.0',
require: { php: '^7.4 || 8' },
},
{
version: '2.0.0',
require: { php: '^7.2' },
},
{
version: '1.0.0',
require: { php: '^5.6 || ^7' },
},
],
'frodo/the-one-package': {
'1.0.0': { require: { php: '^5.6 || ^7' } },
'2.0.0': { require: { php: '^7.2' } },
'3.0.0': { require: { php: '^7.4 || 8' } },
'dev-main': { require: { php: '^8' }, 'default-branch': true },
},
'samwise/gardening': {
'1.0.x-dev': {},
'2.0.x-dev': {},
},
'pippin/mischief': {
'1.0.0': {},
'dev-main': { require: {}, 'default-branch': true },
},
},
}
it('should throw NotFound when package version is missing', async function () {
await expect(
PackagistPhpVersion.prototype.getPhpVersion({
it('should throw NotFound when package version is missing', function () {
expect(() =>
PackagistPhpVersion.prototype.transform({
json,
user: 'frodo',
repo: 'the-one-package',
version: '4.0.0',
})
).to.be.rejectedWith('invalid version')
)
.to.throw(NotFound)
.with.property('prettyMessage', 'invalid version')
})
it('should throw NotFound when PHP version not found on package when using default release', async function () {
const specJson = {
packages: {
'frodo/the-one-package': [
{
version: '3.0.0',
},
{
version: '2.0.0',
require: { php: '^7.2' },
},
{
version: '1.0.0',
require: { php: '^5.6 || ^7' },
},
],
},
}
await expect(
PackagistPhpVersion.prototype.getPhpVersion({
json: specJson,
user: 'frodo',
repo: 'the-one-package',
it('should throw NotFound when version not specified and no default branch found', function () {
expect(() =>
PackagistPhpVersion.prototype.transform({
json,
user: 'samwise',
repo: 'gardening',
})
).to.be.rejectedWith('version requirement not found')
)
.to.throw(NotFound)
.with.property('prettyMessage', 'invalid version')
})
it('should throw NotFound when PHP version not found on package when using specified release', async function () {
const specJson = {
packages: {
'frodo/the-one-package': [
{
version: '3.0.0',
require: { php: '^7.4 || 8' },
},
{
version: '2.0.0',
require: { php: '^7.2' },
},
{
version: '1.0.0',
require: '__unset',
},
],
},
}
await expect(
PackagistPhpVersion.prototype.getPhpVersion({
json: specJson,
user: 'frodo',
repo: 'the-one-package',
it('should throw NotFound when PHP version not found on package when using default branch', function () {
expect(() =>
PackagistPhpVersion.prototype.transform({
json,
user: 'pippin',
repo: 'mischief',
})
)
.to.throw(NotFound)
.with.property('prettyMessage', 'version requirement not found')
})
it('should throw NotFound when PHP version not found on package when using specified version', function () {
expect(() =>
PackagistPhpVersion.prototype.transform({
json,
user: 'pippin',
repo: 'mischief',
version: '1.0.0',
})
).to.be.rejectedWith('version requirement not found')
)
.to.throw(NotFound)
.with.property('prettyMessage', 'version requirement not found')
})
it('should return PHP version for the default release', async function () {
it('should return PHP version for the default branch', function () {
expect(
await PackagistPhpVersion.prototype.getPhpVersion({
PackagistPhpVersion.prototype.transform({
json,
user: 'frodo',
repo: 'the-one-package',
})
)
.to.have.property('phpVersion')
.that.equals('^8')
})
it('should return PHP version for the specified branch', function () {
expect(
PackagistPhpVersion.prototype.transform({
json,
user: 'frodo',
repo: 'the-one-package',
version: '3.0.0',
})
)
.to.have.property('phpVersion')
.that.equals('^7.4 || 8')
})
it('should return PHP version for the specified release', async function () {
expect(
await PackagistPhpVersion.prototype.getPhpVersion({
json,
user: 'frodo',
repo: 'the-one-package',
version: '2.0.0',
})
)
.to.have.property('phpVersion')
.that.equals('^7.2')
})
})

View File

@@ -6,8 +6,8 @@ t.create('gets the package version of symfony')
.get('/symfony/symfony.json')
.expectBadge({ label: 'php', message: isComposerVersion })
t.create('gets the package version of symfony 5.2.3')
.get('/symfony/symfony/v5.2.3.json')
t.create('gets the package version of symfony 2.8')
.get('/symfony/symfony/v2.8.0.json')
.expectBadge({ label: 'php', message: isComposerVersion })
t.create('package with no requirements')

View File

@@ -1,18 +1,26 @@
import Joi from 'joi'
import { renderVersionBadge } from '../version.js'
import { compare, isStable, latest } from '../php-version.js'
import { optionalUrl } from '../validators.js'
import { redirector } from '../index.js'
import { NotFound, redirector } from '../index.js'
import {
allVersionsSchema,
keywords,
BasePackagistService,
customServerDocumentationFragment,
} from './packagist-base.js'
const packageSchema = Joi.array().items(
Joi.object({
version: Joi.string().required(),
})
)
const packageSchema = Joi.object()
.pattern(
/^/,
Joi.object({
version: Joi.string(),
extra: Joi.object({
'branch-alias': Joi.object().pattern(/^/, Joi.string()),
}),
}).required()
)
.required()
const schema = Joi.object({
packages: Joi.object().pattern(/^/, packageSchema).required(),
@@ -72,9 +80,45 @@ class PackagistVersion extends BasePackagistService {
}
static render({ version }) {
if (version === undefined) {
throw new NotFound({ prettyMessage: 'no released version found' })
}
return renderVersionBadge({ version })
}
transform({ includePrereleases, json, user, repo }) {
const versionsData = json.packages[this.getPackageName(user, repo)]
let versions = Object.keys(versionsData)
const aliasesMap = {}
versions.forEach(version => {
const versionData = versionsData[version]
if (
versionData.extra &&
versionData.extra['branch-alias'] &&
versionData.extra['branch-alias'][version]
) {
// eg, version is 'dev-master', mapped to '2.0.x-dev'.
const validVersion = versionData.extra['branch-alias'][version]
if (
aliasesMap[validVersion] === undefined ||
compare(aliasesMap[validVersion], validVersion) < 0
) {
versions.push(validVersion)
aliasesMap[validVersion] = version
}
}
})
versions = versions.filter(version => !/^dev-/.test(version))
if (includePrereleases) {
return { version: latest(versions) }
} else {
const stableVersion = latest(versions.filter(isStable))
return { version: stableVersion || latest(versions) }
}
}
async handle(
{ user, repo },
{ include_prereleases: includePrereleases, server }
@@ -83,11 +127,10 @@ class PackagistVersion extends BasePackagistService {
const json = await this.fetch({
user,
repo,
schema,
schema: includePrereleases ? schema : allVersionsSchema,
server,
})
const versions = json.packages[this.getPackageName(user, repo)]
const { version } = this.findLatestRelease(versions, includePrereleases)
const { version } = this.transform({ includePrereleases, json, user, repo })
return this.constructor.render({ version })
}
}

View File

@@ -1,98 +0,0 @@
import Joi from 'joi'
import { BaseJsonService, InvalidResponse } from '../index.js'
import { renderVersionBadge } from '../version.js'
import { pep440VersionColor } from '../color-formatters.js'
const schema = Joi.object({
releases: Joi.object()
.pattern(
Joi.string(),
Joi.object({
prerelease: Joi.boolean().required(),
yanked: Joi.boolean().required(),
files: Joi.object().required(),
})
)
.required(),
}).required()
const queryParamSchema = Joi.object({
include_prereleases: Joi.equal(''),
}).required()
const keywords = ['python', 'arm', 'raspberry pi']
export default class PiWheelsVersion extends BaseJsonService {
static category = 'version'
static route = { base: 'piwheels/v', pattern: ':wheel', queryParamSchema }
static examples = [
{
title: 'piwheels',
namedParams: { wheel: 'numpy' },
staticPreview: this.render({ version: '1.22.2' }),
keywords,
},
{
title: 'piwheels (including prereleases)',
namedParams: { wheel: 'flask' },
queryParams: {
include_prereleases: null,
},
staticPreview: this.render({ version: '2.0.0rc2' }),
keywords,
},
]
static defaultBadgeData = { label: 'piwheels' }
static render({ version }) {
return renderVersionBadge({ version, versionFormatter: pep440VersionColor })
}
async fetch({ wheel }) {
return this._requestJson({
schema,
url: `https://www.piwheels.org/project/${wheel}/json/`,
errorMessages: { 404: 'package not found' },
})
}
static transform(releases, includePrereleases) {
const allReleases = Object.keys(releases)
.reduce(
(acc, key) =>
acc.concat({
version: key,
prerelease: releases[key].prerelease,
yanked: releases[key].yanked,
hasFiles: Object.keys(releases[key].files).length > 0,
}),
[]
)
.filter(release => !release.yanked) // exclude any yanked releases
.filter(release => release.hasFiles) // exclude any releases with no wheels
if (allReleases.length === 0) {
throw new InvalidResponse({ prettyMessage: 'no versions found' })
}
if (includePrereleases) {
return allReleases[0].version
}
const stableReleases = allReleases.filter(release => !release.prerelease)
if (stableReleases.length > 0) {
return stableReleases[0].version
}
return allReleases[0].version
}
async handle({ wheel }, queryParams) {
const includePrereleases = queryParams.include_prereleases !== undefined
const { releases } = await this.fetch({ wheel })
const version = this.constructor.transform(releases, includePrereleases)
return this.constructor.render({ version })
}
}

View File

@@ -1,65 +0,0 @@
import { expect } from 'chai'
import { test, given } from 'sazerac'
import { InvalidResponse } from '../index.js'
import PiWheelsVersion from './piwheels-version.service.js'
describe('PiWheelsVersion', function () {
test(PiWheelsVersion.transform, () => {
given(
{
'2.0.0rc1': { prerelease: true, yanked: false, files: { foobar: {} } },
'1.9.0': { prerelease: false, yanked: false, files: { foobar: {} } },
},
false
).expect('1.9.0')
given(
{
'2.0.0rc1': { prerelease: true, yanked: false, files: { foobar: {} } },
'1.9.0': { prerelease: false, yanked: false, files: { foobar: {} } },
},
true
).expect('2.0.0rc1')
given(
{
'2.0.0': { prerelease: false, yanked: true, files: { foobar: {} } },
'1.9.0': { prerelease: false, yanked: false, files: { foobar: {} } },
},
false
).expect('1.9.0')
given(
{
'2.0.0': { prerelease: false, yanked: false, files: {} },
'1.9.0': { prerelease: false, yanked: false, files: { foobar: {} } },
},
false
).expect('1.9.0')
given(
{
'2.0.0': { prerelease: false, yanked: false, files: { foobar: {} } },
'1.9.0': { prerelease: false, yanked: false, files: { foobar: {} } },
},
false
).expect('2.0.0')
given(
{
'2.0.0rc2': { prerelease: true, yanked: false, files: { foobar: {} } },
'2.0.0rc1': { prerelease: true, yanked: false, files: { foobar: {} } },
},
false
).expect('2.0.0rc2')
})
it('throws `no releases` InvalidResponse if no versions', function () {
expect(() =>
PiWheelsVersion.transform(
{
'1.0.1': { prerelease: false, yanked: false, files: {} },
'1.0.0': { prerelease: false, yanked: true, files: { foobar: {} } },
},
false
)
)
.to.throw(InvalidResponse)
.with.property('prettyMessage', 'no versions found')
})
})

View File

@@ -1,13 +0,0 @@
import { isVPlusDottedVersionNClauses } from '../test-validators.js'
import { createServiceTester } from '../tester.js'
export const t = await createServiceTester()
t.create('version (valid)').get('/flask.json').expectBadge({
label: 'piwheels',
message: isVPlusDottedVersionNClauses,
})
t.create('version (does not exist)').get('/doesn-not-exist.json').expectBadge({
label: 'piwheels',
message: 'package not found',
})

View File

@@ -1,53 +0,0 @@
import Joi from 'joi'
import { BaseJsonService } from '../index.js'
import { metric } from '../text-formatters.js'
import { nonNegativeInteger } from '../validators.js'
const documentation = `<p>A measure of how many developers have liked a package. This provides a raw measure of the overall sentiment of a package from peer developers.</p>`
const keywords = ['dart', 'flutter']
const schema = Joi.object({
likeCount: nonNegativeInteger,
}).required()
const title = 'Pub Likes'
export default class PubLikes extends BaseJsonService {
static category = 'rating'
static route = { base: 'pub/likes', pattern: ':packageName' }
static examples = [
{
title,
keywords,
documentation,
namedParams: { packageName: 'analysis_options' },
staticPreview: this.render({ likeCount: 1000 }),
},
]
static defaultBadgeData = { label: 'likes' }
static render({ likeCount }) {
return {
label: 'likes',
message: metric(likeCount),
color: 'blue',
}
}
async fetch({ packageName }) {
return this._requestJson({
schema,
url: `https://pub.dev/api/packages/${packageName}/score`,
})
}
async handle({ packageName }) {
const score = await this.fetch({ packageName })
const likeCount = score.likeCount
return this.constructor.render({ likeCount })
}
}

View File

@@ -1,22 +0,0 @@
import { isMetric } from '../test-validators.js'
import { createServiceTester } from '../tester.js'
export const t = await createServiceTester()
t.create('pub likes (valid)').get('/analysis_options.json').expectBadge({
label: 'likes',
message: isMetric,
color: 'blue',
})
t.create('pub likes (not found)').get('/analysisoptions.json').expectBadge({
label: 'likes',
message: 'not found',
color: 'red',
})
t.create('pub likes (invalid)').get('/analysis-options.json').expectBadge({
label: 'likes',
message: 'invalid',
color: 'lightgrey',
})

View File

@@ -1,55 +0,0 @@
import Joi from 'joi'
import { floorCount } from '../color-formatters.js'
import { BaseJsonService } from '../index.js'
import { nonNegativeInteger } from '../validators.js'
const documentation = `<p>A measure of quality. This includes several dimensions of quality such as code style, platform support, and maintainability.</p>`
const keywords = ['dart', 'flutter']
const schema = Joi.object({
grantedPoints: nonNegativeInteger,
maxPoints: nonNegativeInteger,
}).required()
const title = 'Pub Points'
export default class PubPoints extends BaseJsonService {
static category = 'rating'
static route = { base: 'pub/points', pattern: ':packageName' }
static examples = [
{
title,
keywords,
documentation,
namedParams: { packageName: 'analysis_options' },
staticPreview: this.render({ grantedPoints: 120, maxPoints: 130 }),
},
]
static defaultBadgeData = { label: 'points' }
static render({ grantedPoints, maxPoints }) {
return {
label: 'points',
message: `${grantedPoints}/${maxPoints}`,
color: floorCount((grantedPoints / maxPoints) * 100, 40, 60, 80),
}
}
async fetch({ packageName }) {
return this._requestJson({
schema,
url: `https://pub.dev/api/packages/${packageName}/score`,
})
}
async handle({ packageName }) {
const score = await this.fetch({ packageName })
const grantedPoints = score.grantedPoints
const maxPoints = score.maxPoints
return this.constructor.render({ grantedPoints, maxPoints })
}
}

Some files were not shown because too many files have changed in this diff Show More