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