diff --git a/lib/datasource/go/__snapshots__/index.spec.ts.snap b/lib/datasource/go/__snapshots__/index.spec.ts.snap index 6b192f230d8abadacd3fa49a607281ca1bcbe60c..f5bf3271a4a1f5472e54e6f7d967090befe2ad87 100644 --- a/lib/datasource/go/__snapshots__/index.spec.ts.snap +++ b/lib/datasource/go/__snapshots__/index.spec.ts.snap @@ -35,3 +35,20 @@ Array [ ], ] `; + +exports[`datasource/go getPkgReleases works for nested modules on github 1`] = ` +Array [ + Array [ + Object { + "datasource": "github-tags", + "lookupName": "x/text", + }, + ], + Array [ + Object { + "datasource": "github-tags", + "lookupName": "x/text", + }, + ], +] +`; diff --git a/lib/datasource/go/index.spec.ts b/lib/datasource/go/index.spec.ts index e55eaad4472dc54e7a1928476f14fd89e1bcb010..e6242afb3a7bfabd14d4496390ca43841f835fdf 100644 --- a/lib/datasource/go/index.spec.ts +++ b/lib/datasource/go/index.spec.ts @@ -129,5 +129,41 @@ describe('datasource/go', () => { expect(got).toHaveBeenCalledTimes(0); expect(github.getPkgReleases.mock.calls).toMatchSnapshot(); }); + it('works for nested modules on github', async () => { + got.mockClear(); + github.getPkgReleases.mockClear(); + const packages = [ + { lookupName: 'github.com/x/text/a' }, + { lookupName: 'github.com/x/text/b' }, + ]; + + for (const pkg of packages) { + github.getPkgReleases.mockResolvedValueOnce({ + releases: [{ version: 'a/v1.0.0' }, { version: 'b/v2.0.0' }], + }); + const prefix = pkg.lookupName.split('/')[3]; + const result = await go.getPkgReleases(pkg); + expect(result.releases).toHaveLength(1); + expect(result.releases[0].version.startsWith(prefix)); + } + expect(got).toHaveBeenCalledTimes(0); + expect(github.getPkgReleases.mock.calls).toMatchSnapshot(); + }); + it('falls back to old behaviour', async () => { + got.mockClear(); + github.getPkgReleases.mockClear(); + const packages = [ + { lookupName: 'github.com/x/text/a' }, + { lookupName: 'github.com/x/text/b' }, + ]; + + const releases = { + releases: [{ version: 'v1.0.0' }, { version: 'v2.0.0' }], + }; + for (const pkg of packages) { + github.getPkgReleases.mockResolvedValueOnce(releases); + expect(await go.getPkgReleases(pkg)).toBe(releases); + } + }); }); }); diff --git a/lib/datasource/go/index.ts b/lib/datasource/go/index.ts index 6eaf0c16bf21a2bd324a2b7d726eaae59f4762cf..e88d9fffd49d609cde4035a5480849b0ac27499c 100644 --- a/lib/datasource/go/index.ts +++ b/lib/datasource/go/index.ts @@ -80,6 +80,7 @@ async function getDatasource(goModule: string): Promise<DataSource | null> { * This function will: * - Determine the source URL for the module * - Call the respective getPkgReleases in github to retrieve the tags + * - Filter module tags according to the module path */ export async function getPkgReleases({ lookupName, @@ -88,6 +89,32 @@ export async function getPkgReleases({ const source = await getDatasource(lookupName); if (source && source.datasource === github.id) { const res = await github.getPkgReleases(source); + + /** + * github.com/org/mod/submodule should be tagged as submodule/va.b.c + * and that tag should be used instead of just va.b.c, although for compatibility + * the old behaviour stays the same. + */ + const nameParts = lookupName.split('/'); + logger.trace({ nameParts, releases: res.releases }, 'go.getPkgReleases'); + if (nameParts.length > 3) { + const prefix = nameParts.slice(3, nameParts.length).join('/'); + logger.trace(`go.getPkgReleases.prefix:${prefix}`); + const submodReleases = res.releases + .filter( + release => release.version && release.version.startsWith(prefix) + ) + .map(release => { + const r2 = release; + r2.version = r2.version.replace(`${prefix}/`, ''); + return r2; + }); + logger.trace({ submodReleases }, 'go.getPkgReleases'); + if (submodReleases.length > 0) { + res.releases = submodReleases; + return res; + } + } if (res && res.releases) { res.releases = res.releases.filter( release => release.version && release.version.startsWith('v')