diff --git a/lib/modules/datasource/go/releases-goproxy.spec.ts b/lib/modules/datasource/go/releases-goproxy.spec.ts index 55250e597fadb4..06feefb8a766ab 100644 --- a/lib/modules/datasource/go/releases-goproxy.spec.ts +++ b/lib/modules/datasource/go/releases-goproxy.spec.ts @@ -1,3 +1,4 @@ +import { codeBlock } from 'common-tags'; import { Fixtures } from '../../../../test/fixtures'; import * as httpMock from '../../../../test/http-mock'; import { GithubReleasesDatasource } from '../github-releases'; @@ -340,7 +341,10 @@ describe('modules/datasource/go/releases-goproxy', () => { .get('/@v/list') .reply( 200, - ['v1.0.0 2018-08-13T15:31:12Z', 'v1.0.1', ' \n'].join('\n') + codeBlock` + v1.0.0 2018-08-13T15:31:12Z + v1.0.1 + ` ) .get('/@v/v1.0.1.info') .reply(200, { Version: 'v1.0.1', Time: '2019-10-16T16:15:28Z' }) @@ -366,13 +370,21 @@ describe('modules/datasource/go/releases-goproxy', () => { httpMock .scope(`${baseUrl}/github.com/google/btree`) .get('/@v/list') - .reply(200, 'v1.0.0\nv1.0.1\n') + .reply( + 200, + codeBlock` + v1.0.0 + v1.0.1 + ` + ) .get('/@v/v1.0.0.info') .replyWithError('unknown') .get('/@v/v1.0.1.info') .reply(410) .get('/v2/@v/list') - .reply(200); + .reply(200) + .get('/v3/@v/list') + .reply(404); const res = await datasource.getReleases({ packageName: 'github.com/google/btree', @@ -395,7 +407,13 @@ describe('modules/datasource/go/releases-goproxy', () => { httpMock .scope(`${baseUrl}/github.com/google/btree`) .get('/@v/list') - .reply(200, 'v1.0.0\nv1.0.1\n') + .reply( + 200, + codeBlock` + v1.0.0 + v1.0.1 + ` + ) .get('/@v/v1.0.0.info') .reply(200, { Version: 'v1.0.0', Time: '2018-08-13T15:31:12Z' }) .get('/@v/v1.0.1.info') @@ -436,7 +454,13 @@ describe('modules/datasource/go/releases-goproxy', () => { httpMock .scope(`${baseUrl}/github.com/google/btree`) .get('/@v/list') - .reply(200, 'v1.0.0\nv1.0.1\n') + .reply( + 200, + codeBlock` + v1.0.0 + v1.0.1 + ` + ) .get('/@v/v1.0.0.info') .reply(200, { Version: 'v1.0.0', Time: '2018-08-13T15:31:12Z' }) .get('/@v/v1.0.1.info') @@ -580,13 +604,24 @@ describe('modules/datasource/go/releases-goproxy', () => { httpMock .scope(`${baseUrl}/github.com/google/btree`) .get('/@v/list') - .reply(200, 'v1.0.0\nv1.0.1\n') + .reply( + 200, + codeBlock` + v1.0.0 + v1.0.1 + ` + ) .get('/@v/v1.0.0.info') .reply(200, { Version: 'v1.0.0', Time: '2018-08-13T15:31:12Z' }) .get('/@v/v1.0.1.info') .reply(200, { Version: 'v1.0.1', Time: '2019-10-16T16:15:28Z' }) .get('/v2/@v/list') - .reply(200, 'v2.0.0\n') + .reply( + 200, + codeBlock` + v2.0.0 + ` + ) .get('/v2/@v/v2.0.0.info') .reply(200, { Version: 'v2.0.0', Time: '2020-10-16T16:15:28Z' }) .get('/v3/@v/list') @@ -679,7 +714,9 @@ describe('modules/datasource/go/releases-goproxy', () => { httpMock .scope(`${baseUrl}/github.com/google/btree`) .get('/@v/list') - .reply(200); + .reply(200) + .get('/v2/@v/list') + .reply(404); const res = await datasource.getReleases({ packageName: 'github.com/google/btree', diff --git a/lib/modules/datasource/go/releases-goproxy.ts b/lib/modules/datasource/go/releases-goproxy.ts index 7d00bfaa18eb45..a06c3520354486 100644 --- a/lib/modules/datasource/go/releases-goproxy.ts +++ b/lib/modules/datasource/go/releases-goproxy.ts @@ -3,6 +3,7 @@ import { DateTime } from 'luxon'; import moo from 'moo'; import { logger } from '../../../logger'; import { cache } from '../../../util/cache/package/decorator'; +import { HttpError } from '../../../util/http'; import * as p from '../../../util/promises'; import { newlineRegex, regEx } from '../../../util/regex'; import { Datasource } from '../datasource'; @@ -14,7 +15,7 @@ import type { GoproxyItem, VersionInfo } from './types'; const parsedGoproxy: Record = {}; -const modRegex = regEx(`^(?.*?)(?:[./]v(?\\d+))?$`); +const modRegex = regEx(/^(?.*?)(?:[./]v(?\d+))?$/); export class GoProxyDatasource extends Datasource { static readonly id = 'go-proxy'; @@ -47,12 +48,6 @@ export class GoProxyDatasource extends Datasource { return result; } - const isGopkgin = packageName.startsWith('gopkg.in/'); - const majorSuffixSeparator = isGopkgin ? '.' : '/'; - const modParts = packageName.match(modRegex); - const baseMod = modParts?.groups?.baseMod ?? packageName; - const currentMajor = parseInt(modParts?.groups?.majorVersion ?? '0'); - for (const { url, fallback } of proxyList) { try { if (url === 'off') { @@ -62,43 +57,20 @@ export class GoProxyDatasource extends Datasource { break; } - const releases: Release[] = []; - for (let i = 0; ; i++) { - try { - const major = currentMajor + i; - let mod: string; - if (major < 2 && !isGopkgin) { - mod = baseMod; - i++; // v0 and v1 are the same module - } else { - mod = `${baseMod}${majorSuffixSeparator}v${major}`; - } - const result = await this.getVersionsWithInfo(url, mod); - if (result.length === 0) { - break; - } - releases.push(...result); - } catch (err) { - const statusCode = err?.response?.statusCode; - if (i > 0 && statusCode === 404) { - break; - } - throw err; - } - } - - if (releases.length) { + const res = await this.getVersionsWithInfo(url, packageName); + if (res.releases.length) { + result = res; try { const datasource = await BaseGoDatasource.getDatasource( packageName ); - const sourceUrl = getSourceUrl(datasource) ?? null; - result = { releases, sourceUrl }; + const sourceUrl = getSourceUrl(datasource); + if (sourceUrl) { + result.sourceUrl = sourceUrl; + } } catch (err) { logger.trace({ err }, `Can't get datasource for ${packageName}`); - result = { releases }; } - break; } } catch (err) { @@ -263,23 +235,52 @@ export class GoProxyDatasource extends Datasource { async getVersionsWithInfo( baseUrl: string, packageName: string - ): Promise { - const releasesIndex = await this.listVersions(baseUrl, packageName); - const releases = await p.map(releasesIndex, async (versionInfo) => { - const { version, releaseTimestamp } = versionInfo; + ): Promise { + const isGopkgin = packageName.startsWith('gopkg.in/'); + const majorSuffixSeparator = isGopkgin ? '.' : '/'; + const modParts = packageName.match(modRegex)?.groups; + const baseMod = modParts?.baseMod ?? /* istanbul ignore next */ packageName; + const packageMajor = parseInt(modParts?.majorVersion ?? '0'); - if (releaseTimestamp) { - return { version, releaseTimestamp }; + const result: ReleaseResult = { releases: [] }; + for (let major = packageMajor; ; major += 1) { + let pkg = `${baseMod}${majorSuffixSeparator}v${major}`; + if (!isGopkgin && major < 2) { + pkg = baseMod; + major += 1; // v0 and v1 are the same module } try { - return await this.versionInfo(baseUrl, packageName, version); + const res = await this.listVersions(baseUrl, pkg); + const releases = await p.map(res, async (versionInfo) => { + const { version, releaseTimestamp } = versionInfo; + + if (releaseTimestamp) { + return { version, releaseTimestamp }; + } + + try { + return await this.versionInfo(baseUrl, pkg, version); + } catch (err) { + logger.trace({ err }, `Can't obtain data from ${baseUrl}`); + return { version }; + } + }); + result.releases.push(...releases); } catch (err) { - logger.trace({ err }, `Can't obtain data from ${baseUrl}`); - return { version }; + if ( + err instanceof HttpError && + err.response?.statusCode === 404 && + major !== packageMajor + ) { + break; + } + + throw err; } - }); - return releases; + } + + return result; } static getCacheKey({ packageName }: GetReleasesConfig): string {