@aifabrix/builder 2.42.1 → 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 +2 -2
- 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 +157 -0
- package/integration/{hubspot → hubspot-test}/application.json +6 -6
- package/integration/{hubspot → hubspot-test}/create-hubspot.js +10 -10
- package/integration/hubspot-test/env.template +4 -0
- package/integration/hubspot-test/hubspot-test-datasource-company.json +138 -0
- package/integration/hubspot-test/hubspot-test-datasource-contact.json +146 -0
- package/integration/hubspot-test/hubspot-test-datasource-deal.json +146 -0
- package/integration/hubspot-test/hubspot-test-datasource-users.json +76 -0
- package/integration/{hubspot/hubspot-deploy.json → hubspot-test/hubspot-test-deploy.json} +201 -24
- package/integration/{hubspot/hubspot-system.json → hubspot-test/hubspot-test-system.json} +8 -7
- package/integration/hubspot-test/rbac.json +166 -0
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-hubspot-credential-real.yaml +3 -3
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-hubspot-env-vars.yaml +2 -2
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-add-datasource.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-credential-create.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-credential-select.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-known-platform.yaml +1 -1
- package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-source.yaml +2 -0
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-mode.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-openapi-file.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-openapi-url.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-source.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-dimension-array-test.yaml +1 -1
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-key-test.yaml +5 -0
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-path-test.yaml +5 -0
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-dimension-test.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-rbac-test.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-rbac-yaml-test.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-dataplane-down-tests.js +1 -7
- package/integration/{hubspot → hubspot-test}/test-dataplane-down.js +3 -3
- package/integration/{hubspot → hubspot-test}/test.js +137 -102
- package/integration/{hubspot → hubspot-test}/wizard-hubspot-e2e.yaml +2 -2
- package/integration/{hubspot → hubspot-test}/wizard-hubspot-platform.yaml +1 -1
- 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/service-users.api.js +111 -2
- package/lib/api/types/dev.types.js +4 -3
- package/lib/api/types/pipeline.types.js +8 -5
- package/lib/api/types/service-users.types.js +41 -0
- 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 +19 -8
- package/lib/app/rotate-secret.js +17 -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 +59 -123
- package/lib/cli/setup-app.test-commands.js +179 -0
- package/lib/cli/setup-auth.js +36 -14
- 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 +190 -103
- package/lib/cli/setup-environment.js +11 -20
- package/lib/cli/setup-external-system.js +62 -22
- package/lib/cli/setup-infra.js +139 -47
- package/lib/cli/setup-parameters.js +32 -0
- package/lib/cli/setup-secrets.js +147 -10
- package/lib/cli/setup-service-user.js +146 -20
- package/lib/cli/setup-utility.js +47 -19
- 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 +10 -14
- 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 +123 -71
- 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 +16 -10
- package/lib/commands/repair-rbac.js +25 -19
- package/lib/commands/repair.js +116 -32
- package/lib/commands/secrets-list.js +23 -12
- package/lib/commands/secrets-remove-all.js +220 -0
- package/lib/commands/secrets-remove.js +22 -13
- package/lib/commands/secrets-set.js +21 -12
- package/lib/commands/secrets-validate.js +20 -7
- package/lib/commands/secure.js +10 -9
- package/lib/commands/service-user.js +243 -13
- package/lib/commands/test-e2e-external.js +27 -1
- package/lib/commands/up-common.js +28 -2
- package/lib/commands/up-dataplane.js +31 -18
- 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 +16 -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 +59 -58
- package/lib/core/diff.js +3 -2
- package/lib/core/ensure-encryption-key.js +2 -4
- 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 +228 -42
- package/lib/core/templates-env.js +4 -3
- package/lib/core/templates.js +1 -1
- package/lib/datasource/abac-validator.js +148 -0
- package/lib/datasource/deploy.js +75 -53
- package/lib/datasource/field-reference-validator.js +77 -36
- package/lib/datasource/integration-context.js +63 -0
- package/lib/datasource/list.js +8 -7
- package/lib/datasource/log-viewer.js +252 -0
- package/lib/datasource/resolve-app.js +109 -0
- package/lib/datasource/test-e2e.js +95 -155
- package/lib/datasource/test-integration.js +121 -109
- 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 +162 -15
- 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 +104 -14
- 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-controller-manifest.js +3 -3
- package/lib/generator/external.js +23 -11
- package/lib/generator/helpers.js +71 -12
- package/lib/generator/index.js +8 -4
- package/lib/generator/split-readme.js +12 -7
- package/lib/generator/split-variables.js +2 -1
- package/lib/generator/split.js +46 -11
- package/lib/generator/wizard-readme.js +3 -3
- package/lib/generator/wizard.js +16 -13
- package/lib/infrastructure/compose.js +60 -6
- package/lib/infrastructure/helpers.js +238 -51
- package/lib/infrastructure/index.js +64 -37
- 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 +1201 -433
- 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-config-resolver.js +23 -1
- 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 +209 -6
- 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/credential-secrets-env.js +16 -1
- 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 +42 -11
- package/lib/utils/env-template.js +2 -2
- package/lib/utils/environment-scoped-resources.js +144 -0
- package/lib/utils/error-formatter.js +125 -9
- 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-env-template.js +180 -0
- package/lib/utils/external-readme.js +8 -1
- package/lib/utils/external-system-display.js +277 -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 +32 -14
- package/lib/utils/health-check-url.js +119 -0
- package/lib/utils/health-check.js +59 -25
- package/lib/utils/help-builder.js +14 -13
- 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 +29 -7
- package/lib/utils/paths.js +136 -48
- 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 +171 -51
- package/lib/utils/secrets-helpers.js +70 -59
- package/lib/utils/secrets-kv-scope.js +60 -0
- package/lib/utils/secrets-utils.js +35 -37
- package/lib/utils/secrets-validation.js +3 -1
- package/lib/utils/secrets-yaml-preserve.js +109 -0
- package/lib/utils/secure-file-permissions.js +91 -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 +37 -5
- 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 +78 -1
- package/lib/validation/datasource-warnings.js +56 -0
- package/lib/validation/env-template-auth.js +50 -2
- package/lib/validation/external-manifest-validator.js +35 -7
- package/lib/validation/validate-display.js +37 -31
- package/lib/validation/validate.js +9 -10
- package/lib/validation/validator-unresolved-placeholders.js +98 -0
- package/lib/validation/validator.js +32 -78
- package/lib/validation/wizard-config-validator.js +2 -1
- package/package.json +11 -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 +80 -18
- 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 +55 -14
- 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/env.template.hbs +22 -0
- 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/integration/hubspot/README.md +0 -102
- package/integration/hubspot/env.template +0 -4
- package/integration/hubspot/hubspot-datasource-company.json +0 -541
- package/integration/hubspot/hubspot-datasource-contact.json +0 -639
- package/integration/hubspot/hubspot-datasource-deal.json +0 -588
- package/integration/hubspot/hubspot-datasource-users.json +0 -116
- package/integration/hubspot/test-artifacts/wizard-invalid-missing-source.yaml +0 -2
- package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-key-test.yaml +0 -5
- package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-path-test.yaml +0 -5
- package/lib/api/external-test.api.js +0 -111
- package/lib/schema/env-config.yaml +0 -43
- /package/integration/{hubspot → hubspot-test}/companies.json +0 -0
- /package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-app-name.yaml +0 -0
- /package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-missing-app.yaml +0 -0
- /package/integration/{hubspot → hubspot-test}/test-dataplane-down-helpers.js +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const { formatSuccessLine } = require('./cli-test-layout-chalk');
|
|
1
2
|
/**
|
|
2
3
|
* AI Fabrix Builder - App Run Container Helpers
|
|
3
4
|
*
|
|
@@ -9,12 +10,13 @@
|
|
|
9
10
|
* @version 2.0.0
|
|
10
11
|
*/
|
|
11
12
|
|
|
12
|
-
const { exec } = require('child_process');
|
|
13
|
-
const { promisify } = require('util');
|
|
14
13
|
const chalk = require('chalk');
|
|
15
14
|
const logger = require('./logger');
|
|
16
|
-
|
|
17
|
-
const
|
|
15
|
+
const { execWithDockerEnv } = require('./docker-exec');
|
|
16
|
+
const {
|
|
17
|
+
resolveRunContainerName,
|
|
18
|
+
buildDefaultLocalContainerName
|
|
19
|
+
} = require('./environment-scoped-resources');
|
|
18
20
|
|
|
19
21
|
/**
|
|
20
22
|
* Checks if Docker image exists for the application
|
|
@@ -30,7 +32,7 @@ async function checkImageExists(imageName, tag = 'latest', debug = false) {
|
|
|
30
32
|
if (debug) {
|
|
31
33
|
logger.log(chalk.gray(`[DEBUG] Executing: ${cmd}`));
|
|
32
34
|
}
|
|
33
|
-
const { stdout } = await
|
|
35
|
+
const { stdout } = await execWithDockerEnv(cmd);
|
|
34
36
|
const lines = stdout.trim().split('\n').filter(line => line.trim() !== '');
|
|
35
37
|
const exists = lines.some(line => line.trim() === fullImageName);
|
|
36
38
|
if (debug) {
|
|
@@ -57,11 +59,15 @@ async function checkImageExists(imageName, tag = 'latest', debug = false) {
|
|
|
57
59
|
* @function getContainerName
|
|
58
60
|
* @param {string} appName - Application name
|
|
59
61
|
* @param {number|string} developerId - Developer ID
|
|
62
|
+
* @param {{ effectiveEnvironmentScopedResources?: boolean, env?: string }|null} [scopeOpts] - When set (run --env dev|tst + gates), uses env-scoped name
|
|
60
63
|
* @returns {string} Container name
|
|
61
64
|
*/
|
|
62
|
-
function getContainerName(appName, developerId) {
|
|
65
|
+
function getContainerName(appName, developerId, scopeOpts = null) {
|
|
63
66
|
const idNum = typeof developerId === 'string' ? parseInt(developerId, 10) : developerId;
|
|
64
|
-
|
|
67
|
+
if (scopeOpts && scopeOpts.effectiveEnvironmentScopedResources && scopeOpts.env) {
|
|
68
|
+
return resolveRunContainerName(appName, developerId, true, scopeOpts.env);
|
|
69
|
+
}
|
|
70
|
+
return buildDefaultLocalContainerName(appName, developerId, idNum);
|
|
65
71
|
}
|
|
66
72
|
|
|
67
73
|
/**
|
|
@@ -72,21 +78,21 @@ function getContainerName(appName, developerId) {
|
|
|
72
78
|
*/
|
|
73
79
|
async function logContainerDebugInfo(containerName) {
|
|
74
80
|
const statusCmd = `docker ps --filter "name=${containerName}" --format "{{.Status}}"`;
|
|
75
|
-
const { stdout: status } = await
|
|
81
|
+
const { stdout: status } = await execWithDockerEnv(statusCmd);
|
|
76
82
|
const portsCmd = `docker ps --filter "name=${containerName}" --format "{{.Ports}}"`;
|
|
77
|
-
const { stdout: ports } = await
|
|
83
|
+
const { stdout: ports } = await execWithDockerEnv(portsCmd);
|
|
78
84
|
logger.log(chalk.gray(`[DEBUG] Container status: ${status.trim()}`));
|
|
79
85
|
logger.log(chalk.gray(`[DEBUG] Container ports: ${ports.trim()}`));
|
|
80
86
|
}
|
|
81
87
|
|
|
82
|
-
async function checkContainerRunning(appName, developerId, debug = false) {
|
|
88
|
+
async function checkContainerRunning(appName, developerId, debug = false, scopeOpts = null) {
|
|
83
89
|
try {
|
|
84
|
-
const containerName = getContainerName(appName, developerId);
|
|
90
|
+
const containerName = getContainerName(appName, developerId, scopeOpts);
|
|
85
91
|
const cmd = `docker ps --filter "name=${containerName}" --format "{{.Names}}"`;
|
|
86
92
|
if (debug) {
|
|
87
93
|
logger.log(chalk.gray(`[DEBUG] Executing: ${cmd}`));
|
|
88
94
|
}
|
|
89
|
-
const { stdout } = await
|
|
95
|
+
const { stdout } = await execWithDockerEnv(cmd);
|
|
90
96
|
const isRunning = stdout.trim() === containerName;
|
|
91
97
|
if (debug) {
|
|
92
98
|
logger.log(chalk.gray(`[DEBUG] Container ${containerName} running: ${isRunning}`));
|
|
@@ -109,28 +115,26 @@ async function checkContainerRunning(appName, developerId, debug = false) {
|
|
|
109
115
|
* @param {number|string} developerId - Developer ID (0 = default infra, > 0 = developer-specific; string allowed)
|
|
110
116
|
* @param {boolean} [debug=false] - Enable debug logging
|
|
111
117
|
*/
|
|
112
|
-
async function stopAndRemoveContainer(appName, developerId, debug = false) {
|
|
118
|
+
async function stopAndRemoveContainer(appName, developerId, debug = false, scopeOpts = null) {
|
|
113
119
|
try {
|
|
114
|
-
const
|
|
115
|
-
const containerName = idNum === 0 ? `aifabrix-${appName}` : `aifabrix-dev${developerId}-${appName}`;
|
|
120
|
+
const containerName = getContainerName(appName, developerId, scopeOpts);
|
|
116
121
|
logger.log(chalk.yellow(`Stopping existing container ${containerName}...`));
|
|
117
122
|
const stopCmd = `docker stop ${containerName}`;
|
|
118
123
|
if (debug) {
|
|
119
124
|
logger.log(chalk.gray(`[DEBUG] Executing: ${stopCmd}`));
|
|
120
125
|
}
|
|
121
|
-
await
|
|
126
|
+
await execWithDockerEnv(stopCmd);
|
|
122
127
|
const rmCmd = `docker rm ${containerName}`;
|
|
123
128
|
if (debug) {
|
|
124
129
|
logger.log(chalk.gray(`[DEBUG] Executing: ${rmCmd}`));
|
|
125
130
|
}
|
|
126
|
-
await
|
|
127
|
-
logger.log(
|
|
131
|
+
await execWithDockerEnv(rmCmd);
|
|
132
|
+
logger.log(formatSuccessLine(`Container ${containerName} stopped and removed`));
|
|
128
133
|
} catch (error) {
|
|
129
134
|
if (debug) {
|
|
130
135
|
logger.log(chalk.gray(`[DEBUG] Stop/remove container error: ${error.message}`));
|
|
131
136
|
}
|
|
132
|
-
const
|
|
133
|
-
const containerName = idNum2 === 0 ? `aifabrix-${appName}` : `aifabrix-dev${developerId}-${appName}`;
|
|
137
|
+
const containerName = getContainerName(appName, developerId, scopeOpts);
|
|
134
138
|
logger.log(chalk.gray(`Container ${containerName} was not running`));
|
|
135
139
|
}
|
|
136
140
|
}
|
|
@@ -144,9 +148,9 @@ async function stopAndRemoveContainer(appName, developerId, debug = false) {
|
|
|
144
148
|
async function logContainerStatus(containerName, debug) {
|
|
145
149
|
if (debug) {
|
|
146
150
|
const statusCmd = `docker ps --filter "name=${containerName}" --format "{{.Status}}"`;
|
|
147
|
-
const { stdout: status } = await
|
|
151
|
+
const { stdout: status } = await execWithDockerEnv(statusCmd);
|
|
148
152
|
const portsCmd = `docker ps --filter "name=${containerName}" --format "{{.Ports}}"`;
|
|
149
|
-
const { stdout: ports } = await
|
|
153
|
+
const { stdout: ports } = await execWithDockerEnv(portsCmd);
|
|
150
154
|
logger.log(chalk.gray(`[DEBUG] Container status: ${status.trim()}`));
|
|
151
155
|
logger.log(chalk.gray(`[DEBUG] Container ports: ${ports.trim()}`));
|
|
152
156
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read per-application environmentScopedResources from application.yaml (or json).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Plan 117 application gate
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const { loadConfigFile } = require('./config-format');
|
|
12
|
+
const { resolveApplicationConfigPath } = require('./app-config-resolver');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param {string|null|undefined} appPath - Builder app directory
|
|
16
|
+
* @returns {boolean} True when application.yaml sets environmentScopedResources: true
|
|
17
|
+
*/
|
|
18
|
+
function readAppEnvironmentScopedFlagForAppPath(appPath) {
|
|
19
|
+
if (!appPath || typeof appPath !== 'string') {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const cfgPath = resolveApplicationConfigPath(appPath);
|
|
24
|
+
const cfg = loadConfigFile(cfgPath);
|
|
25
|
+
return cfg.environmentScopedResources === true;
|
|
26
|
+
} catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
module.exports = { readAppEnvironmentScopedFlagForAppPath };
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derive PREFIX_HOST, PREFIX_PORT, PREFIX_PUBLIC_PORT from each builder app application.yaml.
|
|
3
|
+
* Merged after infra + legacy static fallbacks so workspace manifests override hardcoded defaults.
|
|
4
|
+
*
|
|
5
|
+
* @fileoverview Plan 126 — app connectivity from YAML when present
|
|
6
|
+
* @author AI Fabrix Team
|
|
7
|
+
* @version 1.0.0
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
'use strict';
|
|
11
|
+
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const yaml = require('js-yaml');
|
|
14
|
+
const fsRealSync = require('../internal/fs-real-sync');
|
|
15
|
+
const { localHostPort } = require('./declarative-url-ports');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Maps application.yaml `app.key` to env var prefix (MISO_HOST, DATAPLANE_PORT, …).
|
|
19
|
+
* Generic keys not listed are skipped (no guessed PREFIX).
|
|
20
|
+
*/
|
|
21
|
+
const APP_KEY_TO_ENV_PREFIX = Object.freeze({
|
|
22
|
+
dataplane: 'DATAPLANE',
|
|
23
|
+
keycloak: 'KEYCLOAK',
|
|
24
|
+
'miso-controller': 'MISO',
|
|
25
|
+
'mori-controller': 'MORI',
|
|
26
|
+
openwebui: 'OPENWEBUI',
|
|
27
|
+
flowise: 'FLOWISE'
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @param {object|null|undefined} doc
|
|
32
|
+
* @returns {number|null}
|
|
33
|
+
*/
|
|
34
|
+
function manifestPortOrNull(doc) {
|
|
35
|
+
if (!doc || typeof doc !== 'object') {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
if (typeof doc.port === 'number' && doc.port > 0) {
|
|
39
|
+
return doc.port;
|
|
40
|
+
}
|
|
41
|
+
if (typeof doc.port === 'string' && /^\d+$/.test(doc.port.trim())) {
|
|
42
|
+
return parseInt(doc.port.trim(), 10);
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* In-container listen port (same rules as port-resolver; no require to avoid infra↔resolver cycle).
|
|
49
|
+
* @param {object} doc
|
|
50
|
+
* @param {number} manifestPort
|
|
51
|
+
* @returns {number}
|
|
52
|
+
*/
|
|
53
|
+
function containerListenFromDoc(doc, manifestPort) {
|
|
54
|
+
const cp = doc.build && doc.build.containerPort;
|
|
55
|
+
const useMain =
|
|
56
|
+
cp === undefined ||
|
|
57
|
+
cp === null ||
|
|
58
|
+
(typeof cp === 'string' && cp.trim() === '');
|
|
59
|
+
if (!useMain && typeof cp === 'number' && cp > 0) {
|
|
60
|
+
return cp;
|
|
61
|
+
}
|
|
62
|
+
if (!useMain && typeof cp === 'string' && /^\d+$/.test(cp.trim())) {
|
|
63
|
+
return parseInt(cp.trim(), 10);
|
|
64
|
+
}
|
|
65
|
+
return manifestPort;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Local workstation ports: manifest-only when published ≠ container (e.g. Keycloak); else port+10 rule.
|
|
70
|
+
* @param {object} doc
|
|
71
|
+
* @returns {{ port: number, publicPort: number }}
|
|
72
|
+
*/
|
|
73
|
+
function localWorkstationPortsForDoc(doc) {
|
|
74
|
+
const manifest = manifestPortOrNull(doc);
|
|
75
|
+
if (manifest === null) {
|
|
76
|
+
return { port: 0, publicPort: 0 };
|
|
77
|
+
}
|
|
78
|
+
const container = containerListenFromDoc(doc, manifest);
|
|
79
|
+
if (container === manifest) {
|
|
80
|
+
const p = localHostPort(manifest, 0);
|
|
81
|
+
return { port: p, publicPort: p };
|
|
82
|
+
}
|
|
83
|
+
return { port: manifest, publicPort: manifest };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @param {Record<string, unknown>} overlayDocker
|
|
88
|
+
* @param {Record<string, unknown>} overlayLocal
|
|
89
|
+
* @param {object} doc
|
|
90
|
+
* @param {string} folderName
|
|
91
|
+
*/
|
|
92
|
+
function mergeDocIntoOverlay(overlayDocker, overlayLocal, doc, folderName) {
|
|
93
|
+
const appKey = (doc.app && doc.app.key) || folderName;
|
|
94
|
+
const prefix = APP_KEY_TO_ENV_PREFIX[appKey];
|
|
95
|
+
if (!prefix) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const manifestPort = manifestPortOrNull(doc);
|
|
99
|
+
if (manifestPort === null || manifestPort <= 0) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const containerPort = containerListenFromDoc(doc, manifestPort);
|
|
103
|
+
const localP = localWorkstationPortsForDoc(doc);
|
|
104
|
+
overlayDocker[`${prefix}_HOST`] = appKey;
|
|
105
|
+
overlayDocker[`${prefix}_PORT`] = containerPort;
|
|
106
|
+
overlayDocker[`${prefix}_PUBLIC_PORT`] = manifestPort;
|
|
107
|
+
overlayLocal[`${prefix}_HOST`] = 'localhost';
|
|
108
|
+
overlayLocal[`${prefix}_PORT`] = localP.port;
|
|
109
|
+
overlayLocal[`${prefix}_PUBLIC_PORT`] = localP.publicPort;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* @param {string} projectRoot
|
|
114
|
+
* @returns {Array<{ doc: object, folderName: string }>}
|
|
115
|
+
*/
|
|
116
|
+
function listBuilderApplicationDocs(projectRoot) {
|
|
117
|
+
const builderDir = path.join(projectRoot, 'builder');
|
|
118
|
+
if (!fsRealSync.existsSync(builderDir) || !fsRealSync.statSync(builderDir).isDirectory()) {
|
|
119
|
+
return [];
|
|
120
|
+
}
|
|
121
|
+
const out = [];
|
|
122
|
+
for (const ent of fsRealSync.readdirSync(builderDir, { withFileTypes: true })) {
|
|
123
|
+
if (!ent.isDirectory()) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const cfg = path.join(builderDir, ent.name, 'application.yaml');
|
|
127
|
+
if (!fsRealSync.existsSync(cfg)) {
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
let doc;
|
|
131
|
+
try {
|
|
132
|
+
doc = yaml.load(fsRealSync.readFileSync(cfg, 'utf8'));
|
|
133
|
+
} catch {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (doc && typeof doc === 'object') {
|
|
137
|
+
out.push({ doc, folderName: ent.name });
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return out;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* @param {string|null|undefined} projectRoot
|
|
145
|
+
* @returns {{ docker: Record<string, unknown>, local: Record<string, unknown> }}
|
|
146
|
+
*/
|
|
147
|
+
function buildAppServiceEnvOverlay(projectRoot) {
|
|
148
|
+
const overlayDocker = {};
|
|
149
|
+
const overlayLocal = {};
|
|
150
|
+
if (!projectRoot || !fsRealSync.existsSync(projectRoot)) {
|
|
151
|
+
return { docker: overlayDocker, local: overlayLocal };
|
|
152
|
+
}
|
|
153
|
+
for (const { doc, folderName } of listBuilderApplicationDocs(projectRoot)) {
|
|
154
|
+
mergeDocIntoOverlay(overlayDocker, overlayLocal, doc, folderName);
|
|
155
|
+
}
|
|
156
|
+
return { docker: overlayDocker, local: overlayLocal };
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
module.exports = {
|
|
160
|
+
APP_KEY_TO_ENV_PREFIX,
|
|
161
|
+
buildAppServiceEnvOverlay,
|
|
162
|
+
localWorkstationPortsForDoc,
|
|
163
|
+
manifestPortOrNull
|
|
164
|
+
};
|
package/lib/utils/build-copy.js
CHANGED
|
@@ -28,7 +28,7 @@ const paths = require('./paths');
|
|
|
28
28
|
*
|
|
29
29
|
* @example
|
|
30
30
|
* const devPath = await copyBuilderToDevDirectory('myapp', 1);
|
|
31
|
-
* // Returns: '
|
|
31
|
+
* // Returns: '<configDir>/applications-dev-1' (e.g. ~/.aifabrix/... when config lives there)
|
|
32
32
|
*/
|
|
33
33
|
async function copyBuilderToDevDirectory(appName, developerId) {
|
|
34
34
|
const builderPath = paths.getBuilderPath(appName);
|
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
* @version 2.0.0
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
const { formatSuccessLine } = require('./cli-test-layout-chalk');
|
|
12
13
|
const path = require('path');
|
|
13
14
|
const dockerfileUtils = require('./dockerfile-utils');
|
|
14
15
|
const logger = require('./logger');
|
|
15
|
-
const chalk = require('chalk');
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Determine Dockerfile path (template, custom, or generate)
|
|
@@ -26,23 +26,30 @@ async function determineDockerfile(appName, options, generateDockerfileFn) {
|
|
|
26
26
|
// Use dev directory if provided, otherwise fall back to builder directory
|
|
27
27
|
const searchPath = options.devDir || path.join(process.cwd(), 'builder', appName);
|
|
28
28
|
|
|
29
|
+
// Prefer application.yaml `build.dockerfile` over a stale Dockerfile copied into ~/.aifabrix/.../Dockerfile
|
|
30
|
+
const customDockerfile = dockerfileUtils.checkProjectDockerfile(
|
|
31
|
+
searchPath,
|
|
32
|
+
appName,
|
|
33
|
+
options.buildConfig,
|
|
34
|
+
options.contextPath,
|
|
35
|
+
options.forceTemplate
|
|
36
|
+
);
|
|
37
|
+
if (customDockerfile) {
|
|
38
|
+
logger.log(formatSuccessLine(`Using custom Dockerfile: ${options.buildConfig.dockerfile}`));
|
|
39
|
+
return customDockerfile;
|
|
40
|
+
}
|
|
41
|
+
|
|
29
42
|
const templateDockerfile = dockerfileUtils.checkTemplateDockerfile(searchPath, appName, options.forceTemplate);
|
|
30
43
|
if (templateDockerfile) {
|
|
31
44
|
const relativePath = path.relative(process.cwd(), templateDockerfile);
|
|
32
|
-
logger.log(
|
|
45
|
+
logger.log(formatSuccessLine(`Using existing Dockerfile: ${relativePath}`));
|
|
33
46
|
return templateDockerfile;
|
|
34
47
|
}
|
|
35
48
|
|
|
36
|
-
const customDockerfile = dockerfileUtils.checkProjectDockerfile(searchPath, appName, options.buildConfig, options.contextPath, options.forceTemplate);
|
|
37
|
-
if (customDockerfile) {
|
|
38
|
-
logger.log(chalk.green(`✓ Using custom Dockerfile: ${options.buildConfig.dockerfile}`));
|
|
39
|
-
return customDockerfile;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
49
|
// Generate Dockerfile in dev directory if provided
|
|
43
50
|
const dockerfilePath = await generateDockerfileFn(appName, options.language, options.config, options.buildConfig, options.devDir);
|
|
44
51
|
const relativePath = path.relative(process.cwd(), dockerfilePath);
|
|
45
|
-
logger.log(
|
|
52
|
+
logger.log(formatSuccessLine(`Generated Dockerfile from template: ${relativePath}`));
|
|
46
53
|
return dockerfilePath;
|
|
47
54
|
}
|
|
48
55
|
|
|
@@ -56,6 +63,8 @@ async function determineDockerfile(appName, options, generateDockerfileFn) {
|
|
|
56
63
|
async function loadAndValidateConfig(appName) {
|
|
57
64
|
const { loadVariablesYaml } = require('../build');
|
|
58
65
|
const validator = require('../validation/validator');
|
|
66
|
+
const config = require('../core/config');
|
|
67
|
+
const { resolveBuildImageRepositoryName } = require('./build-resolve-image');
|
|
59
68
|
|
|
60
69
|
const variables = await loadVariablesYaml(appName);
|
|
61
70
|
|
|
@@ -65,17 +74,8 @@ async function loadAndValidateConfig(appName) {
|
|
|
65
74
|
throw new Error(`Configuration validation failed:\n${validation.errors.join('\n')}`);
|
|
66
75
|
}
|
|
67
76
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (typeof variables.image === 'string') {
|
|
71
|
-
imageName = variables.image.split(':')[0];
|
|
72
|
-
} else if (variables.image?.name) {
|
|
73
|
-
imageName = variables.image.name;
|
|
74
|
-
} else if (variables.app?.key) {
|
|
75
|
-
imageName = variables.app.key;
|
|
76
|
-
} else {
|
|
77
|
-
imageName = appName;
|
|
78
|
-
}
|
|
77
|
+
const developerId = await config.getDeveloperId();
|
|
78
|
+
const imageName = await resolveBuildImageRepositoryName(appName, variables, developerId);
|
|
79
79
|
|
|
80
80
|
// Extract build config
|
|
81
81
|
const buildConfig = variables.build || {};
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve Docker image repository for `aifabrix build` from manifest or local Docker.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview When application.yaml omits image, discover repository from `docker images`
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 2.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const chalk = require('chalk');
|
|
12
|
+
const logger = require('./logger');
|
|
13
|
+
const { execWithDockerEnv } = require('./docker-exec');
|
|
14
|
+
const {
|
|
15
|
+
resolveDockerImageRef,
|
|
16
|
+
getRepositoryPathFromConfig
|
|
17
|
+
} = require('./resolve-docker-image-ref');
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* True when build should try local Docker to infer the repository path.
|
|
21
|
+
* @param {Object} variables - Loaded application manifest
|
|
22
|
+
* @returns {boolean}
|
|
23
|
+
*/
|
|
24
|
+
function wantsLocalDockerImageDiscovery(variables) {
|
|
25
|
+
const img = variables && variables.image;
|
|
26
|
+
if (img === undefined || img === null) {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
if (typeof img === 'string') {
|
|
30
|
+
return !img.trim();
|
|
31
|
+
}
|
|
32
|
+
if (typeof img !== 'object') {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
return Object.keys(img).length === 0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @param {string} repoPath
|
|
40
|
+
* @returns {string}
|
|
41
|
+
*/
|
|
42
|
+
function repositoryTail(repoPath) {
|
|
43
|
+
if (!repoPath || typeof repoPath !== 'string') {
|
|
44
|
+
return '';
|
|
45
|
+
}
|
|
46
|
+
const parts = repoPath.split('/');
|
|
47
|
+
return parts[parts.length - 1] || repoPath;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Strip dev-scoped or -extra suffix from a Docker repository path.
|
|
52
|
+
* @param {string} repo
|
|
53
|
+
* @returns {string}
|
|
54
|
+
*/
|
|
55
|
+
function baseRepositoryFromDevScoped(repo) {
|
|
56
|
+
const devMatch = repo.match(/^(.*)-dev\d+$/);
|
|
57
|
+
if (devMatch) {
|
|
58
|
+
return devMatch[1];
|
|
59
|
+
}
|
|
60
|
+
if (repo.endsWith('-extra')) {
|
|
61
|
+
return repo.slice(0, -'-extra'.length);
|
|
62
|
+
}
|
|
63
|
+
return repo;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @param {string} appName
|
|
68
|
+
* @param {string} repository - Docker repository (no tag)
|
|
69
|
+
* @returns {boolean}
|
|
70
|
+
*/
|
|
71
|
+
function repoMatchesAppName(appName, repository) {
|
|
72
|
+
const base = baseRepositoryFromDevScoped(repository);
|
|
73
|
+
if (repository === appName || base === appName) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
if (repositoryTail(base) === appName) {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
if (repositoryTail(repository) === appName) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @param {string} appName
|
|
87
|
+
* @param {string[]} lines - docker images output lines repository:tag
|
|
88
|
+
* @param {string|number} developerId
|
|
89
|
+
* @returns {string|null}
|
|
90
|
+
*/
|
|
91
|
+
function pickBaseFromDockerLines(appName, lines, developerId) {
|
|
92
|
+
const candidates = [];
|
|
93
|
+
for (const line of lines) {
|
|
94
|
+
if (!line || line.includes('<none>')) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
const colon = line.lastIndexOf(':');
|
|
98
|
+
const repository = colon > 0 ? line.slice(0, colon) : line;
|
|
99
|
+
if (!repository) {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if (!repoMatchesAppName(appName, repository)) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
candidates.push({
|
|
106
|
+
repository,
|
|
107
|
+
base: baseRepositoryFromDevScoped(repository)
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
if (!candidates.length) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
const idNum = typeof developerId === 'string' ? parseInt(developerId, 10) : Number(developerId);
|
|
114
|
+
if (Number.isFinite(idNum) && idNum > 0) {
|
|
115
|
+
const suffix = `-dev${idNum}`;
|
|
116
|
+
const preferred = candidates.find((c) => c.repository.endsWith(suffix));
|
|
117
|
+
if (preferred) {
|
|
118
|
+
return preferred.base;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return candidates[0].base;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Infer repository path from local Docker images when manifest has no image block.
|
|
126
|
+
* @param {string} appName
|
|
127
|
+
* @param {string|number} developerId
|
|
128
|
+
* @returns {Promise<string|null>}
|
|
129
|
+
*/
|
|
130
|
+
async function discoverLocalBaseImageRepository(appName, developerId) {
|
|
131
|
+
try {
|
|
132
|
+
const { stdout } = await execWithDockerEnv(
|
|
133
|
+
'docker images --format "{{.Repository}}:{{.Tag}}"'
|
|
134
|
+
);
|
|
135
|
+
const lines = stdout.trim().split('\n').filter(Boolean);
|
|
136
|
+
return pickBaseFromDockerLines(appName, lines, developerId);
|
|
137
|
+
} catch {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Repository path (may include registry prefix) used for `docker build -t`.
|
|
144
|
+
* @param {string} appName
|
|
145
|
+
* @param {Object} variables - application manifest
|
|
146
|
+
* @param {string|number} developerId
|
|
147
|
+
* @returns {Promise<string>}
|
|
148
|
+
*/
|
|
149
|
+
async function resolveBuildImageRepositoryName(appName, variables, developerId) {
|
|
150
|
+
if (!wantsLocalDockerImageDiscovery(variables)) {
|
|
151
|
+
return resolveDockerImageRef(appName, variables, {}).imageName;
|
|
152
|
+
}
|
|
153
|
+
const discovered = await discoverLocalBaseImageRepository(appName, developerId);
|
|
154
|
+
if (discovered) {
|
|
155
|
+
logger.log(chalk.blue(`Using image repository from local Docker: ${discovered}`));
|
|
156
|
+
return discovered;
|
|
157
|
+
}
|
|
158
|
+
return getRepositoryPathFromConfig(variables, appName);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
module.exports = {
|
|
162
|
+
resolveBuildImageRepositoryName,
|
|
163
|
+
wantsLocalDockerImageDiscovery,
|
|
164
|
+
pickBaseFromDockerLines
|
|
165
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Re-export of CLI layout chalk helpers (same API as cli-test-layout-chalk).
|
|
3
|
+
* Prefer this path for non-test modules; see `.cursor/plans/layout.md` contributor appendix.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
module.exports = require('./cli-test-layout-chalk');
|