diff --git a/lib/modules/datasource/go/__fixtures__/go-get-git-digest.html b/lib/modules/datasource/go/__fixtures__/go-get-git-digest.html new file mode 100644 index 0000000000000000000000000000000000000000..4b10d74eac2094cd3b9c5ee70e0e2d456c54888c --- /dev/null +++ b/lib/modules/datasource/go/__fixtures__/go-get-git-digest.html @@ -0,0 +1,8 @@ +<html> +<head> +<meta name="go-import" content="renovatebot.com/abc/def git https://renovatebot.com/abc/def.git"> +</head> +<body> +go get renovatebot.com/abc/def +</body> +</html> diff --git a/lib/modules/datasource/go/__snapshots__/releases-direct.spec.ts.snap b/lib/modules/datasource/go/__snapshots__/releases-direct.spec.ts.snap index dbb33a89b216711b3d013e1c8a6fb41fd3d373be..40b52a688f5542f53a83d7283ca994eedcec702f 100644 --- a/lib/modules/datasource/go/__snapshots__/releases-direct.spec.ts.snap +++ b/lib/modules/datasource/go/__snapshots__/releases-direct.spec.ts.snap @@ -19,6 +19,22 @@ exports[`modules/datasource/go/releases-direct getReleases support bitbucket tag } `; +exports[`modules/datasource/go/releases-direct getReleases support git 1`] = ` +{ + "releases": [ + { + "gitRef": "v1.0.0", + "version": "v1.0.0", + }, + { + "gitRef": "v2.0.0", + "version": "v2.0.0", + }, + ], + "sourceUrl": undefined, +} +`; + exports[`modules/datasource/go/releases-direct getReleases support gitlab 1`] = ` { "releases": [ diff --git a/lib/modules/datasource/go/base.spec.ts b/lib/modules/datasource/go/base.spec.ts index 517cb5d811ec566043237aa21f27b690d9435892..66d771ed00b6d62eb2832d47492171c3795e07a5 100644 --- a/lib/modules/datasource/go/base.spec.ts +++ b/lib/modules/datasource/go/base.spec.ts @@ -3,6 +3,7 @@ import * as httpMock from '../../../../test/http-mock'; import { mocked } from '../../../../test/util'; import { PlatformId } from '../../../constants'; import * as _hostRules from '../../../util/host-rules'; +import { GitTagsDatasource } from '../git-tags'; import { GithubTagsDatasource } from '../github-tags'; import { GitlabTagsDatasource } from '../gitlab-tags'; import { BaseGoDatasource } from './base'; @@ -99,6 +100,7 @@ describe('modules/datasource/go/base', () => { }); it('supports GitHub EE deps', async () => { + hostRules.hostType.mockReturnValue('github'); httpMock .scope('https://git.enterprise.com') .get('/example/module?go-get=1') @@ -303,7 +305,7 @@ describe('modules/datasource/go/base', () => { const res = await BaseGoDatasource.getDatasource('fyne.io/fyne'); expect(res).toEqual({ - datasource: 'github-tags', + datasource: GithubTagsDatasource.id, registryUrl: 'https://github.com', packageName: 'fyne-io/fyne', }); @@ -320,7 +322,7 @@ describe('modules/datasource/go/base', () => { const res = await BaseGoDatasource.getDatasource('fyne.io/fyne'); expect(res).toEqual({ - datasource: 'github-tags', + datasource: GithubTagsDatasource.id, registryUrl: 'https://github.com', packageName: 'fyne-io/fyne', }); @@ -339,11 +341,29 @@ describe('modules/datasource/go/base', () => { ); expect(res).toEqual({ - datasource: 'gitlab-tags', + datasource: GitlabTagsDatasource.id, registryUrl: 'https://gitlab.com', packageName: 'golang/myrepo', }); }); + + it('handles uncommon imports', async () => { + const meta = + '<meta name="go-import" content="example.com/uncommon git ssh://git.example.com/uncommon">'; + httpMock + .scope('https://example.com') + .get('/uncommon?go-get=1') + .reply(200, meta); + + const res = await BaseGoDatasource.getDatasource( + 'example.com/uncommon' + ); + + expect(res).toEqual({ + datasource: GitTagsDatasource.id, + packageName: 'ssh://git.example.com/uncommon', + }); + }); }); }); }); diff --git a/lib/modules/datasource/go/base.ts b/lib/modules/datasource/go/base.ts index 4e8f00ff83481d1ace028e117c807f63ed0eb831..43e241e5075232985c7bd88f04898eeadd3361c4 100644 --- a/lib/modules/datasource/go/base.ts +++ b/lib/modules/datasource/go/base.ts @@ -3,11 +3,13 @@ import URL from 'url'; import { PlatformId } from '../../../constants'; import { logger } from '../../../logger'; +import { detectPlatform } from '../../../util/common'; import * as hostRules from '../../../util/host-rules'; import { Http } from '../../../util/http'; import { regEx } from '../../../util/regex'; import { trimLeadingSlash, trimTrailingSlash } from '../../../util/url'; import { BitBucketTagsDatasource } from '../bitbucket-tags'; +import { GitTagsDatasource } from '../git-tags'; import { GithubTagsDatasource } from '../github-tags'; import { GitlabTagsDatasource } from '../gitlab-tags'; import type { DataSource } from './types'; @@ -198,18 +200,27 @@ export class BaseGoDatasource { } // fall back to old behaviour if detection did not work - // split the go module from the URL: host/go/module -> go/module - // TODO: `parsedUrl.pathname` can be undefined - const packageName = trimTrailingSlash(`${parsedUrl.pathname}`) - .replace(regEx(/\.git$/), '') - .split('/') - .slice(-2) - .join('/'); + if (detectPlatform(goImportURL) === 'github') { + // split the go module from the URL: host/go/module -> go/module + // TODO: `parsedUrl.pathname` can be undefined + const packageName = trimTrailingSlash(`${parsedUrl.pathname}`) + .replace(regEx(/\.git$/), '') + .split('/') + .slice(-2) + .join('/'); + + return { + datasource: GithubTagsDatasource.id, + registryUrl: `${parsedUrl.protocol}//${parsedUrl.host}`, + packageName, + }; + } + + // Fall back to git tags return { - datasource: GithubTagsDatasource.id, - registryUrl: `${parsedUrl.protocol}//${parsedUrl.host}`, - packageName, + datasource: GitTagsDatasource.id, + packageName: goImportURL, }; } } diff --git a/lib/modules/datasource/go/index.spec.ts b/lib/modules/datasource/go/index.spec.ts index 229bbb32f9dfff30b00834b77cbf094c3770e058..6f5575968b7c65b5ddcd4d864b405628e3db8ef2 100644 --- a/lib/modules/datasource/go/index.spec.ts +++ b/lib/modules/datasource/go/index.spec.ts @@ -11,11 +11,13 @@ const getReleasesDirectMock = jest.fn(); const getDigestGithubMock = jest.fn(); const getDigestGitlabMock = jest.fn(); +const getDigestGitMock = jest.fn(); const getDigestBitbucketMock = jest.fn(); jest.mock('./releases-direct', () => { return { GoDirectDatasource: jest.fn().mockImplementation(() => { return { + git: { getDigest: () => getDigestGitMock() }, github: { getDigest: () => getDigestGithubMock() }, gitlab: { getDigest: () => getDigestGitlabMock() }, bitbucket: { getDigest: () => getDigestBitbucketMock() }, @@ -129,6 +131,19 @@ describe('modules/datasource/go/index', () => { expect(res).toBe('abcdefabcdefabcdefabcdef'); }); + it('supports git digest', async () => { + httpMock + .scope('https://renovatebot.com/') + .get('/abc/def?go-get=1') + .reply(200, Fixtures.get('go-get-git-digest.html')); + getDigestGitMock.mockResolvedValue('abcdefabcdefabcdefabcdef'); + const res = await datasource.getDigest( + { packageName: 'renovatebot.com/abc/def' }, + null + ); + expect(res).toBe('abcdefabcdefabcdefabcdef'); + }); + it('supports gitlab digest with a specific branch', async () => { const branch = 'some-branch'; httpMock diff --git a/lib/modules/datasource/go/index.ts b/lib/modules/datasource/go/index.ts index 8b58406455ca2791321e73bca0abb0400bbc7df2..b3673e2880fc608f0d23a2df1f95162979209978 100644 --- a/lib/modules/datasource/go/index.ts +++ b/lib/modules/datasource/go/index.ts @@ -4,6 +4,7 @@ import { addSecretForSanitizing } from '../../../util/sanitize'; import { parseUrl } from '../../../util/url'; import { BitBucketTagsDatasource } from '../bitbucket-tags'; import { Datasource } from '../datasource'; +import { GitTagsDatasource } from '../git-tags'; import { GithubTagsDatasource } from '../github-tags'; import { GitlabTagsDatasource } from '../gitlab-tags'; import type { DigestConfig, GetReleasesConfig, ReleaseResult } from '../types'; @@ -62,6 +63,9 @@ export class GoDatasource extends Datasource { const tag = value && !value.startsWith('v0.0.0-2') ? value : undefined; switch (source.datasource) { + case GitTagsDatasource.id: { + return this.direct.git.getDigest?.(source, tag) ?? null; + } case GithubTagsDatasource.id: { return this.direct.github.getDigest(source, tag); } diff --git a/lib/modules/datasource/go/releases-direct.spec.ts b/lib/modules/datasource/go/releases-direct.spec.ts index 53753b91761f0e5c2c45d9d22515d5e64107f4f5..12eb327a1bf6c5e540f68192caf3d155bea7a898 100644 --- a/lib/modules/datasource/go/releases-direct.spec.ts +++ b/lib/modules/datasource/go/releases-direct.spec.ts @@ -1,6 +1,7 @@ import * as httpMock from '../../../../test/http-mock'; import { mocked } from '../../../../test/util'; import * as _hostRules from '../../../util/host-rules'; +import { GitTagsDatasource } from '../git-tags'; import { GithubTagsDatasource } from '../github-tags'; import { BaseGoDatasource } from './base'; import { GoDirectDatasource } from './releases-direct'; @@ -13,6 +14,7 @@ const getDatasourceSpy = jest.spyOn(BaseGoDatasource, 'getDatasource'); const hostRules = mocked(_hostRules); describe('modules/datasource/go/releases-direct', () => { + const gitGetTags = jest.spyOn(GitTagsDatasource.prototype, 'getReleases'); const githubGetTags = jest.spyOn( GithubTagsDatasource.prototype, 'getReleases' @@ -90,6 +92,25 @@ describe('modules/datasource/go/releases-direct', () => { expect(res).toBeDefined(); }); + it('support git', async () => { + getDatasourceSpy.mockResolvedValueOnce({ + datasource: 'git-tags', + packageName: 'renovatebot.com/abc/def', + }); + gitGetTags.mockResolvedValueOnce({ + releases: [ + { gitRef: 'v1.0.0', version: 'v1.0.0' }, + { gitRef: 'v2.0.0', version: 'v2.0.0' }, + ], + }); + const res = await datasource.getReleases({ + packageName: 'renovatebot.com/abc/def', + }); + expect(res).toMatchSnapshot(); + expect(res).not.toBeNull(); + expect(res).toBeDefined(); + }); + it('support self hosted gitlab private repositories', async () => { getDatasourceSpy.mockResolvedValueOnce({ datasource: 'gitlab-tags', diff --git a/lib/modules/datasource/go/releases-direct.ts b/lib/modules/datasource/go/releases-direct.ts index 574455e68d1b4ecaf08e2f7c62a79fa00d0bfb92..30f5068c7ea2828269035152d509d62364092871 100644 --- a/lib/modules/datasource/go/releases-direct.ts +++ b/lib/modules/datasource/go/releases-direct.ts @@ -3,6 +3,7 @@ import { cache } from '../../../util/cache/package/decorator'; import { regEx } from '../../../util/regex'; import { BitBucketTagsDatasource } from '../bitbucket-tags'; import { Datasource } from '../datasource'; +import { GitTagsDatasource } from '../git-tags'; import { GithubTagsDatasource } from '../github-tags'; import { GitlabTagsDatasource } from '../gitlab-tags'; import type { DatasourceApi, GetReleasesConfig, ReleaseResult } from '../types'; @@ -12,12 +13,14 @@ import { getSourceUrl } from './common'; export class GoDirectDatasource extends Datasource { static readonly id = 'go-direct'; + git: GitTagsDatasource; github: GithubTagsDatasource; gitlab: DatasourceApi; bitbucket: DatasourceApi; constructor() { super(GoDirectDatasource.id); + this.git = new GitTagsDatasource(); this.github = new GithubTagsDatasource(); this.gitlab = new GitlabTagsDatasource(); this.bitbucket = new BitBucketTagsDatasource(); @@ -55,6 +58,10 @@ export class GoDirectDatasource extends Datasource { } switch (source.datasource) { + case GitTagsDatasource.id: { + res = await this.git.getReleases(source); + break; + } case GithubTagsDatasource.id: { res = await this.github.getReleases(source); break; diff --git a/lib/modules/datasource/go/types.ts b/lib/modules/datasource/go/types.ts index 2f5bac903378dfd3ecc2496a4b2997b81206b9fc..03472dd1ea1dc289dabd0d170a89630d5bef3fc5 100644 --- a/lib/modules/datasource/go/types.ts +++ b/lib/modules/datasource/go/types.ts @@ -2,7 +2,7 @@ import type { GoproxyFallback } from './common'; export interface DataSource { datasource: string; - registryUrl: string; + registryUrl?: string; packageName: string; }