@aifabrix/builder 2.43.0 → 2.44.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/.cursor/rules/anchor-docs.mdc +15 -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 +288 -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 +0 -1
- package/lib/api/pipeline.api.js +67 -20
- 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 +99 -0
- package/lib/api/validation-runner.js +99 -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 +1 -1
- package/lib/app/show.js +1 -1
- package/lib/build/index.js +13 -10
- package/lib/cli/index.js +2 -0
- package/lib/cli/setup-app.help.js +67 -0
- package/lib/cli/setup-app.js +57 -121
- package/lib/cli/setup-app.test-commands.js +179 -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 +62 -22
- package/lib/cli/setup-infra.js +126 -47
- package/lib/cli/setup-parameters.js +32 -0
- package/lib/cli/setup-secrets.js +106 -8
- package/lib/cli/setup-service-user.js +1 -1
- package/lib/cli/setup-utility.js +36 -20
- 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 +22 -10
- 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 +495 -0
- package/lib/commands/datasource-unified-test-cli.options.js +149 -0
- package/lib/commands/datasource-validation-cli.js +129 -0
- package/lib/commands/datasource.js +105 -98
- 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 +138 -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 +84 -53
- package/lib/datasource/resolve-app.js +4 -4
- package/lib/datasource/test-e2e.js +95 -146
- package/lib/datasource/test-integration.js +114 -122
- package/lib/datasource/unified-validation-run-body.js +65 -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 +92 -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 +131 -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 +60 -6
- package/lib/infrastructure/helpers.js +201 -29
- package/lib/infrastructure/index.js +28 -17
- package/lib/infrastructure/services.js +21 -15
- 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 +181 -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 +213 -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 +49 -14
- 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/controller-deployment-outcome.js +68 -0
- package/lib/utils/credential-display.js +2 -2
- 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-debug-display.js +137 -0
- package/lib/utils/datasource-test-run-debug-slice.js +93 -0
- package/lib/utils/datasource-test-run-display.js +442 -0
- package/lib/utils/datasource-test-run-exit.js +58 -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 +234 -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-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 +134 -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 +89 -0
- package/lib/utils/validation-run-post-retry.js +73 -0
- package/lib/utils/validation-run-request.js +98 -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.js +4 -13
- 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 +7 -3
- package/scripts/check-datasource-test-run-schema-sync.js +34 -0
- package/scripts/diagnose-cli.js +150 -0
- package/scripts/install-local.js +304 -55
- package/templates/README.md +15 -2
- package/templates/applications/dataplane/application.yaml +52 -2
- package/templates/applications/dataplane/env.template +75 -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 +20 -4
- 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
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* @version 2.0.0
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
const
|
|
11
|
+
const { formatBlockingError, formatSuccessLine } = require('../utils/cli-test-layout-chalk');
|
|
12
12
|
const {
|
|
13
13
|
setControllerUrl,
|
|
14
14
|
setCurrentEnvironment,
|
|
@@ -42,14 +42,14 @@ async function handleSetController(url) {
|
|
|
42
42
|
if (!loggedInControllerUrl) {
|
|
43
43
|
// No stored credentials: allow setting controller so "aifabrix login" opens the right place
|
|
44
44
|
await setControllerUrl(url);
|
|
45
|
-
logger.log(
|
|
45
|
+
logger.log(formatSuccessLine(`Controller URL set to: ${url}`));
|
|
46
46
|
return;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
const normalizedLoggedIn = loggedInControllerUrl.trim().replace(/\/+$/, '');
|
|
50
50
|
if (normalizedLoggedIn === normalizedUrl) {
|
|
51
51
|
await setControllerUrl(url);
|
|
52
|
-
logger.log(
|
|
52
|
+
logger.log(formatSuccessLine(`Controller URL set to: ${url}`));
|
|
53
53
|
return;
|
|
54
54
|
}
|
|
55
55
|
|
|
@@ -58,7 +58,7 @@ async function handleSetController(url) {
|
|
|
58
58
|
'To use a different controller either run "aifabrix login" with that controller, or run "aifabrix logout" first to clear credentials, then set the new controller with "aifabrix auth --set-controller <url>".'
|
|
59
59
|
);
|
|
60
60
|
} catch (error) {
|
|
61
|
-
logger.error(
|
|
61
|
+
logger.error(formatBlockingError(`Failed to set controller URL: ${error.message}`));
|
|
62
62
|
throw error;
|
|
63
63
|
}
|
|
64
64
|
}
|
|
@@ -95,9 +95,9 @@ async function handleSetEnvironment(environment) {
|
|
|
95
95
|
// Save environment
|
|
96
96
|
await setCurrentEnvironment(environment);
|
|
97
97
|
|
|
98
|
-
logger.log(
|
|
98
|
+
logger.log(formatSuccessLine(`Environment set to: ${environment}`));
|
|
99
99
|
} catch (error) {
|
|
100
|
-
logger.error(
|
|
100
|
+
logger.error(formatBlockingError(`Failed to set environment: ${error.message}`));
|
|
101
101
|
throw error;
|
|
102
102
|
}
|
|
103
103
|
}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
const chalk = require('chalk');
|
|
12
|
+
const { failureGlyph, successGlyph } = require('../utils/cli-test-layout-chalk');
|
|
12
13
|
const logger = require('../utils/logger');
|
|
13
14
|
const config = require('../core/config');
|
|
14
15
|
const { getConfig } = config;
|
|
@@ -194,7 +195,7 @@ function displayUserInfo(user) {
|
|
|
194
195
|
* @param {Object} tokenInfo - Token information
|
|
195
196
|
*/
|
|
196
197
|
function displayTokenInfo(tokenInfo) {
|
|
197
|
-
const statusIcon = tokenInfo.authenticated ?
|
|
198
|
+
const statusIcon = tokenInfo.authenticated ? successGlyph() : failureGlyph();
|
|
198
199
|
const statusText = tokenInfo.authenticated ? 'Authenticated' : 'Not authenticated';
|
|
199
200
|
|
|
200
201
|
logger.log(` Status: ${statusIcon} ${statusText}`);
|
|
@@ -244,7 +245,7 @@ function displayDataplaneSection(dataplaneUrl, dataplaneConnected) {
|
|
|
244
245
|
logger.log('');
|
|
245
246
|
if (dataplaneUrl) {
|
|
246
247
|
logger.log(`Dataplane: ${chalk.cyan(dataplaneUrl)}`);
|
|
247
|
-
const statusIcon = dataplaneConnected ?
|
|
248
|
+
const statusIcon = dataplaneConnected ? successGlyph() : failureGlyph();
|
|
248
249
|
const statusText = dataplaneConnected ? 'Connected' : 'Not reachable';
|
|
249
250
|
displayOpenApiDocs(null, dataplaneUrl);
|
|
250
251
|
logger.log('');
|
|
@@ -297,7 +298,7 @@ function displayStatus(controllerUrl, environment, tokenInfo, dataplaneInfo) {
|
|
|
297
298
|
logger.log(` Environment: ${chalk.cyan(environment || 'Not specified')}\n`);
|
|
298
299
|
|
|
299
300
|
if (!tokenInfo) {
|
|
300
|
-
logger.log(` Status: ${chalk.red('
|
|
301
|
+
logger.log(` Status: ${failureGlyph()} ${chalk.red('Not authenticated')}`);
|
|
301
302
|
logger.log(` Token Type: ${chalk.gray('None')}\n`);
|
|
302
303
|
logger.log(chalk.yellow('💡 Run "aifabrix login" to authenticate\n'));
|
|
303
304
|
return;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
const { formatSuccessLine } = require('../utils/cli-test-layout-chalk');
|
|
1
2
|
/**
|
|
2
3
|
* Credential env command – prompts for KV_* values and writes .env.
|
|
3
|
-
* Used by `aifabrix credential env <
|
|
4
|
+
* Used by `aifabrix credential env <systemKey>`.
|
|
4
5
|
*
|
|
5
6
|
* @fileoverview Credential env command – interactive credential capture to .env
|
|
6
7
|
* @author AI Fabrix Team
|
|
@@ -120,7 +121,7 @@ function buildEnvContent(templateContent, promptValues) {
|
|
|
120
121
|
/**
|
|
121
122
|
* Runs credential env command: prompt for KV_* values and write .env.
|
|
122
123
|
* @async
|
|
123
|
-
* @param {string} systemKey - External system key (integration/<
|
|
124
|
+
* @param {string} systemKey - External system key (integration/<systemKey>/)
|
|
124
125
|
* @returns {Promise<string>} Path to written .env file
|
|
125
126
|
* @throws {Error} If env.template missing or write fails
|
|
126
127
|
*/
|
|
@@ -155,7 +156,7 @@ async function runCredentialEnv(systemKey) {
|
|
|
155
156
|
const dir = path.dirname(envPath);
|
|
156
157
|
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
157
158
|
fs.writeFileSync(envPath, content, { mode: 0o600 });
|
|
158
|
-
logger.log(
|
|
159
|
+
logger.log(formatSuccessLine(`Wrote ${envPath}`));
|
|
159
160
|
return envPath;
|
|
160
161
|
}
|
|
161
162
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const { formatBlockingError } = require('../utils/cli-test-layout-chalk');
|
|
1
2
|
/**
|
|
2
3
|
* Credential list command – list credentials from Dataplane
|
|
3
4
|
* GET /api/v1/credential. Used by `aifabrix credential list`.
|
|
@@ -78,12 +79,12 @@ function displayCredentialList(list, baseUrl) {
|
|
|
78
79
|
async function ensureControllerAndAuth(options = {}) {
|
|
79
80
|
const controllerUrl = options.controller || (await resolveControllerUrl());
|
|
80
81
|
if (!controllerUrl) {
|
|
81
|
-
logger.error(
|
|
82
|
+
logger.error(formatBlockingError('Controller URL is required. Run "aifabrix login" first.'));
|
|
82
83
|
process.exit(1);
|
|
83
84
|
}
|
|
84
85
|
const authResult = await getCredentialListAuth(controllerUrl);
|
|
85
86
|
if (!authResult || !authResult.token) {
|
|
86
|
-
logger.error(
|
|
87
|
+
logger.error(formatBlockingError(`No authentication token for controller: ${controllerUrl}`));
|
|
87
88
|
logger.error(chalk.gray('Run: aifabrix login'));
|
|
88
89
|
process.exit(1);
|
|
89
90
|
}
|
|
@@ -129,7 +130,7 @@ async function resolveDataplaneUrlOrExit(controllerUrl, authConfig) {
|
|
|
129
130
|
try {
|
|
130
131
|
return await resolveCredentialListDataplaneUrl(controllerUrl, authConfig);
|
|
131
132
|
} catch (err) {
|
|
132
|
-
logger.error(
|
|
133
|
+
logger.error(formatBlockingError(`Could not resolve Dataplane URL: ${err.message}`));
|
|
133
134
|
process.exit(1);
|
|
134
135
|
}
|
|
135
136
|
}
|
|
@@ -152,7 +153,7 @@ async function runCredentialList(options = {}) {
|
|
|
152
153
|
try {
|
|
153
154
|
await fetchAndDisplayCredentials(dataplaneUrl, authConfig, listOptions);
|
|
154
155
|
} catch (error) {
|
|
155
|
-
logger.error(
|
|
156
|
+
logger.error(formatBlockingError(`Failed to list credentials: ${error.message}`));
|
|
156
157
|
process.exit(1);
|
|
157
158
|
}
|
|
158
159
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
const { formatSuccessLine } = require('../utils/cli-test-layout-chalk');
|
|
1
2
|
/**
|
|
2
3
|
* Credential push command – pushes KV_* from .env to dataplane.
|
|
3
|
-
* Used by `aifabrix credential push <
|
|
4
|
+
* Used by `aifabrix credential push <systemKey>`.
|
|
4
5
|
*
|
|
5
6
|
* @fileoverview Credential push command – push credential secrets to dataplane
|
|
6
7
|
* @author AI Fabrix Team
|
|
@@ -55,7 +56,7 @@ async function buildPayload(systemKey) {
|
|
|
55
56
|
function logPushResult(pushResult) {
|
|
56
57
|
if (pushResult.pushed > 0) {
|
|
57
58
|
const keyList = pushResult.keys?.length ? ` (${pushResult.keys.join(', ')})` : '';
|
|
58
|
-
logger.log(
|
|
59
|
+
logger.log(formatSuccessLine(`Pushed ${pushResult.pushed} credential secret(s) to dataplane${keyList}.`));
|
|
59
60
|
} else if (pushResult.skipped) {
|
|
60
61
|
logger.log(chalk.yellow('No credential secrets to push (empty .env or no KV_* vars with values).'));
|
|
61
62
|
} else {
|
|
@@ -75,7 +76,7 @@ async function runCredentialPush(systemKey) {
|
|
|
75
76
|
const authConfig = await getDeploymentAuth(controllerUrl, environment, systemKey);
|
|
76
77
|
|
|
77
78
|
if (!authConfig.token && !authConfig.clientId) {
|
|
78
|
-
throw new Error('Authentication required. Run "aifabrix login" or "aifabrix app register <
|
|
79
|
+
throw new Error('Authentication required. Run "aifabrix login" or "aifabrix app register <systemKey>" first.');
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
requireBearerForDataplanePipeline(authConfig);
|
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
const { formatBlockingError } = require('../utils/cli-test-layout-chalk');
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview CLI wiring for `datasource test`, `test-integration`, and `test-e2e` (unified validation + watch).
|
|
4
|
+
* @author AI Fabrix Team
|
|
5
|
+
* @version 2.0.0
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const chalk = require('chalk');
|
|
9
|
+
const logger = require('../utils/logger');
|
|
10
|
+
const { runDatasourceTestIntegration } = require('../datasource/test-integration');
|
|
11
|
+
const { runDatasourceTestE2E } = require('../datasource/test-e2e');
|
|
12
|
+
const { runUnifiedDatasourceValidation } = require('../datasource/unified-validation-run');
|
|
13
|
+
const { displayIntegrationTestResults, displayE2EResults } = require('../utils/external-system-display');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const { getIntegrationPath } = require('../utils/paths');
|
|
16
|
+
const { writeTestLog } = require('../utils/test-log-writer');
|
|
17
|
+
const { includeDebugForRequest } = require('../utils/validation-run-request');
|
|
18
|
+
const {
|
|
19
|
+
exitFromUnifiedValidationResult,
|
|
20
|
+
finalizeUnifiedValidationResult,
|
|
21
|
+
unifiedCliResultFromIntegrationReturn,
|
|
22
|
+
exitAfterIntegrationDisplay,
|
|
23
|
+
finalizeAfterIntegrationDisplay,
|
|
24
|
+
emitCapabilityScopeDiagnostics
|
|
25
|
+
} = require('./datasource-validation-cli');
|
|
26
|
+
const { resolveAppKeyForDatasource } = require('../datasource/resolve-app');
|
|
27
|
+
const { runDatasourceValidationWatchLoop } = require('../utils/datasource-validation-watch');
|
|
28
|
+
const { computeExitCodeFromDatasourceTestRun } = require('../utils/datasource-test-run-exit');
|
|
29
|
+
const { analyzeCapabilityScope } = require('../utils/datasource-test-run-capability-scope');
|
|
30
|
+
const {
|
|
31
|
+
resolveDebugDisplayMode,
|
|
32
|
+
formatDatasourceTestRunDebugBlock
|
|
33
|
+
} = require('../utils/datasource-test-run-debug-display');
|
|
34
|
+
const { formatCapabilityFocusSection } = require('../utils/datasource-test-run-display');
|
|
35
|
+
const {
|
|
36
|
+
datasourceTestHelpAfter,
|
|
37
|
+
datasourceTestIntegrationHelpAfter,
|
|
38
|
+
datasourceTestE2eHelpAfter,
|
|
39
|
+
attachDatasourceWatchOptions,
|
|
40
|
+
attachDatasourceTestCommonOptions
|
|
41
|
+
} = require('./datasource-unified-test-cli.options');
|
|
42
|
+
|
|
43
|
+
function integrationBaseDirForLogs(appKey) {
|
|
44
|
+
return path.dirname(getIntegrationPath(appKey));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function writeDatasourceTestDebugLogIfRequested(appKey, datasourceKey, result, options) {
|
|
48
|
+
if (!options || !options.debug) return;
|
|
49
|
+
const requestMeta = {
|
|
50
|
+
datasourceKey,
|
|
51
|
+
runType: 'test',
|
|
52
|
+
includeDebug: includeDebugForRequest(options.debug)
|
|
53
|
+
};
|
|
54
|
+
const envelope = result && typeof result === 'object' ? result.envelope : null;
|
|
55
|
+
const apiError = result && typeof result === 'object' ? result.apiError : null;
|
|
56
|
+
const errorMessage = apiError
|
|
57
|
+
? apiError.formattedError || apiError.error || 'Request failed'
|
|
58
|
+
: null;
|
|
59
|
+
const data = errorMessage
|
|
60
|
+
? { request: requestMeta, error: errorMessage }
|
|
61
|
+
: { request: requestMeta, response: envelope };
|
|
62
|
+
const logPath = await writeTestLog(
|
|
63
|
+
appKey,
|
|
64
|
+
data,
|
|
65
|
+
'test',
|
|
66
|
+
integrationBaseDirForLogs(appKey)
|
|
67
|
+
);
|
|
68
|
+
logger.log(chalk.gray(` Debug log: ${logPath}`));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function logDatasourceTestRunDebugAppendix(envelope, debugOpt) {
|
|
72
|
+
const mode = resolveDebugDisplayMode(debugOpt);
|
|
73
|
+
if (!mode || !envelope) return;
|
|
74
|
+
const block = formatDatasourceTestRunDebugBlock(envelope, mode, process.stdout.isTTY);
|
|
75
|
+
if (block) logger.log(block);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function logE2eCapabilityFocusFromEnvelope(env, capabilityOpt) {
|
|
79
|
+
if (!env) return;
|
|
80
|
+
const capKey =
|
|
81
|
+
capabilityOpt !== undefined && capabilityOpt !== null
|
|
82
|
+
? String(capabilityOpt).trim()
|
|
83
|
+
: '';
|
|
84
|
+
if (!capKey) return;
|
|
85
|
+
const sec = formatCapabilityFocusSection(env, capKey);
|
|
86
|
+
if (sec) logger.log(sec);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Exit code from envelope only (no stderr diagnostics; use when TTY output already ran emit via logEnvelope).
|
|
91
|
+
* @param {Object|null|undefined} env
|
|
92
|
+
* @param {Object} options
|
|
93
|
+
* @returns {number|null} null if no envelope
|
|
94
|
+
*/
|
|
95
|
+
function exitCodeFromDatasourceTestRunEnvelope(env, options) {
|
|
96
|
+
if (!env || typeof env !== 'object') return null;
|
|
97
|
+
let code = computeExitCodeFromDatasourceTestRun(env, {
|
|
98
|
+
warningsAsErrors: false,
|
|
99
|
+
requireCert: false
|
|
100
|
+
});
|
|
101
|
+
const scope = analyzeCapabilityScope(env, options.capability);
|
|
102
|
+
if (options.strictCapabilityScope === true && scope.violated) {
|
|
103
|
+
code = Math.max(code, 1);
|
|
104
|
+
}
|
|
105
|
+
return code;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Legacy E2E display + exit code (no process.exit; watch mode).
|
|
110
|
+
* @param {Object} data
|
|
111
|
+
* @param {Object} options
|
|
112
|
+
* @returns {number}
|
|
113
|
+
*/
|
|
114
|
+
function finalizeDatasourceTestE2ELegacyPath(data, options) {
|
|
115
|
+
displayE2EResults(data, options.verbose);
|
|
116
|
+
logDatasourceTestRunDebugAppendix(data.datasourceTestRun, options.debug);
|
|
117
|
+
logE2eCapabilityFocusFromEnvelope(data.datasourceTestRun, options.capability);
|
|
118
|
+
const env = data.datasourceTestRun;
|
|
119
|
+
if (env) {
|
|
120
|
+
emitCapabilityScopeDiagnostics(env, { requestedCapabilityKey: options.capability });
|
|
121
|
+
const code = exitCodeFromDatasourceTestRunEnvelope(env, options);
|
|
122
|
+
return code === null ? 1 : code;
|
|
123
|
+
}
|
|
124
|
+
const steps = data.steps || data.completedActions || [];
|
|
125
|
+
const failed = data.success === false || steps.some(s => s.success === false || s.error);
|
|
126
|
+
return failed ? 1 : 0;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Human TTY for single-datasource E2E when DatasourceTestRun envelope is present.
|
|
131
|
+
* @param {string} datasourceKey
|
|
132
|
+
* @param {Object} env
|
|
133
|
+
* @param {Object} options
|
|
134
|
+
*/
|
|
135
|
+
function displayDatasourceTestE2EEnvelopeResults(datasourceKey, env, options) {
|
|
136
|
+
const success = env.status !== 'fail';
|
|
137
|
+
displayIntegrationTestResults(
|
|
138
|
+
{
|
|
139
|
+
systemKey: env.systemKey || 'unknown',
|
|
140
|
+
success,
|
|
141
|
+
datasourceResults: [{ key: datasourceKey, success, datasourceTestRun: env }]
|
|
142
|
+
},
|
|
143
|
+
options.verbose,
|
|
144
|
+
{
|
|
145
|
+
debug: options.debug,
|
|
146
|
+
runType: 'e2e',
|
|
147
|
+
requestedCapabilityKey: options.capability
|
|
148
|
+
}
|
|
149
|
+
);
|
|
150
|
+
logE2eCapabilityFocusFromEnvelope(env, options.capability);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function buildDatasourceTestRunOpts(options) {
|
|
154
|
+
return {
|
|
155
|
+
app: options.app,
|
|
156
|
+
environment: options.env,
|
|
157
|
+
runType: 'test',
|
|
158
|
+
payload: options.payload,
|
|
159
|
+
debug: options.debug,
|
|
160
|
+
verbose: options.verbose,
|
|
161
|
+
timeout: options.timeout,
|
|
162
|
+
async: options.async !== false,
|
|
163
|
+
noAsync: options.async === false,
|
|
164
|
+
sync: options.sync === true
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function buildDatasourceTestDisplayOpts(options) {
|
|
169
|
+
return {
|
|
170
|
+
json: options.json,
|
|
171
|
+
summary: options.summary,
|
|
172
|
+
warningsAsErrors: options.warningsAsErrors,
|
|
173
|
+
requireCert: options.requireCert,
|
|
174
|
+
debug: options.debug
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async function runDatasourceUnifiedTestOnceForWatch(datasourceKey, runOpts, displayOpts) {
|
|
179
|
+
try {
|
|
180
|
+
const result = await runUnifiedDatasourceValidation(datasourceKey, runOpts);
|
|
181
|
+
return {
|
|
182
|
+
exitCode: finalizeUnifiedValidationResult(result, displayOpts),
|
|
183
|
+
envelope: result.envelope
|
|
184
|
+
};
|
|
185
|
+
} catch (err) {
|
|
186
|
+
logger.error(formatBlockingError('Datasource test failed:'), err.message);
|
|
187
|
+
return { exitCode: 4, envelope: null };
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async function datasourceTestCommandAction(datasourceKey, options) {
|
|
192
|
+
const runOpts = buildDatasourceTestRunOpts(options);
|
|
193
|
+
const displayOpts = buildDatasourceTestDisplayOpts(options);
|
|
194
|
+
try {
|
|
195
|
+
if (options.watch) {
|
|
196
|
+
const { appKey } = await resolveAppKeyForDatasource(datasourceKey, options.app);
|
|
197
|
+
await runDatasourceValidationWatchLoop({
|
|
198
|
+
appKey,
|
|
199
|
+
extraPaths: options.watchPath || [],
|
|
200
|
+
includeApplicationYaml: options.watchApplicationYaml === true,
|
|
201
|
+
watchCi: options.watchCi === true,
|
|
202
|
+
watchFullDiff: options.watchFullDiff === true,
|
|
203
|
+
runOnce: async() => {
|
|
204
|
+
const result = await runUnifiedDatasourceValidation(datasourceKey, runOpts);
|
|
205
|
+
await writeDatasourceTestDebugLogIfRequested(appKey, datasourceKey, result, options);
|
|
206
|
+
return {
|
|
207
|
+
exitCode: finalizeUnifiedValidationResult(result, displayOpts),
|
|
208
|
+
envelope: result.envelope
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const result = await runUnifiedDatasourceValidation(datasourceKey, runOpts);
|
|
215
|
+
if (options.debug) {
|
|
216
|
+
try {
|
|
217
|
+
const { appKey } = await resolveAppKeyForDatasource(datasourceKey, options.app);
|
|
218
|
+
await writeDatasourceTestDebugLogIfRequested(appKey, datasourceKey, result, options);
|
|
219
|
+
} catch (e) {
|
|
220
|
+
logger.warn(chalk.yellow(`⚠ Could not write debug log: ${e.message}`));
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
exitFromUnifiedValidationResult(result, displayOpts);
|
|
224
|
+
} catch (error) {
|
|
225
|
+
logger.error(formatBlockingError('Datasource test failed:'), error.message);
|
|
226
|
+
process.exit(4);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function chainDatasourceTestCommand(datasource) {
|
|
231
|
+
const cmd = datasource
|
|
232
|
+
.command('test <datasourceKey>')
|
|
233
|
+
.description('Structural/policy validation for one datasource (unified dataplane API, runType=test)');
|
|
234
|
+
attachDatasourceTestCommonOptions(cmd, {
|
|
235
|
+
includeNoAsync: true,
|
|
236
|
+
verboseHelp: 'Set explain=true on validation request',
|
|
237
|
+
timeoutHelp: 'Aggregate timeout for POST + polls'
|
|
238
|
+
});
|
|
239
|
+
return cmd.addHelpText('after', datasourceTestHelpAfter());
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function setupDatasourceTestCommand(datasource) {
|
|
243
|
+
// watch flags are already attached by attachDatasourceTestCommonOptions()
|
|
244
|
+
chainDatasourceTestCommand(datasource).action(datasourceTestCommandAction);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function buildIntegrationTestOpts(options) {
|
|
248
|
+
return {
|
|
249
|
+
app: options.app,
|
|
250
|
+
payload: options.payload,
|
|
251
|
+
environment: options.env,
|
|
252
|
+
debug: options.debug,
|
|
253
|
+
verbose: options.verbose,
|
|
254
|
+
timeout: options.timeout,
|
|
255
|
+
sync: options.sync === true
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function buildIntegrationUnifiedDisplayOpts(options) {
|
|
260
|
+
return {
|
|
261
|
+
json: options.json,
|
|
262
|
+
summary: options.summary,
|
|
263
|
+
warningsAsErrors: options.warningsAsErrors,
|
|
264
|
+
requireCert: options.requireCert,
|
|
265
|
+
debug: options.debug
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
async function runIntegrationOnceForWatch(datasourceKey, integOpts, options, unifiedDisplayOpts) {
|
|
270
|
+
try {
|
|
271
|
+
const result = await runDatasourceTestIntegration(datasourceKey, integOpts);
|
|
272
|
+
const unifiedModes =
|
|
273
|
+
options.json || options.summary || options.warningsAsErrors || options.requireCert;
|
|
274
|
+
if (unifiedModes) {
|
|
275
|
+
const uni = unifiedCliResultFromIntegrationReturn(result);
|
|
276
|
+
const exitCode = finalizeUnifiedValidationResult(uni, unifiedDisplayOpts);
|
|
277
|
+
return { exitCode, envelope: uni.envelope };
|
|
278
|
+
}
|
|
279
|
+
displayIntegrationTestResults(
|
|
280
|
+
{
|
|
281
|
+
systemKey: result.systemKey || 'unknown',
|
|
282
|
+
datasourceResults: [result],
|
|
283
|
+
success: result.success
|
|
284
|
+
},
|
|
285
|
+
options.verbose,
|
|
286
|
+
{ debug: options.debug, runType: 'integration' }
|
|
287
|
+
);
|
|
288
|
+
const exitCode = finalizeAfterIntegrationDisplay(result, {});
|
|
289
|
+
return { exitCode, envelope: result.datasourceTestRun || null };
|
|
290
|
+
} catch (err) {
|
|
291
|
+
logger.error(formatBlockingError('Integration test failed:'), err.message);
|
|
292
|
+
return { exitCode: 4, envelope: null };
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
async function integrationTestCommandAction(datasourceKey, options) {
|
|
297
|
+
const integOpts = buildIntegrationTestOpts(options);
|
|
298
|
+
const unifiedDisplayOpts = buildIntegrationUnifiedDisplayOpts(options);
|
|
299
|
+
try {
|
|
300
|
+
if (options.watch) {
|
|
301
|
+
const { appKey } = await resolveAppKeyForDatasource(datasourceKey, options.app);
|
|
302
|
+
await runDatasourceValidationWatchLoop({
|
|
303
|
+
appKey,
|
|
304
|
+
extraPaths: options.watchPath || [],
|
|
305
|
+
includeApplicationYaml: options.watchApplicationYaml === true,
|
|
306
|
+
watchCi: options.watchCi === true,
|
|
307
|
+
watchFullDiff: options.watchFullDiff === true,
|
|
308
|
+
runOnce: () => runIntegrationOnceForWatch(datasourceKey, integOpts, options, unifiedDisplayOpts)
|
|
309
|
+
});
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
const result = await runDatasourceTestIntegration(datasourceKey, integOpts);
|
|
313
|
+
const unifiedModes =
|
|
314
|
+
options.json || options.summary || options.warningsAsErrors || options.requireCert;
|
|
315
|
+
if (unifiedModes) {
|
|
316
|
+
exitFromUnifiedValidationResult(unifiedCliResultFromIntegrationReturn(result), unifiedDisplayOpts);
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
displayIntegrationTestResults(
|
|
320
|
+
{
|
|
321
|
+
systemKey: result.systemKey || 'unknown',
|
|
322
|
+
datasourceResults: [result],
|
|
323
|
+
success: result.success
|
|
324
|
+
},
|
|
325
|
+
options.verbose,
|
|
326
|
+
{ debug: options.debug, runType: 'integration' }
|
|
327
|
+
);
|
|
328
|
+
exitAfterIntegrationDisplay(result, {});
|
|
329
|
+
} catch (error) {
|
|
330
|
+
logger.error(formatBlockingError('Integration test failed:'), error.message);
|
|
331
|
+
process.exit(4);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function chainDatasourceTestIntegrationCommand(datasource) {
|
|
336
|
+
const cmd = datasource
|
|
337
|
+
.command('test-integration <datasourceKey>')
|
|
338
|
+
.description('Integration test one datasource (unified validation API, runType=integration)');
|
|
339
|
+
attachDatasourceTestCommonOptions(cmd, {
|
|
340
|
+
includeNoAsync: false,
|
|
341
|
+
debugHelp: 'includeDebug + log under integration/<systemKey>/logs/; TTY appendix: summary, full, or raw'
|
|
342
|
+
});
|
|
343
|
+
return cmd.addHelpText('after', datasourceTestIntegrationHelpAfter());
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function setupDatasourceTestIntegrationCommand(datasource) {
|
|
347
|
+
// watch flags are already attached by attachDatasourceTestCommonOptions()
|
|
348
|
+
chainDatasourceTestIntegrationCommand(datasource).action(integrationTestCommandAction);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* @param {string} datasourceKey
|
|
353
|
+
* @param {Object} options
|
|
354
|
+
* @returns {Promise<{ exitCode: number, envelope: Object|null }>}
|
|
355
|
+
*/
|
|
356
|
+
async function runDatasourceTestE2ECliOnce(datasourceKey, options) {
|
|
357
|
+
const data = await runDatasourceTestE2E(datasourceKey, {
|
|
358
|
+
app: options.app,
|
|
359
|
+
environment: options.env,
|
|
360
|
+
debug: options.debug,
|
|
361
|
+
verbose: options.verbose,
|
|
362
|
+
async: options.async !== false,
|
|
363
|
+
testCrud: options.testCrud,
|
|
364
|
+
recordId: options.recordId,
|
|
365
|
+
cleanup: options.cleanup,
|
|
366
|
+
primaryKeyValue: options.primaryKeyValue,
|
|
367
|
+
timeout: options.timeout,
|
|
368
|
+
capabilityKey: options.capability,
|
|
369
|
+
sync: options.sync === true
|
|
370
|
+
});
|
|
371
|
+
const unifiedModes =
|
|
372
|
+
options.json || options.summary || options.warningsAsErrors || options.requireCert;
|
|
373
|
+
if (unifiedModes && data.datasourceTestRun) {
|
|
374
|
+
const exitCode = finalizeUnifiedValidationResult(
|
|
375
|
+
{
|
|
376
|
+
apiError: null,
|
|
377
|
+
pollTimedOut: false,
|
|
378
|
+
incompleteNoAsync: false,
|
|
379
|
+
envelope: data.datasourceTestRun
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
json: options.json,
|
|
383
|
+
summary: options.summary,
|
|
384
|
+
warningsAsErrors: options.warningsAsErrors,
|
|
385
|
+
requireCert: options.requireCert,
|
|
386
|
+
debug: options.debug,
|
|
387
|
+
requestedCapabilityKey: options.capability,
|
|
388
|
+
strictCapabilityScope: options.strictCapabilityScope === true
|
|
389
|
+
}
|
|
390
|
+
);
|
|
391
|
+
return { exitCode, envelope: data.datasourceTestRun };
|
|
392
|
+
}
|
|
393
|
+
const env = data.datasourceTestRun;
|
|
394
|
+
if (env && !unifiedModes) {
|
|
395
|
+
displayDatasourceTestE2EEnvelopeResults(datasourceKey, env, options);
|
|
396
|
+
const exitCode = exitCodeFromDatasourceTestRunEnvelope(env, options);
|
|
397
|
+
return { exitCode: exitCode === null ? 1 : exitCode, envelope: env };
|
|
398
|
+
}
|
|
399
|
+
const exitCode = finalizeDatasourceTestE2ELegacyPath(data, options);
|
|
400
|
+
return { exitCode, envelope: data.datasourceTestRun || null };
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
async function runDatasourceTestE2ECliAction(datasourceKey, options) {
|
|
404
|
+
const { exitCode } = await runDatasourceTestE2ECliOnce(datasourceKey, options);
|
|
405
|
+
process.exit(exitCode);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
async function e2eTestCommandAction(datasourceKey, capabilityKey, options) {
|
|
409
|
+
const optObj = options && typeof options === 'object' ? options : {};
|
|
410
|
+
const capFromArg = typeof capabilityKey === 'string' ? capabilityKey.trim() : '';
|
|
411
|
+
const capFromFlag = optObj.capability !== undefined && optObj.capability !== null
|
|
412
|
+
? String(optObj.capability).trim()
|
|
413
|
+
: '';
|
|
414
|
+
const requestedCapability = capFromArg || capFromFlag;
|
|
415
|
+
if (capFromArg && capFromFlag && capFromArg !== capFromFlag) {
|
|
416
|
+
logger.warn(
|
|
417
|
+
chalk.yellow('⚠ Capability mismatch:'),
|
|
418
|
+
`using positional '${capFromArg}' instead of --capability '${capFromFlag}'.`
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
const mergedOptions = { ...optObj, capability: requestedCapability || undefined };
|
|
422
|
+
try {
|
|
423
|
+
if (mergedOptions.watch) {
|
|
424
|
+
const { appKey } = await resolveAppKeyForDatasource(datasourceKey, mergedOptions.app);
|
|
425
|
+
await runDatasourceValidationWatchLoop({
|
|
426
|
+
appKey,
|
|
427
|
+
extraPaths: mergedOptions.watchPath || [],
|
|
428
|
+
includeApplicationYaml: mergedOptions.watchApplicationYaml === true,
|
|
429
|
+
watchCi: mergedOptions.watchCi === true,
|
|
430
|
+
watchFullDiff: mergedOptions.watchFullDiff === true,
|
|
431
|
+
runOnce: async() => {
|
|
432
|
+
try {
|
|
433
|
+
return await runDatasourceTestE2ECliOnce(datasourceKey, mergedOptions);
|
|
434
|
+
} catch (err) {
|
|
435
|
+
logger.error(formatBlockingError('E2E test failed:'), err.message);
|
|
436
|
+
return { exitCode: 3, envelope: null };
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
await runDatasourceTestE2ECliAction(datasourceKey, mergedOptions);
|
|
443
|
+
} catch (error) {
|
|
444
|
+
logger.error(formatBlockingError('E2E test failed:'), error.message);
|
|
445
|
+
process.exit(3);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function chainDatasourceTestE2ECommand(datasource) {
|
|
450
|
+
const cmd = datasource
|
|
451
|
+
.command('test-e2e <datasourceKey> [capabilityKey]')
|
|
452
|
+
.description('E2E test one datasource (unified validation API, runType=e2e)');
|
|
453
|
+
attachDatasourceTestCommonOptions(cmd, {
|
|
454
|
+
includeNoAsync: true,
|
|
455
|
+
includePayload: false,
|
|
456
|
+
appHelp: 'Integration folder name (default: resolve from cwd if inside integration/<systemKey>/)',
|
|
457
|
+
verboseHelp: 'Audit / explain-oriented request flags where applicable',
|
|
458
|
+
debugHelp: 'includeDebug + log under integration/<systemKey>/logs/; TTY appendix: summary, full, or raw',
|
|
459
|
+
timeoutHelp: 'Aggregate timeout for POST + polls (default 15m)',
|
|
460
|
+
timeoutDefault: String(15 * 60 * 1000)
|
|
461
|
+
});
|
|
462
|
+
return cmd
|
|
463
|
+
.option('--test-crud', 'Enable CRUD lifecycle test (e2eOptions.testCrud)')
|
|
464
|
+
.option('--record-id <id>', 'Record ID for test (e2eOptions.recordId)')
|
|
465
|
+
.option('--no-cleanup', 'Disable cleanup after test (e2eOptions.cleanup: false)')
|
|
466
|
+
.option(
|
|
467
|
+
'--primary-key-value <value|@path>',
|
|
468
|
+
'Primary key value or path to JSON file (e.g. @pk.json) for e2eOptions.primaryKeyValue'
|
|
469
|
+
)
|
|
470
|
+
.option('--capability <key>', 'Capability drill-down (deprecated; use positional [capabilityKey])')
|
|
471
|
+
.option(
|
|
472
|
+
'--strict-capability-scope',
|
|
473
|
+
'Exit 1 if a capability drill-down is requested but the report lists more than one capabilities[] row (plan §2.3)'
|
|
474
|
+
)
|
|
475
|
+
.addHelpText('after', datasourceTestE2eHelpAfter());
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
function setupDatasourceTestE2ECommand(datasource) {
|
|
479
|
+
// watch flags are already attached by attachDatasourceTestCommonOptions()
|
|
480
|
+
chainDatasourceTestE2ECommand(datasource).action(e2eTestCommandAction);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
module.exports = {
|
|
484
|
+
setupDatasourceTestCommand,
|
|
485
|
+
setupDatasourceTestIntegrationCommand,
|
|
486
|
+
setupDatasourceTestE2ECommand,
|
|
487
|
+
attachDatasourceWatchOptions,
|
|
488
|
+
/** @internal Exported for Jest: CLI action coverage without Commander. */
|
|
489
|
+
runDatasourceUnifiedTestOnceForWatch,
|
|
490
|
+
datasourceTestCommandAction,
|
|
491
|
+
runIntegrationOnceForWatch,
|
|
492
|
+
integrationTestCommandAction,
|
|
493
|
+
runDatasourceTestE2ECliOnce,
|
|
494
|
+
e2eTestCommandAction
|
|
495
|
+
};
|