diff --git a/docker-compose.yml b/docker-compose.yml index 2bbf9fde..d1875e87 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -266,6 +266,11 @@ services: AUTH_PASSWORD: "${UNIDESK_AUTH_PASSWORD}" SESSION_SECRET: "${UNIDESK_SESSION_SECRET}" SESSION_TTL_SECONDS: "${UNIDESK_SESSION_TTL_SECONDS}" + UNIDESK_DEPLOY_REF: "${UNIDESK_FRONTEND_DEPLOY_REF:-deploy.json#environments.prod.services.frontend}" + UNIDESK_DEPLOY_SERVICE_ID: "${UNIDESK_FRONTEND_DEPLOY_SERVICE_ID:-frontend}" + UNIDESK_DEPLOY_REPO: "${UNIDESK_FRONTEND_DEPLOY_REPO:-}" + UNIDESK_DEPLOY_COMMIT: "${UNIDESK_FRONTEND_DEPLOY_COMMIT:-}" + UNIDESK_DEPLOY_REQUESTED_COMMIT: "${UNIDESK_FRONTEND_DEPLOY_REQUESTED_COMMIT:-}" LOG_FILE: "/var/log/unidesk/${UNIDESK_LOG_DAY}/${UNIDESK_LOG_PREFIX}_frontend.jsonl" UNIDESK_LOG_RETENTION_BYTES: "${UNIDESK_LOG_RETENTION_BYTES:-1GiB}" volumes: diff --git a/docs/reference/artifact-registry.md b/docs/reference/artifact-registry.md index 88d8f6b1..be4da3c4 100644 --- a/docs/reference/artifact-registry.md +++ b/docs/reference/artifact-registry.md @@ -59,6 +59,8 @@ bun scripts/cli.ts artifact-registry status bun scripts/cli.ts artifact-registry health bun scripts/cli.ts artifact-registry deploy-backend-core --commit bun scripts/cli.ts artifact-registry deploy-service --service baidu-netdisk --commit +bun scripts/cli.ts artifact-registry deploy-service --service frontend --env prod --commit +bun scripts/cli.ts artifact-registry deploy-service --service frontend --env dev --commit bun scripts/cli.ts artifact-registry deploy-service --service decision-center --commit ``` @@ -68,14 +70,16 @@ bun scripts/cli.ts artifact-registry deploy-service --service decision-center -- `deploy-backend-core` 是 production backend-core 的 CD 入口。它必须先通过 CNCF Distribution HTTP API 确认 D601 registry 中已经存在 `unidesk/backend-core:`,随后通过 provider-gateway Host SSH 流式执行 `docker save | gzip`,在 master server 侧 `docker load`、retag、Compose `--no-build` recreate 和 live commit 验证;如果镜像不存在,应失败并要求先运行 CI artifact publication。 -`deploy-service` 是标准化后的最小通用 artifact consumer。它目前只支持 `backend-core`、`baidu-netdisk` 和 `decision-center`,并且必须先通过 D601 registry 的 commit-pinned manifest 校验,再执行拉取、导入/retag、部署和健康验证: +`deploy-service` 是标准化后的最小通用 artifact consumer。它目前只支持 `backend-core`、`baidu-netdisk`、prod/dev `frontend` 和 `decision-center`,并且必须先通过 D601 registry 的 commit-pinned manifest 校验,再执行拉取、导入/retag、部署和健康验证: ```bash bun scripts/cli.ts artifact-registry deploy-service --service baidu-netdisk --commit --run-now +bun scripts/cli.ts artifact-registry deploy-service --service frontend --env prod --commit --run-now +bun scripts/cli.ts artifact-registry deploy-service --service frontend --env dev --commit --run-now bun scripts/cli.ts artifact-registry deploy-service --service decision-center --commit --run-now ``` -dry-run 输出会暴露 registry probe URL、required labels、目标 image、部署形态和回滚信息。`baidu-netdisk` 的 Compose 路径会通过 provider-gateway Host SSH 把 `unidesk/baidu-netdisk:` 流式拉到 master server,retag 为 `baidu-netdisk` 和 `baidu-netdisk:`,写入 `UNIDESK_BAIDU_NETDISK_DEPLOY_*`,只 recreate `baidu-netdisk` service,并验证容器 image label 与 `/health.deploy.commit`。`decision-center` 的 prod 路径会在 D601 上验证 `unidesk-decision-center:` 是否存在、导入 native k3s containerd、更新 `decision-center` Deployment image/env/annotations,并通过 Kubernetes API service proxy 验证 `/health` 中的 `deploy.commit`。回滚信息通过同一 artifact consumer 的 `rollback` 字段暴露,提示操作者重新对一个旧 commit 运行相同命令,而不是切回 legacy maintenance-channel 构建。 +dry-run 输出会暴露 registry probe URL、required labels、目标 image、部署形态和回滚信息。`baidu-netdisk` 的 Compose 路径会通过 provider-gateway Host SSH 把 `unidesk/baidu-netdisk:` 流式拉到 master server,retag 为 `baidu-netdisk` 和 `baidu-netdisk:`,写入 `UNIDESK_BAIDU_NETDISK_DEPLOY_*`,只 recreate `baidu-netdisk` service,并验证容器 image label 与 `/health.deploy.commit`。`frontend --env prod` 使用同一 Compose artifact consumer,流式拉取 `unidesk/frontend:`,retag 为 `unidesk-frontend` 和 `unidesk-frontend:`,写入 `UNIDESK_FRONTEND_DEPLOY_*`,只 recreate `frontend` service,并验证 image label 与 `/health.deploy.commit`。`frontend --env dev` 和 `decision-center` 的 k3s 路径会在 D601 上验证 commit image、导入 native k3s containerd、更新 Deployment image/env/annotations,并通过 Kubernetes API service proxy 验证 `/health` 中的 `deploy.commit`;dev frontend 还会在 rollout 前把主 server `config.json.auth` 同步到 `unidesk-dev` Secret/ConfigMap。回滚信息通过同一 artifact consumer 的 `rollback` 字段暴露,提示操作者重新对一个旧 commit 运行相同命令,而不是切回 legacy maintenance-channel 构建。 `status` 和 `health` 通过: @@ -115,11 +119,11 @@ docker compose -p unidesk-artifact-registry -f /home/ubuntu/.unidesk/artifact-re 2. D601 CI 从 pushed Git checkout 构建 `unidesk/:`。 3. CI 将镜像 push 到 `127.0.0.1:5000/unidesk/:`,并记录完整 artifact summary,包括 service id、source repo、source commit、Dockerfile、image ref、tag、digest 和 digest ref。 4. CD 在运行目标上确认目标 commit/tag/digest 存在。 -5. Compose runtime 通过 provider-gateway Host SSH 从 D601 registry 流式读取 commit-pinned 镜像 tar,不开放 registry 端口,也不使用第三方镜像托管。 -6. Compose runtime retag 为 Compose 使用的镜像名,并执行 `docker compose up -d --no-build --no-deps --force-recreate `。 +5. Compose runtime 通过 provider-gateway Host SSH 从 D601 registry 流式读取 commit-pinned 镜像 tar;D601 k3s runtime 通过 host-local registry/containerd import 消费同一 commit-pinned 镜像。不开放 registry 端口,也不使用第三方镜像托管。 +6. Compose runtime retag 为 Compose 使用的镜像名,并执行 `docker compose up -d --no-build --no-deps --force-recreate `;k3s runtime 设置 Deployment image/env/annotations 并等待 rollout。 7. 部署后通过 image label、runtime env、health payload 验证 live commit。 -Baidu Netdisk is the first main-server direct user-service sample in this flow. Its dev validation command and prod CD command both consume `127.0.0.1:5000/unidesk/baidu-netdisk:` and must not build source on the master server. Decision Center follows the same artifact-consumer pattern, except the runtime target is native k3s on D601 instead of the master-server Compose stack. The consumer must check the registry manifest, pull the commit-pinned image, import it into `/run/k3s/containerd/containerd.sock`, set the Deployment image to the commit tag, stamp `UNIDESK_DEPLOY_*` env/annotations, and reject an old healthy revision if the live commit does not match. +Baidu Netdisk is the first main-server direct user-service sample in this flow. Its dev validation command and prod CD command both consume `127.0.0.1:5000/unidesk/baidu-netdisk:` and must not build source on the master server. Frontend is the standard UniDesk UI artifact sample: CI publishes `127.0.0.1:5000/unidesk/frontend:`, production CD consumes that artifact into the master-server Compose `frontend` service, and dev CD consumes the same artifact into D601 native k3s `frontend-dev`. Neither path may use `server rebuild frontend`, dirty source, mutable `latest`, or target-side frontend source builds as release truth. Decision Center follows the same artifact-consumer pattern, except the runtime target is native k3s on D601 instead of the master-server Compose stack. The consumer must check the registry manifest, pull the commit-pinned image, import it into `/run/k3s/containerd/containerd.sock`, set the Deployment image to the commit tag, stamp `UNIDESK_DEPLOY_*` env/annotations, and reject an old healthy revision if the live commit does not match. 这个 CD 路径必须满足: diff --git a/docs/reference/ci.md b/docs/reference/ci.md index fa24ab6d..0338bc87 100644 --- a/docs/reference/ci.md +++ b/docs/reference/ci.md @@ -96,7 +96,7 @@ The artifact registry contract and CD consumption path are defined in `docs/refe ## User-Service Artifact Publication -User-service image creation uses the same CI producer boundary as backend-core, but the service identity and Dockerfile come from the registered `config.json.microservices[]` entry. The reviewed sample services are `baidu-netdisk` and `decision-center`. +User-service image creation uses the same CI producer boundary as backend-core. Most service identities and Dockerfiles come from the registered `config.json.microservices[]` entry; `frontend` is the reviewed UniDesk UI artifact sample and uses `src/components/frontend/Dockerfile`. The reviewed sample services are `baidu-netdisk`, `decision-center` and `frontend`. The CI user-service artifact task must follow these rules: @@ -123,6 +123,14 @@ bun scripts/cli.ts ci publish-user-service --service decision-center --commit `. +Publish a frontend artifact: + +```bash +bun scripts/cli.ts ci publish-user-service --service frontend --commit --wait-ms 1200000 +``` + +This command creates the `unidesk-user-service-artifact-publish` Tekton PipelineRun and pushes `127.0.0.1:5000/unidesk/frontend:`. The next step is CD consumption, not a source rebuild: `deploy apply --env dev --service frontend` imports the artifact into D601 native k3s `frontend-dev`, and `deploy apply --env prod --service frontend` recreates the master-server Compose `frontend` service with `--no-build` and live `/health.deploy.commit` verification. + ## Dev Namespace E2E `ci run-dev-e2e` is the manual dev desired-state smoke flow. The single authoritative reference for its Git-controlled runner script, short launcher, result directory and no-CD boundary is `docs/reference/dev-ci-runner.md`. diff --git a/docs/reference/cli.md b/docs/reference/cli.md index 14c9103c..80fc9140 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -25,7 +25,7 @@ CLI 可以从 `master` 快速演进,但必须兼容 `deploy.json` 固定的 CI - `microservice list/status/health/diagnostics/tunnel-self-test/proxy` 通过 backend-core 内网 API 管理挂载在计算节点 Docker 或 k3s 控制面中的用户服务(底层命令名仍为 microservice);`health`、`diagnostics`、`tunnel-self-test` 和 `proxy` 会走真实 backend-core -> provider-gateway 或 k3sctl-adapter -> 节点服务链路,`proxy` 支持受控 JSON 请求体并对超大响应 body 默认输出有界预览,规则见 `docs/reference/microservices.md`。 - `decision upload/list/show/health` 通过 backend-core 用户服务代理访问 D601 k3s Decision Center,用于上传会议记录/决议 Markdown、列出权威记录、查看详情和健康检查;`decision requirement list/upsert` 在同一 records 模型上管理 `goal|decision|blocker|debt|experiment` 需求记录。它们不得直连 D601 Service、NodePort 或 provider-gateway 业务 HTTP。 - `decision diary import ` 将带 `# YYYY年M月D日`、`# YYYY-MM-DD` 或 `# YYYY/M/D` 标题的工作日志拆成每天一篇 Markdown 日记,按 `YYYY-MM/YYYY-MM-DD.md` 虚拟路径写入 Decision Center PostgreSQL;`decision diary list/months/show` 分别用于按月/日期查询、列出月份和查看单日正文;`decision diary edit|upsert --body-file [--title text] [--source-file path] [--tag tag]` 通过 `PUT /api/diary/entries/:idOrDate` 创建当天或历史条目并编辑既有条目。 -- `deploy check/plan/apply` 默认从根目录 `deploy.json` 读取服务 repo 与 commit 期望状态,join `config.json` 和现有 manifest 后使用 target-side build 单一路径校验或更新已支持目标;`deploy plan --env dev|prod` 只从 `origin/master:deploy.json#environments.` 读取 manifest 并输出 dry-run 环境计划,不使用本地 dirty worktree;当前 `deploy apply --env dev` 支持 D601 `backend-core`/`frontend` persistent dev rollout,以及 `baidu-netdisk` artifact-consumer validation,dev desired-state smoke 使用 `ci run-dev-e2e`;规则见 `docs/reference/deploy.md`、`docs/reference/dev-environment.md` 和 `docs/reference/dev-ci-runner.md`。 +- `deploy check/plan/apply` 默认从根目录 `deploy.json` 读取服务 repo 与 commit 期望状态,join `config.json` 和现有 manifest 后使用 target-side build 单一路径校验或更新已支持目标;`deploy plan --env dev|prod` 只从 `origin/master:deploy.json#environments.` 读取 manifest 并输出 dry-run 环境计划,不使用本地 dirty worktree;当前 `deploy apply --env dev` 支持 D601 `backend-core` target-side rollout,以及 `frontend`/`baidu-netdisk` artifact consumers,dev desired-state smoke 使用 `ci run-dev-e2e`;规则见 `docs/reference/deploy.md`、`docs/reference/dev-environment.md` 和 `docs/reference/dev-ci-runner.md`。 - `dev-env validate [--manifest path] [--kubectl-dry-run]` 离线校验 D601 `unidesk-dev` namespace、dev PostgreSQL 底座和 dev workload manifest。默认检查 `src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-foundation.k8s.yaml`;也可显式校验 `src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-core.k8s.yaml` 或 `src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-code-queue.k8s.yaml`。所有 namespaced 对象必须只落到 `unidesk-dev`,foundation manifest 必须包含 `postgres-dev` StatefulSet/Service、dev secret/config、迁移 Job 和 DB URL guard,core manifest 必须包含 `backend-core-dev`/`frontend-dev` Deployment/Service,Code Queue dev manifest 必须包含 `code-queue-scheduler-dev`、`code-queue-read-dev`、`code-queue-write-dev` 和 dev provider egress proxy。加 `--kubectl-dry-run` 时额外执行 `kubectl apply --dry-run=client --validate=false -f `,仍不 apply 资源。 - `dev-env prewarm-images [--image image] [--provider-id D601] [--no-pull] [--proxy-url URL] [--pull-timeout-ms N] [--dry-run]` 创建异步 job,通过 UniDesk SSH 维护桥在 D601 上把开发底座依赖镜像从 Docker 缓存导入原生 k3s containerd。默认镜像是 `postgres:16-alpine` 和 `rancher/mirrored-library-busybox:1.36.1`,用于避免 `postgres-dev` 与 local-path helper pod 卡在外部 registry 拉取。该命令固定验证 `/etc/rancher/k3s/k3s.yaml` 指向的 native k3s 上下文,并输出 `dev_env_containerd_image_ready=...` 作为成功判据;它不 apply manifest、不修改生产 `unidesk` namespace。 - `artifact-registry plan|render|status|health|install|deploy-backend-core|deploy-service` 管理 D601 host-managed CNCF Distribution registry 的声明、安装、只读检查和 pull-only artifact CD。该 registry 固定为 D601 loopback `127.0.0.1:5000`,由 systemd + Docker Compose 管理,位于 native k3s 故障域外;`deploy-backend-core` 和 `deploy-service` 只拉取 CI 已发布的 commit-pinned 镜像、retag/recreate 或导入 native k3s,并做 live commit 验证,不构建 runtime source。长期规则见 `docs/reference/artifact-registry.md`。 @@ -47,9 +47,9 @@ CLI 可以从 `master` 快速演进,但必须兼容 `deploy.json` 固定的 CI 长时操作采用 Fire-and-Forget 模式:CLI 创建 `.state/jobs/{jobId}.json`,后台进程执行真实命令,并将 stdout、stderr 分别写入 `.state/jobs/{jobId}.stdout.log` 与 `.state/jobs/{jobId}.stderr.log`。调用者通过 `bun scripts/cli.ts job status ` 查询进度和尾部输出。 -`server rebuild` 与 `server start`、`server stop` 一样必须通过返回的 job id 确认结果;不要把连续 `server rebuild` 命令理解成“前一个重建已完成”,因为两个命令只是在快速创建异步 job。重建 frontend 的标准流程是运行 `bun scripts/cli.ts server rebuild frontend`,随后轮询 `bun scripts/cli.ts job status ` 到 `succeeded`,再用 `server status` 或 `e2e run` 验证公网 frontend;重建 dev 入口薄代理使用 `bun scripts/cli.ts server rebuild dev-frontend-proxy`,随后验证 `server status` 的 `urls.devFrontend` 和 `http://127.0.0.1:18083/health`;重建 Todo Note 后端使用 `bun scripts/cli.ts server rebuild todo-note`,随后用 `microservice health todo-note` 和 `microservice proxy todo-note /api/instances` 验证;重建 Code Queue Manager 使用 `bun scripts/cli.ts server rebuild code-queue-mgr`,随后用 `microservice health code-queue-mgr`、`microservice health code-queue` 和 `codex submit --dry-run` 验证主 server 控制面路径;重建 Project Manager 后端使用 `bun scripts/cli.ts server rebuild project-manager`,随后用 `microservice health project-manager` 和 `microservice proxy project-manager /api/projects` 验证;重建 Baidu Netdisk 后端使用 `bun scripts/cli.ts server rebuild baidu-netdisk`,随后用 `microservice health baidu-netdisk` 和 `microservice proxy baidu-netdisk /api/transfers` 验证,但该命令只保留为维护/非标准路径;重建 OA Event Flow 后端使用 `bun scripts/cli.ts server rebuild oa-event-flow`,随后用 `microservice health oa-event-flow` 和 `microservice proxy oa-event-flow /api/diagnostics` 验证。D601 Code Queue 执行面和 Decision Center 后端由 D601 k3s/k8s 控制面代管;persistent dev backend-core/frontend 只通过 `deploy apply --env dev --service ...`,当前 Code Queue/Decision Center 仍不得通过维护通道直连 D601 做部署。不得把 `docker rm` 手工兜底当成正式交付步骤。 +`server rebuild` 与 `server start`、`server stop` 一样必须通过返回的 job id 确认结果;不要把连续 `server rebuild` 命令理解成“前一个重建已完成”,因为两个命令只是在快速创建异步 job。重建 frontend 只保留为维护/非标准路径;标准 frontend 发布必须先运行 `ci publish-user-service --service frontend --commit `,再运行 `deploy apply --env dev --service frontend` 和 `deploy apply --env prod --service frontend`,并验证 `/health.deploy.commit`。重建 dev 入口薄代理使用 `bun scripts/cli.ts server rebuild dev-frontend-proxy`,随后验证 `server status` 的 `urls.devFrontend` 和 `http://127.0.0.1:18083/health`;重建 Todo Note 后端使用 `bun scripts/cli.ts server rebuild todo-note`,随后用 `microservice health todo-note` 和 `microservice proxy todo-note /api/instances` 验证;重建 Code Queue Manager 使用 `bun scripts/cli.ts server rebuild code-queue-mgr`,随后用 `microservice health code-queue-mgr`、`microservice health code-queue` 和 `codex submit --dry-run` 验证主 server 控制面路径;重建 Project Manager 后端使用 `bun scripts/cli.ts server rebuild project-manager`,随后用 `microservice health project-manager` 和 `microservice proxy project-manager /api/projects` 验证;重建 Baidu Netdisk 后端使用 `bun scripts/cli.ts server rebuild baidu-netdisk`,随后用 `microservice health baidu-netdisk` 和 `microservice proxy baidu-netdisk /api/transfers` 验证,但该命令只保留为维护/非标准路径;重建 OA Event Flow 后端使用 `bun scripts/cli.ts server rebuild oa-event-flow`,随后用 `microservice health oa-event-flow` 和 `microservice proxy oa-event-flow /api/diagnostics` 验证。D601 Code Queue 执行面和 Decision Center 后端由 D601 k3s/k8s 控制面代管;persistent dev backend-core 走 target-side dev rollout,persistent dev frontend 走 artifact consumer,当前 Code Queue/Decision Center 仍不得通过维护通道直连 D601 做部署。不得把 `docker rm` 手工兜底当成正式交付步骤。 -新部署入口优先使用 `deploy apply`。`deploy apply --env dev --service backend-core|frontend` 已收敛到 D601 target-side dev 路径;`deploy apply --env dev|prod --service baidu-netdisk` 是主 server 直管微服务的 artifact-consumer 样板;旧的 `codex deploy` 已禁用;后续 Code Queue、Decision Center 等 D601 服务部署应另行收敛到同一类受控 CD 路径,部署后用 live commit 校验证明不是旧服务。 +新部署入口优先使用 `deploy apply`。`deploy apply --env dev --service backend-core` 是 D601 target-side dev 路径;`deploy apply --env dev|prod --service frontend` 和 `deploy apply --env dev|prod --service baidu-netdisk` 是 artifact-consumer 样板;旧的 `codex deploy` 已禁用;后续 Code Queue、Decision Center 等 D601 服务部署应另行收敛到同一类受控 CD 路径,部署后用 live commit 校验证明不是旧服务。 ## Output Contract diff --git a/docs/reference/codex-deploy.md b/docs/reference/codex-deploy.md index 2aa531d2..89966477 100644 --- a/docs/reference/codex-deploy.md +++ b/docs/reference/codex-deploy.md @@ -2,7 +2,7 @@ `bun scripts/cli.ts codex deploy ` 是旧兼容入口,现已禁用。原因是它会通过 backend-core `host.ssh` 维护通道直连 D601 部署 Code Queue,把维护入口扩张成第二套部署系统。 -Code Queue 后续正式部署必须走一条受控 target-side CD 路径:读取 `origin/master:deploy.json#environments.dev` 或生产 desired-state,在目标节点执行 source fetch、build、k3s image import、rollout、stamp 和 live commit 验证。当前阶段不提供 Code Queue CD;persistent dev apply 只支持 backend-core/frontend,规则见 `docs/reference/dev-environment.md`,Code Queue smoke 仍通过 `ci run-dev-e2e`,规则见 `docs/reference/dev-ci-runner.md`。 +Code Queue 后续正式部署必须走一条受控 target-side CD 路径:读取 `origin/master:deploy.json#environments.dev` 或生产 desired-state,在目标节点执行 source fetch、build、k3s image import、rollout、stamp 和 live commit 验证。当前阶段不提供 Code Queue CD;persistent dev apply 支持 backend-core target-side rollout 和 frontend artifact consumer,规则见 `docs/reference/dev-environment.md`,Code Queue smoke 仍通过 `ci run-dev-e2e`,规则见 `docs/reference/dev-ci-runner.md`。 ## Command diff --git a/docs/reference/deploy.md b/docs/reference/deploy.md index 8ddfa9c3..46f794c9 100644 --- a/docs/reference/deploy.md +++ b/docs/reference/deploy.md @@ -40,7 +40,7 @@ The root `deploy.json` is the single desired-state source for both prod and dev. The optional non-service execution declaration under `environments.dev` is intentionally not specified here. The only currently allowed declaration is `ci`, and its authoritative `repo`, `scriptPath`, `timeoutMs`, short launcher, host fetch boundary and no-CD rules are defined only in `docs/reference/dev-ci-runner.md`. -Environment mode never reads the local dirty working tree manifest. `deploy check --env ...`, `deploy plan --env ...` and `deploy apply --env ...` fetch `origin/master`, read `origin/master:deploy.json`, select `environments.`, and report the manifest commit/blob, service commit IDs, target namespace, database fingerprint and Provider identity. `deploy apply --env dev` is currently enabled for persistent D601 dev `backend-core`/`frontend` and for `baidu-netdisk` artifact-consumer validation; all other D601 services remain rejected before runtime mutation. `deploy apply --env prod` exposes only reviewed D601 registry artifact consumers (`backend-core`, `baidu-netdisk`, `decision-center`). The default user-service delivery policy, including CI build, registry publication, dev validation, production CD and manual acceptance, is documented in `docs/reference/user-service-delivery.md`. +Environment mode never reads the local dirty working tree manifest. `deploy check --env ...`, `deploy plan --env ...` and `deploy apply --env ...` fetch `origin/master`, read `origin/master:deploy.json`, select `environments.`, and report the manifest commit/blob, service commit IDs, target namespace, database fingerprint and Provider identity. `deploy apply --env dev` is currently enabled for persistent D601 dev `backend-core` target-side rollout and for `frontend`/`baidu-netdisk` artifact-consumer validation; all other D601 services remain rejected before runtime mutation. `deploy apply --env prod` exposes only reviewed D601 registry artifact consumers (`backend-core`, `frontend`, `baidu-netdisk`, `decision-center`). The default user-service delivery policy, including CI build, registry publication, dev validation, production CD and manual acceptance, is documented in `docs/reference/user-service-delivery.md`. The current implementation has not yet enabled separate stable and integration dev lanes. Future lane names such as `dev-v1` and `dev-master`, or an equivalent nested schema, must be added as explicit `deploy.json` and CLI semantics before use. A deploy command must print the manifest ref it used and must not infer `release/v1` from a local branch, a dirty file, or an undocumented environment alias. @@ -83,7 +83,7 @@ Phase 3 introduces the dev backend/frontend manifest at `src/components/microser `backend-core-dev` must use `unidesk-dev-runtime-config` and `unidesk-dev-runtime-secrets`, connect to `postgres-dev.../unidesk_dev`, expose HTTP on 8080 and provider ingress on 8081, and write logs under `/var/log/unidesk-dev`. `frontend-dev` must set `CORE_INTERNAL_URL=http://backend-core-dev.unidesk-dev.svc.cluster.local:8080` and must not proxy to production backend-core. -The manifest keeps placeholder image tags and deploy commit values in source control. The controlled `deploy apply --env dev --service backend-core|frontend` path fetches `origin/master:deploy.json`, materializes the requested source commit on D601, narrows the dev core control manifest to the selected Service/Deployment pair, replaces placeholders with the requested commit and dev image tag, builds on D601, imports the image into native k3s containerd, applies only the `unidesk-dev` objects and stamps the Deployment. Client dry-run and static validation remain useful checks before controlled apply: +The manifest keeps placeholder image tags and deploy commit values in source control. The controlled `deploy apply --env dev --service backend-core` path fetches `origin/master:deploy.json`, materializes the requested source commit on D601, narrows the dev core control manifest to the selected Service/Deployment pair, replaces placeholders with the requested commit and dev image tag, builds on D601, imports the image into native k3s containerd, applies only the `unidesk-dev` objects and stamps the Deployment. `deploy apply --env dev --service frontend` uses the same selected dev manifest objects but consumes the existing D601 registry artifact `127.0.0.1:5000/unidesk/frontend:` instead of building frontend source on the target. Client dry-run and static validation remain useful checks before controlled apply: - `bun scripts/cli.ts dev-env validate --manifest src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-core.k8s.yaml` - `KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl apply --dry-run=client --validate=false -f src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-core.k8s.yaml` @@ -106,7 +106,7 @@ Maintenance-channel direct D601 apply must not deploy dev Code Queue; the CLI re `bun scripts/cli.ts deploy plan --env dev [--service ]` reads `origin/master:deploy.json#environments.dev` and prints a dry-run environment plan without checking or mutating live runtime resources. `deploy check --env dev` uses the same dry-run environment plan. `--env prod` is available for parity as a dry-run planning path; it reads `origin/master:deploy.json#environments.prod` and must not use a dirty local `deploy.json`. -`bun scripts/cli.ts deploy apply [--file deploy.json | --env dev|prod] [--service ] [--commit ] [--dry-run] [--force]` starts an asynchronous job only for supported targets. Use `bun scripts/cli.ts job status --tail-bytes 30000` to observe progress. `--dry-run` resolves the same plan but does not build or replace runtime objects. `--force` rebuilds even when the live commit matches. Environment apply is not the dev e2e trigger; use `bun scripts/cli.ts ci run-dev-e2e` for the Git-controlled temporary namespace smoke flow. `--env dev` apply is enabled for persistent D601 `backend-core`/`frontend` target-side rollout and for `baidu-netdisk` artifact-consumer validation. `--env prod` apply exposes the D601 registry artifact consumer for `backend-core`, `baidu-netdisk`, and `decision-center`. Unsupported prod services return a structured `unsupported` payload instead of silently falling back to a maintenance-channel source build. +`bun scripts/cli.ts deploy apply [--file deploy.json | --env dev|prod] [--service ] [--commit ] [--dry-run] [--force]` starts an asynchronous job only for supported targets. Use `bun scripts/cli.ts job status --tail-bytes 30000` to observe progress. `--dry-run` resolves the same plan but does not build or replace runtime objects. `--force` rebuilds even when the live commit matches. Environment apply is not the dev e2e trigger; use `bun scripts/cli.ts ci run-dev-e2e` for the Git-controlled temporary namespace smoke flow. `--env dev` apply is enabled for persistent D601 `backend-core` target-side rollout and for `frontend`/`baidu-netdisk` artifact consumers. `--env prod` apply exposes the D601 registry artifact consumer for `backend-core`, `frontend`, `baidu-netdisk`, and `decision-center`. Unsupported prod services return a structured `unsupported` payload instead of silently falling back to a maintenance-channel source build. All deploy commands output JSON. Long operations must use `.state/jobs/` and bounded log tails; no deploy path may succeed with missing progress output. @@ -134,6 +134,7 @@ The exception is narrow: - CD must not run Rust compilation, Docker build, Compose build or `server rebuild backend-core`. - The pushed Git commit remains the version source of truth. The image registry is a content cache and transfer boundary, not a replacement for `deploy.json` or Git. - `baidu-netdisk` is the first main-server direct user-service sample for the same split: CI publishes `127.0.0.1:5000/unidesk/baidu-netdisk:` from `src/components/microservices/baidu-netdisk/Dockerfile`; dev validation and prod CD both pull that artifact, retag `baidu-netdisk`, recreate only `baidu-netdisk` with `--no-build --no-deps --force-recreate`, and verify image labels plus `/health.deploy.commit`. +- `frontend` is the UniDesk UI artifact sample: CI publishes `127.0.0.1:5000/unidesk/frontend:` from `src/components/frontend/Dockerfile`; dev CD imports that artifact into native k3s `frontend-dev`, prod CD retags it as `unidesk-frontend` for the master-server Compose service, and both paths verify image labels plus `/health.deploy.commit`. - This exception must not be generalized to other services unless their resource profile and runtime boundary are documented with the same CI-producer/CD-consumer split. The registry contract is defined in `docs/reference/artifact-registry.md`; the CI producer rules are defined in `docs/reference/ci.md`. @@ -158,11 +159,11 @@ Main server targets may build without a proxy unless a service explicitly requir The reconciler selects the executor from `config.json`: -- `deployment.mode=unidesk-direct` on `main-server`: the legacy/local manifest executor builds the image on the main server, then uses the fixed UniDesk Compose project and `up -d --no-build --no-deps --force-recreate `. Reviewed artifact-consumer services such as `baidu-netdisk` use the D601 registry pull-only path for `--env dev` and `--env prod` instead. +- `deployment.mode=unidesk-direct` on `main-server`: the legacy/local manifest executor builds the image on the main server, then uses the fixed UniDesk Compose project and `up -d --no-build --no-deps --force-recreate `. Reviewed artifact-consumer services such as `frontend` and `baidu-netdisk` use the D601 registry pull-only path for `--env dev` and `--env prod` instead. - `deployment.mode=internal-sidecar` on `main-server`: use the same main-server target-side source export, Docker build, image label stamping, fixed Compose project replacement and live commit verification as direct Compose services. This class is for private sidecars such as `code-queue-mgr`; it is still versioned by `deploy.json.commitId`, not by the operator's current worktree. - `deployment.mode=unidesk-direct` on a provider: this executor is disabled for D601 service deployment. The historical behavior dispatched `host.ssh` to the provider, built on the provider, then used the service's provider-local compose file and project; that shape must not remain a second deployment control plane. - Control bridges that UniDesk needs in order to inspect or repair an orchestrator must stay in this direct class. In particular, `k3sctl-adapter` is a UniDesk-managed bridge to native k3s and must remain outside k3s; Docker packaging on Docker Desktop/WSL must create an explicit host-local bridge, currently an adapter-container SSH local tunnel, to reach `/etc/rancher/k3s/k3s.yaml` and WSL `127.0.0.1:6443`. -- `deployment.mode=k3sctl-managed`: the target behavior is to build on the active control target, verify native k3s on the host OS/WSL distro, import the image into native k3s/containerd, apply the existing Kubernetes manifest, stamp the Deployment and wait for rollout. On D601, persistent dev apply is currently allowed only for `backend-core` and `frontend` in `unidesk-dev`; normal production services still cannot use a maintenance-channel direct rollout. The executor must use the native kubeconfig and containerd socket, for example `/etc/rancher/k3s/k3s.yaml` and `/run/k3s/containerd/containerd.sock`; running k3s itself in Docker is forbidden for both control-plane and worker nodes. A `rancher/k3s` image or legacy container may only be used as a temporary artifact source during migration, and any active containerized k3s control plane must be stopped before verification succeeds. The executor must preload a valid `rancher/mirrored-pause:3.6` sandbox image into native k3s containerd through the provider-gateway one-shot egress path, verify its entrypoint is `/pause`, and reject fake or sleep-based replacement images. Code Queue's k3s migration executor must also stop/remove the legacy direct Docker `code-queue-backend` after k3s rollout, so there is never a second scheduler running beside the native k3s scheduler. +- `deployment.mode=k3sctl-managed`: the target behavior is to build on the active control target unless the service has a reviewed artifact-consumer exception, verify native k3s on the host OS/WSL distro, import the image into native k3s/containerd, apply the existing Kubernetes manifest, stamp the Deployment and wait for rollout. On D601, persistent dev apply is currently allowed for `backend-core` target-side build and `frontend` artifact consumption in `unidesk-dev`; normal production services still cannot use a maintenance-channel direct rollout. The executor must use the native kubeconfig and containerd socket, for example `/etc/rancher/k3s/k3s.yaml` and `/run/k3s/containerd/containerd.sock`; running k3s itself in Docker is forbidden for both control-plane and worker nodes. A `rancher/k3s` image or legacy container may only be used as a temporary artifact source during migration, and any active containerized k3s control plane must be stopped before verification succeeds. The executor must preload a valid `rancher/mirrored-pause:3.6` sandbox image into native k3s containerd through the provider-gateway one-shot egress path, verify its entrypoint is `/pause`, and reject fake or sleep-based replacement images. Code Queue's k3s migration executor must also stop/remove the legacy direct Docker `code-queue-backend` after k3s rollout, so there is never a second scheduler running beside the native k3s scheduler. D601 Docker local images are not the source of truth for k3s runtime availability. For Code Queue, the deploy gate must verify `unidesk-code-queue:d601` exists in native k3s containerd after import with `ctr --address /run/k3s/containerd/containerd.sock -n k8s.io images ls`, and it must fail before rollout if the tag is missing. The same gate must verify every production Code Queue Deployment that uses the image (`code-queue`, `code-queue-read`, `code-queue-write`, `d601-provider-egress-proxy`, `d601-tcp-egress-gateway`) still references exactly `unidesk-code-queue:d601`; otherwise kubelet may attempt an external registry pull and leave base gateways in `ImagePullBackOff`. diff --git a/docs/reference/deployment.md b/docs/reference/deployment.md index d75e5aa0..165f7e75 100644 --- a/docs/reference/deployment.md +++ b/docs/reference/deployment.md @@ -30,7 +30,7 @@ CLI 会优先使用 `docker compose` v2 plugin;当 v2 plugin 不存在时才 Compose v2 安装后仍然必须遵守 UniDesk 的服务控制入口:全栈生命周期用 `server start` / `server stop`,单服务重建用 `server rebuild `。不要因为 v2 可用就直接在生产栈上手工执行未纳入 CLI 的 `up --build`、`down -v` 或跨项目清理命令;所有会影响容器的动作都应保持 job 可观测、Compose project 固定、database named volume 保留。主 server Compose 命令必须从 `providerGateway.upgrade.hostProjectRoot` 指定的 canonical UniDesk 根目录运行,临时 worktree、Code Queue 导出目录或实验分支不得复用生产 `-p unidesk` 和固定 `container_name` 去替换生产容器。 -版本化用户服务部署优先使用 `bun scripts/cli.ts deploy apply` 已支持的受控路径;D601 persistent dev apply 当前只支持 `backend-core` 和 `frontend`,`baidu-netdisk` dev 验证使用 artifact consumer,dev desired-state smoke 使用 `ci run-dev-e2e`。`deploy.json` 只声明服务 `id`、`repo` 和 `commitId`;目标节点、Dockerfile、Compose、Kubernetes manifest、健康检查和代理路径继续来自 `config.json` 与现有 manifest。主 server 直管微服务和内部 sidecar,例如 `code-queue-mgr`,也必须支持这一路径:`deploy apply --service code-queue-mgr` 从 `deploy.json` 指定 commit 导出源码、构建镜像、替换固定 Compose service 并验证运行中镜像/健康信息的 commit。部署默认遵循 target-side build:服务部署到哪台 target,就在哪台 target 从 remote commit 导出源码、一次性代理构建镜像并部署;不得把中心构建镜像作为默认分发路径,也不得用 `docker commit` 或脏 worktree 作为部署输入。production backend-core 是明确例外;`baidu-netdisk` 是主 server 直管微服务的镜像化样板:D601 CI 构建并推送 commit-pinned 镜像到 D601 artifact registry,master server dev/prod CD 只拉取、retag、recreate 和验证,不在 master server 执行 Compose build。完整规则见 `docs/reference/deploy.md`,D601 dev/Rust 边界见 `docs/reference/dev-environment.md`,artifact registry 见 `docs/reference/artifact-registry.md`。 +版本化用户服务部署优先使用 `bun scripts/cli.ts deploy apply` 已支持的受控路径;D601 persistent dev apply 当前支持 `backend-core` target-side rollout、`frontend` artifact consumer,`baidu-netdisk` dev 验证也使用 artifact consumer,dev desired-state smoke 使用 `ci run-dev-e2e`。`deploy.json` 只声明服务 `id`、`repo` 和 `commitId`;目标节点、Dockerfile、Compose、Kubernetes manifest、健康检查和代理路径继续来自 `config.json` 与现有 manifest。主 server 直管微服务和内部 sidecar,例如 `code-queue-mgr`,也必须支持这一路径:`deploy apply --service code-queue-mgr` 从 `deploy.json` 指定 commit 导出源码、构建镜像、替换固定 Compose service 并验证运行中镜像/健康信息的 commit。部署默认遵循 target-side build:服务部署到哪台 target,就在哪台 target 从 remote commit 导出源码、一次性代理构建镜像并部署;不得把中心构建镜像作为默认分发路径,也不得用 `docker commit` 或脏 worktree 作为部署输入。production backend-core 是明确例外;`frontend` 是用户服务 UI / 前端镜像化样板,`baidu-netdisk` 是主 server 直管微服务的镜像化样板:D601 CI 构建并推送 commit-pinned 镜像到 D601 artifact registry,dev/prod CD 只拉取、retag 或导入、recreate/rollout 和验证,不在 master server 或 dev target 执行 frontend Compose build。完整规则见 `docs/reference/deploy.md`,D601 dev/Rust 边界见 `docs/reference/dev-environment.md`,artifact registry 见 `docs/reference/artifact-registry.md`。 ## Main Server Swap @@ -46,11 +46,11 @@ swap 管理不能被强塞进所有热路径。`server start/status` 可以暴 ## Single Service Rebuild -前端、本机 provider-gateway、dev-frontend-proxy 或主 server 承载的 Todo Note/Code Queue Manager/Project Manager/Baidu Netdisk/OA Event Flow 用户服务需要非版本化本地重建时,统一使用 `bun scripts/cli.ts server rebuild `,其中 `` 只能是 `backend-core`、`frontend`、`dev-frontend-proxy`、`provider-gateway`、`todo-note`、`code-queue-mgr`、`project-manager`、`baidu-netdisk` 或 `oa-event-flow`。需要按 commit 上线或恢复到 desired-state 时必须改用 `bun scripts/cli.ts deploy apply --service `、backend-core artifact CD 或 `deploy apply --env dev|prod --service baidu-netdisk` artifact consumer;直管微服务也不能把脏工作树或手工重建作为部署真相。Rust backend-core 迭代不得在 master server 用 `server rebuild backend-core` 编译,生产 backend-core 也不得用该命令完成 Rust 构建,必须走 D601 dev deploy/CI 或 D601 artifact registry CD。`server rebuild baidu-netdisk` 只作为维护/非标准路径保留,不得作为标准发布完成证据。D601 Code Queue 执行面、File Browser、FindJob、Pipeline、MET Nonlinear 和 ClaudeQQ 部署在计算节点,不属于主 server Compose 可重建服务;其中 D601 Code Queue 执行面不得再通过 `codex deploy` 或维护通道直连 D601 部署;未来正式 CD 必须经受控 target-side 路径执行 build-first、rollout 和 live commit 验证。 +前端、本机 provider-gateway、dev-frontend-proxy 或主 server 承载的 Todo Note/Code Queue Manager/Project Manager/Baidu Netdisk/OA Event Flow 用户服务需要非版本化本地重建时,统一使用 `bun scripts/cli.ts server rebuild `,其中 `` 只能是 `backend-core`、`frontend`、`dev-frontend-proxy`、`provider-gateway`、`todo-note`、`code-queue-mgr`、`project-manager`、`baidu-netdisk` 或 `oa-event-flow`。需要按 commit 上线或恢复到 desired-state 时必须改用 `bun scripts/cli.ts deploy apply --service `、backend-core artifact CD、`deploy apply --env dev|prod --service frontend` artifact consumer 或 `deploy apply --env dev|prod --service baidu-netdisk` artifact consumer;直管微服务也不能把脏工作树或手工重建作为部署真相。Rust backend-core 迭代不得在 master server 用 `server rebuild backend-core` 编译,生产 backend-core 也不得用该命令完成 Rust 构建,必须走 D601 dev deploy/CI 或 D601 artifact registry CD。`server rebuild frontend` 和 `server rebuild baidu-netdisk` 只作为维护/非标准路径保留,不得作为标准发布完成证据。D601 Code Queue 执行面、File Browser、FindJob、Pipeline、MET Nonlinear 和 ClaudeQQ 部署在计算节点,不属于主 server Compose 可重建服务;其中 D601 Code Queue 执行面不得再通过 `codex deploy` 或维护通道直连 D601 部署;未来正式 CD 必须经受控 target-side 路径执行 build-first、rollout 和 live commit 验证。 -frontend 改动必须明确上线到公网:修改 `src/components/frontend/src/`、`src/components/frontend/public/style.css`、frontend 使用的共享 TSX/TS 模块或 WebUI 导航后,必须在同一变更集中执行 `bun scripts/cli.ts server rebuild frontend`,并等待 job 成功。公网 WebUI 的 `/app.js` 是 `unidesk-frontend` 容器启动时从镜像内源码转译生成的运行时 bundle;只改工作区文件、只跑 `bun run check`、只跑 `Bun.build` 或只刷新浏览器都不会替换已经运行的容器。 +frontend 改动必须明确上线到公网:修改 `src/components/frontend/src/`、`src/components/frontend/public/style.css`、frontend 使用的共享 TSX/TS 模块或 WebUI 导航后,标准发布顺序是先把 pushed commit 交给 `bun scripts/cli.ts ci publish-user-service --service frontend --commit `,再用 `bun scripts/cli.ts deploy apply --env dev --service frontend` 和 `bun scripts/cli.ts deploy apply --env prod --service frontend` 消费同一个 commit-pinned artifact。公网 WebUI 的 `/app.js` 是 `unidesk-frontend` 镜像内运行时 bundle;只改工作区文件、只跑 `bun run check`、只跑 `Bun.build`、只刷新浏览器或只 `server rebuild frontend` 都不能作为标准版本发布证据。 -frontend 的 Docker 上线顺序为:先运行必要的本地校验,例如 `bun scripts/cli.ts check` 或对应的 frontend bundle 检查;然后运行 `bun scripts/cli.ts server rebuild frontend`;再用 `bun scripts/cli.ts job status latest` 或具体 job id 确认 `status=succeeded`;最后用 `bun scripts/cli.ts server status`、`curl -fsS http://74.48.78.17:18081/health` 和真实页面/深链接验证。若必须手工复现 CLI 行为,等价 Docker Compose 命令只能是固定 project/env 的 `docker compose --env-file .state/docker-compose.env -f docker-compose.yml -p unidesk build frontend`,随后 `docker compose --env-file .state/docker-compose.env -f docker-compose.yml -p unidesk up -d --no-deps --force-recreate frontend`;手工路径仍必须做同样的健康检查,不得改用全栈 `up --build`、`down`、删除容器或重启 database/backend-core 来“顺手上线”前端。 +frontend 的 artifact 上线顺序为:先运行必要的轻量本地校验或 D601 CI;然后发布 `127.0.0.1:5000/unidesk/frontend:`;再用 dev/prod `deploy apply` 消费该 artifact;最后验证 dev `frontend-dev` 和 prod `frontend` 的 `/health.deploy.commit`、image label、`UNIDESK_DEPLOY_*` metadata 都等于 requested commit。若必须手工复现维护路径,等价 Docker Compose 命令只能是固定 project/env 的 `docker compose --env-file .state/docker-compose.env -f docker-compose.yml -p unidesk build frontend`,随后 `docker compose --env-file .state/docker-compose.env -f docker-compose.yml -p unidesk up -d --no-deps --force-recreate frontend`;手工路径仍必须做同样的健康检查,不得改用全栈 `up --build`、`down`、删除容器或重启 database/backend-core 来“顺手上线”前端。 单服务重建必须由 CLI 解析出的 Compose 命令执行,且只能影响目标 service,不得连带重启 database、backend-core 或其他未指定服务。重建后 job 必须按 Docker Compose label 校验目标容器:`com.docker.compose.project` 等于 `config.json` 中的固定 project name,`com.docker.compose.service` 等于目标服务名,并等待容器进入 `healthy`;没有 healthcheck 的服务至少要进入 `running`。如果验证失败,job 必须失败并输出目标容器状态,禁止把“无输出”或“只完成 build”当作成功。 diff --git a/docs/reference/dev-environment.md b/docs/reference/dev-environment.md index a178a60b..930bfb5f 100644 --- a/docs/reference/dev-environment.md +++ b/docs/reference/dev-environment.md @@ -9,7 +9,7 @@ The dev environment lets users experience the next UniDesk version without inter - Production stays on the normal public frontend at `http://74.48.78.17:18081/`. - Dev is exposed through a separate main-server public port at `http://74.48.78.17:18083/`. - Dev backend/frontend workloads run in D601 native k3s namespace `unidesk-dev`, not in the main-server Compose stack. -- Dev backend/frontend build and rollout use pushed Git commits from `origin/master:deploy.json#environments.dev`, not dirty local worktrees. +- Dev backend-core build and frontend artifact rollout use pushed Git commits from `origin/master:deploy.json#environments.dev`, not dirty local worktrees. - Rust backend-core check/build must run on D601 through CI or dev deploy; the master server must not compile Rust for this iteration path. ## Public Dev Frontend Port @@ -69,20 +69,20 @@ Rust checking is enabled only when the process is already running inside the D60 ## Dev Deploy Path -`deploy apply --env dev --service backend-core|frontend` is the controlled persistent dev rollout path. The controller runs on the master server, but the heavy work runs on D601: +`deploy apply --env dev --service backend-core|frontend` is the controlled persistent dev rollout path. The controller runs on the master server, but the heavy work runs on D601. `backend-core` still uses the constrained dev target-side build path; `frontend` consumes the CI-published commit-pinned artifact from the D601 registry. 1. Fetch `origin/master:deploy.json#environments.dev` and resolve the requested service commit to a full SHA. 2. Dispatch to D601 through the existing provider-gateway/Host SSH maintenance capability. 3. On D601, fetch/export the requested Git commit through the node-local provider-gateway egress proxy `http://127.0.0.1:18789`. -4. Use the target-side commit as the source for Dockerfile, build context and dev k3s manifest. -5. Build the service image on D601 Docker, importing any required base images through the same egress boundary. -6. Import the image into native k3s containerd at `/run/k3s/containerd/containerd.sock`. +4. For backend-core, use the target-side commit as the source for Dockerfile, build context and dev k3s manifest, then build the service image on D601 Docker. +5. For frontend, require the existing registry image `127.0.0.1:5000/unidesk/frontend:` produced by `ci publish-user-service --service frontend`; do not build frontend source in the dev target. +6. Import the backend-core build output or frontend artifact into native k3s containerd at `/run/k3s/containerd/containerd.sock`. 7. Apply only the selected `unidesk-dev` Service/Deployment objects from the dev manifest. 8. For `frontend`, sync auth/session settings from main-server `config.json.auth` into the dev runtime Secret/ConfigMap before rollout. 9. Stamp the Deployment with `UNIDESK_DEPLOY_*` env and `unidesk.ai/deploy-*` annotations. 10. Verify health through the Kubernetes API service proxy and require the live commit to match the requested commit. -The dev path is not a fallback system. If GitHub fetch, provider-gateway egress, Docker build, native k3s, containerd import, kubectl apply or live health verification fails, the job fails with logs. It must not fall back to building on the master server, using a dirty worktree, direct D601 public ports, NodePort, or another deployment command. +The dev path is not a fallback system. If GitHub fetch, provider-gateway egress, Docker build for backend-core, frontend artifact lookup, native k3s, containerd import, kubectl apply or live health verification fails, the job fails with logs. It must not fall back to building frontend source on the dev target, building on the master server, using a dirty worktree, direct D601 public ports, NodePort, or another deployment command. ## DevOps Hygiene @@ -96,12 +96,13 @@ Use this sequence for backend-core Rust and frontend dev work: 2. Run local non-Rust checks on the master server, for example `bun scripts/cli.ts check --files --scripts-typecheck --compose --logs`. 3. Commit and push the code to `origin master`; `deploy apply --env dev` cannot deploy unpushed local changes. 4. Update `deploy.json` `environments.dev.services` so `backend-core` and `frontend` point at the pushed commit, then commit and push that manifest update. -5. Run `bun scripts/cli.ts deploy apply --env dev --service backend-core` and observe the returned job with `bun scripts/cli.ts job status --tail-bytes 30000`. -6. Run `bun scripts/cli.ts deploy apply --env dev --service frontend` and observe the job the same way. -7. If the dev service catalog changes, deploy the pushed `k3sctl-adapter` commit through the controlled local manifest exception, then verify `/api/control-plane` lists `k3s/dev/unidesk-dev-core.k3s.json`. -8. Rebuild or verify `dev-frontend-proxy` on the main server with `bun scripts/cli.ts server rebuild dev-frontend-proxy` when the proxy config or port changes. -9. Manually test `http://74.48.78.17:18083/` and the dev health endpoints. -10. Run D601 CI for the commit and the dev smoke runner: `bun scripts/cli.ts ci run --revision --wait-ms ` and `bun scripts/cli.ts ci run-dev-e2e --wait-ms `. When Code Queue behavior changes, update the `code-queue` entry in `environments.dev.services` to the pushed commit before running the dev smoke; do not use `deploy apply --env dev --service code-queue`. +5. For frontend changes, publish the artifact first: `bun scripts/cli.ts ci publish-user-service --service frontend --commit --wait-ms 1200000`. +6. Run `bun scripts/cli.ts deploy apply --env dev --service backend-core` and observe the returned job with `bun scripts/cli.ts job status --tail-bytes 30000`. +7. Run `bun scripts/cli.ts deploy apply --env dev --service frontend` and observe the job the same way; this must consume the registry artifact and verify `/health.deploy.commit`. +8. If the dev service catalog changes, deploy the pushed `k3sctl-adapter` commit through the controlled local manifest exception, then verify `/api/control-plane` lists `k3s/dev/unidesk-dev-core.k3s.json`. +9. Rebuild or verify `dev-frontend-proxy` on the main server with `bun scripts/cli.ts server rebuild dev-frontend-proxy` when the proxy config or port changes. +10. Manually test `http://74.48.78.17:18083/` and the dev health endpoints. +11. Run D601 CI for the commit and the dev smoke runner: `bun scripts/cli.ts ci run --revision --wait-ms ` and `bun scripts/cli.ts ci run-dev-e2e --wait-ms `. When Code Queue behavior changes, update the `code-queue` entry in `environments.dev.services` to the pushed commit before running the dev smoke; do not use `deploy apply --env dev --service code-queue`. ## Validation Commands diff --git a/docs/reference/frontend.md b/docs/reference/frontend.md index 06f5a4bb..19825a42 100644 --- a/docs/reference/frontend.md +++ b/docs/reference/frontend.md @@ -16,19 +16,20 @@ Code Queue 的 queue 合并弹窗是该公共组件的首个业务复用示例 ## Deployment Contract -任何会影响公网 WebUI 的 frontend 源码、样式或导航变更,都必须在同一任务内完成 Docker 上线;只运行 TypeScript 检查、`Bun.build` 或修改仓库文件不代表公网生效。 +任何会影响公网 WebUI 的 frontend 源码、样式或导航变更,都必须在同一任务内完成 artifact 发布和 CD 验证;只运行 TypeScript 检查、`Bun.build` 或修改仓库文件不代表公网生效。 -**关键规则**:frontend 容器启动时才从镜像内复制的 `src/components/frontend/src/app.tsx` 及其 TSX imports 构建 `/app.js`,运行中的 `unidesk-frontend` 不会自动读取工作区新文件。 +**关键规则**:frontend 容器只从镜像内的 `src/components/frontend/src/app.tsx` 及其 TSX imports 构建 `/app.js`,运行中的 `unidesk-frontend` 不会自动读取工作区新文件。标准发布真相是 D601 CI 发布的 `127.0.0.1:5000/unidesk/frontend:` 和 dev/prod CD 对该 commit-pinned artifact 的 live commit 验证。 **上线流程**: 1. 修改源码/CSS -2. 执行 `bun scripts/cli.ts server rebuild frontend` -3. 用 `bun scripts/cli.ts job status latest` 确认 `status=succeeded` -4. 用 E2E `frontend:layout-overflow` 验证改动已生效 +2. push commit 后执行 `bun scripts/cli.ts ci publish-user-service --service frontend --commit ` +3. 执行 `bun scripts/cli.ts deploy apply --env dev --service frontend` +4. 执行 `bun scripts/cli.ts deploy apply --env prod --service frontend` +5. 验证 dev/prod `/health.deploy.commit`、image label 和实际页面/深链接都对应 requested commit -禁止用"本地 bundle 校验通过"代替 `server rebuild frontend`;禁止跳过 E2E 验证直接交付。 +禁止用"本地 bundle 校验通过"、`server rebuild frontend`、dirty worktree 或 mutable `latest` 代替 frontend artifact consumer 发布;禁止跳过 live commit 验证直接交付。 -前端修改必须通过 `bun scripts/cli.ts server rebuild frontend` 上线。确认 job status=succeeded 后,用 E2E `frontend:layout-overflow` 验证改动已生效。 +`server rebuild frontend` 只保留为维护/非标准路径,不得作为标准发布证据。正式 frontend 发布必须通过 `ci publish-user-service --service frontend` 产出 commit-pinned image,再由 `deploy apply --env dev|prod --service frontend` 消费。 如果公网仍是旧界面:1. 确认 job 已成功且容器创建时间晚于代码修改;2. 强制刷新或开无痕窗口;3. 用 curl -H "Cache-Control: no-cache" http://74.48.78.17:18081/app.js 查新 bundle。 diff --git a/docs/reference/microservices.md b/docs/reference/microservices.md index 05c7b17c..48d7fd11 100644 --- a/docs/reference/microservices.md +++ b/docs/reference/microservices.md @@ -156,7 +156,7 @@ Baidu Netdisk 在 UniDesk 语境中按纯后端服务管理:不得暴露百度 D601 开发环境底座只允许创建 `unidesk-dev` namespace 与 dev 专用对象,manifest 固定为 `src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-foundation.k8s.yaml`。该 manifest 包含 `postgres-dev` 独立 PostgreSQL StatefulSet/Service/PVC、dev-only secret/config 模板、dev DB 初始化 SQL 和迁移 Job、ResourceQuota/LimitRange,以及 `unidesk-dev-db-guard`。它不得修改生产 `unidesk` namespace、生产 PostgreSQL、生产 PVC、生产 Deployment/Service/Secret 或主 server Docker Compose。 -`postgres-dev` 是 dev backend-core 与未来 dev Code Queue 状态的默认唯一数据库。dev 运行时必须使用 `postgres-dev.unidesk-dev.svc.cluster.local:5432/unidesk_dev` 和 dev Provider 身份 `D601-dev`;不得共享生产 `d601-tcp-egress-gateway.../unidesk`。Persistent dev backend-core/frontend rollout、public dev frontend port and Rust build boundary are defined in `docs/reference/dev-environment.md`; Code Queue dev rollout remains future work. +`postgres-dev` 是 dev backend-core 与未来 dev Code Queue 状态的默认唯一数据库。dev 运行时必须使用 `postgres-dev.unidesk-dev.svc.cluster.local:5432/unidesk_dev` 和 dev Provider 身份 `D601-dev`;不得共享生产 `d601-tcp-egress-gateway.../unidesk`。Persistent dev backend-core target-side rollout, frontend artifact rollout, public dev frontend port and Rust build boundary are defined in `docs/reference/dev-environment.md`; Code Queue dev rollout remains future work. 验收入口:先运行 `bun scripts/cli.ts dev-env validate` 做静态资源与 DB URL 护栏检查;具备 D601 kubeconfig 时运行 `bun scripts/cli.ts dev-env validate --kubectl-dry-run` 做 Kubernetes client dry-run。首次或镜像缓存不确定时,先运行 `bun scripts/cli.ts dev-env prewarm-images`,把 `postgres:16-alpine` 和 local-path helper 所需的 `rancher/mirrored-library-busybox:1.36.1` 导入 D601 原生 k3s containerd;否则 D601 的 Docker 代理/缓存正常也不能保证 k3s/containerd 能实时拉到外部镜像。若实际 apply,只能 apply 到 `unidesk-dev`,随后用 `kubectl -n unidesk-dev get pods,svc,pvc` 验证 dev DB ready,并对比 apply 前后的 `kubectl -n unidesk get deploy,sts,svc,secret,pvc -o name` 证明生产 workload 未变化。 diff --git a/docs/reference/user-service-delivery.md b/docs/reference/user-service-delivery.md index 983b4a90..47362240 100644 --- a/docs/reference/user-service-delivery.md +++ b/docs/reference/user-service-delivery.md @@ -4,7 +4,7 @@ This document owns the default delivery path for UniDesk user services registere ## Scope -User services are non-core business services mounted onto the UniDesk platform. They must remain deliverable without changing the base platform strategy. The default policy here applies to user services that are expected to reach production after validation, including main-server direct services such as Baidu Netdisk and D601-managed services such as Decision Center. +User services are non-core business services mounted onto the UniDesk platform. They must remain deliverable without changing the base platform strategy. The default policy here applies to user services that are expected to reach production after validation, including the UniDesk user-service UI artifact (`frontend`), main-server direct services such as Baidu Netdisk, and D601-managed services such as Decision Center. This policy does not apply to: @@ -39,7 +39,18 @@ The default release flow for a user-service change is: ## Frontend Pairing -Many user services are surfaced through the UniDesk frontend rather than through their own browser-exposed product. When a user-service backend has a paired UniDesk frontend page, the frontend change must be validated in the same dev/prod release window as the backend artifact, but it does not create a second deployment truth. The backend artifact remains the production deployment unit; the frontend page remains the user-visible acceptance surface. +Many user services are surfaced through the UniDesk frontend rather than through their own browser-exposed product. When a user-service backend has a paired UniDesk frontend page, the frontend change must be validated in the same dev/prod release window as the backend artifact. The frontend itself is also a reviewed artifact producer/consumer sample: its release unit is `127.0.0.1:5000/unidesk/frontend:`, and the live UI must expose the same requested commit through image labels and `/health.deploy.commit`. + +## Frontend + +Frontend is the canonical user-service UI sample. It is not released by target-side source build as the standard path. + +- The minimal standard artifact command is `bun scripts/cli.ts ci publish-user-service --service frontend --commit --wait-ms 1200000`. +- The expected artifact is `127.0.0.1:5000/unidesk/frontend:` plus its registry digest from the CI output. +- Dev CD consumes the same artifact with `bun scripts/cli.ts deploy apply --env dev --service frontend`; it imports the image into D601 native k3s, rolls out `frontend-dev`, syncs auth/session metadata from main-server config, and verifies `/health.deploy.commit`. +- Production CD consumes the same artifact with `bun scripts/cli.ts deploy apply --env prod --service frontend`; it recreates only the master-server Compose `frontend` service with `--no-build --no-deps --force-recreate` and verifies image labels plus `/health.deploy.commit`. +- `server rebuild frontend` remains a maintenance/local rebuild path only. It is not the standard versioned release truth for frontend. +- Production acceptance must explicitly verify the public `/health` payload, the requested commit, the running image label, and the expected UI routes for the changed user-service pages. ## Baidu Netdisk diff --git a/scripts/src/artifact-registry.ts b/scripts/src/artifact-registry.ts index 8a6a0f56..eb3fcb11 100644 --- a/scripts/src/artifact-registry.ts +++ b/scripts/src/artifact-registry.ts @@ -1,13 +1,15 @@ import { createHash } from "node:crypto"; import { readFileSync, writeFileSync } from "node:fs"; import { runCommand, type CommandResult } from "./command"; -import { readConfig, repoRoot, rootPath } from "./config"; +import { readConfig, type UniDeskConfig, repoRoot, rootPath } from "./config"; import { resolveComposeCommand, writeComposeEnv } from "./docker"; import { startJob } from "./jobs"; type ArtifactRegistryAction = "plan" | "render" | "status" | "health" | "install" | "deploy-backend-core" | "deploy-service"; +type ArtifactDeployEnvironment = "prod" | "dev"; interface ArtifactRegistryOptions { + environment: ArtifactDeployEnvironment | null; providerId: string; host: string; port: number; @@ -47,6 +49,7 @@ interface RenderedBundle { } const defaultOptions: ArtifactRegistryOptions = { + environment: null, providerId: "D601", host: "127.0.0.1", port: 5000, @@ -66,11 +69,12 @@ const defaultOptions: ArtifactRegistryOptions = { sourceRepo: "https://github.com/pikasTech/unidesk", deployRef: null, }; -const supportedArtifactConsumerServices = ["backend-core", "baidu-netdisk", "decision-center"] as const; +const supportedArtifactConsumerServices = ["backend-core", "baidu-netdisk", "decision-center", "frontend"] as const; type SupportedArtifactConsumerService = typeof supportedArtifactConsumerServices[number]; interface ArtifactConsumerSpec { serviceId: SupportedArtifactConsumerService; + environment?: ArtifactDeployEnvironment; kind: "compose" | "d601-k3s"; registryRepository: string; dockerfile: string; @@ -92,12 +96,15 @@ interface ArtifactConsumerSpec { servicePort: number; containerName: string; healthPath: string; + applySelector?: string; + podLabelSelector?: string; }; } -const artifactConsumerSpecs: Record = { +const artifactConsumerSpecs: Record = { "backend-core": { serviceId: "backend-core", + environment: "prod", kind: "compose", registryRepository: "unidesk/backend-core", dockerfile: "src/components/backend-core/Dockerfile", @@ -114,6 +121,7 @@ const artifactConsumerSpecs: Record `unidesk-frontend:${commit}`, + deployRef: "deploy.json#environments.prod.services.frontend", + compose: { + serviceName: "frontend", + containerName: "unidesk-frontend", + deployEnvPrefix: "UNIDESK_FRONTEND_DEPLOY", + healthProbeCommand: "bun -e \"fetch('http://127.0.0.1:8080/health').then(async r=>{const text=await r.text(); console.log(text); process.exit(r.ok?0:1)}).catch(e=>{console.error(e); process.exit(1)})\"", + requireHealthCommit: true, + }, + }, + "dev:frontend": { + serviceId: "frontend", + environment: "dev", + kind: "d601-k3s", + registryRepository: "unidesk/frontend", + dockerfile: "src/components/frontend/Dockerfile", + targetImage: "unidesk-frontend:dev", + targetCommitImage: (commit: string) => `unidesk-frontend:${commit}`, + deployRef: "origin/master:deploy.json#environments.dev.services.frontend", + k3s: { + namespace: "unidesk-dev", + manifestPath: "/home/ubuntu/cq-deploy/src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-core.k8s.yaml", + deploymentName: "frontend-dev", + serviceName: "frontend-dev", + servicePort: 8080, + containerName: "frontend", + healthPath: "/health", + applySelector: "app.kubernetes.io/name=frontend", + podLabelSelector: "app.kubernetes.io/name=frontend,app.kubernetes.io/component=web,unidesk.ai/environment=dev", + }, + }, }; function isHelpArg(value: string | undefined): boolean { @@ -176,6 +223,11 @@ function commitValue(value: string, option: string): string { return normalized; } +function environmentValue(value: string, option: string): ArtifactDeployEnvironment { + if (value === "prod" || value === "dev") return value; + throw new Error(`${option} must be one of: prod, dev`); +} + function parseOptions(args: string[]): ArtifactRegistryOptions { const options = { ...defaultOptions }; for (let index = 0; index < args.length; index += 1) { @@ -220,6 +272,9 @@ function parseOptions(args: string[]): ArtifactRegistryOptions { } else if (arg === "--deploy-ref") { options.deployRef = requireValue(args, index, arg); index += 1; + } else if (arg === "--env" || arg === "--environment") { + options.environment = environmentValue(requireValue(args, index, arg), arg); + index += 1; } else { throw new Error(`unknown artifact-registry option: ${arg}`); } @@ -237,6 +292,10 @@ function shellQuote(value: string): string { return `'${value.replace(/'/g, `'\\''`)}'`; } +function base64(value: string): string { + return Buffer.from(value, "utf8").toString("base64"); +} + function safeName(value: string): string { return value.replace(/[^A-Za-z0-9_.-]/gu, "-"); } @@ -367,7 +426,7 @@ function plan(options: ArtifactRegistryOptions): Record { "listen only on D601 host loopback 127.0.0.1:5000", "do not expose a public port, NodePort, hostPort, or third-party registry", "do not run inside k3s; keep the registry outside the native k3s failure domain", - "CI builds and publishes backend-core and reviewed user-service artifacts on D601", + "CI builds and publishes backend-core, frontend, and reviewed user-service artifacts on D601", "CD only pulls, retags, recreates/imports artifacts, and verifies live commit", "master server CD must not compile Rust or run docker compose build for artifact consumers", ], @@ -379,6 +438,11 @@ function plan(options: ArtifactRegistryOptions): Record { "k3s consumers pull on D601 and import into native k3s containerd", "CD retags/recreates or updates Deployment images and verifies live commit metadata", ], + frontendArtifactFlow: [ + "D601 CI builds and pushes 127.0.0.1:5000/unidesk/frontend:", + "dev CD imports the image into D601 native k3s and verifies frontend-dev /health deploy.commit", + "prod CD pulls via provider-gateway image stream, recreates Compose frontend with no build, and verifies /health deploy.commit", + ], }; } @@ -490,8 +554,17 @@ function commandTail(result: CommandResult): Record { }; } -function artifactConsumerSpec(serviceId: string): ArtifactConsumerSpec | null { - return (artifactConsumerSpecs as Record)[serviceId] ?? null; +function artifactConsumerSpec(serviceId: string, environment: ArtifactDeployEnvironment | null): ArtifactConsumerSpec | null { + const key = environment === null || environment === "prod" ? serviceId : `${environment}:${serviceId}`; + return artifactConsumerSpecs[key] ?? null; +} + +function supportedArtifactConsumers(): Array<{ environment: ArtifactDeployEnvironment; serviceId: SupportedArtifactConsumerService; kind: ArtifactConsumerSpec["kind"] }> { + return Object.values(artifactConsumerSpecs).map((spec) => ({ + environment: spec.environment ?? "prod", + serviceId: spec.serviceId, + kind: spec.kind, + })); } function unsupportedService(serviceId: string, options: ArtifactRegistryOptions): Record { @@ -500,9 +573,11 @@ function unsupportedService(serviceId: string, options: ArtifactRegistryOptions) supported: false, error: "unsupported", serviceId, + environment: options.environment ?? "prod", providerId: options.providerId, reason: "No standardized D601 registry CD consumer is implemented for this service.", supportedServices: supportedArtifactConsumerServices, + supportedConsumers: supportedArtifactConsumers(), policy: "unsupported services must not silently fall back to maintenance-channel source builds or legacy direct deployment", }; } @@ -786,6 +861,24 @@ function verifyLocalArtifactLabels( }; } +function d601DevFrontendAuthPatchScript(config: UniDeskConfig): string { + const secretData = { + AUTH_USERNAME: base64(config.auth.username), + AUTH_PASSWORD: base64(config.auth.password), + SESSION_SECRET: base64(config.auth.sessionSecret), + }; + const configData = { + SESSION_TTL_SECONDS: String(config.auth.sessionTtlSeconds), + }; + return [ + `secret_patch=${shellQuote(JSON.stringify({ data: secretData }))}`, + `config_patch=${shellQuote(JSON.stringify({ data: configData }))}`, + "kubectl -n unidesk-dev patch secret unidesk-dev-runtime-secrets --type merge -p \"$secret_patch\"", + "kubectl -n unidesk-dev patch configmap unidesk-dev-runtime-config --type merge -p \"$config_patch\"", + "echo artifact_cd_dev_frontend_auth_synced=ok", + ].join("\n"); +} + function composeArtifactEnvValues(spec: ArtifactConsumerSpec, options: ArtifactRegistryOptions, commit: string): Record { if (spec.compose === undefined) throw new Error(`${spec.serviceId} missing compose artifact consumer config`); const prefix = spec.compose.deployEnvPrefix; @@ -848,6 +941,8 @@ async function deployComposeArtifactNow(options: ArtifactRegistryOptions, spec: ...composeArtifactEnvValues(spec, options, commit), }); const compose = resolveComposeCommand(config, runtimeEnv.envFile); + const projectIndex = compose.indexOf("-p"); + const composeProject = projectIndex >= 0 && compose[projectIndex + 1] !== undefined ? compose[projectIndex + 1] : "unidesk"; const serviceName = spec.compose.serviceName; const containerName = spec.compose.containerName; const serviceLogPrefix = spec.serviceId.replace(/-/gu, "_"); @@ -857,7 +952,7 @@ async function deployComposeArtifactNow(options: ArtifactRegistryOptions, spec: `${compose.map(shellQuote).join(" ")} up -d --no-build --no-deps --force-recreate ${shellQuote(serviceName)}`, "ready=0", "for attempt in $(seq 1 60); do", - ` cid=$(docker ps -q --filter label=com.docker.compose.project=unidesk --filter label=com.docker.compose.service=${shellQuote(serviceName)} --filter label=com.docker.compose.oneoff=False | head -1 || true)`, + ` cid=$(docker ps -q --filter label=com.docker.compose.project=${shellQuote(composeProject)} --filter label=com.docker.compose.service=${shellQuote(serviceName)} --filter label=com.docker.compose.oneoff=False | head -1 || true)`, " if [ -n \"$cid\" ]; then", " health=$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' \"$cid\" 2>/dev/null || true)", ` echo "${serviceLogPrefix}_container_probe attempt=$attempt cid=$cid health=$health"`, @@ -868,7 +963,7 @@ async function deployComposeArtifactNow(options: ArtifactRegistryOptions, spec: " sleep 1", "done", "test \"$ready\" = \"1\"", - `cid=$(docker ps -q --filter label=com.docker.compose.project=unidesk --filter label=com.docker.compose.service=${shellQuote(serviceName)} --filter label=com.docker.compose.oneoff=False | head -1)`, + `cid=$(docker ps -q --filter label=com.docker.compose.project=${shellQuote(composeProject)} --filter label=com.docker.compose.service=${shellQuote(serviceName)} --filter label=com.docker.compose.oneoff=False | head -1)`, "image_id=$(docker inspect -f '{{.Image}}' \"$cid\")", "actual_commit=$(docker image inspect -f '{{ index .Config.Labels \"unidesk.ai/source-commit\" }}' \"$image_id\")", `test "$actual_commit" = ${shellQuote(commit)}`, @@ -1006,19 +1101,21 @@ function dryRunArtifactConsumerPlan(options: ArtifactRegistryOptions, spec: Arti "native k3s containerd has the commit image and stable runtime image tag", "Deployment annotation and pod image id label match the requested commit", "service health via Kubernetes API service proxy returns the same deploy.commit", + ...(spec.environment === "dev" && spec.serviceId === "frontend" ? ["dev frontend auth/session config is synced from main-server config before rollout"] : []), ], rollback: rollbackInfo(spec, commit), }; } function rollbackInfo(spec: ArtifactConsumerSpec, commit: string): Record { + const environment = spec.environment ?? "prod"; if (spec.kind === "compose") { const compose = spec.compose; return { type: "compose-retag-recreate", composeService: compose?.serviceName, previousImageHint: `Use docker image ls / docker inspect to find the previous labeled ${spec.serviceId} image id; Compose volumes are unchanged.`, - commandShape: `bun scripts/cli.ts deploy apply --env prod --service ${spec.serviceId} --commit `, + commandShape: `bun scripts/cli.ts deploy apply --env ${environment} --service ${spec.serviceId}${environment === "prod" ? " --commit " : ""}`, }; } return { @@ -1026,12 +1123,12 @@ function rollbackInfo(spec: ArtifactConsumerSpec, commit: string): Record`, + commandShape: `bun scripts/cli.ts deploy apply --env ${environment} --service ${spec.serviceId}${environment === "prod" ? " --commit " : ""}`, note: "Rollback is exposed as the same artifact consumer pointed at a previous commit-pinned image that still exists in D601 registry.", }; } -function d601K3sArtifactDeployScript(options: ArtifactRegistryOptions, spec: ArtifactConsumerSpec, commit: string): string { +function d601K3sArtifactDeployScript(options: ArtifactRegistryOptions, spec: ArtifactConsumerSpec, commit: string, config: UniDeskConfig): string { if (spec.k3s === undefined) throw new Error(`${spec.serviceId} missing k3s artifact consumer config`); const sourceImage = artifactImageRef(options, spec, commit); const commitImage = spec.targetCommitImage(commit); @@ -1062,6 +1159,9 @@ function d601K3sArtifactDeployScript(options: ArtifactRegistryOptions, spec: Art `service_port=${shellQuote(String(k3s.servicePort))}`, `health_path=${shellQuote(k3s.healthPath)}`, `manifest=${shellQuote(k3s.manifestPath)}`, + `apply_selector=${shellQuote(k3s.applySelector ?? "")}`, + `pod_selector=${shellQuote(k3s.podLabelSelector ?? `app.kubernetes.io/name=${k3s.deploymentName}`)}`, + "health_tmp=", "export KUBECONFIG=/etc/rancher/k3s/k3s.yaml", "command -v docker >/dev/null", "command -v kubectl >/dev/null", @@ -1083,7 +1183,8 @@ function d601K3sArtifactDeployScript(options: ArtifactRegistryOptions, spec: Art "root_exec ctr --address /run/k3s/containerd/containerd.sock -n k8s.io images import \"$archive\" >/dev/null", "root_exec ctr --address /run/k3s/containerd/containerd.sock -n k8s.io images ls | grep -F \"$stable_image\" >/dev/null", "root_exec ctr --address /run/k3s/containerd/containerd.sock -n k8s.io images ls | grep -F \"$commit_image\" >/dev/null", - "if [ -f \"$manifest\" ]; then kubectl apply -f \"$manifest\"; else echo artifact_cd_manifest_missing=$manifest; fi", + "if [ -f \"$manifest\" ]; then if [ -n \"$apply_selector\" ]; then kubectl apply -f \"$manifest\" -l \"$apply_selector\"; else kubectl apply -f \"$manifest\"; fi; else echo artifact_cd_manifest_missing=$manifest; fi", + ...(spec.environment === "dev" && spec.serviceId === "frontend" ? [d601DevFrontendAuthPatchScript(config)] : []), "previous_commit=$(kubectl -n \"$namespace\" get deployment \"$deployment\" -o jsonpath='{.metadata.annotations.unidesk\\.ai/deploy-commit}' 2>/dev/null || true)", "kubectl -n \"$namespace\" set image \"deployment/$deployment\" \"$container_name=$commit_image\"", "kubectl -n \"$namespace\" set env \"deployment/$deployment\" \"UNIDESK_DEPLOY_SERVICE_ID=$service_id\" \"UNIDESK_DEPLOY_REF=$deploy_ref\" \"UNIDESK_DEPLOY_REPO=$source_repo\" \"UNIDESK_DEPLOY_COMMIT=$commit\" \"UNIDESK_DEPLOY_REQUESTED_COMMIT=$commit\"", @@ -1134,7 +1235,7 @@ function d601K3sArtifactDeployScript(options: ArtifactRegistryOptions, spec: Art "image_label_service=$(containerd_config_label \"$commit_image\" 'unidesk.ai/service-id')", "test \"$image_label_commit\" = \"$commit\"", "test \"$image_label_service\" = \"$service_id\"", - "pod=$(kubectl -n \"$namespace\" get pod -l \"app.kubernetes.io/name=$deployment\" -o jsonpath='{.items[0].metadata.name}')", + "pod=$(kubectl -n \"$namespace\" get pod -l \"$pod_selector\" -o jsonpath='{.items[0].metadata.name}')", "test -n \"$pod\"", "pod_image=$(kubectl -n \"$namespace\" get pod \"$pod\" -o jsonpath='{.spec.containers[?(@.name==\"'\"$container_name\"'\")].image}')", "test \"$pod_image\" = \"$commit_image\"", @@ -1177,7 +1278,8 @@ async function deployD601K3sArtifactNow(options: ArtifactRegistryOptions, spec: registryProbe: commandTail(registryProbe), }; } - const deployScript = d601K3sArtifactDeployScript(options, spec, commit); + const config = readConfig(); + const deployScript = d601K3sArtifactDeployScript(options, spec, commit, config); const deploy = runRemoteScript(options, deployScript, Math.max(options.timeoutMs, 420_000)); if (deploy.exitCode !== 0 || deploy.timedOut) { return { @@ -1217,7 +1319,7 @@ async function deployD601K3sArtifactNow(options: ArtifactRegistryOptions, spec: async function deployServiceNow(options: ArtifactRegistryOptions): Promise> { if (options.serviceId === null) throw new Error("artifact-registry deploy-service requires --service "); if (options.commit === null) throw new Error("artifact-registry deploy-service requires --commit "); - const spec = artifactConsumerSpec(options.serviceId); + const spec = artifactConsumerSpec(options.serviceId, options.environment); if (spec === null) return unsupportedService(options.serviceId, options); if (options.dryRun) return dryRunArtifactConsumerPlan(options, spec, options.commit); if (spec.kind === "compose") return deployComposeArtifactNow(options, spec); @@ -1227,16 +1329,17 @@ async function deployServiceNow(options: ArtifactRegistryOptions): Promise { if (options.serviceId === null) throw new Error("artifact-registry deploy-service requires --service "); if (options.commit === null) throw new Error("artifact-registry deploy-service requires --commit "); - const spec = artifactConsumerSpec(options.serviceId); + const spec = artifactConsumerSpec(options.serviceId, options.environment); if (spec === null) return unsupportedService(options.serviceId, options); if (options.dryRun) return dryRunArtifactConsumerPlan(options, spec, options.commit); const runArgs = args.includes("--run-now") ? args : [...args, "--run-now"]; const command = [process.execPath, rootPath("scripts", "cli.ts"), "artifact-registry", ...runArgs]; - const job = startJob("artifact_registry_service_cd", command, `Pull and deploy ${options.serviceId} artifact ${options.commit} from D601 registry`); + const job = startJob("artifact_registry_service_cd", command, `Pull and deploy ${options.environment ?? "prod"} ${options.serviceId} artifact ${options.commit} from D601 registry`); return { ok: true, mode: "async-job", serviceId: options.serviceId, + environment: options.environment ?? "prod", job, statusCommand: `bun scripts/cli.ts job status ${job.id}`, tailCommand: `bun scripts/cli.ts job status ${job.id} --tail-bytes 30000`, @@ -1262,17 +1365,24 @@ function localHelp(): Record { "bun scripts/cli.ts artifact-registry install [--provider-id D601]", "bun scripts/cli.ts artifact-registry deploy-backend-core --commit [--run-now] [--provider-id D601]", "bun scripts/cli.ts artifact-registry deploy-service --service baidu-netdisk --commit [--dry-run] [--run-now] [--provider-id D601]", + "bun scripts/cli.ts artifact-registry deploy-service --service frontend --env prod --commit [--dry-run] [--run-now] [--provider-id D601]", + "bun scripts/cli.ts artifact-registry deploy-service --service frontend --env dev --commit [--dry-run] [--run-now] [--provider-id D601]", "bun scripts/cli.ts artifact-registry deploy-service --service decision-center --commit [--dry-run] [--run-now] [--provider-id D601]", ], firstStage: "install now writes the rendered systemd/Compose/config files and starts the registry", artifactConsumers: { supportedServices: supportedArtifactConsumerServices, + supportedConsumers: supportedArtifactConsumers(), unsupportedPolicy: "return structured unsupported; never fall back to legacy maintenance-channel source builds", prodCommands: [ "bun scripts/cli.ts deploy apply --env prod --service backend-core", "bun scripts/cli.ts deploy apply --env prod --service baidu-netdisk", + "bun scripts/cli.ts deploy apply --env prod --service frontend", "bun scripts/cli.ts deploy apply --env prod --service decision-center", ], + devCommands: [ + "bun scripts/cli.ts deploy apply --env dev --service frontend", + ], rollbackShape: "rerun the same artifact consumer with a previous commit-pinned image", }, defaults: defaultOptions, diff --git a/scripts/src/ci.ts b/scripts/src/ci.ts index 5eafb22b..a77aaeca 100644 --- a/scripts/src/ci.ts +++ b/scripts/src/ci.ts @@ -216,6 +216,13 @@ function requireSupportedUserService(config: UniDeskConfig, serviceId: string): return service; } +function frontendArtifactTarget(repoOverride: string | null): { repoUrl: string; dockerfile: string } { + return { + repoUrl: repoOverride ?? "https://github.com/pikasTech/unidesk", + dockerfile: "src/components/frontend/Dockerfile", + }; +} + function chunks(value: string, size: number): string[] { const result: string[] = []; for (let index = 0; index < value.length; index += size) { @@ -1415,6 +1422,7 @@ export function ciHelp(): Record { "bun scripts/cli.ts ci publish-backend-core --commit ", "bun scripts/cli.ts ci publish-user-service --service baidu-netdisk --commit ", "bun scripts/cli.ts ci publish-user-service --service decision-center --commit ", + "bun scripts/cli.ts ci publish-user-service --service frontend --commit ", "bun scripts/cli.ts ci run-dev-e2e --wait-ms 600000", "bun scripts/cli.ts ci logs ", ], @@ -1435,10 +1443,14 @@ export function ciHelp(): Record { userServiceArtifact: { producer: "D601 CI", command: "bun scripts/cli.ts ci publish-user-service --service --commit ", - initiallySupportedServices: ["baidu-netdisk", "decision-center"], + initiallySupportedServices: ["baidu-netdisk", "decision-center", "frontend"], registry: "127.0.0.1:5000/unidesk/:", outputFields: ["serviceId", "sourceCommit", "sourceRepo", "dockerfile", "imageRef", "tag", "digest", "digestRef"], boundary: "artifact producer only; no prod deploy and no production namespace mutation", + frontendNext: [ + "bun scripts/cli.ts deploy apply --env dev --service frontend", + "bun scripts/cli.ts deploy apply --env prod --service frontend", + ], }, runDevE2E: { defaultTriggerMode: "commit-pinned-ssh-launcher", @@ -1475,17 +1487,25 @@ export async function runCiCommand(config: UniDeskConfig, args: string[]): Promi } if (action === "publish-user-service") { const serviceId = requireServiceId(stringOption(args, "--service") ?? stringOption(args, "--service-id")); - const service = requireSupportedUserService(config, serviceId); - const repoUrl = stringOption(args, "--repo") ?? stringOption(args, "--repo-url") ?? service.repository.url; + const repoOverride = stringOption(args, "--repo") ?? stringOption(args, "--repo-url"); + const target = serviceId === "frontend" + ? frontendArtifactTarget(repoOverride) + : (() => { + const service = requireSupportedUserService(config, serviceId); + return { + repoUrl: repoOverride ?? service.repository.url, + dockerfile: service.repository.dockerfile, + }; + })(); const commit = requireFullCommit(stringOption(args, "--commit") ?? stringOption(args, "--revision")); const waitMs = numberOption(args, "--wait-ms", 0); const dryRun = boolFlag(args, "--dry-run"); - const dockerfile = requireRepoRelativePath(service.repository.dockerfile, `microservices.${serviceId}.repository.dockerfile`); - if (!["baidu-netdisk", "decision-center"].includes(serviceId)) { - throw new Error("ci publish-user-service currently allows only baidu-netdisk and decision-center until each user-service Dockerfile contract is reviewed"); + const dockerfile = requireRepoRelativePath(target.dockerfile, serviceId === "frontend" ? "frontend.dockerfile" : `microservices.${serviceId}.repository.dockerfile`); + if (!["baidu-netdisk", "decision-center", "frontend"].includes(serviceId)) { + throw new Error("ci publish-user-service currently allows only baidu-netdisk, decision-center, and frontend until each user-service Dockerfile contract is reviewed"); } return publishUserServiceArtifact(config, { - repoUrl, + repoUrl: target.repoUrl, commit, waitMs, serviceId, diff --git a/scripts/src/deploy.ts b/scripts/src/deploy.ts index 6c753d68..dc704099 100644 --- a/scripts/src/deploy.ts +++ b/scripts/src/deploy.ts @@ -133,10 +133,10 @@ const nativeK3sInstallVersion = "v1.34.1+k3s1"; const nativeK3sImage = "rancher/k3s:v1.34.1-k3s1"; const nativeK3sCtrAddress = "/run/k3s/containerd/containerd.sock"; const unideskRepoUrl = "https://github.com/pikasTech/unidesk"; -const d601MaintenanceDeployAllowedServiceIds = new Set(["backend-core", "frontend", "k3sctl-adapter", "code-queue"]); -const devApplySupportedServiceIds = new Set(["backend-core", "frontend"]); -const devArtifactConsumerServiceIds = new Set(["baidu-netdisk"]); -const prodArtifactConsumerServiceIds = new Set(["backend-core", "baidu-netdisk", "decision-center"]); +const d601MaintenanceDeployAllowedServiceIds = new Set(["backend-core", "k3sctl-adapter", "code-queue"]); +const devApplySupportedServiceIds = new Set(["backend-core"]); +const devArtifactConsumerServiceIds = new Set(["baidu-netdisk", "frontend"]); +const prodArtifactConsumerServiceIds = new Set(["backend-core", "baidu-netdisk", "decision-center", "frontend"]); const deployEnvironmentTargets: Record = { dev: { environment: "dev", @@ -199,7 +199,7 @@ export function deployHelp(action: string | undefined = undefined): Record", default: defaultDeployFile, description: "Desired-state manifest path relative to the repo root. JSON and ESM JS manifests are supported, for example deploy.json or develop.js. Local manifest apply allows k3sctl-adapter and explicit production code-queue controlled rollout on D601." }, - { name: "--env ", description: "Read the named environment from origin/master:deploy.json. Dev apply supports backend-core/frontend target-side rollout plus baidu-netdisk artifact validation; prod apply uses the D601 registry artifact consumer for backend-core, baidu-netdisk, and decision-center." }, + { name: "--env ", description: "Read the named environment from origin/master:deploy.json. Dev apply supports backend-core target-side rollout plus frontend/baidu-netdisk artifact consumers; prod apply uses the D601 registry artifact consumer for backend-core, frontend, baidu-netdisk, and decision-center." }, { name: "--service ", description: "Limit reconcile to one service from the manifest." }, { name: "--commit ", description: "Prod artifact rollback/apply override for a selected service; the image must already exist in D601 registry." }, { name: "--dry-run", description: "Prepare and validate without mutating the target service." }, @@ -2305,7 +2305,7 @@ async function applyOneService(config: UniDeskConfig, service: UniDeskMicroservi ok: false, serviceId: service.id, skipped: true, - reason: `D601 target-side deployment is allowed only for k3sctl-adapter and dev backend-core/frontend; ${service.id} is not enabled. Use ci run-dev-e2e for smoke verification.`, + reason: `D601 target-side deployment is allowed only for k3sctl-adapter and dev backend-core; ${service.id} is not enabled. Use ci run-dev-e2e for smoke verification.`, steps, }; } @@ -2439,7 +2439,9 @@ function environmentDryRunPlan( })); const fingerprint = databaseFingerprint(target); return { - ok: environment === "prod" ? services.every((service) => prodArtifactConsumerServiceIds.has(service.id)) : true, + ok: environment === "prod" + ? services.every((service) => prodArtifactConsumerServiceIds.has(service.id)) + : services.every((service) => devApplySupportedServiceIds.has(service.id) || devArtifactConsumerServiceIds.has(service.id)), action, mode: "environment-ref-dry-run", dryRun: true, @@ -2478,8 +2480,10 @@ function environmentDryRunPlan( ? "d601-registry-artifact-consumer" : "unsupported" : devArtifactConsumerServiceIds.has(service.id) - ? "d601-registry-artifact-consumer-dev-validation" - : "d601-dev-target-side-build", + ? service.id === "frontend" ? "d601-registry-artifact-consumer" : "d601-registry-artifact-consumer-dev-validation" + : devApplySupportedServiceIds.has(service.id) + ? "d601-dev-target-side-build" + : "unsupported", unsupported: (environment === "prod" && !prodArtifactConsumerServiceIds.has(service.id)) || (environment === "dev" && !devApplySupportedServiceIds.has(service.id) && !devArtifactConsumerServiceIds.has(service.id)) ? { @@ -2508,7 +2512,7 @@ function blockedD601MaintenanceDeployServices(config: UniDeskConfig, manifest: D } function d601MaintenanceDeployBlockMessage(blocked: string[]): string { - return `D601 target-side deployment is enabled only for k3sctl-adapter and dev backend-core/frontend; blocked services: ${blocked.join(", ")}. Use ci run-dev-e2e for dev smoke verification.`; + return `D601 target-side deployment is enabled only for k3sctl-adapter and dev backend-core; blocked services: ${blocked.join(", ")}. Use ci run-dev-e2e for dev smoke verification.`; } function selectedDevArtifactServices(manifest: DeployManifest, serviceId: string | null): DeployManifestService[] { @@ -2518,7 +2522,8 @@ function selectedDevArtifactServices(manifest: DeployManifest, serviceId: string function selectedDevTargetServices(manifest: DeployManifest, serviceId: string | null): DeployManifestService[] { if (manifest.environment !== "dev") return []; - return selectedEnvironmentServices(manifest, serviceId).filter((service) => devApplySupportedServiceIds.has(service.id)); + return selectedEnvironmentServices(manifest, serviceId) + .filter((service) => devApplySupportedServiceIds.has(service.id) && !devArtifactConsumerServiceIds.has(service.id)); } function selectedEnvironmentServices(manifest: DeployManifest, serviceId: string | null): DeployManifestService[] { @@ -2563,7 +2568,8 @@ async function runArtifactConsumerApplyNow( "--service", service.id, "--commit", commit, "--source-repo", service.repo, - "--deploy-ref", `deploy.json#environments.${environment}.services.${service.id}`, + "--deploy-ref", `${deployEnvironmentTargets[environment].gitRef}:deploy.json#environments.${environment}.services.${service.id}`, + ...(environment === "prod" || service.id === "frontend" ? ["--env", environment] : []), "--timeout-ms", String(options.timeoutMs), "--run-now", ...(options.dryRun ? ["--dry-run"] : []), @@ -2622,11 +2628,11 @@ function devArtifactApplyJob(args: string[], options: DeployOptions): Record 0) { - throw new Error(`deploy apply --env dev currently supports only backend-core/frontend target-side rollout and baidu-netdisk artifact validation; unsupported selected services: ${unsupported.join(", ")}. Use ci run-dev-e2e for smoke verification.`); + throw new Error(`deploy apply --env dev currently supports backend-core target-side rollout plus frontend/baidu-netdisk artifact consumers; unsupported selected services: ${unsupported.join(", ")}. Use ci run-dev-e2e for smoke verification.`); } const devArtifactServices = selectedDevArtifactServices(manifest, options.serviceId); const devTargetServices = selectedDevTargetServices(manifest, options.serviceId); if (devArtifactServices.length > 0 && devTargetServices.length > 0) { - throw new Error("deploy apply --env dev cannot mix artifact validation services with target-side rollout services in one invocation; pass --service"); + throw new Error("deploy apply --env dev cannot mix artifact consumer services with target-side rollout services in one invocation; pass --service"); } if (devArtifactServices.length > 0) { if (options.dryRun || options.runNow) return await runArtifactConsumerApplyNow(manifest, options, "dev", devArtifactServices); diff --git a/scripts/src/docker.ts b/scripts/src/docker.ts index 469b10cd..f000e96a 100644 --- a/scripts/src/docker.ts +++ b/scripts/src/docker.ts @@ -111,6 +111,11 @@ export function writeComposeEnv(config: UniDeskConfig, freshLogPrefix: boolean): UNIDESK_DEPLOY_REPO: runtimeSecret("UNIDESK_DEPLOY_REPO"), UNIDESK_DEPLOY_COMMIT: runtimeSecret("UNIDESK_DEPLOY_COMMIT"), UNIDESK_DEPLOY_REQUESTED_COMMIT: runtimeSecret("UNIDESK_DEPLOY_REQUESTED_COMMIT"), + UNIDESK_FRONTEND_DEPLOY_REF: runtimeSecret("UNIDESK_FRONTEND_DEPLOY_REF"), + UNIDESK_FRONTEND_DEPLOY_SERVICE_ID: runtimeSecret("UNIDESK_FRONTEND_DEPLOY_SERVICE_ID") || "frontend", + UNIDESK_FRONTEND_DEPLOY_REPO: runtimeSecret("UNIDESK_FRONTEND_DEPLOY_REPO"), + UNIDESK_FRONTEND_DEPLOY_COMMIT: runtimeSecret("UNIDESK_FRONTEND_DEPLOY_COMMIT"), + UNIDESK_FRONTEND_DEPLOY_REQUESTED_COMMIT: runtimeSecret("UNIDESK_FRONTEND_DEPLOY_REQUESTED_COMMIT"), UNIDESK_AUTH_USERNAME: config.auth.username, UNIDESK_AUTH_PASSWORD: config.auth.password, UNIDESK_SESSION_SECRET: config.auth.sessionSecret, diff --git a/scripts/src/help.ts b/scripts/src/help.ts index 8c0c92ab..778c895a 100644 --- a/scripts/src/help.ts +++ b/scripts/src/help.ts @@ -260,6 +260,8 @@ function artifactRegistryHelp(): unknown { "bun scripts/cli.ts artifact-registry install [--provider-id D601]", "bun scripts/cli.ts artifact-registry deploy-backend-core --commit [--run-now] [--provider-id D601]", "bun scripts/cli.ts artifact-registry deploy-service --service baidu-netdisk --commit [--dry-run] [--run-now] [--provider-id D601]", + "bun scripts/cli.ts artifact-registry deploy-service --service frontend --env prod --commit [--dry-run] [--run-now] [--provider-id D601]", + "bun scripts/cli.ts artifact-registry deploy-service --service frontend --env dev --commit [--dry-run] [--run-now] [--provider-id D601]", "bun scripts/cli.ts artifact-registry deploy-service --service decision-center --commit [--dry-run] [--run-now] [--provider-id D601]", ], description: "Manage the declaration, rendered files and readonly checks for the D601 host-managed CNCF Distribution artifact registry.", @@ -268,7 +270,7 @@ function artifactRegistryHelp(): unknown { "service is host-managed by systemd + Docker Compose, not k3s-managed", "install writes the rendered host unit/config and starts the registry", "deploy-backend-core only pulls commit-pinned backend-core artifacts and does not build backend-core on the master server", - "deploy-service currently supports backend-core, baidu-netdisk, and decision-center as standardized consumers", + "deploy-service currently supports backend-core, baidu-netdisk, prod/dev frontend, and decision-center as standardized consumers", "status and health use provider-gateway Host SSH readonly checks", ], }; diff --git a/src/components/frontend/src/index.ts b/src/components/frontend/src/index.ts index bc2ddebf..0be29e81 100644 --- a/src/components/frontend/src/index.ts +++ b/src/components/frontend/src/index.ts @@ -151,7 +151,17 @@ function readNumberEnv(name: string): number { return parsed; } +function deployEnv(name: "REF" | "SERVICE_ID" | "REPO" | "COMMIT" | "REQUESTED_COMMIT"): string { + return process.env[`UNIDESK_FRONTEND_DEPLOY_${name}`]?.trim() + || process.env[`UNIDESK_DEPLOY_${name}`]?.trim() + || ""; +} + function readConfig(): RuntimeConfig { + const serviceId = deployEnv("SERVICE_ID") || "frontend"; + const repo = deployEnv("REPO"); + const commit = deployEnv("COMMIT"); + const requestedCommit = deployEnv("REQUESTED_COMMIT") || commit; return { port: readNumberEnv("PORT"), coreInternalUrl: requiredEnv("CORE_INTERNAL_URL"), @@ -166,17 +176,17 @@ function readConfig(): RuntimeConfig { environment: process.env.UNIDESK_ENV?.trim() || "prod", namespace: process.env.UNIDESK_NAMESPACE?.trim() || "", databaseName: process.env.UNIDESK_DATABASE_NAME?.trim() || process.env.UNIDESK_DEV_DATABASE_NAME?.trim() || "", - deployRef: process.env.UNIDESK_DEPLOY_REF?.trim() || "", - serviceId: process.env.UNIDESK_DEPLOY_SERVICE_ID?.trim() || "frontend", - repo: process.env.UNIDESK_DEPLOY_REPO?.trim() || "", - commit: process.env.UNIDESK_DEPLOY_COMMIT?.trim() || "", - requestedCommit: process.env.UNIDESK_DEPLOY_REQUESTED_COMMIT?.trim() || "", + deployRef: deployEnv("REF"), + serviceId, + repo, + commit, + requestedCommit, }, deploy: { - serviceId: process.env.UNIDESK_DEPLOY_SERVICE_ID || "frontend", - repo: process.env.UNIDESK_DEPLOY_REPO || "", - commit: process.env.UNIDESK_DEPLOY_COMMIT || "", - requestedCommit: process.env.UNIDESK_DEPLOY_REQUESTED_COMMIT || "", + serviceId, + repo, + commit, + requestedCommit, }, }; } diff --git a/src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-core.k8s.yaml b/src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-core.k8s.yaml index e21eda67..b850f83c 100644 --- a/src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-core.k8s.yaml +++ b/src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-core.k8s.yaml @@ -245,6 +245,8 @@ spec: key: SESSION_TTL_SECONDS - name: UNIDESK_DATABASE_NAME value: unidesk_dev + - name: UNIDESK_DEPLOY_REF + value: origin/master:deploy.json#environments.dev.services.frontend - name: UNIDESK_DEPLOY_SERVICE_ID value: frontend - name: UNIDESK_DEPLOY_REPO