@quadnix/octo 0.0.29 → 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 +77 -0
- package/dist/errors/transaction.error.js +83 -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 -24
- package/dist/modules/test-module.container.js +410 -163
- 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,112 +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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
await this.stateProvider.unlockApp(appLockId);
|
|
67
|
-
const container = Container.getInstance();
|
|
68
|
-
const inputService = await container.get(InputService);
|
|
69
|
-
for (const moduleId of filterByModuleIds) {
|
|
70
|
-
response.modelDiffs = response.modelDiffs
|
|
71
|
-
.map((i) => i.filter((j) => {
|
|
72
|
-
if (j.node instanceof AModel && !(j.node instanceof AOverlay)) {
|
|
73
|
-
return inputService.getModuleIdFromModel(j.node) === moduleId;
|
|
74
|
-
}
|
|
75
|
-
else if (j.node instanceof AOverlay) {
|
|
76
|
-
return inputService.getModuleIdFromOverlay(j.node) === moduleId;
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
return false;
|
|
80
|
-
}
|
|
81
|
-
}))
|
|
82
|
-
.filter((i) => i.length);
|
|
83
|
-
response.modelTransaction = response.modelTransaction
|
|
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.resourceDiffs = response.resourceDiffs
|
|
97
|
-
.map((i) => i.filter((j) => {
|
|
98
|
-
if (j.node instanceof AResource) {
|
|
99
|
-
return inputService.getModuleIdFromResource(j.node) === moduleId;
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
102
|
-
return false;
|
|
103
|
-
}
|
|
104
|
-
}))
|
|
105
|
-
.filter((i) => i.length);
|
|
106
|
-
response.resourceTransaction = response.resourceTransaction
|
|
107
|
-
.map((i) => i.filter((j) => {
|
|
108
|
-
if (j.node instanceof AResource) {
|
|
109
|
-
return inputService.getModuleIdFromResource(j.node) === moduleId;
|
|
110
|
-
}
|
|
111
|
-
else {
|
|
112
|
-
return false;
|
|
113
|
-
}
|
|
114
|
-
}))
|
|
115
|
-
.filter((i) => i.length);
|
|
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);
|
|
116
125
|
}
|
|
117
|
-
|
|
118
|
-
return response;
|
|
126
|
+
return result;
|
|
119
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* To build a throwaway anchor for a test double, without declaring an anchor class.
|
|
130
|
+
*/
|
|
120
131
|
createTestAnchor(anchorId, properties, parent) {
|
|
121
132
|
return new TestAnchor(anchorId, properties, parent);
|
|
122
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
|
+
*/
|
|
123
138
|
async createTestModels(moduleId, args) {
|
|
124
|
-
const container =
|
|
139
|
+
const container = this.container;
|
|
125
140
|
const [inputService, moduleContainer, transactionService] = await Promise.all([
|
|
126
141
|
container.get(InputService),
|
|
127
142
|
container.get(ModuleContainer),
|
|
@@ -133,16 +148,11 @@ export class TestModuleContainer {
|
|
|
133
148
|
moduleContainer.unload(UniversalTestModule);
|
|
134
149
|
const result = create(args);
|
|
135
150
|
for (const models of Object.values(result)) {
|
|
136
|
-
// Check if the model has already been registered.
|
|
137
|
-
// If no error thrown, the model has already been registered.
|
|
138
151
|
for (const model of models) {
|
|
139
|
-
|
|
140
|
-
|
|
152
|
+
// Skip models that are already registered (a defined moduleId means it is known).
|
|
153
|
+
if (inputService.getModuleIdFromModel(model) !== undefined) {
|
|
141
154
|
continue;
|
|
142
155
|
}
|
|
143
|
-
catch (error) {
|
|
144
|
-
/* do nothing. */
|
|
145
|
-
}
|
|
146
156
|
inputService.registerModel(moduleId, model);
|
|
147
157
|
const universalAction = new UniversalModelAction();
|
|
148
158
|
Object.assign(universalAction, {
|
|
@@ -162,41 +172,44 @@ export class TestModuleContainer {
|
|
|
162
172
|
}
|
|
163
173
|
return result;
|
|
164
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
|
+
*/
|
|
165
179
|
async createTestOverlays(moduleId, args) {
|
|
166
|
-
const container =
|
|
167
|
-
const [inputService, moduleContainer
|
|
180
|
+
const container = this.container;
|
|
181
|
+
const [inputService, moduleContainer] = await Promise.all([
|
|
168
182
|
container.get(InputService),
|
|
169
183
|
container.get(ModuleContainer),
|
|
170
|
-
container.get(TransactionService),
|
|
171
184
|
]);
|
|
172
185
|
// Register new moduleId as instance of the universal module.
|
|
173
186
|
moduleContainer.load(UniversalTestModule, moduleId, {});
|
|
174
187
|
// Immediately unload the universal module to ensure it does not run in apply().
|
|
175
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
|
+
}
|
|
176
201
|
const result = await createTestOverlays(args);
|
|
177
202
|
for (const overlay of Object.values(result)) {
|
|
178
203
|
inputService.registerOverlay(moduleId, overlay);
|
|
179
|
-
const universalAction = new UniversalModelAction();
|
|
180
|
-
Object.assign(universalAction, {
|
|
181
|
-
constructor: { name: `${UniversalModelAction.name}For${overlay.constructor.name}` },
|
|
182
|
-
});
|
|
183
|
-
try {
|
|
184
|
-
transactionService.unregisterOverlayActions(overlay.constructor);
|
|
185
|
-
transactionService.registerOverlayActions(overlay.constructor, [
|
|
186
|
-
universalAction,
|
|
187
|
-
]);
|
|
188
|
-
}
|
|
189
|
-
catch (error) {
|
|
190
|
-
if (error.message !==
|
|
191
|
-
`Action "${universalAction.constructor.name}" already registered for overlay "${overlay.constructor.name}"!`) {
|
|
192
|
-
throw error;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
204
|
}
|
|
196
205
|
return result;
|
|
197
206
|
}
|
|
198
|
-
|
|
199
|
-
|
|
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;
|
|
200
213
|
const [inputService, moduleContainer] = await Promise.all([
|
|
201
214
|
container.get(InputService),
|
|
202
215
|
container.get(ModuleContainer),
|
|
@@ -205,43 +218,66 @@ export class TestModuleContainer {
|
|
|
205
218
|
moduleContainer.load(UniversalTestModule, moduleId, {});
|
|
206
219
|
// Immediately unload the universal module to ensure it does not run in apply().
|
|
207
220
|
moduleContainer.unload(UniversalTestModule);
|
|
208
|
-
|
|
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);
|
|
209
235
|
for (const resource of Object.values(result)) {
|
|
210
236
|
inputService.registerResource(moduleId, resource);
|
|
211
237
|
}
|
|
212
238
|
return result;
|
|
213
239
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
new UniversalResourceAction(),
|
|
231
|
-
]);
|
|
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()}`);
|
|
232
256
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
}
|
|
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()}`);
|
|
238
269
|
}
|
|
239
270
|
}
|
|
240
|
-
return
|
|
241
|
-
}
|
|
242
|
-
mapTransactionActions(transaction) {
|
|
243
|
-
return transaction.map((i) => i.map((j) => j.actions.map((a) => a.constructor.name)).flat());
|
|
271
|
+
return changes;
|
|
244
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
|
+
*/
|
|
245
281
|
async initialize(stateProvider, initializeInContainer, excludeInContainer) {
|
|
246
282
|
if (stateProvider &&
|
|
247
283
|
!(stateProvider instanceof LocalEncryptionStateProvider ||
|
|
@@ -252,36 +288,90 @@ export class TestModuleContainer {
|
|
|
252
288
|
this.stateProvider = stateProvider ?? new TestStateProvider();
|
|
253
289
|
await this.octo.initialize(this.stateProvider, initializeInContainer, excludeInContainer);
|
|
254
290
|
// Always register the UniversalTestModule to allow users to create test prerequisites.
|
|
255
|
-
const moduleContainer = await
|
|
291
|
+
const moduleContainer = await this.container.get(ModuleContainer);
|
|
256
292
|
moduleContainer.register(UniversalTestModule, { packageName: '@octo' });
|
|
257
293
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
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);
|
|
261
304
|
}
|
|
262
|
-
|
|
263
|
-
|
|
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());
|
|
264
311
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
}
|
|
271
|
-
const moduleMetadata = moduleContainer.getMetadata(module.type);
|
|
272
|
-
if (module.hidden === true) {
|
|
273
|
-
moduleContainer.unload(moduleMetadata.module);
|
|
274
|
-
}
|
|
275
|
-
else {
|
|
276
|
-
moduleContainer.load(moduleMetadata.module, module.moduleId, module.inputs);
|
|
277
|
-
}
|
|
278
|
-
return (await this.octo.compose());
|
|
312
|
+
/**
|
|
313
|
+
* See {@link Octo.registerHooks}.
|
|
314
|
+
*/
|
|
315
|
+
registerHooks(...args) {
|
|
316
|
+
return this.octo.registerHooks(...args);
|
|
279
317
|
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
318
|
+
/**
|
|
319
|
+
* See {@link Octo.registerTags}.
|
|
320
|
+
*/
|
|
321
|
+
registerTags(...args) {
|
|
322
|
+
return this.octo.registerTags(...args);
|
|
323
|
+
}
|
|
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);
|
|
335
|
+
}
|
|
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) {
|
|
285
375
|
moduleContainer.register(module.type, {
|
|
286
376
|
packageName: module.type.MODULE_PACKAGE,
|
|
287
377
|
});
|
|
@@ -294,18 +384,175 @@ export class TestModuleContainer {
|
|
|
294
384
|
moduleContainer.load(moduleMetadata.module, module.moduleId, module.inputs);
|
|
295
385
|
}
|
|
296
386
|
}
|
|
297
|
-
|
|
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 };
|
|
298
458
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
await
|
|
304
|
-
|
|
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,
|
|
305
478
|
});
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
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;
|
|
309
556
|
}
|
|
310
557
|
}
|
|
311
558
|
//# sourceMappingURL=test-module.container.js.map
|