Files
xgj/setup-opencode/action.yml
T
Lyda 0e3519f994 fix: 优化 setup-opencode action 的包安装验证逻辑,使用 npm list 替代命令检测
- 安装验证改用 npm list 检查包是否存在,避免包名与命令名不一致导致的误判
- 验证成功时显示已安装版本号,并尝试列出 bin 目录中的可用命令
- 版本检测逻辑简化,统一使用 npm list JSON 输出获取版本信息
- 优化错误提示,明确显示未找到的包名
- 移除备用的命令行版本检测方案,统一使用 npm 元数据
2026-03-17 16:31:03 +08:00

304 lines
10 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: 'Setup OpenCode'
description: '使用 npm 全局安装 OpenCode 并缓存,支持版本检测和自动更新'
author: 'Your Organization'
branding:
icon: 'code'
color: 'purple'
inputs:
version:
description: 'OpenCode 版本号(例如: 1.0.0, latest'
required: false
default: 'latest'
package-name:
description: 'npm 包名'
required: false
default: 'opencode-ai'
use-taobao-registry:
description: '使用淘宝 npm 镜像源 (true/false)'
required: false
default: 'false'
npm-registry:
description: '自定义 npm 镜像源地址'
required: false
default: ''
cache-prefix:
description: '缓存前缀名称'
required: false
default: 'opencode-npm'
skip-cache:
description: '跳过缓存,强制重新安装 (true/false)'
required: false
default: 'false'
outputs:
version:
description: '安装的 OpenCode 版本'
value: ${{ steps.get-version.outputs.version }}
cache-hit:
description: '缓存是否命中 (true/false)'
value: ${{ steps.cache-restore.outputs.cache-hit }}
updated:
description: '是否执行了更新 (true/false)'
value: ${{ steps.check-update.outputs.updated }}
runs:
using: 'composite'
steps:
- name: 验证输入参数
shell: bash
run: |
echo "🔍 验证输入参数..."
if [[ -z "${{ inputs.version }}" ]]; then
echo "❌ version 参数不能为空"
exit 1
fi
if [[ -z "${{ inputs.package-name }}" ]]; then
echo "❌ package-name 参数不能为空"
exit 1
fi
echo "✅ 输入参数验证通过"
echo " - npm 包名: ${{ inputs.package-name }}"
echo " - 版本: ${{ inputs.version }}"
echo " - 使用淘宝镜像: ${{ inputs.use-taobao-registry }}"
echo " - 跳过缓存: ${{ inputs.skip-cache }}"
- name: 配置 npm 镜像源
id: setup-registry
shell: bash
run: |
if [[ -n "${{ inputs.npm-registry }}" ]]; then
echo "🔧 使用自定义 npm 镜像源"
NPM_REGISTRY="${{ inputs.npm-registry }}"
echo " - 镜像源: ${NPM_REGISTRY}"
elif [[ "${{ inputs.use-taobao-registry }}" == "true" ]]; then
echo "🇨🇳 使用淘宝 npm 镜像源"
NPM_REGISTRY="https://registry.npmmirror.com"
echo " - 镜像源: ${NPM_REGISTRY}"
else
echo "🌍 使用默认 npm 镜像源"
NPM_REGISTRY=""
fi
echo "registry=${NPM_REGISTRY}" >> $GITHUB_OUTPUT
- name: 获取 npm 路径
id: npm-paths
shell: bash
run: |
NPM_PREFIX=$(npm config get prefix)
NPM_GLOBAL_ROOT=$(npm root -g)
echo "prefix=${NPM_PREFIX}" >> $GITHUB_OUTPUT
echo "global-root=${NPM_GLOBAL_ROOT}" >> $GITHUB_OUTPUT
echo "📁 npm 全局路径: ${NPM_PREFIX}"
echo "📦 npm 全局包路径: ${NPM_GLOBAL_ROOT}"
- name: 解析版本号
id: resolve-version
shell: bash
env:
NPM_CONFIG_REGISTRY: ${{ steps.setup-registry.outputs.registry }}
run: |
VERSION="${{ inputs.version }}"
PACKAGE="${{ inputs.package-name }}"
if [[ "${VERSION}" == "latest" ]]; then
echo "🔍 获取最新版本号..."
LATEST_VERSION=$(npm view ${PACKAGE} version 2>/dev/null || echo "")
if [[ -n "${LATEST_VERSION}" ]]; then
VERSION="${LATEST_VERSION}"
echo "✅ 最新版本: ${VERSION}"
else
echo "⚠️ 无法获取最新版本,使用 latest 标签"
VERSION="latest"
fi
fi
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "📌 目标版本: ${VERSION}"
- name: 生成缓存键
id: cache-key
shell: bash
run: |
VERSION="${{ steps.resolve-version.outputs.version }}"
PACKAGE="${{ inputs.package-name }}"
CACHE_KEY="${{ runner.os }}-${{ inputs.cache-prefix }}-${PACKAGE}-${VERSION}"
echo "key=${CACHE_KEY}" >> $GITHUB_OUTPUT
echo "🔑 缓存键: ${CACHE_KEY}"
- name: 恢复缓存
id: cache-restore
if: inputs.skip-cache != 'true'
uses: actions/cache/restore@v4
with:
path: |
~/.npm
${{ steps.npm-paths.outputs.global-root }}/${{ inputs.package-name }}
${{ steps.npm-paths.outputs.prefix }}/bin/${{ inputs.package-name }}
key: ${{ steps.cache-key.outputs.key }}
restore-keys: |
${{ runner.os }}-${{ inputs.cache-prefix }}-${{ inputs.package-name }}-
- name: 检查已安装版本
id: check-installed
shell: bash
run: |
PACKAGE="${{ inputs.package-name }}"
TARGET_VERSION="${{ steps.resolve-version.outputs.version }}"
NEED_INSTALL="true"
if command -v $PACKAGE &> /dev/null; then
# 使用 JSON 格式获取版本信息,更可靠
INSTALLED_INFO=$(npm list -g $PACKAGE --json --depth=0 2>/dev/null || echo '{}')
INSTALLED_VERSION=$(echo "${INSTALLED_INFO}" | grep -o '"version":"[^"]*"' | head -1 | cut -d'"' -f4 || echo "unknown")
echo "📦 已安装版本: ${INSTALLED_VERSION}"
echo "🎯 目标版本: ${TARGET_VERSION}"
if [[ "${INSTALLED_VERSION}" == "${TARGET_VERSION}" ]]; then
NEED_INSTALL="false"
echo "✅ 版本匹配,无需重新安装"
elif [[ "${INSTALLED_VERSION}" != "unknown" ]]; then
echo "⚠️ 版本不匹配,需要更新"
fi
else
echo "⚠️ 未安装 ${PACKAGE}"
fi
echo "need-install=${NEED_INSTALL}" >> $GITHUB_OUTPUT
- name: 安装 OpenCode
if: steps.check-installed.outputs.need-install == 'true'
shell: bash
env:
NPM_CONFIG_REGISTRY: ${{ steps.setup-registry.outputs.registry }}
run: |
PACKAGE="${{ inputs.package-name }}"
VERSION="${{ steps.resolve-version.outputs.version }}"
INSTALL_SPEC="${PACKAGE}@${VERSION}"
echo "📥 安装 ${INSTALL_SPEC}..."
# 重试机制:最多尝试 3 次
MAX_RETRIES=3
RETRY_COUNT=0
while [[ ${RETRY_COUNT} -lt ${MAX_RETRIES} ]]; do
if npm install -g "${INSTALL_SPEC}" --no-audit --no-fund; then
echo "✅ 安装成功"
break
else
RETRY_COUNT=$((RETRY_COUNT + 1))
if [[ ${RETRY_COUNT} -lt ${MAX_RETRIES} ]]; then
echo "⚠️ 安装失败,等待 3 秒后重试 (${RETRY_COUNT}/${MAX_RETRIES})..."
sleep 3
else
echo "❌ 安装失败,已重试 ${MAX_RETRIES} 次"
exit 1
fi
fi
done
- name: 验证安装
id: verify-install
if: steps.check-installed.outputs.need-install == 'true'
shell: bash
run: |
PACKAGE="${{ inputs.package-name }}"
# 通过 npm list 检查包是否安装,而不是检查命令(因为包名和命令名可能不同)
INSTALLED_INFO=$(npm list -g $PACKAGE --json --depth=0 2>/dev/null || echo '{}')
INSTALLED_VERSION=$(echo "${INSTALLED_INFO}" | grep -o '"version":"[^"]*"' | head -1 | cut -d'"' -f4 || echo "")
if [[ -n "${INSTALLED_VERSION}" ]]; then
echo "install-verified=true" >> $GITHUB_OUTPUT
echo "✅ 安装验证成功 - 版本: ${INSTALLED_VERSION}"
# 尝试查找实际的命令名
BIN_DIR="${{ steps.npm-paths.outputs.prefix }}/bin"
if [[ -d "${BIN_DIR}" ]]; then
COMMANDS=$(ls -1 "${BIN_DIR}" 2>/dev/null | grep -i opencode || echo "")
if [[ -n "${COMMANDS}" ]]; then
echo "📦 可用命令: ${COMMANDS}"
fi
fi
else
echo "install-verified=false" >> $GITHUB_OUTPUT
echo "❌ 安装验证失败 - 未找到包 ${PACKAGE}"
exit 1
fi
- name: 保存缓存
if: steps.check-installed.outputs.need-install == 'true' && steps.verify-install.outputs.install-verified == 'true' && inputs.skip-cache != 'true'
uses: actions/cache/save@v4
with:
path: |
~/.npm
${{ steps.npm-paths.outputs.global-root }}/${{ inputs.package-name }}
${{ steps.npm-paths.outputs.prefix }}/bin/${{ inputs.package-name }}
key: ${{ steps.cache-key.outputs.key }}
- name: 获取安装版本
id: get-version
shell: bash
run: |
PACKAGE="${{ inputs.package-name }}"
# 使用 JSON 格式获取版本,更可靠
INSTALLED_INFO=$(npm list -g $PACKAGE --json --depth=0 2>/dev/null || echo '{}')
VERSION=$(echo "${INSTALLED_INFO}" | grep -o '"version":"[^"]*"' | head -1 | cut -d'"' -f4 || echo "unknown")
if [[ "${VERSION}" != "unknown" ]]; then
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "✅ OpenCode 版本: ${VERSION}"
else
echo "version=unknown" >> $GITHUB_OUTPUT
echo "⚠️ 无法获取 OpenCode 版本"
fi
- name: 检查更新状态
id: check-update
shell: bash
run: |
if [[ "${{ steps.check-installed.outputs.need-install }}" == "true" ]]; then
echo "updated=true" >> $GITHUB_OUTPUT
echo "🔄 已安装新版本"
else
echo "updated=false" >> $GITHUB_OUTPUT
echo "📌 使用已安装版本,未执行更新"
fi
- name: 安装总结
shell: bash
run: |
echo "📊 OpenCode 安装总结:"
echo " - npm 包名: ${{ inputs.package-name }}"
echo " - 安装版本: ${{ steps.get-version.outputs.version }}"
echo " - 缓存命中: ${{ steps.cache-restore.outputs.cache-hit }}"
echo " - 执行更新: ${{ steps.check-update.outputs.updated }}"
echo " - 缓存键名: ${{ steps.cache-key.outputs.key }}"
if [[ "${{ steps.check-update.outputs.updated }}" == "true" ]]; then
echo " 🔄 已通过 npm 安装新版本"
else
echo " ✅ 使用已安装版本,跳过安装"
fi
echo ""
echo "🎉 OpenCode 已准备就绪!"