From 12ae0d1ee9990d07a01db986a0e3aa77bc252859 Mon Sep 17 00:00:00 2001 From: Sebastian Poxhofer Date: Wed, 15 Sep 2021 09:20:31 +0200 Subject: [PATCH] feat(manager/terraform): support range strategy update lockfile (#11720) Co-authored-by: Michael Kriese --- docs/usage/configuration-options.md | 2 +- .../terraform/__fixtures__/lockedVersion.tf | 15 +++++ .../terraform/__fixtures__/rangeStrategy.hcl | 32 +++++++++++ .../__snapshots__/extract.spec.ts.snap | 57 ++++++++++++++++++- lib/manager/terraform/extract.spec.ts | 54 ++++++++++++++---- lib/manager/terraform/extract.ts | 23 +++++++- lib/manager/terraform/lockfile/index.ts | 26 ++++----- lib/manager/terraform/providers.ts | 38 ++++++++----- lib/manager/terraform/required-providers.ts | 8 ++- lib/manager/terraform/util.ts | 34 +++++++++++ lib/versioning/hashicorp/index.spec.ts | 22 ++++--- lib/versioning/hashicorp/index.ts | 2 +- 12 files changed, 257 insertions(+), 56 deletions(-) create mode 100644 lib/manager/terraform/__fixtures__/lockedVersion.tf create mode 100644 lib/manager/terraform/__fixtures__/rangeStrategy.hcl diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md index 8abfac7a137caa..8cfcb0a98af3dc 100644 --- a/docs/usage/configuration-options.md +++ b/docs/usage/configuration-options.md @@ -1860,7 +1860,7 @@ Behavior: - `bump` = e.g. bump the range even if the new version satisfies the existing range, e.g. `^1.0.0` -> `^1.1.0` - `replace` = Replace the range with a newer one if the new version falls outside it, e.g. `^1.0.0` -> `^2.0.0` - `widen` = Widen the range with newer one, e.g. `^1.0.0` -> `^1.0.0 || ^2.0.0` -- `update-lockfile` = Update the lock file when in-range updates are available, otherwise `replace` for updates out of range. Works for `bundler`, `composer`, `npm`, `yarn` and `poetry` so far +- `update-lockfile` = Update the lock file when in-range updates are available, otherwise `replace` for updates out of range. Works for `bundler`, `composer`, `npm`, `yarn`, `terraform` and `poetry` so far Renovate's `"auto"` strategy works like this for npm: diff --git a/lib/manager/terraform/__fixtures__/lockedVersion.tf b/lib/manager/terraform/__fixtures__/lockedVersion.tf new file mode 100644 index 00000000000000..fc354ff15d17e3 --- /dev/null +++ b/lib/manager/terraform/__fixtures__/lockedVersion.tf @@ -0,0 +1,15 @@ +terraform { + required_providers { + aws = { + source = "aws" + version = "~> 3.0" + } + azurerm = { + version = "~> 2.50.0" + } + kubernetes = { + source = "terraform.example.com/example/kubernetes" + version = ">= 1.0" + } + } +} diff --git a/lib/manager/terraform/__fixtures__/rangeStrategy.hcl b/lib/manager/terraform/__fixtures__/rangeStrategy.hcl new file mode 100644 index 00000000000000..5bcdf22bcbbf8a --- /dev/null +++ b/lib/manager/terraform/__fixtures__/rangeStrategy.hcl @@ -0,0 +1,32 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/aws" { + version = "3.1.0" + constraints = "~> 3.0" + hashes = [ + "h1:ULKfwySvQ4pDhy027ryRhLxDhg640wsojYc+7NHMFBU=", + "zh:df568a69087831c1780fac4395630a2cfb3cdf67b7dffbfe16bd78c64770bb75", + "zh:fce1b69dd673aace19508640b0b9b7eb1ef7e746d76cb846b49e7d52e0f5fb7e", + ] +} + +provider "registry.terraform.io/hashicorp/azurerm" { + version = "2.50.0" + constraints = "~> 2.50.0" + hashes = [ + "h1:Vr6WUm88s9hXGkyVjHtHsP2Jmc2ypQXn6ww7dXtvk1M=", + "zh:e98f1d178d1e111b3f3449e27d305ce263071226fad3d86272e1bd161c26fd43", + "zh:eb76ec000c9c49a0bf730370c8880f671597bc01f7b7401ab301df7124c049ec", + ] +} + +provider "https://terraform.example.com/example/kubernetes" { + version = "1.5.0" + constraints = ">= 1.0" + hashes = [ + "h1:Vr6WUm88s9hXGkyVjHtHsP2Jmc2ypQXn6ww7dXtvk1M=", + "zh:e98f1d178d1e111b3f3449e27d305ce263071226fad3d86272e1bd161c26fd43", + "zh:eb76ec000c9c49a0bf730370c8880f671597bc01f7b7401ab301df7124c049ec", + ] +} diff --git a/lib/manager/terraform/__snapshots__/extract.spec.ts.snap b/lib/manager/terraform/__snapshots__/extract.spec.ts.snap index 1fba3faa42c84d..edc6ea6fdc2be1 100644 --- a/lib/manager/terraform/__snapshots__/extract.spec.ts.snap +++ b/lib/manager/terraform/__snapshots__/extract.spec.ts.snap @@ -187,29 +187,39 @@ Object { "datasource": "terraform-provider", "depName": "azurerm", "depType": "provider", + "lockedVersion": undefined, + "lookupName": "hashicorp/azurerm", }, Object { "currentValue": "=2.4", "datasource": "terraform-provider", "depName": "gitlab", "depType": "provider", + "lockedVersion": undefined, + "lookupName": "hashicorp/gitlab", }, Object { "currentValue": "=1.3", "datasource": "terraform-provider", "depName": "gitlab", "depType": "provider", + "lockedVersion": undefined, + "lookupName": "hashicorp/gitlab", }, Object { "datasource": "terraform-provider", "depName": "helm", "depType": "provider", + "lockedVersion": undefined, + "lookupName": "hashicorp/helm", }, Object { "currentValue": "V1.9", "datasource": "terraform-provider", "depName": "newrelic", "depType": "provider", + "lockedVersion": undefined, + "lookupName": "hashicorp/newrelic", }, Object { "currentValue": "v1.0.0", @@ -258,12 +268,16 @@ Object { "datasource": "terraform-provider", "depName": "aws", "depType": "required_provider", + "lockedVersion": undefined, + "lookupName": "hashicorp/aws", }, Object { "currentValue": ">= 2.0.0", "datasource": "terraform-provider", "depName": "azurerm", "depType": "required_provider", + "lockedVersion": undefined, + "lookupName": "hashicorp/azurerm", }, Object { "currentValue": ">= 0.13", @@ -278,6 +292,8 @@ Object { "datasource": "terraform-provider", "depName": "docker", "depType": "required_provider", + "lockedVersion": undefined, + "lookupName": "hashicorp/docker", "registryUrls": Array [ "https://releases.hashicorp.com", ], @@ -287,13 +303,16 @@ Object { "datasource": "terraform-provider", "depName": "aws", "depType": "required_provider", - "lookupName": "aws", + "lockedVersion": undefined, + "lookupName": "hashicorp/aws", }, Object { "currentValue": "=2.27.0", "datasource": "terraform-provider", "depName": "azurerm", "depType": "required_provider", + "lockedVersion": undefined, + "lookupName": "hashicorp/azurerm", }, Object { "currentValue": "1.2.4", @@ -307,6 +326,7 @@ Object { "datasource": "terraform-provider", "depName": "helm", "depType": "required_provider", + "lockedVersion": undefined, "lookupName": "hashicorp/helm", }, Object { @@ -314,6 +334,7 @@ Object { "datasource": "terraform-provider", "depName": "kubernetes", "depType": "required_provider", + "lockedVersion": undefined, "lookupName": "hashicorp/kubernetes", "registryUrls": Array [ "https://terraform.example.com", @@ -368,3 +389,37 @@ Object { ], } `; + +exports[`manager/terraform/extract extractPackageFile() update lockfile constraints with range strategy update-lockfile 1`] = ` +Object { + "deps": Array [ + Object { + "currentValue": "~> 3.0", + "datasource": "terraform-provider", + "depName": "aws", + "depType": "required_provider", + "lockedVersion": "3.1.0", + "lookupName": "hashicorp/aws", + }, + Object { + "currentValue": "~> 2.50.0", + "datasource": "terraform-provider", + "depName": "azurerm", + "depType": "required_provider", + "lockedVersion": "2.50.0", + "lookupName": "hashicorp/azurerm", + }, + Object { + "currentValue": ">= 1.0", + "datasource": "terraform-provider", + "depName": "kubernetes", + "depType": "required_provider", + "lockedVersion": undefined, + "lookupName": "example/kubernetes", + "registryUrls": Array [ + "https://terraform.example.com", + ], + }, + ], +} +`; diff --git a/lib/manager/terraform/extract.spec.ts b/lib/manager/terraform/extract.spec.ts index 90f9abc5bd8c7d..88f53e9ffbfc07 100644 --- a/lib/manager/terraform/extract.spec.ts +++ b/lib/manager/terraform/extract.spec.ts @@ -1,5 +1,8 @@ -import { loadFixture } from '../../../test/util'; -import { extractPackageFile } from './extract'; +import { join } from 'upath'; +import { fs, loadFixture } from '../../../test/util'; +import { setGlobalConfig } from '../../config/global'; +import type { RepoGlobalConfig } from '../../config/types'; +import { extractPackageFile } from '.'; const tf1 = loadFixture('1.tf'); const tf2 = `module "relative" { @@ -7,26 +10,57 @@ const tf2 = `module "relative" { } `; const helm = loadFixture('helm.tf'); +const lockedVersion = loadFixture('lockedVersion.tf'); +const lockedVersionLockfile = loadFixture('rangeStrategy.hcl'); + +const adminConfig: RepoGlobalConfig = { + // `join` fixes Windows CI + localDir: join('/tmp/github/some/repo'), + cacheDir: join('/tmp/cache'), +}; + +// auto-mock fs +jest.mock('../../util/fs'); describe('manager/terraform/extract', () => { + beforeEach(() => { + setGlobalConfig(adminConfig); + }); describe('extractPackageFile()', () => { - it('returns null for empty', () => { - expect(extractPackageFile('nothing here')).toBeNull(); + it('returns null for empty', async () => { + expect(await extractPackageFile('nothing here', '1.tf', {})).toBeNull(); }); - it('extracts', () => { - const res = extractPackageFile(tf1); + + it('extracts', async () => { + const res = await extractPackageFile(tf1, '1.tf', {}); expect(res).toMatchSnapshot(); expect(res.deps).toHaveLength(46); expect(res.deps.filter((dep) => dep.skipReason)).toHaveLength(8); }); - it('returns null if only local deps', () => { - expect(extractPackageFile(tf2)).toBeNull(); + + it('returns null if only local deps', async () => { + expect(await extractPackageFile(tf2, '2.tf', {})).toBeNull(); }); - it('extract helm releases', () => { - const res = extractPackageFile(helm); + + it('extract helm releases', async () => { + const res = await extractPackageFile(helm, 'helm.tf', {}); expect(res).toMatchSnapshot(); expect(res.deps).toHaveLength(6); expect(res.deps.filter((dep) => dep.skipReason)).toHaveLength(2); }); + + it('update lockfile constraints with range strategy update-lockfile', async () => { + fs.readLocalFile.mockResolvedValueOnce(lockedVersionLockfile); + fs.getSiblingFileName.mockReturnValueOnce('aLockFile.hcl'); + + const res = await extractPackageFile( + lockedVersion, + 'lockedVersion.tf', + {} + ); + expect(res).toMatchSnapshot(); + expect(res.deps).toHaveLength(3); + expect(res.deps.filter((dep) => dep.skipReason)).toHaveLength(0); + }); }); }); diff --git a/lib/manager/terraform/extract.ts b/lib/manager/terraform/extract.ts index 2d94fb982014c5..952bf0fab80ef8 100644 --- a/lib/manager/terraform/extract.ts +++ b/lib/manager/terraform/extract.ts @@ -1,6 +1,8 @@ import { logger } from '../../logger'; +import type { ExtractConfig } from '../types'; import type { PackageDependency, PackageFile } from '../types'; import { TerraformDependencyTypes } from './common'; +import { extractLocks, findLockFile, readLockFile } from './lockfile/util'; import { analyseTerraformModule, extractTerraformModule } from './modules'; import { analyzeTerraformProvider, @@ -34,7 +36,11 @@ const contentCheckList = [ ' "docker_image" ', ]; -export function extractPackageFile(content: string): PackageFile | null { +export async function extractPackageFile( + content: string, + fileName: string, + config: ExtractConfig +): Promise { logger.trace({ content }, 'terraform.extractPackageFile()'); if (!checkFileContainsDependency(content, contentCheckList)) { return null; @@ -99,13 +105,24 @@ export function extractPackageFile(content: string): PackageFile | null { } catch (err) /* istanbul ignore next */ { logger.warn({ err }, 'Error extracting terraform plugins'); } + + const locks = []; + const lockFilePath = findLockFile(fileName); + if (lockFilePath) { + const lockFileContent = await readLockFile(lockFilePath); + if (lockFileContent) { + const extractedLocks = extractLocks(lockFileContent); + locks.push(...extractedLocks); + } + } + deps.forEach((dep) => { switch (dep.managerData.terraformDependencyType) { case TerraformDependencyTypes.required_providers: - analyzeTerraformRequiredProvider(dep); + analyzeTerraformRequiredProvider(dep, locks); break; case TerraformDependencyTypes.provider: - analyzeTerraformProvider(dep); + analyzeTerraformProvider(dep, locks); break; case TerraformDependencyTypes.module: analyseTerraformModule(dep); diff --git a/lib/manager/terraform/lockfile/index.ts b/lib/manager/terraform/lockfile/index.ts index 6322f3e6fedc05..4fe381265a7f11 100644 --- a/lib/manager/terraform/lockfile/index.ts +++ b/lib/manager/terraform/lockfile/index.ts @@ -4,6 +4,7 @@ import { TerraformProviderDatasource } from '../../../datasource/terraform-provi import { logger } from '../../../logger'; import { get as getVersioning } from '../../../versioning'; import type { UpdateArtifact, UpdateArtifactsResult } from '../../types'; +import { massageProviderLookupName } from '../util'; import { TerraformProviderHash } from './hash'; import type { ProviderLock, ProviderLockUpdate } from './types'; import { @@ -85,30 +86,23 @@ export async function updateArtifacts({ ['provider', 'required_provider'].includes(dep.depType) ); for (const dep of providerDeps) { - const lookupName = dep.lookupName ?? dep.depName; + massageProviderLookupName(dep); + const { registryUrls, newVersion, newValue, lookupName } = dep; - // handle cases like `Telmate/proxmox` - const massagedLookupName = lookupName.toLowerCase(); - - const repository = massagedLookupName.includes('/') - ? massagedLookupName - : `hashicorp/${massagedLookupName}`; - const registryUrl = dep.registryUrls - ? dep.registryUrls[0] + const registryUrl = registryUrls + ? registryUrls[0] : TerraformProviderDatasource.defaultRegistryUrls[0]; - const newConstraint = isPinnedVersion(dep.newValue) - ? dep.newVersion - : dep.newValue; + const newConstraint = isPinnedVersion(newValue) ? newVersion : newValue; const updateLock = locks.find( - (value) => value.lookupName === repository + (value) => value.lookupName === lookupName ); const update: ProviderLockUpdate = { - newVersion: dep.newVersion, + newVersion, newConstraint, newHashes: await TerraformProviderHash.createHashes( registryUrl, - repository, - dep.newVersion + lookupName, + newVersion ), ...updateLock, }; diff --git a/lib/manager/terraform/providers.ts b/lib/manager/terraform/providers.ts index 6feb0f9209c1ce..553fcacbe84a5c 100644 --- a/lib/manager/terraform/providers.ts +++ b/lib/manager/terraform/providers.ts @@ -4,8 +4,13 @@ import { logger } from '../../logger'; import { SkipReason } from '../../types'; import type { PackageDependency } from '../types'; import { TerraformDependencyTypes } from './common'; +import type { ProviderLock } from './lockfile/types'; import type { ExtractionResult } from './types'; -import { keyValueExtractionRegex } from './util'; +import { + getLockedVersion, + keyValueExtractionRegex, + massageProviderLookupName, +} from './util'; export const sourceExtractionRegex = /^(?:(?(?:[a-zA-Z0-9]+\.+)+[a-zA-Z0-9]+)\/)?(?:(?[^/]+)\/)?(?[^/]+)/; @@ -58,7 +63,10 @@ export function extractTerraformProvider( return { lineNumber, dependencies: deps }; } -export function analyzeTerraformProvider(dep: PackageDependency): void { +export function analyzeTerraformProvider( + dep: PackageDependency, + locks: ProviderLock[] +): void { /* eslint-disable no-param-reassign */ dep.depType = 'provider'; dep.depName = dep.managerData.moduleName; @@ -66,19 +74,23 @@ export function analyzeTerraformProvider(dep: PackageDependency): void { if (is.nonEmptyString(dep.managerData.source)) { const source = sourceExtractionRegex.exec(dep.managerData.source); - if (source) { - // buildin providers https://github.com/terraform-providers - if (source.groups.namespace === 'terraform-providers') { - dep.registryUrls = [`https://releases.hashicorp.com`]; - } else if (source.groups.hostname) { - dep.registryUrls = [`https://${source.groups.hostname}`]; - dep.lookupName = `${source.groups.namespace}/${source.groups.type}`; - } else { - dep.lookupName = dep.managerData.source; - } - } else { + if (!source) { dep.skipReason = SkipReason.UnsupportedUrl; + return; + } + + // buildin providers https://github.com/terraform-providers + if (source.groups.namespace === 'terraform-providers') { + dep.registryUrls = [`https://releases.hashicorp.com`]; + } else if (source.groups.hostname) { + dep.registryUrls = [`https://${source.groups.hostname}`]; + dep.lookupName = `${source.groups.namespace}/${source.groups.type}`; + } else { + dep.lookupName = dep.managerData.source; } } + massageProviderLookupName(dep); + + dep.lockedVersion = getLockedVersion(dep, locks); /* eslint-enable no-param-reassign */ } diff --git a/lib/manager/terraform/required-providers.ts b/lib/manager/terraform/required-providers.ts index 7d519ed74aec3c..95c7f0d25fc1d2 100644 --- a/lib/manager/terraform/required-providers.ts +++ b/lib/manager/terraform/required-providers.ts @@ -1,5 +1,6 @@ import type { PackageDependency } from '../types'; import { TerraformDependencyTypes } from './common'; +import type { ProviderLock } from './lockfile/types'; import { analyzeTerraformProvider } from './providers'; import type { ExtractionResult } from './types'; import { keyValueExtractionRegex } from './util'; @@ -72,9 +73,12 @@ export function extractTerraformRequiredProviders( return { lineNumber, dependencies: deps }; } -export function analyzeTerraformRequiredProvider(dep: PackageDependency): void { +export function analyzeTerraformRequiredProvider( + dep: PackageDependency, + locks: ProviderLock[] +): void { /* eslint-disable no-param-reassign */ - analyzeTerraformProvider(dep); + analyzeTerraformProvider(dep, locks); dep.depType = `required_provider`; /* eslint-enable no-param-reassign */ } diff --git a/lib/manager/terraform/util.ts b/lib/manager/terraform/util.ts index 9e42e144c621da..10082d7d555f8f 100644 --- a/lib/manager/terraform/util.ts +++ b/lib/manager/terraform/util.ts @@ -1,4 +1,7 @@ +import { TerraformProviderDatasource } from '../../datasource/terraform-provider'; +import type { PackageDependency } from '../types'; import { TerraformDependencyTypes } from './common'; +import type { ProviderLock } from './lockfile/types'; export const keyValueExtractionRegex = /^\s*(?[^\s]+)\s+=\s+"(?[^"]+)"\s*$/; @@ -42,3 +45,34 @@ export function checkIfStringIsPath(path: string): boolean { const match = pathStringRegex.exec(path); return !!match; } + +export function massageProviderLookupName(dep: PackageDependency): void { + /* eslint-disable no-param-reassign */ + if (!dep.lookupName) { + dep.lookupName = dep.depName; + } + if (!dep.lookupName.includes('/')) { + dep.lookupName = `hashicorp/${dep.lookupName}`; + } + + // handle cases like `Telmate/proxmox` + dep.lookupName = dep.lookupName.toLowerCase(); + /* eslint-enable no-param-reassign */ +} + +export function getLockedVersion( + dep: PackageDependency, + locks: ProviderLock[] +): string { + const depRegistryUrl = dep.registryUrls + ? dep.registryUrls[0] + : TerraformProviderDatasource.defaultRegistryUrls[0]; + const foundLock = locks.find( + (lock) => + lock.lookupName === dep.lookupName && lock.registryUrl === depRegistryUrl + ); + if (foundLock) { + return foundLock.version; + } + return undefined; +} diff --git a/lib/versioning/hashicorp/index.spec.ts b/lib/versioning/hashicorp/index.spec.ts index e05f9ae507add4..63f68318833479 100644 --- a/lib/versioning/hashicorp/index.spec.ts +++ b/lib/versioning/hashicorp/index.spec.ts @@ -53,15 +53,19 @@ describe('versioning/hashicorp/index', () => { ); test.each` - currentValue | rangeStrategy | currentVersion | newVersion | expected - ${'~> 1.2'} | ${'replace'} | ${'1.2.3'} | ${'2.0.7'} | ${'~> 2.0'} - ${'~> 1.2.0'} | ${'replace'} | ${'1.2.3'} | ${'2.0.7'} | ${'~> 2.0.0'} - ${'~> 0.14.0'} | ${'replace'} | ${'0.14.1'} | ${'0.15.0'} | ${'~> 0.15.0'} - ${'~> 0.14.0'} | ${'replace'} | ${'0.14.1'} | ${'0.15.1'} | ${'~> 0.15.0'} - ${'~> 0.14.6'} | ${'replace'} | ${'0.14.6'} | ${'0.15.0'} | ${'~> 0.15.0'} - ${'>= 1.0.0, <= 2.0.0'} | ${'widen'} | ${'1.2.3'} | ${'2.0.7'} | ${'>= 1.0.0, <= 2.0.7'} - ${'0.14'} | ${'replace'} | ${'0.14.2'} | ${'0.15.0'} | ${'0.15'} - ${'~> 0.14'} | ${'replace'} | ${'0.14.2'} | ${'0.15.0'} | ${'~> 0.15'} + currentValue | rangeStrategy | currentVersion | newVersion | expected + ${'~> 1.2'} | ${'replace'} | ${'1.2.3'} | ${'2.0.7'} | ${'~> 2.0'} + ${'~> 1.2.0'} | ${'replace'} | ${'1.2.3'} | ${'2.0.7'} | ${'~> 2.0.0'} + ${'~> 0.14.0'} | ${'replace'} | ${'0.14.1'} | ${'0.15.0'} | ${'~> 0.15.0'} + ${'~> 0.14.0'} | ${'replace'} | ${'0.14.1'} | ${'0.15.1'} | ${'~> 0.15.0'} + ${'~> 0.14.6'} | ${'replace'} | ${'0.14.6'} | ${'0.15.0'} | ${'~> 0.15.0'} + ${'>= 1.0.0, <= 2.0.0'} | ${'widen'} | ${'1.2.3'} | ${'2.0.7'} | ${'>= 1.0.0, <= 2.0.7'} + ${'0.14'} | ${'replace'} | ${'0.14.2'} | ${'0.15.0'} | ${'0.15'} + ${'~> 0.14'} | ${'replace'} | ${'0.14.2'} | ${'0.15.0'} | ${'~> 0.15'} + ${'~> 0.14'} | ${'update-lockfile'} | ${'0.14.2'} | ${'0.14.6'} | ${'~> 0.14'} + ${'~> 0.14'} | ${'update-lockfile'} | ${'0.14.2'} | ${'0.15.0'} | ${'~> 0.15'} + ${'~> 2.62.0'} | ${'update-lockfile'} | ${'2.62.0'} | ${'2.62.1'} | ${'~> 2.62.0'} + ${'~> 2.62.0'} | ${'update-lockfile'} | ${'2.62.0'} | ${'2.67.0'} | ${'~> 2.67.0'} `( 'getNewValue("$currentValue", "$rangeStrategy", "$currentVersion", "$newVersion") === "$expected"', ({ currentValue, rangeStrategy, currentVersion, newVersion, expected }) => { diff --git a/lib/versioning/hashicorp/index.ts b/lib/versioning/hashicorp/index.ts index 288c0a210ba8fa..7fccf31e6a0673 100644 --- a/lib/versioning/hashicorp/index.ts +++ b/lib/versioning/hashicorp/index.ts @@ -35,7 +35,7 @@ function getNewValue({ currentVersion, newVersion, }: NewValueConfig): string { - if (rangeStrategy === 'replace') { + if (['replace', 'update-lockfile'].includes(rangeStrategy)) { if (/~>\s*0\.\d+/.test(currentValue) && npm.getMajor(newVersion) === 0) { const testFullVersion = /(~>\s*0\.)(\d+)\.\d$/; let replaceValue = '';