-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(manager): Cloud Native Buildpacks project descriptor manager (#3…
…0799) Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> Co-authored-by: Michael Kriese <michael.kriese@visualon.de> Co-authored-by: loewenstein-sap <jan.von.loewenstein@sap.com>
- Loading branch information
1 parent
6bdd27a
commit bbedb2d
Showing
7 changed files
with
280 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import { codeBlock } from 'common-tags'; | ||
|
||
import { extractPackageFile } from '.'; | ||
|
||
describe('modules/manager/buildpacks/extract', () => { | ||
describe('extractPackageFile()', () => { | ||
it('returns null for invalid files', () => { | ||
expect(extractPackageFile('not a project toml', '', {})).toBeNull(); | ||
}); | ||
|
||
it('returns null for empty package.toml', () => { | ||
const res = extractPackageFile( | ||
'[_]\nschema-version = "0.2"', | ||
'project.toml', | ||
{}, | ||
); | ||
expect(res).toBeNull(); | ||
}); | ||
|
||
it('extracts builder and buildpack images', () => { | ||
const res = extractPackageFile( | ||
codeBlock` | ||
[_] | ||
schema-version = "0.2" | ||
[io.buildpacks] | ||
builder = "registry.corp/builder/noble:1.1.1" | ||
[[io.buildpacks.group]] | ||
uri = "docker://buildpacks/java:2.2.2" | ||
[[io.buildpacks.group]] | ||
uri = "buildpacks/nodejs:3.3.3" | ||
[[io.buildpacks.group]] | ||
uri = "example/foo@1.0.0" | ||
[[io.buildpacks.group]] | ||
uri = "example/registry-cnb" | ||
[[io.buildpacks.group]] | ||
uri = "urn:cnb:registry:example/foo@1.0.0" | ||
[[io.buildpacks.group]] | ||
uri = "some-bp@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" | ||
[[io.buildpacks.group]] | ||
uri = "cnbs/some-bp:some-tag@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" | ||
[[io.buildpacks.group]] | ||
uri = "from=builder:foobar" | ||
[[io.buildpacks.group]] | ||
uri = "file://local.oci" | ||
[[io.buildpacks.group]] | ||
uri = "foo://fake.oci"`, | ||
'project.toml', | ||
{}, | ||
); | ||
expect(res?.deps).toEqual([ | ||
{ | ||
autoReplaceStringTemplate: | ||
'{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}', | ||
commitMessageTopic: 'builder {{depName}}', | ||
currentValue: '1.1.1', | ||
datasource: 'docker', | ||
depName: 'registry.corp/builder/noble', | ||
replaceString: 'registry.corp/builder/noble:1.1.1', | ||
}, | ||
{ | ||
autoReplaceStringTemplate: | ||
'{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}', | ||
currentValue: '2.2.2', | ||
datasource: 'docker', | ||
depName: 'buildpacks/java', | ||
replaceString: 'buildpacks/java:2.2.2', | ||
}, | ||
{ | ||
autoReplaceStringTemplate: | ||
'{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}', | ||
currentValue: '3.3.3', | ||
datasource: 'docker', | ||
depName: 'buildpacks/nodejs', | ||
replaceString: 'buildpacks/nodejs:3.3.3', | ||
}, | ||
{ | ||
autoReplaceStringTemplate: | ||
'{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}', | ||
currentDigest: | ||
'sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef', | ||
datasource: 'docker', | ||
depName: 'some-bp', | ||
replaceString: | ||
'some-bp@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef', | ||
}, | ||
{ | ||
autoReplaceStringTemplate: | ||
'{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}', | ||
currentDigest: | ||
'sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef', | ||
currentValue: 'some-tag', | ||
datasource: 'docker', | ||
depName: 'cnbs/some-bp', | ||
replaceString: | ||
'cnbs/some-bp:some-tag@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef', | ||
}, | ||
]); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import is from '@sindresorhus/is'; | ||
import { logger } from '../../../logger'; | ||
import { regEx } from '../../../util/regex'; | ||
import { getDep } from '../dockerfile/extract'; | ||
import type { | ||
ExtractConfig, | ||
PackageDependency, | ||
PackageFileContent, | ||
} from '../types'; | ||
import { type ProjectDescriptor, ProjectDescriptorToml } from './schema'; | ||
|
||
const dockerPrefix = regEx(/^docker:\/?\//); | ||
const dockerRef = regEx( | ||
/^((?:[a-z\d](?:[a-z\d-]{0,61}[a-z\d])?(?:\.[a-z\d](?:[a-z\d-]{0,61}[a-z\d])?)*)(?::\d{2,5}\/)?)?[a-z\d]+((\.|_|__|-+)[a-z\d]+)*(\/[a-z\d]+((\.|_|__|-+)[a-z\d]+)*)*(?::(\w[\w.-]{0,127})(?:@sha256:[A-Fa-f\d]{32,})?|@sha256:[A-Fa-f\d]{32,})$/, | ||
); | ||
|
||
function isDockerRef(ref: string): boolean { | ||
if (ref.startsWith('docker:/') || dockerRef.test(ref)) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
function parseProjectToml( | ||
content: string, | ||
packageFile: string, | ||
): ProjectDescriptor | null { | ||
const res = ProjectDescriptorToml.safeParse(content); | ||
if (res.success) { | ||
return res.data; | ||
} | ||
|
||
logger.debug( | ||
{ packageFile, err: res.error }, | ||
'Failed to parse buildpacks project descriptor TOML', | ||
); | ||
|
||
return null; | ||
} | ||
|
||
export function extractPackageFile( | ||
content: string, | ||
packageFile: string, | ||
config: ExtractConfig, | ||
): PackageFileContent | null { | ||
const deps: PackageDependency[] = []; | ||
|
||
const descriptor = parseProjectToml(content, packageFile); | ||
if (!descriptor) { | ||
return null; | ||
} | ||
|
||
if ( | ||
descriptor.io?.buildpacks?.builder && | ||
isDockerRef(descriptor.io.buildpacks.builder) | ||
) { | ||
const dep = getDep( | ||
descriptor.io.buildpacks.builder.replace(dockerPrefix, ''), | ||
true, | ||
config.registryAliases, | ||
); | ||
logger.trace( | ||
{ | ||
depName: dep.depName, | ||
currentValue: dep.currentValue, | ||
currentDigest: dep.currentDigest, | ||
}, | ||
'Cloud Native Buildpacks builder', | ||
); | ||
|
||
deps.push({ ...dep, commitMessageTopic: 'builder {{depName}}' }); | ||
} | ||
|
||
if ( | ||
descriptor.io?.buildpacks?.group && | ||
is.array(descriptor.io.buildpacks.group) | ||
) { | ||
for (const group of descriptor.io.buildpacks.group) { | ||
if (group.uri && isDockerRef(group.uri)) { | ||
const dep = getDep( | ||
group.uri.replace(dockerPrefix, ''), | ||
true, | ||
config.registryAliases, | ||
); | ||
logger.trace( | ||
{ | ||
depName: dep.depName, | ||
currentValue: dep.currentValue, | ||
currentDigest: dep.currentDigest, | ||
}, | ||
'Cloud Native Buildpack', | ||
); | ||
|
||
deps.push(dep); | ||
} | ||
} | ||
} | ||
|
||
if (!deps.length) { | ||
return null; | ||
} | ||
return { deps }; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import type { Category } from '../../../constants'; | ||
import { DockerDatasource } from '../../datasource/docker'; | ||
export { extractPackageFile } from './extract'; | ||
|
||
export const defaultConfig = { | ||
commitMessageTopic: 'buildpack {{depName}}', | ||
fileMatch: ['(^|/)project\\.toml$'], | ||
pinDigests: false, | ||
}; | ||
|
||
export const categories: Category[] = ['docker']; | ||
export const supportedDatasources = [DockerDatasource.id]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
The `buildpacks` manager updates Cloud Native Buildpacks project descriptors in `project.toml` files. | ||
A `project.toml` file can reference builder / buildpack images by URIs. | ||
Renovate can update a `project.toml` file if: | ||
|
||
- It can find the file | ||
- The file follows the [project descriptor specifications](https://github.com/buildpacks/spec/blob/main/extensions/project-descriptor.md) | ||
- The buildpack `uri` is an OCI image reference (references to a local file or buildpack registry are ignored) | ||
|
||
If you use buildpacks in the `io.buildpacks.group` array, then you _must_ configure the Docker reference (`uri`) for Renovate to work. | ||
|
||
```toml title="Example of a project.toml file with Docker reference URIs" | ||
[_] | ||
schema-version = "0.2" | ||
|
||
[io.buildpacks] | ||
builder = "registry.corp/builder/noble:1.1.1" | ||
|
||
[[io.buildpacks.group]] | ||
uri = "docker://buildpacks/java:2.2.2" | ||
|
||
[[io.buildpacks.group]] | ||
uri = "buildpacks/nodejs:3.3.3" | ||
|
||
[[io.buildpacks.group]] | ||
uri = "file://local.oci" # will be ignored | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { z } from 'zod'; | ||
import { Toml } from '../../../util/schema-utils'; | ||
|
||
const BuildpackGroup = z.object({ | ||
uri: z.string().optional(), | ||
}); | ||
|
||
const IoBuildpacks = z.object({ | ||
builder: z.string().optional(), | ||
group: z.array(BuildpackGroup).optional(), | ||
}); | ||
|
||
export const ProjectDescriptor = z.object({ | ||
_: z.object({ | ||
'schema-version': z.string(), | ||
}), | ||
io: z | ||
.object({ | ||
buildpacks: IoBuildpacks.optional(), | ||
}) | ||
.optional(), | ||
}); | ||
|
||
export type ProjectDescriptor = z.infer<typeof ProjectDescriptor>; | ||
export const ProjectDescriptorToml = Toml.pipe(ProjectDescriptor); |