@cdktn/hcl2cdk 0.24.0-pre.45 → 0.24.0-pre.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +355 -0
- package/README.md +1 -1
- package/build/__tests__/expressions.test.js +10 -19
- package/build/__tests__/functions.test.js +8 -18
- package/build/__tests__/testHelpers.js +3 -2
- package/build/coerceType.js +11 -21
- package/build/dynamic-blocks.js +3 -3
- package/build/expressions.js +13 -22
- package/build/function-bindings/functions.generated.js +2 -2
- package/build/generation.js +24 -34
- package/build/index.js +15 -25
- package/build/iteration.js +7 -6
- package/build/jsii-rosetta-workarounds.js +6 -5
- package/build/partialCode.js +11 -20
- package/build/provider.js +4 -3
- package/build/references.js +6 -5
- package/build/schema.js +8 -18
- package/build/terraformSchema.js +4 -4
- package/build/utils.js +3 -3
- package/build/variables.js +12 -21
- package/package.json +20 -17
- package/package.sh +1 -1
- package/src/__tests__/coerceType.test.ts +207 -0
- package/src/__tests__/expressionToTs.test.ts +1167 -0
- package/src/__tests__/expressions.test.ts +541 -0
- package/src/__tests__/findExpressionType.test.ts +112 -0
- package/src/__tests__/functions.test.ts +768 -0
- package/src/__tests__/generation.test.ts +72 -0
- package/src/__tests__/jsii-rosetta-workarounds.test.ts +145 -0
- package/src/__tests__/partialCode.test.ts +432 -0
- package/src/__tests__/terraformSchema.test.ts +107 -0
- package/src/__tests__/testHelpers.ts +11 -0
- package/src/coerceType.ts +261 -0
- package/src/dynamic-blocks.ts +61 -0
- package/src/expressions.ts +968 -0
- package/src/function-bindings/functions.generated.ts +1139 -0
- package/src/function-bindings/functions.ts +104 -0
- package/src/generation.ts +1189 -0
- package/src/index.ts +584 -0
- package/src/iteration.ts +156 -0
- package/src/jsii-rosetta-workarounds.ts +145 -0
- package/src/partialCode.ts +132 -0
- package/src/provider.ts +60 -0
- package/src/references.ts +193 -0
- package/src/schema.ts +74 -0
- package/src/terraformSchema.ts +182 -0
- package/src/types.ts +58 -0
- package/src/utils.ts +19 -0
- package/src/variables.ts +214 -0
- package/test/__snapshots__/backends.test.ts.snap +70 -0
- package/test/__snapshots__/externals.test.ts.snap +37 -0
- package/test/__snapshots__/granular-imports.test.ts.snap +180 -0
- package/test/__snapshots__/imports.test.ts.snap +159 -0
- package/test/__snapshots__/iteration.test.ts.snap +532 -0
- package/test/__snapshots__/jsiiLanguage.test.ts.snap +347 -0
- package/test/__snapshots__/locals.test.ts.snap +55 -0
- package/test/__snapshots__/modules.test.ts.snap +127 -0
- package/test/__snapshots__/outputs.test.ts.snap +77 -0
- package/test/__snapshots__/partialCode.test.ts.snap +120 -0
- package/test/__snapshots__/provider.test.ts.snap +128 -0
- package/test/__snapshots__/references.test.ts.snap +376 -0
- package/test/__snapshots__/resource-meta-properties.test.ts.snap +342 -0
- package/test/__snapshots__/resources.test.ts.snap +613 -0
- package/test/__snapshots__/tfExpressions.test.ts.snap +537 -0
- package/test/__snapshots__/typeCoercion.test.ts.snap +253 -0
- package/test/__snapshots__/variables.test.ts.snap +150 -0
- package/test/backends.test.ts +75 -0
- package/test/convertProject.test.ts +257 -0
- package/test/externals.test.ts +35 -0
- package/test/globalSetup.ts +224 -0
- package/test/globalTeardown.ts +11 -0
- package/test/granular-imports.test.ts +161 -0
- package/test/hcl2cdk.test.ts +88 -0
- package/test/helpers/convert.ts +543 -0
- package/test/helpers/tmp.ts +25 -0
- package/test/imports.test.ts +141 -0
- package/test/iteration.test.ts +342 -0
- package/test/jsiiLanguage.test.ts +73 -0
- package/test/locals.test.ts +47 -0
- package/test/modules.test.ts +143 -0
- package/test/outputs.test.ts +69 -0
- package/test/partialCode.test.ts +25 -0
- package/test/provider.test.ts +106 -0
- package/test/references.test.ts +287 -0
- package/test/resource-meta-properties.test.ts +288 -0
- package/test/resources.test.ts +551 -0
- package/test/tfExpressions.test.ts +300 -0
- package/test/typeCoercion.test.ts +154 -0
- package/test/variables.test.ts +96 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
// Copyright (c) HashiCorp, Inc
|
|
2
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
3
|
+
import * as fs from "fs";
|
|
4
|
+
import * as path from "path";
|
|
5
|
+
import { execSync } from "child_process";
|
|
6
|
+
import {
|
|
7
|
+
LANGUAGES,
|
|
8
|
+
TerraformProviderConstraint,
|
|
9
|
+
ConstructsMakerProviderTarget,
|
|
10
|
+
} from "@cdktn/commons";
|
|
11
|
+
import { readSchema } from "@cdktn/provider-schema";
|
|
12
|
+
import { convertProject, getTerraformConfigFromDir } from "../src";
|
|
13
|
+
import { createTmpHelper } from "./helpers/tmp";
|
|
14
|
+
|
|
15
|
+
const tmp = createTmpHelper();
|
|
16
|
+
|
|
17
|
+
const providerRequirements = ["kreuzwerker/docker@ ~>2.15.0"];
|
|
18
|
+
const CDKTF_CLI = path.resolve(
|
|
19
|
+
__dirname,
|
|
20
|
+
"..",
|
|
21
|
+
"..",
|
|
22
|
+
"..",
|
|
23
|
+
"..",
|
|
24
|
+
"packages",
|
|
25
|
+
"cdktn-cli",
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const createFiles = (cwd: string, files: [string, string][]) => {
|
|
29
|
+
files.forEach(([p, content]) => {
|
|
30
|
+
fs.writeFileSync(path.resolve(cwd, p), content, "utf8");
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const createTSCdkProject = (cwd: string) =>
|
|
35
|
+
createFiles(cwd, [
|
|
36
|
+
[
|
|
37
|
+
"cdktf.json",
|
|
38
|
+
`{
|
|
39
|
+
"language": "typescript",
|
|
40
|
+
"app": "npm run --silent compile && node main.js",
|
|
41
|
+
"terraformProviders": [],
|
|
42
|
+
"terraformModules": [],
|
|
43
|
+
"context": {}}`,
|
|
44
|
+
],
|
|
45
|
+
[
|
|
46
|
+
"main.ts",
|
|
47
|
+
`import { Construct } from "constructs";
|
|
48
|
+
import { App, TerraformStack } from "cdktn";
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class MyStack extends TerraformStack {
|
|
52
|
+
constructor(scope: Construct, name: string) {
|
|
53
|
+
super(scope, name);
|
|
54
|
+
|
|
55
|
+
// define resources here
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const app = new App();
|
|
60
|
+
new MyStack(app, "converted");
|
|
61
|
+
app.synth();`,
|
|
62
|
+
],
|
|
63
|
+
[
|
|
64
|
+
"package.json",
|
|
65
|
+
`{
|
|
66
|
+
"name": "converted",
|
|
67
|
+
"version": "1.0.0",
|
|
68
|
+
"main": "main.js",
|
|
69
|
+
"types": "main.ts",
|
|
70
|
+
"license": "MPL-2.0",
|
|
71
|
+
"private": true,
|
|
72
|
+
"scripts": {
|
|
73
|
+
"get": "cdktn get",
|
|
74
|
+
"build": "tsc",
|
|
75
|
+
"synth": "cdktn synth",
|
|
76
|
+
"compile": "tsc --pretty",
|
|
77
|
+
"watch": "tsc -w",
|
|
78
|
+
"test": "echo ok",
|
|
79
|
+
"upgrade": "npm i cdktn@latest cdktn-cli@latest",
|
|
80
|
+
"upgrade:next": "npm i cdktn@next cdktn-cli@next"
|
|
81
|
+
},
|
|
82
|
+
"engines": {
|
|
83
|
+
"node": ">=20.9"
|
|
84
|
+
},
|
|
85
|
+
"dependencies": {
|
|
86
|
+
"cdktn": "latest",
|
|
87
|
+
"constructs": "^10.3.0"
|
|
88
|
+
},
|
|
89
|
+
"devDependencies": {
|
|
90
|
+
"@types/node": "^14.0.26",
|
|
91
|
+
"typescript": "^5.4.5",
|
|
92
|
+
"cdktn-cli": "${CDKTF_CLI}"
|
|
93
|
+
}
|
|
94
|
+
}`,
|
|
95
|
+
],
|
|
96
|
+
[
|
|
97
|
+
"tsconfig.json",
|
|
98
|
+
`{
|
|
99
|
+
"compilerOptions": {
|
|
100
|
+
"alwaysStrict": true,
|
|
101
|
+
"declaration": true,
|
|
102
|
+
"experimentalDecorators": true,
|
|
103
|
+
"inlineSourceMap": true,
|
|
104
|
+
"inlineSources": true,
|
|
105
|
+
"lib": [
|
|
106
|
+
"es2018"
|
|
107
|
+
],
|
|
108
|
+
"module": "CommonJS",
|
|
109
|
+
"noEmitOnError": true,
|
|
110
|
+
"noFallthroughCasesInSwitch": true,
|
|
111
|
+
"noImplicitAny": true,
|
|
112
|
+
"noImplicitReturns": true,
|
|
113
|
+
"noImplicitThis": true,
|
|
114
|
+
"noUnusedLocals": true,
|
|
115
|
+
"noUnusedParameters": true,
|
|
116
|
+
"resolveJsonModule": true,
|
|
117
|
+
"strict": true,
|
|
118
|
+
"strictNullChecks": true,
|
|
119
|
+
"strictPropertyInitialization": true,
|
|
120
|
+
"stripInternal": true,
|
|
121
|
+
"target": "ES2018"
|
|
122
|
+
},
|
|
123
|
+
"include": [
|
|
124
|
+
"**/*.ts"
|
|
125
|
+
],
|
|
126
|
+
"exclude": [
|
|
127
|
+
"node_modules"
|
|
128
|
+
]
|
|
129
|
+
}`,
|
|
130
|
+
],
|
|
131
|
+
]);
|
|
132
|
+
|
|
133
|
+
const terraformProject = (files: [string, string][]) => {
|
|
134
|
+
const dir = tmp("cdktf-convert.");
|
|
135
|
+
createFiles(dir, files);
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
importPath: dir,
|
|
139
|
+
targetPath: tmp("cdktf-converted."),
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const exec = (command: string, cwd: string) =>
|
|
144
|
+
execSync(command, {
|
|
145
|
+
cwd,
|
|
146
|
+
...(process.env.VERBOSE === "true" ? { stdio: "inherit" } : {}),
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
const getTerraformPlan = (cwd: string) => {
|
|
150
|
+
exec(`terraform init`, cwd);
|
|
151
|
+
exec(`terraform plan -out planfile`, cwd);
|
|
152
|
+
exec(`terraform show -json planfile > plan.json`, cwd);
|
|
153
|
+
|
|
154
|
+
return JSON.parse(fs.readFileSync(path.resolve(cwd, "plan.json"), "utf8"));
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const getCdkPlan = (cwd: string) => {
|
|
158
|
+
exec(`npm install`, cwd);
|
|
159
|
+
exec(`npm run get`, cwd);
|
|
160
|
+
exec(`npm run synth`, cwd);
|
|
161
|
+
|
|
162
|
+
return getTerraformPlan(path.resolve(cwd, "cdktf.out/stacks/converted/"));
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
function resources(plan: any) {
|
|
166
|
+
return plan.planned_values.root_module.resources.map((item: any) => ({
|
|
167
|
+
type: item.type,
|
|
168
|
+
provider_name: item.provider_name,
|
|
169
|
+
values: item.values,
|
|
170
|
+
}));
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
let cachedProviderSchema: any;
|
|
174
|
+
describe.skip("convertProject", () => {
|
|
175
|
+
beforeAll(async () => {
|
|
176
|
+
// Get all the provider schemas
|
|
177
|
+
const { providerSchema } = await readSchema(
|
|
178
|
+
providerRequirements.map((spec) =>
|
|
179
|
+
ConstructsMakerProviderTarget.from(
|
|
180
|
+
new TerraformProviderConstraint(spec),
|
|
181
|
+
LANGUAGES[0],
|
|
182
|
+
),
|
|
183
|
+
),
|
|
184
|
+
);
|
|
185
|
+
cachedProviderSchema = providerSchema;
|
|
186
|
+
});
|
|
187
|
+
it("has a similar plan", async () => {
|
|
188
|
+
const { importPath, targetPath } = terraformProject([
|
|
189
|
+
[
|
|
190
|
+
"main.tf",
|
|
191
|
+
`terraform {
|
|
192
|
+
required_providers {
|
|
193
|
+
docker = {
|
|
194
|
+
source = "kreuzwerker/docker"
|
|
195
|
+
version = "2.14.0"
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
provider "docker" {
|
|
201
|
+
host = "unix:///var/run/docker.sock"
|
|
202
|
+
}`,
|
|
203
|
+
],
|
|
204
|
+
[
|
|
205
|
+
"container.tf",
|
|
206
|
+
`resource "docker_image" "ubuntu" {
|
|
207
|
+
name = "ubuntu:latest"
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
resource "docker_container" "foo" {
|
|
211
|
+
image = docker_image.ubuntu.latest
|
|
212
|
+
name = "foo"
|
|
213
|
+
}`,
|
|
214
|
+
],
|
|
215
|
+
[
|
|
216
|
+
"cluster.tf",
|
|
217
|
+
`module "k3s" {
|
|
218
|
+
source = "camptocamp/k3s/docker"
|
|
219
|
+
version = "0.11.0"
|
|
220
|
+
|
|
221
|
+
cluster_endpoint = ""
|
|
222
|
+
cluster_name = "cdktf"
|
|
223
|
+
network_name = ""
|
|
224
|
+
}`,
|
|
225
|
+
],
|
|
226
|
+
]);
|
|
227
|
+
|
|
228
|
+
const previousPlan = getTerraformPlan(importPath);
|
|
229
|
+
createTSCdkProject(targetPath);
|
|
230
|
+
const mainTs = fs.readFileSync(path.resolve(targetPath, "main.ts"), "utf8");
|
|
231
|
+
|
|
232
|
+
const { code, cdktfJson } = await convertProject(
|
|
233
|
+
getTerraformConfigFromDir(importPath),
|
|
234
|
+
{
|
|
235
|
+
language: "typescript",
|
|
236
|
+
providerSchema: cachedProviderSchema,
|
|
237
|
+
},
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
fs.writeFileSync(path.resolve(targetPath, "main.ts"), code(mainTs), "utf8");
|
|
241
|
+
fs.writeFileSync(
|
|
242
|
+
path.resolve(targetPath, "cdktf.json"),
|
|
243
|
+
JSON.stringify(
|
|
244
|
+
cdktfJson(
|
|
245
|
+
JSON.parse(
|
|
246
|
+
fs.readFileSync(path.resolve(targetPath, "cdktf.json"), "utf-8"),
|
|
247
|
+
),
|
|
248
|
+
),
|
|
249
|
+
),
|
|
250
|
+
"utf8",
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
const currentPlan = getCdkPlan(targetPath);
|
|
254
|
+
|
|
255
|
+
expect(resources(currentPlan)).toEqual(resources(previousPlan));
|
|
256
|
+
});
|
|
257
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) HashiCorp, Inc.
|
|
3
|
+
* SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { testCase, Synth, binding, Snapshot } from "./helpers/convert";
|
|
7
|
+
|
|
8
|
+
describe("externals", () => {
|
|
9
|
+
testCase.test(
|
|
10
|
+
"handle simple external data",
|
|
11
|
+
`
|
|
12
|
+
provider "external" {
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
variable "fargate_region" {
|
|
16
|
+
type = string
|
|
17
|
+
default = "us-east-1"
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
data "external" "thumbprint" {
|
|
21
|
+
program = ["\${path.module}/oidc_thumbprint.sh", var.fargate_region]
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
output "foo" {
|
|
25
|
+
value = data.external.thumbprint.result.thumbprint
|
|
26
|
+
}
|
|
27
|
+
`,
|
|
28
|
+
[binding.external],
|
|
29
|
+
Snapshot.yes,
|
|
30
|
+
Synth.yes,
|
|
31
|
+
{
|
|
32
|
+
dataSources: ["external"],
|
|
33
|
+
},
|
|
34
|
+
);
|
|
35
|
+
});
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
// Copyright (c) HashiCorp, Inc
|
|
2
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
3
|
+
import * as fs from "fs-extra";
|
|
4
|
+
import * as path from "path";
|
|
5
|
+
import * as os from "os";
|
|
6
|
+
import execa from "execa";
|
|
7
|
+
import { readSchema } from "@cdktn/provider-schema";
|
|
8
|
+
import {
|
|
9
|
+
TerraformProviderConstraint,
|
|
10
|
+
TerraformModuleConstraint,
|
|
11
|
+
} from "@cdktn/commons";
|
|
12
|
+
|
|
13
|
+
const cdktnBin = path.join(__dirname, "../../../cdktn-cli/bin/cdktn");
|
|
14
|
+
const cdktnDist = path.join(__dirname, "../../../../dist");
|
|
15
|
+
|
|
16
|
+
const includeSynthTests = Boolean(process.env.CI);
|
|
17
|
+
|
|
18
|
+
enum ProviderType {
|
|
19
|
+
provider,
|
|
20
|
+
module,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type ProviderDefinition = {
|
|
24
|
+
fqn: string;
|
|
25
|
+
type: ProviderType;
|
|
26
|
+
path: string;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const bindings: Record<string, ProviderDefinition> = {
|
|
30
|
+
aws: {
|
|
31
|
+
fqn: "hashicorp/aws@=5.11.0",
|
|
32
|
+
type: ProviderType.provider,
|
|
33
|
+
path: "providers/aws",
|
|
34
|
+
},
|
|
35
|
+
docker: {
|
|
36
|
+
fqn: "kreuzwerker/docker@=3.0.1",
|
|
37
|
+
type: ProviderType.provider,
|
|
38
|
+
path: "providers/docker",
|
|
39
|
+
},
|
|
40
|
+
null: {
|
|
41
|
+
fqn: "hashicorp/null@=3.2.1",
|
|
42
|
+
type: ProviderType.provider,
|
|
43
|
+
path: "providers/null",
|
|
44
|
+
},
|
|
45
|
+
google: {
|
|
46
|
+
fqn: "hashicorp/google@=4.55.0",
|
|
47
|
+
type: ProviderType.provider,
|
|
48
|
+
path: "providers/google",
|
|
49
|
+
},
|
|
50
|
+
azuread: {
|
|
51
|
+
fqn: "hashicorp/azuread@=2.36.0",
|
|
52
|
+
type: ProviderType.provider,
|
|
53
|
+
path: "providers/azuread",
|
|
54
|
+
},
|
|
55
|
+
local: {
|
|
56
|
+
fqn: "hashicorp/local@=2.3.0",
|
|
57
|
+
type: ProviderType.provider,
|
|
58
|
+
path: "providers/local",
|
|
59
|
+
},
|
|
60
|
+
auth0: {
|
|
61
|
+
fqn: "alexkappa/auth0@=0.26.2",
|
|
62
|
+
type: ProviderType.provider,
|
|
63
|
+
path: "providers/auth0",
|
|
64
|
+
},
|
|
65
|
+
datadog: {
|
|
66
|
+
fqn: "DataDog/datadog@=3.21.0",
|
|
67
|
+
type: ProviderType.provider,
|
|
68
|
+
path: "providers/datadog",
|
|
69
|
+
},
|
|
70
|
+
kubernetes: {
|
|
71
|
+
fqn: "hashicorp/kubernetes@=2.18.0",
|
|
72
|
+
type: ProviderType.provider,
|
|
73
|
+
path: "providers/kubernetes",
|
|
74
|
+
},
|
|
75
|
+
scaleway: {
|
|
76
|
+
fqn: "scaleway/scaleway@ ~>2.10.0",
|
|
77
|
+
type: ProviderType.provider,
|
|
78
|
+
path: "providers/scaleway",
|
|
79
|
+
},
|
|
80
|
+
external: {
|
|
81
|
+
fqn: "hashicorp/external@=2.3.1",
|
|
82
|
+
type: ProviderType.provider,
|
|
83
|
+
path: "providers/external",
|
|
84
|
+
},
|
|
85
|
+
awsVpc: {
|
|
86
|
+
fqn: "terraform-aws-modules/vpc/aws@=3.19.0",
|
|
87
|
+
type: ProviderType.module,
|
|
88
|
+
path: "modules/terraform-aws-modules/aws",
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Generates TypeScript bindings for one provider or module by running `cdktn get` in a fresh temp dir under
|
|
94
|
+
* `parentDir`, and returns the absolute path to the generated `.gen/<binding.path>` subtree. The temp dir lives under
|
|
95
|
+
* `parentDir` (the fixtures root) so `globalTeardown` reclaims it along with the rest of the fixtures.
|
|
96
|
+
*
|
|
97
|
+
* @param binding The provider or module to generate bindings for (fqn, type, path inside `.gen`).
|
|
98
|
+
* @param parentDir Parent directory under which the per-binding temp dir is created — pass `fixturesDir` so cleanup
|
|
99
|
+
* happens via `globalTeardown`.
|
|
100
|
+
* @returns Absolute path to the generated binding root (i.e. `<tempDir>/.gen/<binding.path>`).
|
|
101
|
+
*/
|
|
102
|
+
async function generateBinding(
|
|
103
|
+
binding: ProviderDefinition,
|
|
104
|
+
parentDir: string,
|
|
105
|
+
): Promise<string> {
|
|
106
|
+
const tempDir = await fs.mkdtemp(path.join(parentDir, "cdktf-provider-"));
|
|
107
|
+
await fs.writeFile(
|
|
108
|
+
path.resolve(tempDir, "cdktf.json"),
|
|
109
|
+
JSON.stringify({
|
|
110
|
+
language: "typescript",
|
|
111
|
+
app: "npx ts-node main.ts",
|
|
112
|
+
terraformProviders:
|
|
113
|
+
binding.type === ProviderType.provider ? [binding.fqn] : [],
|
|
114
|
+
terraformModules:
|
|
115
|
+
binding.type === ProviderType.module ? [binding.fqn] : [],
|
|
116
|
+
}),
|
|
117
|
+
);
|
|
118
|
+
await execa(cdktnBin, ["get"], { cwd: tempDir });
|
|
119
|
+
|
|
120
|
+
return path.resolve(tempDir, ".gen", binding.path);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Initialises a fresh CDKTN project for the given language by running `cdktn init --local --template=<language>` in a
|
|
125
|
+
* new temp dir under `parentDir`, and returns the absolute path to that project. The project is treated as a read-only
|
|
126
|
+
* base — each test gets its own provisioned copy via `copyBaseProject` (which symlinks the heavy `node_modules`).
|
|
127
|
+
*
|
|
128
|
+
* @param language Template to initialise (e.g. `typescript`, `python`, `csharp`).
|
|
129
|
+
* @param parentDir Parent directory under which the per-language temp project dir is created — pass `fixturesDir` so
|
|
130
|
+
* cleanup happens via `globalTeardown`.
|
|
131
|
+
* @returns Absolute path to the initialised base project.
|
|
132
|
+
*/
|
|
133
|
+
async function prepareBaseProject(
|
|
134
|
+
language: string,
|
|
135
|
+
parentDir: string,
|
|
136
|
+
): Promise<string> {
|
|
137
|
+
const projectDir = await fs.mkdtemp(
|
|
138
|
+
path.join(parentDir, "cdktf-convert-base-"),
|
|
139
|
+
);
|
|
140
|
+
await execa(
|
|
141
|
+
cdktnBin,
|
|
142
|
+
[
|
|
143
|
+
"init",
|
|
144
|
+
"--local",
|
|
145
|
+
`--dist=${cdktnDist}`,
|
|
146
|
+
"--project-name='hello'",
|
|
147
|
+
"--project-description='world'",
|
|
148
|
+
`--template=${language}`,
|
|
149
|
+
"--enable-crash-reporting=false",
|
|
150
|
+
],
|
|
151
|
+
{
|
|
152
|
+
cwd: projectDir,
|
|
153
|
+
},
|
|
154
|
+
);
|
|
155
|
+
return projectDir;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export interface FixturesManifest {
|
|
159
|
+
providerBindings: Record<string, string>; // fqn -> absolute path to generated binding dir
|
|
160
|
+
baseProjects: Record<string, string>; // language -> absolute path to base project dir
|
|
161
|
+
schemaCacheDir: string; // absolute path to pre-populated provider schema cache
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
module.exports = async function globalSetup() {
|
|
165
|
+
const fixturesDir = await fs.mkdtemp(
|
|
166
|
+
path.join(os.tmpdir(), "hcl2cdk-fixtures-"),
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
console.log("[globalSetup] Generating provider bindings...");
|
|
170
|
+
const bindingEntries = Object.values(bindings);
|
|
171
|
+
const bindingResults = await Promise.all(
|
|
172
|
+
bindingEntries.map(async (b) => {
|
|
173
|
+
const absolutePath = await generateBinding(b, fixturesDir);
|
|
174
|
+
return [b.fqn, absolutePath] as [string, string];
|
|
175
|
+
}),
|
|
176
|
+
);
|
|
177
|
+
const providerBindings = Object.fromEntries(bindingResults);
|
|
178
|
+
|
|
179
|
+
const requiredLanguages = includeSynthTests
|
|
180
|
+
? ["typescript", "python", "csharp"]
|
|
181
|
+
: ["typescript"];
|
|
182
|
+
|
|
183
|
+
console.log(
|
|
184
|
+
`[globalSetup] Initializing base projects for: ${requiredLanguages.join(", ")}...`,
|
|
185
|
+
);
|
|
186
|
+
const baseProjectEntries = await Promise.all(
|
|
187
|
+
requiredLanguages.map(async (lang) => {
|
|
188
|
+
const projectDir = await prepareBaseProject(lang, fixturesDir);
|
|
189
|
+
return [lang, projectDir] as [string, string];
|
|
190
|
+
}),
|
|
191
|
+
);
|
|
192
|
+
const baseProjects = Object.fromEntries(baseProjectEntries);
|
|
193
|
+
|
|
194
|
+
// Pre-cache provider schemas so test workers never need to run terraform
|
|
195
|
+
const schemaCacheDir = path.join(fixturesDir, "schema-cache");
|
|
196
|
+
await fs.mkdirp(schemaCacheDir);
|
|
197
|
+
|
|
198
|
+
console.log("[globalSetup] Pre-caching provider schemas...");
|
|
199
|
+
await Promise.all(
|
|
200
|
+
bindingEntries.map(async (entry) => {
|
|
201
|
+
const constraint =
|
|
202
|
+
entry.type === ProviderType.provider
|
|
203
|
+
? new TerraformProviderConstraint(entry.fqn)
|
|
204
|
+
: new TerraformModuleConstraint(entry.fqn);
|
|
205
|
+
await readSchema([constraint], schemaCacheDir);
|
|
206
|
+
}),
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
const manifest: FixturesManifest = {
|
|
210
|
+
providerBindings,
|
|
211
|
+
baseProjects,
|
|
212
|
+
schemaCacheDir,
|
|
213
|
+
};
|
|
214
|
+
const manifestPath = path.join(fixturesDir, "manifest.json");
|
|
215
|
+
await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2));
|
|
216
|
+
|
|
217
|
+
// Pass to test workers via environment variables
|
|
218
|
+
// (Jest 29 propagates parent env to forked workers)
|
|
219
|
+
process.env.HCL2CDK_FIXTURES_MANIFEST = manifestPath;
|
|
220
|
+
process.env.CDKTF_EXPERIMENTAL_PROVIDER_SCHEMA_CACHE_PATH = schemaCacheDir;
|
|
221
|
+
process.env.HCL2CDK_FIXTURES_DIR = fixturesDir;
|
|
222
|
+
|
|
223
|
+
console.log(`[globalSetup] Fixtures manifest written to ${manifestPath}`);
|
|
224
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Copyright (c) HashiCorp, Inc
|
|
2
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
3
|
+
import * as fs from "fs-extra";
|
|
4
|
+
|
|
5
|
+
module.exports = async function globalTeardown() {
|
|
6
|
+
const fixturesDir = process.env.HCL2CDK_FIXTURES_DIR;
|
|
7
|
+
if (fixturesDir) {
|
|
8
|
+
console.log(`[globalTeardown] Cleaning up fixtures at ${fixturesDir}`);
|
|
9
|
+
await fs.remove(fixturesDir);
|
|
10
|
+
}
|
|
11
|
+
};
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// Copyright (c) HashiCorp, Inc
|
|
2
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
3
|
+
import { testCase, Synth, binding, Snapshot } from "./helpers/convert";
|
|
4
|
+
|
|
5
|
+
describe("granular-imports", () => {
|
|
6
|
+
testCase.test(
|
|
7
|
+
"nested sub-structs",
|
|
8
|
+
`
|
|
9
|
+
provider "kubernetes" {
|
|
10
|
+
}
|
|
11
|
+
resource "kubernetes_deployment" "example" {
|
|
12
|
+
metadata {
|
|
13
|
+
name = "terraform-example"
|
|
14
|
+
labels = {
|
|
15
|
+
test = "MyExampleApp"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
spec {
|
|
20
|
+
replicas = 3
|
|
21
|
+
|
|
22
|
+
selector {
|
|
23
|
+
match_labels = {
|
|
24
|
+
test = "MyExampleApp"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
template {
|
|
29
|
+
metadata {
|
|
30
|
+
labels = {
|
|
31
|
+
test = "MyExampleApp"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
spec {
|
|
36
|
+
container {
|
|
37
|
+
image = "nginx:1.21.6"
|
|
38
|
+
name = "example"
|
|
39
|
+
|
|
40
|
+
resources {
|
|
41
|
+
limits = {
|
|
42
|
+
cpu = "0.5"
|
|
43
|
+
memory = "512Mi"
|
|
44
|
+
}
|
|
45
|
+
requests = {
|
|
46
|
+
cpu = "250m"
|
|
47
|
+
memory = "50Mi"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
liveness_probe {
|
|
52
|
+
http_get {
|
|
53
|
+
path = "/"
|
|
54
|
+
port = 80
|
|
55
|
+
|
|
56
|
+
http_header {
|
|
57
|
+
name = "X-Custom-Header"
|
|
58
|
+
value = "Awesome"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
initial_delay_seconds = 3
|
|
63
|
+
period_seconds = 3
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
`,
|
|
71
|
+
[binding.kubernetes],
|
|
72
|
+
Snapshot.yes,
|
|
73
|
+
Synth.yes_but_only_typescript_right_now_because_it_breaks,
|
|
74
|
+
{
|
|
75
|
+
resources: ["kubernetes_deployment"],
|
|
76
|
+
},
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
testCase.test(
|
|
80
|
+
"should handle most cdktf and provider constructs for granular imports",
|
|
81
|
+
`
|
|
82
|
+
terraform {
|
|
83
|
+
backend "remote" {
|
|
84
|
+
organization = "example_corp"
|
|
85
|
+
|
|
86
|
+
workspaces {
|
|
87
|
+
name = "my-app-prod"
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
provider "google" {
|
|
93
|
+
project = "my-project"
|
|
94
|
+
region = "us-central1"
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
provider "local" {}
|
|
98
|
+
|
|
99
|
+
resource "google_compute_autoscaler" "example" {
|
|
100
|
+
name = "example-autoscaler"
|
|
101
|
+
zone = "us-east1-b"
|
|
102
|
+
target = "target-for-example-autoscaler"
|
|
103
|
+
count = 2
|
|
104
|
+
|
|
105
|
+
autoscaling_policy = {
|
|
106
|
+
max_replicas = 8
|
|
107
|
+
min_replicas = 2
|
|
108
|
+
cooldown_period = 60
|
|
109
|
+
|
|
110
|
+
cpu_utilization = {
|
|
111
|
+
target = 0.5
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
resource "google_compute_instance_group_manager" "default" {
|
|
117
|
+
name = "my-igm"
|
|
118
|
+
zone = "us-central1-f"
|
|
119
|
+
|
|
120
|
+
version {
|
|
121
|
+
instance_template = 1
|
|
122
|
+
name = "primary"
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
target_pools = []
|
|
126
|
+
base_instance_name = "autoscaler-sample"
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
resource "google_compute_autoscaler" "default" {
|
|
130
|
+
name = "my-autoscaler"
|
|
131
|
+
zone = "us-central1-f"
|
|
132
|
+
target = google_compute_instance_group_manager.default.id
|
|
133
|
+
|
|
134
|
+
autoscaling_policy {
|
|
135
|
+
max_replicas = 5 + 2
|
|
136
|
+
min_replicas = 1
|
|
137
|
+
cooldown_period = 60
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
variable "image_id" {
|
|
142
|
+
type = string
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
output "image_id" {
|
|
146
|
+
value = var.image_id
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
data "local_file" "foo" {
|
|
150
|
+
filename = "./\${var.image_id}.img"
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
`,
|
|
154
|
+
[binding.google, binding.local],
|
|
155
|
+
Snapshot.yes,
|
|
156
|
+
Synth.yes,
|
|
157
|
+
{
|
|
158
|
+
resources: ["google_compute_autoscaler", "local_file"],
|
|
159
|
+
},
|
|
160
|
+
);
|
|
161
|
+
});
|