Files
xgj/setup-opencode/action.yml
T
Lyda 489cc94316 feat: 新增 setup-opencode action,支持 npm 全局安装和智能缓存
- 使用 npm 全局安装 OpenCode,支持版本管理和自动更新
- 智能缓存策略:缓存 npm 目录和全局安装,加速后续构建
- 支持淘宝镜像源和自定义 npm 镜像,国内环境友好
- 版本检测:自动比对已安装版本,避免重复安装
- 输出安装版本、缓存命中状态和更新状态
- 提供详细的使用文档和多场景示例
2026-03-17 16:17:03 +08:00

296 lines
9.8 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'
use-taobao-registry:
description: '使用淘宝 npm 镜像源 (true/false)'
required: false
default: 'true'
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 }}"
if command -v $PACKAGE &> /dev/null; then
echo "install-verified=true" >> $GITHUB_OUTPUT
echo "✅ 安装验证成功"
else
echo "install-verified=false" >> $GITHUB_OUTPUT
echo "❌ 安装验证失败"
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 }}"
if command -v $PACKAGE &> /dev/null; then
# 使用 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
# 备用方案:直接运行命令获取版本
VERSION=$($PACKAGE --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || echo "unknown")
fi
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 已准备就绪!"