mirror of
https://github.com/renovatebot/renovate.git
synced 2026-10-31 09:41:46 +00:00
e5f067ccce
* feat(manager): add proto manager for .prototools files Add a new manager for moonrepo's proto tool version manager. Proto uses .prototools (TOML) files to pin tool versions at the directory level. The manager extracts top-level version entries and maps them to the appropriate Renovate datasources. Supported built-in tools: bun, deno, go, moon, node, npm, pnpm, yarn, python, ruby, rust, proto, gh, poetry, uv. Non-version sections ([settings], [plugins], [tools], [env], [shell], [backends]) are correctly ignored. Version aliases (latest, stable, canary, nightly) are skipped with appropriate skipReason. Unknown tools are reported as unsupported-datasource. * fix(manager): address proto manager PR review feedback - Remove deduplicateArray/sort from supportedDatasources, sort manually - Sort protoTooling entries alphabetically - Inline createDependency call into deps.push() - Inline fixture content into test, remove fixture file
306 lines
7.6 KiB
TypeScript
306 lines
7.6 KiB
TypeScript
import { codeBlock } from 'common-tags';
|
|
import { extractPackageFile } from './index.ts';
|
|
|
|
vi.mock('../../../util/fs/index.ts');
|
|
|
|
const protoFilename = '.prototools';
|
|
|
|
describe('modules/manager/proto/extract', () => {
|
|
describe('extractPackageFile()', () => {
|
|
it('returns null for empty content', () => {
|
|
expect(extractPackageFile('', protoFilename)).toBeNull();
|
|
});
|
|
|
|
it('returns null for invalid TOML', () => {
|
|
expect(extractPackageFile('{{invalid', protoFilename)).toBeNull();
|
|
});
|
|
|
|
it('returns null when only config sections exist', () => {
|
|
const content = codeBlock`
|
|
[settings]
|
|
auto-install = true
|
|
|
|
[env]
|
|
DEBUG = "*"
|
|
`;
|
|
expect(extractPackageFile(content, protoFilename)).toBeNull();
|
|
});
|
|
|
|
it('extracts a single tool version', () => {
|
|
const content = codeBlock`
|
|
node = "22.14.0"
|
|
`;
|
|
const result = extractPackageFile(content, protoFilename);
|
|
expect(result).toMatchObject({
|
|
deps: [
|
|
{
|
|
depName: 'node',
|
|
currentValue: '22.14.0',
|
|
datasource: 'node-version',
|
|
packageName: 'node',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('extracts multiple tool versions', () => {
|
|
const content = codeBlock`
|
|
node = "22.14.0"
|
|
bun = "1.2.2"
|
|
npm = "11.6.2"
|
|
`;
|
|
const result = extractPackageFile(content, protoFilename);
|
|
expect(result).toMatchObject({
|
|
deps: [
|
|
{
|
|
depName: 'node',
|
|
currentValue: '22.14.0',
|
|
datasource: 'node-version',
|
|
},
|
|
{
|
|
depName: 'bun',
|
|
currentValue: '1.2.2',
|
|
datasource: 'github-releases',
|
|
packageName: 'oven-sh/bun',
|
|
},
|
|
{
|
|
depName: 'npm',
|
|
currentValue: '11.6.2',
|
|
datasource: 'npm',
|
|
packageName: 'npm',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('skips non-version sections', () => {
|
|
const content = codeBlock`
|
|
node = "22.14.0"
|
|
|
|
[settings]
|
|
auto-install = true
|
|
|
|
[plugins.tools]
|
|
my-tool = "https://example.com/plugin.toml"
|
|
|
|
[tools.node]
|
|
bundled-npm = true
|
|
|
|
[env]
|
|
DEBUG = "*"
|
|
`;
|
|
const result = extractPackageFile(content, protoFilename);
|
|
expect(result).toMatchObject({
|
|
deps: [
|
|
{
|
|
depName: 'node',
|
|
currentValue: '22.14.0',
|
|
datasource: 'node-version',
|
|
},
|
|
],
|
|
});
|
|
expect(result!.deps).toHaveLength(1);
|
|
});
|
|
|
|
it('handles proto self-versioning', () => {
|
|
const content = codeBlock`
|
|
proto = "0.56.0"
|
|
`;
|
|
const result = extractPackageFile(content, protoFilename);
|
|
expect(result).toMatchObject({
|
|
deps: [
|
|
{
|
|
depName: 'proto',
|
|
currentValue: '0.56.0',
|
|
datasource: 'github-releases',
|
|
packageName: 'moonrepo/proto',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('handles moon tool', () => {
|
|
const content = codeBlock`
|
|
moon = "1.30.0"
|
|
`;
|
|
const result = extractPackageFile(content, protoFilename);
|
|
expect(result).toMatchObject({
|
|
deps: [
|
|
{
|
|
depName: 'moon',
|
|
currentValue: '1.30.0',
|
|
datasource: 'github-releases',
|
|
packageName: 'moonrepo/moon',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('handles uv tool', () => {
|
|
const content = codeBlock`
|
|
uv = "0.6.0"
|
|
`;
|
|
const result = extractPackageFile(content, protoFilename);
|
|
expect(result).toMatchObject({
|
|
deps: [
|
|
{
|
|
depName: 'uv',
|
|
currentValue: '0.6.0',
|
|
datasource: 'github-releases',
|
|
packageName: 'astral-sh/uv',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('marks unknown tools as unsupported-datasource', () => {
|
|
const content = codeBlock`
|
|
unknown-tool = "1.0.0"
|
|
`;
|
|
const result = extractPackageFile(content, protoFilename);
|
|
expect(result).toMatchObject({
|
|
deps: [
|
|
{
|
|
depName: 'unknown-tool',
|
|
currentValue: '1.0.0',
|
|
skipReason: 'unsupported-datasource',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('skips alias values like latest', () => {
|
|
const content = codeBlock`
|
|
node = "latest"
|
|
`;
|
|
const result = extractPackageFile(content, protoFilename);
|
|
expect(result).toMatchObject({
|
|
deps: [
|
|
{
|
|
depName: 'node',
|
|
currentValue: 'latest',
|
|
skipReason: 'unsupported-version',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('skips alias value stable', () => {
|
|
const content = codeBlock`
|
|
rust = "stable"
|
|
`;
|
|
const result = extractPackageFile(content, protoFilename);
|
|
expect(result).toMatchObject({
|
|
deps: [
|
|
{
|
|
depName: 'rust',
|
|
currentValue: 'stable',
|
|
skipReason: 'unsupported-version',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('handles partial versions', () => {
|
|
const content = codeBlock`
|
|
go = "~1.22"
|
|
`;
|
|
const result = extractPackageFile(content, protoFilename);
|
|
expect(result).toMatchObject({
|
|
deps: [
|
|
{
|
|
depName: 'go',
|
|
currentValue: '~1.22',
|
|
datasource: 'github-tags',
|
|
packageName: 'golang/go',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('extracts all supported tools from fixture', () => {
|
|
const content = codeBlock`
|
|
node = "22.14.0"
|
|
bun = "1.2.2"
|
|
npm = "11.6.2"
|
|
go = "~1.22"
|
|
proto = "0.56.0"
|
|
|
|
[settings]
|
|
auto-install = true
|
|
detect-strategy = "prefer-prototools"
|
|
|
|
[plugins.tools]
|
|
my-tool = "https://raw.githubusercontent.com/my/tool/master/proto-plugin.toml"
|
|
|
|
[tools.node]
|
|
bundled-npm = true
|
|
|
|
[env]
|
|
DEBUG = "*"
|
|
`;
|
|
const result = extractPackageFile(content, protoFilename);
|
|
expect(result).not.toBeNull();
|
|
expect(result!.deps).toHaveLength(5);
|
|
expect(result!.deps).toMatchObject([
|
|
{
|
|
depName: 'node',
|
|
currentValue: '22.14.0',
|
|
datasource: 'node-version',
|
|
},
|
|
{
|
|
depName: 'bun',
|
|
currentValue: '1.2.2',
|
|
datasource: 'github-releases',
|
|
packageName: 'oven-sh/bun',
|
|
},
|
|
{
|
|
depName: 'npm',
|
|
currentValue: '11.6.2',
|
|
datasource: 'npm',
|
|
packageName: 'npm',
|
|
},
|
|
{
|
|
depName: 'go',
|
|
currentValue: '~1.22',
|
|
datasource: 'github-tags',
|
|
packageName: 'golang/go',
|
|
},
|
|
{
|
|
depName: 'proto',
|
|
currentValue: '0.56.0',
|
|
datasource: 'github-releases',
|
|
packageName: 'moonrepo/proto',
|
|
},
|
|
]);
|
|
});
|
|
|
|
it('extracts all supported built-in tools', () => {
|
|
const content = codeBlock`
|
|
bun = "1.2.2"
|
|
deno = "2.0.0"
|
|
go = "1.22.0"
|
|
moon = "1.30.0"
|
|
node = "22.14.0"
|
|
npm = "11.6.2"
|
|
pnpm = "9.0.0"
|
|
yarn = "4.0.0"
|
|
python = "3.12.0"
|
|
ruby = "3.3.0"
|
|
rust = "1.80.0"
|
|
proto = "0.56.0"
|
|
gh = "2.60.0"
|
|
poetry = "1.8.0"
|
|
uv = "0.6.0"
|
|
`;
|
|
const result = extractPackageFile(content, protoFilename);
|
|
expect(result).not.toBeNull();
|
|
expect(result!.deps).toHaveLength(15);
|
|
// Verify no deps have skipReason
|
|
for (const dep of result!.deps) {
|
|
expect(dep.skipReason).toBeUndefined();
|
|
}
|
|
});
|
|
});
|
|
});
|