@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,459 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Minimal human TTY + --summary for DatasourceTestRun (plan §3.2 / §16.9 subset).
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 2.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
const { sectionTitle, headerKeyValue, colorAggregateGlyph, successGlyph, failureGlyph } = require('./cli-test-layout-chalk');
|
|
9
|
+
const { appendCertificateTTY } = require('./datasource-test-run-certificate-tty');
|
|
10
|
+
|
|
11
|
+
const SEP = '────────────────────────────────';
|
|
12
|
+
|
|
13
|
+
/** @type {number} */
|
|
14
|
+
const DEFAULT_MAX_REF_CHARS = 200;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param {'ok'|'warn'|'fail'|'skipped'} status
|
|
18
|
+
* @returns {string}
|
|
19
|
+
*/
|
|
20
|
+
function statusGlyph(status) {
|
|
21
|
+
if (status === 'ok') return '✔';
|
|
22
|
+
if (status === 'warn') return '⚠';
|
|
23
|
+
if (status === 'fail') return '✖';
|
|
24
|
+
if (status === 'skipped') return '⏭';
|
|
25
|
+
return '?';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Map API status string to aggregate bucket for colors.
|
|
30
|
+
* @param {*} status
|
|
31
|
+
* @returns {'ok'|'warn'|'fail'|'skipped'|null} null = unknown / other
|
|
32
|
+
*/
|
|
33
|
+
function envelopeStatusAggregate(status) {
|
|
34
|
+
const s = String(status || '').toLowerCase();
|
|
35
|
+
if (s === 'warn') return 'warn';
|
|
36
|
+
if (s === 'fail') return 'fail';
|
|
37
|
+
if (s === 'skipped' || s === 'skip') return 'skipped';
|
|
38
|
+
if (s === 'ok') return 'ok';
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @param {*} status
|
|
44
|
+
* @param {string} rawWord - as returned by API (e.g. ok, warn)
|
|
45
|
+
* @returns {string}
|
|
46
|
+
*/
|
|
47
|
+
function colorStatusWord(status, rawWord) {
|
|
48
|
+
const agg = envelopeStatusAggregate(status);
|
|
49
|
+
const w = String(rawWord);
|
|
50
|
+
if (!agg) return chalk.gray(w);
|
|
51
|
+
if (agg === 'ok') return chalk.green(w);
|
|
52
|
+
if (agg === 'warn') return chalk.yellow(w);
|
|
53
|
+
if (agg === 'fail') return chalk.red(w);
|
|
54
|
+
return chalk.gray(w);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Colored glyph for status (neutral when unknown).
|
|
59
|
+
* @param {*} status
|
|
60
|
+
* @returns {string}
|
|
61
|
+
*/
|
|
62
|
+
function colorStatusGlyph(status) {
|
|
63
|
+
const agg = envelopeStatusAggregate(status);
|
|
64
|
+
const glyph = statusGlyph(status);
|
|
65
|
+
return agg ? colorAggregateGlyph(agg, glyph) : chalk.gray(glyph);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* `Status: ✔ ok` with layout-aligned colors (preserves raw status text).
|
|
70
|
+
* @param {Object} envelope
|
|
71
|
+
* @returns {string}
|
|
72
|
+
*/
|
|
73
|
+
function formatEnvelopeStatusLine(envelope) {
|
|
74
|
+
const raw = envelope.status !== undefined && envelope.status !== null ? String(envelope.status) : 'unknown';
|
|
75
|
+
const g = colorStatusGlyph(envelope.status);
|
|
76
|
+
return `${chalk.gray('Status:')} ${g} ${colorStatusWord(envelope.status, raw)}`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @param {boolean} ok
|
|
81
|
+
* @param {string} body - step name + optional tail
|
|
82
|
+
* @returns {string}
|
|
83
|
+
*/
|
|
84
|
+
function colorStepLine(ok, body) {
|
|
85
|
+
const sym = ok ? successGlyph() : failureGlyph();
|
|
86
|
+
return ` ${sym} ${chalk.white(body)}`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Normalize CLI --capability value for matching envelope.capabilities[].key
|
|
91
|
+
* @param {*} focusCapabilityKey
|
|
92
|
+
* @returns {string} trimmed or ''
|
|
93
|
+
*/
|
|
94
|
+
function normalizedFocusCapabilityKey(focusCapabilityKey) {
|
|
95
|
+
if (focusCapabilityKey === undefined || focusCapabilityKey === null) return '';
|
|
96
|
+
const s = String(focusCapabilityKey).trim();
|
|
97
|
+
return s;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* @param {string[]} lines
|
|
102
|
+
* @param {Object|null|undefined} e2e
|
|
103
|
+
*/
|
|
104
|
+
function pushCapabilityE2eLines(lines, e2e) {
|
|
105
|
+
if (!e2e || typeof e2e !== 'object') return;
|
|
106
|
+
if (e2e.status) {
|
|
107
|
+
const g = colorStatusGlyph(e2e.status);
|
|
108
|
+
lines.push(`${chalk.gray('E2E:')} ${g} ${colorStatusWord(e2e.status, e2e.status)}`);
|
|
109
|
+
}
|
|
110
|
+
const esteps = Array.isArray(e2e.steps) ? e2e.steps : [];
|
|
111
|
+
for (const st of esteps) {
|
|
112
|
+
const nm = st.name || st.step || 'step';
|
|
113
|
+
const ok = st.success !== false && !st.error;
|
|
114
|
+
const tail = st.error || st.message ? `: ${st.error || st.message}` : '';
|
|
115
|
+
lines.push(colorStepLine(ok, `${nm}${tail}`));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Multi-line TTY block for a single capability row (plan §2.3 drill-down).
|
|
121
|
+
* @param {Object|null|undefined} envelope
|
|
122
|
+
* @param {string} focusKey - non-empty
|
|
123
|
+
* @returns {string}
|
|
124
|
+
*/
|
|
125
|
+
function formatCapabilityFocusSection(envelope, focusKey) {
|
|
126
|
+
if (!focusKey) return '';
|
|
127
|
+
const lines = ['', chalk.gray(SEP), sectionTitle(`Capability scope: ${focusKey}`)];
|
|
128
|
+
const caps =
|
|
129
|
+
envelope && typeof envelope === 'object' && Array.isArray(envelope.capabilities)
|
|
130
|
+
? envelope.capabilities
|
|
131
|
+
: [];
|
|
132
|
+
const cap = caps.find(c => c && String(c.key) === focusKey);
|
|
133
|
+
if (!cap) {
|
|
134
|
+
lines.push(chalk.yellow(`(No row with key "${focusKey}" in capabilities[])`));
|
|
135
|
+
return lines.join('\n');
|
|
136
|
+
}
|
|
137
|
+
lines.push(formatEnvelopeStatusLine(cap));
|
|
138
|
+
if (cap.permission) {
|
|
139
|
+
lines.push(headerKeyValue('Permission:', String(cap.permission)));
|
|
140
|
+
}
|
|
141
|
+
pushCapabilityE2eLines(lines, cap.e2e);
|
|
142
|
+
return lines.join('\n');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* @param {Object} envelope
|
|
147
|
+
* @returns {string[]}
|
|
148
|
+
*/
|
|
149
|
+
function buildTtyMetaLines(envelope) {
|
|
150
|
+
const lines = [];
|
|
151
|
+
lines.push(
|
|
152
|
+
headerKeyValue('Datasource:', `${envelope.datasourceKey} (${envelope.systemKey})`)
|
|
153
|
+
);
|
|
154
|
+
lines.push(headerKeyValue('Run:', String(envelope.runType)));
|
|
155
|
+
lines.push(formatEnvelopeStatusLine(envelope));
|
|
156
|
+
const rid = envelope.runId || envelope.testRunId;
|
|
157
|
+
if (rid) lines.push(`${chalk.gray('Run ID:')} ${chalk.cyan(String(rid))}`);
|
|
158
|
+
if (envelope.reportCompleteness && envelope.reportCompleteness !== 'full') {
|
|
159
|
+
lines.push(
|
|
160
|
+
`${chalk.gray('Report:')} ${chalk.yellow(String(envelope.reportCompleteness))}`
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
return lines;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* @param {*} val
|
|
168
|
+
* @returns {string[]}
|
|
169
|
+
*/
|
|
170
|
+
function normalizeRefArray(val) {
|
|
171
|
+
if (val === null || val === undefined) return [];
|
|
172
|
+
return Array.isArray(val) ? val : [val];
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* @param {string} str
|
|
177
|
+
* @param {number} maxChars
|
|
178
|
+
* @returns {string}
|
|
179
|
+
*/
|
|
180
|
+
function truncateRefLine(str, maxChars) {
|
|
181
|
+
const s = String(str);
|
|
182
|
+
if (s.length <= maxChars) return s;
|
|
183
|
+
return `${s.slice(0, Math.max(0, maxChars - 24))}… [+${s.length - maxChars + 24} chars]`;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* @param {string[]} lines
|
|
188
|
+
* @param {string} title
|
|
189
|
+
* @param {*} arr
|
|
190
|
+
* @param {number} maxRefChars
|
|
191
|
+
* @returns {boolean}
|
|
192
|
+
*/
|
|
193
|
+
function appendStringRefBlock(lines, title, arr, maxRefChars) {
|
|
194
|
+
const entries = normalizeRefArray(arr).map(String);
|
|
195
|
+
if (!entries.length) return false;
|
|
196
|
+
lines.push(chalk.blue.bold(String(title)));
|
|
197
|
+
entries.forEach((text, i) => {
|
|
198
|
+
lines.push(` ${chalk.gray(`[${i + 1}]`)} ${chalk.white(truncateRefLine(text, maxRefChars))}`);
|
|
199
|
+
});
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* @param {string[]} lines
|
|
205
|
+
* @param {Object|null|undefined} dbg
|
|
206
|
+
* @param {number} maxRefChars
|
|
207
|
+
* @returns {boolean}
|
|
208
|
+
*/
|
|
209
|
+
function appendDebugPayloadRefLines(lines, dbg, maxRefChars) {
|
|
210
|
+
const payloadRefs = dbg && typeof dbg === 'object' ? normalizeRefArray(dbg.payloadRefs) : [];
|
|
211
|
+
if (!payloadRefs.length) return false;
|
|
212
|
+
lines.push(chalk.blue.bold('debug.payloadRefs:'));
|
|
213
|
+
payloadRefs.forEach((pr, i) => {
|
|
214
|
+
const idx = chalk.gray(`[${i + 1}]`);
|
|
215
|
+
if (typeof pr === 'string') {
|
|
216
|
+
lines.push(` ${idx} ${chalk.white(truncateRefLine(pr, maxRefChars))}`);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
if (pr && typeof pr === 'object') {
|
|
220
|
+
const k = pr.key !== undefined && pr.key !== null ? String(pr.key) : 'payload';
|
|
221
|
+
const r = pr.ref !== undefined && pr.ref !== null ? String(pr.ref) : '';
|
|
222
|
+
const row = r ? `${k}: ${r}` : k;
|
|
223
|
+
lines.push(` ${idx} ${chalk.white(truncateRefLine(row, maxRefChars))}`);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
lines.push(` ${idx} ${chalk.gray('(ref)')}`);
|
|
227
|
+
});
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* @param {string[]} lines
|
|
233
|
+
* @param {Object} dbg
|
|
234
|
+
* @param {number} maxRefChars
|
|
235
|
+
* @returns {boolean}
|
|
236
|
+
*/
|
|
237
|
+
function appendDebugMetaLines(lines, dbg, maxRefChars) {
|
|
238
|
+
let added = false;
|
|
239
|
+
function formatSecondsText(s) {
|
|
240
|
+
const txt = String(s);
|
|
241
|
+
// UI-only: reduce noisy float seconds to 3 decimals, e.g. "1.1713749s" -> "1.171s".
|
|
242
|
+
// Applies only to number tokens immediately followed by "s".
|
|
243
|
+
return txt.replace(/(\d+\.\d+)(?=s\b)/g, m => {
|
|
244
|
+
const n = Number(m);
|
|
245
|
+
if (!Number.isFinite(n)) return m;
|
|
246
|
+
return n.toFixed(3);
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
if (dbg.mode) {
|
|
250
|
+
lines.push(
|
|
251
|
+
`${chalk.blue.bold('debug.mode:')} ${chalk.white(String(dbg.mode))}`
|
|
252
|
+
);
|
|
253
|
+
added = true;
|
|
254
|
+
}
|
|
255
|
+
if (dbg.executionSummary) {
|
|
256
|
+
lines.push(
|
|
257
|
+
`${chalk.blue.bold('debug.executionSummary:')} ${chalk.white(
|
|
258
|
+
truncateRefLine(formatSecondsText(dbg.executionSummary), maxRefChars)
|
|
259
|
+
)}`
|
|
260
|
+
);
|
|
261
|
+
added = true;
|
|
262
|
+
}
|
|
263
|
+
return added;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Append audit + debug reference layout (OpenAPI AuditRefs, DebugTrace.payloadRefs).
|
|
268
|
+
* @param {string[]} lines
|
|
269
|
+
* @param {Object} envelope
|
|
270
|
+
* @param {{ maxRefChars?: number }} [opts]
|
|
271
|
+
* @returns {boolean} True if any reference line was added
|
|
272
|
+
*/
|
|
273
|
+
function appendReferenceLayoutLines(lines, envelope, opts = {}) {
|
|
274
|
+
const maxRefChars = opts.maxRefChars ?? DEFAULT_MAX_REF_CHARS;
|
|
275
|
+
const audit = envelope && envelope.audit;
|
|
276
|
+
const dbg = envelope && envelope.debug;
|
|
277
|
+
const parts = [];
|
|
278
|
+
|
|
279
|
+
if (audit && typeof audit === 'object') {
|
|
280
|
+
parts.push(appendStringRefBlock(lines, 'audit.executionIds:', audit.executionIds, maxRefChars));
|
|
281
|
+
parts.push(appendStringRefBlock(lines, 'audit.traceRefs:', audit.traceRefs, maxRefChars));
|
|
282
|
+
parts.push(appendStringRefBlock(lines, 'audit.rbacTraceRefs:', audit.rbacTraceRefs, maxRefChars));
|
|
283
|
+
parts.push(appendStringRefBlock(lines, 'audit.abacTraceRefs:', audit.abacTraceRefs, maxRefChars));
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
parts.push(appendDebugPayloadRefLines(lines, dbg, maxRefChars));
|
|
287
|
+
|
|
288
|
+
if (dbg && typeof dbg === 'object') {
|
|
289
|
+
parts.push(appendStringRefBlock(lines, 'debug.executionIds:', dbg.executionIds, maxRefChars));
|
|
290
|
+
parts.push(appendDebugMetaLines(lines, dbg, maxRefChars));
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return parts.some(Boolean);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* @param {string[]} lines
|
|
298
|
+
* @param {Object} envelope
|
|
299
|
+
* @param {number} [maxIssues]
|
|
300
|
+
*/
|
|
301
|
+
function appendValidationIssueLines(lines, envelope, maxIssues = 5) {
|
|
302
|
+
const issues = envelope && envelope.validation && Array.isArray(envelope.validation.issues) ? envelope.validation.issues : [];
|
|
303
|
+
if (!issues.length) return;
|
|
304
|
+
lines.push(sectionTitle('Validation issues:'));
|
|
305
|
+
const cap = Math.min(maxIssues, issues.length);
|
|
306
|
+
for (let i = 0; i < cap; i += 1) {
|
|
307
|
+
const iss = issues[i];
|
|
308
|
+
const code = iss && iss.code ? chalk.red(`[${iss.code}] `) : '';
|
|
309
|
+
const msg = iss && iss.message ? String(iss.message) : JSON.stringify(iss);
|
|
310
|
+
lines.push(` ${code}${chalk.yellow(msg)}`);
|
|
311
|
+
}
|
|
312
|
+
if (issues.length > cap) {
|
|
313
|
+
lines.push(chalk.gray(` … and ${issues.length - cap} more (see --json or debug full/raw)`));
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* @param {string[]} lines
|
|
319
|
+
* @param {Object} envelope
|
|
320
|
+
*/
|
|
321
|
+
function formatIntegrationStepLine(st) {
|
|
322
|
+
const nm = (st && (st.name || st.step)) || 'step';
|
|
323
|
+
const ok = st && st.success !== false && !st.error;
|
|
324
|
+
const detail = st && (st.message || st.error) ? `: ${st.message || st.error}` : '';
|
|
325
|
+
return colorStepLine(ok, `${nm}${detail}`);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function appendIntegrationStepLines(lines, envelope) {
|
|
329
|
+
const integ = envelope && envelope.integration;
|
|
330
|
+
const steps = integ && Array.isArray(integ.stepResults) ? integ.stepResults : [];
|
|
331
|
+
if (!steps.length) return;
|
|
332
|
+
lines.push(sectionTitle('Integration steps:'));
|
|
333
|
+
for (const st of steps) {
|
|
334
|
+
lines.push(formatIntegrationStepLine(st));
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function pickExecutiveVerdictLine(envelope) {
|
|
339
|
+
const dev = envelope.developer;
|
|
340
|
+
const cert = envelope.certificate;
|
|
341
|
+
if (envelope.runType === 'e2e' && cert && typeof cert === 'object') {
|
|
342
|
+
const cs = cert.summary;
|
|
343
|
+
if (cs && String(cs).trim()) return String(cs).trim();
|
|
344
|
+
}
|
|
345
|
+
return (
|
|
346
|
+
(dev && dev.executiveSummary) ||
|
|
347
|
+
(cert && cert.summary) ||
|
|
348
|
+
(envelope.validation && envelope.validation.summary) ||
|
|
349
|
+
(envelope.integration && envelope.integration.summary) ||
|
|
350
|
+
`Run finished with status ${envelope.status}.`
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Plan §3.9: explicit line when E2E has no capability rows (skipped when --capability drill-down is active).
|
|
356
|
+
* @param {string[]} lines
|
|
357
|
+
* @param {Object} envelope
|
|
358
|
+
* @param {{ focusCapabilityKey?: string }} [options]
|
|
359
|
+
*/
|
|
360
|
+
function appendNoCapabilitiesReportedLine(lines, envelope, options = {}) {
|
|
361
|
+
if (envelope.runType !== 'e2e') return;
|
|
362
|
+
if (normalizedFocusCapabilityKey(options.focusCapabilityKey)) return;
|
|
363
|
+
const caps = envelope.capabilities;
|
|
364
|
+
if (Array.isArray(caps) && caps.length > 0) return;
|
|
365
|
+
lines.push(chalk.gray('No capabilities reported.'));
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* @param {string[]} parts
|
|
370
|
+
* @param {Object} envelope
|
|
371
|
+
* @param {string} focus - normalized or ''
|
|
372
|
+
*/
|
|
373
|
+
function appendCapabilitySummaryPart(parts, envelope, focus) {
|
|
374
|
+
if (focus) {
|
|
375
|
+
const caps = Array.isArray(envelope.capabilities) ? envelope.capabilities : [];
|
|
376
|
+
const row = caps.find(c => c && String(c.key) === focus);
|
|
377
|
+
parts.push(
|
|
378
|
+
row ? `Cap ${focus}: ${statusGlyph(row.status)} ${row.status}` : `Cap ${focus}: (missing)`
|
|
379
|
+
);
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
const capSummary = envelope.capabilitySummary;
|
|
383
|
+
if (capSummary && typeof capSummary === 'object') {
|
|
384
|
+
const passed = capSummary.passedCount;
|
|
385
|
+
const total = capSummary.totalCount;
|
|
386
|
+
if (typeof passed === 'number' && typeof total === 'number') {
|
|
387
|
+
parts.push(`Capabilities: ${passed}/${total}`);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* @param {string[]} parts
|
|
394
|
+
* @param {Object} envelope
|
|
395
|
+
*/
|
|
396
|
+
function appendCertificateSummaryPart(parts, envelope) {
|
|
397
|
+
const cert = envelope.certificate;
|
|
398
|
+
if (!cert || typeof cert !== 'object') return;
|
|
399
|
+
const level =
|
|
400
|
+
cert.level !== undefined && cert.level !== null ? String(cert.level) : '';
|
|
401
|
+
const cg = cert.status === 'passed' ? '✔' : cert.status === 'not_passed' ? '✖' : '⚠';
|
|
402
|
+
if (level) parts.push(`Certificate: ${level} ${cg}`);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* One-line summary (plan §16.9 normative field order subset).
|
|
407
|
+
* @param {Object} envelope
|
|
408
|
+
* @param {{ focusCapabilityKey?: string }} [options]
|
|
409
|
+
* @returns {string}
|
|
410
|
+
*/
|
|
411
|
+
function formatDatasourceTestRunSummary(envelope, options = {}) {
|
|
412
|
+
if (!envelope || typeof envelope !== 'object') return '';
|
|
413
|
+
const parts = [];
|
|
414
|
+
parts.push(String(envelope.datasourceKey || 'unknown'));
|
|
415
|
+
parts.push(`${statusGlyph(envelope.status)} ${(envelope.status || '').toUpperCase()}`);
|
|
416
|
+
const focus = normalizedFocusCapabilityKey(options.focusCapabilityKey);
|
|
417
|
+
appendCapabilitySummaryPart(parts, envelope, focus);
|
|
418
|
+
appendCertificateSummaryPart(parts, envelope);
|
|
419
|
+
return parts.join(' | ');
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Default TTY block (header + verdict line + short summary + optional completeness).
|
|
424
|
+
* @param {Object} envelope
|
|
425
|
+
* @param {{ focusCapabilityKey?: string }} [options] - When set (e.g. --capability), append single-cap block (plan §2.3).
|
|
426
|
+
* @returns {string}
|
|
427
|
+
*/
|
|
428
|
+
function formatDatasourceTestRunTTY(envelope, options = {}) {
|
|
429
|
+
if (!envelope || typeof envelope !== 'object') return '';
|
|
430
|
+
const lines = [...buildTtyMetaLines(envelope)];
|
|
431
|
+
appendNoCapabilitiesReportedLine(lines, envelope, options);
|
|
432
|
+
lines.push('');
|
|
433
|
+
lines.push(sectionTitle('Verdict:'));
|
|
434
|
+
lines.push(chalk.white(pickExecutiveVerdictLine(envelope)));
|
|
435
|
+
appendCertificateTTY(lines, envelope);
|
|
436
|
+
lines.push('');
|
|
437
|
+
lines.push(chalk.gray(SEP));
|
|
438
|
+
if (appendReferenceLayoutLines(lines, envelope, { maxRefChars: 160 })) {
|
|
439
|
+
lines.push('');
|
|
440
|
+
}
|
|
441
|
+
appendValidationIssueLines(lines, envelope);
|
|
442
|
+
appendIntegrationStepLines(lines, envelope);
|
|
443
|
+
const focus = normalizedFocusCapabilityKey(options.focusCapabilityKey);
|
|
444
|
+
if (focus) {
|
|
445
|
+
lines.push(formatCapabilityFocusSection(envelope, focus));
|
|
446
|
+
}
|
|
447
|
+
return lines.join('\n');
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
module.exports = {
|
|
451
|
+
formatDatasourceTestRunSummary,
|
|
452
|
+
formatDatasourceTestRunTTY,
|
|
453
|
+
formatCapabilityFocusSection,
|
|
454
|
+
normalizedFocusCapabilityKey,
|
|
455
|
+
statusGlyph,
|
|
456
|
+
SEP,
|
|
457
|
+
appendReferenceLayoutLines,
|
|
458
|
+
normalizeRefArray
|
|
459
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Exit code matrix for DatasourceTestRun after successful HTTP (plan §3.1).
|
|
3
|
+
* HTTP/transport failures are exit 3 (handled by callers).
|
|
4
|
+
* @author AI Fabrix Team
|
|
5
|
+
* @version 2.0.0
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Compute CLI exit code from parsed DatasourceTestRun envelope.
|
|
10
|
+
* Ordering: status / warnings-as-errors → require-cert (§3.1).
|
|
11
|
+
* @param {import('../api/types/validation-run.types').DatasourceTestRunLike|null|undefined} body
|
|
12
|
+
* @param {Object} [opts]
|
|
13
|
+
* @param {boolean} [opts.warningsAsErrors]
|
|
14
|
+
* @param {boolean} [opts.requireCert]
|
|
15
|
+
* @returns {number} 0 | 1 | 2 | 3 (3 = treat as parse/body unusable)
|
|
16
|
+
*/
|
|
17
|
+
function computeExitCodeFromDatasourceTestRun(body, opts = {}) {
|
|
18
|
+
if (!body || typeof body !== 'object') {
|
|
19
|
+
return 3;
|
|
20
|
+
}
|
|
21
|
+
const status = body.status;
|
|
22
|
+
if (status === 'fail') {
|
|
23
|
+
return 1;
|
|
24
|
+
}
|
|
25
|
+
if (status === 'warn' && opts.warningsAsErrors === true) {
|
|
26
|
+
return 1;
|
|
27
|
+
}
|
|
28
|
+
if (status === 'ok' || status === 'skipped' || status === 'warn') {
|
|
29
|
+
if (opts.requireCert === true) {
|
|
30
|
+
const cert = body.certificate;
|
|
31
|
+
if (!cert) {
|
|
32
|
+
return 2;
|
|
33
|
+
}
|
|
34
|
+
if (cert.status === 'not_passed') {
|
|
35
|
+
return 2;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return 0;
|
|
39
|
+
}
|
|
40
|
+
return 3;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Exit code for poll timeout with last envelope (plan §3.4).
|
|
45
|
+
* @param {import('../api/types/validation-run.types').DatasourceTestRunLike|null} lastBody
|
|
46
|
+
* @returns {number} 1 if root fail, else 3
|
|
47
|
+
*/
|
|
48
|
+
function exitCodeForPollTimeout(lastBody) {
|
|
49
|
+
if (lastBody && typeof lastBody === 'object' && lastBody.status === 'fail') {
|
|
50
|
+
return 1;
|
|
51
|
+
}
|
|
52
|
+
return 3;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const {
|
|
56
|
+
deriveSystemStatus,
|
|
57
|
+
systemCertStatus
|
|
58
|
+
} = require('./external-system-system-test-tty');
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* System-level exit code from per-datasource result rows (same matrix as §3.1 on synthetic rollup).
|
|
62
|
+
* @param {Array<{ skipped?: boolean, success?: boolean, datasourceTestRun?: Object|null }>} rows
|
|
63
|
+
* @param {Object} [opts]
|
|
64
|
+
* @param {boolean} [opts.warningsAsErrors]
|
|
65
|
+
* @param {boolean} [opts.requireCert]
|
|
66
|
+
* @returns {number}
|
|
67
|
+
*/
|
|
68
|
+
function computeSystemExitCodeFromDatasourceRows(rows, opts = {}) {
|
|
69
|
+
const list = Array.isArray(rows) ? rows : [];
|
|
70
|
+
const status = deriveSystemStatus(list);
|
|
71
|
+
const certAgg = systemCertStatus(list);
|
|
72
|
+
const body = {
|
|
73
|
+
status,
|
|
74
|
+
certificate: certAgg ? { status: certAgg === 'passed' ? 'passed' : 'not_passed' } : undefined
|
|
75
|
+
};
|
|
76
|
+
return computeExitCodeFromDatasourceTestRun(body, opts);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
module.exports = {
|
|
80
|
+
computeExitCodeFromDatasourceTestRun,
|
|
81
|
+
computeSystemExitCodeFromDatasourceRows,
|
|
82
|
+
exitCodeForPollTimeout
|
|
83
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Map DatasourceTestRun envelope → legacy CLI display shapes (integration + E2E).
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 2.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @param {Object|null} envelope
|
|
9
|
+
* @returns {string|null}
|
|
10
|
+
*/
|
|
11
|
+
function firstIssueMessage(envelope) {
|
|
12
|
+
const v = envelope && envelope.validation;
|
|
13
|
+
const issues = v && Array.isArray(v.issues) ? v.issues : [];
|
|
14
|
+
const first = issues.find(i => i && (i.message || i.hint));
|
|
15
|
+
if (first) return String(first.message || first.hint);
|
|
16
|
+
const integ = envelope && envelope.integration;
|
|
17
|
+
const steps = integ && Array.isArray(integ.stepResults) ? integ.stepResults : [];
|
|
18
|
+
const bad = steps.find(s => s && s.success === false && (s.message || s.error));
|
|
19
|
+
if (bad) return String(bad.message || bad.error || 'Integration step failed');
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Legacy integration result for displayIntegrationTestResults / verbose details.
|
|
25
|
+
* @param {Object|null} envelope
|
|
26
|
+
* @param {string} datasourceKey
|
|
27
|
+
* @returns {Object}
|
|
28
|
+
*/
|
|
29
|
+
function integrationResultFromEnvelope(envelope, datasourceKey) {
|
|
30
|
+
if (!envelope || typeof envelope !== 'object') {
|
|
31
|
+
return {
|
|
32
|
+
key: datasourceKey,
|
|
33
|
+
systemKey: 'unknown',
|
|
34
|
+
success: false,
|
|
35
|
+
skipped: false,
|
|
36
|
+
validationResults: {},
|
|
37
|
+
fieldMappingResults: {},
|
|
38
|
+
endpointTestResults: {},
|
|
39
|
+
error: 'No report envelope',
|
|
40
|
+
envelope: null
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const success = envelope.status !== 'fail';
|
|
44
|
+
const err = success ? undefined : firstIssueMessage(envelope) || `status: ${envelope.status}`;
|
|
45
|
+
return {
|
|
46
|
+
key: datasourceKey,
|
|
47
|
+
systemKey: envelope.systemKey || 'unknown',
|
|
48
|
+
success,
|
|
49
|
+
skipped: false,
|
|
50
|
+
error: err,
|
|
51
|
+
envelope
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Map integration.stepResults → E2E-style steps for displayE2EResults.
|
|
57
|
+
* @param {Object|null} envelope
|
|
58
|
+
* @returns {{ steps: Object[], success: boolean, status?: string, error?: string }}
|
|
59
|
+
*/
|
|
60
|
+
function e2eShapeFromEnvelope(envelope) {
|
|
61
|
+
if (!envelope || typeof envelope !== 'object') {
|
|
62
|
+
return { steps: [], success: false, error: 'No report envelope' };
|
|
63
|
+
}
|
|
64
|
+
const integ = envelope.integration;
|
|
65
|
+
const raw = integ && Array.isArray(integ.stepResults) ? integ.stepResults : [];
|
|
66
|
+
const steps = raw.map(s => ({
|
|
67
|
+
name: s.name || 'step',
|
|
68
|
+
step: s.name,
|
|
69
|
+
success: s.success !== false,
|
|
70
|
+
message: s.message,
|
|
71
|
+
error: s.success === false ? s.message || 'failed' : undefined
|
|
72
|
+
}));
|
|
73
|
+
const success = envelope.status !== 'fail';
|
|
74
|
+
let status;
|
|
75
|
+
if (envelope.status === 'fail') status = 'failed';
|
|
76
|
+
else if (envelope.reportCompleteness && envelope.reportCompleteness !== 'full') {
|
|
77
|
+
status = 'completed';
|
|
78
|
+
} else {
|
|
79
|
+
status = 'completed';
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
steps,
|
|
83
|
+
success,
|
|
84
|
+
status,
|
|
85
|
+
error: success ? undefined : firstIssueMessage(envelope) || undefined
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
module.exports = {
|
|
90
|
+
integrationResultFromEnvelope,
|
|
91
|
+
e2eShapeFromEnvelope,
|
|
92
|
+
firstIssueMessage
|
|
93
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview reportVersion compatibility warnings (plan §3.15).
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 2.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** CLI-supported major reportVersion (bump when breaking). */
|
|
8
|
+
const SUPPORTED_MAJOR = 1;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Parse leading major from semver-like string (e.g. 1.1.0 → 1).
|
|
12
|
+
* @param {string} v
|
|
13
|
+
* @returns {number|null}
|
|
14
|
+
*/
|
|
15
|
+
function parseMajor(v) {
|
|
16
|
+
if (!v || typeof v !== 'string') return null;
|
|
17
|
+
const m = /^v?(\d+)/.exec(v.trim());
|
|
18
|
+
if (!m) return null;
|
|
19
|
+
return parseInt(m[1], 10);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* stderr messages for reportVersion handling.
|
|
24
|
+
* @param {string|undefined} reportVersion - From envelope
|
|
25
|
+
* @returns {{ level: 'none'|'warn'|'info', message: string }|null}
|
|
26
|
+
*/
|
|
27
|
+
function getReportVersionStderrMessage(reportVersion) {
|
|
28
|
+
const major = parseMajor(reportVersion || '');
|
|
29
|
+
if (major === null) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
if (major < SUPPORTED_MAJOR - 1) {
|
|
33
|
+
return {
|
|
34
|
+
level: 'warn',
|
|
35
|
+
message: `reportVersion unsupported (got ${reportVersion}, support ${SUPPORTED_MAJOR - 1}–${SUPPORTED_MAJOR} major)`
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
if (major > SUPPORTED_MAJOR) {
|
|
39
|
+
return {
|
|
40
|
+
level: 'info',
|
|
41
|
+
message: 'Newer reportVersion; some fields may be ignored'
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports = {
|
|
48
|
+
SUPPORTED_MAJOR,
|
|
49
|
+
parseMajor,
|
|
50
|
+
getReportVersionStderrMessage
|
|
51
|
+
};
|