nx-terraform 0.3.0 → 0.5.0
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/README.md +517 -5
- package/generators.json +5 -0
- package/package.json +1 -1
- package/src/dependencies/createDependencies.d.ts +8 -0
- package/src/dependencies/createDependencies.js +66 -0
- package/src/dependencies/createDependencies.js.map +1 -0
- package/src/dependencies/fileParser.d.ts +33 -0
- package/src/dependencies/fileParser.js +75 -0
- package/src/dependencies/fileParser.js.map +1 -0
- package/src/dependencies/index.d.ts +1 -0
- package/src/dependencies/index.js +6 -0
- package/src/dependencies/index.js.map +1 -0
- package/src/dependencies/utils.d.ts +9 -0
- package/src/dependencies/utils.js +29 -0
- package/src/dependencies/utils.js.map +1 -0
- package/src/generators/init/README.md +90 -0
- package/src/generators/preset/README.md +152 -0
- package/src/generators/preset/generator.js +7 -0
- package/src/generators/preset/generator.js.map +1 -1
- package/src/generators/terraform-backend/README.md +211 -0
- package/src/generators/terraform-backend/files/local-backend/provider.tf +10 -0
- package/src/generators/terraform-backend/schema.json +2 -2
- package/src/generators/terraform-module/README.md +308 -0
- package/src/generators/terraform-module/files/simple-module/README.md__tmpl__ +22 -0
- package/src/generators/terraform-module/files/simple-module/__ignoreFile__ +3 -0
- package/src/generators/terraform-module/files/simple-module/main.tf__tmpl__ +16 -0
- package/src/generators/terraform-module/files/simple-module/outputs.tf +7 -0
- package/src/generators/terraform-module/files/simple-module/variables.tf +7 -0
- package/src/generators/terraform-module/files/stateful-module/README.md__tmpl__ +20 -0
- package/src/generators/terraform-module/files/stateful-module/__ignoreFile__ +3 -0
- package/src/generators/terraform-module/files/stateful-module/backend.tf__tmpl__ +8 -0
- package/src/generators/terraform-module/files/stateful-module/main.tf__tmpl__ +16 -0
- package/src/generators/terraform-module/files/stateful-module/outputs.tf +7 -0
- package/src/generators/terraform-module/files/stateful-module/provider.tf__tmpl__ +22 -0
- package/src/generators/terraform-module/files/stateful-module/variables.tf +7 -0
- package/src/generators/terraform-module/schema.d.ts +14 -0
- package/src/generators/terraform-module/schema.json +37 -0
- package/src/generators/terraform-module/terraform-module.d.ts +4 -0
- package/src/generators/terraform-module/terraform-module.js +49 -0
- package/src/generators/terraform-module/terraform-module.js.map +1 -0
- package/src/index.d.ts +2 -1
- package/src/index.js +2 -1
- package/src/index.js.map +1 -1
- package/src/{inferedTasks.d.ts → targets/createNodes.d.ts} +1 -1
- package/src/{inferedTasks.js → targets/createNodes.js} +5 -5
- package/src/targets/createNodes.js.map +1 -0
- package/src/targets/index.d.ts +1 -5
- package/src/targets/index.js +3 -35
- package/src/targets/index.js.map +1 -1
- package/src/targets/inferedTasks.d.ts +5 -0
- package/src/targets/inferedTasks.js +38 -0
- package/src/targets/inferedTasks.js.map +1 -0
- package/src/types.d.ts +4 -0
- package/src/types.js +3 -0
- package/src/types.js.map +1 -0
- package/src/inferedTasks.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,11 +1,523 @@
|
|
|
1
1
|
# nx-terraform
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
An [Nx](https://nx.dev) plugin for managing Terraform projects within an Nx monorepo. This plugin provides generators, automatic project discovery, and inferred tasks for Terraform infrastructure-as-code projects.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Overview
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
The `nx-terraform` plugin enables you to manage Terraform projects alongside your other code in an Nx monorepo. It provides:
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
- **Automatic Project Discovery**: Automatically discovers Terraform projects based on `main.tf` files
|
|
10
|
+
- **Inferred Tasks**: Automatically creates Terraform targets (init, plan, apply, destroy, validate, fmt, output)
|
|
11
|
+
- **Generators**: Scaffold Terraform backend projects and modules
|
|
12
|
+
- **Target Dependencies**: Smart dependency management between Terraform projects
|
|
13
|
+
- **Caching**: Intelligent caching for safe operations (fmt, validate)
|
|
10
14
|
|
|
11
|
-
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
### For New Workspaces
|
|
18
|
+
|
|
19
|
+
Create a new workspace with Terraform support:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx create-nx-terraform-app my-workspace
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
This creates a new Nx workspace with the `nx-terraform` plugin already configured.
|
|
26
|
+
|
|
27
|
+
### For Existing Workspaces
|
|
28
|
+
|
|
29
|
+
Install the plugin in your existing Nx workspace:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
nx add nx-terraform
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
This will:
|
|
36
|
+
- Add `nx-terraform` as a dependency
|
|
37
|
+
- Register the plugin in `nx.json`
|
|
38
|
+
- Enable automatic Terraform project discovery
|
|
39
|
+
|
|
40
|
+
## Quick Start
|
|
41
|
+
|
|
42
|
+
1. **Initialize the plugin** (if not using `create-nx-terraform-app`):
|
|
43
|
+
```bash
|
|
44
|
+
nx g @nx-terraform/plugin:init
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
2. **Create a Terraform backend project**:
|
|
48
|
+
```bash
|
|
49
|
+
nx g @nx-terraform/plugin:terraform-backend my-backend --backendType=aws-s3
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
3. **Apply the backend** (to create the state storage infrastructure):
|
|
53
|
+
```bash
|
|
54
|
+
nx run my-backend:terraform-apply
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
4. **Create a Terraform module**:
|
|
58
|
+
```bash
|
|
59
|
+
nx g @nx-terraform/plugin:terraform-module my-infra \
|
|
60
|
+
--backendProject=my-backend \
|
|
61
|
+
--backendType=aws-s3
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
5. **Use Terraform targets**:
|
|
65
|
+
```bash
|
|
66
|
+
nx run my-infra:terraform-init
|
|
67
|
+
nx run my-infra:terraform-plan
|
|
68
|
+
nx run my-infra:terraform-apply
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Features
|
|
72
|
+
|
|
73
|
+
### Automatic Project Discovery
|
|
74
|
+
|
|
75
|
+
The plugin automatically discovers Terraform projects by looking for `main.tf` files in your workspace. Projects are detected based on:
|
|
76
|
+
|
|
77
|
+
- **Presence of `main.tf`**: Required for discovery
|
|
78
|
+
- **Project configuration**: Must have `project.json` in the same directory
|
|
79
|
+
- **Project type**: Determined by `projectType` and `metadata` in `project.json`
|
|
80
|
+
|
|
81
|
+
### Inferred Tasks
|
|
82
|
+
|
|
83
|
+
The plugin automatically creates these targets for each Terraform project:
|
|
84
|
+
|
|
85
|
+
- **terraform-init**: Initialize Terraform workspace
|
|
86
|
+
- **terraform-plan**: Create execution plan
|
|
87
|
+
- **terraform-apply**: Apply changes to infrastructure
|
|
88
|
+
- **terraform-destroy**: Destroy infrastructure
|
|
89
|
+
- **terraform-validate**: Validate Terraform configuration
|
|
90
|
+
- **terraform-fmt**: Format Terraform code
|
|
91
|
+
- **terraform-output**: Show Terraform outputs
|
|
92
|
+
|
|
93
|
+
### Project Types
|
|
94
|
+
|
|
95
|
+
The plugin supports three types of Terraform projects:
|
|
96
|
+
|
|
97
|
+
1. **Backend Projects** (`application` without `backendProject` metadata):
|
|
98
|
+
- Manage remote state infrastructure (e.g., S3 bucket, DynamoDB table)
|
|
99
|
+
- Generate `backend.config` files
|
|
100
|
+
- Full target set with caching enabled
|
|
101
|
+
|
|
102
|
+
2. **Stateful Projects** (`application` with `backendProject` metadata):
|
|
103
|
+
- Infrastructure projects that use remote state
|
|
104
|
+
- Reference backend project via `metadata.backendProject`
|
|
105
|
+
- Full target set (no caching for init/plan due to state)
|
|
106
|
+
|
|
107
|
+
3. **Module Projects** (`library`):
|
|
108
|
+
- Reusable Terraform modules
|
|
109
|
+
- No state management
|
|
110
|
+
- Stub targets (modules don't have state)
|
|
111
|
+
|
|
112
|
+
### Smart Dependencies
|
|
113
|
+
|
|
114
|
+
The plugin automatically manages dependencies between Terraform projects using the `createDependencies` API. This creates a project dependency graph that ensures proper execution order.
|
|
115
|
+
|
|
116
|
+
#### Automatic Dependency Detection
|
|
117
|
+
|
|
118
|
+
The plugin automatically detects and creates dependencies in two ways:
|
|
119
|
+
|
|
120
|
+
1. **Backend Project Dependencies**: Projects with `metadata.backendProject` in their `project.json` automatically depend on their backend project. This ensures backend projects are applied before stateful projects initialize.
|
|
121
|
+
|
|
122
|
+
2. **Module Reference Dependencies**: The plugin analyzes `.tf` files to detect module references using local paths (e.g., `source = "../../packages/networking"`). When a module block references another Terraform project, a dependency is automatically created.
|
|
123
|
+
|
|
124
|
+
**How Module Detection Works:**
|
|
125
|
+
- Scans `.tf` files for `module` blocks
|
|
126
|
+
- Extracts `source` attributes that use local paths (`./` or `../`)
|
|
127
|
+
- Matches the last path segment to project names in the workspace
|
|
128
|
+
- Creates static dependencies from the referencing project to the referenced project
|
|
129
|
+
|
|
130
|
+
**Example:**
|
|
131
|
+
```hcl
|
|
132
|
+
# In packages/web-app/main.tf
|
|
133
|
+
module "networking" {
|
|
134
|
+
source = "../../packages/networking"
|
|
135
|
+
# ... module configuration
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
This automatically creates a dependency: `web-app` → `networking`
|
|
140
|
+
|
|
141
|
+
#### Target Dependencies
|
|
142
|
+
|
|
143
|
+
In addition to project dependencies, targets have their own dependencies:
|
|
144
|
+
|
|
145
|
+
- **Backend first**: `terraform-init` depends on `^terraform-apply` (backend must be applied first)
|
|
146
|
+
- **Init before operations**: `terraform-plan`, `terraform-apply`, and `terraform-validate` require `terraform-init`
|
|
147
|
+
- **Plan before apply**: `terraform-apply` depends on `terraform-plan`
|
|
148
|
+
|
|
149
|
+
### Caching
|
|
150
|
+
|
|
151
|
+
Intelligent caching for safe operations:
|
|
152
|
+
|
|
153
|
+
- **Cached**: `terraform-fmt`, `terraform-validate` (when safe)
|
|
154
|
+
- **Non-cached**: `terraform-init`, `terraform-plan`, `terraform-apply` (state-dependent)
|
|
155
|
+
|
|
156
|
+
## Generators
|
|
157
|
+
|
|
158
|
+
The plugin provides four generators:
|
|
159
|
+
|
|
160
|
+
### `init` Generator
|
|
161
|
+
|
|
162
|
+
Registers the `nx-terraform` plugin in your workspace.
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
nx g @nx-terraform/plugin:init
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Documentation**: [`packages/nx-terraform/src/generators/init/README.md`](./src/generators/init/README.md)
|
|
169
|
+
|
|
170
|
+
### `terraform-backend` Generator
|
|
171
|
+
|
|
172
|
+
Creates a Terraform backend project for managing remote state.
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
nx g @nx-terraform/plugin:terraform-backend my-backend --backendType=aws-s3
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Options**:
|
|
179
|
+
- `name`: Backend project name (required)
|
|
180
|
+
- `backendType`: 'aws-s3' or 'local' (required)
|
|
181
|
+
- `bucketNamePrefix`: Prefix for S3 bucket name (optional, AWS S3 only)
|
|
182
|
+
|
|
183
|
+
**Documentation**: [`packages/nx-terraform/src/generators/terraform-backend/README.md`](./src/generators/terraform-backend/README.md)
|
|
184
|
+
|
|
185
|
+
### `terraform-module` Generator
|
|
186
|
+
|
|
187
|
+
Creates Terraform modules (simple library or stateful application).
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
# Simple module (library)
|
|
191
|
+
nx g @nx-terraform/plugin:terraform-module my-module --backendType=local
|
|
192
|
+
|
|
193
|
+
# Stateful module (application)
|
|
194
|
+
nx g @nx-terraform/plugin:terraform-module my-infra \
|
|
195
|
+
--backendProject=my-backend \
|
|
196
|
+
--backendType=aws-s3
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Options**:
|
|
200
|
+
- `name`: Module name (required)
|
|
201
|
+
- `backendType`: 'aws-s3' or 'local' (required)
|
|
202
|
+
- `backendProject`: Backend project name (optional, creates stateful module if provided)
|
|
203
|
+
|
|
204
|
+
**Documentation**: [`packages/nx-terraform/src/generators/terraform-module/README.md`](./src/generators/terraform-module/README.md)
|
|
205
|
+
|
|
206
|
+
### `preset` Generator
|
|
207
|
+
|
|
208
|
+
Initializes workspace with Terraform setup (used by `create-nx-terraform-app`).
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
nx g @nx-terraform/plugin:preset --projectName=terraform-setup --backendType=aws-s3
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
**Documentation**: [`packages/nx-terraform/src/generators/preset/README.md`](./src/generators/preset/README.md)
|
|
215
|
+
|
|
216
|
+
## Targets
|
|
217
|
+
|
|
218
|
+
Each Terraform project automatically gets these targets:
|
|
219
|
+
|
|
220
|
+
### terraform-init
|
|
221
|
+
|
|
222
|
+
Initializes Terraform workspace.
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
nx run my-project:terraform-init
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**Dependencies**: `^terraform-apply` (backend must be applied first)
|
|
229
|
+
|
|
230
|
+
### terraform-plan
|
|
231
|
+
|
|
232
|
+
Creates an execution plan.
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
nx run my-project:terraform-plan
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
**Dependencies**: `terraform-init`
|
|
239
|
+
|
|
240
|
+
**Configurations**: Supports `dev` and `prod` configurations via `-var-file` arguments
|
|
241
|
+
|
|
242
|
+
### terraform-apply
|
|
243
|
+
|
|
244
|
+
Applies changes to infrastructure.
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
nx run my-project:terraform-apply
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
**Dependencies**: `terraform-plan`
|
|
251
|
+
|
|
252
|
+
**Configurations**: Supports `dev` and `prod` configurations
|
|
253
|
+
|
|
254
|
+
### terraform-destroy
|
|
255
|
+
|
|
256
|
+
Destroys infrastructure.
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
nx run my-project:terraform-destroy
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
**Dependencies**: `terraform-init`
|
|
263
|
+
|
|
264
|
+
### terraform-validate
|
|
265
|
+
|
|
266
|
+
Validates Terraform configuration.
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
nx run my-project:terraform-validate
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
**Dependencies**: `terraform-init`
|
|
273
|
+
|
|
274
|
+
**Caching**: Enabled (safe operation)
|
|
275
|
+
|
|
276
|
+
### terraform-fmt
|
|
277
|
+
|
|
278
|
+
Formats Terraform code.
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
nx run my-project:terraform-fmt
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
**Caching**: Enabled (safe operation)
|
|
285
|
+
|
|
286
|
+
### terraform-output
|
|
287
|
+
|
|
288
|
+
Shows Terraform outputs.
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
nx run my-project:terraform-output
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
**Dependencies**: `terraform-init`
|
|
295
|
+
|
|
296
|
+
## Project Structure
|
|
297
|
+
|
|
298
|
+
Terraform projects should follow this structure:
|
|
299
|
+
|
|
300
|
+
```
|
|
301
|
+
packages/
|
|
302
|
+
└── my-terraform-project/
|
|
303
|
+
├── project.json # Nx project configuration
|
|
304
|
+
├── main.tf # Required for discovery
|
|
305
|
+
├── backend.tf # Backend configuration (stateful projects)
|
|
306
|
+
├── provider.tf # Provider requirements
|
|
307
|
+
├── variables.tf # Input variables
|
|
308
|
+
├── outputs.tf # Output values
|
|
309
|
+
├── tfvars/
|
|
310
|
+
│ ├── dev.tfvars # Dev environment variables
|
|
311
|
+
│ └── prod.tfvars # Prod environment variables
|
|
312
|
+
└── backend.config # Generated backend config (backend projects)
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### Project Configuration
|
|
316
|
+
|
|
317
|
+
For **stateful projects**, configure `metadata.backendProject`:
|
|
318
|
+
|
|
319
|
+
```json
|
|
320
|
+
{
|
|
321
|
+
"root": "packages/my-infra",
|
|
322
|
+
"projectType": "application",
|
|
323
|
+
"metadata": {
|
|
324
|
+
"backendProject": "my-backend"
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
## Configuration
|
|
330
|
+
|
|
331
|
+
### Backend Types
|
|
332
|
+
|
|
333
|
+
The plugin supports two backend types:
|
|
334
|
+
|
|
335
|
+
#### AWS S3 Backend
|
|
336
|
+
|
|
337
|
+
Production-ready remote state storage using AWS S3:
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
nx g @nx-terraform/plugin:terraform-backend my-backend --backendType=aws-s3
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
**Features**:
|
|
344
|
+
- Versioning enabled
|
|
345
|
+
- Object lock for state protection
|
|
346
|
+
- Dynamic bucket naming
|
|
347
|
+
- Region detection
|
|
348
|
+
|
|
349
|
+
#### Local Backend
|
|
350
|
+
|
|
351
|
+
Local state files for development:
|
|
352
|
+
|
|
353
|
+
```bash
|
|
354
|
+
nx g @nx-terraform/plugin:terraform-backend my-backend --backendType=local
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
**Use Cases**:
|
|
358
|
+
- Development and testing
|
|
359
|
+
- Single-user scenarios
|
|
360
|
+
- Ephemeral environments
|
|
361
|
+
|
|
362
|
+
### Environment Variables
|
|
363
|
+
|
|
364
|
+
Terraform projects support environment-specific variables via `tfvars` files:
|
|
365
|
+
|
|
366
|
+
- `tfvars/dev.tfvars` - Development environment
|
|
367
|
+
- `tfvars/prod.tfvars` - Production environment
|
|
368
|
+
|
|
369
|
+
Targets automatically use the appropriate `-var-file` argument based on configuration:
|
|
370
|
+
|
|
371
|
+
```bash
|
|
372
|
+
# Uses tfvars/dev.tfvars
|
|
373
|
+
nx run my-project:terraform-plan --configuration=dev
|
|
374
|
+
|
|
375
|
+
# Uses tfvars/prod.tfvars
|
|
376
|
+
nx run my-project:terraform-plan --configuration=prod
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
## Examples
|
|
380
|
+
|
|
381
|
+
### Complete Workflow
|
|
382
|
+
|
|
383
|
+
```bash
|
|
384
|
+
# 1. Create new workspace (creates terraform-setup backend and terraform-infra module)
|
|
385
|
+
npx create-nx-terraform-app my-workspace
|
|
386
|
+
|
|
387
|
+
# 2. Apply backend (from workspace creation)
|
|
388
|
+
cd my-workspace
|
|
389
|
+
nx run terraform-setup:terraform-apply
|
|
390
|
+
|
|
391
|
+
# 3. Plan and apply infrastructure module (already created by preset)
|
|
392
|
+
nx run terraform-infra:terraform-init
|
|
393
|
+
nx run terraform-infra:terraform-plan --configuration=dev
|
|
394
|
+
nx run terraform-infra:terraform-apply --configuration=dev
|
|
395
|
+
|
|
396
|
+
# 4. (Optional) Create additional infrastructure modules
|
|
397
|
+
nx g @nx-terraform/plugin:terraform-module web-infra \
|
|
398
|
+
--backendProject=terraform-setup \
|
|
399
|
+
--backendType=aws-s3
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### Multiple Environments
|
|
403
|
+
|
|
404
|
+
```bash
|
|
405
|
+
# Create dev environment
|
|
406
|
+
nx g @nx-terraform/plugin:terraform-module dev-infra \
|
|
407
|
+
--backendProject=terraform-setup \
|
|
408
|
+
--backendType=aws-s3
|
|
409
|
+
|
|
410
|
+
# Create prod environment
|
|
411
|
+
nx g @nx-terraform/plugin:terraform-module prod-infra \
|
|
412
|
+
--backendProject=terraform-setup \
|
|
413
|
+
--backendType=aws-s3
|
|
414
|
+
|
|
415
|
+
# Deploy to dev
|
|
416
|
+
nx run dev-infra:terraform-plan --configuration=dev
|
|
417
|
+
nx run dev-infra:terraform-apply --configuration=dev
|
|
418
|
+
|
|
419
|
+
# Deploy to prod
|
|
420
|
+
nx run prod-infra:terraform-plan --configuration=prod
|
|
421
|
+
nx run prod-infra:terraform-apply --configuration=prod
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
### Reusable Modules with Automatic Dependencies
|
|
425
|
+
|
|
426
|
+
```bash
|
|
427
|
+
# Create reusable networking module
|
|
428
|
+
nx g @nx-terraform/plugin:terraform-module networking --backendType=local
|
|
429
|
+
|
|
430
|
+
# Create web app that uses the networking module
|
|
431
|
+
nx g @nx-terraform/plugin:terraform-module web-app \
|
|
432
|
+
--backendProject=terraform-setup \
|
|
433
|
+
--backendType=aws-s3
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
Then reference the module in your Terraform code:
|
|
437
|
+
```hcl
|
|
438
|
+
# In packages/web-app/main.tf
|
|
439
|
+
module "networking" {
|
|
440
|
+
source = "../../packages/networking"
|
|
441
|
+
vpc_cidr = "10.0.0.0/16"
|
|
442
|
+
}
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
**Automatic Dependency Detection**: The plugin automatically detects this module reference and creates a project dependency (`web-app` → `networking`). When you run `nx graph`, you'll see the dependency visualized. This ensures `networking` is built/validated before `web-app`.
|
|
446
|
+
|
|
447
|
+
## Project Discovery
|
|
448
|
+
|
|
449
|
+
The plugin automatically discovers Terraform projects using:
|
|
450
|
+
|
|
451
|
+
- **Pattern**: `**/main.tf` (looks for `main.tf` files recursively)
|
|
452
|
+
- **Requirement**: Projects must have `project.json` in the same directory
|
|
453
|
+
- **Type Detection**: Based on `projectType` and `metadata.backendProject`
|
|
454
|
+
|
|
455
|
+
Projects are discovered on workspace load, so new projects are automatically available without restarting Nx.
|
|
456
|
+
|
|
457
|
+
## Caching Strategy
|
|
458
|
+
|
|
459
|
+
Caching behavior varies by project type:
|
|
460
|
+
|
|
461
|
+
### Backend Projects (caching enabled)
|
|
462
|
+
|
|
463
|
+
- **terraform-init**: Cached (backend projects don't depend on external state)
|
|
464
|
+
- **terraform-plan**: Cached
|
|
465
|
+
- **terraform-apply**: Cached
|
|
466
|
+
- **terraform-fmt**: Cached (code formatting is deterministic)
|
|
467
|
+
- **terraform-validate**: Cached (validation results can be cached when inputs haven't changed)
|
|
468
|
+
- **terraform-destroy**: Not cached
|
|
469
|
+
- **terraform-output**: Not cached
|
|
470
|
+
|
|
471
|
+
### Stateful Projects (caching disabled for state-dependent operations)
|
|
472
|
+
|
|
473
|
+
- **terraform-init**: Not cached (state-dependent, requires backend access)
|
|
474
|
+
- **terraform-plan**: Not cached (state-dependent, shows infrastructure changes)
|
|
475
|
+
- **terraform-apply**: Not cached (state-dependent, modifies infrastructure)
|
|
476
|
+
- **terraform-fmt**: Cached (code formatting is deterministic)
|
|
477
|
+
- **terraform-validate**: Cached (validation results can be cached when inputs haven't changed)
|
|
478
|
+
- **terraform-destroy**: Not cached
|
|
479
|
+
- **terraform-output**: Not cached
|
|
480
|
+
|
|
481
|
+
### Module Projects (library)
|
|
482
|
+
|
|
483
|
+
- **terraform-fmt**: Cached
|
|
484
|
+
- **terraform-validate**: Cached
|
|
485
|
+
- **terraform-apply**: Not cached (though modules typically don't use apply)
|
|
486
|
+
- All other targets are stubs (cached but no-op)
|
|
487
|
+
|
|
488
|
+
Cache inputs include:
|
|
489
|
+
- All `.tf` and `.tfvars` files
|
|
490
|
+
- Relevant environment variables
|
|
491
|
+
- Terraform version
|
|
492
|
+
- Provider and backend configuration files
|
|
493
|
+
|
|
494
|
+
## Compatibility
|
|
495
|
+
|
|
496
|
+
- **Nx**: v22.0.2 or compatible
|
|
497
|
+
- **Terraform**: Any version (uses Terraform CLI)
|
|
498
|
+
- **Node.js**: v18+ recommended
|
|
499
|
+
|
|
500
|
+
## Documentation
|
|
501
|
+
|
|
502
|
+
Comprehensive documentation is available for each component:
|
|
503
|
+
|
|
504
|
+
- **Generators**:
|
|
505
|
+
- [`init`](./src/generators/init/README.md) - Plugin initialization
|
|
506
|
+
- [`terraform-backend`](./src/generators/terraform-backend/README.md) - Backend project creation
|
|
507
|
+
- [`terraform-module`](./src/generators/terraform-module/README.md) - Module creation
|
|
508
|
+
- [`preset`](./src/generators/preset/README.md) - Workspace preset
|
|
509
|
+
|
|
510
|
+
- **Workspace Creation**:
|
|
511
|
+
- [`create-nx-terraform-app`](../create-nx-terraform-app/README.md) - CLI tool for workspace creation
|
|
512
|
+
|
|
513
|
+
## Contributing
|
|
514
|
+
|
|
515
|
+
Contributions are welcome! Please see the repository for contribution guidelines.
|
|
516
|
+
|
|
517
|
+
## License
|
|
518
|
+
|
|
519
|
+
MIT
|
|
520
|
+
|
|
521
|
+
## Repository
|
|
522
|
+
|
|
523
|
+
https://github.com/alexpialetski/nx-terraform
|
package/generators.json
CHANGED
|
@@ -15,6 +15,11 @@
|
|
|
15
15
|
"factory": "./src/generators/init/init",
|
|
16
16
|
"schema": "./src/generators/init/schema.json",
|
|
17
17
|
"description": "init generator"
|
|
18
|
+
},
|
|
19
|
+
"terraform-module": {
|
|
20
|
+
"factory": "./src/generators/terraform-module/terraform-module",
|
|
21
|
+
"schema": "./src/generators/terraform-module/schema.json",
|
|
22
|
+
"description": "terraform-module generator"
|
|
18
23
|
}
|
|
19
24
|
}
|
|
20
25
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { CreateDependencies } from '@nx/devkit';
|
|
2
|
+
import { NxTerraformPluginOptions } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Creates dependencies between Terraform projects by:
|
|
5
|
+
* 1. Creating static dependencies from projects to their backend projects (from project.json metadata)
|
|
6
|
+
* 2. Analyzing module references in .tf files (static dependencies)
|
|
7
|
+
*/
|
|
8
|
+
export declare const createDependencies: CreateDependencies<NxTerraformPluginOptions>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createDependencies = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const path = require("node:path");
|
|
6
|
+
const fileParser_1 = require("./fileParser");
|
|
7
|
+
const utils_1 = require("./utils");
|
|
8
|
+
/**
|
|
9
|
+
* Creates dependencies between Terraform projects by:
|
|
10
|
+
* 1. Creating static dependencies from projects to their backend projects (from project.json metadata)
|
|
11
|
+
* 2. Analyzing module references in .tf files (static dependencies)
|
|
12
|
+
*/
|
|
13
|
+
const createDependencies = (_, ctx) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
|
|
14
|
+
var _a, _b;
|
|
15
|
+
const results = [];
|
|
16
|
+
for (const [projectName, projectConfig] of Object.entries(ctx.projects)) {
|
|
17
|
+
// ----------------------------------------------------------------
|
|
18
|
+
// Static dependencies from projects to their backend projects
|
|
19
|
+
// ----------------------------------------------------------------
|
|
20
|
+
const backendProject = (_a = projectConfig.metadata) === null || _a === void 0 ? void 0 : _a.backendProject;
|
|
21
|
+
if (backendProject) {
|
|
22
|
+
// Verify backend project exists
|
|
23
|
+
if (ctx.projects[backendProject]) {
|
|
24
|
+
(0, utils_1.validateAndAddDependency)((0, utils_1.createStaticDependency)(projectName, backendProject, path.join(projectConfig.root, 'project.json')), ctx, results);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// ----------------------------------------------------------------
|
|
28
|
+
// Static dependencies from projects to their module projects
|
|
29
|
+
// ----------------------------------------------------------------
|
|
30
|
+
// Find .tf files to process in this project (only changed files)
|
|
31
|
+
const tfFilesToProcess = (0, fileParser_1.getTerraformFilesToProcess)((_b = ctx.filesToProcess.projectFileMap[projectName]) !== null && _b !== void 0 ? _b : []);
|
|
32
|
+
for (const file of tfFilesToProcess) {
|
|
33
|
+
const filePath = path.join(ctx.workspaceRoot, file.file);
|
|
34
|
+
// Read and parse the Terraform file
|
|
35
|
+
const { content: fileContent, success: readSuccess } = (0, fileParser_1.readTerraformFile)(filePath, file.file);
|
|
36
|
+
if (!readSuccess) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const { parsed, success: parseSuccess } = yield (0, fileParser_1.parseTerraformFile)(file.file, fileContent);
|
|
40
|
+
if (!parseSuccess) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
// Extract module blocks and process each one
|
|
44
|
+
for (const { source: sourcePath } of (0, fileParser_1.extractModuleBlocks)(parsed)) {
|
|
45
|
+
// Only process local paths (./ or ../)
|
|
46
|
+
if (!(0, fileParser_1.isLocalPath)(sourcePath)) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
// Extract the last segment of the path as the potential project name
|
|
50
|
+
const potentialProjectName = sourcePath.split('/').pop();
|
|
51
|
+
// Check if the last segment matches a project name
|
|
52
|
+
const targetProject = ctx.projects[potentialProjectName]
|
|
53
|
+
? potentialProjectName
|
|
54
|
+
: undefined;
|
|
55
|
+
// Skip if no target project found or if it's a self-reference
|
|
56
|
+
if (!targetProject || targetProject === projectName) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
(0, utils_1.validateAndAddDependency)((0, utils_1.createStaticDependency)(projectName, targetProject, file.file), ctx, results);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return results;
|
|
64
|
+
});
|
|
65
|
+
exports.createDependencies = createDependencies;
|
|
66
|
+
//# sourceMappingURL=createDependencies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createDependencies.js","sourceRoot":"","sources":["../../../../../packages/nx-terraform/src/dependencies/createDependencies.ts"],"names":[],"mappings":";;;;AAKA,kCAAkC;AAElC,6CAMsB;AACtB,mCAA2E;AAE3E;;;;GAIG;AACI,MAAM,kBAAkB,GAE3B,CAAO,CAAC,EAAE,GAA8B,EAAE,EAAE;;IAC9C,MAAM,OAAO,GAAgC,EAAE,CAAC;IAEhD,KAAK,MAAM,CAAC,WAAW,EAAE,aAAa,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxE,mEAAmE;QACnE,8DAA8D;QAC9D,mEAAmE;QACnE,MAAM,cAAc,GAAG,MAAA,aAAa,CAAC,QAAQ,0CAAE,cAAc,CAAC;QAE9D,IAAI,cAAc,EAAE,CAAC;YACnB,gCAAgC;YAChC,IAAI,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;gBACjC,IAAA,gCAAwB,EACtB,IAAA,8BAAsB,EACpB,WAAW,EACX,cAAc,EACd,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,cAAc,CAAC,CAC9C,EACD,GAAG,EACH,OAAO,CACR,CAAC;YACJ,CAAC;QACH,CAAC;QAED,mEAAmE;QACnE,6DAA6D;QAC7D,mEAAmE;QAEnE,iEAAiE;QACjE,MAAM,gBAAgB,GAAG,IAAA,uCAA0B,EACjD,MAAA,GAAG,CAAC,cAAc,CAAC,cAAc,CAAC,WAAW,CAAC,mCAAI,EAAE,CACrD,CAAC;QAEF,KAAK,MAAM,IAAI,IAAI,gBAAgB,EAAE,CAAC;YACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;YAEzD,oCAAoC;YACpC,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,IAAA,8BAAiB,EACtE,QAAQ,EACR,IAAI,CAAC,IAAI,CACV,CAAC;YACF,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,SAAS;YACX,CAAC;YAED,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM,IAAA,+BAAkB,EAChE,IAAI,CAAC,IAAI,EACT,WAAW,CACZ,CAAC;YACF,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,SAAS;YACX,CAAC;YAED,6CAA6C;YAC7C,KAAK,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,IAAA,gCAAmB,EAAC,MAAM,CAAC,EAAE,CAAC;gBACjE,uCAAuC;gBACvC,IAAI,CAAC,IAAA,wBAAW,EAAC,UAAU,CAAC,EAAE,CAAC;oBAC7B,SAAS;gBACX,CAAC;gBAED,qEAAqE;gBACrE,MAAM,oBAAoB,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;gBAEzD,mDAAmD;gBACnD,MAAM,aAAa,GAAG,GAAG,CAAC,QAAQ,CAAC,oBAAoB,CAAC;oBACtD,CAAC,CAAC,oBAAoB;oBACtB,CAAC,CAAC,SAAS,CAAC;gBAEd,8DAA8D;gBAC9D,IAAI,CAAC,aAAa,IAAI,aAAa,KAAK,WAAW,EAAE,CAAC;oBACpD,SAAS;gBACX,CAAC;gBAED,IAAA,gCAAwB,EACtB,IAAA,8BAAsB,EAAC,WAAW,EAAE,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC,EAC7D,GAAG,EACH,OAAO,CACR,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC,CAAA,CAAC;AArFW,QAAA,kBAAkB,sBAqF7B"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads a Terraform file and returns its content
|
|
3
|
+
*/
|
|
4
|
+
export declare function readTerraformFile(filePath: string, relativePath: string): {
|
|
5
|
+
content: string;
|
|
6
|
+
success: boolean;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Parses HCL content into a JSON structure
|
|
10
|
+
*/
|
|
11
|
+
export declare function parseTerraformFile(fileName: string, content: string): Promise<{
|
|
12
|
+
parsed: any;
|
|
13
|
+
success: boolean;
|
|
14
|
+
}>;
|
|
15
|
+
/**
|
|
16
|
+
* Extracts module blocks from parsed HCL structure
|
|
17
|
+
*/
|
|
18
|
+
export declare function extractModuleBlocks(parsed: any): Array<{
|
|
19
|
+
moduleName: string;
|
|
20
|
+
source: string;
|
|
21
|
+
}>;
|
|
22
|
+
/**
|
|
23
|
+
* Gets all .tf files to process for a project
|
|
24
|
+
*/
|
|
25
|
+
export declare function getTerraformFilesToProcess(filesToProcess: Array<{
|
|
26
|
+
file: string;
|
|
27
|
+
}>): Array<{
|
|
28
|
+
file: string;
|
|
29
|
+
}>;
|
|
30
|
+
/**
|
|
31
|
+
* Checks if a path is a local path (starts with ./ or ../)
|
|
32
|
+
*/
|
|
33
|
+
export declare function isLocalPath(sourcePath: string): boolean;
|