/
index.ts
144 lines (134 loc) · 3.6 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import { logger } from '../../logger';
import * as globalCache from '../../util/cache/global';
import { Http } from '../../util/http';
import { DatasourceError, GetReleasesConfig, ReleaseResult } from '../common';
export const id = 'terraform-provider';
const http = new Http(id);
interface TerraformProvider {
namespace: string;
name: string;
provider: string;
source?: string;
versions: string[];
}
interface TerraformProviderReleaseBackend {
[key: string]: {
name: string;
versions: VersionsReleaseBackend;
};
}
interface VersionsReleaseBackend {
[key: string]: Record<string, any>;
}
async function queryRegistry(
lookupName: string,
backendURL: string,
repository: string
): Promise<ReleaseResult> {
try {
const res = (await http.getJson<TerraformProvider>(backendURL)).body;
const dep: ReleaseResult = {
name: repository,
versions: {},
releases: null,
};
if (res.source) {
dep.sourceUrl = res.source;
}
dep.releases = res.versions.map((version) => ({
version,
}));
dep.homepage = `https://registry.terraform.io/providers/${repository}`;
logger.trace({ dep }, 'dep');
return dep;
} catch (err) {
logger.debug(
{ lookupName },
`Terraform registry ("registry.terraform.io") lookup failure: not found`
);
logger.debug({
err,
});
return null;
}
}
async function queryReleaseBackend(
lookupName: string,
backendURL: string,
repository: string
): Promise<ReleaseResult> {
const backendLookUpName = `terraform-provider-${lookupName}`;
try {
const res = (
await http.getJson<TerraformProviderReleaseBackend>(backendURL)
).body;
const dep: ReleaseResult = {
name: repository,
versions: {},
releases: null,
};
dep.releases = Object.keys(res[backendLookUpName].versions).map(
(version) => ({
version,
})
);
logger.trace({ dep }, 'dep');
return dep;
} catch (err) {
logger.debug(
{ lookupName },
`Terraform registry ("releases.hashicorp.com") lookup failure: not found`
);
logger.debug({
err,
});
return null;
}
}
/**
* terraform-provider.getReleases
*
* This function will fetch a provider from the public Terraform registry and return all semver versions.
*/
export async function getReleases({
lookupName,
registryUrls,
}: GetReleasesConfig): Promise<ReleaseResult | null> {
const repository = `hashicorp/${lookupName}`;
const releasesBackendURL = `https://releases.hashicorp.com/index.json`;
const registryBackendURL = `https://registry.terraform.io/v1/providers/${repository}`;
logger.debug({ lookupName }, 'terraform-provider.getDependencies()');
const cacheNamespace = 'terraform-providers';
const cacheMinutes = 30;
const cachedResult = await globalCache.get<ReleaseResult>(
cacheNamespace,
lookupName
);
// istanbul ignore if
if (cachedResult) {
return cachedResult;
}
try {
let dep = await queryRegistry(lookupName, registryBackendURL, repository);
if (dep) {
await globalCache.set(cacheNamespace, lookupName, dep, cacheMinutes);
return dep;
}
dep = await queryReleaseBackend(lookupName, releasesBackendURL, repository);
if (dep) {
await globalCache.set(cacheNamespace, lookupName, dep, cacheMinutes);
}
return dep;
} catch (err) {
const failureCodes = ['EAI_AGAIN'];
// istanbul ignore if
if (failureCodes.includes(err.code)) {
throw new DatasourceError(err);
}
logger.warn(
{ err, lookupName },
'Terraform registry failure: Unknown error'
);
return null;
}
}