@aifabrix/builder 2.43.0 → 2.44.1
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/.cursor/rules/anchor-docs.mdc +15 -0
- package/.cursor/rules/cli-layout.mdc +75 -0
- package/.cursor/rules/project-rules.mdc +8 -0
- package/.npmrc.token +1 -0
- package/.nyc_output/55e9d034-ddab-4579-a706-e02a91d75c91.json +1 -0
- package/.nyc_output/processinfo/55e9d034-ddab-4579-a706-e02a91d75c91.json +1 -0
- package/.nyc_output/processinfo/index.json +1 -0
- package/README.md +1 -1
- package/anchor-docs/README.md +10 -0
- package/anchor-docs/_TEMPLATE +24 -0
- package/bin/aifabrix.js +13 -4
- package/integration/hubspot-test/README.md +31 -0
- package/integration/hubspot-test/create-hubspot.js +5 -5
- package/integration/hubspot-test/hubspot-test-datasource-company.json +58 -462
- package/integration/hubspot-test/hubspot-test-datasource-contact.json +61 -555
- package/integration/hubspot-test/hubspot-test-datasource-deal.json +63 -506
- package/integration/hubspot-test/hubspot-test-datasource-users.json +42 -83
- package/integration/hubspot-test/hubspot-test-deploy.json +3 -3
- package/integration/hubspot-test/test-dataplane-down-tests.js +1 -7
- package/integration/hubspot-test/test-dataplane-down.js +3 -3
- package/integration/hubspot-test/test.js +35 -43
- package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +23 -0
- package/integration/roundtrip-test-local/README.md +144 -0
- package/integration/roundtrip-test-local/application.yaml +13 -0
- package/integration/roundtrip-test-local/env.template +15 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +14 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +61 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +25 -0
- package/integration/roundtrip-test-local2/README.md +144 -0
- package/integration/roundtrip-test-local2/application.yaml +13 -0
- package/integration/roundtrip-test-local2/env.template +15 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +31 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +86 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +25 -0
- package/integration/test/wizard.yaml +8 -0
- package/jest.config.default.js +10 -0
- package/jest.config.integration.fixtures.js +22 -0
- package/jest.config.integration.js +21 -18
- package/jest.config.isolated.js +10 -0
- package/jest.projects.js +301 -0
- package/lib/api/certificates.api.js +62 -0
- package/lib/api/datasources-core.api.js +3 -3
- package/lib/api/dev-mtls-request.js +110 -0
- package/lib/api/dev-server-https.js +145 -0
- package/lib/api/dev.api.js +133 -144
- package/lib/api/index.js +11 -3
- package/lib/api/pipeline.api.js +67 -20
- package/lib/api/types/certificates.types.js +48 -0
- package/lib/api/types/dev.types.js +4 -3
- package/lib/api/types/pipeline.types.js +8 -5
- package/lib/api/types/validation-run.types.js +56 -0
- package/lib/api/validation-run.api.js +111 -0
- package/lib/api/validation-runner.js +109 -0
- package/lib/app/certification-show-enrich.js +129 -0
- package/lib/app/certification-verify-rows.js +60 -0
- package/lib/app/config.js +1 -1
- package/lib/app/deploy-status-display.js +2 -2
- package/lib/app/deploy.js +7 -6
- package/lib/app/display.js +2 -1
- package/lib/app/dockerfile.js +3 -2
- package/lib/app/down.js +2 -1
- package/lib/app/helpers.js +6 -5
- package/lib/app/index.js +27 -8
- package/lib/app/list.js +7 -6
- package/lib/app/push.js +4 -3
- package/lib/app/register.js +16 -7
- package/lib/app/rotate-secret.js +14 -13
- package/lib/app/run-container-start.js +184 -0
- package/lib/app/run-docker-fallback.js +108 -0
- package/lib/app/run-env-compose.js +30 -42
- package/lib/app/run-helpers.js +49 -126
- package/lib/app/run-infra-requirements.js +30 -0
- package/lib/app/run-resolve-image.js +21 -0
- package/lib/app/run.js +74 -21
- package/lib/app/show-display.js +44 -1
- package/lib/app/show.js +93 -9
- package/lib/build/index.js +13 -10
- package/lib/certification/cli-cert-sync-skip.js +21 -0
- package/lib/certification/merge-certification-from-artifact.js +185 -0
- package/lib/certification/post-unified-cert-sync.js +33 -0
- package/lib/certification/sync-after-external-command.js +52 -0
- package/lib/certification/sync-system-certification.js +197 -0
- package/lib/cli/index.js +2 -0
- package/lib/cli/setup-app.help.js +67 -0
- package/lib/cli/setup-app.js +61 -121
- package/lib/cli/setup-app.test-commands.js +195 -0
- package/lib/cli/setup-auth.js +19 -5
- package/lib/cli/setup-credential-deployment.js +22 -8
- package/lib/cli/setup-dev-path-commands.js +124 -0
- package/lib/cli/setup-dev.js +170 -113
- package/lib/cli/setup-environment.js +7 -1
- package/lib/cli/setup-external-system.js +84 -23
- package/lib/cli/setup-infra.js +126 -47
- package/lib/cli/setup-parameters.js +32 -0
- package/lib/cli/setup-secrets.js +137 -18
- package/lib/cli/setup-service-user.js +1 -1
- package/lib/cli/setup-utility.js +54 -22
- package/lib/commands/app-down.js +5 -7
- package/lib/commands/app-install.js +14 -7
- package/lib/commands/app-logs.js +13 -10
- package/lib/commands/app-shell.js +4 -1
- package/lib/commands/app-test.js +25 -19
- package/lib/commands/app.js +32 -11
- package/lib/commands/auth-config.js +6 -6
- package/lib/commands/auth-status.js +4 -3
- package/lib/commands/credential-env.js +4 -3
- package/lib/commands/credential-list.js +5 -4
- package/lib/commands/credential-push.js +4 -3
- package/lib/commands/datasource-unified-test-cli.js +428 -0
- package/lib/commands/datasource-unified-test-cli.options.js +191 -0
- package/lib/commands/datasource-unified-test-e2e-cli-helpers.js +106 -0
- package/lib/commands/datasource-validation-cli.js +143 -0
- package/lib/commands/datasource.js +125 -95
- package/lib/commands/deployment-list.js +6 -5
- package/lib/commands/dev-cli-handlers.js +122 -18
- package/lib/commands/dev-down.js +4 -3
- package/lib/commands/dev-init.js +231 -116
- package/lib/commands/dev-show-display.js +473 -0
- package/lib/commands/login-credentials.js +3 -2
- package/lib/commands/login-device.js +4 -3
- package/lib/commands/login.js +5 -4
- package/lib/commands/logout.js +8 -7
- package/lib/commands/parameters-validate.js +54 -0
- package/lib/commands/repair-datasource.js +314 -68
- package/lib/commands/repair-env-template.js +2 -2
- package/lib/commands/repair.js +21 -3
- package/lib/commands/secrets-list.js +23 -12
- package/lib/commands/secrets-remove-all.js +220 -0
- package/lib/commands/secrets-remove.js +21 -12
- package/lib/commands/secrets-set.js +21 -12
- package/lib/commands/secrets-validate.js +4 -4
- package/lib/commands/secure.js +10 -9
- package/lib/commands/service-user.js +26 -25
- package/lib/commands/test-e2e-external.js +27 -1
- package/lib/commands/up-common.js +3 -2
- package/lib/commands/up-dataplane.js +29 -16
- package/lib/commands/up-miso.js +19 -29
- package/lib/commands/upload.js +149 -39
- package/lib/commands/wizard-core-helpers.js +1 -1
- package/lib/commands/wizard-dataplane.js +4 -3
- package/lib/commands/wizard-helpers.js +3 -3
- package/lib/commands/wizard.js +2 -2
- package/lib/core/admin-secrets.js +14 -5
- package/lib/core/audit-logger.js +12 -4
- package/lib/core/config-attach-extensions.js +46 -0
- package/lib/core/config-runtime-paths.js +29 -0
- package/lib/core/config.js +55 -56
- package/lib/core/diff.js +3 -2
- package/lib/core/ensure-encryption-key.js +1 -1
- package/lib/core/secrets-ensure-infra.js +77 -0
- package/lib/core/secrets-ensure.js +120 -64
- package/lib/core/secrets-env-write.js +35 -7
- package/lib/core/secrets-infra-placeholder-sync.js +61 -0
- package/lib/core/secrets.js +200 -37
- package/lib/core/templates-env.js +4 -3
- package/lib/datasource/abac-validator.js +1 -10
- package/lib/datasource/deploy.js +75 -53
- package/lib/datasource/field-reference-validator.js +9 -6
- package/lib/datasource/integration-context.js +63 -0
- package/lib/datasource/list.js +8 -7
- package/lib/datasource/log-viewer.js +189 -67
- package/lib/datasource/resolve-app.js +4 -4
- package/lib/datasource/test-e2e.js +113 -146
- package/lib/datasource/test-integration.js +114 -122
- package/lib/datasource/unified-validation-run-body.js +68 -0
- package/lib/datasource/unified-validation-run-post.js +23 -0
- package/lib/datasource/unified-validation-run-resolve.js +43 -0
- package/lib/datasource/unified-validation-run.js +93 -0
- package/lib/datasource/validate.js +157 -13
- package/lib/deployment/deployer.js +4 -3
- package/lib/deployment/environment.js +7 -6
- package/lib/deployment/push.js +17 -8
- package/lib/external-system/delete.js +4 -3
- package/lib/external-system/deploy.js +166 -53
- package/lib/external-system/download-helpers.js +1 -1
- package/lib/external-system/download.js +7 -6
- package/lib/external-system/generator.js +92 -6
- package/lib/external-system/integration-test-dispatch.js +26 -0
- package/lib/external-system/test-execution.js +5 -1
- package/lib/external-system/test-helpers.js +0 -4
- package/lib/external-system/test-system-level-helpers.js +110 -0
- package/lib/external-system/test-system-level.js +83 -44
- package/lib/external-system/test.js +59 -8
- package/lib/generator/builders.js +23 -11
- package/lib/generator/deploy-manifest-azure-kv.js +81 -0
- package/lib/generator/external.js +16 -4
- package/lib/generator/helpers.js +58 -3
- package/lib/generator/index.js +4 -0
- package/lib/generator/split-readme.js +12 -7
- package/lib/generator/split-variables.js +2 -1
- package/lib/generator/split.js +1 -1
- package/lib/generator/wizard-readme.js +3 -3
- package/lib/generator/wizard.js +8 -8
- package/lib/infrastructure/compose.js +70 -7
- package/lib/infrastructure/helpers-docker-check.js +67 -0
- package/lib/infrastructure/helpers.js +203 -42
- package/lib/infrastructure/index.js +31 -18
- package/lib/infrastructure/services.js +21 -67
- package/lib/internal/fs-real-sync.js +104 -0
- package/lib/internal/node-fs.js +98 -0
- package/lib/parameters/database-secret-values.js +173 -0
- package/lib/parameters/infra-kv-discovery.js +121 -0
- package/lib/parameters/infra-parameter-catalog.js +458 -0
- package/lib/parameters/infra-parameter-validate.js +64 -0
- package/lib/schema/application-schema.json +37 -17
- package/lib/schema/datasource-test-run.schema.json +493 -0
- package/lib/schema/deployment-rules.yaml +102 -63
- package/lib/schema/external-datasource.schema.json +1200 -442
- package/lib/schema/external-system.schema.json +203 -5
- package/lib/schema/flag-map-validation-run.json +31 -0
- package/lib/schema/infra-parameter.schema.json +106 -0
- package/lib/schema/infra.parameter.yaml +421 -0
- package/lib/schema/type/credential-auth-templates.json +40 -0
- package/lib/schema/type/document-storage.json +226 -0
- package/lib/schema/type/message-service.json +123 -0
- package/lib/schema/type/vector-store.json +88 -0
- package/lib/utils/aifabrix-runtime-config-dir.js +132 -0
- package/lib/utils/api-error-handler.js +2 -2
- package/lib/utils/api.js +77 -17
- package/lib/utils/app-register-api.js +3 -2
- package/lib/utils/app-register-auth.js +1 -1
- package/lib/utils/app-register-config.js +4 -4
- package/lib/utils/app-register-display.js +3 -2
- package/lib/utils/app-register-validator.js +3 -2
- package/lib/utils/app-run-containers.js +26 -22
- package/lib/utils/app-scoped-config.js +31 -0
- package/lib/utils/app-service-env-from-builder.js +164 -0
- package/lib/utils/build-copy.js +1 -1
- package/lib/utils/build-helpers.js +20 -20
- package/lib/utils/build-resolve-image.js +165 -0
- package/lib/utils/cli-layout-chalk.js +8 -0
- package/lib/utils/cli-test-layout-chalk.js +267 -0
- package/lib/utils/cli-utils.js +88 -11
- package/lib/utils/compose-db-passwords.js +138 -0
- package/lib/utils/compose-generate-docker-compose.js +216 -0
- package/lib/utils/compose-generator.js +197 -291
- package/lib/utils/compose-miso-env.js +18 -0
- package/lib/utils/compose-traefik-ingress-base.js +158 -0
- package/lib/utils/config-paths.js +166 -7
- package/lib/utils/config-scoped-resources-preference.js +41 -0
- package/lib/utils/configuration-env-resolver.js +11 -8
- package/lib/utils/controller-deployment-outcome.js +68 -0
- package/lib/utils/credential-display.js +2 -2
- package/lib/utils/credential-secrets-env.js +5 -5
- package/lib/utils/dataplane-pipeline-warning.js +4 -3
- package/lib/utils/datasource-test-run-capability-scope.js +43 -0
- package/lib/utils/datasource-test-run-certificate-tty.js +82 -0
- package/lib/utils/datasource-test-run-debug-display.js +137 -0
- package/lib/utils/datasource-test-run-debug-slice.js +93 -0
- package/lib/utils/datasource-test-run-display.js +459 -0
- package/lib/utils/datasource-test-run-exit.js +83 -0
- package/lib/utils/datasource-test-run-legacy-adapter.js +93 -0
- package/lib/utils/datasource-test-run-report-version.js +51 -0
- package/lib/utils/datasource-test-run-schema-sync.js +59 -0
- package/lib/utils/datasource-test-run-tty-log.js +81 -0
- package/lib/utils/datasource-validation-watch.js +266 -0
- package/lib/utils/declarative-url-ports.js +47 -0
- package/lib/utils/derive-env-key-from-client-id.js +41 -0
- package/lib/utils/dev-ca-install.js +185 -23
- package/lib/utils/dev-cert-helper.js +266 -17
- package/lib/utils/dev-hosts-helper.js +307 -0
- package/lib/utils/dev-init-cert-hints.js +37 -0
- package/lib/utils/dev-init-health-messages.js +52 -0
- package/lib/utils/dev-init-resolve.js +86 -0
- package/lib/utils/dev-init-ssh-merge.js +65 -0
- package/lib/utils/dev-ssh-config-helper.js +196 -0
- package/lib/utils/dev-user-groups.js +93 -0
- package/lib/utils/docker-build.js +42 -17
- package/lib/utils/docker-exec.js +28 -0
- package/lib/utils/docker-manifest-public-port.js +116 -0
- package/lib/utils/docker-not-running-hint.js +52 -0
- package/lib/utils/docker.js +98 -11
- package/lib/utils/ensure-dev-certs-for-remote-docker.js +192 -0
- package/lib/utils/env-config-loader.js +10 -91
- package/lib/utils/env-copy.js +19 -10
- package/lib/utils/env-map.js +35 -8
- package/lib/utils/env-template.js +2 -2
- package/lib/utils/environment-scoped-resources.js +144 -0
- package/lib/utils/error-formatter.js +92 -13
- package/lib/utils/error-formatters/http-status-errors.js +6 -5
- package/lib/utils/error-formatters/network-errors.js +2 -1
- package/lib/utils/error-formatters/permission-errors.js +2 -1
- package/lib/utils/error-formatters/validation-errors.js +2 -1
- package/lib/utils/external-readme.js +8 -1
- package/lib/utils/external-system-display.js +242 -136
- package/lib/utils/external-system-local-test-tty.js +389 -0
- package/lib/utils/external-system-readiness-core.js +377 -0
- package/lib/utils/external-system-readiness-deploy-display.js +270 -0
- package/lib/utils/external-system-readiness-display-internals.js +150 -0
- package/lib/utils/external-system-readiness-display.js +186 -0
- package/lib/utils/external-system-system-test-tty-overview.js +120 -0
- package/lib/utils/external-system-system-test-tty.js +417 -0
- package/lib/utils/external-system-test-helpers.js +24 -6
- package/lib/utils/external-system-validators.js +30 -12
- package/lib/utils/health-check-url.js +119 -0
- package/lib/utils/health-check.js +59 -25
- package/lib/utils/help-builder.js +11 -8
- package/lib/utils/image-version.js +4 -8
- package/lib/utils/infra-containers.js +4 -7
- package/lib/utils/infra-env-defaults.js +162 -0
- package/lib/utils/infra-status-display.js +167 -0
- package/lib/utils/infra-status.js +16 -8
- package/lib/utils/local-secrets.js +3 -4
- package/lib/utils/paths.js +148 -47
- package/lib/utils/port-resolver.js +10 -23
- package/lib/utils/redis-env-scope.js +62 -0
- package/lib/utils/register-aifabrix-shell-env.js +204 -0
- package/lib/utils/remote-builder-validation.js +99 -0
- package/lib/utils/remote-dev-auth.js +117 -21
- package/lib/utils/remote-docker-env.js +67 -15
- package/lib/utils/remote-secrets-loader.js +13 -4
- package/lib/utils/resolve-docker-image-ref.js +124 -0
- package/lib/utils/schema-loader.js +22 -9
- package/lib/utils/secrets-bash-kv.js +25 -0
- package/lib/utils/secrets-generator.js +169 -49
- package/lib/utils/secrets-helpers.js +70 -59
- package/lib/utils/secrets-kv-scope.js +60 -0
- package/lib/utils/secrets-utils.js +32 -38
- package/lib/utils/secrets-validation.js +3 -1
- package/lib/utils/secrets-yaml-preserve.js +109 -0
- package/lib/utils/ssh-key-helper.js +4 -2
- package/lib/utils/template-helpers.js +2 -2
- package/lib/utils/test-log-writer.js +3 -3
- package/lib/utils/token-manager.js +1 -2
- package/lib/utils/url-declarative-public-base.js +188 -0
- package/lib/utils/url-declarative-resolve-build.js +493 -0
- package/lib/utils/url-declarative-resolve-load-doc.js +51 -0
- package/lib/utils/url-declarative-resolve.js +220 -0
- package/lib/utils/url-declarative-token-parse.js +74 -0
- package/lib/utils/url-declarative-url-flags.js +50 -0
- package/lib/utils/url-declarative-vdir-inactive-env.js +99 -0
- package/lib/utils/url-public-path-prefix.js +34 -0
- package/lib/utils/urls-local-registry.js +220 -0
- package/lib/utils/validation-report-tty-kit.js +77 -0
- package/lib/utils/validation-run-poll.js +112 -0
- package/lib/utils/validation-run-post-retry.js +85 -0
- package/lib/utils/validation-run-request.js +116 -0
- package/lib/utils/variable-transformer.js +21 -4
- package/lib/utils/yaml-preserve.js +33 -14
- package/lib/validation/datasource-warnings.js +56 -0
- package/lib/validation/env-template-auth.js +1 -1
- package/lib/validation/external-manifest-validator.js +27 -7
- package/lib/validation/validate-display.js +37 -31
- package/lib/validation/validate-external-cert-sync.js +23 -0
- package/lib/validation/validate.js +8 -14
- package/lib/validation/validator-unresolved-placeholders.js +98 -0
- package/lib/validation/validator.js +22 -65
- package/lib/validation/wizard-config-validator.js +2 -1
- package/package.json +9 -4
- package/scripts/check-datasource-test-run-schema-sync.js +34 -0
- package/scripts/diagnose-cli.js +150 -0
- package/scripts/install-local.js +307 -55
- package/scripts/pnpm-global-remove.js +48 -0
- package/templates/README.md +15 -2
- package/templates/applications/dataplane/application.yaml +52 -2
- package/templates/applications/dataplane/env.template +79 -17
- package/templates/applications/dataplane/rbac.yaml +8 -0
- package/templates/applications/keycloak/application.yaml +9 -1
- package/templates/applications/keycloak/env.template +15 -6
- package/templates/applications/miso-controller/application.yaml +10 -2
- package/templates/applications/miso-controller/env.template +42 -12
- package/templates/applications/miso-controller/rbac.yaml +5 -0
- package/templates/external-system/README.md.hbs +20 -7
- package/templates/external-system/deploy.js.hbs +5 -5
- package/templates/external-system/external-datasource.yaml.hbs +197 -118
- package/templates/infra/compose.yaml.hbs +33 -16
- package/templates/infra/servers.json.hbs +3 -1
- package/templates/python/docker-compose.hbs +16 -0
- package/templates/typescript/docker-compose.hbs +16 -0
- package/lib/api/external-test.api.js +0 -111
- package/lib/schema/env-config.yaml +0 -60
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Build ValidationRunRequest body for unified datasource runs.
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 2.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const {
|
|
8
|
+
buildExternalDataSourceValidationRequest,
|
|
9
|
+
buildE2eOptionsFromCli,
|
|
10
|
+
includeDebugForRequest
|
|
11
|
+
} = require('../utils/validation-run-request');
|
|
12
|
+
const testHelpers = require('../utils/external-system-test-helpers');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param {Object} params
|
|
16
|
+
* @param {string} params.systemKey
|
|
17
|
+
* @param {string} params.datasourceKey
|
|
18
|
+
* @param {'test'|'integration'|'e2e'} params.runType
|
|
19
|
+
* @param {Object} params.datasource - Loaded datasource config
|
|
20
|
+
* @param {string} [params.payloadPath]
|
|
21
|
+
* @param {boolean} params.useAsync
|
|
22
|
+
* @param {Object} params.options - CLI options (debug, verbose, e2e fields, capabilityKey)
|
|
23
|
+
* @returns {Promise<import('../api/types/validation-run.types').ValidationRunRequestBody>}
|
|
24
|
+
*/
|
|
25
|
+
async function buildUnifiedValidationBody(params) {
|
|
26
|
+
const { systemKey, datasourceKey, runType, datasource, payloadPath, useAsync, options } = params;
|
|
27
|
+
|
|
28
|
+
let payloadTemplate;
|
|
29
|
+
if (payloadPath || runType === 'integration') {
|
|
30
|
+
const customPayload = await testHelpers.loadCustomPayload(payloadPath);
|
|
31
|
+
payloadTemplate = testHelpers.determinePayloadTemplate(datasource, datasourceKey, customPayload);
|
|
32
|
+
if (runType === 'integration' && !payloadTemplate) {
|
|
33
|
+
throw new Error(`No test payload found for datasource '${datasourceKey}'`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const e2eExtra = options.capabilityKey
|
|
38
|
+
? { capabilityKeys: [String(options.capabilityKey).trim()] }
|
|
39
|
+
: undefined;
|
|
40
|
+
const e2eOptions =
|
|
41
|
+
runType === 'e2e'
|
|
42
|
+
? buildE2eOptionsFromCli({
|
|
43
|
+
debug: options.debug,
|
|
44
|
+
verbose: options.verbose,
|
|
45
|
+
testCrud: options.testCrud,
|
|
46
|
+
recordId: options.recordId,
|
|
47
|
+
cleanup: options.cleanup,
|
|
48
|
+
primaryKeyValue: options.primaryKeyValue,
|
|
49
|
+
minVectorHits: options.minVectorHits,
|
|
50
|
+
minProcessed: options.minProcessed,
|
|
51
|
+
minRecordCount: options.minRecordCount,
|
|
52
|
+
e2eOptionsExtra: e2eExtra
|
|
53
|
+
})
|
|
54
|
+
: undefined;
|
|
55
|
+
|
|
56
|
+
return buildExternalDataSourceValidationRequest({
|
|
57
|
+
systemKey,
|
|
58
|
+
datasourceKey,
|
|
59
|
+
runType,
|
|
60
|
+
payloadTemplate,
|
|
61
|
+
asyncRun: runType === 'e2e' && useAsync === true,
|
|
62
|
+
includeDebug: includeDebugForRequest(options.debug),
|
|
63
|
+
explain: options.verbose === true,
|
|
64
|
+
e2eOptions: e2eOptions && Object.keys(e2eOptions).length > 0 ? e2eOptions : undefined
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
module.exports = { buildUnifiedValidationBody };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview POST + optional poll for unified validation run (keeps main module small).
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 2.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { postValidationRunAndOptionalPoll } = require('../api/validation-runner');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @param {Object} opts
|
|
11
|
+
* @param {string} opts.dataplaneUrl
|
|
12
|
+
* @param {Object} opts.authConfig
|
|
13
|
+
* @param {Object} opts.body
|
|
14
|
+
* @param {number} opts.timeoutMs
|
|
15
|
+
* @param {boolean} opts.useAsync
|
|
16
|
+
* @param {boolean} opts.noAsync
|
|
17
|
+
* @returns {Promise<{ envelope: Object|null, apiError: Object|null, pollTimedOut: boolean, incompleteNoAsync: boolean }>}
|
|
18
|
+
*/
|
|
19
|
+
/* eslint-disable max-lines-per-function, max-statements, complexity -- POST + poll orchestration */
|
|
20
|
+
// Re-exported thin wrapper; single implementation lives in lib/api/validation-runner.js
|
|
21
|
+
/* eslint-enable max-lines-per-function, max-statements, complexity */
|
|
22
|
+
|
|
23
|
+
module.exports = { postValidationRunAndOptionalPoll };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Resolve datasource file path + parsed config for unified validation.
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 2.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const { getIntegrationPath } = require('../utils/paths');
|
|
9
|
+
const { resolveApplicationConfigPath } = require('../utils/app-config-resolver');
|
|
10
|
+
const { loadConfigFile } = require('../utils/config-format');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @param {string} appKey
|
|
14
|
+
* @param {string} datasourceKey
|
|
15
|
+
* @param {Function} findDatasourceFileByKey - From integration-context
|
|
16
|
+
* @returns {{ datasource: Object, datasourcePath: string }}
|
|
17
|
+
*/
|
|
18
|
+
function loadDatasourceForApp(appKey, datasourceKey, findDatasourceFileByKey) {
|
|
19
|
+
const appPath = getIntegrationPath(appKey);
|
|
20
|
+
const config = loadConfigFile(resolveApplicationConfigPath(appPath));
|
|
21
|
+
const schemaBasePath = config.externalIntegration?.schemaBasePath || './';
|
|
22
|
+
const datasourceFiles = config.externalIntegration?.dataSources || [];
|
|
23
|
+
let datasourceFile = datasourceFiles.find(f => {
|
|
24
|
+
const base = path.basename(f, path.extname(f));
|
|
25
|
+
return base === datasourceKey || base.includes(datasourceKey);
|
|
26
|
+
});
|
|
27
|
+
if (!datasourceFile) {
|
|
28
|
+
datasourceFile = findDatasourceFileByKey(appPath, schemaBasePath, datasourceFiles, datasourceKey);
|
|
29
|
+
}
|
|
30
|
+
if (!datasourceFile) {
|
|
31
|
+
throw new Error(`Datasource '${datasourceKey}' not found in application config`);
|
|
32
|
+
}
|
|
33
|
+
const datasourcePath = path.isAbsolute(schemaBasePath)
|
|
34
|
+
? path.join(schemaBasePath, datasourceFile)
|
|
35
|
+
: path.join(appPath, schemaBasePath, datasourceFile);
|
|
36
|
+
const datasource = loadConfigFile(datasourcePath);
|
|
37
|
+
if (datasource.key !== datasourceKey) {
|
|
38
|
+
throw new Error(`Datasource key mismatch: file has '${datasource.key}', expected '${datasourceKey}'`);
|
|
39
|
+
}
|
|
40
|
+
return { datasource, datasourcePath };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = { loadDatasourceForApp };
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
const { formatSuccessLine } = require('../utils/cli-test-layout-chalk');
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Run one persisted datasource through the dataplane unified validation flow (POST + optional poll via `lib/api/validation-run.api.js`).
|
|
4
|
+
*
|
|
5
|
+
* **CLI:** `aifabrix datasource test`, `test-integration`, and `test-e2e` use this module with different `runType` values.
|
|
6
|
+
* **User-facing permissions:** see `docs/commands/permissions.md` (Dataplane scopes may differ from the minimum noted on the HTTP helper JSDoc).
|
|
7
|
+
* @author AI Fabrix Team
|
|
8
|
+
* @version 2.0.0
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const chalk = require('chalk');
|
|
12
|
+
const { resolveAppKeyForDatasource } = require('./resolve-app');
|
|
13
|
+
const { setupIntegrationTestAuth } = require('../external-system/test-auth');
|
|
14
|
+
const { getConfig } = require('../core/config');
|
|
15
|
+
const { getSystemKeyFromAppKey, findDatasourceFileByKey } = require('./integration-context');
|
|
16
|
+
const { loadDatasourceForApp } = require('./unified-validation-run-resolve');
|
|
17
|
+
const { buildUnifiedValidationBody } = require('./unified-validation-run-body');
|
|
18
|
+
const { postValidationRunAndOptionalPoll } = require('./unified-validation-run-post');
|
|
19
|
+
const { publishDatasourceViaPipeline } = require('../api/pipeline.api');
|
|
20
|
+
const { requireBearerForDataplanePipeline } = require('../utils/token-manager');
|
|
21
|
+
const { formatApiError } = require('../utils/api-error-handler');
|
|
22
|
+
const logger = require('../utils/logger');
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Resolve datasource JSON path and loaded object (same rules as test-integration).
|
|
26
|
+
* Re-export for tests.
|
|
27
|
+
*/
|
|
28
|
+
function loadDatasourceForAppExport(appKey, datasourceKey) {
|
|
29
|
+
return loadDatasourceForApp(appKey, datasourceKey, findDatasourceFileByKey);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Run unified validation for one persisted datasource.
|
|
34
|
+
* @async
|
|
35
|
+
* @param {string} datasourceKey
|
|
36
|
+
* @param {Object} options
|
|
37
|
+
* @param {boolean} [options.sync] - Publish local datasource JSON via pipeline before POST validation/run
|
|
38
|
+
* @returns {Promise<{ envelope: Object|null, apiError: Object|null, pollTimedOut: boolean, incompleteNoAsync: boolean }>}
|
|
39
|
+
*/
|
|
40
|
+
async function runUnifiedDatasourceValidation(datasourceKey, options) {
|
|
41
|
+
if (!datasourceKey || typeof datasourceKey !== 'string') {
|
|
42
|
+
throw new Error('Datasource key is required');
|
|
43
|
+
}
|
|
44
|
+
const runType = options.runType || 'test';
|
|
45
|
+
const { appKey } = await resolveAppKeyForDatasource(datasourceKey, options.app);
|
|
46
|
+
const systemKey = await getSystemKeyFromAppKey(appKey);
|
|
47
|
+
const { datasource } = loadDatasourceForAppExport(appKey, datasourceKey);
|
|
48
|
+
|
|
49
|
+
const configObj = await getConfig();
|
|
50
|
+
const { authConfig, dataplaneUrl } = await setupIntegrationTestAuth(appKey, options, configObj);
|
|
51
|
+
|
|
52
|
+
if (options.sync === true) {
|
|
53
|
+
requireBearerForDataplanePipeline(authConfig);
|
|
54
|
+
logger.log(chalk.cyan('Syncing local config to dataplane…'));
|
|
55
|
+
const publishResponse = await publishDatasourceViaPipeline(dataplaneUrl, systemKey, authConfig, datasource);
|
|
56
|
+
if (!publishResponse || publishResponse.success === false) {
|
|
57
|
+
const msg =
|
|
58
|
+
(publishResponse && (publishResponse.formattedError || publishResponse.error)) ||
|
|
59
|
+
formatApiError(publishResponse, dataplaneUrl) ||
|
|
60
|
+
'Publish failed';
|
|
61
|
+
throw new Error(`Sync failed: ${msg}`);
|
|
62
|
+
}
|
|
63
|
+
logger.log(formatSuccessLine('Sync complete'));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const useAsync = options.noAsync ? false : options.async !== false;
|
|
67
|
+
const timeoutMs = parseInt(String(options.timeout || '30000'), 10) || 30000;
|
|
68
|
+
|
|
69
|
+
const body = await buildUnifiedValidationBody({
|
|
70
|
+
systemKey,
|
|
71
|
+
datasourceKey,
|
|
72
|
+
runType,
|
|
73
|
+
datasource,
|
|
74
|
+
payloadPath: options.payload,
|
|
75
|
+
useAsync,
|
|
76
|
+
options
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
return postValidationRunAndOptionalPoll({
|
|
80
|
+
dataplaneUrl,
|
|
81
|
+
authConfig,
|
|
82
|
+
body,
|
|
83
|
+
timeoutMs,
|
|
84
|
+
useAsync,
|
|
85
|
+
noAsync: options.noAsync === true || options.async === false,
|
|
86
|
+
verbosePoll: options.verbose === true
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
module.exports = {
|
|
91
|
+
runUnifiedDatasourceValidation,
|
|
92
|
+
loadDatasourceForApp: loadDatasourceForAppExport
|
|
93
|
+
};
|
|
@@ -8,33 +8,172 @@
|
|
|
8
8
|
* @version 2.0.0
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
const path = require('path');
|
|
11
12
|
const fs = require('fs');
|
|
13
|
+
const pathsUtil = require('../utils/paths');
|
|
12
14
|
const { loadExternalDataSourceSchema } = require('../utils/schema-loader');
|
|
13
15
|
const { formatValidationErrors } = require('../utils/error-formatter');
|
|
14
16
|
const { validateFieldReferences } = require('./field-reference-validator');
|
|
15
17
|
const { validateAbac } = require('./abac-validator');
|
|
16
18
|
|
|
19
|
+
const EXCLUDE_JSON_NAMES = new Set(['application.json', 'rbac.json', 'package.json', 'package-lock.json']);
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Resolve identifier to an existing file path, or null.
|
|
23
|
+
* If `fs.statSync` is unavailable (partial Jest mocks), `existsSync` alone implies a file.
|
|
24
|
+
* @param {string} identifier
|
|
25
|
+
* @returns {string|null} Absolute path
|
|
26
|
+
*/
|
|
27
|
+
function tryResolveAsExistingFile(identifier) {
|
|
28
|
+
const candidates = [...new Set([identifier, path.resolve(identifier)])];
|
|
29
|
+
for (const p of candidates) {
|
|
30
|
+
try {
|
|
31
|
+
if (!fs.existsSync(p)) continue;
|
|
32
|
+
try {
|
|
33
|
+
const st = fs.statSync(p);
|
|
34
|
+
if (st && typeof st.isFile === 'function' && st.isFile()) {
|
|
35
|
+
return path.resolve(p);
|
|
36
|
+
}
|
|
37
|
+
} catch {
|
|
38
|
+
return path.resolve(p);
|
|
39
|
+
}
|
|
40
|
+
} catch {
|
|
41
|
+
// ignore
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Pick integration app folder for a datasource `key` (longest matching prefix wins).
|
|
49
|
+
* @param {string} datasourceKey
|
|
50
|
+
* @param {string[]} appNames
|
|
51
|
+
* @returns {string|null}
|
|
52
|
+
*/
|
|
53
|
+
function pickIntegrationAppForDatasourceKey(datasourceKey, appNames) {
|
|
54
|
+
const matches = appNames.filter((app) => datasourceKey === app || datasourceKey.startsWith(`${app}-`));
|
|
55
|
+
if (matches.length === 0) return null;
|
|
56
|
+
matches.sort((a, b) => b.length - a.length);
|
|
57
|
+
return matches[0];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @param {string} fileName
|
|
62
|
+
* @returns {boolean}
|
|
63
|
+
*/
|
|
64
|
+
function shouldScanJsonDatasourceCandidate(fileName) {
|
|
65
|
+
const lower = fileName.toLowerCase();
|
|
66
|
+
if (!lower.endsWith('.json')) return false;
|
|
67
|
+
if (EXCLUDE_JSON_NAMES.has(fileName)) return false;
|
|
68
|
+
if (lower.endsWith('-deploy.json') || lower.endsWith('-system.json')) return false;
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @param {string} fileName
|
|
74
|
+
* @returns {boolean}
|
|
75
|
+
*/
|
|
76
|
+
function isDatasourceNamedJson(fileName) {
|
|
77
|
+
return fileName.toLowerCase().includes('datasource');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @param {string} dir
|
|
82
|
+
* @param {string[]} scanOrder
|
|
83
|
+
* @param {string} datasourceKey
|
|
84
|
+
* @returns {string[]}
|
|
85
|
+
*/
|
|
86
|
+
function collectJsonPathsMatchingDatasourceKey(dir, scanOrder, datasourceKey) {
|
|
87
|
+
const hits = [];
|
|
88
|
+
for (const name of scanOrder) {
|
|
89
|
+
const full = path.join(dir, name);
|
|
90
|
+
let parsed;
|
|
91
|
+
try {
|
|
92
|
+
parsed = JSON.parse(fs.readFileSync(full, 'utf8'));
|
|
93
|
+
} catch {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (parsed && typeof parsed === 'object' && parsed.key === datasourceKey) {
|
|
97
|
+
hits.push(full);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return hits;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Find integration JSON whose parsed `key` equals datasourceKey.
|
|
105
|
+
* @param {string} datasourceKey
|
|
106
|
+
* @returns {string} Absolute file path
|
|
107
|
+
* @throws {Error}
|
|
108
|
+
*/
|
|
109
|
+
function resolvePathFromIntegrationDatasourceKey(datasourceKey) {
|
|
110
|
+
const appNames = pathsUtil.listIntegrationAppNames();
|
|
111
|
+
const appName = pickIntegrationAppForDatasourceKey(datasourceKey, appNames);
|
|
112
|
+
if (!appName) {
|
|
113
|
+
throw new Error(
|
|
114
|
+
`No integration/<app>/ folder matches datasource key "${datasourceKey}". ` +
|
|
115
|
+
'Pass a path to the JSON file, or use a key whose prefix matches an app under integration/ ' +
|
|
116
|
+
'(e.g. app test-e2e-hubspot for key test-e2e-hubspot-users).'
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
const dir = pathsUtil.getIntegrationPath(appName);
|
|
120
|
+
if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) {
|
|
121
|
+
throw new Error(`Integration folder not found: ${dir}`);
|
|
122
|
+
}
|
|
123
|
+
const entries = fs.readdirSync(dir);
|
|
124
|
+
const jsonFiles = entries.filter(shouldScanJsonDatasourceCandidate);
|
|
125
|
+
const prefer = jsonFiles.filter(isDatasourceNamedJson);
|
|
126
|
+
const scanOrder = [...prefer, ...jsonFiles.filter((f) => !prefer.includes(f))];
|
|
127
|
+
const hits = collectJsonPathsMatchingDatasourceKey(dir, scanOrder, datasourceKey);
|
|
128
|
+
if (hits.length === 0) {
|
|
129
|
+
throw new Error(
|
|
130
|
+
`No datasource JSON with key "${datasourceKey}" under integration/${appName}/. ` +
|
|
131
|
+
`Checked: ${scanOrder.length ? scanOrder.join(', ') : '(no JSON candidates)'}`
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
if (hits.length > 1) {
|
|
135
|
+
throw new Error(`Ambiguous: multiple files declare key "${datasourceKey}": ${hits.join(', ')}`);
|
|
136
|
+
}
|
|
137
|
+
return hits[0];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* @param {string} identifier - File path or datasource `key`
|
|
142
|
+
* @returns {string} Absolute path to JSON file
|
|
143
|
+
* @throws {Error}
|
|
144
|
+
*/
|
|
145
|
+
function resolveValidateInputPath(identifier) {
|
|
146
|
+
const trimmed = String(identifier || '').trim();
|
|
147
|
+
if (!trimmed) {
|
|
148
|
+
throw new Error('File path is required and must be a string');
|
|
149
|
+
}
|
|
150
|
+
const asFile = tryResolveAsExistingFile(trimmed);
|
|
151
|
+
if (asFile) return asFile;
|
|
152
|
+
if (trimmed.toLowerCase().endsWith('.json')) {
|
|
153
|
+
throw new Error(`File not found: ${trimmed}`);
|
|
154
|
+
}
|
|
155
|
+
return resolvePathFromIntegrationDatasourceKey(trimmed);
|
|
156
|
+
}
|
|
157
|
+
|
|
17
158
|
/**
|
|
18
159
|
* Validates a datasource file against external-datasource schema
|
|
19
160
|
*
|
|
20
161
|
* @async
|
|
21
162
|
* @function validateDatasourceFile
|
|
22
|
-
* @param {string}
|
|
23
|
-
* @returns {Promise<Object>} Validation result with errors and
|
|
163
|
+
* @param {string} filePathOrKey - Path to the datasource JSON file, or datasource `key` resolved under integration/<app>/
|
|
164
|
+
* @returns {Promise<Object>} Validation result with errors, warnings, and `resolvedPath` (absolute JSON path)
|
|
24
165
|
* @throws {Error} If file cannot be read or parsed
|
|
25
166
|
*
|
|
26
167
|
* @example
|
|
27
168
|
* const result = await validateDatasourceFile('./hubspot-deal.json');
|
|
28
|
-
* // Returns: { valid: true, errors: [], warnings: [] }
|
|
169
|
+
* // Returns: { valid: true, errors: [], warnings: [], resolvedPath: '...' }
|
|
29
170
|
*/
|
|
30
|
-
async function validateDatasourceFile(
|
|
31
|
-
if (!
|
|
171
|
+
async function validateDatasourceFile(filePathOrKey) {
|
|
172
|
+
if (!filePathOrKey || typeof filePathOrKey !== 'string') {
|
|
32
173
|
throw new Error('File path is required and must be a string');
|
|
33
174
|
}
|
|
34
175
|
|
|
35
|
-
|
|
36
|
-
throw new Error(`File not found: ${filePath}`);
|
|
37
|
-
}
|
|
176
|
+
const filePath = resolveValidateInputPath(filePathOrKey.trim());
|
|
38
177
|
|
|
39
178
|
const content = fs.readFileSync(filePath, 'utf8');
|
|
40
179
|
let parsed;
|
|
@@ -45,7 +184,8 @@ async function validateDatasourceFile(filePath) {
|
|
|
45
184
|
return {
|
|
46
185
|
valid: false,
|
|
47
186
|
errors: [`Invalid JSON syntax: ${error.message}`],
|
|
48
|
-
warnings: []
|
|
187
|
+
warnings: [],
|
|
188
|
+
resolvedPath: filePath
|
|
49
189
|
};
|
|
50
190
|
}
|
|
51
191
|
|
|
@@ -56,7 +196,8 @@ async function validateDatasourceFile(filePath) {
|
|
|
56
196
|
return {
|
|
57
197
|
valid: false,
|
|
58
198
|
errors: formatValidationErrors(validate.errors),
|
|
59
|
-
warnings: []
|
|
199
|
+
warnings: [],
|
|
200
|
+
resolvedPath: filePath
|
|
60
201
|
};
|
|
61
202
|
}
|
|
62
203
|
|
|
@@ -67,18 +208,21 @@ async function validateDatasourceFile(filePath) {
|
|
|
67
208
|
return {
|
|
68
209
|
valid: false,
|
|
69
210
|
errors: postSchemaErrors,
|
|
70
|
-
warnings: []
|
|
211
|
+
warnings: [],
|
|
212
|
+
resolvedPath: filePath
|
|
71
213
|
};
|
|
72
214
|
}
|
|
73
215
|
|
|
74
216
|
return {
|
|
75
217
|
valid: true,
|
|
76
218
|
errors: [],
|
|
77
|
-
warnings: []
|
|
219
|
+
warnings: [],
|
|
220
|
+
resolvedPath: filePath
|
|
78
221
|
};
|
|
79
222
|
}
|
|
80
223
|
|
|
81
224
|
module.exports = {
|
|
82
|
-
validateDatasourceFile
|
|
225
|
+
validateDatasourceFile,
|
|
226
|
+
resolveValidateInputPath
|
|
83
227
|
};
|
|
84
228
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const { formatSuccessLine } = require('../utils/cli-test-layout-chalk');
|
|
1
2
|
/**
|
|
2
3
|
* AI Fabrix Builder Deployment Module
|
|
3
4
|
*
|
|
@@ -139,7 +140,7 @@ async function validateDeployment(url, envKey, manifest, authConfig, options = {
|
|
|
139
140
|
const shouldRetry = attempt < maxRetries && error.status && error.status >= 500;
|
|
140
141
|
if (shouldRetry) {
|
|
141
142
|
const delay = Math.min(1000 * Math.pow(2, attempt - 1), 5000);
|
|
142
|
-
logger.log(chalk.yellow(
|
|
143
|
+
logger.log(chalk.yellow(`⚠ Validation attempt ${attempt} failed, retrying in ${delay}ms...`));
|
|
143
144
|
await new Promise(resolve => setTimeout(resolve, delay));
|
|
144
145
|
} else {
|
|
145
146
|
throw error;
|
|
@@ -266,7 +267,7 @@ async function sendDeploymentRequest(url, envKey, validateToken, authConfig, opt
|
|
|
266
267
|
lastError = error;
|
|
267
268
|
if (attempt < maxRetries) {
|
|
268
269
|
const delay = Math.min(1000 * Math.pow(2, attempt - 1), 5000);
|
|
269
|
-
logger.log(chalk.yellow(
|
|
270
|
+
logger.log(chalk.yellow(`⚠ Deployment attempt ${attempt} failed, retrying in ${delay}ms...`));
|
|
270
271
|
await new Promise(resolve => setTimeout(resolve, delay));
|
|
271
272
|
}
|
|
272
273
|
}
|
|
@@ -365,7 +366,7 @@ async function sendDeployment(url, validatedEnvKey, manifest, authConfig, option
|
|
|
365
366
|
throw new Error('Validation failed: validateToken not received');
|
|
366
367
|
}
|
|
367
368
|
|
|
368
|
-
logger.log(
|
|
369
|
+
logger.log(formatSuccessLine('Validation successful'));
|
|
369
370
|
if (validateResult.draftDeploymentId) {
|
|
370
371
|
logger.log(chalk.gray(` Draft Deployment ID: ${validateResult.draftDeploymentId}`));
|
|
371
372
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const { formatSuccessLine, formatSuccessParagraph } = require('../utils/cli-test-layout-chalk');
|
|
1
2
|
/**
|
|
2
3
|
* AI Fabrix Builder Environment Deployment Module
|
|
3
4
|
*
|
|
@@ -276,16 +277,16 @@ async function pollEnvironmentStatus(deploymentId, controllerUrl, envKey, authCo
|
|
|
276
277
|
* @param {Object} result - Deployment result
|
|
277
278
|
*/
|
|
278
279
|
function displayDeploymentResults(result) {
|
|
279
|
-
logger.log(
|
|
280
|
+
logger.log(formatSuccessParagraph('Environment deployed successfully'));
|
|
280
281
|
logger.log(chalk.blue(` Environment: ${result.environment}`));
|
|
281
|
-
logger.log(chalk.blue(` Status: ${result.status === 'ready' ? '
|
|
282
|
+
logger.log(chalk.blue(` Status: ${result.status === 'ready' ? '✔ ready' : result.status}`));
|
|
282
283
|
if (result.url) {
|
|
283
284
|
logger.log(chalk.blue(` URL: ${result.url}`));
|
|
284
285
|
}
|
|
285
286
|
if (result.deploymentId) {
|
|
286
287
|
logger.log(chalk.blue(` Deployment ID: ${result.deploymentId}`));
|
|
287
288
|
}
|
|
288
|
-
logger.log(
|
|
289
|
+
logger.log(formatSuccessParagraph('Environment is ready for application deployments'));
|
|
289
290
|
}
|
|
290
291
|
|
|
291
292
|
/**
|
|
@@ -340,8 +341,8 @@ async function prepareEnvironmentDeployment(envKey, controllerUrl, options) {
|
|
|
340
341
|
// Get authentication (device token)
|
|
341
342
|
logger.log(chalk.blue(`\n📋 Deploying environment '${envKey}' to ${controllerUrl}...`));
|
|
342
343
|
const authConfig = await getEnvironmentAuth(controllerUrl);
|
|
343
|
-
logger.log(
|
|
344
|
-
logger.log(
|
|
344
|
+
logger.log(formatSuccessLine('Environment validated'));
|
|
345
|
+
logger.log(formatSuccessLine('Authentication successful'));
|
|
345
346
|
|
|
346
347
|
return authConfig;
|
|
347
348
|
}
|
|
@@ -412,7 +413,7 @@ async function deployEnvironment(envKey, options = {}) {
|
|
|
412
413
|
// Error handling is done in sendEnvironmentDeployment and pollEnvironmentStatus
|
|
413
414
|
// Re-throw with context
|
|
414
415
|
if (error._logged !== true) {
|
|
415
|
-
logger.error(chalk.red(`\n
|
|
416
|
+
logger.error(chalk.red(`\n✖ Environment deployment failed: ${error.message}`));
|
|
416
417
|
}
|
|
417
418
|
throw error;
|
|
418
419
|
}
|
package/lib/deployment/push.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const { formatSuccessLine } = require('../utils/cli-test-layout-chalk');
|
|
1
2
|
/**
|
|
2
3
|
* AI Fabrix Builder Push Utilities
|
|
3
4
|
*
|
|
@@ -170,7 +171,7 @@ async function authenticateACR(registry) {
|
|
|
170
171
|
// On Windows, use shell option to ensure proper command resolution
|
|
171
172
|
const options = process.platform === 'win32' ? { shell: true } : {};
|
|
172
173
|
await execAsync(`az acr login --name ${registryName}`, { ...options, timeout: AZ_ACR_LOGIN_TIMEOUT_MS });
|
|
173
|
-
logger.log(
|
|
174
|
+
logger.log(formatSuccessLine(`Authenticated with ${registry}`));
|
|
174
175
|
} catch (error) {
|
|
175
176
|
const msg = error.message || String(error);
|
|
176
177
|
if (msg.includes('ETIMEDOUT') || msg.includes('timeout')) {
|
|
@@ -196,7 +197,9 @@ async function authenticateExternalRegistry(registry, username, password) {
|
|
|
196
197
|
// Use cross-platform approach: write password to stdin directly
|
|
197
198
|
// This works on Windows, Linux, and macOS
|
|
198
199
|
const { spawn } = require('child_process');
|
|
199
|
-
const
|
|
200
|
+
const { getDockerExecEnv } = require('../utils/remote-docker-env');
|
|
201
|
+
const dockerEnv = await getDockerExecEnv();
|
|
202
|
+
const dockerLogin = spawn('docker', ['login', registry, '-u', username, '--password-stdin'], { env: dockerEnv });
|
|
200
203
|
|
|
201
204
|
return new Promise((resolve, reject) => {
|
|
202
205
|
let errorOutput = '';
|
|
@@ -214,7 +217,7 @@ async function authenticateExternalRegistry(registry, username, password) {
|
|
|
214
217
|
|
|
215
218
|
dockerLogin.on('close', (code) => {
|
|
216
219
|
if (code === 0) {
|
|
217
|
-
logger.log(
|
|
220
|
+
logger.log(formatSuccessLine(`Authenticated with ${registry}`));
|
|
218
221
|
resolve();
|
|
219
222
|
} else {
|
|
220
223
|
reject(new Error(`Docker login failed: ${errorOutput || `Exit code ${code}`}`));
|
|
@@ -238,8 +241,10 @@ async function authenticateExternalRegistry(registry, username, password) {
|
|
|
238
241
|
*/
|
|
239
242
|
async function checkLocalImageExists(imageName, tag = 'latest') {
|
|
240
243
|
try {
|
|
244
|
+
const { getDockerExecEnv } = require('../utils/remote-docker-env');
|
|
245
|
+
const env = await getDockerExecEnv();
|
|
241
246
|
// Use Docker's native filtering for cross-platform compatibility (Windows-safe)
|
|
242
|
-
const { stdout } = await execAsync(`docker images --format "{{.Repository}}:{{.Tag}}" --filter "reference=${imageName}:${tag}"
|
|
247
|
+
const { stdout } = await execAsync(`docker images --format "{{.Repository}}:{{.Tag}}" --filter "reference=${imageName}:${tag}"`, { env });
|
|
243
248
|
const lines = stdout.trim().split('\n').filter(line => line.trim() !== '');
|
|
244
249
|
return lines.some(line => line.trim() === `${imageName}:${tag}`);
|
|
245
250
|
} catch (error) {
|
|
@@ -255,9 +260,11 @@ async function checkLocalImageExists(imageName, tag = 'latest') {
|
|
|
255
260
|
*/
|
|
256
261
|
async function tagImage(sourceImage, targetImage) {
|
|
257
262
|
try {
|
|
263
|
+
const { getDockerExecEnv } = require('../utils/remote-docker-env');
|
|
264
|
+
const env = await getDockerExecEnv();
|
|
258
265
|
logger.log(chalk.blue(`Tagging ${sourceImage} as ${targetImage}...`));
|
|
259
|
-
await execAsync(`docker tag ${sourceImage} ${targetImage}
|
|
260
|
-
logger.log(
|
|
266
|
+
await execAsync(`docker tag ${sourceImage} ${targetImage}`, { env });
|
|
267
|
+
logger.log(formatSuccessLine(`Tagged: ${targetImage}`));
|
|
261
268
|
} catch (error) {
|
|
262
269
|
throw new Error(`Failed to tag image: ${error.message}`);
|
|
263
270
|
}
|
|
@@ -271,9 +278,11 @@ async function tagImage(sourceImage, targetImage) {
|
|
|
271
278
|
*/
|
|
272
279
|
async function pushImage(imageWithTag, registry = null) {
|
|
273
280
|
try {
|
|
281
|
+
const { getDockerExecEnv } = require('../utils/remote-docker-env');
|
|
282
|
+
const env = await getDockerExecEnv();
|
|
274
283
|
logger.log(chalk.blue(`Pushing ${imageWithTag}...`));
|
|
275
|
-
await execAsync(`docker push ${imageWithTag}
|
|
276
|
-
logger.log(
|
|
284
|
+
await execAsync(`docker push ${imageWithTag}`, { env });
|
|
285
|
+
logger.log(formatSuccessLine(`Pushed: ${imageWithTag}`));
|
|
277
286
|
} catch (error) {
|
|
278
287
|
const errorMessage = error.message || error.stderr || String(error);
|
|
279
288
|
const isAuthError = errorMessage.includes('authentication required') ||
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
'use strict';
|
|
12
|
+
const { formatSuccessLine } = require('../utils/cli-test-layout-chalk');
|
|
12
13
|
|
|
13
14
|
const chalk = require('chalk');
|
|
14
15
|
const inquirer = require('inquirer');
|
|
@@ -97,7 +98,7 @@ async function confirmDeletion(systemKey, datasources, options) {
|
|
|
97
98
|
return true;
|
|
98
99
|
}
|
|
99
100
|
|
|
100
|
-
logger.log(chalk.yellow(`\n
|
|
101
|
+
logger.log(chalk.yellow(`\n⚠ Warning: Deleting external system '${systemKey}' will also delete all associated datasources:`));
|
|
101
102
|
if (datasources.length > 0) {
|
|
102
103
|
datasources.forEach(ds => logger.log(chalk.yellow(` - ${ds}`)));
|
|
103
104
|
} else {
|
|
@@ -141,8 +142,8 @@ async function deleteExternalSystemCommand(systemKey, options = {}) {
|
|
|
141
142
|
throw new Error(response?.error || response?.formattedError || `Failed to delete external system '${systemKey}'`);
|
|
142
143
|
}
|
|
143
144
|
|
|
144
|
-
logger.log(
|
|
145
|
-
logger.log(
|
|
145
|
+
logger.log(formatSuccessLine(`External system '${systemKey}' deleted successfully`));
|
|
146
|
+
logger.log(formatSuccessLine('All associated datasources have been removed'));
|
|
146
147
|
}
|
|
147
148
|
|
|
148
149
|
module.exports = {
|