From 3bc70052d7c0859a56c72c71b3602e94f6568f33 Mon Sep 17 00:00:00 2001 From: Nicolas Bender Date: Mon, 25 Nov 2024 15:18:08 +0100 Subject: [PATCH 01/13] Add datasource for buildpack registry Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> Co-authored-by: Michael Kriese Co-authored-by: Pavel Busko Co-authored-by: Johannes Dillmann Co-authored-by: Nicolas Bender --- lib/modules/datasource/api.ts | 2 + .../__fixtures__/heroku-python.json | 1 + .../__snapshots__/index.spec.ts.snap | 88 +++++++++++++++++++ .../buildpacks-registry/index.spec.ts | 22 +++++ .../datasource/buildpacks-registry/index.ts | 59 +++++++++++++ .../buildpacks-registry/schema.spec.ts | 59 +++++++++++++ .../datasource/buildpacks-registry/schema.ts | 15 ++++ .../manager/buildpacks/extract.spec.ts | 43 +++++++-- lib/modules/manager/buildpacks/extract.ts | 65 ++++++++++++-- lib/modules/manager/buildpacks/index.ts | 8 +- lib/modules/manager/buildpacks/readme.md | 2 +- lib/modules/manager/buildpacks/schema.ts | 29 +++++- 12 files changed, 374 insertions(+), 19 deletions(-) create mode 100644 lib/modules/datasource/buildpacks-registry/__fixtures__/heroku-python.json create mode 100644 lib/modules/datasource/buildpacks-registry/__snapshots__/index.spec.ts.snap create mode 100644 lib/modules/datasource/buildpacks-registry/index.spec.ts create mode 100644 lib/modules/datasource/buildpacks-registry/index.ts create mode 100644 lib/modules/datasource/buildpacks-registry/schema.spec.ts create mode 100644 lib/modules/datasource/buildpacks-registry/schema.ts diff --git a/lib/modules/datasource/api.ts b/lib/modules/datasource/api.ts index a9839f4f7a11de..73fcae31cda19c 100644 --- a/lib/modules/datasource/api.ts +++ b/lib/modules/datasource/api.ts @@ -6,6 +6,7 @@ import { AzurePipelinesTasksDatasource } from './azure-pipelines-tasks'; import { BazelDatasource } from './bazel'; import { BitbucketTagsDatasource } from './bitbucket-tags'; import { BitriseDatasource } from './bitrise'; +import { BuildpacksRegistryDatasource } from './buildpacks-registry'; import { CdnjsDatasource } from './cdnjs'; import { ClojureDatasource } from './clojure'; import { ConanDatasource } from './conan'; @@ -76,6 +77,7 @@ api.set(AzurePipelinesTasksDatasource.id, new AzurePipelinesTasksDatasource()); api.set(BazelDatasource.id, new BazelDatasource()); api.set(BitbucketTagsDatasource.id, new BitbucketTagsDatasource()); api.set(BitriseDatasource.id, new BitriseDatasource()); +api.set(BuildpacksRegistryDatasource.id, new BuildpacksRegistryDatasource()); api.set(CdnjsDatasource.id, new CdnjsDatasource()); api.set(ClojureDatasource.id, new ClojureDatasource()); api.set(ConanDatasource.id, new ConanDatasource()); diff --git a/lib/modules/datasource/buildpacks-registry/__fixtures__/heroku-python.json b/lib/modules/datasource/buildpacks-registry/__fixtures__/heroku-python.json new file mode 100644 index 00000000000000..7afbd41212f63b --- /dev/null +++ b/lib/modules/datasource/buildpacks-registry/__fixtures__/heroku-python.json @@ -0,0 +1 @@ +{"latest":{"version":"0.17.1","namespace":"heroku","name":"python","description":"Heroku's buildpack for Python applications.","homepage":"https://github.com/heroku/buildpacks-python","licenses":["BSD-3-Clause"],"stacks":["*"],"id":"75946bf8-3f6a-4af0-a757-614bebfdfcd6"},"versions":[{"version":"0.17.1","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.17.1"},{"version":"0.17.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.17.0"},{"version":"0.16.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.16.0"},{"version":"0.15.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.15.0"},{"version":"0.14.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.14.0"},{"version":"0.13.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.13.0"},{"version":"0.12.1","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.12.1"},{"version":"0.12.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.12.0"},{"version":"0.11.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.11.0"},{"version":"0.10.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.10.0"},{"version":"0.9.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.9.0"},{"version":"0.8.4","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.8.4"},{"version":"0.8.3","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.8.3"},{"version":"0.8.2","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.8.2"},{"version":"0.8.1","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.8.1"},{"version":"0.8.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.8.0"},{"version":"0.7.3","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.7.3"},{"version":"0.7.2","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.7.2"},{"version":"0.7.1","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.7.1"},{"version":"0.7.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.7.0"},{"version":"0.6.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.6.0"},{"version":"0.5.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.5.0"},{"version":"0.4.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.4.0"},{"version":"0.3.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.3.0"},{"version":"0.2.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.2.0"},{"version":"0.1.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.1.0"}]} \ No newline at end of file diff --git a/lib/modules/datasource/buildpacks-registry/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/buildpacks-registry/__snapshots__/index.spec.ts.snap new file mode 100644 index 00000000000000..10a3c2f0f5899f --- /dev/null +++ b/lib/modules/datasource/buildpacks-registry/__snapshots__/index.spec.ts.snap @@ -0,0 +1,88 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`modules/datasource/buildpacks-registry/index getReleases processes real data 1`] = ` +{ + "registryUrl": "https://registry.buildpacks.io/", + "releases": [ + { + "version": "0.1.0", + }, + { + "version": "0.2.0", + }, + { + "version": "0.3.0", + }, + { + "version": "0.4.0", + }, + { + "version": "0.5.0", + }, + { + "version": "0.6.0", + }, + { + "version": "0.7.0", + }, + { + "version": "0.7.1", + }, + { + "version": "0.7.2", + }, + { + "version": "0.7.3", + }, + { + "version": "0.8.0", + }, + { + "version": "0.8.1", + }, + { + "version": "0.8.2", + }, + { + "version": "0.8.3", + }, + { + "version": "0.8.4", + }, + { + "version": "0.9.0", + }, + { + "version": "0.10.0", + }, + { + "version": "0.11.0", + }, + { + "version": "0.12.0", + }, + { + "version": "0.12.1", + }, + { + "version": "0.13.0", + }, + { + "version": "0.14.0", + }, + { + "version": "0.15.0", + }, + { + "version": "0.16.0", + }, + { + "version": "0.17.0", + }, + { + "version": "0.17.1", + }, + ], + "sourceUrl": "https://github.com/heroku/buildpacks-python", +} +`; diff --git a/lib/modules/datasource/buildpacks-registry/index.spec.ts b/lib/modules/datasource/buildpacks-registry/index.spec.ts new file mode 100644 index 00000000000000..d20c9adb754a98 --- /dev/null +++ b/lib/modules/datasource/buildpacks-registry/index.spec.ts @@ -0,0 +1,22 @@ +import { getPkgReleases } from '..'; +import { Fixtures } from '../../../../test/fixtures'; +import * as httpMock from '../../../../test/http-mock'; +import { BuildpacksRegistryDatasource } from '.'; + +const baseUrl = 'https://registry.buildpacks.io/api/v1/buildpacks/'; + +describe('modules/datasource/buildpacks-registry/index', () => { + describe('getReleases', () => { + it('processes real data', async () => { + httpMock + .scope(baseUrl) + .get('/heroku/python') + .reply(200, Fixtures.get('heroku-python.json')); + const res = await getPkgReleases({ + datasource: BuildpacksRegistryDatasource.id, + packageName: 'heroku/python', + }); + expect(res).toMatchSnapshot(); + }); + }); +}); diff --git a/lib/modules/datasource/buildpacks-registry/index.ts b/lib/modules/datasource/buildpacks-registry/index.ts new file mode 100644 index 00000000000000..9a10af8d3efc45 --- /dev/null +++ b/lib/modules/datasource/buildpacks-registry/index.ts @@ -0,0 +1,59 @@ +import { ZodError } from 'zod'; +import { logger } from '../../../logger'; +import { Result } from '../../../util/result'; +import { Datasource } from '../datasource'; +import { ReleasesConfig } from '../schema'; +import type { GetReleasesConfig, Release, ReleaseResult } from '../types'; +import { BuildpacksRegistryResponseSchema } from './schema'; + +export class BuildpacksRegistryDatasource extends Datasource { + static readonly id = 'buildpacks-registry'; + + constructor() { + super(BuildpacksRegistryDatasource.id); + } + + override readonly customRegistrySupport = false; + + override readonly defaultRegistryUrls = ['https://registry.buildpacks.io/']; + + override readonly releaseTimestampSupport = true; + override readonly releaseTimestampNote = + 'The release timestamp is determined from the `published_at` field in the results.'; + override readonly sourceUrlSupport = 'release'; + override readonly sourceUrlNote = + 'The source URL is determined from the `source_code_url` field of the release object in the results.'; + + async getReleases(config: GetReleasesConfig): Promise { + const result = Result.parse(config, ReleasesConfig) + .transform(({ packageName, registryUrl }) => { + const url = `${registryUrl}api/v1/buildpacks/${packageName}`; + + return this.http.getJsonSafe(url, BuildpacksRegistryResponseSchema); + }) + .transform(({ versions, latest }): ReleaseResult => { + const releases: Release[] = versions; + + const res: ReleaseResult = { releases }; + + if (latest) { + res.homepage = latest.homepage; + } + + return res; + }); + + const { val, err } = await result.unwrap(); + + if (err instanceof ZodError) { + logger.debug({ err }, 'buildpacks: validation error'); + return null; + } + + if (err) { + this.handleGenericErrors(err); + } + + return val; + } +} diff --git a/lib/modules/datasource/buildpacks-registry/schema.spec.ts b/lib/modules/datasource/buildpacks-registry/schema.spec.ts new file mode 100644 index 00000000000000..d83eae1310fad0 --- /dev/null +++ b/lib/modules/datasource/buildpacks-registry/schema.spec.ts @@ -0,0 +1,59 @@ +import { BuildpacksRegistryResponseSchema } from './schema'; + +describe('modules/datasource/buildpacks-registry/schema', () => { + it('parses buildpack-registry schema', () => { + const response = { + latest: { + version: '0.17.1', + namespace: 'heroku', + name: 'python', + description: "Heroku's buildpack for Python applications.", + homepage: 'https://github.com/heroku/buildpacks-python', + licenses: ['BSD-3-Clause'], + stacks: ['*'], + id: '75946bf8-3f6a-4af0-a757-614bebfdfcd6', + }, + versions: [ + { + version: '0.4.0', + _link: + 'https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.4.0', + }, + { + version: '0.3.0', + _link: + 'https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.3.0', + }, + { + version: '0.2.0', + _link: + 'https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.2.0', + }, + { + version: '0.1.0', + _link: + 'https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.1.0', + }, + ], + }; + expect(BuildpacksRegistryResponseSchema.parse(response)).toMatchObject({ + latest: { + homepage: 'https://github.com/heroku/buildpacks-python', + }, + versions: [ + { + version: '0.4.0', + }, + { + version: '0.3.0', + }, + { + version: '0.2.0', + }, + { + version: '0.1.0', + }, + ], + }); + }); +}); diff --git a/lib/modules/datasource/buildpacks-registry/schema.ts b/lib/modules/datasource/buildpacks-registry/schema.ts new file mode 100644 index 00000000000000..a181f1c4da2c26 --- /dev/null +++ b/lib/modules/datasource/buildpacks-registry/schema.ts @@ -0,0 +1,15 @@ +import { z } from 'zod'; + +/** + * Response from registry.buildpacks.io + */ +export const BuildpacksRegistryResponseSchema = z.object({ + latest: z.object({ + homepage: z.string(), + }), + versions: z + .object({ + version: z.string(), + }) + .array(), +}); diff --git a/lib/modules/manager/buildpacks/extract.spec.ts b/lib/modules/manager/buildpacks/extract.spec.ts index dedcefcbd4f68a..0b59e2c7877db2 100644 --- a/lib/modules/manager/buildpacks/extract.spec.ts +++ b/lib/modules/manager/buildpacks/extract.spec.ts @@ -23,6 +23,7 @@ describe('modules/manager/buildpacks/extract', () => { [_] schema-version = "0.2" +# valid cases [io.buildpacks] builder = "registry.corp/builder/noble:1.1.1" @@ -36,16 +37,22 @@ uri = "buildpacks/nodejs:3.3.3" uri = "example/foo@1.0.0" [[io.buildpacks.group]] -uri = "example/registry-cnb" +uri = "urn:cnb:registry:example/bar@1.2.3" [[io.buildpacks.group]] -uri = "urn:cnb:registry:example/foo@1.0.0" +uri = "cnbs/some-bp@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" [[io.buildpacks.group]] -uri = "some-bp@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" +uri = "cnbs/some-bp:some-tag@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" [[io.buildpacks.group]] -uri = "cnbs/some-bp:some-tag@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" +id = "example/tee" +version = "2.3.4" + +#invalid cases + +[[io.buildpacks.group]] +uri = "example/registry-cnb" [[io.buildpacks.group]] uri = "from=builder:foobar" @@ -54,10 +61,14 @@ uri = "from=builder:foobar" uri = "file://local.oci" [[io.buildpacks.group]] -uri = "foo://fake.oci"`, +uri = "foo://fake.oci" + +[[io.buildpacks.group]] +id = "not/valid"`, 'project.toml', {}, ); + expect(res?.deps).toHaveLength(8); expect(res?.deps).toEqual([ { autoReplaceStringTemplate: @@ -84,15 +95,27 @@ uri = "foo://fake.oci"`, depName: 'buildpacks/nodejs', replaceString: 'buildpacks/nodejs:3.3.3', }, + { + datasource: 'buildpacks-registry', + currentValue: '1.0.0', + packageName: 'example/foo', + replaceString: 'urn:cnb:registry:example/foo@1.0.0', + }, + { + datasource: 'buildpacks-registry', + currentValue: '1.2.3', + packageName: 'example/bar', + replaceString: 'urn:cnb:registry:example/bar@1.2.3', + }, { autoReplaceStringTemplate: '{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}', currentDigest: 'sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef', datasource: 'docker', - depName: 'some-bp', + depName: 'cnbs/some-bp', replaceString: - 'some-bp@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef', + 'cnbs/some-bp@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef', }, { autoReplaceStringTemplate: @@ -105,6 +128,12 @@ uri = "foo://fake.oci"`, replaceString: 'cnbs/some-bp:some-tag@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef', }, + { + datasource: 'buildpacks-registry', + currentValue: '2.3.4', + packageName: 'example/tee', + replaceString: '2.3.4', + }, ]); }); }); diff --git a/lib/modules/manager/buildpacks/extract.ts b/lib/modules/manager/buildpacks/extract.ts index c00d4a4c681e19..e74fbece2458ea 100644 --- a/lib/modules/manager/buildpacks/extract.ts +++ b/lib/modules/manager/buildpacks/extract.ts @@ -2,12 +2,19 @@ import is from '@sindresorhus/is'; import { logger } from '../../../logger'; import { regEx } from '../../../util/regex'; import { getDep } from '../dockerfile/extract'; +import { isVersion } from '../../versioning/semver'; import type { ExtractConfig, PackageDependency, PackageFileContent, } from '../types'; -import { type ProjectDescriptor, ProjectDescriptorToml } from './schema'; +import { + type ProjectDescriptor, + ProjectDescriptorToml, + isBuildpackByName, + isBuildpackByURI, +} from './schema'; +import { BuildpacksRegistryDatasource } from '../../datasource/buildpacks-registry'; const dockerPrefix = regEx(/^docker:\/?\//); const dockerRef = regEx( @@ -20,6 +27,27 @@ function isDockerRef(ref: string): boolean { } return false; } +const buildpackRegistryPrefix = regEx(/^urn:cnb:registry:/) +const buildpackRegistryId = regEx( + /^[a-z0-9\-.]+\/[a-z0-9\-.]+(?:@(?.+))?$/, +); + +function isBuildpackRegistryId(ref: string | undefined): boolean { + if (ref === undefined) { + return false; + } + const bpRegistryMatch = buildpackRegistryId.exec(ref); + if (!bpRegistryMatch) { + return false; + } else if (!bpRegistryMatch.groups?.version) { + return true; + } + return isVersion(bpRegistryMatch.groups.version); +} + +function isBuildpackRegistryRef(ref: string): boolean { + return isBuildpackRegistryId(ref) || ref.startsWith('urn:cnb:registry:'); +} function parseProjectToml( content: string, @@ -49,7 +77,7 @@ export function extractPackageFile( if (!descriptor) { return null; } - + if ( descriptor.io?.buildpacks?.builder && isDockerRef(descriptor.io.buildpacks.builder) @@ -67,16 +95,16 @@ export function extractPackageFile( }, '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)) { + if (isBuildpackByURI(group) && isDockerRef(group.uri)) { const dep = getDep( group.uri.replace(dockerPrefix, ''), true, @@ -90,8 +118,33 @@ export function extractPackageFile( }, 'Cloud Native Buildpack', ); - + deps.push(dep); + } else if (isBuildpackByURI(group) && isBuildpackRegistryRef(group.uri)) { + const dependency = group.uri.replace(buildpackRegistryPrefix, '') + + if(dependency.includes('@')) { + const version = dependency.split('@')[1] + const dep: PackageDependency = { + datasource: BuildpacksRegistryDatasource.id, + currentValue: version, + packageName: dependency.split('@')[0], + replaceString: `urn:cnb:registry:${dependency}`, + }; + deps.push(dep); + } + } else if (isBuildpackByName(group)) { + const version = group.version; + + if (version) { + const dep: PackageDependency = { + datasource: BuildpacksRegistryDatasource.id, + currentValue: version, + packageName: group.id, + replaceString: `${version}`, + }; + deps.push(dep); + } } } } diff --git a/lib/modules/manager/buildpacks/index.ts b/lib/modules/manager/buildpacks/index.ts index 53a3dcfeb4c221..869bcd7252b86c 100644 --- a/lib/modules/manager/buildpacks/index.ts +++ b/lib/modules/manager/buildpacks/index.ts @@ -1,4 +1,5 @@ import type { Category } from '../../../constants'; +import { BuildpacksRegistryDatasource } from '../../datasource/buildpacks-registry'; import { DockerDatasource } from '../../datasource/docker'; export { extractPackageFile } from './extract'; @@ -8,5 +9,8 @@ export const defaultConfig = { pinDigests: false, }; -export const categories: Category[] = ['docker']; -export const supportedDatasources = [DockerDatasource.id]; +export const categories: Category[] = ['docker', 'ci', 'cd']; +export const supportedDatasources = [ + DockerDatasource.id, + BuildpacksRegistryDatasource.id, +]; diff --git a/lib/modules/manager/buildpacks/readme.md b/lib/modules/manager/buildpacks/readme.md index d2f7b6c613968a..7bb081f9b0d02a 100644 --- a/lib/modules/manager/buildpacks/readme.md +++ b/lib/modules/manager/buildpacks/readme.md @@ -6,7 +6,7 @@ Renovate can update a `project.toml` file if: - 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. +__Note__: 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" [_] diff --git a/lib/modules/manager/buildpacks/schema.ts b/lib/modules/manager/buildpacks/schema.ts index dc90371ca4ce93..938f2cffef0fbe 100644 --- a/lib/modules/manager/buildpacks/schema.ts +++ b/lib/modules/manager/buildpacks/schema.ts @@ -1,10 +1,33 @@ import { z } from 'zod'; import { Toml } from '../../../util/schema-utils'; -const BuildpackGroup = z.object({ - uri: z.string().optional(), +const BuildpackByName = z.object({ + id: z.string(), + version: z.string().optional(), }); +const BuildpackByURI = z.object({ + uri: z.string(), +}); + +const BuildpackGroup = BuildpackByName.or(BuildpackByURI); + +type BuildpackByNameType = z.infer; +type BuildpackByURIType = z.infer; +type BuildpackGroupType = z.infer; + +export function isBuildpackByName( + group: BuildpackGroupType, +): group is BuildpackByNameType { + return 'id' in group; +} + +export function isBuildpackByURI( + group: BuildpackGroupType, +): group is BuildpackByURIType { + return 'uri' in group; +} + const IoBuildpacks = z.object({ builder: z.string().optional(), group: z.array(BuildpackGroup).optional(), @@ -22,4 +45,4 @@ export const ProjectDescriptor = z.object({ }); export type ProjectDescriptor = z.infer; -export const ProjectDescriptorToml = Toml.pipe(ProjectDescriptor); +export const ProjectDescriptorToml = Toml.pipe(ProjectDescriptor); \ No newline at end of file From 3b4430da9abccc0f31b7d71bc1535bf1f4efa5cd Mon Sep 17 00:00:00 2001 From: Ralf Pannemans Date: Tue, 26 Nov 2024 15:20:46 +0100 Subject: [PATCH 02/13] Fix replaceString for buildpack-registry prefix --- lib/modules/manager/buildpacks/extract.spec.ts | 4 ++-- lib/modules/manager/buildpacks/extract.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/modules/manager/buildpacks/extract.spec.ts b/lib/modules/manager/buildpacks/extract.spec.ts index 0b59e2c7877db2..0668f6c4ecf4ed 100644 --- a/lib/modules/manager/buildpacks/extract.spec.ts +++ b/lib/modules/manager/buildpacks/extract.spec.ts @@ -99,13 +99,13 @@ id = "not/valid"`, datasource: 'buildpacks-registry', currentValue: '1.0.0', packageName: 'example/foo', - replaceString: 'urn:cnb:registry:example/foo@1.0.0', + replaceString: 'example/foo@1.0.0', }, { datasource: 'buildpacks-registry', currentValue: '1.2.3', packageName: 'example/bar', - replaceString: 'urn:cnb:registry:example/bar@1.2.3', + replaceString: 'example/bar@1.2.3', }, { autoReplaceStringTemplate: diff --git a/lib/modules/manager/buildpacks/extract.ts b/lib/modules/manager/buildpacks/extract.ts index e74fbece2458ea..27096abb5b11bc 100644 --- a/lib/modules/manager/buildpacks/extract.ts +++ b/lib/modules/manager/buildpacks/extract.ts @@ -129,7 +129,7 @@ export function extractPackageFile( datasource: BuildpacksRegistryDatasource.id, currentValue: version, packageName: dependency.split('@')[0], - replaceString: `urn:cnb:registry:${dependency}`, + replaceString: `${dependency}`, }; deps.push(dep); } From 11b1b398813fb627dccaa0c2c114ccdd700e9ea9 Mon Sep 17 00:00:00 2001 From: Ralf Pannemans Date: Tue, 26 Nov 2024 17:04:09 +0100 Subject: [PATCH 03/13] Fix reviewed suggestions --- .../__fixtures__/heroku-python.json | 2 +- .../__snapshots__/index.spec.ts.snap | 88 ------------------- .../buildpacks-registry/index.spec.ts | 14 ++- .../datasource/buildpacks-registry/index.ts | 8 +- .../datasource/buildpacks-registry/schema.ts | 4 +- 5 files changed, 23 insertions(+), 93 deletions(-) delete mode 100644 lib/modules/datasource/buildpacks-registry/__snapshots__/index.spec.ts.snap diff --git a/lib/modules/datasource/buildpacks-registry/__fixtures__/heroku-python.json b/lib/modules/datasource/buildpacks-registry/__fixtures__/heroku-python.json index 7afbd41212f63b..99481b81f5bc30 100644 --- a/lib/modules/datasource/buildpacks-registry/__fixtures__/heroku-python.json +++ b/lib/modules/datasource/buildpacks-registry/__fixtures__/heroku-python.json @@ -1 +1 @@ -{"latest":{"version":"0.17.1","namespace":"heroku","name":"python","description":"Heroku's buildpack for Python applications.","homepage":"https://github.com/heroku/buildpacks-python","licenses":["BSD-3-Clause"],"stacks":["*"],"id":"75946bf8-3f6a-4af0-a757-614bebfdfcd6"},"versions":[{"version":"0.17.1","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.17.1"},{"version":"0.17.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.17.0"},{"version":"0.16.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.16.0"},{"version":"0.15.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.15.0"},{"version":"0.14.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.14.0"},{"version":"0.13.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.13.0"},{"version":"0.12.1","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.12.1"},{"version":"0.12.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.12.0"},{"version":"0.11.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.11.0"},{"version":"0.10.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.10.0"},{"version":"0.9.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.9.0"},{"version":"0.8.4","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.8.4"},{"version":"0.8.3","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.8.3"},{"version":"0.8.2","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.8.2"},{"version":"0.8.1","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.8.1"},{"version":"0.8.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.8.0"},{"version":"0.7.3","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.7.3"},{"version":"0.7.2","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.7.2"},{"version":"0.7.1","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.7.1"},{"version":"0.7.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.7.0"},{"version":"0.6.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.6.0"},{"version":"0.5.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.5.0"},{"version":"0.4.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.4.0"},{"version":"0.3.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.3.0"},{"version":"0.2.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.2.0"},{"version":"0.1.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.1.0"}]} \ No newline at end of file +{"latest":{"version":"0.17.1","namespace":"heroku","name":"python","description":"Heroku's buildpack for Python applications.","homepage":"https://github.com/heroku/buildpacks-python","licenses":["BSD-3-Clause"],"stacks":["*"],"id":"75946bf8-3f6a-4af0-a757-614bebfdfcd6"},"versions":[{"version":"0.17.1","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.17.1"},{"version":"0.17.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.17.0"}]} \ No newline at end of file diff --git a/lib/modules/datasource/buildpacks-registry/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/buildpacks-registry/__snapshots__/index.spec.ts.snap deleted file mode 100644 index 10a3c2f0f5899f..00000000000000 --- a/lib/modules/datasource/buildpacks-registry/__snapshots__/index.spec.ts.snap +++ /dev/null @@ -1,88 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`modules/datasource/buildpacks-registry/index getReleases processes real data 1`] = ` -{ - "registryUrl": "https://registry.buildpacks.io/", - "releases": [ - { - "version": "0.1.0", - }, - { - "version": "0.2.0", - }, - { - "version": "0.3.0", - }, - { - "version": "0.4.0", - }, - { - "version": "0.5.0", - }, - { - "version": "0.6.0", - }, - { - "version": "0.7.0", - }, - { - "version": "0.7.1", - }, - { - "version": "0.7.2", - }, - { - "version": "0.7.3", - }, - { - "version": "0.8.0", - }, - { - "version": "0.8.1", - }, - { - "version": "0.8.2", - }, - { - "version": "0.8.3", - }, - { - "version": "0.8.4", - }, - { - "version": "0.9.0", - }, - { - "version": "0.10.0", - }, - { - "version": "0.11.0", - }, - { - "version": "0.12.0", - }, - { - "version": "0.12.1", - }, - { - "version": "0.13.0", - }, - { - "version": "0.14.0", - }, - { - "version": "0.15.0", - }, - { - "version": "0.16.0", - }, - { - "version": "0.17.0", - }, - { - "version": "0.17.1", - }, - ], - "sourceUrl": "https://github.com/heroku/buildpacks-python", -} -`; diff --git a/lib/modules/datasource/buildpacks-registry/index.spec.ts b/lib/modules/datasource/buildpacks-registry/index.spec.ts index d20c9adb754a98..5da5f389514521 100644 --- a/lib/modules/datasource/buildpacks-registry/index.spec.ts +++ b/lib/modules/datasource/buildpacks-registry/index.spec.ts @@ -16,7 +16,19 @@ describe('modules/datasource/buildpacks-registry/index', () => { datasource: BuildpacksRegistryDatasource.id, packageName: 'heroku/python', }); - expect(res).toMatchSnapshot(); + const expectedResponse = { + registryUrl: "https://registry.buildpacks.io/", + releases: [ + { + "version": "0.17.0", + }, + { + "version": "0.17.1", + }, + ], + sourceUrl: "https://github.com/heroku/buildpacks-python", + }; + expect(res).toEqual(expectedResponse); }); }); }); diff --git a/lib/modules/datasource/buildpacks-registry/index.ts b/lib/modules/datasource/buildpacks-registry/index.ts index 9a10af8d3efc45..28663a22562833 100644 --- a/lib/modules/datasource/buildpacks-registry/index.ts +++ b/lib/modules/datasource/buildpacks-registry/index.ts @@ -5,6 +5,7 @@ import { Datasource } from '../datasource'; import { ReleasesConfig } from '../schema'; import type { GetReleasesConfig, Release, ReleaseResult } from '../types'; import { BuildpacksRegistryResponseSchema } from './schema'; +import { cache } from '../../../util/cache/package/decorator'; export class BuildpacksRegistryDatasource extends Datasource { static readonly id = 'buildpacks-registry'; @@ -24,6 +25,11 @@ export class BuildpacksRegistryDatasource extends Datasource { override readonly sourceUrlNote = 'The source URL is determined from the `source_code_url` field of the release object in the results.'; + @cache({ + namespace: `datasource-${BuildpacksRegistryDatasource.id}`, + key: ({ registryUrl, packageName }: GetReleasesConfig) => + `${registryUrl}:${packageName}`, + }) async getReleases(config: GetReleasesConfig): Promise { const result = Result.parse(config, ReleasesConfig) .transform(({ packageName, registryUrl }) => { @@ -36,7 +42,7 @@ export class BuildpacksRegistryDatasource extends Datasource { const res: ReleaseResult = { releases }; - if (latest) { + if (latest?.homepage) { res.homepage = latest.homepage; } diff --git a/lib/modules/datasource/buildpacks-registry/schema.ts b/lib/modules/datasource/buildpacks-registry/schema.ts index a181f1c4da2c26..339cdd88ab3247 100644 --- a/lib/modules/datasource/buildpacks-registry/schema.ts +++ b/lib/modules/datasource/buildpacks-registry/schema.ts @@ -5,8 +5,8 @@ import { z } from 'zod'; */ export const BuildpacksRegistryResponseSchema = z.object({ latest: z.object({ - homepage: z.string(), - }), + homepage: z.string().optional(), + }).optional(), versions: z .object({ version: z.string(), From 8bcf76cc4f650d15eb822930436c6753413c71d2 Mon Sep 17 00:00:00 2001 From: Ralf Pannemans Date: Thu, 28 Nov 2024 10:52:10 +0100 Subject: [PATCH 04/13] Fix linter and prettier errors --- .../__fixtures__/heroku-python.json | 1 - .../buildpacks-registry/index.spec.ts | 25 ++++++++----------- .../datasource/buildpacks-registry/index.ts | 2 +- .../datasource/buildpacks-registry/schema.ts | 8 +++--- lib/modules/manager/buildpacks/extract.ts | 22 ++++++++-------- lib/modules/manager/buildpacks/readme.md | 2 +- lib/modules/manager/buildpacks/schema.ts | 2 +- lib/util/cache/package/types.ts | 1 + 8 files changed, 31 insertions(+), 32 deletions(-) delete mode 100644 lib/modules/datasource/buildpacks-registry/__fixtures__/heroku-python.json diff --git a/lib/modules/datasource/buildpacks-registry/__fixtures__/heroku-python.json b/lib/modules/datasource/buildpacks-registry/__fixtures__/heroku-python.json deleted file mode 100644 index 99481b81f5bc30..00000000000000 --- a/lib/modules/datasource/buildpacks-registry/__fixtures__/heroku-python.json +++ /dev/null @@ -1 +0,0 @@ -{"latest":{"version":"0.17.1","namespace":"heroku","name":"python","description":"Heroku's buildpack for Python applications.","homepage":"https://github.com/heroku/buildpacks-python","licenses":["BSD-3-Clause"],"stacks":["*"],"id":"75946bf8-3f6a-4af0-a757-614bebfdfcd6"},"versions":[{"version":"0.17.1","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.17.1"},{"version":"0.17.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.17.0"}]} \ No newline at end of file diff --git a/lib/modules/datasource/buildpacks-registry/index.spec.ts b/lib/modules/datasource/buildpacks-registry/index.spec.ts index 5da5f389514521..65aaf8d36597bc 100644 --- a/lib/modules/datasource/buildpacks-registry/index.spec.ts +++ b/lib/modules/datasource/buildpacks-registry/index.spec.ts @@ -1,33 +1,30 @@ import { getPkgReleases } from '..'; -import { Fixtures } from '../../../../test/fixtures'; import * as httpMock from '../../../../test/http-mock'; import { BuildpacksRegistryDatasource } from '.'; const baseUrl = 'https://registry.buildpacks.io/api/v1/buildpacks/'; +const herokuJSON = `{"latest":{"version":"0.17.1","namespace":"heroku","name":"python","description":"Heroku's buildpack for Python applications.","homepage":"https://github.com/heroku/buildpacks-python","licenses":["BSD-3-Clause"],"stacks":["*"],"id":"75946bf8-3f6a-4af0-a757-614bebfdfcd6"},"versions":[{"version":"0.17.1","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.17.1"},{"version":"0.17.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.17.0"}]}`; describe('modules/datasource/buildpacks-registry/index', () => { describe('getReleases', () => { it('processes real data', async () => { - httpMock - .scope(baseUrl) - .get('/heroku/python') - .reply(200, Fixtures.get('heroku-python.json')); + httpMock.scope(baseUrl).get('/heroku/python').reply(200, herokuJSON); const res = await getPkgReleases({ datasource: BuildpacksRegistryDatasource.id, packageName: 'heroku/python', }); const expectedResponse = { - registryUrl: "https://registry.buildpacks.io/", + registryUrl: 'https://registry.buildpacks.io/', releases: [ - { - "version": "0.17.0", - }, - { - "version": "0.17.1", - }, + { + version: '0.17.0', + }, + { + version: '0.17.1', + }, ], - sourceUrl: "https://github.com/heroku/buildpacks-python", - }; + sourceUrl: 'https://github.com/heroku/buildpacks-python', + }; expect(res).toEqual(expectedResponse); }); }); diff --git a/lib/modules/datasource/buildpacks-registry/index.ts b/lib/modules/datasource/buildpacks-registry/index.ts index 28663a22562833..2c3fefeb88f921 100644 --- a/lib/modules/datasource/buildpacks-registry/index.ts +++ b/lib/modules/datasource/buildpacks-registry/index.ts @@ -1,11 +1,11 @@ import { ZodError } from 'zod'; import { logger } from '../../../logger'; +import { cache } from '../../../util/cache/package/decorator'; import { Result } from '../../../util/result'; import { Datasource } from '../datasource'; import { ReleasesConfig } from '../schema'; import type { GetReleasesConfig, Release, ReleaseResult } from '../types'; import { BuildpacksRegistryResponseSchema } from './schema'; -import { cache } from '../../../util/cache/package/decorator'; export class BuildpacksRegistryDatasource extends Datasource { static readonly id = 'buildpacks-registry'; diff --git a/lib/modules/datasource/buildpacks-registry/schema.ts b/lib/modules/datasource/buildpacks-registry/schema.ts index 339cdd88ab3247..6bc544196380ea 100644 --- a/lib/modules/datasource/buildpacks-registry/schema.ts +++ b/lib/modules/datasource/buildpacks-registry/schema.ts @@ -4,9 +4,11 @@ import { z } from 'zod'; * Response from registry.buildpacks.io */ export const BuildpacksRegistryResponseSchema = z.object({ - latest: z.object({ - homepage: z.string().optional(), - }).optional(), + latest: z + .object({ + homepage: z.string().optional(), + }) + .optional(), versions: z .object({ version: z.string(), diff --git a/lib/modules/manager/buildpacks/extract.ts b/lib/modules/manager/buildpacks/extract.ts index 27096abb5b11bc..1dcc204ad05338 100644 --- a/lib/modules/manager/buildpacks/extract.ts +++ b/lib/modules/manager/buildpacks/extract.ts @@ -1,8 +1,9 @@ import is from '@sindresorhus/is'; import { logger } from '../../../logger'; import { regEx } from '../../../util/regex'; -import { getDep } from '../dockerfile/extract'; +import { BuildpacksRegistryDatasource } from '../../datasource/buildpacks-registry'; import { isVersion } from '../../versioning/semver'; +import { getDep } from '../dockerfile/extract'; import type { ExtractConfig, PackageDependency, @@ -14,7 +15,6 @@ import { isBuildpackByName, isBuildpackByURI, } from './schema'; -import { BuildpacksRegistryDatasource } from '../../datasource/buildpacks-registry'; const dockerPrefix = regEx(/^docker:\/?\//); const dockerRef = regEx( @@ -27,7 +27,7 @@ function isDockerRef(ref: string): boolean { } return false; } -const buildpackRegistryPrefix = regEx(/^urn:cnb:registry:/) +const buildpackRegistryPrefix = regEx(/^urn:cnb:registry:/); const buildpackRegistryId = regEx( /^[a-z0-9\-.]+\/[a-z0-9\-.]+(?:@(?.+))?$/, ); @@ -77,7 +77,7 @@ export function extractPackageFile( if (!descriptor) { return null; } - + if ( descriptor.io?.buildpacks?.builder && isDockerRef(descriptor.io.buildpacks.builder) @@ -95,10 +95,10 @@ export function extractPackageFile( }, 'Cloud Native Buildpacks builder', ); - + deps.push({ ...dep, commitMessageTopic: 'builder {{depName}}' }); } - + if ( descriptor.io?.buildpacks?.group && is.array(descriptor.io.buildpacks.group) @@ -118,13 +118,13 @@ export function extractPackageFile( }, 'Cloud Native Buildpack', ); - + deps.push(dep); } else if (isBuildpackByURI(group) && isBuildpackRegistryRef(group.uri)) { - const dependency = group.uri.replace(buildpackRegistryPrefix, '') - - if(dependency.includes('@')) { - const version = dependency.split('@')[1] + const dependency = group.uri.replace(buildpackRegistryPrefix, ''); + + if (dependency.includes('@')) { + const version = dependency.split('@')[1]; const dep: PackageDependency = { datasource: BuildpacksRegistryDatasource.id, currentValue: version, diff --git a/lib/modules/manager/buildpacks/readme.md b/lib/modules/manager/buildpacks/readme.md index 7bb081f9b0d02a..b25340bffc2431 100644 --- a/lib/modules/manager/buildpacks/readme.md +++ b/lib/modules/manager/buildpacks/readme.md @@ -6,7 +6,7 @@ Renovate can update a `project.toml` file if: - 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) -__Note__: If you use buildpacks in the `io.buildpacks.group` array, then you _must_ configure the Docker reference (`uri`) for Renovate to work. +**Note**: 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" [_] diff --git a/lib/modules/manager/buildpacks/schema.ts b/lib/modules/manager/buildpacks/schema.ts index 938f2cffef0fbe..746d96914e7cad 100644 --- a/lib/modules/manager/buildpacks/schema.ts +++ b/lib/modules/manager/buildpacks/schema.ts @@ -45,4 +45,4 @@ export const ProjectDescriptor = z.object({ }); export type ProjectDescriptor = z.infer; -export const ProjectDescriptorToml = Toml.pipe(ProjectDescriptor); \ No newline at end of file +export const ProjectDescriptorToml = Toml.pipe(ProjectDescriptor); diff --git a/lib/util/cache/package/types.ts b/lib/util/cache/package/types.ts index 7435f8bc787301..afc974de9f4919 100644 --- a/lib/util/cache/package/types.ts +++ b/lib/util/cache/package/types.ts @@ -34,6 +34,7 @@ export type PackageCacheNamespace = | 'datasource-bazel' | 'datasource-bitbucket-tags' | 'datasource-bitrise' + | 'datasource-buildpacks-registry' | 'datasource-cdnjs' | 'datasource-conan' | 'datasource-conda' From 489a2abc42456e54a63fa5136d0c802801551d65 Mon Sep 17 00:00:00 2001 From: Nicolas Bender Date: Thu, 28 Nov 2024 15:32:35 +0100 Subject: [PATCH 05/13] Fix test coverage --- .../buildpacks-registry/index.spec.ts | 17 +++++++++++++++++ lib/modules/manager/buildpacks/extract.ts | 5 +---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/lib/modules/datasource/buildpacks-registry/index.spec.ts b/lib/modules/datasource/buildpacks-registry/index.spec.ts index 65aaf8d36597bc..222025d854b28f 100644 --- a/lib/modules/datasource/buildpacks-registry/index.spec.ts +++ b/lib/modules/datasource/buildpacks-registry/index.spec.ts @@ -4,6 +4,7 @@ import { BuildpacksRegistryDatasource } from '.'; const baseUrl = 'https://registry.buildpacks.io/api/v1/buildpacks/'; const herokuJSON = `{"latest":{"version":"0.17.1","namespace":"heroku","name":"python","description":"Heroku's buildpack for Python applications.","homepage":"https://github.com/heroku/buildpacks-python","licenses":["BSD-3-Clause"],"stacks":["*"],"id":"75946bf8-3f6a-4af0-a757-614bebfdfcd6"},"versions":[{"version":"0.17.1","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.17.1"},{"version":"0.17.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.17.0"}]}`; +const invalidResult = `{}` describe('modules/datasource/buildpacks-registry/index', () => { describe('getReleases', () => { @@ -27,5 +28,21 @@ describe('modules/datasource/buildpacks-registry/index', () => { }; expect(res).toEqual(expectedResponse); }); + it('returns null on empty result', async () => { + httpMock.scope(baseUrl).get('/heroku/empty').reply(200, invalidResult); + const res = await getPkgReleases({ + datasource: BuildpacksRegistryDatasource.id, + packageName: 'heroku/empty', + }); + expect(res).toBeNull(); + }); + it('handles not found', async () => { + httpMock.scope(baseUrl).get('/heroku/notexisting').reply(404); + const res = await getPkgReleases({ + datasource: BuildpacksRegistryDatasource.id, + packageName: 'heroku/notexisting', + }); + expect(res).toBeNull(); + }); }); }); diff --git a/lib/modules/manager/buildpacks/extract.ts b/lib/modules/manager/buildpacks/extract.ts index 1dcc204ad05338..0d5ca6f4d64a53 100644 --- a/lib/modules/manager/buildpacks/extract.ts +++ b/lib/modules/manager/buildpacks/extract.ts @@ -32,10 +32,7 @@ const buildpackRegistryId = regEx( /^[a-z0-9\-.]+\/[a-z0-9\-.]+(?:@(?.+))?$/, ); -function isBuildpackRegistryId(ref: string | undefined): boolean { - if (ref === undefined) { - return false; - } +function isBuildpackRegistryId(ref: string): boolean { const bpRegistryMatch = buildpackRegistryId.exec(ref); if (!bpRegistryMatch) { return false; From ccc40c165696f1cdb7683ed73fc0b97ffd572fc8 Mon Sep 17 00:00:00 2001 From: Ralf Pannemans Date: Fri, 29 Nov 2024 08:52:06 +0100 Subject: [PATCH 06/13] Some minor code style changes --- .../datasource/buildpacks-registry/index.spec.ts | 10 ++++++---- .../datasource/buildpacks-registry/index.ts | 3 ++- .../buildpacks-registry/schema.spec.ts | 16 ---------------- lib/modules/manager/buildpacks/extract.spec.ts | 1 - lib/modules/manager/buildpacks/extract.ts | 4 ++-- lib/modules/manager/buildpacks/schema.ts | 14 +++++++------- 6 files changed, 17 insertions(+), 31 deletions(-) diff --git a/lib/modules/datasource/buildpacks-registry/index.spec.ts b/lib/modules/datasource/buildpacks-registry/index.spec.ts index 222025d854b28f..393ea9fdee9ca5 100644 --- a/lib/modules/datasource/buildpacks-registry/index.spec.ts +++ b/lib/modules/datasource/buildpacks-registry/index.spec.ts @@ -3,13 +3,13 @@ import * as httpMock from '../../../../test/http-mock'; import { BuildpacksRegistryDatasource } from '.'; const baseUrl = 'https://registry.buildpacks.io/api/v1/buildpacks/'; -const herokuJSON = `{"latest":{"version":"0.17.1","namespace":"heroku","name":"python","description":"Heroku's buildpack for Python applications.","homepage":"https://github.com/heroku/buildpacks-python","licenses":["BSD-3-Clause"],"stacks":["*"],"id":"75946bf8-3f6a-4af0-a757-614bebfdfcd6"},"versions":[{"version":"0.17.1","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.17.1"},{"version":"0.17.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.17.0"}]}`; -const invalidResult = `{}` +const herokuResult = {"latest":{"version":"0.17.1","namespace":"heroku","name":"python","description":"Heroku's buildpack for Python applications.","homepage":"https://github.com/heroku/buildpacks-python","licenses":["BSD-3-Clause"],"stacks":["*"],"id":"75946bf8-3f6a-4af0-a757-614bebfdfcd6"},"versions":[{"version":"0.17.1","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.17.1"},{"version":"0.17.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.17.0"}]}; +const emptResult = {} describe('modules/datasource/buildpacks-registry/index', () => { describe('getReleases', () => { it('processes real data', async () => { - httpMock.scope(baseUrl).get('/heroku/python').reply(200, herokuJSON); + httpMock.scope(baseUrl).get('/heroku/python').reply(200, herokuResult); const res = await getPkgReleases({ datasource: BuildpacksRegistryDatasource.id, packageName: 'heroku/python', @@ -28,14 +28,16 @@ describe('modules/datasource/buildpacks-registry/index', () => { }; expect(res).toEqual(expectedResponse); }); + it('returns null on empty result', async () => { - httpMock.scope(baseUrl).get('/heroku/empty').reply(200, invalidResult); + httpMock.scope(baseUrl).get('/heroku/empty').reply(200, emptResult); const res = await getPkgReleases({ datasource: BuildpacksRegistryDatasource.id, packageName: 'heroku/empty', }); expect(res).toBeNull(); }); + it('handles not found', async () => { httpMock.scope(baseUrl).get('/heroku/notexisting').reply(404); const res = await getPkgReleases({ diff --git a/lib/modules/datasource/buildpacks-registry/index.ts b/lib/modules/datasource/buildpacks-registry/index.ts index 2c3fefeb88f921..8e4cbff17c0507 100644 --- a/lib/modules/datasource/buildpacks-registry/index.ts +++ b/lib/modules/datasource/buildpacks-registry/index.ts @@ -6,6 +6,7 @@ import { Datasource } from '../datasource'; import { ReleasesConfig } from '../schema'; import type { GetReleasesConfig, Release, ReleaseResult } from '../types'; import { BuildpacksRegistryResponseSchema } from './schema'; +import urlJoin from 'url-join'; export class BuildpacksRegistryDatasource extends Datasource { static readonly id = 'buildpacks-registry'; @@ -33,7 +34,7 @@ export class BuildpacksRegistryDatasource extends Datasource { async getReleases(config: GetReleasesConfig): Promise { const result = Result.parse(config, ReleasesConfig) .transform(({ packageName, registryUrl }) => { - const url = `${registryUrl}api/v1/buildpacks/${packageName}`; + const url = urlJoin(registryUrl, 'api', 'v1', 'buildpacks', packageName); return this.http.getJsonSafe(url, BuildpacksRegistryResponseSchema); }) diff --git a/lib/modules/datasource/buildpacks-registry/schema.spec.ts b/lib/modules/datasource/buildpacks-registry/schema.spec.ts index d83eae1310fad0..a46bd3998fe8fe 100644 --- a/lib/modules/datasource/buildpacks-registry/schema.spec.ts +++ b/lib/modules/datasource/buildpacks-registry/schema.spec.ts @@ -14,16 +14,6 @@ describe('modules/datasource/buildpacks-registry/schema', () => { id: '75946bf8-3f6a-4af0-a757-614bebfdfcd6', }, versions: [ - { - version: '0.4.0', - _link: - 'https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.4.0', - }, - { - version: '0.3.0', - _link: - 'https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.3.0', - }, { version: '0.2.0', _link: @@ -41,12 +31,6 @@ describe('modules/datasource/buildpacks-registry/schema', () => { homepage: 'https://github.com/heroku/buildpacks-python', }, versions: [ - { - version: '0.4.0', - }, - { - version: '0.3.0', - }, { version: '0.2.0', }, diff --git a/lib/modules/manager/buildpacks/extract.spec.ts b/lib/modules/manager/buildpacks/extract.spec.ts index 0668f6c4ecf4ed..0da53e92354b07 100644 --- a/lib/modules/manager/buildpacks/extract.spec.ts +++ b/lib/modules/manager/buildpacks/extract.spec.ts @@ -68,7 +68,6 @@ id = "not/valid"`, 'project.toml', {}, ); - expect(res?.deps).toHaveLength(8); expect(res?.deps).toEqual([ { autoReplaceStringTemplate: diff --git a/lib/modules/manager/buildpacks/extract.ts b/lib/modules/manager/buildpacks/extract.ts index 0d5ca6f4d64a53..bd820cd01eeb5b 100644 --- a/lib/modules/manager/buildpacks/extract.ts +++ b/lib/modules/manager/buildpacks/extract.ts @@ -27,7 +27,7 @@ function isDockerRef(ref: string): boolean { } return false; } -const buildpackRegistryPrefix = regEx(/^urn:cnb:registry:/); +const buildpackRegistryPrefix = 'urn:cnb:registry:'; const buildpackRegistryId = regEx( /^[a-z0-9\-.]+\/[a-z0-9\-.]+(?:@(?.+))?$/, ); @@ -43,7 +43,7 @@ function isBuildpackRegistryId(ref: string): boolean { } function isBuildpackRegistryRef(ref: string): boolean { - return isBuildpackRegistryId(ref) || ref.startsWith('urn:cnb:registry:'); + return isBuildpackRegistryId(ref) || ref.startsWith(buildpackRegistryPrefix); } function parseProjectToml( diff --git a/lib/modules/manager/buildpacks/schema.ts b/lib/modules/manager/buildpacks/schema.ts index 746d96914e7cad..15d5b54fa77c4c 100644 --- a/lib/modules/manager/buildpacks/schema.ts +++ b/lib/modules/manager/buildpacks/schema.ts @@ -12,19 +12,19 @@ const BuildpackByURI = z.object({ const BuildpackGroup = BuildpackByName.or(BuildpackByURI); -type BuildpackByNameType = z.infer; -type BuildpackByURIType = z.infer; -type BuildpackGroupType = z.infer; +type BuildpackByName = z.infer; +type BuildpackByURI = z.infer; +type BuildpackGroup = z.infer; export function isBuildpackByName( - group: BuildpackGroupType, -): group is BuildpackByNameType { + group: BuildpackGroup, +): group is BuildpackByName { return 'id' in group; } export function isBuildpackByURI( - group: BuildpackGroupType, -): group is BuildpackByURIType { + group: BuildpackGroup, +): group is BuildpackByURI { return 'uri' in group; } From 198af06c489e678cf163685eb609e3ebb20869b4 Mon Sep 17 00:00:00 2001 From: Nicolas Bender Date: Fri, 29 Nov 2024 09:43:32 +0100 Subject: [PATCH 07/13] Address review --- .../buildpacks-registry/index.spec.ts | 21 +++++++------------ .../datasource/buildpacks-registry/index.ts | 10 +++++++-- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/lib/modules/datasource/buildpacks-registry/index.spec.ts b/lib/modules/datasource/buildpacks-registry/index.spec.ts index 393ea9fdee9ca5..475c648235cf08 100644 --- a/lib/modules/datasource/buildpacks-registry/index.spec.ts +++ b/lib/modules/datasource/buildpacks-registry/index.spec.ts @@ -16,14 +16,7 @@ describe('modules/datasource/buildpacks-registry/index', () => { }); const expectedResponse = { registryUrl: 'https://registry.buildpacks.io/', - releases: [ - { - version: '0.17.0', - }, - { - version: '0.17.1', - }, - ], + releases: [{ version: '0.17.0' }, { version: '0.17.1' }], sourceUrl: 'https://github.com/heroku/buildpacks-python', }; expect(res).toEqual(expectedResponse); @@ -32,18 +25,18 @@ describe('modules/datasource/buildpacks-registry/index', () => { it('returns null on empty result', async () => { httpMock.scope(baseUrl).get('/heroku/empty').reply(200, emptResult); const res = await getPkgReleases({ - datasource: BuildpacksRegistryDatasource.id, - packageName: 'heroku/empty', - }); + datasource: BuildpacksRegistryDatasource.id, + packageName: 'heroku/empty', + }); expect(res).toBeNull(); }); it('handles not found', async () => { httpMock.scope(baseUrl).get('/heroku/notexisting').reply(404); const res = await getPkgReleases({ - datasource: BuildpacksRegistryDatasource.id, - packageName: 'heroku/notexisting', - }); + datasource: BuildpacksRegistryDatasource.id, + packageName: 'heroku/notexisting', + }); expect(res).toBeNull(); }); }); diff --git a/lib/modules/datasource/buildpacks-registry/index.ts b/lib/modules/datasource/buildpacks-registry/index.ts index 8e4cbff17c0507..5858c4678e2b82 100644 --- a/lib/modules/datasource/buildpacks-registry/index.ts +++ b/lib/modules/datasource/buildpacks-registry/index.ts @@ -1,3 +1,4 @@ +import urlJoin from 'url-join'; import { ZodError } from 'zod'; import { logger } from '../../../logger'; import { cache } from '../../../util/cache/package/decorator'; @@ -6,7 +7,6 @@ import { Datasource } from '../datasource'; import { ReleasesConfig } from '../schema'; import type { GetReleasesConfig, Release, ReleaseResult } from '../types'; import { BuildpacksRegistryResponseSchema } from './schema'; -import urlJoin from 'url-join'; export class BuildpacksRegistryDatasource extends Datasource { static readonly id = 'buildpacks-registry'; @@ -34,7 +34,13 @@ export class BuildpacksRegistryDatasource extends Datasource { async getReleases(config: GetReleasesConfig): Promise { const result = Result.parse(config, ReleasesConfig) .transform(({ packageName, registryUrl }) => { - const url = urlJoin(registryUrl, 'api', 'v1', 'buildpacks', packageName); + const url = urlJoin( + registryUrl, + 'api', + 'v1', + 'buildpacks', + packageName, + ); return this.http.getJsonSafe(url, BuildpacksRegistryResponseSchema); }) From 9f72055f51f19c5cbf9ff9619841e88950a81b77 Mon Sep 17 00:00:00 2001 From: Ralf Pannemans Date: Fri, 29 Nov 2024 14:33:41 +0100 Subject: [PATCH 08/13] Style changes --- .../buildpacks-registry/index.spec.ts | 37 +++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/lib/modules/datasource/buildpacks-registry/index.spec.ts b/lib/modules/datasource/buildpacks-registry/index.spec.ts index 475c648235cf08..1d91f2f4cde4fc 100644 --- a/lib/modules/datasource/buildpacks-registry/index.spec.ts +++ b/lib/modules/datasource/buildpacks-registry/index.spec.ts @@ -3,27 +3,50 @@ import * as httpMock from '../../../../test/http-mock'; import { BuildpacksRegistryDatasource } from '.'; const baseUrl = 'https://registry.buildpacks.io/api/v1/buildpacks/'; -const herokuResult = {"latest":{"version":"0.17.1","namespace":"heroku","name":"python","description":"Heroku's buildpack for Python applications.","homepage":"https://github.com/heroku/buildpacks-python","licenses":["BSD-3-Clause"],"stacks":["*"],"id":"75946bf8-3f6a-4af0-a757-614bebfdfcd6"},"versions":[{"version":"0.17.1","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.17.1"},{"version":"0.17.0","_link":"https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.17.0"}]}; -const emptResult = {} describe('modules/datasource/buildpacks-registry/index', () => { describe('getReleases', () => { it('processes real data', async () => { - httpMock.scope(baseUrl).get('/heroku/python').reply(200, herokuResult); + httpMock + .scope(baseUrl) + .get('/heroku/python') + .reply(200, { + latest: { + version: '0.17.1', + namespace: 'heroku', + name: 'python', + description: "Heroku's buildpack for Python applications.", + homepage: 'https://github.com/heroku/buildpacks-python', + licenses: ['BSD-3-Clause'], + stacks: ['*'], + id: '75946bf8-3f6a-4af0-a757-614bebfdfcd6', + }, + versions: [ + { + version: '0.17.1', + _link: + 'https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.17.1', + }, + { + version: '0.17.0', + _link: + 'https://registry.buildpacks.io//api/v1/buildpacks/heroku/python/0.17.0', + }, + ], + }); const res = await getPkgReleases({ datasource: BuildpacksRegistryDatasource.id, packageName: 'heroku/python', }); - const expectedResponse = { + expect(res).toEqual({ registryUrl: 'https://registry.buildpacks.io/', releases: [{ version: '0.17.0' }, { version: '0.17.1' }], sourceUrl: 'https://github.com/heroku/buildpacks-python', - }; - expect(res).toEqual(expectedResponse); + }); }); it('returns null on empty result', async () => { - httpMock.scope(baseUrl).get('/heroku/empty').reply(200, emptResult); + httpMock.scope(baseUrl).get('/heroku/empty').reply(200, {}); const res = await getPkgReleases({ datasource: BuildpacksRegistryDatasource.id, packageName: 'heroku/empty', From bb2d87272a2a2c6781f3f7dd4848d9755d3a6933 Mon Sep 17 00:00:00 2001 From: Nicolas Bender Date: Wed, 18 Dec 2024 10:27:10 +0100 Subject: [PATCH 09/13] Update lib/modules/manager/buildpacks/extract.ts Co-authored-by: Michael Kriese --- lib/modules/manager/buildpacks/extract.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/modules/manager/buildpacks/extract.ts b/lib/modules/manager/buildpacks/extract.ts index bd820cd01eeb5b..2d138342447016 100644 --- a/lib/modules/manager/buildpacks/extract.ts +++ b/lib/modules/manager/buildpacks/extract.ts @@ -126,7 +126,6 @@ export function extractPackageFile( datasource: BuildpacksRegistryDatasource.id, currentValue: version, packageName: dependency.split('@')[0], - replaceString: `${dependency}`, }; deps.push(dep); } From d6ea7e0b1244a59d24a4d16be49386147c7550c6 Mon Sep 17 00:00:00 2001 From: Nicolas Bender Date: Wed, 18 Dec 2024 10:27:18 +0100 Subject: [PATCH 10/13] Update lib/modules/datasource/buildpacks-registry/index.ts Co-authored-by: Michael Kriese --- lib/modules/datasource/buildpacks-registry/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/modules/datasource/buildpacks-registry/index.ts b/lib/modules/datasource/buildpacks-registry/index.ts index 5858c4678e2b82..bf54f00daf8b35 100644 --- a/lib/modules/datasource/buildpacks-registry/index.ts +++ b/lib/modules/datasource/buildpacks-registry/index.ts @@ -17,7 +17,7 @@ export class BuildpacksRegistryDatasource extends Datasource { override readonly customRegistrySupport = false; - override readonly defaultRegistryUrls = ['https://registry.buildpacks.io/']; + override readonly defaultRegistryUrls = ['https://registry.buildpacks.io']; override readonly releaseTimestampSupport = true; override readonly releaseTimestampNote = From 2e0e0fa6cd6b18caee80596747bdf156f8ab6a4e Mon Sep 17 00:00:00 2001 From: Nicolas Bender Date: Wed, 18 Dec 2024 10:27:25 +0100 Subject: [PATCH 11/13] Update lib/modules/manager/buildpacks/extract.ts Co-authored-by: Michael Kriese --- lib/modules/manager/buildpacks/extract.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/modules/manager/buildpacks/extract.ts b/lib/modules/manager/buildpacks/extract.ts index 2d138342447016..d9f165b9d6db8b 100644 --- a/lib/modules/manager/buildpacks/extract.ts +++ b/lib/modules/manager/buildpacks/extract.ts @@ -137,7 +137,6 @@ export function extractPackageFile( datasource: BuildpacksRegistryDatasource.id, currentValue: version, packageName: group.id, - replaceString: `${version}`, }; deps.push(dep); } From 8104226e80b299a5ddbcbb7c68368181b9f0ea7b Mon Sep 17 00:00:00 2001 From: Nicolas Bender Date: Wed, 18 Dec 2024 14:00:05 +0100 Subject: [PATCH 12/13] Adjust tests to removed replaceString --- lib/modules/datasource/buildpacks-registry/index.spec.ts | 2 +- lib/modules/manager/buildpacks/extract.spec.ts | 7 ++++--- lib/modules/manager/buildpacks/extract.ts | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/modules/datasource/buildpacks-registry/index.spec.ts b/lib/modules/datasource/buildpacks-registry/index.spec.ts index 1d91f2f4cde4fc..5c386d9aadb7c2 100644 --- a/lib/modules/datasource/buildpacks-registry/index.spec.ts +++ b/lib/modules/datasource/buildpacks-registry/index.spec.ts @@ -39,7 +39,7 @@ describe('modules/datasource/buildpacks-registry/index', () => { packageName: 'heroku/python', }); expect(res).toEqual({ - registryUrl: 'https://registry.buildpacks.io/', + registryUrl: 'https://registry.buildpacks.io', releases: [{ version: '0.17.0' }, { version: '0.17.1' }], sourceUrl: 'https://github.com/heroku/buildpacks-python', }); diff --git a/lib/modules/manager/buildpacks/extract.spec.ts b/lib/modules/manager/buildpacks/extract.spec.ts index 0da53e92354b07..2cc8b60ebe829b 100644 --- a/lib/modules/manager/buildpacks/extract.spec.ts +++ b/lib/modules/manager/buildpacks/extract.spec.ts @@ -95,16 +95,18 @@ id = "not/valid"`, replaceString: 'buildpacks/nodejs:3.3.3', }, { + autoReplaceStringTemplate: + '{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}', datasource: 'buildpacks-registry', currentValue: '1.0.0', packageName: 'example/foo', - replaceString: 'example/foo@1.0.0', }, { + autoReplaceStringTemplate: + '{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}', datasource: 'buildpacks-registry', currentValue: '1.2.3', packageName: 'example/bar', - replaceString: 'example/bar@1.2.3', }, { autoReplaceStringTemplate: @@ -131,7 +133,6 @@ id = "not/valid"`, datasource: 'buildpacks-registry', currentValue: '2.3.4', packageName: 'example/tee', - replaceString: '2.3.4', }, ]); }); diff --git a/lib/modules/manager/buildpacks/extract.ts b/lib/modules/manager/buildpacks/extract.ts index d9f165b9d6db8b..4f41bbab86a946 100644 --- a/lib/modules/manager/buildpacks/extract.ts +++ b/lib/modules/manager/buildpacks/extract.ts @@ -126,6 +126,7 @@ export function extractPackageFile( datasource: BuildpacksRegistryDatasource.id, currentValue: version, packageName: dependency.split('@')[0], + autoReplaceStringTemplate: '{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}' }; deps.push(dep); } From bb39e6a230aa438759ff7820ba4e5a23c71a6793 Mon Sep 17 00:00:00 2001 From: Nicolas Bender Date: Wed, 18 Dec 2024 14:53:23 +0100 Subject: [PATCH 13/13] Fix prettier finding --- lib/modules/manager/buildpacks/extract.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/modules/manager/buildpacks/extract.ts b/lib/modules/manager/buildpacks/extract.ts index 4f41bbab86a946..f723e6ddf2999c 100644 --- a/lib/modules/manager/buildpacks/extract.ts +++ b/lib/modules/manager/buildpacks/extract.ts @@ -126,7 +126,8 @@ export function extractPackageFile( datasource: BuildpacksRegistryDatasource.id, currentValue: version, packageName: dependency.split('@')[0], - autoReplaceStringTemplate: '{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}' + autoReplaceStringTemplate: + '{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}', }; deps.push(dep); }