跳到主要内容

退出码

CloudBase CLI 使用结构化退出码(Exit Codes)来表示命令执行结果,便于 CI/CD 流水线、脚本和自动化工具进行错误处理和重试决策。

为什么需要退出码?

退出码是 Unix/Linux 进程的标准机制,用于告诉调用者命令是否成功以及失败原因的分类:

1. CI/CD 流程控制

# GitHub Actions 示例
- name: Deploy function
run: tcb fn deploy app --env-id ${{ secrets.ENV_ID }}
continue-on-error: false # 非 0 退出码会中断流水线

2. Shell 脚本错误处理

#!/bin/bash
set -e # 遇到非 0 退出码立即退出

tcb fn deploy app --env-id my-env
if [ $? -eq 2 ]; then
echo "认证失败,请重新登录"
tcb login
fi

3. 条件执行和重试

# 仅当函数部署成功时,才部署静态资源
tcb fn deploy && tcb hosting deploy

# 认证失败时自动重试登录
tcb fn list || (tcb login && tcb fn list)

4. 自动化测试

# 测试脚本验证 CLI 行为
tcb fn delete non-existent-func
EXIT_CODE=$?
if [ $EXIT_CODE -eq 4 ]; then
echo "✅ 资源不存在错误码正确"
else
echo "❌ 期望退出码 4,实际 $EXIT_CODE"
exit 1
fi

退出码定义

退出码语义触发场景建议处理方式
0成功命令正常执行完成继续下一步
1通用错误未分类的错误(兜底)查看错误信息,手动排查
2认证失败未登录、Token 过期、无权限执行 tcb login 重新登录
3参数错误缺少必填参数、格式错误、枚举值非法检查命令参数,参考 --help
4资源不存在函数名/环境 ID 无效、集合不存在等确认资源名称是否正确
5云 API 错误CloudBase API 返回错误、网络超时检查网络连接,查看 --verbose 日志
6本地文件错误cloudbaserc.json 缺失/损坏、路径不存在检查配置文件和路径

使用场景

场景 1: 条件执行

# 仅当函数部署成功时,才部署静态资源
tcb fn deploy app && tcb hosting deploy

场景 2: 错误捕获与处理

#!/bin/bash

tcb fn deploy app --env-id my-env
EXIT_CODE=$?

case $EXIT_CODE in
0)
echo "✅ 部署成功"
;;
2)
echo "❌ 认证失败,请重新登录"
tcb login
;;
3)
echo "❌ 参数错误,请检查命令"
exit 1
;;
4)
echo "❌ 资源不存在"
exit 1
;;
5)
echo "⚠️ 云 API 错误,5 秒后重试..."
sleep 5
tcb fn deploy app --env-id my-env
;;
*)
echo "❌ 未知错误(退出码 $EXIT_CODE)"
exit 1
;;
esac

场景 3: 重试机制

#!/bin/bash

MAX_RETRIES=3
RETRY_DELAY=5

for i in $(seq 1 $MAX_RETRIES); do
tcb fn deploy app --env-id my-env
EXIT_CODE=$?

if [ $EXIT_CODE -eq 0 ]; then
echo "✅ 部署成功"
exit 0
elif [ $EXIT_CODE -eq 5 ]; then
echo "⚠️ 云 API 错误,$RETRY_DELAY 秒后重试(第 $i/$MAX_RETRIES 次)"
sleep $RETRY_DELAY
else
echo "❌ 不可重试的错误(退出码 $EXIT_CODE)"
exit $EXIT_CODE
fi
done

echo "❌ 重试 $MAX_RETRIES 次后仍失败"
exit 1

场景 4: 批量操作

#!/bin/bash

FUNCTIONS=("func1" "func2" "func3")
FAILED=()

for func in "${FUNCTIONS[@]}"; do
tcb fn deploy "$func" --yes
if [ $? -ne 0 ]; then
FAILED+=("$func")
fi
done

