mirror of
https://github.com/renovatebot/renovate.git
synced 2026-10-31 09:41:46 +00:00
9ecbaa8581
When Go updates dependencies using i.e. `go get` or `go mod download`, it uses Minimal Version Selection (MVS)[0], which takes the lowest version available from the given packages. In the case of an updated dependency, in practice this means that Go will chose the version of an indirect (transitive) package dependency as the version that the updated package points to in their `go.mod`, which must be older than the updated package, as the updated package has only just been updated. This protects against cases in other ecosystems where an unpinned transitive dependency can be pulled by an updated package, potentially bypassing `minimumReleaseAge`. However, I can imagine there may be some questions about this, so we can preemptively add a note into the `Artifact update notice` when `minimumReleaseAge` is set. [0]: https://go.dev/ref/mod#minimal-version-selection
139 lines
3.8 KiB
TypeScript
139 lines
3.8 KiB
TypeScript
import { diffLines } from 'diff';
|
|
import { markdownTable } from 'markdown-table';
|
|
import type { UpdateArtifactsConfig } from '../types.ts';
|
|
import { parseLine } from './line-parser.ts';
|
|
import type { ExtraDep } from './types.ts';
|
|
|
|
export function getExtraDeps(
|
|
goModBefore: string,
|
|
goModAfter: string,
|
|
excludeDeps: string[],
|
|
): ExtraDep[] {
|
|
const result: ExtraDep[] = [];
|
|
|
|
const diff = diffLines(goModBefore, goModAfter, {
|
|
newlineIsToken: true,
|
|
});
|
|
|
|
const addDeps: Record<string, string> = {};
|
|
const rmDeps: Record<string, string> = {};
|
|
for (const { added, removed, value } of diff) {
|
|
if (!added && !removed) {
|
|
continue;
|
|
}
|
|
|
|
const res = parseLine(value);
|
|
if (!res) {
|
|
continue;
|
|
}
|
|
|
|
const { depName, depType, currentValue } = res;
|
|
if (!depName || !currentValue) {
|
|
continue;
|
|
}
|
|
|
|
let expandedDepName = depName;
|
|
// NOTE: Right now the only special depType we care about is 'toolchain' because the table
|
|
// rendering prior to this change was ambiguous with regards to go version vs toolchain
|
|
// version updates.
|
|
if (depType === 'toolchain') {
|
|
expandedDepName = `${depName} (${depType})`;
|
|
}
|
|
|
|
if (added) {
|
|
addDeps[expandedDepName] = currentValue;
|
|
} else {
|
|
rmDeps[expandedDepName] = currentValue;
|
|
}
|
|
}
|
|
|
|
for (const [depName, currentValue] of Object.entries(rmDeps)) {
|
|
if (excludeDeps.includes(depName)) {
|
|
continue;
|
|
}
|
|
|
|
const newValue = addDeps[depName];
|
|
if (newValue) {
|
|
result.push({
|
|
depName,
|
|
currentValue,
|
|
newValue,
|
|
});
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
export function extraDepsTable(extraDeps: ExtraDep[]): string {
|
|
const tableLines: string[][] = [];
|
|
|
|
tableLines.push(['**Package**', '**Change**']);
|
|
|
|
for (const { depName, currentValue, newValue } of extraDeps) {
|
|
const depNameQuoted = `\`${depName}\``;
|
|
const versionChangeQuoted = `\`${currentValue}\` -> \`${newValue}\``;
|
|
tableLines.push([depNameQuoted, versionChangeQuoted]);
|
|
}
|
|
|
|
return markdownTable(tableLines, {
|
|
align: ['l', 'l'],
|
|
});
|
|
}
|
|
|
|
export function getExtraDepsNotice(
|
|
goModBefore: string | null,
|
|
goModAfter: string | null,
|
|
excludeDeps: string[],
|
|
{ minimumReleaseAge }: Pick<UpdateArtifactsConfig, 'minimumReleaseAge'>,
|
|
): string | null {
|
|
if (!goModBefore || !goModAfter) {
|
|
return null;
|
|
}
|
|
|
|
const extraDeps = getExtraDeps(goModBefore, goModAfter, excludeDeps);
|
|
if (extraDeps.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
const noticeLines: string[] = [
|
|
'In order to perform the update(s) described in the table above, Renovate ran the `go get` command, which resulted in the following additional change(s):',
|
|
'\n',
|
|
];
|
|
|
|
const goUpdated = extraDeps.some(({ depName }) => depName === 'go');
|
|
const toolchainUpdated = extraDeps.some(
|
|
({ depName }) => depName === 'go (toolchain)',
|
|
);
|
|
const otherDepsCount =
|
|
extraDeps.length - (goUpdated ? 1 : 0) - (toolchainUpdated ? 1 : 0);
|
|
|
|
if (otherDepsCount === 1) {
|
|
noticeLines.push(`- ${otherDepsCount} additional dependency was updated`);
|
|
} else if (otherDepsCount > 1) {
|
|
noticeLines.push(
|
|
`- ${otherDepsCount} additional dependencies were updated`,
|
|
);
|
|
}
|
|
|
|
if (goUpdated) {
|
|
noticeLines.push(
|
|
'- The `go` directive was updated for compatibility reasons',
|
|
);
|
|
}
|
|
|
|
if (minimumReleaseAge) {
|
|
noticeLines.push('\n');
|
|
noticeLines.push(
|
|
`Due to Go's usage of [Minimal Version Selection (MVS)](https://go.dev/ref/mod#minimal-version-selection), these packages have been updated to the minimum version available, so will still abide by \`minimumReleaseAge=${minimumReleaseAge}\``,
|
|
);
|
|
}
|
|
|
|
noticeLines.push('\n');
|
|
noticeLines.push('Details:');
|
|
noticeLines.push('\n');
|
|
noticeLines.push(extraDepsTable(extraDeps));
|
|
|
|
return noticeLines.join('\n');
|
|
}
|