diff --git a/lib/modules/datasource/github-releases/cache/cache-base.spec.ts b/lib/modules/datasource/github-releases/cache/cache-base.spec.ts index b0fa4162c66af85b10a786f7e6c06425c8da43e3..b08d2002633008537900a70667bd27cb2ff5c2d9 100644 --- a/lib/modules/datasource/github-releases/cache/cache-base.spec.ts +++ b/lib/modules/datasource/github-releases/cache/cache-base.spec.ts @@ -333,7 +333,7 @@ describe('modules/datasource/github-releases/cache/cache-base', () => { { statusCode: 200, headers: {}, - body: { errors: [{ message: 'Ooops' }] }, + body: { errors: [{} as never, { message: 'Ooops' }] }, }, ]; const cache = new TestCache(http, { resetDeltaMinutes: 0 }); @@ -345,6 +345,50 @@ describe('modules/datasource/github-releases/cache/cache-base', () => { expect(packageCache.set).not.toHaveBeenCalled(); }); + it('throws for unknown graphql errors', async () => { + packageCache.get.mockResolvedValueOnce({ + items: {}, + createdAt: t3, + updatedAt: t3, + }); + responses = [ + { + statusCode: 200, + headers: {}, + body: { errors: [] }, + }, + ]; + const cache = new TestCache(http, { resetDeltaMinutes: 0 }); + + await expect(cache.getItems({ packageName: 'foo/bar' })).rejects.toThrow( + 'GitHub datasource cache: unknown GraphQL error' + ); + expect(packageCache.get).toHaveBeenCalled(); + expect(packageCache.set).not.toHaveBeenCalled(); + }); + + it('throws for empty payload', async () => { + packageCache.get.mockResolvedValueOnce({ + items: {}, + createdAt: t3, + updatedAt: t3, + }); + responses = [ + { + statusCode: 200, + headers: {}, + body: { data: { repository: { payload: null as never } } }, + }, + ]; + const cache = new TestCache(http, { resetDeltaMinutes: 0 }); + + await expect(cache.getItems({ packageName: 'foo/bar' })).rejects.toThrow( + 'GitHub datasource cache: failed to obtain payload data' + ); + expect(packageCache.get).toHaveBeenCalled(); + expect(packageCache.set).not.toHaveBeenCalled(); + }); + it('shrinks for some of graphql errors', async () => { packageCache.get.mockResolvedValueOnce({ items: {}, diff --git a/lib/modules/datasource/github-releases/cache/cache-base.ts b/lib/modules/datasource/github-releases/cache/cache-base.ts index a5a7d27fb1aa36fc2da248a9c264988d2247b956..447ec37156f710c4b9671bdc4f58af2612117cb0 100644 --- a/lib/modules/datasource/github-releases/cache/cache-base.ts +++ b/lib/modules/datasource/github-releases/cache/cache-base.ts @@ -1,3 +1,4 @@ +import is from '@sindresorhus/is'; import { DateTime, DurationLikeObject } from 'luxon'; import { logger } from '../../../../logger'; import * as memCache from '../../../../util/cache/memory'; @@ -164,11 +165,11 @@ export abstract class AbstractGithubDatasourceCache< */ abstract coerceFetched(fetchedItem: FetchedItem): StoredItem | null; - private async query( + private async queryPayload( baseUrl: string, variables: GithubQueryParams, options: GithubHttpOptions - ): Promise<QueryResponse<FetchedItem> | Error> { + ): Promise<QueryResponse<FetchedItem>['repository']['payload'] | Error> { try { const graphqlRes = await this.http.postJson< GithubGraphqlResponse<QueryResponse<FetchedItem>> @@ -179,7 +180,22 @@ export abstract class AbstractGithubDatasourceCache< }); const { body } = graphqlRes; const { data, errors } = body; - return data ?? new Error(errors?.[0]?.message); + + if (errors) { + let [errorMessage] = errors + .map(({ message }) => message) + .filter(is.string); + errorMessage ??= 'GitHub datasource cache: unknown GraphQL error'; + return new Error(errorMessage); + } + + if (!data?.repository?.payload) { + return new Error( + 'GitHub datasource cache: failed to obtain payload data' + ); + } + + return data.repository.payload; } catch (err) { return err; } @@ -282,12 +298,12 @@ export abstract class AbstractGithubDatasourceCache< : this.maxPrefetchPages; let stopIteration = false; while (pagesRemained > 0 && !stopIteration) { - const res = await this.query(baseUrl, variables, { + const queryResult = await this.queryPayload(baseUrl, variables, { repository: packageName, }); - if (res instanceof Error) { + if (queryResult instanceof Error) { if ( - res.message.startsWith( + queryResult.message.startsWith( 'Something went wrong while executing your query.' // #16343 ) && variables.count > 30 @@ -299,7 +315,7 @@ export abstract class AbstractGithubDatasourceCache< variables.count = Math.floor(variables.count / 2); continue; } - throw res; + throw queryResult; } pagesRemained -= 1; @@ -307,7 +323,7 @@ export abstract class AbstractGithubDatasourceCache< const { nodes: fetchedItems, pageInfo: { hasNextPage, endCursor }, - } = res.repository.payload; + } = queryResult; if (hasNextPage) { variables.cursor = endCursor;