Compare commits

..

29 Commits

Author SHA1 Message Date
chris48s
b0ef5046d0 use credentials if available 2023-01-15 12:36:30 +00:00
chris48s
f60c2058fa fix PAT check 2023-01-15 11:32:01 +00:00
chris48s
39e4d9bcbc rename GithubGist to Gist 2023-01-15 11:22:41 +00:00
chris48s
2bf863fb09 use a PAT if available 2023-01-12 20:40:49 +00:00
chris48s
ed277d4e79 give token contents:read 2023-01-11 20:33:03 +00:00
chris48s
fdc81c2e3a give token gist:read 2023-01-11 20:24:50 +00:00
chris48s
6ef9dcaba5 use workflow token for github service tests 2023-01-11 20:05:58 +00:00
chris48s
541cb9acf2 update triggers 2023-01-11 19:53:56 +00:00
chris48s
2492ff79f7 Merge branch 'master' into services-gha 2023-01-11 19:42:32 +00:00
chris48s
9c692cd53a fail + report if tests are pending 2022-09-19 18:25:51 +01:00
chris48s
7410bf2e97 do nothing 2022-09-19 18:16:02 +01:00
chris48s
a83cfa4fb6 do nothing 2022-09-19 18:11:29 +01:00
chris48s
4d64969738 do nothing 2022-09-19 18:08:14 +01:00
chris48s
ade213c6d3 pass PR title safely 2022-09-19 17:26:14 +01:00
chris48s
1135fba9f6 remove spurious debug 2022-09-19 17:09:09 +01:00
chris48s
0234fb077f improve report 2022-09-19 17:04:57 +01:00
chris48s
ed86c1de21 debug statement 2022-09-19 17:00:53 +01:00
chris48s
a47f770c82 better summary 2022-09-19 16:30:45 +01:00
chris48s
3176d6f7f3 Revert "break some stuff on purpose"
This reverts commit 0763d8ec66.
2022-09-19 16:20:00 +01:00
chris48s
0763d8ec66 break some stuff on purpose 2022-09-19 16:14:17 +01:00
chris48s
3fcb959ed2 single-quote the PR title 2022-09-19 16:08:42 +01:00
chris48s
f562dfe868 Revert "pass the PR title from the workflow to the action"
This reverts commit 22aee48544.
2022-09-19 16:06:44 +01:00
chris48s
22aee48544 pass the PR title from the workflow to the action 2022-09-19 16:02:56 +01:00
chris48s
098a24cae5 do nothing 2022-09-19 15:56:46 +01:00
chris48s
a2c8ed27b8 only run summary if there were any tests to run 2022-09-19 15:35:51 +01:00
chris48s
2dccd3d040 only run summary if there were any tests to run 2022-09-19 15:27:14 +01:00
chris48s
b8ce38a041 fix titles 2022-09-19 15:25:01 +01:00
chris48s
0784a14153 fix runs-on 2022-09-19 15:21:11 +01:00
chris48s
afc7b283bc migrate service tests to GH actions 2022-09-19 15:16:09 +01:00
19 changed files with 521 additions and 719 deletions

View File

@@ -1,77 +1,3 @@
version: 2
services_steps: &services_steps
steps:
- checkout
- run:
name: Install dependencies
command: |
npm ci
environment:
CYPRESS_INSTALL_BINARY: 0
- run:
name: Identify services tagged in the PR title
command: npm run test:services:pr:prepare
- run:
name: Run tests for tagged services
environment:
mocha_reporter: mocha-junit-reporter
MOCHA_FILE: junit/services/results.xml
command: RETRY_COUNT=3 npm run test:services:pr:run
- store_test_results:
path: junit
jobs:
services:
docker:
- image: cimg/node:16.15
<<: *services_steps
services@node-17:
docker:
- image: cimg/node:17.9
environment:
NPM_CONFIG_ENGINE_STRICT: 'false'
<<: *services_steps
workflows:
version: 2
on-commit:
jobs:
- services:
filters:
branches:
ignore:
- master
- gh-pages
- services@node-17:
filters:
branches:
ignore:
- master
- gh-pages
# on-commit-with-cache:
# jobs:
# - npm-install:
# filters:
# branches:
# ignore: gh-pages
# - services:
# requires:
# - npm-install
# filters:
# branches:
# ignore: master
# - services@node-latest:
# requires:
# - npm-install
# filters:
# branches:
# ignore: master
# Do nothing
# TODO: disable Circle

