mirror of
https://github.com/renovatebot/renovate.git
synced 2025-01-10 22:16:28 +00:00
Merge 89f4276560
into 1d2c1a35e3
This commit is contained in:
commit
f0c725909d
5 changed files with 177 additions and 28 deletions
|
@ -3170,7 +3170,6 @@ Managers which do not support replacement:
|
||||||
|
|
||||||
- `bazel`
|
- `bazel`
|
||||||
- `git-submodules`
|
- `git-submodules`
|
||||||
- `gomod`
|
|
||||||
- `gradle`
|
- `gradle`
|
||||||
- `homebrew`
|
- `homebrew`
|
||||||
- `maven`
|
- `maven`
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { join } from 'upath';
|
||||||
import { envMock, mockExecAll } from '../../../../test/exec-util';
|
import { envMock, mockExecAll } from '../../../../test/exec-util';
|
||||||
import { env, fs, git, mocked, partial } from '../../../../test/util';
|
import { env, fs, git, mocked, partial } from '../../../../test/util';
|
||||||
import { GlobalConfig } from '../../../config/global';
|
import { GlobalConfig } from '../../../config/global';
|
||||||
import type { RepoGlobalConfig } from '../../../config/types';
|
import type { RepoGlobalConfig, UpdateType } from '../../../config/types';
|
||||||
import * as docker from '../../../util/exec/docker';
|
import * as docker from '../../../util/exec/docker';
|
||||||
import type { StatusResult } from '../../../util/git/types';
|
import type { StatusResult } from '../../../util/git/types';
|
||||||
import * as _hostRules from '../../../util/host-rules';
|
import * as _hostRules from '../../../util/host-rules';
|
||||||
|
@ -1547,6 +1547,67 @@ describe('modules/manager/gomod/artifacts', () => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('updates import paths with gomodUpdateImportPaths when performing a replacement', async () => {
|
||||||
|
fs.readLocalFile.mockResolvedValueOnce('Current go.sum');
|
||||||
|
fs.readLocalFile.mockResolvedValueOnce(null); // vendor modules filename
|
||||||
|
const execSnapshots = mockExecAll();
|
||||||
|
git.getRepoStatus.mockResolvedValueOnce(
|
||||||
|
partial<StatusResult>({
|
||||||
|
modified: ['go.sum', 'main.go'],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
fs.readLocalFile
|
||||||
|
.mockResolvedValueOnce('New go.sum')
|
||||||
|
.mockResolvedValueOnce('New main.go')
|
||||||
|
.mockResolvedValueOnce('New go.mod');
|
||||||
|
expect(
|
||||||
|
await gomod.updateArtifacts({
|
||||||
|
packageFileName: 'go.mod',
|
||||||
|
updatedDeps: [
|
||||||
|
{
|
||||||
|
depName: 'github.com/google/go-github/v24',
|
||||||
|
newVersion: 'v28.0.0',
|
||||||
|
|
||||||
|
updateType: 'replacement' as UpdateType,
|
||||||
|
newName: 'github.com/forkzilla/go-github/v28',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
newPackageFileContent: gomod1,
|
||||||
|
config: {
|
||||||
|
...config,
|
||||||
|
updateType: 'major',
|
||||||
|
postUpdateOptions: ['gomodUpdateImportPaths'],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).toEqual([
|
||||||
|
{ file: { type: 'addition', path: 'go.sum', contents: 'New go.sum' } },
|
||||||
|
{ file: { type: 'addition', path: 'main.go', contents: 'New main.go' } },
|
||||||
|
{ file: { type: 'addition', path: 'go.mod', contents: 'New go.mod' } },
|
||||||
|
]);
|
||||||
|
expect(execSnapshots).toMatchObject([
|
||||||
|
{
|
||||||
|
cmd: 'go get -d -t ./...',
|
||||||
|
options: { cwd: '/tmp/github/some/repo' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cmd: 'go install github.com/marwan-at-work/mod/cmd/mod@latest',
|
||||||
|
options: { cwd: '/tmp/github/some/repo' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cmd: 'mod upgrade --mod-name=github.com/forkzilla/go-github/v28 -t=28',
|
||||||
|
options: { cwd: '/tmp/github/some/repo' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cmd: 'go mod tidy',
|
||||||
|
options: { cwd: '/tmp/github/some/repo' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cmd: 'go mod tidy',
|
||||||
|
options: { cwd: '/tmp/github/some/repo' },
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it('updates correct import paths with gomodUpdateImportPaths and multiple dependencies', async () => {
|
it('updates correct import paths with gomodUpdateImportPaths and multiple dependencies', async () => {
|
||||||
fs.readLocalFile.mockResolvedValueOnce('Current go.sum');
|
fs.readLocalFile.mockResolvedValueOnce('Current go.sum');
|
||||||
fs.readLocalFile.mockResolvedValueOnce(null); // vendor modules filename
|
fs.readLocalFile.mockResolvedValueOnce(null); // vendor modules filename
|
||||||
|
|
|
@ -21,7 +21,7 @@ import { getGitEnvironmentVariables } from '../../../util/git/auth';
|
||||||
import { regEx } from '../../../util/regex';
|
import { regEx } from '../../../util/regex';
|
||||||
import { isValid } from '../../versioning/semver';
|
import { isValid } from '../../versioning/semver';
|
||||||
import type {
|
import type {
|
||||||
PackageDependency,
|
Upgrade,
|
||||||
UpdateArtifact,
|
UpdateArtifact,
|
||||||
UpdateArtifactsConfig,
|
UpdateArtifactsConfig,
|
||||||
UpdateArtifactsResult,
|
UpdateArtifactsResult,
|
||||||
|
@ -31,7 +31,7 @@ import { getExtraDepsNotice } from './artifacts-extra';
|
||||||
const { major, valid } = semver;
|
const { major, valid } = semver;
|
||||||
|
|
||||||
function getUpdateImportPathCmds(
|
function getUpdateImportPathCmds(
|
||||||
updatedDeps: PackageDependency[],
|
updatedDeps: Upgrade[],
|
||||||
{ constraints }: UpdateArtifactsConfig,
|
{ constraints }: UpdateArtifactsConfig,
|
||||||
): string[] {
|
): string[] {
|
||||||
// Check if we fail to parse any major versions and log that they're skipped
|
// Check if we fail to parse any major versions and log that they're skipped
|
||||||
|
@ -52,8 +52,8 @@ function getUpdateImportPathCmds(
|
||||||
({ newVersion }) =>
|
({ newVersion }) =>
|
||||||
valid(newVersion) && !newVersion!.endsWith('+incompatible'),
|
valid(newVersion) && !newVersion!.endsWith('+incompatible'),
|
||||||
)
|
)
|
||||||
.map(({ depName, newVersion }) => ({
|
.map(({ depName, newVersion, newName }) => ({
|
||||||
depName: depName!,
|
depName: newName || depName!,
|
||||||
newMajor: major(newVersion!),
|
newMajor: major(newVersion!),
|
||||||
}))
|
}))
|
||||||
// Skip path updates going from v0 to v1
|
// Skip path updates going from v0 to v1
|
||||||
|
@ -247,10 +247,10 @@ export async function updateArtifacts({
|
||||||
logger.trace({ cmd, args }, 'go get command included');
|
logger.trace({ cmd, args }, 'go get command included');
|
||||||
execCommands.push(`${cmd} ${args}`);
|
execCommands.push(`${cmd} ${args}`);
|
||||||
|
|
||||||
// Update import paths on major updates
|
// Update import paths on major updates, or when performing replacements
|
||||||
const isImportPathUpdateRequired =
|
const isImportPathUpdateRequired =
|
||||||
config.postUpdateOptions?.includes('gomodUpdateImportPaths') &&
|
config.postUpdateOptions?.includes('gomodUpdateImportPaths') &&
|
||||||
config.updateType === 'major';
|
(config.updateType === 'major' || config.updateType == 'replacement');
|
||||||
|
|
||||||
if (isImportPathUpdateRequired) {
|
if (isImportPathUpdateRequired) {
|
||||||
const updateImportCmds = getUpdateImportPathCmds(updatedDeps, config);
|
const updateImportCmds = getUpdateImportPathCmds(updatedDeps, config);
|
||||||
|
|
|
@ -384,14 +384,6 @@ describe('modules/manager/gomod/update', () => {
|
||||||
expect(res).toContain('k8s.io/client-go/v2 => k8s.io/client-go v2.2.2');
|
expect(res).toContain('k8s.io/client-go/v2 => k8s.io/client-go v2.2.2');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return null for replacement', () => {
|
|
||||||
const res = updateDependency({
|
|
||||||
fileContent: '',
|
|
||||||
upgrade: { updateType: 'replacement' },
|
|
||||||
});
|
|
||||||
expect(res).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should perform indirect upgrades when top-level', () => {
|
it('should perform indirect upgrades when top-level', () => {
|
||||||
const upgrade = {
|
const upgrade = {
|
||||||
depName: 'github.com/davecgh/go-spew',
|
depName: 'github.com/davecgh/go-spew',
|
||||||
|
@ -415,5 +407,84 @@ describe('modules/manager/gomod/update', () => {
|
||||||
expect(res).not.toEqual(gomod2);
|
expect(res).not.toEqual(gomod2);
|
||||||
expect(res).toContain(`${upgrade.newValue} // indirect`);
|
expect(res).toContain(`${upgrade.newValue} // indirect`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should perform package replacements', () => {
|
||||||
|
const upgrade = {
|
||||||
|
depName: 'github.com/aws/aws-sdk-go',
|
||||||
|
managerData: { lineNumber: 3 },
|
||||||
|
newValue: 'v1.27.1',
|
||||||
|
depType: 'require',
|
||||||
|
|
||||||
|
updateType: 'replacement' as UpdateType,
|
||||||
|
newName: 'github.com/aws/aws-sdk-go-v2',
|
||||||
|
};
|
||||||
|
const res = updateDependency({ fileContent: gomod1, upgrade });
|
||||||
|
expect(res).not.toEqual(gomod1);
|
||||||
|
expect(res).toContain(`github.com/aws/aws-sdk-go-v2 v1.27.1`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should perform package replacements for indirect packages', () => {
|
||||||
|
const upgrade = {
|
||||||
|
depName: 'github.com/davecgh/go-spew',
|
||||||
|
managerData: { lineNumber: 4 },
|
||||||
|
newValue: 'v1.1.1',
|
||||||
|
depType: 'indirect',
|
||||||
|
|
||||||
|
updateType: 'replacement' as UpdateType,
|
||||||
|
newName: 'github.com/spew/go-spew',
|
||||||
|
};
|
||||||
|
const res = updateDependency({ fileContent: gomod1, upgrade });
|
||||||
|
expect(res).not.toEqual(gomod1);
|
||||||
|
expect(res).toContain(
|
||||||
|
`${upgrade.newName} ${upgrade.newValue} // indirect`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should perform package replacements for a digest version', () => {
|
||||||
|
const upgrade = {
|
||||||
|
depName: 'golang.org/x/net',
|
||||||
|
managerData: { lineNumber: 54, multiLine: true },
|
||||||
|
currentDigest: 'c39426892332',
|
||||||
|
newDigest: 'foo',
|
||||||
|
depType: 'require',
|
||||||
|
|
||||||
|
updateType: 'replacement' as UpdateType,
|
||||||
|
newName: 'golang.org/foo-x-bar/net',
|
||||||
|
};
|
||||||
|
const res = updateDependency({ fileContent: gomod2, upgrade });
|
||||||
|
expect(res).not.toEqual(gomod2);
|
||||||
|
expect(res).toContain(`golang.org/foo-x-bar/net foo`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should perform package replacements for a major version', () => {
|
||||||
|
const upgrade = {
|
||||||
|
depName: 'github.com/stretchr/testify',
|
||||||
|
managerData: { lineNumber: 48, multiLine: true },
|
||||||
|
newValue: 'v2.0.0',
|
||||||
|
newMajor: 2,
|
||||||
|
depType: 'require',
|
||||||
|
|
||||||
|
updateType: 'replacement' as UpdateType,
|
||||||
|
newName: 'github.com/testify-core/testify/v2',
|
||||||
|
};
|
||||||
|
const res = updateDependency({ fileContent: gomod2, upgrade });
|
||||||
|
expect(res).not.toEqual(gomod2);
|
||||||
|
expect(res).toContain(`github.com/testify-core/testify/v2 v2.0.0`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should perform package replacements for a replace directive', () => {
|
||||||
|
const upgrade = {
|
||||||
|
depName: 'github.com/pravesht/gocql',
|
||||||
|
managerData: { lineNumber: 11 },
|
||||||
|
newValue: 'v0.0.1',
|
||||||
|
depType: 'replace',
|
||||||
|
|
||||||
|
updateType: 'replacement' as UpdateType,
|
||||||
|
newName: 'github.com/pravesht/gocql-new',
|
||||||
|
};
|
||||||
|
const res = updateDependency({ fileContent: gomod1, upgrade });
|
||||||
|
expect(res).not.toEqual(gomod1);
|
||||||
|
expect(res).toContain(`github.com/pravesht/gocql-new v0.0.1`);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,12 +17,8 @@ export function updateDependency({
|
||||||
}: UpdateDependencyConfig): string | null {
|
}: UpdateDependencyConfig): string | null {
|
||||||
try {
|
try {
|
||||||
logger.debug(`gomod.updateDependency: ${upgrade.newValue}`);
|
logger.debug(`gomod.updateDependency: ${upgrade.newValue}`);
|
||||||
const { depType, updateType } = upgrade;
|
const { depType } = upgrade;
|
||||||
const currentName = upgrade.depName;
|
const currentName = upgrade.depName;
|
||||||
if (updateType === 'replacement') {
|
|
||||||
logger.warn('gomod manager does not support replacement updates yet');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
// istanbul ignore if: should never happen
|
// istanbul ignore if: should never happen
|
||||||
if (!currentName || !upgrade.managerData) {
|
if (!currentName || !upgrade.managerData) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -56,19 +52,21 @@ export function updateDependency({
|
||||||
if (depType === 'replace') {
|
if (depType === 'replace') {
|
||||||
if (upgrade.managerData.multiLine) {
|
if (upgrade.managerData.multiLine) {
|
||||||
updateLineExp = regEx(
|
updateLineExp = regEx(
|
||||||
/^(?<depPart>\s+[^\s]+[\s]+[=][>]+\s+)(?<divider>[^\s]+\s+)[^\s]+/,
|
/^(?<depPart>\s+[^\s]+[\s]+[=][>]+\s+)(?<depName>[^\s]+)(?<divider>\s+)[^\s]+/,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
updateLineExp = regEx(
|
updateLineExp = regEx(
|
||||||
/^(?<depPart>replace\s+[^\s]+[\s]+[=][>]+\s+)(?<divider>[^\s]+\s+)[^\s]+/,
|
/^(?<depPart>replace\s+[^\s]+[\s]+[=][>]+\s+)(?<depName>[^\s]+)(?<divider>\s+)[^\s]+/,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (depType === 'require' || depType === 'indirect') {
|
} else if (depType === 'require' || depType === 'indirect') {
|
||||||
if (upgrade.managerData.multiLine) {
|
if (upgrade.managerData.multiLine) {
|
||||||
updateLineExp = regEx(/^(?<depPart>\s+[^\s]+)(?<divider>\s+)[^\s]+/);
|
updateLineExp = regEx(
|
||||||
|
/^(?<depPart>\s+)(?<depName>[^\s]+)(?<divider>\s+)[^\s]+/,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
updateLineExp = regEx(
|
updateLineExp = regEx(
|
||||||
/^(?<depPart>require\s+[^\s]+)(?<divider>\s+)[^\s]+/,
|
/^(?<depPart>require\s+)(?<depName>[^\s]+)(?<divider>\s+)[^\s]+/,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,7 +75,27 @@ export function updateDependency({
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
let newLine: string;
|
let newLine: string;
|
||||||
if (upgrade.updateType === 'digest') {
|
let quote = '';
|
||||||
|
|
||||||
|
if (updateLineExp) {
|
||||||
|
const groups = lineToChange.match(updateLineExp)?.groups;
|
||||||
|
// istanbul ignore if: should never happen
|
||||||
|
if (!groups) {
|
||||||
|
return fileContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (`${groups.depName}`.startsWith('"')) {
|
||||||
|
quote = '"';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// newName will be available for replacement
|
||||||
|
const newName = upgrade.newName ?? currentName;
|
||||||
|
|
||||||
|
if (
|
||||||
|
upgrade.updateType === 'digest' ||
|
||||||
|
(upgrade.updateType === 'replacement' && upgrade.newDigest)
|
||||||
|
) {
|
||||||
const newDigestRightSized = upgrade.newDigest!.substring(
|
const newDigestRightSized = upgrade.newDigest!.substring(
|
||||||
0,
|
0,
|
||||||
upgrade.currentDigest!.length,
|
upgrade.currentDigest!.length,
|
||||||
|
@ -92,13 +110,13 @@ export function updateDependency({
|
||||||
newLine = lineToChange.replace(
|
newLine = lineToChange.replace(
|
||||||
// TODO: can be undefined? (#22198)
|
// TODO: can be undefined? (#22198)
|
||||||
updateLineExp!,
|
updateLineExp!,
|
||||||
`$<depPart>$<divider>${newDigestRightSized}`,
|
`$<depPart>${quote}${newName}${quote}$<divider>${newDigestRightSized}`,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
newLine = lineToChange.replace(
|
newLine = lineToChange.replace(
|
||||||
// TODO: can be undefined? (#22198)
|
// TODO: can be undefined? (#22198)
|
||||||
updateLineExp!,
|
updateLineExp!,
|
||||||
`$<depPart>$<divider>${upgrade.newValue}`,
|
`$<depPart>${quote}${newName}${quote}$<divider>${upgrade.newValue}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (upgrade.updateType === 'major') {
|
if (upgrade.updateType === 'major') {
|
||||||
|
|
Loading…
Reference in a new issue