Files
renovate/lib/modules/manager/gomod/integration.spec.ts
Jamie Tanna d8705054b0 fix(datasource/go): prefer later releaseTimestamp from GitHub Releases (#45315)
As noted in #45314, there are cases where we may see as similar case to
the GitHub Releases datasource in #43451, where a Go module's published
`Time` matches the time that the commit the Git tag points to was
committed, rather than the time that the release was created.

If we do have a GitHub repository, we can look up the GitHub Releases
(or we'll get the Git Tags, if no Releases are present) and use the date
if it's /newer/

Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
2026-08-17 19:01:23 +00:00

145 lines
4.2 KiB
TypeScript

import { codeBlock } from 'common-tags';
import * as httpMock from '~test/http-mock.ts';
import { partial } from '~test/util.ts';
import { getConfig } from '../../../config/defaults.ts';
import * as githubGraphql from '../../../util/github/graphql/index.ts';
import { fetchUpdates } from '../../../workers/repository/process/fetch.ts';
import type { LookupUpdateConfig } from '../../../workers/repository/process/lookup/types.ts';
import type { PackageFile } from '../types.ts';
import { extractPackageFile } from './extract.ts';
describe('modules/manager/gomod/integration', () => {
let baseConfig: LookupUpdateConfig;
beforeEach(() => {
// TODO: fix types #22198
baseConfig = partial<LookupUpdateConfig>(getConfig() as never);
baseConfig.manager = 'gomod';
baseConfig.constraintsFiltering = 'strict';
vi.spyOn(githubGraphql, 'queryReleases').mockResolvedValue([]);
});
describe('when constraintsFiltering=strict', () => {
it('only suggests updates within the minor version of the `go` directive', async () => {
// make sure we can validate all suggested releases
baseConfig.separateMultipleMinor = true;
const goMod = codeBlock`
module github.com/renovate-tests/gomod
go 1.22.5
require github.com/renovate-tests/some-module v0.1.0
`;
const extracted = extractPackageFile(goMod);
expect(extracted).not.toBeNull();
expect(extracted?.deps).toHaveLength(2);
const dep = extracted!.deps.find(
(d) => d.depName === 'github.com/renovate-tests/some-module',
);
expect(dep).toBeDefined();
httpMock
.scope('https://raw.githubusercontent.com')
.get('/golang/website/HEAD/internal/history/release.go')
.reply(200, '');
httpMock
.scope('https://proxy.golang.org')
.get('/github.com/renovate-tests/some-module/@v/list')
.reply(
200,
codeBlock`
v0.2.0
v0.3.0
v0.4.0
v0.5.0
v0.6.0
`,
);
const versions = {
'v0.2.0': '1.18',
'v0.3.0': '1.22.2',
'v0.4.0': '1.22.5',
'v0.5.0': '1.22.1000',
'v0.6.0': '1.30.0',
};
for (const [k, v] of Object.entries(versions)) {
httpMock
.scope('https://proxy.golang.org')
.get(`/github.com/renovate-tests/some-module/@v/${k}.info`)
.reply(200, {
Version: k,
});
httpMock
.scope('https://proxy.golang.org')
.get(`/github.com/renovate-tests/some-module/@v/${k}.mod`)
.reply(
200,
codeBlock`module github.com/renovate-tests/some-module
go ${v}
`,
);
}
httpMock
.scope('https://proxy.golang.org')
.get('/github.com/renovate-tests/some-module/v2/@v/list')
.reply(404);
httpMock
.scope('https://proxy.golang.org')
.get('/github.com/renovate-tests/some-module/@latest')
.reply(200, 'v0.6.0');
const packageFiles: Record<string, PackageFile[]> = {
gomod: [
partial({
...extracted,
packageFile: 'go.mod',
}),
],
};
await fetchUpdates(baseConfig, packageFiles);
const updates = packageFiles.gomod[0].deps[1].updates;
expect(updates).toEqual([
{
bucket: 'v0.3',
hasAttestation: undefined,
isBreaking: true,
newMajor: 0,
newMinor: 3,
newPatch: 0,
newValue: 'v0.3.0',
newVersion: 'v0.3.0',
updateType: 'minor',
},
{
bucket: 'v0.4',
hasAttestation: undefined,
isBreaking: true,
newMajor: 0,
newMinor: 4,
newPatch: 0,
newValue: 'v0.4.0',
newVersion: 'v0.4.0',
updateType: 'minor',
},
{
bucket: 'v0.5',
hasAttestation: undefined,
isBreaking: true,
newMajor: 0,
newMinor: 5,
newPatch: 0,
newValue: 'v0.5.0',
newVersion: 'v0.5.0',
updateType: 'minor',
},
]);
});
});
});