View File

@@ -0,0 +1,86 @@
name: 'Service tests'
description: 'Run tests for selected services'
inputs:
github-token:
description: 'The GITHUB_TOKEN secret'
required: true
librariesio-tokens:
description: 'The SERVICETESTS_LIBRARIESIO_TOKENS secret'
required: false
default: ''
obs-user:
description: 'The SERVICETESTS_OBS_USER secret'
required: false
default: ''
obs-pass:
description: 'The SERVICETESTS_OBS_PASS secret'
required: false
default: ''
sl-insight-user-uuid:
description: 'The SERVICETESTS_SL_INSIGHT_USER_UUID secret'
required: false
default: ''
sl-insight-api-token:
description: 'The SERVICETESTS_SL_INSIGHT_API_TOKEN secret'
required: false
default: ''
twitch-client-id:
description: 'The SERVICETESTS_TWITCH_CLIENT_ID secret'
required: false
default: ''
twitch-client-secret:
description: 'The SERVICETESTS_TWITCH_CLIENT_SECRET secret'
required: false
default: ''
wheelmap-token:
description: 'The SERVICETESTS_WHEELMAP_TOKEN secret'
required: false
default: ''
youtube-api-key:
description: 'The SERVICETESTS_YOUTUBE_API_KEY secret'
required: false
default: ''
runs:
using: 'composite'
steps:
- name: Derive list of service tests to run
# Note: In this step we are using an intermediate env var instead of
# passing github.event.pull_request.title as an argument
# to prevent a shell injection attack. Further reading:
# https://securitylab.github.com/research/github-actions-untrusted-input/#exploitability-and-impact
# https://securitylab.github.com/research/github-actions-untrusted-input/#remediation
if: always()
env:
TITLE: ${{ github.event.pull_request.title }}
run: npm run test:services:pr:prepare "$TITLE"
shell: bash
- name: Run service tests
if: always()
run: npm run test:services:pr:run -- --reporter json --reporter-option 'output=reports/service-tests.json'
shell: bash
env:
RETRY_COUNT: 3
GH_TOKEN: '${{ inputs.github-token }}'
LIBRARIESIO_TOKENS: '${{ inputs.librariesio-tokens }}'
OBS_USER: '${{ inputs.obs-user }}'
OBS_PASS: '${{ inputs.obs-pass }}'
SL_INSIGHT_USER_UUID: '${{ inputs.sl-insight-user-uuid }}'
SL_INSIGHT_API_TOKEN: '${{ inputs.sl-insight-api-token }}'
TWITCH_CLIENT_ID: '${{ inputs.twitch-client-id }}'
TWITCH_CLIENT_SECRET: '${{ inputs.twitch-client-secret }}'
WHEELMAP_TOKEN: '${{ inputs.wheelmap-token }}'
YOUTUBE_API_KEY: '${{ inputs.youtube-api-key }}'
- name: Write Markdown Summary
if: always()
run: |
if test -f 'reports/service-tests.json'; then
echo '# Services' >> $GITHUB_STEP_SUMMARY
sed -e 's/^/- /' pull-request-services.log >> $GITHUB_STEP_SUMMARY
node scripts/mocha2md.js Report reports/service-tests.json >> $GITHUB_STEP_SUMMARY
else
echo 'No services found. Nothing to do.' >> $GITHUB_STEP_SUMMARY
fi
shell: bash

40
.github/workflows/test-services-17.yml vendored Normal file
View File

