diff --git a/lib/manager/terraform/__snapshots__/extract.spec.ts.snap b/lib/manager/terraform/__snapshots__/extract.spec.ts.snap index e8baaac71da8980bd391072da7ae0bcbf9f532c2..5c3eebb6fb06783a307148e39cacdf6c9a768b5e 100644 --- a/lib/manager/terraform/__snapshots__/extract.spec.ts.snap +++ b/lib/manager/terraform/__snapshots__/extract.spec.ts.snap @@ -259,6 +259,13 @@ Object { "depName": "azurerm", "depType": "terraform", }, + Object { + "currentValue": ">= 0.13", + "datasource": "github-tags", + "depName": "hashicorp/terraform", + "extractVersion": "v(?<version>.*)$", + "lineNumber": 205, + }, Object { "currentValue": "2.7.2", "datasource": "terraform-provider", diff --git a/lib/manager/terraform/extract.spec.ts b/lib/manager/terraform/extract.spec.ts index d63177e92f1c2c856b496c7ef9bde9f72933a56a..b7647c943f105d36ab59af104651ae5e49f6ca75 100644 --- a/lib/manager/terraform/extract.spec.ts +++ b/lib/manager/terraform/extract.spec.ts @@ -16,7 +16,7 @@ describe('lib/manager/terraform/extract', () => { it('extracts', () => { const res = extractPackageFile(tf1); expect(res).toMatchSnapshot(); - expect(res.deps).toHaveLength(44); + expect(res.deps).toHaveLength(45); expect(res.deps.filter((dep) => dep.skipReason)).toHaveLength(8); }); it('returns null if only local deps', () => { diff --git a/lib/manager/terraform/extract.ts b/lib/manager/terraform/extract.ts index c883a657e7c52da7e4636c750fb89a0d00e41a46..1fcd2a87fb88f8d64dffa56b4274ec131a0c27a3 100644 --- a/lib/manager/terraform/extract.ts +++ b/lib/manager/terraform/extract.ts @@ -6,6 +6,10 @@ import { extractTerraformProvider, } from './providers'; import { extractTerraformRequiredProviders } from './required-providers'; +import { + analyseTerraformVersion, + extractTerraformRequiredVersion, +} from './required-version'; import { analyseTerraformResource, extractTerraformResource, @@ -70,6 +74,10 @@ export function extractPackageFile(content: string): PackageFile | null { result = extractTerraformResource(lineNumber, lines); break; } + case TerraformDependencyTypes.terraform_version: { + result = extractTerraformRequiredVersion(lineNumber, lines); + break; + } /* istanbul ignore next */ default: logger.trace( @@ -99,6 +107,9 @@ export function extractPackageFile(content: string): PackageFile | null { case TerraformDependencyTypes.resource: analyseTerraformResource(dep); break; + case TerraformDependencyTypes.terraform_version: + analyseTerraformVersion(dep); + break; /* istanbul ignore next */ default: } diff --git a/lib/manager/terraform/required-version.ts b/lib/manager/terraform/required-version.ts new file mode 100644 index 0000000000000000000000000000000000000000..aac37eaf7ef770ae6c7359d60dd16548cf36ac70 --- /dev/null +++ b/lib/manager/terraform/required-version.ts @@ -0,0 +1,55 @@ +import * as datasourceGithubTags from '../../datasource/github-tags'; +import { logger } from '../../logger'; +import { PackageDependency } from '../common'; +import { + ExtractionResult, + TerraformDependencyTypes, + keyValueExtractionRegex, +} from './util'; + +export function extractTerraformRequiredVersion( + startingLine: number, + lines: string[] +): ExtractionResult { + const deps: PackageDependency[] = []; + let lineNumber = startingLine; + let braceCounter = 0; + do { + // istanbul ignore if + if (lineNumber > lines.length - 1) { + logger.debug(`Malformed Terraform file detected.`); + } + + const line = lines[lineNumber]; + // `{` will be counted wit +1 and `}` with -1. Therefore if we reach braceCounter == 0. We have found the end of the terraform block + const openBrackets = (line.match(/\{/g) || []).length; + const closedBrackets = (line.match(/\}/g) || []).length; + braceCounter = braceCounter + openBrackets - closedBrackets; + + const kvMatch = keyValueExtractionRegex.exec(line); + if (kvMatch && kvMatch.groups.key === 'required_version') { + const dep: PackageDependency = { + currentValue: kvMatch.groups.value, + lineNumber, + managerData: { + terraformDependencyType: TerraformDependencyTypes.terraform_version, + }, + }; + deps.push(dep); + // returning starting line as required_providers are also in the terraform block + // if we would return the position of the required_version line we would potentially skip the providers + return { lineNumber: startingLine, dependencies: deps }; + } + + lineNumber += 1; + } while (braceCounter !== 0); + return null; +} + +export function analyseTerraformVersion(dep: PackageDependency): void { + /* eslint-disable no-param-reassign */ + dep.datasource = datasourceGithubTags.id; + dep.depName = 'hashicorp/terraform'; + dep.extractVersion = 'v(?<version>.*)$'; + /* eslint-enable no-param-reassign */ +} diff --git a/lib/manager/terraform/util.ts b/lib/manager/terraform/util.ts index 0744a8a9221e557ce589a44ab17fc27d65e258dc..d202e54c324bd967022c18a3aa138e2f5a332e2b 100644 --- a/lib/manager/terraform/util.ts +++ b/lib/manager/terraform/util.ts @@ -14,6 +14,7 @@ export enum TerraformDependencyTypes { provider = 'provider', required_providers = 'required_providers', resource = 'resource', + terraform_version = 'terraform_version', } export interface TerraformManagerData { @@ -64,6 +65,9 @@ export function getTerraformDependencyType( case 'resource': { return TerraformDependencyTypes.resource; } + case 'terraform': { + return TerraformDependencyTypes.terraform_version; + } default: { return TerraformDependencyTypes.unknown; }