if [ ${#FAILED[@]} -gt 0 ]; then
echo "❌ 以下函数部署失败:"
printf '%s\n' "${FAILED[@]}"
exit 1
else
echo "✅ 所有函数部署成功"
fi

场景 5: Makefile

.PHONY: deploy test clean

deploy:
@echo "部署函数..."
@tcb fn deploy app --env-id $(ENV_ID)
@echo "部署静态资源..."
@tcb hosting deploy --env-id $(ENV_ID)

test:
@echo "运行测试..."
@tcb fn invoke app --env-id $(ENV_ID) --data '{"test": true}'
@if [ $$? -eq 0 ]; then \
echo "✅ 测试通过"; \
else \
echo "❌ 测试失败"; \
exit 1; \
fi

clean:
@echo "清理资源..."
@tcb fn delete app --yes --env-id $(ENV_ID) || true

CI/CD 最佳实践

GitHub Actions

name: Deploy to CloudBase

on:
push:
branches: [main]

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'

- name: Install CloudBase CLI
run: npm install -g @cloudbase/cli

- name: Login to CloudBase
run: |
echo "${{ secrets.CLOUDBASE_SECRET_ID }}" > /tmp/secret_id
echo "${{ secrets.CLOUDBASE_SECRET_KEY }}" > /tmp/secret_key
tcb login --key --secretId $(cat /tmp/secret_id) --secretKey $(cat /tmp/secret_key)

- name: Deploy Function
id: deploy
run: |
tcb fn deploy app --env-id ${{ secrets.ENV_ID }} --json --yes
continue-on-error: true

- name: Handle Deployment Result
if: failure()
run: |
EXIT_CODE=${{ steps.deploy.outcome }}
if [ "$EXIT_CODE" = "2" ]; then
echo "认证失败,检查密钥配置"
exit 1
elif [ "$EXIT_CODE" = "5" ]; then
echo "云 API 错误,5 秒后重试"
sleep 5
tcb fn deploy app --env-id ${{ secrets.ENV_ID }} --json --yes
else
echo "部署失败(退出码 $EXIT_CODE)"
exit 1
fi

GitLab CI

deploy:
stage: deploy
image: node:18
script:
- npm install -g @cloudbase/cli
- tcb login --key --secretId $SECRET_ID --secretKey $SECRET_KEY
- tcb fn deploy app --env-id $ENV_ID --json --yes
retry:
max: 2
when:
- script_failure # 仅在脚本失败时重试
only:
- main

Jenkins

pipeline {
agent any

stages {
stage('Deploy') {
steps {
script {
def result = sh(
script: 'tcb fn deploy app --env-id ${ENV_ID} --json --yes',
returnStatus: true
)

if (result == 0) {
echo '✅ 部署成功'
} else if (result == 2) {
error '❌ 认证失败,检查密钥配置'
} else if (result == 5) {
echo '⚠️ 云 API 错误,重试中...'
sleep 5
sh 'tcb fn deploy app --env-id ${ENV_ID} --json --yes'
} else {
error "❌ 部署失败(退出码 ${result})"
}
}
}
}
}
}

调试方法

1. 查看退出码

tcb fn deploy app
echo "退出码: $?"

2. 使用 --verbose 查看详细日志

tcb fn deploy app --verbose

3. 使用 --json 获取结构化错误信息

tcb fn deploy app --json

输出示例

{
"error": {
"code": "FUNCTION_NOT_FOUND",
"message": "函数 app 不存在",
"exit_code": 4
}
}

注意事项

  1. 退出码不是 HTTP 状态码
    退出码 4 表示"资源不存在",不是 HTTP 404。退出码 5 表示"云 API 错误",不是 HTTP 500。

  2. --yes 不影响退出码
    --yes 只跳过确认提示,不改变命令的执行结果和退出码。

  3. 管道操作需要 set -e
    在 Shell 脚本中,使用 set -e 确保管道中的任何命令失败都会中断执行:

    #!/bin/bash
    set -e # 遇到非 0 退出码立即退出

    tcb fn deploy app
    tcb hosting deploy
  4. CI/CD 中建议使用 --json
    --json 输出结构化数据,便于解析错误信息和提取字段。


参考资料