@@ -0,0 +1,40 @@
name: Services@node 17
on:
pull_request:
types: [opened, edited, reopened, synchronize]
jobs:
test-services-17:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup
uses: ./.github/actions/setup
with:
node-version: 17
env:
NPM_CONFIG_ENGINE_STRICT: 'false'
- name: Service tests (triggered from local branch)
if: github.event.pull_request.head.repo.full_name == github.repository
uses: ./.github/actions/service-tests
with:
github-token: '${{ secrets.GH_PAT }}'
librariesio-tokens: '${{ secrets.SERVICETESTS_LIBRARIESIO_TOKENS }}'
obs-user: '${{ secrets.SERVICETESTS_OBS_USER }}'
obs-pass: '${{ secrets.SERVICETESTS_OBS_PASS }}'
sl-insight-user-uuid: '${{ secrets.SERVICETESTS_SL_INSIGHT_USER_UUID }}'
sl-insight-api-token: '${{ secrets.SERVICETESTS_SL_INSIGHT_API_TOKEN }}'
twitch-client-id: '${{ secrets.SERVICETESTS_TWITCH_CLIENT_ID }}'
twitch-client-secret: '${{ secrets.SERVICETESTS_TWITCH_CLIENT_SECRET }}'
wheelmap-token: '${{ secrets.SERVICETESTS_WHEELMAP_TOKEN }}'
youtube-api-key: '${{ secrets.SERVICETESTS_YOUTUBE_API_KEY }}'
- name: Service tests (triggered from fork)
if: github.event.pull_request.head.repo.full_name != github.repository
uses: ./.github/actions/service-tests
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'

38
.github/workflows/test-services.yml vendored Normal file
View File

@@ -0,0 +1,38 @@
name: Services
on:
pull_request:
types: [opened, edited, reopened, synchronize]
jobs:
test-services:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup
uses: ./.github/actions/setup
with:
node-version: 16
- name: Service tests (triggered from local branch)
if: github.event.pull_request.head.repo.full_name == github.repository
uses: ./.github/actions/service-tests
with:
github-token: '${{ secrets.GH_PAT }}'
librariesio-tokens: '${{ secrets.SERVICETESTS_LIBRARIESIO_TOKENS }}'
obs-user: '${{ secrets.SERVICETESTS_OBS_USER }}'
obs-pass: '${{ secrets.SERVICETESTS_OBS_PASS }}'
sl-insight-user-uuid: '${{ secrets.SERVICETESTS_SL_INSIGHT_USER_UUID }}'
sl-insight-api-token: '${{ secrets.SERVICETESTS_SL_INSIGHT_API_TOKEN }}'
twitch-client-id: '${{ secrets.SERVICETESTS_TWITCH_CLIENT_ID }}'
twitch-client-secret: '${{ secrets.SERVICETESTS_TWITCH_CLIENT_SECRET }}'
wheelmap-token: '${{ secrets.SERVICETESTS_WHEELMAP_TOKEN }}'
youtube-api-key: '${{ secrets.SERVICETESTS_YOUTUBE_API_KEY }}'
- name: Service tests (triggered from fork)
if: github.event.pull_request.head.repo.full_name != github.repository
uses: ./.github/actions/service-tests
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'

View File

@@ -27,13 +27,11 @@ class InvalidService extends Error {
}
}
function getServicePaths(pattern) {
return glob.sync(toUnixPath(path.join(serviceDir, '**', pattern)))
}
async function loadServiceClasses(servicePaths) {
if (!servicePaths) {
servicePaths = getServicePaths('*.service.js')
servicePaths = glob.sync(
toUnixPath(path.join(serviceDir, '**', '*.service.js'))
)
}
const serviceClasses = []
@@ -104,16 +102,15 @@ async function collectDefinitions() {
async function loadTesters() {
return Promise.all(
getServicePaths('*.tester.js').map(
async path => await import(`file://${path}`)
)
glob
.sync(path.join(serviceDir, '**', '*.tester.js'))
.map(async path => await import(`file://${path}`))
)
}
export {
InvalidService,
loadServiceClasses,
getServicePaths,
checkNames,
collectDefinitions,
loadTesters,

View File

@@ -2,11 +2,7 @@ import path from 'path'
import { fileURLToPath } from 'url'
import chai from 'chai'
import chaiAsPromised from 'chai-as-promised'
import {
loadServiceClasses,
getServicePaths,
InvalidService,
} from './loader.js'
import { loadServiceClasses, InvalidService } from './loader.js'
chai.use(chaiAsPromised)
const { expect } = chai
@@ -69,15 +65,3 @@ describe('loadServiceClasses function', function () {
).to.eventually.have.length(5)
})
})
describe('getServicePaths', function () {
// these tests just make sure we discover a
// plausibly large number of .service and .tester files
it('finds a non-zero number of services in the project', function () {
expect(getServicePaths('*.service.js')).to.have.length.above(400)
})
it('finds a non-zero number of testers in the project', function () {
expect(getServicePaths('*.tester.js')).to.have.length.above(400)
})
})

