mirror of
https://github.com/renovatebot/renovate.git
synced 2026-10-25 15:01:49 +00:00
9788f3698d
* refactor(manager): type manager data of the remaining managers Co-Authored-By: Claude Fable 5.1 <michael.kriese+claude-code@mend.io> Co-Authored-By: Claude Opus 5.5 <michael.kriese+claude-code@mend.io> * refactor(manager): type flux deps from shared helpers and require ansible collection names Co-Authored-By: Claude Opus 5.5 <michael.kriese+claude-code@mend.io> --------- Co-authored-by: Claude Fable 5.1 <michael.kriese+claude-code@mend.io>
196 lines
6.8 KiB
TypeScript
196 lines
6.8 KiB
TypeScript
// TODO: types (#22198)
|
|
import { logger } from '../../../logger/index.ts';
|
|
import { newlineRegex, regEx } from '../../../util/regex.ts';
|
|
import { isPseudoVersion } from '../../versioning/gomod/index.ts';
|
|
import type { UpdateDependencyConfig } from '../types.ts';
|
|
import type { GoModManagerData } from './types.ts';
|
|
|
|
function getNameWithNoVersion(name: string): string {
|
|
// remove version suffixes like /v1 or /v2
|
|
let nameNoVersion = name.replace(regEx(/\/v\d+$/), '');
|
|
// gopkg.in is a special case where the major version is added with a dot rather than a slash
|
|
if (nameNoVersion.startsWith('gopkg.in')) {
|
|
nameNoVersion = nameNoVersion.replace(regEx(/\.v\d+$/), '');
|
|
}
|
|
return nameNoVersion;
|
|
}
|
|
|
|
export function updateDependency({
|
|
fileContent,
|
|
upgrade,
|
|
}: UpdateDependencyConfig<GoModManagerData>): string | null {
|
|
try {
|
|
logger.debug(`gomod.updateDependency: ${upgrade.newValue}`);
|
|
const { depType, updateType } = upgrade;
|
|
const currentName = upgrade.depName;
|
|
if (updateType === 'replacement') {
|
|
logger.warn('gomod manager does not support replacement updates yet');
|
|
return null;
|
|
}
|
|
const lineNumber = upgrade.managerData?.lineNumber;
|
|
const multiLine = upgrade.managerData?.multiLine;
|
|
/* v8 ignore next -- should never happen */
|
|
if (!currentName || lineNumber === undefined) {
|
|
return null;
|
|
}
|
|
const currentNameNoVersion = getNameWithNoVersion(currentName);
|
|
const lines = fileContent.split(newlineRegex);
|
|
/* v8 ignore next -- hard to test */
|
|
if (lines.length <= lineNumber) {
|
|
logger.warn('go.mod current line no longer exists after update');
|
|
return null;
|
|
}
|
|
const lineToChange = lines[lineNumber];
|
|
logger.trace({ upgrade, lineToChange }, 'go.mod current line');
|
|
if (
|
|
!lineToChange.includes(currentNameNoVersion) &&
|
|
!lineToChange.includes('rethinkdb/rethinkdb-go.v5')
|
|
) {
|
|
logger.debug(
|
|
{ lineToChange, depName: currentName },
|
|
"go.mod current line doesn't contain dependency",
|
|
);
|
|
return null;
|
|
}
|
|
let updateLineExp: RegExp | undefined;
|
|
|
|
if (depType === 'golang' || depType === 'toolchain') {
|
|
updateLineExp = regEx(
|
|
/(?<depPart>(?:toolchain )?go)(?<divider>\s*)(?:[^\s]+|[\w]+)/,
|
|
);
|
|
}
|
|
if (depType === 'replace') {
|
|
if (multiLine) {
|
|
updateLineExp = regEx(
|
|
/^(?<depPart>\s+[^\s]+[\s]+[=][>]+\s+)(?<divider>[^\s]+\s+)[^\s]+/,
|
|
);
|
|
} else {
|
|
updateLineExp = regEx(
|
|
/^(?<depPart>replace\s+[^\s]+[\s]+[=][>]+\s+)(?<divider>[^\s]+\s+)[^\s]+/,
|
|
);
|
|
}
|
|
} else if (depType === 'require' || depType === 'indirect') {
|
|
if (multiLine) {
|
|
updateLineExp = regEx(/^(?<depPart>\s+[^\s]+)(?<divider>\s+)[^\s]+/);
|
|
} else {
|
|
updateLineExp = regEx(
|
|
/^(?<depPart>require\s+[^\s]+)(?<divider>\s+)[^\s]+/,
|
|
);
|
|
}
|
|
}
|
|
if (updateLineExp && !updateLineExp.test(lineToChange)) {
|
|
logger.debug('No line found to update');
|
|
return null;
|
|
}
|
|
let newLine: string;
|
|
if (upgrade.updateType === 'digest') {
|
|
// Since the 2024 goproxy datasource changes, newValue and newDigest are
|
|
// both extracted from the same proxy version string and always reference
|
|
// the same commit, so newValue can be written directly for pseudo-versions.
|
|
// However, for private modules (GONOPROXY / direct datasource), the proxy
|
|
// has no data and newValue may equal currentValue. In that case, fall
|
|
// through to the bare hash path so that gomodTidy can resolve it.
|
|
if (
|
|
isPseudoVersion(upgrade.newValue) &&
|
|
upgrade.newValue !== upgrade.currentValue
|
|
) {
|
|
logger.debug(
|
|
{ depName: currentName, lineToChange, newValue: upgrade.newValue },
|
|
'gomod: updating pseudo-version digest',
|
|
);
|
|
newLine = lineToChange.replace(
|
|
// TODO: can be undefined? (#22198)
|
|
updateLineExp!,
|
|
`$<depPart>$<divider>${upgrade.newValue}`,
|
|
);
|
|
} else {
|
|
// Fallback for private modules where the proxy could not resolve a new
|
|
// pseudo-version, or non-pseudo-version digest updates.
|
|
// Writes the bare hash so that postUpdateOptions like gomodTidy can
|
|
// normalize it into a valid pseudo-version via `go get`.
|
|
const newDigestRightSized = upgrade.newDigest!.substring(
|
|
0,
|
|
upgrade.currentDigest!.length,
|
|
);
|
|
if (lineToChange.includes(newDigestRightSized)) {
|
|
return fileContent;
|
|
}
|
|
logger.debug(
|
|
{ depName: currentName, lineToChange, newDigestRightSized },
|
|
'gomod: need to update digest',
|
|
);
|
|
newLine = lineToChange.replace(
|
|
// TODO: can be undefined? (#22198)
|
|
updateLineExp!,
|
|
`$<depPart>$<divider>${newDigestRightSized}`,
|
|
);
|
|
}
|
|
} else {
|
|
newLine = lineToChange.replace(
|
|
// TODO: can be undefined? (#22198)
|
|
updateLineExp!,
|
|
`$<depPart>$<divider>${upgrade.newValue}`,
|
|
);
|
|
}
|
|
if (upgrade.updateType === 'major') {
|
|
logger.debug(`gomod: major update for ${currentName}`);
|
|
if (currentName.startsWith('gopkg.in/')) {
|
|
const oldV = currentName.split('.').pop();
|
|
newLine = newLine.replace(`.${oldV}`, `.v${upgrade.newMajor}`);
|
|
// Package renames - I couldn't think of a better place to do this
|
|
newLine = newLine.replace(
|
|
'gorethink/gorethink.v5',
|
|
'rethinkdb/rethinkdb-go.v5',
|
|
);
|
|
} else if (
|
|
upgrade.newMajor! > 1 &&
|
|
!newLine.includes(`/v${upgrade.newMajor}`) &&
|
|
!upgrade.newValue!.endsWith('+incompatible')
|
|
) {
|
|
if (currentName === currentNameNoVersion) {
|
|
// If package currently has no version, pin to latest one.
|
|
newLine = newLine.replaceAll(
|
|
currentName,
|
|
`${currentName}/v${upgrade.newMajor}`,
|
|
);
|
|
} else {
|
|
// Replace version
|
|
const [oldV] = upgrade.currentValue!.split('.');
|
|
newLine = newLine.replace(
|
|
regEx(`/${oldV}(\\s+)`, undefined, false),
|
|
`/v${upgrade.newMajor}$1`,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
if (
|
|
lineToChange.endsWith('+incompatible') &&
|
|
!upgrade.newValue?.endsWith('+incompatible')
|
|
) {
|
|
let toAdd = '+incompatible';
|
|
|
|
if (upgrade.updateType === 'major' && upgrade.newMajor! >= 2) {
|
|
toAdd = '';
|
|
}
|
|
newLine += toAdd;
|
|
}
|
|
if (newLine === lineToChange) {
|
|
logger.debug('No changes necessary');
|
|
return fileContent;
|
|
}
|
|
|
|
if (depType === 'indirect') {
|
|
newLine = newLine.replace(
|
|
regEx(/\s*(?:\/\/\s*indirect(?:\s*;)?\s*)*$/),
|
|
' // indirect',
|
|
);
|
|
}
|
|
|
|
lines[lineNumber] = newLine;
|
|
return lines.join('\n');
|
|
} catch (err) {
|
|
logger.debug({ err }, 'Error setting new go.mod version');
|
|
return null;
|
|
}
|
|
}
|