**部署工作流（打包 → 上传/发布 → smoke‑test）**

- **目的**: 描述如何把本地 `uniCloud` 云函数项目自动化打包、上传并发布为可供后端调用的云函数；说明两种上传方式（直接调用上传 API / 使用 `unicloud` CLI）与 smoke‑test 验证流程；给出 CI 集成与常见故障排查建议。

- **目录结构（示例）**:
  - `uniCloud-alipay/cloudfunctions/<funcName>/` - 云函数源码目录（含 `index.js`、`package.json` 等）
  - `server/tools/deploy-cloudfunc.js` - 打包并上传/发布的脚本
  - `server/dist/` - 输出的 zip 文件目录

1) 打包

- 使用脚本 `server/tools/deploy-cloudfunc.js` 的默认行为：把指定云函数目录压缩为 zip（例如 `dist/testUnipush2.zip`）。
- 本地快速命令：
  ```bash
  # 只打包（不上传）
  node server/tools/deploy-cloudfunc.js --dir path/to/your/cloudfunctions/func
  ```

2) 上传 / 发布（两种方式，任选其一）

- A. 使用提供商“上传/发布”HTTP API（推荐用于无 CLI 的环境）
  - 要求：提供上传 URL（CLOUD_UPLOAD_URL 或 `--upload`）、必要的 token（CLOUD_UPLOAD_TOKEN）和可能的额外表单字段（例如 appId）。
  - 流程：脚本把 zip 作为 `multipart/form-data` POST 到上传端点；若上传端点返回仅是“已接收”而非“已发布”，还需调用发布/部署 API（CLOUD_DEPLOY_API 或 `--deployApi`）。
  - 注意：不要把 zip 发到函数的 invoke（调用）URL（例如 `/test`）。如果你把文件 POST 到 invoke URL，平台会把请求当作函数执行并返回业务错误（例如 `{"errCode":400,"errMsg":"push_clientid required"}`）。脚本内已添加检测，当响应看起来像 invoke 返回会立即报错并提示。

- B. 使用 `unicloud` CLI（简单且与 HBuilder 官方流程一致）
  - 前提：机器/CI 能安装并执行 `unicloud`，并已登录或有可用凭证。常用命令示例：
    ```bash
    unicloud upload -p <SPACE_ID> -f <FUNCTION_NAME> ./uniCloud-alipay/cloudfunctions/<FUNCTION_NAME>
    ```
  - 优点：不需要逆向抓包，等同于控制台发布，适合 CI。缺点：需在 CI 中安装 CLI 并处理登录。
  - 建议：在脚本中添加 CLI fallback，当未提供 `--upload` 时尝试调用 `unicloud upload`（脚本可接收 `--spaceId` 或环境变量 `CLOUD_UNICLOUD_SPACEID`）。

3) smoke‑test（发布后验证）

- 在上传/发布成功后，应通过函数的 invoke URL 做一次简单调用，验证函数行为（例如发送测试推送或返回 expected response）。脚本支持传入 `--invokeUrl` / `--funcInvokeUrl` 与 `--testCid` 做自动验证。
- 若 smoke‑test 失败：检查是否为 invoke URL 被误用为 upload URL、是否发布尚未完成、或权限/鉴权（token）问题。

4) CI 集成（GitHub Actions 示例思路）

- 步骤：
  1. Checkout 代码
  2. 安装依赖（若使用脚本中的 archiver/form-data/node-fetch）
  3. 若使用 CLI：安装 `unicloud` 并通过 secrets 登录（或在 runner 上提前配置 service account）
  4. 运行 `node server/tools/deploy-cloudfunc.js --upload ${{ secrets.CLOUD_UPLOAD_URL }} --invokeUrl ${{ secrets.CLOUD_FUNC_URL }} --testCid ${{ secrets.TEST_DEVICE_CID }}` 或运行 CLI fallback
  5. 检查返回码并在失败时标记 Job 失败

5) 必要环境变量与参数

- CLOUD_UPLOAD_URL / --upload : 上传 API URL（非函数 invoke URL）
- CLOUD_UPLOAD_TOKEN : 上传时使用的 Bearer token（或其它鉴权）
- CLOUD_DEPLOY_API / --deployApi : 若上传后需单独调用发布 API，可传入
- CLOUD_FUNC_URL / --invokeUrl : 发布后的函数调用 URL，用来做 smoke‑test
- TEST_DEVICE_CID / --testCid : 用于 push smoke‑test 的测试设备 CID
- CLOUD_UNICLOUD_SPACEID / --spaceId : 若使用 `unicloud` CLI 上传则为服务空间 ID

6) 常见问题与排查步骤

- 问：脚本返回 `Only absolute URLs are supported` 或 fetch 报错
  - 答：通常因为 `--upload` 使用但没有提供值；请改为 `--upload <URL>` 或设置 `CLOUD_UPLOAD_URL`。

- 问：上传后看到 `{"errCode":400,"errMsg":"push_clientid required"}`
  - 答：说明你把 zip POST 到了函数的 invoke URL（它把请求当作函数调用处理）。请提供正确的上传/发布 API 或使用 `unicloud upload` CLI 来发布。

- 排查建议：
  - 在 HBuilderX 的发布流程中打开 Network 面板，执行一次发布并抓取对应请求（记录 URL、method、form 字段、headers），把它贴到脚本配置中或发给维护者。
  - 在 PowerShell 或 Linux 上用 `curl -v` 验证上传端点返回内容，注意响应结构是否像“发布成功”而非函数执行结果。

7) 安全建议

- 把上传/发布的 token、spaceId、testCid 等放在 CI secrets 或受保护的环境变量中，避免写入代码库。
- 脚本中的自动部署入口应加鉴权（例如 `DEPLOY_BEARER`），不要在公网上暴露未经保护的上传接口。

8) 下一步（可选）

- 我可以把 `deploy-cloudfunc.js` 增加 `unicloud` CLI fallback（检测 `--spaceId` 或 `CLOUD_UNICLOUD_SPACEID` 并在没有 `--upload` 时调用 CLI），也可直接把你抓到的 HBuilder 上传请求模式接入脚本以实现完全自动化。请告知你偏好哪个方案。

-----------------

文件位置：server/DEPLOY_WORKFLOW.md
