From acc6cf5ced53e608d6026f7b00a454c535919851 Mon Sep 17 00:00:00 2001 From: Jamie Magee Date: Tue, 14 Jul 2020 10:58:44 +0200 Subject: [PATCH] refactor(datasource): migrate to class based datasource A small experiment into what OOP/class based datasources might look like. Picked Cdnjs as it's the smallest & simplest. With this approach we can share common logic, like error handling, rate limiting, etc. between different datasources, instead of having to reimplement it each time we write a new datasource. Currently there's nothing shared, as it's only 1 datasource, but the interesting stuff will come with the 2nd datasource --- .eslintrc.js | 1 + .../cdnjs/__snapshots__/index.spec.ts.snap | 2 +- lib/datasource/cdnjs/index.spec.ts | 2 +- lib/datasource/cdnjs/index.ts | 82 +- lib/datasource/clojure/index.ts | 14 +- .../crate/__snapshots__/index.spec.ts.snap | 791 ++++++++++++++++++ lib/datasource/crate/index.spec.ts | 33 +- lib/datasource/crate/index.ts | 140 ++-- lib/datasource/datasource.ts | 36 + lib/datasource/index.spec.ts | 25 +- lib/datasource/index.ts | 20 +- lib/datasource/pod/index.ts | 2 +- lib/util/http/index.ts | 4 + lib/versioning/loose/generic.ts | 1 - package.json | 4 +- tools/generate-imports.ts | 10 +- tools/jest-gh-reporter.ts | 1 - 17 files changed, 1027 insertions(+), 141 deletions(-) create mode 100644 lib/datasource/datasource.ts diff --git a/.eslintrc.js b/.eslintrc.js index d53c730b04d746..bfc99497a8bdd5 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -42,6 +42,7 @@ module.exports = { 'prefer-destructuring': 0, 'prefer-template': 0, 'no-underscore-dangle': 0, + 'class-methods-use-this': 0, 'sort-imports': [ 'error', diff --git a/lib/datasource/cdnjs/__snapshots__/index.spec.ts.snap b/lib/datasource/cdnjs/__snapshots__/index.spec.ts.snap index 3c12b51b7598c5..e77fdf10664362 100644 --- a/lib/datasource/cdnjs/__snapshots__/index.spec.ts.snap +++ b/lib/datasource/cdnjs/__snapshots__/index.spec.ts.snap @@ -185,7 +185,7 @@ Array [ ] `; -exports[`datasource/cdnjs getReleases returns null for unknown error 1`] = ` +exports[`datasource/cdnjs getReleases throws for unknown error 1`] = ` Array [ Object { "headers": Object { diff --git a/lib/datasource/cdnjs/index.spec.ts b/lib/datasource/cdnjs/index.spec.ts index 2ff92f7cbf5e6d..3e9927a29e1521 100644 --- a/lib/datasource/cdnjs/index.spec.ts +++ b/lib/datasource/cdnjs/index.spec.ts @@ -87,7 +87,7 @@ describe('datasource/cdnjs', () => { ).rejects.toThrow(EXTERNAL_HOST_ERROR); expect(httpMock.getTrace()).toMatchSnapshot(); }); - it('returns null for unknown error', async () => { + it('throws for unknown error', async () => { httpMock.scope(baseUrl).get(pathFor('foo/bar')).replyWithError('error'); await expect( getPkgReleases({ datasource, depName: 'foo/bar' }) diff --git a/lib/datasource/cdnjs/index.ts b/lib/datasource/cdnjs/index.ts index 58f912c6454202..7fd34d1f12b7fb 100644 --- a/lib/datasource/cdnjs/index.ts +++ b/lib/datasource/cdnjs/index.ts @@ -1,12 +1,11 @@ import { ExternalHostError } from '../../types/errors/external-host-error'; -import { Http } from '../../util/http'; +import { HttpError } from '../../util/http'; import { CachePromise, cacheAble } from '../cache'; import { GetReleasesConfig, ReleaseResult } from '../common'; +import { Datasource } from '../datasource'; export const id = 'cdnjs'; -const http = new Http(id); - interface CdnjsAsset { version: string; files: string[]; @@ -22,43 +21,54 @@ interface CdnjsResponse { assets?: CdnjsAsset[]; } -async function downloadLibrary(library: string): CachePromise { - const url = `https://api.cdnjs.com/libraries/${library}?fields=homepage,repository,assets`; - return { data: (await http.getJson(url)).body }; -} - -export async function getReleases({ - lookupName, -}: GetReleasesConfig): Promise { - // Each library contains multiple assets, so we cache at the library level instead of per-asset - const library = lookupName.split('/')[0]; - try { - const { assets, homepage, repository } = await cacheAble({ - id, - lookup: library, - cb: downloadLibrary, - }); - if (!assets) { - return null; - } - const assetName = lookupName.replace(`${library}/`, ''); - const releases = assets - .filter(({ files }) => files.includes(assetName)) - .map(({ version, sri }) => ({ version, newDigest: sri[assetName] })); +export class CdnJs extends Datasource { + readonly id = 'cdnjs'; - const result: ReleaseResult = { releases }; + private async downloadLibrary(library: string): CachePromise { + const url = `https://api.cdnjs.com/libraries/${library}?fields=homepage,repository,assets`; + return { data: (await this.http.getJson(url)).body }; + } - if (homepage) { - result.homepage = homepage; - } - if (repository?.url) { - result.sourceUrl = repository.url; - } - return result; - } catch (err) { + handleSpecificErrors(err: HttpError): void { if (err.statusCode !== 404) { throw new ExternalHostError(err); } - throw err; + } + + // this.handleErrors will always throw + // eslint-disable-next-line consistent-return + async getReleases({ + lookupName, + }: GetReleasesConfig): Promise { + const library = lookupName.split('/')[0]; + try { + const { assets, homepage, repository } = await cacheAble({ + id, + lookup: library, + cb: () => this.downloadLibrary(library), + }); + if (!assets) { + return null; + } + const assetName = lookupName.replace(`${library}/`, ''); + const releases = assets + .filter(({ files }) => files.includes(assetName)) + .map(({ version, sri }) => ({ version, newDigest: sri[assetName] })); + + const result: ReleaseResult = { releases }; + + if (homepage) { + result.homepage = homepage; + } + if (repository?.url) { + result.sourceUrl = repository.url; + } + return result; + } catch (err) { + if (err.statusCode !== undefined && err.statusCode !== 404) { + throw new ExternalHostError(err); + } + this.handleGenericErrors(err); + } } } diff --git a/lib/datasource/clojure/index.ts b/lib/datasource/clojure/index.ts index 8e86fdded4ee9e..4ec2554b32a002 100644 --- a/lib/datasource/clojure/index.ts +++ b/lib/datasource/clojure/index.ts @@ -1,3 +1,6 @@ +import { GetReleasesConfig, ReleaseResult } from '../common'; +import { Datasource } from '../datasource'; +import { getReleases } from '../maven'; import { MAVEN_REPO } from '../maven/common'; export const id = 'clojure'; @@ -5,4 +8,13 @@ export const id = 'clojure'; export const defaultRegistryUrls = ['https://clojars.org/repo', MAVEN_REPO]; export const registryStrategy = 'merge'; -export { getReleases } from '../maven'; +export class Clojure extends Datasource { + readonly id = 'clojure'; + + getReleases({ + lookupName, + registryUrl, + }: GetReleasesConfig): Promise { + return getReleases({ lookupName, registryUrl }); + } +} diff --git a/lib/datasource/crate/__snapshots__/index.spec.ts.snap b/lib/datasource/crate/__snapshots__/index.spec.ts.snap index 12358777c1acce..e44f33a4da2581 100644 --- a/lib/datasource/crate/__snapshots__/index.spec.ts.snap +++ b/lib/datasource/crate/__snapshots__/index.spec.ts.snap @@ -1,5 +1,796 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`datasource/crate getReleases makes http call with correct suffix 1`] = ` +Array [ + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/no/n_/non_existent_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/no/n_/non_existent_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/no/n_/non_existent_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/so/me/some_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/so/me/some_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/so/me/some_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/li/bc/libc", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/am/et/amethyst", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/1/a", + }, +] +`; + +exports[`datasource/crate getReleases makes http call with correct suffix 2`] = ` +Array [ + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/no/n_/non_existent_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/no/n_/non_existent_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/no/n_/non_existent_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/so/me/some_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/so/me/some_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/so/me/some_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/li/bc/libc", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/am/et/amethyst", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/1/a", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/1/1", + }, +] +`; + +exports[`datasource/crate getReleases makes http call with correct suffix 3`] = ` +Array [ + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/no/n_/non_existent_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/no/n_/non_existent_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/no/n_/non_existent_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/so/me/some_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/so/me/some_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/so/me/some_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/li/bc/libc", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/am/et/amethyst", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/1/a", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/1/1", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/12/34/1234567", + }, +] +`; + +exports[`datasource/crate getReleases makes http call with correct suffix 4`] = ` +Array [ + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/no/n_/non_existent_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/no/n_/non_existent_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/no/n_/non_existent_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/so/me/some_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/so/me/some_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/so/me/some_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/li/bc/libc", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/am/et/amethyst", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/1/a", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/1/1", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/12/34/1234567", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/2/ab", + }, +] +`; + +exports[`datasource/crate getReleases makes http call with correct suffix 5`] = ` +Array [ + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/no/n_/non_existent_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/no/n_/non_existent_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/no/n_/non_existent_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/so/me/some_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/so/me/some_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/so/me/some_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/li/bc/libc", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/am/et/amethyst", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/1/a", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/1/1", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/12/34/1234567", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/2/ab", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/3/a/abc", + }, +] +`; + +exports[`datasource/crate getReleases makes http call with correct suffix 6`] = ` +Array [ + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/no/n_/non_existent_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/no/n_/non_existent_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/no/n_/non_existent_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/so/me/some_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/so/me/some_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/so/me/some_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/li/bc/libc", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/am/et/amethyst", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/1/a", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/1/1", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/12/34/1234567", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/2/ab", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/3/a/abc", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/ab/cd/abcd", + }, +] +`; + +exports[`datasource/crate getReleases makes http call with correct suffix 7`] = ` +Array [ + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/no/n_/non_existent_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/no/n_/non_existent_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/no/n_/non_existent_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/so/me/some_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/so/me/some_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/so/me/some_crate", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/li/bc/libc", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/am/et/amethyst", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/1/a", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/1/1", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/12/34/1234567", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/2/ab", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/3/a/abc", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/ab/cd/abcd", + }, + Object { + "headers": Object { + "accept-encoding": "gzip, deflate", + "host": "raw.githubusercontent.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://raw.githubusercontent.com/rust-lang/crates.io-index/master/ab/cd/abcde", + }, +] +`; + exports[`datasource/crate getReleases processes real data: amethyst 1`] = ` Object { "dependencyUrl": "https://crates.io/crates/amethyst", diff --git a/lib/datasource/crate/index.spec.ts b/lib/datasource/crate/index.spec.ts index 4677e8d0252935..179b4841dc932f 100644 --- a/lib/datasource/crate/index.spec.ts +++ b/lib/datasource/crate/index.spec.ts @@ -2,7 +2,7 @@ import fs from 'fs'; import { getPkgReleases } from '..'; import * as httpMock from '../../../test/httpMock'; -import { id as datasource, getIndexSuffix } from '.'; +import { id as datasource } from '.'; const res1 = fs.readFileSync('lib/datasource/crate/__fixtures__/libc', 'utf8'); const res2 = fs.readFileSync( @@ -14,18 +14,6 @@ const baseUrl = 'https://raw.githubusercontent.com/rust-lang/crates.io-index/master/'; describe('datasource/crate', () => { - describe('getIndexSuffix', () => { - it('returns correct suffixes', () => { - expect(getIndexSuffix('a')).toBe('1/a'); - expect(getIndexSuffix('1')).toBe('1/1'); - expect(getIndexSuffix('1234567')).toBe('12/34/1234567'); - expect(getIndexSuffix('ab')).toBe('2/ab'); - expect(getIndexSuffix('abc')).toBe('3/a/abc'); - expect(getIndexSuffix('abcd')).toBe('ab/cd/abcd'); - expect(getIndexSuffix('abcde')).toBe('ab/cd/abcde'); - }); - }); - describe('getReleases', () => { it('returns null for empty result', async () => { httpMock.scope(baseUrl).get('/no/n_/non_existent_crate').reply(200, {}); @@ -108,5 +96,24 @@ describe('datasource/crate', () => { expect(res).toBeDefined(); expect(httpMock.getTrace()).toMatchSnapshot(); }); + it.each([ + ['a', '/1/a'], + ['1', '/1/1'], + ['1234567', '/12/34/1234567'], + ['ab', '/2/ab'], + ['abc', '/3/a/abc'], + ['abcd', '/ab/cd/abcd'], + ['abcde', '/ab/cd/abcde'], + ])( + 'makes http call with correct suffix', + async (lookupName, indexSuffix) => { + httpMock.scope(baseUrl).get(indexSuffix).reply(200, '\n'); + await getPkgReleases({ + datasource, + depName: lookupName, + }); + expect(httpMock.getTrace()).toMatchSnapshot(); + } + ); }); }); diff --git a/lib/datasource/crate/index.ts b/lib/datasource/crate/index.ts index 198e781a9d1295..c553181b004ffa 100644 --- a/lib/datasource/crate/index.ts +++ b/lib/datasource/crate/index.ts @@ -1,88 +1,84 @@ -import { ExternalHostError } from '../../types/errors/external-host-error'; import * as packageCache from '../../util/cache/package'; -import { Http } from '../../util/http'; import { GetReleasesConfig, Release, ReleaseResult } from '../common'; +import { Datasource } from '../datasource'; export const id = 'crate'; -const http = new Http(id); - -const BASE_URL = - 'https://raw.githubusercontent.com/rust-lang/crates.io-index/master/'; - -export function getIndexSuffix(lookupName: string): string { - const len = lookupName.length; - - if (len === 1) { - return '1/' + lookupName; - } - if (len === 2) { - return '2/' + lookupName; - } - if (len === 3) { - return '3/' + lookupName[0] + '/' + lookupName; - } - - return ( - lookupName.slice(0, 2) + '/' + lookupName.slice(2, 4) + '/' + lookupName - ); -} - interface CrateRecord { vers: string; yanked: boolean; } -export async function getReleases({ - lookupName, -}: GetReleasesConfig): Promise { - const cacheNamespace = 'datasource-crate'; - const cacheKey = lookupName; - const cachedResult = await packageCache.get( - cacheNamespace, - cacheKey - ); - // istanbul ignore if - if (cachedResult) { - return cachedResult; +export class Crate extends Datasource { + readonly id = 'crate'; + + readonly BASE_URL = + 'https://raw.githubusercontent.com/rust-lang/crates.io-index/master/'; + + getIndexSuffix(lookupName: string): string { + const len = lookupName.length; + + if (len === 1) { + return '1/' + lookupName; + } + if (len === 2) { + return '2/' + lookupName; + } + if (len === 3) { + return '3/' + lookupName[0] + '/' + lookupName; + } + + return ( + lookupName.slice(0, 2) + '/' + lookupName.slice(2, 4) + '/' + lookupName + ); } - const crateUrl = BASE_URL + getIndexSuffix(lookupName); - const dependencyUrl = `https://crates.io/crates/${lookupName}`; - try { - const lines = (await http.get(crateUrl)).body - .split('\n') // break into lines - .map((line) => line.trim()) // remove whitespace - .filter((line) => line.length !== 0) // remove empty lines - .map((line) => JSON.parse(line) as CrateRecord); // parse - const result: ReleaseResult = { - dependencyUrl, - releases: [], - }; - result.releases = lines - .map((version) => { - const release: Release = { - version: version.vers, - }; - if (version.yanked) { - release.isDeprecated = true; - } - return release; - }) - .filter((release) => release.version); - if (!result.releases.length) { - return null; + // this.handleErrors will always throw + // eslint-disable-next-line consistent-return + async getReleases({ + lookupName, + }: GetReleasesConfig): Promise { + const cacheNamespace = 'datasource-crate'; + const cacheKey = lookupName; + const cachedResult = await packageCache.get( + cacheNamespace, + cacheKey + ); + // istanbul ignore if + if (cachedResult) { + return cachedResult; } - const cacheMinutes = 10; - await packageCache.set(cacheNamespace, cacheKey, result, cacheMinutes); - return result; - } catch (err) { - if ( - err.statusCode === 429 || - (err.statusCode >= 500 && err.statusCode < 600) - ) { - throw new ExternalHostError(err); + const crateUrl = this.BASE_URL + this.getIndexSuffix(lookupName); + const dependencyUrl = `https://crates.io/crates/${lookupName}`; + try { + const lines = (await this.http.get(crateUrl)).body + .split('\n') // break into lines + .map((line) => line.trim()) // remove whitespace + .filter((line) => line.length !== 0) // remove empty lines + .map((line) => JSON.parse(line) as CrateRecord); // parse + const result: ReleaseResult = { + dependencyUrl, + releases: [], + }; + result.releases = lines + .map((version: { vers: string; yanked: boolean }) => { + const release: Release = { + version: version.vers, + }; + if (version.yanked) { + release.isDeprecated = true; + } + return release; + }) + .filter((release) => release.version); + if (!result.releases.length) { + return null; + } + const cacheMinutes = 10; + await packageCache.set(cacheNamespace, cacheKey, result, cacheMinutes); + return result; + } catch (err) { + this.handleGenericErrors(err); } - throw err; } } diff --git a/lib/datasource/datasource.ts b/lib/datasource/datasource.ts new file mode 100644 index 00000000000000..58859a43644486 --- /dev/null +++ b/lib/datasource/datasource.ts @@ -0,0 +1,36 @@ +import { ExternalHostError } from '../types/errors/external-host-error'; +import { Http, HttpError } from '../util/http'; +import { GetReleasesConfig, ReleaseResult } from './common'; + +export abstract class Datasource { + constructor() { + this.http = new Http(this.getId()); + } + + abstract id: string; + + getId(): string { + return this.id; + } + + protected http: Http; + + abstract getReleases( + getReleasesConfig: GetReleasesConfig + ): Promise; + + handleSpecificErrors(err: HttpError): void {} + + protected handleGenericErrors(err: HttpError): never { + this.handleSpecificErrors(err); + if (err.statusCode !== undefined) { + if ( + err.statusCode === 429 || + (err.statusCode >= 500 && err.statusCode < 600) + ) { + throw new ExternalHostError(err); + } + } + throw err; + } +} diff --git a/lib/datasource/index.spec.ts b/lib/datasource/index.spec.ts index ee1ec40b11d7df..681d6275f10e50 100644 --- a/lib/datasource/index.spec.ts +++ b/lib/datasource/index.spec.ts @@ -28,9 +28,8 @@ describe('datasource/index', () => { }); it('returns datasources', () => { expect(datasource.getDatasources()).toBeDefined(); - expect(datasource.getDatasourceList()).toBeDefined(); }); - it('validates dataource', () => { + it('validates datasource', () => { function validateDatasource( module: datasource.Datasource, name: string @@ -43,9 +42,21 @@ describe('datasource/index', () => { } return true; } + function filterClassBasedDatasources(name: string): boolean { + return !['cdnjs', 'clojure', 'crate'].includes(name); + } const dss = datasource.getDatasources(); - const loadedDs = loadModules(__dirname, validateDatasource); + // class based datasources + dss.delete('cdnjs'); + dss.delete('clojure'); + dss.delete('crate'); + + const loadedDs = loadModules( + __dirname, + validateDatasource, + filterClassBasedDatasources + ); expect(Array.from(dss.keys())).toEqual(Object.keys(loadedDs)); for (const dsName of dss.keys()) { @@ -82,6 +93,14 @@ describe('datasource/index', () => { }) ).toBeNull(); }); + it('returns class datasource', async () => { + expect( + await datasource.getPkgReleases({ + datasource: 'cdnjs', + depName: null, + }) + ).toBeNull(); + }); it('returns getDigest', async () => { expect( await datasource.getDigest({ diff --git a/lib/datasource/index.ts b/lib/datasource/index.ts index 2aa1554f0d5886..28aa70e4784288 100644 --- a/lib/datasource/index.ts +++ b/lib/datasource/index.ts @@ -8,6 +8,8 @@ import { clone } from '../util/clone'; import { regEx } from '../util/regex'; import * as allVersioning from '../versioning'; import datasources from './api.generated'; +import { CdnJs } from './cdnjs'; +import { Clojure } from './clojure'; import { Datasource, DigestConfig, @@ -16,16 +18,20 @@ import { Release, ReleaseResult, } from './common'; +import { Crate } from './crate'; import { addMetaData } from './metadata'; export * from './common'; export const getDatasources = (): Map => datasources; -export const getDatasourceList = (): string[] => Array.from(datasources.keys()); const cacheNamespace = 'datasource-releases'; -function load(datasource: string): Datasource { +datasources.set('cdnjs', new CdnJs()); +datasources.set('clojure', new Clojure()); +datasources.set('crate', new Crate()); + +function getDatasourceFor(datasource: string): Datasource { return datasources.get(datasource); } @@ -166,11 +172,11 @@ async function fetchReleases( config: GetReleasesInternalConfig ): Promise { const { datasource: datasourceName } = config; - if (!datasourceName || !datasources.has(datasourceName)) { + if (!datasourceName || getDatasourceFor(datasourceName) === undefined) { logger.warn('Unknown datasource: ' + datasourceName); return null; } - const datasource = load(datasourceName); + const datasource = getDatasourceFor(datasourceName); const registryUrls = resolveRegistryUrls(datasource, config.registryUrls); let dep: ReleaseResult = null; try { @@ -295,14 +301,14 @@ export async function getPkgReleases( } export function supportsDigests(config: DigestConfig): boolean { - return 'getDigest' in load(config.datasource); + return 'getDigest' in getDatasourceFor(config.datasource); } export function getDigest( config: DigestConfig, value?: string ): Promise { - const datasource = load(config.datasource); + const datasource = getDatasourceFor(config.datasource); const lookupName = config.lookupName || config.depName; const registryUrls = resolveRegistryUrls(datasource, config.registryUrls); return datasource.getDigest( @@ -314,7 +320,7 @@ export function getDigest( export function getDefaultConfig( datasource: string ): Promise> { - const loadedDatasource = load(datasource); + const loadedDatasource = getDatasourceFor(datasource); return Promise.resolve>( loadedDatasource?.defaultConfig || Object.create({}) ); diff --git a/lib/datasource/pod/index.ts b/lib/datasource/pod/index.ts index 065734df1f86eb..ee3d9ccc475634 100644 --- a/lib/datasource/pod/index.ts +++ b/lib/datasource/pod/index.ts @@ -41,7 +41,7 @@ function releasesGithubUrl( function handleError(lookupName: string, err: HttpError): void { const errorData = { lookupName, err }; - const statusCode = err.response?.statusCode; + const statusCode = err.statusCode; if (statusCode === 429 || (statusCode >= 500 && statusCode < 600)) { logger.warn({ lookupName, err }, `CocoaPods registry failure`); throw new ExternalHostError(err); diff --git a/lib/util/http/index.ts b/lib/util/http/index.ts index 8cb1e3af52052c..ea4290623bb9ba 100644 --- a/lib/util/http/index.ts +++ b/lib/util/http/index.ts @@ -45,6 +45,10 @@ export interface HttpResponse { headers: any; } +export interface HttpError extends Error { + statusCode: number; +} + function cloneResponse(response: any): HttpResponse { // clone body and headers so that the cached result doesn't get accidentally mutated return { diff --git a/lib/versioning/loose/generic.ts b/lib/versioning/loose/generic.ts index 55c50b8e987959..e6ad6b5dc600ef 100644 --- a/lib/versioning/loose/generic.ts +++ b/lib/versioning/loose/generic.ts @@ -189,7 +189,6 @@ export abstract class GenericVersioningApi< return versions.find((v) => this.equals(v, range)) || null; } - // eslint-disable-next-line class-methods-use-this getNewValue(newValueConfig: NewValueConfig): string { const { toVersion } = newValueConfig || {}; return toVersion; diff --git a/package.json b/package.json index 06cca77a538ca7..ee41cd8192d815 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,8 @@ "renovate-config-validator": "dist/config-validator.js" }, "scripts": { - "build": "run-s clean generate:* compile:*", - "clean": "rimraf dist", + "build": "run-s clean prepare:* generate:* compile:*", + "clean": "rimraf dist tmp", "clean-cache": "node bin/clean-cache.js", "compile:ts": "tsc -p tsconfig.app.json", "compile:dts": "tsc -p tsconfig.dts.json", diff --git a/tools/generate-imports.ts b/tools/generate-imports.ts index 530b284894176b..349d19806a4c17 100644 --- a/tools/generate-imports.ts +++ b/tools/generate-imports.ts @@ -9,12 +9,13 @@ if (!fs.existsSync('lib')) { shell.exit(0); } -function findModules(dirname: string): string[] { +function findModules(dirname: string, excludes: string[] = []): string[] { return fs .readdirSync(dirname, { withFileTypes: true }) .filter((dirent) => dirent.isDirectory()) .map((dirent) => dirent.name) .filter((name) => !name.startsWith('__')) + .filter((name) => !excludes.includes(name)) .sort(); } async function updateFile(file: string, code: string): Promise { @@ -68,7 +69,12 @@ async function generate({ (async () => { try { // datasources - await generate({ path: 'datasource', types: ['DatasourceApi'] }); + const datasourceExcludes = ['cdnjs', 'clojure', 'crate']; + await generate({ + path: 'datasource', + types: ['DatasourceApi'], + excludes: datasourceExcludes, + }); // managers await generate({ path: 'manager', types: ['ManagerApi'] }); diff --git a/tools/jest-gh-reporter.ts b/tools/jest-gh-reporter.ts index 3112a8c8836419..2ae31c6391afe6 100644 --- a/tools/jest-gh-reporter.ts +++ b/tools/jest-gh-reporter.ts @@ -45,7 +45,6 @@ function getPos(msg: string): Record { } class GitHubReporter extends BaseReporter { - // eslint-disable-next-line class-methods-use-this onRunComplete(_contexts: Set, testResult: AggregatedResult): void { try { if (getEnv('GITHUB_ACTIONS') !== 'true') {