View File

@@ -1,102 +0,0 @@
/**
* @module
*/
import { URL, format as urlFormat } from 'url'
function formatSlug(owner, repo, pullRequest) {
return `${owner}/${repo}#${pullRequest}`
}
function parseGithubPullRequestUrl(url, options = {}) {
const { verifyBaseUrl } = options
const parsed = new URL(url)
const components = parsed.pathname.substr(1).split('/')
if (components[2] !== 'pull' || components.length !== 4) {
throw Error(`Invalid GitHub pull request URL: ${url}`)
}
const [owner, repo, , pullRequest] = components
parsed.pathname = ''
const baseUrl = urlFormat(parsed, {
auth: false,
fragment: false,
search: false,
}).replace(/\/$/, '')
if (verifyBaseUrl && baseUrl !== verifyBaseUrl) {
throw Error(`Expected base URL to be ${verifyBaseUrl} but got ${baseUrl}`)
}
return {
baseUrl,
owner,
repo,
pullRequest: +pullRequest,
slug: formatSlug(owner, repo, pullRequest),
}
}
function parseGithubRepoSlug(slug) {
const components = slug.split('/')
if (components.length !== 2) {
throw Error(`Invalid GitHub repo slug: ${slug}`)
}
const [owner, repo] = components
return { owner, repo }
}
function _inferPullRequestFromTravisEnv(env) {
const { owner, repo } = parseGithubRepoSlug(env.TRAVIS_REPO_SLUG)
const pullRequest = +env.TRAVIS_PULL_REQUEST
return {
owner,
repo,
pullRequest,
slug: formatSlug(owner, repo, pullRequest),
}
}
function _inferPullRequestFromCircleEnv(env) {
return parseGithubPullRequestUrl(
env.CI_PULL_REQUEST || env.CIRCLE_PULL_REQUEST
)
}
/**
* When called inside a CI build, infer the details
* of a pull request from the environment variables.
*
* @param {object} [env=process.env] Environment variables
* @returns {module:core/service-test-runner/infer-pull-request~PullRequest}
* Pull Request
*/
function inferPullRequest(env = process.env) {
if (env.TRAVIS) {
return _inferPullRequestFromTravisEnv(env)
} else if (env.CIRCLECI) {
return _inferPullRequestFromCircleEnv(env)
} else if (env.CI) {
throw Error(
'Unsupported CI system. Unable to obtain pull request information from the environment.'
)
} else {
throw Error(
'Unable to obtain pull request information from the environment. Is this running in CI?'
)
}
}
/**
* Pull Request
*
* @typedef PullRequest
* @property {string} pr.baseUrl (returned for travis CI only)
* @property {string} owner
* @property {string} repo
* @property {string} pullRequest PR/issue number
* @property {string} slug owner/repo/#pullRequest
*/
export { parseGithubPullRequestUrl, parseGithubRepoSlug, inferPullRequest }

View File

@@ -1,48 +0,0 @@
import { test, given, forCases } from 'sazerac'
import {
parseGithubPullRequestUrl,
inferPullRequest,
} from './infer-pull-request.js'
describe('Pull request inference', function () {
test(parseGithubPullRequestUrl, () => {
forCases([
given('https://github.com/badges/shields/pull/1234'),
given('https://github.com/badges/shields/pull/1234', {
verifyBaseUrl: 'https://github.com',
}),
]).expect({
baseUrl: 'https://github.com',
owner: 'badges',
repo: 'shields',
pullRequest: 1234,
slug: 'badges/shields#1234',
})
given('https://github.com/badges/shields/pull/1234', {
verifyBaseUrl: 'https://example.com',
}).expectError(
'Expected base URL to be https://example.com but got https://github.com'
)
})
test(inferPullRequest, () => {
const expected = {
owner: 'badges',
repo: 'shields',
pullRequest: 1234,
slug: 'badges/shields#1234',
}
given({
CIRCLECI: '1',
CI_PULL_REQUEST: 'https://github.com/badges/shields/pull/1234',
}).expect(Object.assign({ baseUrl: 'https://github.com' }, expected))
given({
TRAVIS: '1',
TRAVIS_REPO_SLUG: 'badges/shields',
TRAVIS_PULL_REQUEST: '1234',
}).expect(expected)
})
})

