diff --git a/lib/datasource/terraform-module/__fixtures__/service-custom-discovery.json b/lib/datasource/terraform-module/__fixtures__/service-custom-discovery.json new file mode 100644 index 00000000000000..6b3cbb2141db6b --- /dev/null +++ b/lib/datasource/terraform-module/__fixtures__/service-custom-discovery.json @@ -0,0 +1,8 @@ +{ + "modules.v1": "/api/registry/v1/modules/", + "state.v2": "/api/v2/", + "tfe.v2": "/api/v2/", + "tfe.v2.1": "/api/v2/", + "tfe.v2.2": "/api/v2/", + "versions.v1": "https://checkpoint-api.hashicorp.com/v1/versions/" +} diff --git a/lib/datasource/terraform-module/__fixtures__/service-discovery.json b/lib/datasource/terraform-module/__fixtures__/service-discovery.json new file mode 100644 index 00000000000000..db3cc145ea3c03 --- /dev/null +++ b/lib/datasource/terraform-module/__fixtures__/service-discovery.json @@ -0,0 +1,4 @@ +{ + "modules.v1": "/v1/modules/", + "providers.v1": "/v1/providers/" +} diff --git a/lib/datasource/terraform-module/__snapshots__/index.spec.ts.snap b/lib/datasource/terraform-module/__snapshots__/index.spec.ts.snap index f325481abea80d..c898411c25f8c2 100644 --- a/lib/datasource/terraform-module/__snapshots__/index.spec.ts.snap +++ b/lib/datasource/terraform-module/__snapshots__/index.spec.ts.snap @@ -82,6 +82,16 @@ Object { exports[`datasource/terraform-module getReleases processes real data 2`] = ` Array [ + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "host": "registry.terraform.io", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://registry.terraform.io/.well-known/terraform.json", + }, Object { "headers": Object { "accept": "application/json", @@ -95,6 +105,110 @@ Array [ ] `; +exports[`datasource/terraform-module getReleases processes real data on changed subpath 1`] = ` +Object { + "name": "hashicorp/consul/aws", + "releases": Array [ + Object { + "version": "0.0.1", + }, + Object { + "version": "0.0.2", + }, + Object { + "version": "0.0.3", + }, + Object { + "version": "0.0.4", + }, + Object { + "version": "0.0.5", + }, + Object { + "version": "0.1.0", + }, + Object { + "version": "0.1.1", + }, + Object { + "version": "0.1.2", + }, + Object { + "version": "0.2.0", + }, + Object { + "version": "0.2.1", + }, + Object { + "version": "0.2.2", + }, + Object { + "version": "0.3.0", + }, + Object { + "version": "0.3.1", + }, + Object { + "version": "0.3.2", + }, + Object { + "version": "0.3.3", + }, + Object { + "version": "0.3.4", + }, + Object { + "version": "0.3.5", + }, + Object { + "version": "0.3.6", + }, + Object { + "version": "0.3.7", + }, + Object { + "version": "0.3.8", + }, + Object { + "version": "0.3.9", + }, + Object { + "version": "0.3.10", + }, + Object { + "version": "0.4.0", + }, + ], + "sourceUrl": "https://github.com/hashicorp/terraform-aws-consul", + "versions": Object {}, +} +`; + +exports[`datasource/terraform-module getReleases processes real data on changed subpath 2`] = ` +Array [ + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "host": "terraform.foo.bar", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://terraform.foo.bar/.well-known/terraform.json", + }, + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "host": "terraform.foo.bar", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://terraform.foo.bar/api/registry/v1/modules/hashicorp/consul/aws", + }, +] +`; + exports[`datasource/terraform-module getReleases processes with registry in name 1`] = ` Object { "homepage": "https://registry.terraform.io/modules/hashicorp/consul/aws", @@ -177,6 +291,16 @@ Object { exports[`datasource/terraform-module getReleases processes with registry in name 2`] = ` Array [ + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "host": "registry.terraform.io", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://registry.terraform.io/.well-known/terraform.json", + }, Object { "headers": Object { "accept": "application/json", @@ -192,6 +316,16 @@ Array [ exports[`datasource/terraform-module getReleases rejects mismatch 1`] = ` Array [ + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "host": "terraform.company.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://terraform.company.com/.well-known/terraform.json", + }, Object { "headers": Object { "accept": "application/json", @@ -205,8 +339,33 @@ Array [ ] `; +exports[`datasource/terraform-module getReleases rejects servicediscovery 1`] = ` +Array [ + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "host": "terraform.company.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://terraform.company.com/.well-known/terraform.json", + }, +] +`; + exports[`datasource/terraform-module getReleases returns null for 404 1`] = ` Array [ + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "host": "registry.terraform.io", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://registry.terraform.io/.well-known/terraform.json", + }, Object { "headers": Object { "accept": "application/json", @@ -222,6 +381,16 @@ Array [ exports[`datasource/terraform-module getReleases returns null for empty result 1`] = ` Array [ + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "host": "registry.terraform.io", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://registry.terraform.io/.well-known/terraform.json", + }, Object { "headers": Object { "accept": "application/json", @@ -237,6 +406,16 @@ Array [ exports[`datasource/terraform-module getReleases returns null for unknown error 1`] = ` Array [ + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "host": "registry.terraform.io", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://registry.terraform.io/.well-known/terraform.json", + }, Object { "headers": Object { "accept": "application/json", diff --git a/lib/datasource/terraform-module/index.spec.ts b/lib/datasource/terraform-module/index.spec.ts index df5e7c7b6c29fc..a5d7a0f1331d22 100644 --- a/lib/datasource/terraform-module/index.spec.ts +++ b/lib/datasource/terraform-module/index.spec.ts @@ -6,8 +6,15 @@ import { id as datasource } from '.'; const consulData: any = fs.readFileSync( 'lib/datasource/terraform-module/__fixtures__/registry-consul.json' ); +const serviceDiscoveryResult: any = fs.readFileSync( + 'lib/datasource/terraform-module/__fixtures__/service-discovery.json' +); +const serviceDiscoveryCustomResult: any = fs.readFileSync( + 'lib/datasource/terraform-module/__fixtures__/service-custom-discovery.json' +); const baseUrl = 'https://registry.terraform.io'; +const localTerraformEnterprisebaseUrl = 'https://terraform.foo.bar'; describe('datasource/terraform-module', () => { describe('getReleases', () => { @@ -24,7 +31,9 @@ describe('datasource/terraform-module', () => { httpMock .scope(baseUrl) .get('/v1/modules/hashicorp/consul/aws') - .reply(200, {}); + .reply(200, {}) + .get('/.well-known/terraform.json') + .reply(200, serviceDiscoveryResult); expect( await getPkgReleases({ datasource, @@ -37,7 +46,9 @@ describe('datasource/terraform-module', () => { httpMock .scope(baseUrl) .get('/v1/modules/hashicorp/consul/aws') - .reply(404, {}); + .reply(404, {}) + .get('/.well-known/terraform.json') + .reply(200, serviceDiscoveryResult); expect( await getPkgReleases({ datasource, @@ -50,7 +61,9 @@ describe('datasource/terraform-module', () => { httpMock .scope(baseUrl) .get('/v1/modules/hashicorp/consul/aws') - .replyWithError(''); + .replyWithError('') + .get('/.well-known/terraform.json') + .reply(200, serviceDiscoveryResult); expect( await getPkgReleases({ datasource, @@ -63,7 +76,9 @@ describe('datasource/terraform-module', () => { httpMock .scope(baseUrl) .get('/v1/modules/hashicorp/consul/aws') - .reply(200, consulData); + .reply(200, consulData) + .get('/.well-known/terraform.json') + .reply(200, serviceDiscoveryResult); const res = await getPkgReleases({ datasource, depName: 'hashicorp/consul/aws', @@ -76,7 +91,9 @@ describe('datasource/terraform-module', () => { httpMock .scope(baseUrl) .get('/v1/modules/hashicorp/consul/aws') - .reply(200, consulData); + .reply(200, consulData) + .get('/.well-known/terraform.json') + .reply(200, serviceDiscoveryResult); const res = await getPkgReleases({ datasource, depName: 'registry.terraform.io/hashicorp/consul/aws', @@ -89,7 +106,9 @@ describe('datasource/terraform-module', () => { httpMock .scope('https://terraform.company.com') .get('/v1/modules/consul/foo') - .reply(200, consulData); + .reply(200, consulData) + .get('/.well-known/terraform.json') + .reply(200, serviceDiscoveryResult); const res = await getPkgReleases({ datasource, depName: 'consul/foo', @@ -98,5 +117,34 @@ describe('datasource/terraform-module', () => { expect(res).toBeNull(); expect(httpMock.getTrace()).toMatchSnapshot(); }); + it('rejects servicediscovery', async () => { + httpMock + .scope('https://terraform.company.com') + .get('/.well-known/terraform.json') + .reply(404); + const res = await getPkgReleases({ + datasource, + depName: 'consul/foo', + registryUrls: ['https://terraform.company.com'], + }); + expect(res).toBeNull(); + expect(httpMock.getTrace()).toMatchSnapshot(); + }); + it('processes real data on changed subpath', async () => { + httpMock + .scope(localTerraformEnterprisebaseUrl) + .get('/api/registry/v1/modules/hashicorp/consul/aws') + .reply(200, consulData) + .get('/.well-known/terraform.json') + .reply(200, serviceDiscoveryCustomResult); + const res = await getPkgReleases({ + datasource, + registryUrls: ['terraform.foo.bar'], + depName: 'hashicorp/consul/aws', + }); + expect(res).toMatchSnapshot(); + expect(res).not.toBeNull(); + expect(httpMock.getTrace()).toMatchSnapshot(); + }); }); }); diff --git a/lib/datasource/terraform-module/index.ts b/lib/datasource/terraform-module/index.ts index 50c7a7b90d016e..d096500a603a5c 100644 --- a/lib/datasource/terraform-module/index.ts +++ b/lib/datasource/terraform-module/index.ts @@ -45,6 +45,38 @@ interface TerraformRelease { versions: string[]; } +export interface ServiceDiscoveryResult { + 'modules.v1'?: string; + 'providers.v1'?: string; +} + +export async function getTerraformServiceDiscoveryResult( + registryUrl: string +): Promise { + const discoveryURL = `${registryUrl}/.well-known/terraform.json`; + const cacheNamespace = 'terraform-service-discovery'; + const cachedResult = await packageCache.get( + cacheNamespace, + registryUrl + ); + // istanbul ignore if + if (cachedResult) { + return cachedResult; + } + const serviceDiscovery = ( + await http.getJson(discoveryURL) + ).body; + + const cacheMinutes = 1440; // 24h + await packageCache.set( + cacheNamespace, + registryUrl, + serviceDiscovery, + cacheMinutes + ); + + return serviceDiscovery; +} /** * terraform.getReleases * @@ -65,16 +97,20 @@ export async function getReleases({ 'terraform.getDependencies()' ); const cacheNamespace = 'terraform-module'; - const pkgUrl = `${registry}/v1/modules/${repository}`; + const cacheURL = `${registry}/${repository}`; const cachedResult = await packageCache.get( cacheNamespace, - pkgUrl + cacheURL ); // istanbul ignore if if (cachedResult) { return cachedResult; } try { + const serviceDiscovery = await getTerraformServiceDiscoveryResult( + registryUrl + ); + const pkgUrl = `${registry}${serviceDiscovery['modules.v1']}${repository}`; const res = (await http.getJson(pkgUrl)).body; const returnedName = res.namespace + '/' + res.name + '/' + res.provider; if (returnedName !== repository) { diff --git a/lib/datasource/terraform-provider/__fixtures__/service-discovery.json b/lib/datasource/terraform-provider/__fixtures__/service-discovery.json new file mode 100644 index 00000000000000..db3cc145ea3c03 --- /dev/null +++ b/lib/datasource/terraform-provider/__fixtures__/service-discovery.json @@ -0,0 +1,4 @@ +{ + "modules.v1": "/v1/modules/", + "providers.v1": "/v1/providers/" +} diff --git a/lib/datasource/terraform-provider/__snapshots__/index.spec.ts.snap b/lib/datasource/terraform-provider/__snapshots__/index.spec.ts.snap index 577c59d31c1a48..cc8000d12f97d7 100644 --- a/lib/datasource/terraform-provider/__snapshots__/index.spec.ts.snap +++ b/lib/datasource/terraform-provider/__snapshots__/index.spec.ts.snap @@ -20,6 +20,16 @@ Object { exports[`datasource/terraform getReleases processes data with alternative backend 2`] = ` Array [ + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "host": "registry.terraform.io", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://registry.terraform.io/.well-known/terraform.json", + }, Object { "headers": Object { "accept": "application/json", @@ -251,6 +261,16 @@ Object { exports[`datasource/terraform getReleases processes real data 2`] = ` Array [ + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "host": "registry.terraform.io", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://registry.terraform.io/.well-known/terraform.json", + }, Object { "headers": Object { "accept": "application/json", @@ -266,6 +286,16 @@ Array [ exports[`datasource/terraform getReleases returns null for 404 1`] = ` Array [ + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "host": "registry.terraform.io", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://registry.terraform.io/.well-known/terraform.json", + }, Object { "headers": Object { "accept": "application/json", @@ -291,6 +321,16 @@ Array [ exports[`datasource/terraform getReleases returns null for empty result 1`] = ` Array [ + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "host": "registry.terraform.io", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://registry.terraform.io/.well-known/terraform.json", + }, Object { "headers": Object { "accept": "application/json", @@ -314,8 +354,43 @@ Array [ ] `; +exports[`datasource/terraform getReleases returns null for error in service discovery 1`] = ` +Array [ + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "host": "registry.terraform.io", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://registry.terraform.io/.well-known/terraform.json", + }, + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "host": "releases.hashicorp.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://releases.hashicorp.com/index.json", + }, +] +`; + exports[`datasource/terraform getReleases returns null for unknown error 1`] = ` Array [ + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "host": "registry.terraform.io", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://registry.terraform.io/.well-known/terraform.json", + }, Object { "headers": Object { "accept": "application/json", diff --git a/lib/datasource/terraform-provider/index.spec.ts b/lib/datasource/terraform-provider/index.spec.ts index e4e37cc9b1f578..53c750c492035a 100644 --- a/lib/datasource/terraform-provider/index.spec.ts +++ b/lib/datasource/terraform-provider/index.spec.ts @@ -9,6 +9,9 @@ const consulData: any = fs.readFileSync( const hashicorpReleases: any = fs.readFileSync( 'lib/datasource/terraform-provider/__fixtures__/releaseBackendIndex.json' ); +const serviceDiscoveryResult: any = fs.readFileSync( + 'lib/datasource/terraform-module/__fixtures__/service-discovery.json' +); const primaryUrl = defaultRegistryUrls[0]; const secondaryUrl = defaultRegistryUrls[1]; @@ -28,7 +31,9 @@ describe('datasource/terraform', () => { httpMock .scope(primaryUrl) .get('/v1/providers/hashicorp/azurerm') - .reply(200, {}); + .reply(200, {}) + .get('/.well-known/terraform.json') + .reply(200, serviceDiscoveryResult); httpMock.scope(secondaryUrl).get('/index.json').reply(200, {}); expect( await getPkgReleases({ @@ -42,7 +47,9 @@ describe('datasource/terraform', () => { httpMock .scope(primaryUrl) .get('/v1/providers/hashicorp/azurerm') - .reply(404); + .reply(404) + .get('/.well-known/terraform.json') + .reply(200, serviceDiscoveryResult); httpMock.scope(secondaryUrl).get('/index.json').reply(404); expect( await getPkgReleases({ @@ -56,7 +63,9 @@ describe('datasource/terraform', () => { httpMock .scope(primaryUrl) .get('/v1/providers/hashicorp/azurerm') - .replyWithError(''); + .replyWithError('') + .get('/.well-known/terraform.json') + .reply(200, serviceDiscoveryResult); httpMock.scope(secondaryUrl).get('/index.json').replyWithError(''); expect( await getPkgReleases({ @@ -70,7 +79,9 @@ describe('datasource/terraform', () => { httpMock .scope(primaryUrl) .get('/v1/providers/hashicorp/azurerm') - .reply(200, JSON.parse(consulData)); + .reply(200, JSON.parse(consulData)) + .get('/.well-known/terraform.json') + .reply(200, serviceDiscoveryResult); const res = await getPkgReleases({ datasource, depName: 'azurerm', @@ -85,7 +96,9 @@ describe('datasource/terraform', () => { .get('/v1/providers/hashicorp/google-beta') .reply(404, { errors: ['Not Found'], - }); + }) + .get('/.well-known/terraform.json') + .reply(200, serviceDiscoveryResult); httpMock .scope(secondaryUrl) .get('/index.json') @@ -105,7 +118,9 @@ describe('datasource/terraform', () => { .get('/v1/providers/hashicorp/google-beta') .reply(404, { errors: ['Not Found'], - }); + }) + .get('/.well-known/terraform.json') + .reply(200, serviceDiscoveryResult); httpMock.scope(secondaryUrl).get('/index.json').reply(404); const res = await getPkgReleases({ @@ -115,5 +130,16 @@ describe('datasource/terraform', () => { expect(res).toMatchSnapshot(); expect(res).toBeNull(); }); + it('returns null for error in service discovery', async () => { + httpMock.scope(primaryUrl).get('/.well-known/terraform.json').reply(404); + httpMock.scope(secondaryUrl).get('/index.json').replyWithError(''); + expect( + await getPkgReleases({ + datasource, + depName: 'azurerm', + }) + ).toBeNull(); + expect(httpMock.getTrace()).toMatchSnapshot(); + }); }); }); diff --git a/lib/datasource/terraform-provider/index.ts b/lib/datasource/terraform-provider/index.ts index 1ee32ca991cab6..f97a3608482243 100644 --- a/lib/datasource/terraform-provider/index.ts +++ b/lib/datasource/terraform-provider/index.ts @@ -3,6 +3,7 @@ import { logger } from '../../logger'; import * as packageCache from '../../util/cache/package'; import { Http } from '../../util/http'; import { GetReleasesConfig, ReleaseResult } from '../common'; +import { getTerraformServiceDiscoveryResult } from '../terraform-module'; export const id = 'terraform-provider'; export const defaultRegistryUrls = [ @@ -37,7 +38,10 @@ async function queryRegistry( registryURL: string, repository: string ): Promise { - const backendURL = `${registryURL}/v1/providers/${repository}`; + const serviceDiscovery = await getTerraformServiceDiscoveryResult( + registryURL + ); + const backendURL = `${registryURL}${serviceDiscovery['providers.v1']}${repository}`; const res = (await http.getJson(backendURL)).body; const dep: ReleaseResult = { name: repository, @@ -103,10 +107,10 @@ export async function getReleases({ logger.debug({ lookupName }, 'terraform-provider.getDependencies()'); let dep: ReleaseResult = null; const registryHost = URL.parse(registryUrl).host; - if (registryHost === 'registry.terraform.io') { - dep = await queryRegistry(lookupName, registryUrl, repository); - } else if (registryHost === 'releases.hashicorp.com') { + if (registryHost === 'releases.hashicorp.com') { dep = await queryReleaseBackend(lookupName, registryUrl, repository); + } else { + dep = await queryRegistry(lookupName, registryUrl, repository); } const cacheMinutes = 30; await packageCache.set(cacheNamespace, pkgUrl, dep, cacheMinutes); diff --git a/lib/manager/terraform/__snapshots__/extract.spec.ts.snap b/lib/manager/terraform/__snapshots__/extract.spec.ts.snap index 2d3476bb075324..6f4f5802a08fae 100644 --- a/lib/manager/terraform/__snapshots__/extract.spec.ts.snap +++ b/lib/manager/terraform/__snapshots__/extract.spec.ts.snap @@ -154,6 +154,9 @@ Object { "depName": "app.terraform.io/example-corp/k8s-cluster/azurerm", "depNameShort": "app.terraform.io/example-corp/k8s-cluster/azurerm", "depType": "terraform", + "registryUrls": Array [ + "https://app.terraform.io", + ], }, Object { "currentValue": "~> 1.1", @@ -161,6 +164,9 @@ Object { "depName": "app.terraform.io/example-corp/k8s-cluster/azurerm", "depNameShort": "app.terraform.io/example-corp/k8s-cluster/azurerm", "depType": "terraform", + "registryUrls": Array [ + "https://app.terraform.io", + ], }, Object { "currentValue": "~~ 1.1", @@ -168,6 +174,9 @@ Object { "depName": "app.terraform.io/example-corp/k8s-cluster/azurerm", "depNameShort": "app.terraform.io/example-corp/k8s-cluster/azurerm", "depType": "terraform", + "registryUrls": Array [ + "https://app.terraform.io", + ], }, Object { "currentValue": ">= 1.0.0, <= 2.0.0", diff --git a/lib/manager/terraform/modules.ts b/lib/manager/terraform/modules.ts index 9c84b94d0af38e..87b8cd07c7e9e2 100644 --- a/lib/manager/terraform/modules.ts +++ b/lib/manager/terraform/modules.ts @@ -10,6 +10,7 @@ import { ExtractionResult, TerraformDependencyTypes } from './util'; const githubRefMatchRegex = /github.com([/:])(?[^/]+\/[a-z0-9-.]+).*\?ref=(?.*)$/; const gitTagsRefMatchRegex = /(?:git::)?(?(?:http|https|ssh):\/\/(?:.*@)?(?.*.*\/(?.*\/.*)))\?ref=(?.*)$/; +const hostnameMatchRegex = /^(?([\w|\d]+\.)+[\w|\d]+)/; export function extractTerraformModule( startingLine: number, @@ -62,6 +63,10 @@ export function analyseTerraformModule(dep: PackageDependency): void { if (moduleParts[0] === '..') { dep.skipReason = SkipReason.Local; } else if (moduleParts.length >= 3) { + const hostnameMatch = hostnameMatchRegex.exec(dep.managerData.source); + if (hostnameMatch) { + dep.registryUrls = [`https://${hostnameMatch.groups.hostname}`]; + } dep.depType = 'terraform'; dep.depName = moduleParts.join('/'); dep.depNameShort = dep.depName;