feat(manager/bazel): recognize Bazel rules that begin with an underscore (#24496)

Co-authored-by: Rhys Arkins <rhys@arkins.net>
This commit is contained in:
Zak Cutner
2023-09-20 08:03:58 +01:00
committed by GitHub
parent 1580b4d8d5
commit da7fbc0223
13 changed files with 255 additions and 25 deletions
+6 -2
View File
@@ -154,14 +154,18 @@ Renovate ignores [`multiple_version_override`](https://bazel.build/rules/lib/glo
## Legacy `WORKSPACE` files
Renovate extracts dependencies from:
Renovate extracts dependencies from the following repository rules:
- `container_pull`
- `oci_pull`
- `git_repository`
- `go_repository`
- `maven_install`
- `http_archive` or `http_file` declarations
- `http_archive`
- `http_file`
It also recognizes when these repository rule names are prefixed with an
underscore. For example, `_http_archive` is treated the same as `http_archive`.
### `git_repository`
@@ -1,14 +1,14 @@
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
load("@bazel_tools//tools/build_defs/repo:http.bzl", _http_archive = "http_archive")
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
http_archive(
_http_archive(
name = "GBDeviceInfo",
url = "https://github.com/lmirosevic/GBDeviceInfo/archive/6.3.0.tar.gz",
sha256 = "d7666275dff039407ea467c3083b83e24934101777c8b55b6b1b3b7e9a9e220b",
strip_prefix = "GBDeviceInfo-6.3.0/GBDeviceInfo"
)
http_archive(
_http_archive(
name = "com_github_nelhage_rules_boost",
url = "https://github.com/nelhage/rules_boost/archive/135d46b4c9423ee7d494c78a21ff621bc73c12f3.tar.gz",
sha256 = "3651f5dda0f7296e4cecafacc7f9d1f274be0fd64e30bebd74e28ffba28fe77f",
@@ -17,14 +17,14 @@ http_archive(
load("@com_github_nelhage_rules_boost//:boost/boost.bzl", "boost_deps")
boost_deps()
http_archive(
_http_archive(
name = "GBDeviceInfo-zip",
url = "https://github.com/lmirosevic/GBDeviceInfo/archive/6.3.0.zip",
sha256 = "4ef4320c4880fd64cfb7f42132f4b02fa626bccf1ba3e1a71dfbfcb50735f141",
strip_prefix = "GBDeviceInfo-6.3.0/GBDeviceInfo"
)
http_archive(
_http_archive(
name = "com_github_nelhage_rules_boost-zip",
url = "https://github.com/nelhage/rules_boost/archive/135d46b4c9423ee7d494c78a21ff621bc73c12f3.zip",
sha256 = "de8aac034cabe4a9ba5f7a33b9523862bf76c245a6c554c0e737f591bb7c7aeb",
@@ -32,7 +32,7 @@ http_archive(
)
maybe(
http_archive,
_http_archive,
name = "io_bazel_rules_go",
sha256 = "2b1641428dff9018f9e85c0384f03ec6c10660d935b750e3fa1492a281a53b0f",
url = "https://github.com/bazelbuild/rules_go/releases/download/v0.29.0/rules_go-v0.29.0.zip",
+189
View File
@@ -276,6 +276,61 @@ describe('modules/manager/bazel/artifacts', () => {
expect(res).toBeNull();
});
it('errors for _http_archive without urls', async () => {
const input = codeBlock`
_http_archive(
name = "bazel_skylib",
sha256 = "b5f6abe419da897b7901f90cbab08af958b97a8f3575b0d3dd062ac7ce78541f",
strip_prefix = "bazel-skylib-0.5.0",
)
`;
const upgrade = {
depName: 'bazel_skylib',
depType: 'http_archive',
repo: 'bazelbuild/bazel-skylib',
managerData: { idx: 0 },
currentValue: '0.5.0',
newValue: '0.6.2',
};
const res = await updateArtifacts(
partial<UpdateArtifact>({
packageFileName: 'WORKSPACE',
updatedDeps: [upgrade],
newPackageFileContent: input,
})
);
expect(res).toBeNull();
});
it('errors for maybe(_http_archive) without urls', async () => {
const input = codeBlock`
maybe(
_http_archive,
name = "bazel_skylib",
sha256 = "b5f6abe419da897b7901f90cbab08af958b97a8f3575b0d3dd062ac7ce78541f",
strip_prefix = "bazel-skylib-0.5.0",
)
`;
const upgrade = {
depName: 'bazel_skylib',
depType: 'http_archive',
repo: 'bazelbuild/bazel-skylib',
managerData: { idx: 0 },
currentValue: '0.5.0',
newValue: '0.6.2',
};
const res = await updateArtifacts(
partial<UpdateArtifact>({
packageFileName: 'WORKSPACE',
updatedDeps: [upgrade],
newPackageFileContent: input,
})
);
expect(res).toBeNull();
});
it('updates http_archive with urls array', async () => {
const inputHash =
'b5f6abe419da897b7901f90cbab08af958b97a8f3575b0d3dd062ac7ce78541f';
@@ -410,6 +465,140 @@ describe('modules/manager/bazel/artifacts', () => {
]);
});
it('updates _http_archive with urls array', async () => {
const inputHash =
'b5f6abe419da897b7901f90cbab08af958b97a8f3575b0d3dd062ac7ce78541f';
const input = codeBlock`
_http_archive(
name = "bazel_skylib",
sha256 = "${inputHash}",
strip_prefix = "bazel-skylib-0.5.0",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/archive/0.5.0.tar.gz",
"https://github.com/bazelbuild/bazel-skylib/archive/0.5.0.tar.gz",
],
)
`;
const currentValue = '0.5.0';
const newValue = '0.6.2';
const upgrade = {
depName: 'bazel_skylib',
depType: 'http_archive',
repo: 'bazelbuild/bazel-skylib',
managerData: { idx: 0 },
currentValue,
newValue,
};
const tarContent = Buffer.from('foo');
const outputHash = crypto
.createHash('sha256')
.update(tarContent)
.digest('hex');
const output = input
.replace(currentValue, newValue)
.replace(currentValue, newValue)
.replace(currentValue, newValue)
.replace(inputHash, outputHash);
httpMock
.scope('https://github.com')
.get('/bazelbuild/bazel-skylib/archive/0.6.2.tar.gz')
.reply(200, tarContent);
httpMock
.scope('https://mirror.bazel.build')
.get('/github.com/bazelbuild/bazel-skylib/archive/0.6.2.tar.gz')
.reply(200, tarContent);
const res = await updateArtifacts(
partial<UpdateArtifact>({
packageFileName: 'WORKSPACE',
updatedDeps: [upgrade],
newPackageFileContent: input,
})
);
expect(res).toEqual([
{
file: {
contents: output,
path: 'WORKSPACE',
type: 'addition',
},
},
]);
});
it('updates maybe(_http_archive) with urls array', async () => {
const inputHash =
'b5f6abe419da897b7901f90cbab08af958b97a8f3575b0d3dd062ac7ce78541f';
const input = codeBlock`
maybe(
_http_archive,
name = "bazel_skylib",
sha256 = "${inputHash}",
strip_prefix = "bazel-skylib-0.5.0",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/archive/0.5.0.tar.gz",
"https://github.com/bazelbuild/bazel-skylib/archive/0.5.0.tar.gz",
],
)
`;
const currentValue = '0.5.0';
const newValue = '0.6.2';
const upgrade = {
depName: 'bazel_skylib',
depType: 'http_archive',
repo: 'bazelbuild/bazel-skylib',
managerData: { idx: 0 },
currentValue,
newValue,
};
const tarContent = Buffer.from('foo');
const outputHash = crypto
.createHash('sha256')
.update(tarContent)
.digest('hex');
const output = input
.replace(currentValue, newValue)
.replace(currentValue, newValue)
.replace(currentValue, newValue)
.replace(inputHash, outputHash);
httpMock
.scope('https://github.com')
.get('/bazelbuild/bazel-skylib/archive/0.6.2.tar.gz')
.reply(200, tarContent);
httpMock
.scope('https://mirror.bazel.build')
.get('/github.com/bazelbuild/bazel-skylib/archive/0.6.2.tar.gz')
.reply(200, tarContent);
const res = await updateArtifacts(
partial<UpdateArtifact>({
packageFileName: 'WORKSPACE',
updatedDeps: [upgrade],
newPackageFileContent: input,
})
);
expect(res).toEqual([
{
file: {
contents: output,
path: 'WORKSPACE',
type: 'addition',
},
},
]);
});
it('updates one http_archive alongside others', async () => {
const inputHash =
'5aef09ed3279aa01d5c928e3beb248f9ad32dde6aafe6373a8c994c3ce643064';
+8 -8
View File
@@ -1,6 +1,10 @@
import type { PackageDependency, PackageFileContent } from '../types';
import { parse } from './parser';
import { extractDepsFromFragment } from './rules';
import { dockerRules } from './rules/docker';
import { gitRules } from './rules/git';
import { goRules } from './rules/go';
import { ociRules } from './rules/oci';
import type { RecordFragment } from './types';
export function extractPackageFile(
@@ -19,15 +23,11 @@ export function extractPackageFile(
for (const dep of extractDepsFromFragment(fragment)) {
dep.managerData = { idx };
// Selectively provide `replaceString` in order
// to auto-replace functionality work correctly.
// Selectively provide `replaceString` in order to make auto-replace
// functionality work correctly.
const rules = [...dockerRules, ...ociRules, ...gitRules, ...goRules];
const replaceString = fragment.value;
if (
replaceString.startsWith('container_pull') ||
replaceString.startsWith('oci_pull') ||
replaceString.startsWith('git_repository') ||
replaceString.startsWith('go_repository')
) {
if (rules.some((rule) => replaceString.startsWith(rule))) {
if (dep.currentValue && dep.currentDigest) {
dep.replaceString = replaceString;
}
+32
View File
@@ -7,6 +7,8 @@ describe('modules/manager/bazel/parser', () => {
const input = codeBlock`
go_repository(name = "foo")
maybe(go_repository, name = "bar", deps = ["baz", "qux"])
_go_repository(name = "quux")
maybe(_go_repository, name = "corge", deps = ["grault", "garply"])
`;
const res = parse(input);
@@ -39,10 +41,40 @@ describe('modules/manager/bazel/parser', () => {
},
},
},
{
type: 'record',
value: '_go_repository(name = "quux")',
offset: 86,
children: {
rule: { type: 'string', value: '_go_repository', offset: 86 },
name: { type: 'string', value: 'quux', offset: 109 },
},
},
{
type: 'record',
value:
'maybe(_go_repository, name = "corge", deps = ["grault", "garply"])',
offset: 116,
children: {
rule: { type: 'string', value: '_go_repository', offset: 122 },
name: { type: 'string', value: 'corge', offset: 146 },
deps: {
type: 'array',
value: '["grault", "garply"]',
offset: 161,
children: [
{ type: 'string', value: 'grault', offset: 163 },
{ type: 'string', value: 'garply', offset: 173 },
],
},
},
},
]);
expect(res?.map(extract)).toMatchObject([
{ rule: 'go_repository', name: 'foo' },
{ rule: 'go_repository', name: 'bar', deps: ['baz', 'qux'] },
{ rule: '_go_repository', name: 'quux' },
{ rule: '_go_repository', name: 'corge', deps: ['grault', 'garply'] },
]);
});
+2 -2
View File
@@ -261,7 +261,7 @@ function ruleNameHandler(ctx: Ctx, { value, offset }: lexer.Token): Ctx {
/**
* Matches regular rules:
* - `git_repository(...)`
* - `go_repository(...)`
* - `_go_repository(...)`
*/
const regularRule = q
.sym<Ctx>(supportedRulesRegex, (ctx, token) =>
@@ -272,7 +272,7 @@ const regularRule = q
/**
* Matches "maybe"-form rules:
* - `maybe(git_repository, ...)`
* - `maybe(go_repository, ...)`
* - `maybe(_go_repository, ...)`
*/
const maybeRule = q
.sym<Ctx>('maybe', recordStartHandler)
+1 -1
View File
@@ -3,7 +3,7 @@ import { DockerDatasource } from '../../../datasource/docker';
import { id as dockerVersioning } from '../../../versioning/docker';
import type { PackageDependency } from '../../types';
export const dockerRules = ['container_pull'] as const;
export const dockerRules = ['container_pull', '_container_pull'] as const;
export const DockerTarget = z
.object({
+1 -1
View File
@@ -17,7 +17,7 @@ function githubPackageName(input: string): string | undefined {
return parseGithubUrl(input)?.match(githubUrlRegex)?.groups?.packageName;
}
export const gitRules = ['git_repository'] as const;
export const gitRules = ['git_repository', '_git_repository'] as const;
export const GitTarget = z
.object({
+1 -1
View File
@@ -3,7 +3,7 @@ import { regEx } from '../../../../util/regex';
import { GoDatasource } from '../../../datasource/go';
import type { PackageDependency } from '../../types';
export const goRules = ['go_repository'] as const;
export const goRules = ['go_repository', '_go_repository'] as const;
export const GoTarget = z
.object({
+6 -1
View File
@@ -119,7 +119,12 @@ export function parseArchiveUrl(
return null;
}
export const httpRules = ['http_archive', 'http_file'] as const;
export const httpRules = [
'http_archive',
'_http_archive',
'http_file',
'_http_file',
] as const;
export const HttpTarget = z
.object({
+1 -1
View File
@@ -30,7 +30,7 @@ const supportedRules = [
...httpRules,
...mavenRules,
];
export const supportedRulesRegex = regEx(`^${supportedRules.join('|')}$`);
export const supportedRulesRegex = regEx(`^(?:${supportedRules.join('|')})$`);
export function extractDepsFromFragmentData(
fragmentData: FragmentData
+1 -1
View File
@@ -4,7 +4,7 @@ import { MavenDatasource } from '../../../datasource/maven';
import { id as versioning } from '../../../versioning/gradle';
import type { PackageDependency } from '../../types';
export const mavenRules = ['maven_install'] as const;
export const mavenRules = ['maven_install', '_maven_install'] as const;
const ArtifactSpec = z.union([
z.object({
+1 -1
View File
@@ -3,7 +3,7 @@ import { DockerDatasource } from '../../../datasource/docker';
import { id as dockerVersioning } from '../../../versioning/docker';
import type { PackageDependency } from '../../types';
export const ociRules = ['oci_pull'] as const;
export const ociRules = ['oci_pull', '_oci_pull'] as const;
export const OciTarget = z
.object({