View File

@@ -1,5 +1,5 @@
// Infer the current PR from the Travis environment, and look for bracketed,
// space-separated service names in the pull request title.
// Derive a list of service tests to run based on
// space-separated service names in the PR title.
//
// Output the list of services.
//
@@ -8,54 +8,26 @@
// Output:
// travis
// sonar
//
// Example:
//
// TRAVIS=1 TRAVIS_REPO_SLUG=badges/shields TRAVIS_PULL_REQUEST=1108 npm run test:services:pr:prepare
import got from 'got'
import { inferPullRequest } from './infer-pull-request.js'
import servicesForTitle from './services-for-title.js'
async function getTitle(owner, repo, pullRequest) {
const {
body: { title },
} = await got(
`https://api.github.com/repos/${owner}/${repo}/pulls/${pullRequest}`,
{
headers: {
'User-Agent': 'badges/shields',
Authorization: `token ${process.env.GITHUB_TOKEN}`,
},
responseType: 'json',
}
)
return title
let title
try {
if (process.argv.length < 3) {
throw new Error()
}
title = process.argv[2]
} catch (e) {
console.error('Error processing arguments')
process.exit(1)
}
async function main() {
const { owner, repo, pullRequest, slug } = inferPullRequest()
console.error(`PR: ${slug}`)
const title = await getTitle(owner, repo, pullRequest)
console.error(`Title: ${title}\n`)
const services = servicesForTitle(title)
if (services.length === 0) {
console.error('No services found. Nothing to do.')
} else {
console.error(
`Services: (${services.length} found) ${services.join(', ')}\n`
)
console.log(services.join('\n'))
}
console.error(`Title: ${title}\n`)
const services = servicesForTitle(title)
if (services.length === 0) {
console.error('No services found. Nothing to do.')
} else {
console.error(`Services: (${services.length} found) ${services.join(', ')}\n`)
console.log(services.join('\n'))
}
;(async () => {
try {
await main()
} catch (e) {
console.error(e)
process.exit(1)
}
})()

View File

@@ -11,6 +11,7 @@
// DANGER_GITHUB_API_TOKEN=your-github-api-token npm run danger -- pr https://github.com/badges/shields/pull/2665
const { danger, fail, message, warn } = require('danger')
const { default: noTestShortcuts } = require('danger-plugin-no-test-shortcuts')
const { fileMatch } = danger.git
const documentation = fileMatch(
@@ -172,3 +173,11 @@ affectedServices.forEach(service => {
)
}
})
// Prevent merging exclusive services tests.
noTestShortcuts({
testFilePredicate: filePath => filePath.endsWith('.tester.js'),
patterns: {
only: ['only()'],
},
})

701
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -24,8 +24,8 @@
"@fontsource/lato": "^4.5.10",
"@fontsource/lekton": "^4.5.11",
"@renovate/pep440": "^1.0.0",
"@renovatebot/ruby-semver": "^1.1.8",
"@sentry/node": "^7.30.0",
"@renovatebot/ruby-semver": "^1.1.7",
"@sentry/node": "^7.29.0",
"@shields_io/camp": "^18.1.1",
"badge-maker": "file:badge-maker",
"bytes": "^3.1.2",
@@ -39,7 +39,7 @@
"decamelize": "^3.2.0",
"emojic": "^1.1.17",
"escape-string-regexp": "^4.0.0",
"fast-xml-parser": "^4.0.13",
"fast-xml-parser": "^4.0.12",
"glob": "^8.0.3",
"global-agent": "^3.0.0",
"got": "^12.5.3",
@@ -181,13 +181,13 @@
"eslint-config-standard-react": "^11.0.1",
"eslint-plugin-chai-friendly": "^0.7.2",
"eslint-plugin-cypress": "^2.12.1",
"eslint-plugin-import": "^2.27.4",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsdoc": "^39.6.4",
"eslint-plugin-mocha": "^10.1.0",
"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.32.0",
"eslint-plugin-react": "^7.31.11",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-sort-class-members": "^1.16.0",
"fetch-ponyfill": "^7.1.0",
@@ -213,13 +213,13 @@
"mocha-env-reporter": "^4.0.0",
"mocha-junit-reporter": "^2.2.0",
"mocha-yaml-loader": "^1.0.3",
"nock": "13.3.0",
"nock": "13.2.9",
"node-mocks-http": "^1.12.1",
"nodemon": "^2.0.20",
"npm-run-all": "^4.1.5",
"open-cli": "^7.1.0",
"portfinder": "^1.0.32",
"prettier": "2.8.2",
"prettier": "2.8.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-error-overlay": "^6.0.11",
@@ -229,7 +229,7 @@
"react-select": "^4.3.1",
"read-all-stdin-sync": "^1.0.5",
"redis-server": "^1.2.2",
"rimraf": "^4.0.4",
"rimraf": "^3.0.2",
"sazerac": "^2.0.0",
"simple-git-hooks": "^2.8.1",
"sinon": "^15.0.1",

View File

@@ -22,6 +22,10 @@ if (data.stats.passes > 0) {
if (data.stats.failures > 0) {
process.stdout.write(`${data.stats.failures} failed\n\n`)
}
if (data.stats.pending > 0) {
process.stdout.write(`${data.stats.pending} pending\n\n`)
process.exit(2)
}
if (data.stats.failures > 0) {
for (const test of data.tests) {

View File

@@ -1,6 +1,7 @@
import { ServiceTester } from '../../tester.js'
export const t = new ServiceTester({
id: 'GithubGistLastCommitRedirect',
id: 'GistLastCommitRedirect',
title: 'Github Gist Last Commit Redirect',
pathPrefix: '/github-gist',
})

View File

@@ -8,7 +8,7 @@ const schema = Joi.object({
updated_at: Joi.string().required(),
}).required()
export default class GithubGistLastCommit extends GithubAuthV3Service {
export default class GistLastCommit extends GithubAuthV3Service {
static category = 'activity'
static route = { base: 'github/gist/last-commit', pattern: ':gistId' }
static examples = [

View File

@@ -1,6 +1,6 @@
import { ServiceTester } from '../../tester.js'
export const t = new ServiceTester({
id: 'GithubGistStarsRedirect',
id: 'GistStarsRedirect',
title: 'Github Gist Stars Redirect',
pathPrefix: '/github',
})

View File

@@ -24,7 +24,7 @@ const documentation = `${commonDocumentation}
<p>This badge shows the number of stargazers for a gist. Gist id is accepted as input and 'gist not found' is returned if the gist is not found for the given gist id.
</p>`
export default class GithubGistStars extends GithubAuthV4Service {
export default class GistStars extends GithubAuthV4Service {
static category = 'social'
static route = {

View File

@@ -66,9 +66,9 @@ class GithubPipenvLockedPythonVersion extends ConditionalGithubAuthV3Service {
namedParams: {
user: 'metabolize',
repo: 'rq-dashboard-on-heroku',
branch: 'main',
branch: 'master',
},
staticPreview: this.render({ version: '3.7', branch: 'main' }),
staticPreview: this.render({ version: '3.7', branch: 'master' }),
documentation,
keywords,
},
@@ -135,7 +135,7 @@ class GithubPipenvLockedDependencyVersion extends ConditionalGithubAuthV3Service
repo: 'rq-dashboard-on-heroku',
kind: 'dev',
packageName: 'black',
branch: 'main',
branch: 'master',
},
staticPreview: this.render({ dependency: 'black', version: '19.3b0' }),
documentation,

View File

@@ -47,7 +47,7 @@ t.create('Locked version of default dependency')
t.create('Locked version of default dependency (branch)')
.get(
'/locked/dependency-version/metabolize/rq-dashboard-on-heroku/rq-dashboard/main.json'
'/locked/dependency-version/metabolize/rq-dashboard-on-heroku/rq-dashboard/master.json'
)
.expectBadge({
label: 'rq-dashboard',
@@ -65,7 +65,7 @@ t.create('Locked version of dev dependency')
t.create('Locked version of dev dependency (branch)')
.get(
'/locked/dependency-version/metabolize/rq-dashboard-on-heroku/dev/black/main.json'
'/locked/dependency-version/metabolize/rq-dashboard-on-heroku/dev/black/master.json'
)
.expectBadge({
label: 'black',