@quadnix/octo 0.0.30 → 0.1.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/LICENSE +661 -0
- package/README.md +25 -3
- package/dist/app.type.d.ts +143 -4
- package/dist/app.type.js +80 -9
- package/dist/app.type.js.map +1 -1
- package/dist/decorators/action.decorator.d.ts +10 -6
- package/dist/decorators/action.decorator.js +19 -6
- package/dist/decorators/action.decorator.js.map +1 -1
- package/dist/decorators/anchor.decorator.d.ts +12 -5
- package/dist/decorators/anchor.decorator.js +12 -5
- package/dist/decorators/anchor.decorator.js.map +1 -1
- package/dist/decorators/enable-hook.decorator.d.ts +1 -1
- package/dist/decorators/enable-hook.decorator.js +1 -1
- package/dist/decorators/factory.decorator.d.ts +18 -34
- package/dist/decorators/factory.decorator.js +18 -34
- package/dist/decorators/factory.decorator.js.map +1 -1
- package/dist/decorators/model.decorator.d.ts +1 -1
- package/dist/decorators/model.decorator.js +1 -1
- package/dist/decorators/module.decorator.d.ts +16 -10
- package/dist/decorators/module.decorator.js +16 -10
- package/dist/decorators/module.decorator.js.map +1 -1
- package/dist/decorators/on-event.decorator.d.ts +5 -0
- package/dist/decorators/on-event.decorator.js +5 -0
- package/dist/decorators/on-event.decorator.js.map +1 -1
- package/dist/decorators/validate.decorator.d.ts +15 -1
- package/dist/decorators/validate.decorator.js +15 -1
- package/dist/decorators/validate.decorator.js.map +1 -1
- package/dist/errors/container.error.d.ts +18 -0
- package/dist/errors/container.error.js +18 -0
- package/dist/errors/container.error.js.map +1 -1
- package/dist/errors/index.d.ts +1 -0
- package/dist/errors/index.js +1 -0
- package/dist/errors/index.js.map +1 -1
- package/dist/errors/module.error.d.ts +6 -0
- package/dist/errors/module.error.js +6 -0
- package/dist/errors/module.error.js.map +1 -1
- package/dist/errors/node.error.d.ts +56 -0
- package/dist/errors/node.error.js +56 -0
- package/dist/errors/node.error.js.map +1 -1
- package/dist/errors/schema.error.d.ts +6 -0
- package/dist/errors/schema.error.js +6 -0
- package/dist/errors/schema.error.js.map +1 -1
- package/dist/errors/terraform.error.d.ts +19 -0
- package/dist/errors/terraform.error.js +23 -0
- package/dist/errors/terraform.error.js.map +1 -0
- package/dist/errors/transaction.error.d.ts +61 -0
- package/dist/errors/transaction.error.js +61 -0
- package/dist/errors/transaction.error.js.map +1 -1
- package/dist/events/action.event.d.ts +0 -2
- package/dist/events/action.event.js +0 -2
- package/dist/events/action.event.js.map +1 -1
- package/dist/events/event.model.d.ts +21 -5
- package/dist/events/event.model.js +11 -5
- package/dist/events/event.model.js.map +1 -1
- package/dist/events/hook/commit.hook.event.d.ts +0 -6
- package/dist/events/hook/commit.hook.event.js +0 -6
- package/dist/events/hook/commit.hook.event.js.map +1 -1
- package/dist/events/hook/hook.event.d.ts +0 -2
- package/dist/events/hook/hook.event.js +0 -2
- package/dist/events/hook/hook.event.js.map +1 -1
- package/dist/events/hook/model.hook.event.d.ts +0 -6
- package/dist/events/hook/model.hook.event.js +0 -6
- package/dist/events/hook/model.hook.event.js.map +1 -1
- package/dist/events/hook/resource.hook.event.d.ts +0 -6
- package/dist/events/hook/resource.hook.event.js +0 -6
- package/dist/events/hook/resource.hook.event.js.map +1 -1
- package/dist/events/index.d.ts +3 -0
- package/dist/events/index.js +3 -0
- package/dist/events/index.js.map +1 -1
- package/dist/events/mode-result.event.d.ts +57 -0
- package/dist/events/mode-result.event.js +24 -0
- package/dist/events/mode-result.event.js.map +1 -0
- package/dist/events/mode.event.d.ts +57 -0
- package/dist/events/mode.event.js +32 -0
- package/dist/events/mode.event.js.map +1 -0
- package/dist/events/module.event.d.ts +0 -2
- package/dist/events/module.event.js +0 -2
- package/dist/events/module.event.js.map +1 -1
- package/dist/events/registration.event.d.ts +18 -14
- package/dist/events/registration.event.js +18 -14
- package/dist/events/registration.event.js.map +1 -1
- package/dist/events/serialization.event.d.ts +15 -12
- package/dist/events/serialization.event.js +15 -12
- package/dist/events/serialization.event.js.map +1 -1
- package/dist/events/terraform.event.d.ts +42 -0
- package/dist/events/terraform.event.js +31 -0
- package/dist/events/terraform.event.js.map +1 -0
- package/dist/events/transaction.event.d.ts +0 -37
- package/dist/events/transaction.event.js +0 -28
- package/dist/events/transaction.event.js.map +1 -1
- package/dist/functions/container/container.d.ts +54 -13
- package/dist/functions/container/container.js +63 -18
- package/dist/functions/container/container.js.map +1 -1
- package/dist/functions/container/test-container.d.ts +43 -29
- package/dist/functions/container/test-container.js +71 -43
- package/dist/functions/container/test-container.js.map +1 -1
- package/dist/functions/dependency/dependency.d.ts +82 -8
- package/dist/functions/dependency/dependency.js +80 -14
- package/dist/functions/dependency/dependency.js.map +1 -1
- package/dist/functions/diff/aggregate-resource-actions.d.ts +19 -0
- package/dist/functions/diff/aggregate-resource-actions.js +41 -0
- package/dist/functions/diff/aggregate-resource-actions.js.map +1 -0
- package/dist/functions/diff/diff-metadata.d.ts +21 -3
- package/dist/functions/diff/diff-metadata.js +18 -0
- package/dist/functions/diff/diff-metadata.js.map +1 -1
- package/dist/functions/diff/diff.d.ts +55 -1
- package/dist/functions/diff/diff.js +44 -3
- package/dist/functions/diff/diff.js.map +1 -1
- package/dist/functions/diff/diff.utility.d.ts +17 -2
- package/dist/functions/diff/diff.utility.js +53 -38
- package/dist/functions/diff/diff.utility.js.map +1 -1
- package/dist/functions/hook/commit.hook.d.ts +16 -1
- package/dist/functions/hook/commit.hook.js +21 -6
- package/dist/functions/hook/commit.hook.js.map +1 -1
- package/dist/functions/hook/model-action.hook.d.ts +16 -1
- package/dist/functions/hook/model-action.hook.js +21 -6
- package/dist/functions/hook/model-action.hook.js.map +1 -1
- package/dist/functions/hook/resource-action.hook.d.ts +16 -1
- package/dist/functions/hook/resource-action.hook.js +21 -6
- package/dist/functions/hook/resource-action.hook.js.map +1 -1
- package/dist/functions/node/node-action.abstract.d.ts +23 -0
- package/dist/functions/node/node-action.abstract.js +20 -0
- package/dist/functions/node/node-action.abstract.js.map +1 -1
- package/dist/functions/node/node.abstract.d.ts +56 -5
- package/dist/functions/node/node.abstract.js +85 -12
- package/dist/functions/node/node.abstract.js.map +1 -1
- package/dist/functions/node/node.interface.d.ts +1 -0
- package/dist/functions/schema/schema.d.ts +7 -0
- package/dist/functions/schema/schema.js +9 -0
- package/dist/functions/schema/schema.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts +244 -14
- package/dist/main.js +361 -72
- package/dist/main.js.map +1 -1
- package/dist/models/account/account.model.d.ts +37 -7
- package/dist/models/account/account.model.js +40 -8
- package/dist/models/account/account.model.js.map +1 -1
- package/dist/models/account/account.schema.d.ts +13 -1
- package/dist/models/account/account.schema.js +12 -0
- package/dist/models/account/account.schema.js.map +1 -1
- package/dist/models/app/app.model.d.ts +16 -1
- package/dist/models/app/app.model.js +19 -4
- package/dist/models/app/app.model.js.map +1 -1
- package/dist/models/app/app.schema.d.ts +6 -0
- package/dist/models/app/app.schema.js +6 -0
- package/dist/models/app/app.schema.js.map +1 -1
- package/dist/models/deployment/deployment.model.d.ts +13 -1
- package/dist/models/deployment/deployment.model.js +16 -4
- package/dist/models/deployment/deployment.model.js.map +1 -1
- package/dist/models/deployment/deployment.schema.d.ts +2 -0
- package/dist/models/deployment/deployment.schema.js +2 -0
- package/dist/models/deployment/deployment.schema.js.map +1 -1
- package/dist/models/environment/environment.model.d.ts +13 -1
- package/dist/models/environment/environment.model.js +20 -8
- package/dist/models/environment/environment.model.js.map +1 -1
- package/dist/models/environment/environment.schema.d.ts +2 -0
- package/dist/models/environment/environment.schema.js +2 -0
- package/dist/models/environment/environment.schema.js.map +1 -1
- package/dist/models/execution/execution.model.d.ts +20 -2
- package/dist/models/execution/execution.model.js +46 -28
- package/dist/models/execution/execution.model.js.map +1 -1
- package/dist/models/execution/execution.schema.d.ts +11 -0
- package/dist/models/execution/execution.schema.js +11 -0
- package/dist/models/execution/execution.schema.js.map +1 -1
- package/dist/models/filesystem/filesystem.model.d.ts +27 -1
- package/dist/models/filesystem/filesystem.model.js +30 -4
- package/dist/models/filesystem/filesystem.model.js.map +1 -1
- package/dist/models/filesystem/filesystem.schema.d.ts +5 -0
- package/dist/models/filesystem/filesystem.schema.js +5 -0
- package/dist/models/filesystem/filesystem.schema.js.map +1 -1
- package/dist/models/image/image.model.d.ts +17 -4
- package/dist/models/image/image.model.js +20 -7
- package/dist/models/image/image.model.js.map +1 -1
- package/dist/models/image/image.schema.d.ts +8 -0
- package/dist/models/image/image.schema.js +8 -0
- package/dist/models/image/image.schema.js.map +1 -1
- package/dist/models/model-action.interface.d.ts +17 -4
- package/dist/models/model.abstract.d.ts +96 -1
- package/dist/models/model.abstract.js +106 -7
- package/dist/models/model.abstract.js.map +1 -1
- package/dist/models/model.interface.d.ts +3 -0
- package/dist/models/pipeline/pipeline.model.d.ts +13 -1
- package/dist/models/pipeline/pipeline.model.js +18 -6
- package/dist/models/pipeline/pipeline.model.js.map +1 -1
- package/dist/models/pipeline/pipeline.schema.d.ts +8 -0
- package/dist/models/pipeline/pipeline.schema.js +8 -0
- package/dist/models/pipeline/pipeline.schema.js.map +1 -1
- package/dist/models/region/region.model.d.ts +16 -1
- package/dist/models/region/region.model.js +19 -4
- package/dist/models/region/region.model.js.map +1 -1
- package/dist/models/region/region.schema.d.ts +6 -0
- package/dist/models/region/region.schema.js +6 -0
- package/dist/models/region/region.schema.js.map +1 -1
- package/dist/models/server/server.model.d.ts +13 -1
- package/dist/models/server/server.model.js +16 -4
- package/dist/models/server/server.model.js.map +1 -1
- package/dist/models/server/server.schema.d.ts +3 -1
- package/dist/models/server/server.schema.js +3 -1
- package/dist/models/server/server.schema.js.map +1 -1
- package/dist/models/service/service.model.d.ts +15 -1
- package/dist/models/service/service.model.js +15 -1
- package/dist/models/service/service.model.js.map +1 -1
- package/dist/models/service/service.schema.d.ts +4 -1
- package/dist/models/service/service.schema.js +4 -1
- package/dist/models/service/service.schema.js.map +1 -1
- package/dist/models/subnet/subnet.model.d.ts +27 -3
- package/dist/models/subnet/subnet.model.js +40 -16
- package/dist/models/subnet/subnet.model.js.map +1 -1
- package/dist/models/subnet/subnet.schema.d.ts +9 -0
- package/dist/models/subnet/subnet.schema.js +9 -0
- package/dist/models/subnet/subnet.schema.js.map +1 -1
- package/dist/modes/apply-transaction.d.ts +23 -0
- package/dist/modes/apply-transaction.js +25 -0
- package/dist/modes/apply-transaction.js.map +1 -0
- package/dist/modes/commit.mode.d.ts +54 -0
- package/dist/modes/commit.mode.js +235 -0
- package/dist/modes/commit.mode.js.map +1 -0
- package/dist/modes/generate.mode.d.ts +29 -0
- package/dist/modes/generate.mode.js +49 -0
- package/dist/modes/generate.mode.js.map +1 -0
- package/dist/modes/run-action.mode.d.ts +30 -0
- package/dist/modes/run-action.mode.js +140 -0
- package/dist/modes/run-action.mode.js.map +1 -0
- package/dist/modes/validate.mode.d.ts +162 -0
- package/dist/modes/validate.mode.js +480 -0
- package/dist/modes/validate.mode.js.map +1 -0
- package/dist/modules/module.abstract.d.ts +51 -0
- package/dist/modules/module.abstract.js +36 -0
- package/dist/modules/module.abstract.js.map +1 -1
- package/dist/modules/module.container.d.ts +36 -0
- package/dist/modules/module.container.js +36 -0
- package/dist/modules/module.container.js.map +1 -1
- package/dist/modules/test-module.container.d.ts +139 -25
- package/dist/modules/test-module.container.js +410 -178
- package/dist/modules/test-module.container.js.map +1 -1
- package/dist/overlays/anchor.abstract.d.ts +32 -1
- package/dist/overlays/anchor.abstract.js +42 -11
- package/dist/overlays/anchor.abstract.js.map +1 -1
- package/dist/overlays/anchor.schema.d.ts +21 -0
- package/dist/overlays/anchor.schema.js +21 -0
- package/dist/overlays/anchor.schema.js.map +1 -1
- package/dist/overlays/overlay-data.repository.d.ts +18 -0
- package/dist/overlays/overlay-data.repository.js +18 -0
- package/dist/overlays/overlay-data.repository.js.map +1 -1
- package/dist/overlays/overlay.abstract.d.ts +56 -1
- package/dist/overlays/overlay.abstract.js +79 -20
- package/dist/overlays/overlay.abstract.js.map +1 -1
- package/dist/overlays/overlay.schema.d.ts +20 -0
- package/dist/overlays/overlay.schema.js +20 -0
- package/dist/overlays/overlay.schema.js.map +1 -1
- package/dist/resources/resource-action.interface.d.ts +26 -2
- package/dist/resources/resource-data.repository.d.ts +63 -1
- package/dist/resources/resource-data.repository.js +94 -4
- package/dist/resources/resource-data.repository.js.map +1 -1
- package/dist/resources/resource.abstract.d.ts +118 -3
- package/dist/resources/resource.abstract.js +166 -33
- package/dist/resources/resource.abstract.js.map +1 -1
- package/dist/resources/resource.schema.d.ts +29 -1
- package/dist/resources/resource.schema.js +28 -0
- package/dist/resources/resource.schema.js.map +1 -1
- package/dist/resources/terraform-resource.abstract.d.ts +44 -0
- package/dist/resources/terraform-resource.abstract.js +45 -0
- package/dist/resources/terraform-resource.abstract.js.map +1 -0
- package/dist/services/event/event.service.d.ts +30 -3
- package/dist/services/event/event.service.js +58 -16
- package/dist/services/event/event.service.js.map +1 -1
- package/dist/services/input/input.service.d.ts +52 -3
- package/dist/services/input/input.service.js +72 -8
- package/dist/services/input/input.service.js.map +1 -1
- package/dist/services/schema-translation/schema-translation.service.d.ts +9 -0
- package/dist/services/schema-translation/schema-translation.service.js +9 -0
- package/dist/services/schema-translation/schema-translation.service.js.map +1 -1
- package/dist/services/serialization/model/model-serialization.service.d.ts +26 -2
- package/dist/services/serialization/model/model-serialization.service.js +110 -62
- package/dist/services/serialization/model/model-serialization.service.js.map +1 -1
- package/dist/services/serialization/resource/resource-serialization.service.d.ts +33 -4
- package/dist/services/serialization/resource/resource-serialization.service.js +64 -28
- package/dist/services/serialization/resource/resource-serialization.service.js.map +1 -1
- package/dist/services/state-management/file-app-lock.utility.d.ts +43 -0
- package/dist/services/state-management/file-app-lock.utility.js +124 -0
- package/dist/services/state-management/file-app-lock.utility.js.map +1 -0
- package/dist/services/state-management/local-encryption.state-provider.d.ts +53 -2
- package/dist/services/state-management/local-encryption.state-provider.js +75 -49
- package/dist/services/state-management/local-encryption.state-provider.js.map +1 -1
- package/dist/services/state-management/local.state-provider.d.ts +49 -2
- package/dist/services/state-management/local.state-provider.js +70 -49
- package/dist/services/state-management/local.state-provider.js.map +1 -1
- package/dist/services/state-management/state-management.service.d.ts +141 -6
- package/dist/services/state-management/state-management.service.js +149 -4
- package/dist/services/state-management/state-management.service.js.map +1 -1
- package/dist/services/state-management/state-provider.interface.d.ts +55 -1
- package/dist/services/state-management/terraform-state.service.d.ts +76 -0
- package/dist/services/state-management/terraform-state.service.js +154 -0
- package/dist/services/state-management/terraform-state.service.js.map +1 -0
- package/dist/services/state-management/test.state-provider.d.ts +38 -1
- package/dist/services/state-management/test.state-provider.js +52 -21
- package/dist/services/state-management/test.state-provider.js.map +1 -1
- package/dist/services/terraform/terraform.service.d.ts +426 -0
- package/dist/services/terraform/terraform.service.js +995 -0
- package/dist/services/terraform/terraform.service.js.map +1 -0
- package/dist/services/terraform/terraform.type.d.ts +387 -0
- package/dist/services/terraform/terraform.type.js +579 -0
- package/dist/services/terraform/terraform.type.js.map +1 -0
- package/dist/services/transaction/transaction.service.d.ts +86 -10
- package/dist/services/transaction/transaction.service.js +387 -232
- package/dist/services/transaction/transaction.service.js.map +1 -1
- package/dist/services/validation/validation.service.d.ts +13 -1
- package/dist/services/validation/validation.service.js +12 -0
- package/dist/services/validation/validation.service.js.map +1 -1
- package/dist/utilities/array/array.utility.d.ts +3 -0
- package/dist/utilities/array/array.utility.js +3 -0
- package/dist/utilities/array/array.utility.js.map +1 -1
- package/dist/utilities/file/file.utility.d.ts +15 -0
- package/dist/utilities/file/file.utility.js +18 -1
- package/dist/utilities/file/file.utility.js.map +1 -1
- package/dist/utilities/hcl/hcl.utility.d.ts +61 -0
- package/dist/utilities/hcl/hcl.utility.js +229 -0
- package/dist/utilities/hcl/hcl.utility.js.map +1 -0
- package/dist/utilities/node/node.utility.d.ts +3 -0
- package/dist/utilities/node/node.utility.js +3 -0
- package/dist/utilities/node/node.utility.js.map +1 -1
- package/dist/utilities/object/object.utility.d.ts +12 -0
- package/dist/utilities/object/object.utility.js +12 -0
- package/dist/utilities/object/object.utility.js.map +1 -1
- package/dist/utilities/project/project.utility.d.ts +28 -0
- package/dist/utilities/project/project.utility.js +35 -0
- package/dist/utilities/project/project.utility.js.map +1 -0
- package/dist/utilities/string/string.utility.d.ts +21 -0
- package/dist/utilities/string/string.utility.js +39 -0
- package/dist/utilities/string/string.utility.js.map +1 -0
- package/dist/utilities/terraform/terraform.utility.d.ts +227 -0
- package/dist/utilities/terraform/terraform.utility.js +434 -0
- package/dist/utilities/terraform/terraform.utility.js.map +1 -0
- package/dist/utilities/test-helpers/test-classes.d.ts +18 -31
- package/dist/utilities/test-helpers/test-classes.js +18 -41
- package/dist/utilities/test-helpers/test-classes.js.map +1 -1
- package/dist/utilities/test-helpers/test-models.js +12 -0
- package/dist/utilities/test-helpers/test-models.js.map +1 -1
- package/dist/utilities/test-helpers/test-modes.d.ts +315 -0
- package/dist/utilities/test-helpers/test-modes.js +463 -0
- package/dist/utilities/test-helpers/test-modes.js.map +1 -0
- package/dist/utilities/test-helpers/test-modules.d.ts +41 -0
- package/dist/utilities/test-helpers/test-modules.js +79 -0
- package/dist/utilities/test-helpers/test-modules.js.map +1 -0
- package/dist/utilities/test-helpers/test-overlays.d.ts +17 -1
- package/dist/utilities/test-helpers/test-overlays.js +49 -5
- package/dist/utilities/test-helpers/test-overlays.js.map +1 -1
- package/dist/utilities/test-helpers/test-resources.d.ts +19 -1
- package/dist/utilities/test-helpers/test-resources.js +61 -3
- package/dist/utilities/test-helpers/test-resources.js.map +1 -1
- package/dist/utilities/validation/validation.utility.d.ts +24 -0
- package/dist/utilities/validation/validation.utility.js +24 -0
- package/dist/utilities/validation/validation.utility.js.map +1 -1
- package/package.json +6 -5
- package/dist/services/capture/capture.service.d.ts +0 -19
- package/dist/services/capture/capture.service.js +0 -43
- package/dist/services/capture/capture.service.js.map +0 -1
- package/dist/utilities/cidr/cidr.utility.d.ts +0 -10
- package/dist/utilities/cidr/cidr.utility.js +0 -51
- package/dist/utilities/cidr/cidr.utility.js.map +0 -1
|
@@ -1,14 +1,25 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mkdtemp } from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import {} from '../functions/container/container.js';
|
|
5
|
+
import { DiffAction } from '../functions/diff/diff.js';
|
|
6
|
+
import { DiffUtility } from '../functions/diff/diff.utility.js';
|
|
2
7
|
import { Octo } from '../main.js';
|
|
3
8
|
import { AModel } from '../models/model.abstract.js';
|
|
9
|
+
import { applyModelTransaction } from '../modes/apply-transaction.js';
|
|
4
10
|
import { OverlayDataRepository } from '../overlays/overlay-data.repository.js';
|
|
5
11
|
import { AOverlay } from '../overlays/overlay.abstract.js';
|
|
12
|
+
import { ResourceDataRepository } from '../resources/resource-data.repository.js';
|
|
6
13
|
import { AResource } from '../resources/resource.abstract.js';
|
|
7
14
|
import { InputService } from '../services/input/input.service.js';
|
|
8
15
|
import { LocalEncryptionStateProvider } from '../services/state-management/local-encryption.state-provider.js';
|
|
9
16
|
import { LocalStateProvider } from '../services/state-management/local.state-provider.js';
|
|
17
|
+
import { StateManagementService } from '../services/state-management/state-management.service.js';
|
|
10
18
|
import { TestStateProvider } from '../services/state-management/test.state-provider.js';
|
|
19
|
+
import { TerraformService } from '../services/terraform/terraform.service.js';
|
|
11
20
|
import { TransactionService } from '../services/transaction/transaction.service.js';
|
|
21
|
+
import { HclUtility } from '../utilities/hcl/hcl.utility.js';
|
|
22
|
+
import { TerraformUtility } from '../utilities/terraform/terraform.utility.js';
|
|
12
23
|
import { TestAnchor } from '../utilities/test-helpers/test-classes.js';
|
|
13
24
|
import { create } from '../utilities/test-helpers/test-models.js';
|
|
14
25
|
import { createTestOverlays } from '../utilities/test-helpers/test-overlays.js';
|
|
@@ -16,127 +27,116 @@ import { createResources, createTestResources } from '../utilities/test-helpers/
|
|
|
16
27
|
import { AModule } from './module.abstract.js';
|
|
17
28
|
import { ModuleContainer } from './module.container.js';
|
|
18
29
|
// Universal Test Module and Actions.
|
|
30
|
+
/**
|
|
31
|
+
* @internal
|
|
32
|
+
*/
|
|
19
33
|
class UniversalTestModuleSchema {
|
|
20
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* @internal
|
|
37
|
+
*/
|
|
21
38
|
class UniversalTestModule extends AModule {
|
|
22
39
|
static { this.MODULE_PACKAGE = '@octo'; }
|
|
23
40
|
static { this.MODULE_SCHEMA = UniversalTestModuleSchema; }
|
|
41
|
+
/**
|
|
42
|
+
* @internal
|
|
43
|
+
*/
|
|
24
44
|
async onInit() {
|
|
25
45
|
return;
|
|
26
46
|
}
|
|
27
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* @internal
|
|
50
|
+
*/
|
|
28
51
|
class UniversalModelAction {
|
|
52
|
+
/**
|
|
53
|
+
* @internal
|
|
54
|
+
*/
|
|
29
55
|
filter() {
|
|
30
56
|
return true;
|
|
31
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* @internal
|
|
60
|
+
*/
|
|
32
61
|
async handle() {
|
|
33
62
|
return {};
|
|
34
63
|
}
|
|
35
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* @internal
|
|
67
|
+
*/
|
|
36
68
|
class UniversalResourceAction {
|
|
69
|
+
/**
|
|
70
|
+
* @internal
|
|
71
|
+
*/
|
|
37
72
|
filter() {
|
|
38
73
|
return true;
|
|
39
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* @internal
|
|
77
|
+
*/
|
|
40
78
|
async handle() { }
|
|
41
|
-
async mock() { }
|
|
42
79
|
}
|
|
43
80
|
/**
|
|
81
|
+
* The harness for testing a module.
|
|
82
|
+
*
|
|
83
|
+
* It runs your module through the real Octo lifecycle against an in-memory state provider, and hands
|
|
84
|
+
* back everything a test needs to assert on: the model and resource transactions, the generated HCL,
|
|
85
|
+
* and the resource responses. Create it inside a {@link TestContainer} so each test file is isolated.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* const container = await TestContainer.create({ mocks: [] }, { factoryTimeoutInMs: 500 });
|
|
90
|
+
* const testModuleContainer = new TestModuleContainer(container);
|
|
91
|
+
* await testModuleContainer.initialize();
|
|
92
|
+
*
|
|
93
|
+
* const generator = testModuleContainer.runModules([
|
|
94
|
+
* { inputs: { name: 'test-app' }, moduleId: 'app', type: SimpleAppModule },
|
|
95
|
+
* ]);
|
|
96
|
+
* const { modelTransaction } = (await generator.next()).value;
|
|
97
|
+
* ```
|
|
98
|
+
*
|
|
44
99
|
* @group Modules
|
|
45
100
|
*/
|
|
46
101
|
export class TestModuleContainer {
|
|
47
|
-
|
|
102
|
+
/**
|
|
103
|
+
* @param container The {@link TestContainer} this run resolves its services from.
|
|
104
|
+
*/
|
|
105
|
+
constructor(container) {
|
|
106
|
+
this.container = container;
|
|
48
107
|
this.octo = new Octo();
|
|
49
108
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
response.modelTransaction = (await generator.next()).value;
|
|
67
|
-
response.resourceDiffs = (await generator.next()).value;
|
|
68
|
-
response.resourceTransaction = (await generator.next()).value;
|
|
69
|
-
await generator.next();
|
|
70
|
-
}
|
|
71
|
-
catch (error) {
|
|
72
|
-
if (!skipResourceTransaction || error.message !== 'App is not in lock state!') {
|
|
73
|
-
await this.reset();
|
|
74
|
-
throw error;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
finally {
|
|
78
|
-
await this.stateProvider.unlockApp(appLockId);
|
|
79
|
-
}
|
|
80
|
-
const container = Container.getInstance();
|
|
81
|
-
const inputService = await container.get(InputService);
|
|
82
|
-
for (const moduleId of filterByModuleIds) {
|
|
83
|
-
response.modelDiffs = response.modelDiffs
|
|
84
|
-
.map((i) => i.filter((j) => {
|
|
85
|
-
if (j.node instanceof AModel && !(j.node instanceof AOverlay)) {
|
|
86
|
-
return inputService.getModuleIdFromModel(j.node) === moduleId;
|
|
87
|
-
}
|
|
88
|
-
else if (j.node instanceof AOverlay) {
|
|
89
|
-
return inputService.getModuleIdFromOverlay(j.node) === moduleId;
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
92
|
-
return false;
|
|
93
|
-
}
|
|
94
|
-
}))
|
|
95
|
-
.filter((i) => i.length);
|
|
96
|
-
response.modelTransaction = response.modelTransaction
|
|
97
|
-
.map((i) => i.filter((j) => {
|
|
98
|
-
if (j.node instanceof AModel && !(j.node instanceof AOverlay)) {
|
|
99
|
-
return inputService.getModuleIdFromModel(j.node) === moduleId;
|
|
100
|
-
}
|
|
101
|
-
else if (j.node instanceof AOverlay) {
|
|
102
|
-
return inputService.getModuleIdFromOverlay(j.node) === moduleId;
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
return false;
|
|
106
|
-
}
|
|
107
|
-
}))
|
|
108
|
-
.filter((i) => i.length);
|
|
109
|
-
response.resourceDiffs = response.resourceDiffs
|
|
110
|
-
.map((i) => i.filter((j) => {
|
|
111
|
-
if (j.node instanceof AResource) {
|
|
112
|
-
return inputService.getModuleIdFromResource(j.node) === moduleId;
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
return false;
|
|
116
|
-
}
|
|
117
|
-
}))
|
|
118
|
-
.filter((i) => i.length);
|
|
119
|
-
if (!skipResourceTransaction) {
|
|
120
|
-
response.resourceTransaction = response.resourceTransaction
|
|
121
|
-
.map((i) => i.filter((j) => {
|
|
122
|
-
if (j.node instanceof AResource) {
|
|
123
|
-
return inputService.getModuleIdFromResource(j.node) === moduleId;
|
|
124
|
-
}
|
|
125
|
-
else {
|
|
126
|
-
return false;
|
|
127
|
-
}
|
|
128
|
-
}))
|
|
129
|
-
.filter((i) => i.length);
|
|
130
|
-
}
|
|
109
|
+
/**
|
|
110
|
+
* To seed resources that already exist, as though the given module had produced them.
|
|
111
|
+
* Use it to stand up the prerequisites a module under test expects to find.
|
|
112
|
+
*/
|
|
113
|
+
async createResources(moduleId, args, options) {
|
|
114
|
+
const [inputService, moduleContainer] = await Promise.all([
|
|
115
|
+
this.container.get(InputService),
|
|
116
|
+
this.container.get(ModuleContainer),
|
|
117
|
+
]);
|
|
118
|
+
// Register new moduleId as instance of the universal module.
|
|
119
|
+
moduleContainer.load(UniversalTestModule, moduleId, {});
|
|
120
|
+
// Immediately unload the universal module to ensure it does not run in apply().
|
|
121
|
+
moduleContainer.unload(UniversalTestModule);
|
|
122
|
+
const result = await createResources(args, options);
|
|
123
|
+
for (const resource of Object.values(result)) {
|
|
124
|
+
inputService.registerResource(moduleId, resource);
|
|
131
125
|
}
|
|
132
|
-
|
|
133
|
-
return response;
|
|
126
|
+
return result;
|
|
134
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* To build a throwaway anchor for a test double, without declaring an anchor class.
|
|
130
|
+
*/
|
|
135
131
|
createTestAnchor(anchorId, properties, parent) {
|
|
136
132
|
return new TestAnchor(anchorId, properties, parent);
|
|
137
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* To seed models, as though the given module had produced them.
|
|
136
|
+
* Each model gets a no-op action, so the models appear in a transaction without doing any work.
|
|
137
|
+
*/
|
|
138
138
|
async createTestModels(moduleId, args) {
|
|
139
|
-
const container =
|
|
139
|
+
const container = this.container;
|
|
140
140
|
const [inputService, moduleContainer, transactionService] = await Promise.all([
|
|
141
141
|
container.get(InputService),
|
|
142
142
|
container.get(ModuleContainer),
|
|
@@ -148,16 +148,11 @@ export class TestModuleContainer {
|
|
|
148
148
|
moduleContainer.unload(UniversalTestModule);
|
|
149
149
|
const result = create(args);
|
|
150
150
|
for (const models of Object.values(result)) {
|
|
151
|
-
// Check if the model has already been registered.
|
|
152
|
-
// If no error thrown, the model has already been registered.
|
|
153
151
|
for (const model of models) {
|
|
154
|
-
|
|
155
|
-
|
|
152
|
+
// Skip models that are already registered (a defined moduleId means it is known).
|
|
153
|
+
if (inputService.getModuleIdFromModel(model) !== undefined) {
|
|
156
154
|
continue;
|
|
157
155
|
}
|
|
158
|
-
catch (error) {
|
|
159
|
-
/* do nothing. */
|
|
160
|
-
}
|
|
161
156
|
inputService.registerModel(moduleId, model);
|
|
162
157
|
const universalAction = new UniversalModelAction();
|
|
163
158
|
Object.assign(universalAction, {
|
|
@@ -177,41 +172,44 @@ export class TestModuleContainer {
|
|
|
177
172
|
}
|
|
178
173
|
return result;
|
|
179
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* To seed overlays, as though the given module had produced them.
|
|
177
|
+
* An overlay given no actions gets a no-op one.
|
|
178
|
+
*/
|
|
180
179
|
async createTestOverlays(moduleId, args) {
|
|
181
|
-
const container =
|
|
182
|
-
const [inputService, moduleContainer
|
|
180
|
+
const container = this.container;
|
|
181
|
+
const [inputService, moduleContainer] = await Promise.all([
|
|
183
182
|
container.get(InputService),
|
|
184
183
|
container.get(ModuleContainer),
|
|
185
|
-
container.get(TransactionService),
|
|
186
184
|
]);
|
|
187
185
|
// Register new moduleId as instance of the universal module.
|
|
188
186
|
moduleContainer.load(UniversalTestModule, moduleId, {});
|
|
189
187
|
// Immediately unload the universal module to ensure it does not run in apply().
|
|
190
188
|
moduleContainer.unload(UniversalTestModule);
|
|
189
|
+
// Default any overlay without explicit actions to a universal no-op action, named after the
|
|
190
|
+
// overlay so it reads clearly in a transaction snapshot. createTestOverlays registers them.
|
|
191
|
+
for (const arg of args) {
|
|
192
|
+
if (!arg.overlayActions || arg.overlayActions.length === 0) {
|
|
193
|
+
const [, nodeName] = arg.context.split('=')[0].split('/');
|
|
194
|
+
const universalAction = new UniversalModelAction();
|
|
195
|
+
Object.assign(universalAction, {
|
|
196
|
+
constructor: { name: `${UniversalModelAction.name}For${nodeName}` },
|
|
197
|
+
});
|
|
198
|
+
arg.overlayActions = [universalAction];
|
|
199
|
+
}
|
|
200
|
+
}
|
|
191
201
|
const result = await createTestOverlays(args);
|
|
192
202
|
for (const overlay of Object.values(result)) {
|
|
193
203
|
inputService.registerOverlay(moduleId, overlay);
|
|
194
|
-
const universalAction = new UniversalModelAction();
|
|
195
|
-
Object.assign(universalAction, {
|
|
196
|
-
constructor: { name: `${UniversalModelAction.name}For${overlay.constructor.name}` },
|
|
197
|
-
});
|
|
198
|
-
try {
|
|
199
|
-
transactionService.unregisterOverlayActions(overlay.constructor);
|
|
200
|
-
transactionService.registerOverlayActions(overlay.constructor, [
|
|
201
|
-
universalAction,
|
|
202
|
-
]);
|
|
203
|
-
}
|
|
204
|
-
catch (error) {
|
|
205
|
-
if (error.message !==
|
|
206
|
-
`Action "${universalAction.constructor.name}" already registered for overlay "${overlay.constructor.name}"!`) {
|
|
207
|
-
throw error;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
204
|
}
|
|
211
205
|
return result;
|
|
212
206
|
}
|
|
213
|
-
|
|
214
|
-
|
|
207
|
+
/**
|
|
208
|
+
* To seed resources, as though the given module had produced them.
|
|
209
|
+
* A resource given no actions gets a no-op one, unless terraform owns it.
|
|
210
|
+
*/
|
|
211
|
+
async createTestResources(moduleId, args, options) {
|
|
212
|
+
const container = this.container;
|
|
215
213
|
const [inputService, moduleContainer] = await Promise.all([
|
|
216
214
|
container.get(InputService),
|
|
217
215
|
container.get(ModuleContainer),
|
|
@@ -220,43 +218,66 @@ export class TestModuleContainer {
|
|
|
220
218
|
moduleContainer.load(UniversalTestModule, moduleId, {});
|
|
221
219
|
// Immediately unload the universal module to ensure it does not run in apply().
|
|
222
220
|
moduleContainer.unload(UniversalTestModule);
|
|
223
|
-
|
|
221
|
+
// Default any resource without explicit actions to a universal no-op action, named after the
|
|
222
|
+
// resource so it reads clearly in a transaction snapshot. createTestResources registers them,
|
|
223
|
+
// and skips terraform resources (which terraform owns and cannot have actions).
|
|
224
|
+
for (const arg of args) {
|
|
225
|
+
if (!arg.resourceActions || arg.resourceActions.length === 0) {
|
|
226
|
+
const [, nodeName] = arg.resourceContext.split('=')[0].split('/');
|
|
227
|
+
const universalAction = new UniversalResourceAction();
|
|
228
|
+
Object.assign(universalAction, {
|
|
229
|
+
constructor: { name: `${UniversalResourceAction.name}For${nodeName}` },
|
|
230
|
+
});
|
|
231
|
+
arg.resourceActions = [universalAction];
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
const result = await createTestResources(args, options);
|
|
224
235
|
for (const resource of Object.values(result)) {
|
|
225
236
|
inputService.registerResource(moduleId, resource);
|
|
226
237
|
}
|
|
227
238
|
return result;
|
|
228
239
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
new UniversalResourceAction(),
|
|
246
|
-
]);
|
|
240
|
+
/**
|
|
241
|
+
* Reduces a transaction's diffs, model or resource, to a stable digest you can snapshot:
|
|
242
|
+
* `+ <context>` (create), `- <context>` (delete), `^ <context>` (replace), `* <context>` (update).
|
|
243
|
+
*
|
|
244
|
+
* A diff is classified exactly as {@link Octo.validate} aggregates it, so a digest and a validate
|
|
245
|
+
* report of the same transaction never disagree. Only an add/delete of a `resourceId` creates or
|
|
246
|
+
* destroys a resource; an add/delete on any other field changes a resource that stays -
|
|
247
|
+
* re-pointing a `parent`, most commonly - and reads as an update.
|
|
248
|
+
*
|
|
249
|
+
* The digest has one entry per diff, not per resource, so a resource may appear more than once.
|
|
250
|
+
*/
|
|
251
|
+
digestDiffs(diffs) {
|
|
252
|
+
const changes = [];
|
|
253
|
+
for (const d of diffs.flat()) {
|
|
254
|
+
if (d.action === DiffAction.ADD && d.field === 'resourceId') {
|
|
255
|
+
changes.push(`+ ${d.node.getContext()}`);
|
|
247
256
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
}
|
|
257
|
+
else if (d.action === DiffAction.DELETE && d.field === 'resourceId') {
|
|
258
|
+
changes.push(`- ${d.node.getContext()}`);
|
|
259
|
+
}
|
|
260
|
+
else if (d.action === DiffAction.REPLACE) {
|
|
261
|
+
changes.push(`^ ${d.node.getContext()}`);
|
|
262
|
+
}
|
|
263
|
+
else if (d.action === DiffAction.VALIDATE) {
|
|
264
|
+
// Not a change: validation runs as its own transaction, one diff per surviving resource.
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
changes.push(`* ${d.node.getContext()}`);
|
|
253
269
|
}
|
|
254
270
|
}
|
|
255
|
-
return
|
|
256
|
-
}
|
|
257
|
-
mapTransactionActions(transaction) {
|
|
258
|
-
return transaction.map((i) => i.map((j) => j.actions.map((a) => a.constructor.name)).flat());
|
|
271
|
+
return changes;
|
|
259
272
|
}
|
|
273
|
+
/**
|
|
274
|
+
* Boots Octo for the test. Call it once, before running any module.
|
|
275
|
+
*
|
|
276
|
+
* @param stateProvider Defaults to an in-memory {@link TestStateProvider}. Only the local and test
|
|
277
|
+
* providers are accepted - a test must never write to shared state.
|
|
278
|
+
* @param initializeInContainer Factories to resolve at boot. See {@link Octo.initialize}.
|
|
279
|
+
* @param excludeInContainer Factories to unregister at boot. See {@link Octo.initialize}.
|
|
280
|
+
*/
|
|
260
281
|
async initialize(stateProvider, initializeInContainer, excludeInContainer) {
|
|
261
282
|
if (stateProvider &&
|
|
262
283
|
!(stateProvider instanceof LocalEncryptionStateProvider ||
|
|
@@ -267,36 +288,90 @@ export class TestModuleContainer {
|
|
|
267
288
|
this.stateProvider = stateProvider ?? new TestStateProvider();
|
|
268
289
|
await this.octo.initialize(this.stateProvider, initializeInContainer, excludeInContainer);
|
|
269
290
|
// Always register the UniversalTestModule to allow users to create test prerequisites.
|
|
270
|
-
const moduleContainer = await
|
|
291
|
+
const moduleContainer = await this.container.get(ModuleContainer);
|
|
271
292
|
moduleContainer.register(UniversalTestModule, { packageName: '@octo' });
|
|
272
293
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
294
|
+
/**
|
|
295
|
+
* Whether the committed resource state matches the previous one, i.e. whether the last run
|
|
296
|
+
* settled without leaving a pending change.
|
|
297
|
+
*/
|
|
298
|
+
async isResourceStateEqual() {
|
|
299
|
+
const container = this.container;
|
|
300
|
+
const stateManagementService = await container.get(StateManagementService);
|
|
301
|
+
const resourcesActual = await stateManagementService.getResourceState('resources-actual.json');
|
|
302
|
+
const resourcesOld = await stateManagementService.getResourceState('resources-old.json');
|
|
303
|
+
return DiffUtility.isObjectDeepEquals(resourcesActual.data, resourcesOld.data);
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Reduces a transaction to the names of the actions it ran, in order. Snapshot it to assert that
|
|
307
|
+
* a change triggered the actions you expected.
|
|
308
|
+
*/
|
|
309
|
+
mapTransactionActions(transaction) {
|
|
310
|
+
return transaction.map((i) => i.map((j) => j.actions.map((a) => a.constructor.name)).flat());
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* See {@link Octo.registerHooks}.
|
|
314
|
+
*/
|
|
315
|
+
registerHooks(...args) {
|
|
316
|
+
return this.octo.registerHooks(...args);
|
|
276
317
|
}
|
|
277
|
-
|
|
278
|
-
|
|
318
|
+
/**
|
|
319
|
+
* See {@link Octo.registerTags}.
|
|
320
|
+
*/
|
|
321
|
+
registerTags(...args) {
|
|
322
|
+
return this.octo.registerTags(...args);
|
|
279
323
|
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
moduleContainer.load(moduleMetadata.module, module.moduleId, module.inputs);
|
|
292
|
-
}
|
|
293
|
-
return (await this.octo.compose());
|
|
324
|
+
/**
|
|
325
|
+
* See {@link Octo.registerTerraformConfig}. Required before a run that generates terraform.
|
|
326
|
+
*/
|
|
327
|
+
registerTerraformConfig(...args) {
|
|
328
|
+
return this.octo.registerTerraformConfig(...args);
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* See {@link Octo.registerTerraformProvider}. Required before a run that generates terraform.
|
|
332
|
+
*/
|
|
333
|
+
registerTerraformProvider(...args) {
|
|
334
|
+
return this.octo.registerTerraformProvider(...args);
|
|
294
335
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
336
|
+
/**
|
|
337
|
+
* Tears down the composed graph - models, overlays, inputs, and modules - so the next
|
|
338
|
+
* {@link TestModuleContainer.runModules} composes fresh. Call it in your test teardown.
|
|
339
|
+
*/
|
|
340
|
+
async reset() {
|
|
341
|
+
const container = this.container;
|
|
342
|
+
// Reset ModuleContainer constructor injections.
|
|
343
|
+
await container.get(InputService, { args: [true] });
|
|
344
|
+
await container.get(OverlayDataRepository, {
|
|
345
|
+
args: [true, []],
|
|
346
|
+
});
|
|
347
|
+
// Reset module container.
|
|
348
|
+
const moduleContainer = await container.get(ModuleContainer);
|
|
349
|
+
moduleContainer.reset();
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Runs the given modules through Octo's lifecycle, and yields the result once.
|
|
353
|
+
*
|
|
354
|
+
* How far the lifecycle goes is set by `terraformTarget`, and this is the choice that decides what
|
|
355
|
+
* the test costs:
|
|
356
|
+
* - `'skip'` - composes and commits in memory. No terraform, no cloud. This is a unit test.
|
|
357
|
+
* - `'plan'` - generates the module folders and runs `terraform plan` against them.
|
|
358
|
+
* - `'apply'` - generates, plans, applies, and commits. **This creates real infrastructure.**
|
|
359
|
+
*
|
|
360
|
+
* @param modules The modules to load, in order.
|
|
361
|
+
* @param options `filterByModuleIds` narrows the run to those modules; `outputDir` is where the
|
|
362
|
+
* terraform folders are written, defaulting to a temporary directory.
|
|
363
|
+
*/
|
|
364
|
+
async *runModules(modules, { filterByModuleIds = [], outputDir, terraformTarget = 'skip', } = {}) {
|
|
365
|
+
const [moduleContainer, resourceDataRepository, terraformService, terraformUtility] = await Promise.all([
|
|
366
|
+
this.container.get(ModuleContainer),
|
|
367
|
+
this.container.get(ResourceDataRepository),
|
|
368
|
+
this.container.get(TerraformService),
|
|
369
|
+
this.container.get(TerraformUtility),
|
|
370
|
+
]);
|
|
371
|
+
// Load modules.
|
|
372
|
+
const moduleList = Array.isArray(modules) ? modules : [modules];
|
|
373
|
+
for (const module of moduleList) {
|
|
374
|
+
if (moduleContainer.getMetadataIndex(module.type) === -1) {
|
|
300
375
|
moduleContainer.register(module.type, {
|
|
301
376
|
packageName: module.type.MODULE_PACKAGE,
|
|
302
377
|
});
|
|
@@ -309,18 +384,175 @@ export class TestModuleContainer {
|
|
|
309
384
|
moduleContainer.load(moduleMetadata.module, module.moduleId, module.inputs);
|
|
310
385
|
}
|
|
311
386
|
}
|
|
312
|
-
|
|
387
|
+
// Compose modules.
|
|
388
|
+
moduleContainer.order(moduleList.map((m) => m.type));
|
|
389
|
+
await this.octo.compose();
|
|
390
|
+
const app = this.octo.getRootModel();
|
|
391
|
+
const collectResponses = () => Object.fromEntries(resourceDataRepository.getActualResourcesByProperties().map((r) => [r.getContext(), r.response]));
|
|
392
|
+
if (terraformTarget === 'skip') {
|
|
393
|
+
// this.commit() applies the model graph exactly once and, before its internal reset, stores the
|
|
394
|
+
// rendered desired state in `previousHcl`. Derive the render and block diff from that single
|
|
395
|
+
// apply rather than a separate preview render — a preview would re-run model actions, and
|
|
396
|
+
// non-idempotent ones (e.g. sibling associations) would then apply twice.
|
|
397
|
+
const priorHcl = this.previousHcl ?? '';
|
|
398
|
+
const transaction = await this.commit(app, { filterByModuleIds });
|
|
399
|
+
const currentHcl = this.previousHcl ?? '';
|
|
400
|
+
yield {
|
|
401
|
+
hclDiff: HclUtility.diffBlocks(priorHcl, currentHcl),
|
|
402
|
+
hclRender: currentHcl,
|
|
403
|
+
modelTransaction: transaction.modelTransaction,
|
|
404
|
+
resourceDiffs: transaction.resourceDiffs,
|
|
405
|
+
resourceTransaction: transaction.resourceTransaction,
|
|
406
|
+
responses: collectResponses(),
|
|
407
|
+
validateReport: undefined,
|
|
408
|
+
warnings: [],
|
|
409
|
+
};
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
// In production octo runs generate/validate/commit as three separate processes, each of which
|
|
413
|
+
// derives the resource graph once from intent. runModules drives all three in one process, so it
|
|
414
|
+
// builds the model transaction once and hands the same result to each mode.
|
|
415
|
+
const transaction = await applyModelTransaction(app);
|
|
416
|
+
// Generate.
|
|
417
|
+
const dir = outputDir ?? (await mkdtemp(join(tmpdir(), 'octo-hcl-')));
|
|
418
|
+
const resourceDiffs = await this.octo.generate(app, { outputDir: dir }, transaction);
|
|
419
|
+
// Render the full HCL and the block diff from the sweep the transaction produced.
|
|
420
|
+
const currentHcl = HclUtility.serialize(terraformService.renderAllModules());
|
|
421
|
+
const diffHcl = HclUtility.diffBlocks(this.previousHcl ?? '', currentHcl);
|
|
422
|
+
this.previousHcl = currentHcl;
|
|
423
|
+
// Validate.
|
|
424
|
+
const validateReport = await this.octo.validate(app, await terraformUtility.plan(dir, { json: true }), transaction);
|
|
425
|
+
if (validateReport.failures.length > 0) {
|
|
426
|
+
throw new Error(`runModules(): terraform could not plan:\n${validateReport.failures
|
|
427
|
+
.map((failure) => `${failure.moduleId ? `[${failure.moduleId}] ` : ''}${failure.message}`)
|
|
428
|
+
.join('\n')}`);
|
|
429
|
+
}
|
|
430
|
+
const result = {
|
|
431
|
+
hclDiff: diffHcl,
|
|
432
|
+
hclRender: currentHcl,
|
|
433
|
+
modelTransaction: [],
|
|
434
|
+
resourceDiffs,
|
|
435
|
+
resourceTransaction: [],
|
|
436
|
+
responses: collectResponses(),
|
|
437
|
+
validateReport,
|
|
438
|
+
warnings: [],
|
|
439
|
+
};
|
|
440
|
+
if (terraformTarget === 'plan') {
|
|
441
|
+
yield result;
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
// Apply.
|
|
445
|
+
await terraformUtility.apply(dir);
|
|
446
|
+
// Commit. The lock is taken and released here, the way the CLI does it around octo.commit().
|
|
447
|
+
const { lockId } = await this.stateProvider.lockApp();
|
|
448
|
+
let warnings;
|
|
449
|
+
try {
|
|
450
|
+
({ warnings } = await this.octo.commit(app, { lockId, outputs: await terraformUtility.output(dir, { json: true }) }, transaction));
|
|
451
|
+
}
|
|
452
|
+
finally {
|
|
453
|
+
await this.stateProvider.unlockApp(lockId);
|
|
454
|
+
}
|
|
455
|
+
// Re-collect responses after the commit: it is commit that maps terraform outputs onto the
|
|
456
|
+
// actual resource graph, so a snapshot taken before it (as `response` holds) would miss them.
|
|
457
|
+
yield { ...result, responses: collectResponses(), warnings };
|
|
313
458
|
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
await
|
|
319
|
-
|
|
459
|
+
/**
|
|
460
|
+
* Persists the run's state, so a later run in the same test diffs against it.
|
|
461
|
+
*/
|
|
462
|
+
async commit(app, { filterByModuleIds = [], skipResourceTransaction = false, } = {}) {
|
|
463
|
+
const [terraformService, transactionService] = await Promise.all([
|
|
464
|
+
this.container.get(TerraformService),
|
|
465
|
+
this.container.get(TransactionService),
|
|
466
|
+
]);
|
|
467
|
+
// Each transaction sweeps the full resource graph into the terraform service, so the previous
|
|
468
|
+
// call's sweep must be cleared first. Config and providers survive, as they would in a real
|
|
469
|
+
// process — tests register them once (in beforeEach), not per transaction.
|
|
470
|
+
terraformService.resetTransactionState();
|
|
471
|
+
const diffs = await app.diff();
|
|
472
|
+
const generator = transactionService.beginTransaction(diffs, {
|
|
473
|
+
generateTerraform: true,
|
|
474
|
+
yieldModelDiffs: true,
|
|
475
|
+
yieldModelTransaction: true,
|
|
476
|
+
yieldResourceDiffs: true,
|
|
477
|
+
yieldResourceTransaction: true,
|
|
320
478
|
});
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
479
|
+
const response = {};
|
|
480
|
+
try {
|
|
481
|
+
response.modelDiffs = (await generator.next()).value;
|
|
482
|
+
response.modelTransaction = (await generator.next()).value;
|
|
483
|
+
response.resourceDiffs = (await generator.next()).value;
|
|
484
|
+
if (!skipResourceTransaction) {
|
|
485
|
+
response.resourceTransaction = (await generator.next()).value;
|
|
486
|
+
await generator.next();
|
|
487
|
+
}
|
|
488
|
+
else {
|
|
489
|
+
response.resourceTransaction = [];
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
catch (error) {
|
|
493
|
+
await this.reset();
|
|
494
|
+
throw error;
|
|
495
|
+
}
|
|
496
|
+
if (!skipResourceTransaction) {
|
|
497
|
+
await this.octo['commitTransaction'](app, response.modelTransaction, response.resourceTransaction);
|
|
498
|
+
}
|
|
499
|
+
// Establish the HCL diff baseline from the same transaction that just applied the models, so the
|
|
500
|
+
// next runModules() render reports its `diff` against the committed state. Captured before
|
|
501
|
+
// reset(), which wipes the model attribution renderAllModules() depends on.
|
|
502
|
+
this.previousHcl = HclUtility.serialize(terraformService.renderAllModules());
|
|
503
|
+
const inputService = await this.container.get(InputService);
|
|
504
|
+
for (const moduleId of filterByModuleIds) {
|
|
505
|
+
response.modelDiffs = response.modelDiffs
|
|
506
|
+
.map((i) => i.filter((j) => {
|
|
507
|
+
if (j.node instanceof AModel && !(j.node instanceof AOverlay)) {
|
|
508
|
+
return inputService.getModuleIdFromModel(j.node) === moduleId;
|
|
509
|
+
}
|
|
510
|
+
else if (j.node instanceof AOverlay) {
|
|
511
|
+
return inputService.getModuleIdFromOverlay(j.node) === moduleId;
|
|
512
|
+
}
|
|
513
|
+
else {
|
|
514
|
+
return false;
|
|
515
|
+
}
|
|
516
|
+
}))
|
|
517
|
+
.filter((i) => i.length);
|
|
518
|
+
response.modelTransaction = response.modelTransaction
|
|
519
|
+
.map((i) => i.filter((j) => {
|
|
520
|
+
if (j.node instanceof AModel && !(j.node instanceof AOverlay)) {
|
|
521
|
+
return inputService.getModuleIdFromModel(j.node) === moduleId;
|
|
522
|
+
}
|
|
523
|
+
else if (j.node instanceof AOverlay) {
|
|
524
|
+
return inputService.getModuleIdFromOverlay(j.node) === moduleId;
|
|
525
|
+
}
|
|
526
|
+
else {
|
|
527
|
+
return false;
|
|
528
|
+
}
|
|
529
|
+
}))
|
|
530
|
+
.filter((i) => i.length);
|
|
531
|
+
response.resourceDiffs = response.resourceDiffs
|
|
532
|
+
.map((i) => i.filter((j) => {
|
|
533
|
+
if (j.node instanceof AResource) {
|
|
534
|
+
return inputService.getModuleIdFromResource(j.node) === moduleId;
|
|
535
|
+
}
|
|
536
|
+
else {
|
|
537
|
+
return false;
|
|
538
|
+
}
|
|
539
|
+
}))
|
|
540
|
+
.filter((i) => i.length);
|
|
541
|
+
if (!skipResourceTransaction) {
|
|
542
|
+
response.resourceTransaction = response.resourceTransaction
|
|
543
|
+
.map((i) => i.filter((j) => {
|
|
544
|
+
if (j.node instanceof AResource) {
|
|
545
|
+
return inputService.getModuleIdFromResource(j.node) === moduleId;
|
|
546
|
+
}
|
|
547
|
+
else {
|
|
548
|
+
return false;
|
|
549
|
+
}
|
|
550
|
+
}))
|
|
551
|
+
.filter((i) => i.length);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
await this.reset();
|
|
555
|
+
return response;
|
|
324
556
|
}
|
|
325
557
|
}
|
|
326
558
|
//# sourceMappingURL=test-module.container.js.map
|