diff --git a/lib/datasource/helm/index.ts b/lib/datasource/helm/index.ts index c23b04e75e99b5f330c892f762969f3c372abb19..4b18435817fa3499fde63b7f4a6f2764a88d5633 100644 --- a/lib/datasource/helm/index.ts +++ b/lib/datasource/helm/index.ts @@ -3,6 +3,7 @@ import { load } from 'js-yaml'; import { logger } from '../../logger'; import { cache } from '../../util/cache/package/decorator'; import { ensureTrailingSlash } from '../../util/url'; +import * as helmVersioning from '../../versioning/helm'; import { Datasource } from '../datasource'; import type { GetReleasesConfig, ReleaseResult } from '../types'; import { findSourceUrl } from './common'; @@ -24,6 +25,8 @@ export class HelmDatasource extends Datasource { }, }; + override readonly defaultVersioning = helmVersioning.id; + @cache({ namespace: `datasource-${HelmDatasource.id}`, key: (repository: string) => repository, diff --git a/lib/versioning/api.ts b/lib/versioning/api.ts index a96a3261a6faafe646998463853ebef4f9cce5cb..a6770f7794ab940dcd81eb9eb539fe58abbba00a 100644 --- a/lib/versioning/api.ts +++ b/lib/versioning/api.ts @@ -4,6 +4,7 @@ import * as docker from './docker'; import * as git from './git'; import * as gradle from './gradle'; import * as hashicorp from './hashicorp'; +import * as helm from './helm'; import * as hex from './hex'; import * as ivy from './ivy'; import * as loose from './loose'; @@ -31,6 +32,7 @@ api.set('docker', docker.api); api.set('git', git.api); api.set('gradle', gradle.api); api.set('hashicorp', hashicorp.api); +api.set('helm', helm.api); api.set('hex', hex.api); api.set('ivy', ivy.api); api.set('loose', loose.api); diff --git a/lib/versioning/helm/index.spec.ts b/lib/versioning/helm/index.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..6cbb6653cd93c0d7c30f41469b7d581749915e50 --- /dev/null +++ b/lib/versioning/helm/index.spec.ts @@ -0,0 +1,98 @@ +import { api as semver } from '.'; + +describe('versioning/helm/index', () => { + test.each` + version | isValid + ${'17.04.0'} | ${false} + ${'1.2.3'} | ${true} + ${'1.2.3-foo'} | ${true} + ${'1.2.3foo'} | ${false} + ${'~1.2.3'} | ${true} + ${'^1.2.3'} | ${true} + ${'>1.2.3'} | ${true} + ${'>=1.2.3'} | ${true} + ${'renovatebot/renovate'} | ${false} + ${'renovatebot/renovate#main'} | ${false} + ${'https://github.com/renovatebot/renovate.git'} | ${false} + `('isValid("$version") === $isValid', ({ version, isValid }) => { + const res = !!semver.isValid(version); + expect(res).toBe(isValid); + }); + + test.each` + version | isSingle + ${'1.2.3'} | ${true} + ${'1.2.3-alpha.1'} | ${true} + ${'=1.2.3'} | ${true} + ${'= 1.2.3'} | ${true} + ${'1.x'} | ${false} + `('isSingleVersion("$version") === $isSingle', ({ version, isSingle }) => { + const res = !!semver.isSingleVersion(version); + expect(res).toBe(isSingle); + }); + + test.each` + currentValue | rangeStrategy | currentVersion | newVersion | expected + ${'=1.0.0'} | ${'bump'} | ${'1.0.0'} | ${'1.1.0'} | ${'=1.1.0'} + ${'^1.0'} | ${'bump'} | ${'1.0.0'} | ${'1.0.7'} | ${'^1.0'} + ${'^1'} | ${'bump'} | ${'1.0.0'} | ${'1.0.7-prerelease.1'} | ${'^1.0.7-prerelease.1'} + ${'^1.0'} | ${'bump'} | ${'1.0.0'} | ${'1.1.7'} | ${'^1.1'} + ${'~1.0'} | ${'bump'} | ${'1.0.0'} | ${'1.1.7'} | ${'~1.1'} + ${'~1.0'} | ${'bump'} | ${'1.0.0'} | ${'1.0.7-prerelease.1'} | ${'~1.0.7-prerelease.1'} + ${'^1'} | ${'bump'} | ${'1.0.0'} | ${'2.1.7'} | ${'^2'} + ${'~1'} | ${'bump'} | ${'1.0.0'} | ${'1.1.7'} | ${'~1'} + ${'5'} | ${'bump'} | ${'5.0.0'} | ${'5.1.7'} | ${'5'} + ${'5'} | ${'bump'} | ${'5.0.0'} | ${'6.1.7'} | ${'6'} + ${'5.0'} | ${'bump'} | ${'5.0.0'} | ${'5.0.7'} | ${'5.0'} + ${'5.0'} | ${'bump'} | ${'5.0.0'} | ${'5.1.7'} | ${'5.1'} + ${'5.0'} | ${'bump'} | ${'5.0.0'} | ${'6.1.7'} | ${'6.1'} + ${'>=1.0.0'} | ${'bump'} | ${'1.0.0'} | ${'1.1.0'} | ${'>=1.1.0'} + ${'>= 1.0.0'} | ${'bump'} | ${'1.0.0'} | ${'1.1.0'} | ${'>= 1.1.0'} + ${'=1.0.0'} | ${'replace'} | ${'1.0.0'} | ${'1.1.0'} | ${'=1.1.0'} + ${'1.0.*'} | ${'replace'} | ${'1.0.0'} | ${'1.1.0'} | ${'1.1.*'} + ${'1.*'} | ${'replace'} | ${'1.0.0'} | ${'2.1.0'} | ${'2.*'} + ${'~0.6.1'} | ${'replace'} | ${'0.6.8'} | ${'0.7.0-rc.2'} | ${'~0.7.0-rc'} + ${'>= 0.1.21 < 0.2.0'} | ${'bump'} | ${'0.1.21'} | ${'0.1.24'} | ${'>= 0.1.24 < 0.2.0'} + ${'>= 0.1.21 <= 0.2.0'} | ${'bump'} | ${'0.1.21'} | ${'0.1.24'} | ${'>= 0.1.24 <= 0.2.0'} + ${'>= 0.0.1 <= 0.1'} | ${'bump'} | ${'0.0.1'} | ${'0.0.2'} | ${'>= 0.0.2 <= 0.1'} + ${'>= 0.0.1 < 0.1'} | ${'bump'} | ${'0.1.0'} | ${'0.2.1'} | ${'>= 0.2.1 < 0.3'} + ${'>= 0.0.1 < 0.0.4'} | ${'bump'} | ${'0.0.4'} | ${'0.0.5'} | ${'>= 0.0.5 < 0.0.6'} + ${'>= 0.0.1 < 1'} | ${'bump'} | ${'1.0.0'} | ${'1.0.1'} | ${'>= 1.0.1 < 2'} + ${'>= 0.0.1 < 1'} | ${'bump'} | ${'1.0.0'} | ${'1.0.1'} | ${'>= 1.0.1 < 2'} + ${'<=1.2.3'} | ${'widen'} | ${'1.0.0'} | ${'1.2.3'} | ${'<=1.2.3'} + ${'<=1.2.3'} | ${'widen'} | ${'1.0.0'} | ${'1.2.4'} | ${'<=1.2.4'} + ${'>=1.2.3'} | ${'widen'} | ${'1.0.0'} | ${'1.2.3'} | ${'>=1.2.3'} + ${'>=1.2.3'} | ${'widen'} | ${'1.0.0'} | ${'1.2.1'} | ${'>=1.2.3 || 1.2.1'} + ${'^0.0.3'} | ${'replace'} | ${'0.0.3'} | ${'0.0.6'} | ${'^0.0.6'} + ${'^0.0.3'} | ${'replace'} | ${'0.0.3'} | ${'0.5.0'} | ${'^0.5.0'} + ${'^0.0.3'} | ${'replace'} | ${'0.0.3'} | ${'0.5.6'} | ${'^0.5.0'} + ${'^0.0.3'} | ${'replace'} | ${'0.0.3'} | ${'4.0.0'} | ${'^4.0.0'} + ${'^0.0.3'} | ${'replace'} | ${'0.0.3'} | ${'4.0.6'} | ${'^4.0.0'} + ${'^0.0.3'} | ${'replace'} | ${'0.0.3'} | ${'4.5.6'} | ${'^4.0.0'} + ${'^0.2.0'} | ${'replace'} | ${'0.2.0'} | ${'0.5.6'} | ${'^0.5.0'} + ${'^0.2.3'} | ${'replace'} | ${'0.2.3'} | ${'0.5.0'} | ${'^0.5.0'} + ${'^0.2.3'} | ${'replace'} | ${'0.2.3'} | ${'0.5.6'} | ${'^0.5.0'} + ${'^1.2.3'} | ${'replace'} | ${'1.2.3'} | ${'4.0.0'} | ${'^4.0.0'} + ${'^1.2.3'} | ${'replace'} | ${'1.2.3'} | ${'4.5.6'} | ${'^4.0.0'} + ${'^1.0.0'} | ${'replace'} | ${'1.0.0'} | ${'4.5.6'} | ${'^4.0.0'} + ${'^0.2.3'} | ${'replace'} | ${'0.2.3'} | ${'0.2.4'} | ${'^0.2.3'} + ${'^2.3.0'} | ${'replace'} | ${'2.3.0'} | ${'2.4.0'} | ${'^2.3.0'} + ${'^2.3.4'} | ${'replace'} | ${'2.3.4'} | ${'2.4.5'} | ${'^2.3.4'} + ${'^0.0.1'} | ${'replace'} | ${'0.0.1'} | ${'0.0.2'} | ${'^0.0.2'} + ${'^1.0.1'} | ${'replace'} | ${'1.0.1'} | ${'2.0.2'} | ${'^2.0.0'} + ${'^1.2.3'} | ${'replace'} | ${'1.2.3'} | ${'1.2.3'} | ${'^1.2.3'} + ${'^1.2.3'} | ${'replace'} | ${'1.2.3'} | ${'1.2.2'} | ${'^1.2.2'} + ${'^0.9.21'} | ${'replace'} | ${'0.9.21'} | ${'0.9.22'} | ${'^0.9.21'} + `( + 'getNewValue("$currentValue", "$rangeStrategy", "$currentVersion", "$newVersion") === "$expected"', + ({ currentValue, rangeStrategy, currentVersion, newVersion, expected }) => { + const res = semver.getNewValue({ + currentValue, + rangeStrategy, + currentVersion, + newVersion, + }); + expect(res).toEqual(expected); + } + ); +}); diff --git a/lib/versioning/helm/index.ts b/lib/versioning/helm/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..a05de053fd359be3057b722aff3b4f898fcaca41 --- /dev/null +++ b/lib/versioning/helm/index.ts @@ -0,0 +1,22 @@ +import { api as npm } from '../npm'; +import type { VersioningApi } from '../types'; + +export const id = 'helm'; +export const displayName = 'helm'; +export const urls = [ + 'https://semver.org/', + 'https://helm.sh/docs/chart_best_practices/dependencies/#versions', + 'https://github.com/Masterminds/semver#basic-comparisons', +]; +export const supportsRanges = true; +export const supportedRangeStrategies = [ + 'bump', + 'extend', + 'pin', + 'replace', + 'widen', +]; + +export const api: VersioningApi = { + ...npm, +};