mirror of
https://github.com/renovatebot/renovate.git
synced 2025-01-14 16:46:25 +00:00
feat(bazel-modules): support single_version_override
(#22610)
Co-authored-by: Rhys Arkins <rhys@arkins.net>
This commit is contained in:
parent
0be6dba296
commit
ad61b6c875
5 changed files with 232 additions and 39 deletions
|
@ -180,5 +180,63 @@ describe('modules/manager/bazel-module/extract', () => {
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('returns bazel_dep and single_version_override dependencies if a version is specified', async () => {
|
||||||
|
const input = codeBlock`
|
||||||
|
bazel_dep(name = "rules_foo", version = "1.2.3")
|
||||||
|
single_version_override(
|
||||||
|
module_name = "rules_foo",
|
||||||
|
version = "1.2.3",
|
||||||
|
registry = "https://example.com/custom_registry",
|
||||||
|
)
|
||||||
|
`;
|
||||||
|
const result = await extractPackageFile(input, 'MODULE.bazel');
|
||||||
|
if (!result) {
|
||||||
|
throw new Error('Expected a result.');
|
||||||
|
}
|
||||||
|
expect(result.deps).toHaveLength(2);
|
||||||
|
expect(result.deps).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
{
|
||||||
|
datasource: BazelDatasource.id,
|
||||||
|
depType: 'bazel_dep',
|
||||||
|
depName: 'rules_foo',
|
||||||
|
currentValue: '1.2.3',
|
||||||
|
skipReason: 'is-pinned',
|
||||||
|
registryUrls: ['https://example.com/custom_registry'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
depType: 'single_version_override',
|
||||||
|
depName: 'rules_foo',
|
||||||
|
currentValue: '1.2.3',
|
||||||
|
skipReason: 'ignored',
|
||||||
|
registryUrls: ['https://example.com/custom_registry'],
|
||||||
|
},
|
||||||
|
])
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns bazel_dep dependency if single_version_override does not have a version', async () => {
|
||||||
|
const input = codeBlock`
|
||||||
|
bazel_dep(name = "rules_foo", version = "1.2.3")
|
||||||
|
single_version_override(
|
||||||
|
module_name = "rules_foo",
|
||||||
|
registry = "https://example.com/custom_registry",
|
||||||
|
)
|
||||||
|
`;
|
||||||
|
const result = await extractPackageFile(input, 'MODULE.bazel');
|
||||||
|
if (!result) {
|
||||||
|
throw new Error('Expected a result.');
|
||||||
|
}
|
||||||
|
expect(result.deps).toEqual([
|
||||||
|
{
|
||||||
|
datasource: BazelDatasource.id,
|
||||||
|
depType: 'bazel_dep',
|
||||||
|
depName: 'rules_foo',
|
||||||
|
currentValue: '1.2.3',
|
||||||
|
registryUrls: ['https://example.com/custom_registry'],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -136,5 +136,36 @@ describe('modules/manager/bazel-module/parser', () => {
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('finds single_version_override', () => {
|
||||||
|
const input = codeBlock`
|
||||||
|
bazel_dep(name = "rules_foo", version = "1.2.3")
|
||||||
|
single_version_override(
|
||||||
|
module_name = "rules_foo",
|
||||||
|
version = "1.2.3",
|
||||||
|
registry = "https://example.com/custom_registry",
|
||||||
|
)
|
||||||
|
`;
|
||||||
|
const res = parse(input);
|
||||||
|
expect(res).toEqual([
|
||||||
|
fragments.record(
|
||||||
|
{
|
||||||
|
rule: fragments.string('bazel_dep'),
|
||||||
|
name: fragments.string('rules_foo'),
|
||||||
|
version: fragments.string('1.2.3'),
|
||||||
|
},
|
||||||
|
true
|
||||||
|
),
|
||||||
|
fragments.record(
|
||||||
|
{
|
||||||
|
rule: fragments.string('single_version_override'),
|
||||||
|
module_name: fragments.string('rules_foo'),
|
||||||
|
version: fragments.string('1.2.3'),
|
||||||
|
registry: fragments.string('https://example.com/custom_registry'),
|
||||||
|
},
|
||||||
|
true
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,6 +10,7 @@ const supportedRules = [
|
||||||
'bazel_dep',
|
'bazel_dep',
|
||||||
'git_override',
|
'git_override',
|
||||||
'local_path_override',
|
'local_path_override',
|
||||||
|
'single_version_override',
|
||||||
];
|
];
|
||||||
const supportedRulesRegex = regEx(`^${supportedRules.join('|')}$`);
|
const supportedRulesRegex = regEx(`^${supportedRules.join('|')}$`);
|
||||||
|
|
||||||
|
|
|
@ -6,13 +6,16 @@ import * as fragments from './fragments';
|
||||||
import {
|
import {
|
||||||
BasePackageDep,
|
BasePackageDep,
|
||||||
BazelModulePackageDep,
|
BazelModulePackageDep,
|
||||||
|
MergePackageDep,
|
||||||
OverridePackageDep,
|
OverridePackageDep,
|
||||||
RuleToBazelModulePackageDep,
|
RuleToBazelModulePackageDep,
|
||||||
overrideToPackageDependency,
|
bazelModulePackageDepToPackageDependency,
|
||||||
processModulePkgDeps,
|
processModulePkgDeps,
|
||||||
toPackageDependencies,
|
toPackageDependencies,
|
||||||
} from './rules';
|
} from './rules';
|
||||||
|
|
||||||
|
const customRegistryUrl = 'https://example.com/custom_registry';
|
||||||
|
|
||||||
const bazelDepPkgDep: BasePackageDep = {
|
const bazelDepPkgDep: BasePackageDep = {
|
||||||
datasource: BazelDatasource.id,
|
datasource: BazelDatasource.id,
|
||||||
depType: 'bazel_dep',
|
depType: 'bazel_dep',
|
||||||
|
@ -46,6 +49,27 @@ const localPathOverridePkgDep: OverridePackageDep = {
|
||||||
skipReason: 'unsupported-datasource',
|
skipReason: 'unsupported-datasource',
|
||||||
bazelDepSkipReason: 'local-dependency',
|
bazelDepSkipReason: 'local-dependency',
|
||||||
};
|
};
|
||||||
|
const singleVersionOverridePkgDep: OverridePackageDep & MergePackageDep = {
|
||||||
|
depType: 'single_version_override',
|
||||||
|
depName: 'rules_foo',
|
||||||
|
skipReason: 'ignored',
|
||||||
|
bazelDepSkipReason: 'is-pinned',
|
||||||
|
currentValue: '1.2.3',
|
||||||
|
bazelDepMergeFields: ['registryUrls'],
|
||||||
|
registryUrls: [customRegistryUrl],
|
||||||
|
};
|
||||||
|
const singleVersionOverrideWithRegistryPkgDep: MergePackageDep = {
|
||||||
|
depType: 'single_version_override',
|
||||||
|
depName: 'rules_foo',
|
||||||
|
skipReason: 'ignored',
|
||||||
|
bazelDepMergeFields: ['registryUrls'],
|
||||||
|
registryUrls: [customRegistryUrl],
|
||||||
|
};
|
||||||
|
const singleVersionOverrideWithoutVersionAndRegistryPkgDep: BasePackageDep = {
|
||||||
|
depType: 'single_version_override',
|
||||||
|
depName: 'rules_foo',
|
||||||
|
skipReason: 'ignored',
|
||||||
|
};
|
||||||
|
|
||||||
describe('modules/manager/bazel-module/rules', () => {
|
describe('modules/manager/bazel-module/rules', () => {
|
||||||
describe('RuleToBazelModulePackageDep', () => {
|
describe('RuleToBazelModulePackageDep', () => {
|
||||||
|
@ -76,6 +100,17 @@ describe('modules/manager/bazel-module/rules', () => {
|
||||||
module_name: fragments.string('rules_foo'),
|
module_name: fragments.string('rules_foo'),
|
||||||
path: fragments.string('/path/to/module'),
|
path: fragments.string('/path/to/module'),
|
||||||
});
|
});
|
||||||
|
const singleVersionOverride = fragments.record({
|
||||||
|
rule: fragments.string('single_version_override'),
|
||||||
|
module_name: fragments.string('rules_foo'),
|
||||||
|
version: fragments.string('1.2.3'),
|
||||||
|
registry: fragments.string(customRegistryUrl),
|
||||||
|
});
|
||||||
|
const singleVersionOverrideWithRegistry = fragments.record({
|
||||||
|
rule: fragments.string('single_version_override'),
|
||||||
|
module_name: fragments.string('rules_foo'),
|
||||||
|
registry: fragments.string(customRegistryUrl),
|
||||||
|
});
|
||||||
|
|
||||||
it.each`
|
it.each`
|
||||||
msg | a | exp
|
msg | a | exp
|
||||||
|
@ -84,6 +119,8 @@ describe('modules/manager/bazel-module/rules', () => {
|
||||||
${'git_override, unsupported host'} | ${gitOverrideWithUnsupportedHost} | ${gitOverrideForUnsupportedPkgDep}
|
${'git_override, unsupported host'} | ${gitOverrideWithUnsupportedHost} | ${gitOverrideForUnsupportedPkgDep}
|
||||||
${'archive_override'} | ${archiveOverride} | ${archiveOverridePkgDep}
|
${'archive_override'} | ${archiveOverride} | ${archiveOverridePkgDep}
|
||||||
${'local_path_override'} | ${localPathOverride} | ${localPathOverridePkgDep}
|
${'local_path_override'} | ${localPathOverride} | ${localPathOverridePkgDep}
|
||||||
|
${'single_version_override with version and registry'} | ${singleVersionOverride} | ${singleVersionOverridePkgDep}
|
||||||
|
${'single_version_override with registry'} | ${singleVersionOverrideWithRegistry} | ${singleVersionOverrideWithRegistryPkgDep}
|
||||||
`('.parse() with $msg', ({ a, exp }) => {
|
`('.parse() with $msg', ({ a, exp }) => {
|
||||||
const pkgDep = RuleToBazelModulePackageDep.parse(a);
|
const pkgDep = RuleToBazelModulePackageDep.parse(a);
|
||||||
expect(pkgDep).toEqual(exp);
|
expect(pkgDep).toEqual(exp);
|
||||||
|
@ -94,15 +131,27 @@ describe('modules/manager/bazel-module/rules', () => {
|
||||||
const expectedBazelDepNoOverrides: PackageDependency[] = [bazelDepPkgDep];
|
const expectedBazelDepNoOverrides: PackageDependency[] = [bazelDepPkgDep];
|
||||||
const expectedBazelDepAndGitOverride: PackageDependency[] = [
|
const expectedBazelDepAndGitOverride: PackageDependency[] = [
|
||||||
deepmerge(bazelDepPkgDep, { skipReason: 'git-dependency' }),
|
deepmerge(bazelDepPkgDep, { skipReason: 'git-dependency' }),
|
||||||
overrideToPackageDependency(gitOverrideForGithubPkgDep),
|
bazelModulePackageDepToPackageDependency(gitOverrideForGithubPkgDep),
|
||||||
|
];
|
||||||
|
const expectedBazelDepAndSingleVersionOverride: PackageDependency[] = [
|
||||||
|
deepmerge(bazelDepPkgDep, {
|
||||||
|
skipReason: 'is-pinned',
|
||||||
|
registryUrls: [customRegistryUrl],
|
||||||
|
}),
|
||||||
|
bazelModulePackageDepToPackageDependency(singleVersionOverridePkgDep),
|
||||||
];
|
];
|
||||||
const expectedBazelDepAndArchiveOverride: PackageDependency[] = [
|
const expectedBazelDepAndArchiveOverride: PackageDependency[] = [
|
||||||
deepmerge(bazelDepPkgDep, { skipReason: 'file-dependency' }),
|
deepmerge(bazelDepPkgDep, { skipReason: 'file-dependency' }),
|
||||||
overrideToPackageDependency(archiveOverridePkgDep),
|
bazelModulePackageDepToPackageDependency(archiveOverridePkgDep),
|
||||||
];
|
];
|
||||||
const expectedBazelDepAndLocalPathOverride: PackageDependency[] = [
|
const expectedBazelDepAndLocalPathOverride: PackageDependency[] = [
|
||||||
deepmerge(bazelDepPkgDep, { skipReason: 'local-dependency' }),
|
deepmerge(bazelDepPkgDep, { skipReason: 'local-dependency' }),
|
||||||
overrideToPackageDependency(localPathOverridePkgDep),
|
bazelModulePackageDepToPackageDependency(localPathOverridePkgDep),
|
||||||
|
];
|
||||||
|
// If a registry is specified and a version is not specified for a
|
||||||
|
// single_version_override, it is merely providing a registry URL for the bazel_dep.
|
||||||
|
const expectedBazelDepWithRegistry: PackageDependency[] = [
|
||||||
|
deepmerge(bazelDepPkgDep, { registryUrls: [customRegistryUrl] }),
|
||||||
];
|
];
|
||||||
|
|
||||||
it.each`
|
it.each`
|
||||||
|
@ -112,25 +161,15 @@ describe('modules/manager/bazel-module/rules', () => {
|
||||||
${'git_override, no bazel_dep'} | ${[gitOverrideForGithubPkgDep]} | ${[]}
|
${'git_override, no bazel_dep'} | ${[gitOverrideForGithubPkgDep]} | ${[]}
|
||||||
${'bazel_dep & archive_override'} | ${[bazelDepPkgDep, archiveOverridePkgDep]} | ${expectedBazelDepAndArchiveOverride}
|
${'bazel_dep & archive_override'} | ${[bazelDepPkgDep, archiveOverridePkgDep]} | ${expectedBazelDepAndArchiveOverride}
|
||||||
${'bazel_dep & local_path_override'} | ${[bazelDepPkgDep, localPathOverridePkgDep]} | ${expectedBazelDepAndLocalPathOverride}
|
${'bazel_dep & local_path_override'} | ${[bazelDepPkgDep, localPathOverridePkgDep]} | ${expectedBazelDepAndLocalPathOverride}
|
||||||
`('with $msg', ({ a, exp }) => {
|
${'single_version_override, with version and registry'} | ${[bazelDepPkgDep, singleVersionOverridePkgDep]} | ${expectedBazelDepAndSingleVersionOverride}
|
||||||
|
${'single_version_override, with registry'} | ${[bazelDepPkgDep, singleVersionOverrideWithRegistryPkgDep]} | ${expectedBazelDepWithRegistry}
|
||||||
|
${'single_version_override, without version and registry'} | ${[bazelDepPkgDep, singleVersionOverrideWithoutVersionAndRegistryPkgDep]} | ${[bazelDepPkgDep]}
|
||||||
|
`('with $msg', ({ msg, a, exp }) => {
|
||||||
const result = toPackageDependencies(a);
|
const result = toPackageDependencies(a);
|
||||||
expect(result).toEqual(exp);
|
expect(result).toEqual(exp);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('.overrideToPackageDependency()', () => {
|
|
||||||
it('removes the properties specific to OverridePackageDep', () => {
|
|
||||||
const result = overrideToPackageDependency(gitOverrideForGithubPkgDep);
|
|
||||||
expect(result).toEqual({
|
|
||||||
datasource: GithubTagsDatasource.id,
|
|
||||||
depType: 'git_override',
|
|
||||||
depName: 'rules_foo',
|
|
||||||
packageName: 'example/rules_foo',
|
|
||||||
currentDigest: '850cb49c8649e463b80ef7984e7c744279746170',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('.processModulePkgDeps', () => {
|
describe('.processModulePkgDeps', () => {
|
||||||
it('returns an empty array if the input is an empty array', () => {
|
it('returns an empty array if the input is an empty array', () => {
|
||||||
expect(processModulePkgDeps([])).toHaveLength(0);
|
expect(processModulePkgDeps([])).toHaveLength(0);
|
||||||
|
|
|
@ -16,27 +16,49 @@ export interface BasePackageDep extends PackageDependency {
|
||||||
depName: string;
|
depName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BasePackageDepMergeKeys = Extract<keyof BasePackageDep, 'registryUrls'>;
|
||||||
|
|
||||||
|
export interface MergePackageDep extends BasePackageDep {
|
||||||
|
// The fields that should be copied from this struct to the bazel_dep
|
||||||
|
// PackageDependency.
|
||||||
|
bazelDepMergeFields: BasePackageDepMergeKeys[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface OverridePackageDep extends BasePackageDep {
|
export interface OverridePackageDep extends BasePackageDep {
|
||||||
// This value is set as the skipReason on the bazel_dep PackageDependency.
|
// This value is set as the skipReason on the bazel_dep PackageDependency.
|
||||||
bazelDepSkipReason: SkipReason;
|
bazelDepSkipReason: SkipReason;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BazelModulePackageDep = BasePackageDep | OverridePackageDep;
|
export type BazelModulePackageDep =
|
||||||
|
| BasePackageDep
|
||||||
|
| OverridePackageDep
|
||||||
|
| MergePackageDep;
|
||||||
|
|
||||||
function isOverride(value: BazelModulePackageDep): value is OverridePackageDep {
|
function isOverride(value: BazelModulePackageDep): value is OverridePackageDep {
|
||||||
return 'bazelDepSkipReason' in value;
|
return 'bazelDepSkipReason' in value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isMerge(value: BazelModulePackageDep): value is MergePackageDep {
|
||||||
|
return 'bazelDepMergeFields' in value;
|
||||||
|
}
|
||||||
|
|
||||||
// This function exists to remove properties that are specific to
|
// This function exists to remove properties that are specific to
|
||||||
// OverridePackageDep. In theory, there is no harm in leaving the properties
|
// BazelModulePackageDep. In theory, there is no harm in leaving the properties
|
||||||
// as it does not invalidate the PackageDependency interface. However, it might
|
// as it does not invalidate the PackageDependency interface. However, it might
|
||||||
// be surprising to someone outside the bazel-module code to see the extra
|
// be surprising to someone outside the bazel-module code to see the extra
|
||||||
// properties.
|
// properties.
|
||||||
export function overrideToPackageDependency(
|
export function bazelModulePackageDepToPackageDependency(
|
||||||
override: OverridePackageDep
|
bmpd: BazelModulePackageDep
|
||||||
): PackageDependency {
|
): PackageDependency {
|
||||||
const copy: Partial<OverridePackageDep> = { ...override };
|
const copy: BazelModulePackageDep = structuredClone(bmpd);
|
||||||
delete copy.bazelDepSkipReason;
|
if (isOverride(copy)) {
|
||||||
|
const partial = copy as Partial<OverridePackageDep>;
|
||||||
|
delete partial.bazelDepSkipReason;
|
||||||
|
}
|
||||||
|
if (isMerge(copy)) {
|
||||||
|
const partial = copy as Partial<MergePackageDep>;
|
||||||
|
delete partial.bazelDepMergeFields;
|
||||||
|
}
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,6 +109,40 @@ const GitOverrideToPackageDep = RecordFragmentSchema.extend({
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const SingleVersionOverrideToPackageDep = RecordFragmentSchema.extend({
|
||||||
|
children: z.object({
|
||||||
|
rule: StringFragmentSchema.extend({
|
||||||
|
value: z.literal('single_version_override'),
|
||||||
|
}),
|
||||||
|
module_name: StringFragmentSchema,
|
||||||
|
version: StringFragmentSchema.optional(),
|
||||||
|
registry: StringFragmentSchema.optional(),
|
||||||
|
}),
|
||||||
|
}).transform(
|
||||||
|
({
|
||||||
|
children: { rule, module_name: moduleName, version, registry },
|
||||||
|
}): BasePackageDep => {
|
||||||
|
const base: BasePackageDep = {
|
||||||
|
depType: rule.value,
|
||||||
|
depName: moduleName.value,
|
||||||
|
skipReason: 'ignored',
|
||||||
|
};
|
||||||
|
// If a version is specified, then add a skipReason to bazel_dep
|
||||||
|
if (version) {
|
||||||
|
const override = base as OverridePackageDep;
|
||||||
|
override.bazelDepSkipReason = 'is-pinned';
|
||||||
|
override.currentValue = version.value;
|
||||||
|
}
|
||||||
|
// If a registry is specified, then merge it into the bazel_dep
|
||||||
|
if (registry) {
|
||||||
|
const merge = base as MergePackageDep;
|
||||||
|
merge.bazelDepMergeFields = ['registryUrls'];
|
||||||
|
merge.registryUrls = [registry.value];
|
||||||
|
}
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const UnsupportedOverrideToPackageDep = RecordFragmentSchema.extend({
|
const UnsupportedOverrideToPackageDep = RecordFragmentSchema.extend({
|
||||||
children: z.object({
|
children: z.object({
|
||||||
rule: StringFragmentSchema.extend({
|
rule: StringFragmentSchema.extend({
|
||||||
|
@ -117,6 +173,7 @@ const UnsupportedOverrideToPackageDep = RecordFragmentSchema.extend({
|
||||||
export const RuleToBazelModulePackageDep = z.union([
|
export const RuleToBazelModulePackageDep = z.union([
|
||||||
BazelDepToPackageDep,
|
BazelDepToPackageDep,
|
||||||
GitOverrideToPackageDep,
|
GitOverrideToPackageDep,
|
||||||
|
SingleVersionOverrideToPackageDep,
|
||||||
UnsupportedOverrideToPackageDep,
|
UnsupportedOverrideToPackageDep,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -151,7 +208,14 @@ export function processModulePkgDeps(
|
||||||
logger.debug(`A 'bazel_dep' was not found for '${moduleName}'.`);
|
logger.debug(`A 'bazel_dep' was not found for '${moduleName}'.`);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const deps: PackageDependency[] = [bazelDep];
|
// Create a new bazelDep that will be modified. We do not want to change the
|
||||||
|
// input.
|
||||||
|
const bazelDepOut = { ...bazelDep };
|
||||||
|
const deps: PackageDependency[] = [bazelDepOut];
|
||||||
|
const merges = packageDeps.filter(isMerge);
|
||||||
|
for (const merge of merges) {
|
||||||
|
merge.bazelDepMergeFields.forEach((k) => (bazelDepOut[k] = merge[k]));
|
||||||
|
}
|
||||||
const overrides = packageDeps.filter(isOverride);
|
const overrides = packageDeps.filter(isOverride);
|
||||||
// It is an error for more than one override to exist for a module. We will
|
// It is an error for more than one override to exist for a module. We will
|
||||||
// ignore the overrides if there is more than one.
|
// ignore the overrides if there is more than one.
|
||||||
|
@ -164,8 +228,8 @@ export function processModulePkgDeps(
|
||||||
return deps;
|
return deps;
|
||||||
}
|
}
|
||||||
const override = overrides[0];
|
const override = overrides[0];
|
||||||
deps.push(overrideToPackageDependency(override));
|
deps.push(bazelModulePackageDepToPackageDependency(override));
|
||||||
bazelDep.skipReason = override.bazelDepSkipReason;
|
bazelDepOut.skipReason = override.bazelDepSkipReason;
|
||||||
return deps;
|
return deps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue