Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 595d906213 | |||
| ff48b8a3e8 | |||
| 520bc406f4 | |||
| d4720de1a5 | |||
| cad99bbfc5 | |||
| df3a7e1eba | |||
| dc525a04b6 | |||
| 1aa9b20a79 | |||
| 4609366c51 | |||
| 3d246034c0 | |||
| bf094b92dd | |||
| b3ca961260 | |||
| ea1c69a371 | |||
| dfcf7e8c22 | |||
| 017d6705a2 | |||
| 12d3d5dc0d |
@@ -1,261 +0,0 @@
|
||||
name: Test Setup OpenCode Action
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, develop ]
|
||||
paths:
|
||||
- 'setup-opencode/**'
|
||||
- '.github/workflows/test-setup-opencode.yml'
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
paths:
|
||||
- 'setup-opencode/**'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
test-basic-install:
|
||||
name: 测试基础安装
|
||||
runs-on: ci-node-22
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 安装 OpenCode
|
||||
id: setup
|
||||
uses: ./setup-opencode
|
||||
with:
|
||||
version: 'latest'
|
||||
|
||||
- name: 验证安装
|
||||
run: |
|
||||
echo "安装版本: ${{ steps.setup.outputs.version }}"
|
||||
echo "缓存命中: ${{ steps.setup.outputs.cache-hit }}"
|
||||
echo "执行更新: ${{ steps.setup.outputs.updated }}"
|
||||
|
||||
# 验证命令是否可用
|
||||
if command -v opencode &> /dev/null; then
|
||||
echo "✅ opencode 命令可用"
|
||||
opencode --version || echo "⚠️ 无法获取版本信息(这是正常的,因为 opencode 可能不是真实的包)"
|
||||
else
|
||||
echo "❌ opencode 命令不可用"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
test-specific-version:
|
||||
name: 测试指定版本
|
||||
runs-on: ci-node-22
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 安装 OpenCode 指定版本
|
||||
id: setup
|
||||
uses: ./setup-opencode
|
||||
with:
|
||||
version: '1.0.0'
|
||||
|
||||
- name: 验证版本
|
||||
run: |
|
||||
echo "安装版本: ${{ steps.setup.outputs.version }}"
|
||||
|
||||
if [[ "${{ steps.setup.outputs.version }}" == "1.0.0" ]]; then
|
||||
echo "✅ 版本匹配"
|
||||
else
|
||||
echo "⚠️ 版本不匹配,但这可能是因为包不存在"
|
||||
fi
|
||||
|
||||
test-taobao-registry:
|
||||
name: 测试淘宝镜像源
|
||||
runs-on: ci-node-22
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 使用淘宝镜像安装
|
||||
id: setup
|
||||
uses: ./setup-opencode
|
||||
with:
|
||||
version: 'latest'
|
||||
use-taobao-registry: 'true'
|
||||
|
||||
- name: 验证安装
|
||||
run: |
|
||||
echo "安装版本: ${{ steps.setup.outputs.version }}"
|
||||
echo "缓存命中: ${{ steps.setup.outputs.cache-hit }}"
|
||||
|
||||
test-custom-registry:
|
||||
name: 测试自定义镜像源
|
||||
runs-on: ci-node-22
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 使用自定义镜像源
|
||||
id: setup
|
||||
uses: ./setup-opencode
|
||||
with:
|
||||
version: 'latest'
|
||||
npm-registry: 'https://registry.npmmirror.com'
|
||||
|
||||
- name: 验证安装
|
||||
run: |
|
||||
echo "安装版本: ${{ steps.setup.outputs.version }}"
|
||||
|
||||
test-cache:
|
||||
name: 测试缓存功能
|
||||
runs-on: ci-node-22
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 第一次安装
|
||||
id: first-install
|
||||
uses: ./setup-opencode
|
||||
with:
|
||||
version: 'latest'
|
||||
|
||||
- name: 验证第一次安装
|
||||
run: |
|
||||
echo "第一次安装 - 缓存命中: ${{ steps.first-install.outputs.cache-hit }}"
|
||||
echo "第一次安装 - 执行更新: ${{ steps.first-install.outputs.updated }}"
|
||||
|
||||
if [[ "${{ steps.first-install.outputs.cache-hit }}" == "true" ]]; then
|
||||
echo "✅ 缓存命中(可能是之前的运行)"
|
||||
else
|
||||
echo "✅ 首次安装,未命中缓存"
|
||||
fi
|
||||
|
||||
- name: 第二次安装(应该使用缓存)
|
||||
id: second-install
|
||||
uses: ./setup-opencode
|
||||
with:
|
||||
version: 'latest'
|
||||
|
||||
- name: 验证第二次安装
|
||||
run: |
|
||||
echo "第二次安装 - 缓存命中: ${{ steps.second-install.outputs.cache-hit }}"
|
||||
echo "第二次安装 - 执行更新: ${{ steps.second-install.outputs.updated }}"
|
||||
|
||||
if [[ "${{ steps.second-install.outputs.updated }}" == "false" ]]; then
|
||||
echo "✅ 正确使用了已安装的版本"
|
||||
else
|
||||
echo "⚠️ 重新安装了(可能版本不同)"
|
||||
fi
|
||||
|
||||
test-skip-cache:
|
||||
name: 测试跳过缓存
|
||||
runs-on: ci-node-22
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 跳过缓存安装
|
||||
id: setup
|
||||
uses: ./setup-opencode
|
||||
with:
|
||||
version: 'latest'
|
||||
skip-cache: 'true'
|
||||
|
||||
- name: 验证安装
|
||||
run: |
|
||||
echo "安装版本: ${{ steps.setup.outputs.version }}"
|
||||
echo "缓存命中: ${{ steps.setup.outputs.cache-hit }}"
|
||||
|
||||
if [[ "${{ steps.setup.outputs.cache-hit }}" == "false" || "${{ steps.setup.outputs.cache-hit }}" == "" ]]; then
|
||||
echo "✅ 正确跳过了缓存"
|
||||
else
|
||||
echo "⚠️ 未跳过缓存"
|
||||
fi
|
||||
|
||||
test-custom-package:
|
||||
name: 测试自定义包名
|
||||
runs-on: ci-node-22
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 安装真实的 npm 包(用于测试)
|
||||
id: setup
|
||||
uses: ./setup-opencode
|
||||
with:
|
||||
package-name: 'cowsay'
|
||||
version: 'latest'
|
||||
|
||||
- name: 验证安装
|
||||
run: |
|
||||
echo "安装版本: ${{ steps.setup.outputs.version }}"
|
||||
|
||||
if command -v cowsay &> /dev/null; then
|
||||
echo "✅ cowsay 安装成功"
|
||||
cowsay "Setup OpenCode Action 测试成功!"
|
||||
else
|
||||
echo "❌ cowsay 未安装"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
test-matrix:
|
||||
name: 测试多版本矩阵
|
||||
runs-on: ci-node-22
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [18, 20]
|
||||
package: ['cowsay', 'figlet']
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 设置 Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: 安装 ${{ matrix.package }}
|
||||
id: setup
|
||||
uses: ./setup-opencode
|
||||
with:
|
||||
package-name: ${{ matrix.package }}
|
||||
version: 'latest'
|
||||
|
||||
- name: 验证安装
|
||||
run: |
|
||||
echo "Node.js 版本: $(node --version)"
|
||||
echo "npm 版本: $(npm --version)"
|
||||
echo "安装的包: ${{ matrix.package }}"
|
||||
echo "包版本: ${{ steps.setup.outputs.version }}"
|
||||
|
||||
if command -v ${{ matrix.package }} &> /dev/null; then
|
||||
echo "✅ ${{ matrix.package }} 安装成功"
|
||||
else
|
||||
echo "❌ ${{ matrix.package }} 未安装"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
test-summary:
|
||||
name: 测试总结
|
||||
runs-on: ci-node-22
|
||||
needs:
|
||||
- test-basic-install
|
||||
- test-specific-version
|
||||
- test-taobao-registry
|
||||
- test-custom-registry
|
||||
- test-cache
|
||||
- test-skip-cache
|
||||
- test-custom-package
|
||||
- test-matrix
|
||||
if: always()
|
||||
steps:
|
||||
- name: 测试结果总结
|
||||
run: |
|
||||
echo "## 🎉 Setup OpenCode Action 测试完成"
|
||||
echo ""
|
||||
echo "### 测试项目:"
|
||||
echo "- ✅ 基础安装"
|
||||
echo "- ✅ 指定版本"
|
||||
echo "- ✅ 淘宝镜像源"
|
||||
echo "- ✅ 自定义镜像源"
|
||||
echo "- ✅ 缓存功能"
|
||||
echo "- ✅ 跳过缓存"
|
||||
echo "- ✅ 自定义包名"
|
||||
echo "- ✅ 多版本矩阵"
|
||||
echo ""
|
||||
echo "所有测试已执行完成!"
|
||||
+31
-35
@@ -1,58 +1,58 @@
|
||||
name: "Configure Build Environment"
|
||||
description: "验证已有环境并配置 Git 与 kubectl(不执行软件安装)"
|
||||
author: "Your Organization"
|
||||
name: 'Configure Build Environment'
|
||||
description: '验证已有环境并配置 Git 与 kubectl(不执行软件安装)'
|
||||
author: 'Your Organization'
|
||||
|
||||
branding:
|
||||
icon: "settings"
|
||||
color: "green"
|
||||
icon: 'settings'
|
||||
color: 'green'
|
||||
|
||||
inputs:
|
||||
git-user-name:
|
||||
description: "Git 用户名"
|
||||
description: 'Git 用户名'
|
||||
required: false
|
||||
default: "GiteaActions"
|
||||
default: 'GiteaActions'
|
||||
git-user-email:
|
||||
description: "Git 用户邮箱"
|
||||
description: 'Git 用户邮箱'
|
||||
required: false
|
||||
default: "xgj-actions@xmail.bjxgj.com"
|
||||
default: 'xgj-actions@xmail.bjxgj.com'
|
||||
kube-config:
|
||||
description: "Base64 编码的 kubectl 配置文件"
|
||||
description: 'Base64 编码的 kubectl 配置文件'
|
||||
required: false
|
||||
default: ""
|
||||
default: ''
|
||||
enable-validation:
|
||||
description: "是否执行环境校验 (true/false)"
|
||||
description: '是否执行环境校验 (true/false)'
|
||||
required: false
|
||||
default: "false"
|
||||
default: 'true'
|
||||
docker-registry:
|
||||
description: "Docker 私有仓库地址"
|
||||
description: 'Docker 私有仓库地址'
|
||||
required: false
|
||||
default: "docker-registry.bjxgj.com"
|
||||
default: 'docker-registry.bjxgj.com'
|
||||
docker-username:
|
||||
description: "Docker 仓库用户名"
|
||||
description: 'Docker 仓库用户名'
|
||||
required: false
|
||||
default: "GiteaDocker"
|
||||
default: 'GiteaDocker'
|
||||
docker-password:
|
||||
description: "Docker 仓库密码(开启登录时必填)"
|
||||
description: 'Docker 仓库密码(开启登录时必填)'
|
||||
required: false
|
||||
default: ""
|
||||
default: ''
|
||||
skip-docker-login:
|
||||
description: "是否跳过 Docker 登录 (true/false)"
|
||||
description: '是否跳过 Docker 登录 (true/false)'
|
||||
required: false
|
||||
default: "false"
|
||||
default: 'false'
|
||||
|
||||
outputs:
|
||||
docker-version:
|
||||
description: "检测到的 Docker 版本"
|
||||
description: '检测到的 Docker 版本'
|
||||
value: ${{ steps.validate-tools.outputs.docker-version }}
|
||||
kubectl-version:
|
||||
description: "检测到的 kubectl 版本"
|
||||
description: '检测到的 kubectl 版本'
|
||||
value: ${{ steps.validate-tools.outputs.kubectl-version }}
|
||||
kubectl-context:
|
||||
description: "验证通过时的当前 kubectl 上下文"
|
||||
description: '验证通过时的当前 kubectl 上下文'
|
||||
value: ${{ steps.verify-kubectl.outputs.current-context }}
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: 配置 Git
|
||||
shell: bash
|
||||
@@ -69,7 +69,7 @@ runs:
|
||||
ENABLE_VALIDATION: ${{ inputs.enable-validation }}
|
||||
|
||||
- name: 配置 kubectl
|
||||
if: ${{ inputs.kube-config != '' && steps.validate-tools.outputs.kubectl-version != 'not-found' }}
|
||||
if: ${{ inputs.kube-config != '' }}
|
||||
shell: bash
|
||||
run: bash ${{ github.action_path }}/scripts/configure-kubectl.sh
|
||||
env:
|
||||
@@ -77,12 +77,12 @@ runs:
|
||||
|
||||
- name: 验证 kubectl 连通性
|
||||
id: verify-kubectl
|
||||
if: ${{ inputs.kube-config != '' && inputs.enable-validation != 'false' && steps.validate-tools.outputs.kubectl-version != 'not-found' && steps.validate-tools.outputs.kubectl-version != 'skipped' }}
|
||||
if: ${{ inputs.kube-config != '' && inputs.enable-validation != 'false' }}
|
||||
shell: bash
|
||||
run: bash ${{ github.action_path }}/scripts/verify-kubectl.sh
|
||||
|
||||
- name: 登录私有 Docker 仓库
|
||||
if: ${{ inputs.skip-docker-login != 'true' && steps.validate-tools.outputs.docker-version != 'not-found' }}
|
||||
if: ${{ inputs.skip-docker-login != 'true' }}
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ inputs.docker-registry }}
|
||||
@@ -94,13 +94,9 @@ runs:
|
||||
run: |
|
||||
echo '🎉 环境校验与配置步骤完成'
|
||||
if [[ "${{ inputs.enable-validation }}" != 'false' ]]; then
|
||||
if [[ "${{ steps.validate-tools.outputs.docker-version }}" != 'not-found' && "${{ steps.validate-tools.outputs.docker-version }}" != 'skipped' ]]; then
|
||||
echo " - Docker: ${{ steps.validate-tools.outputs.docker-version }}"
|
||||
fi
|
||||
if [[ "${{ steps.validate-tools.outputs.kubectl-version }}" != 'not-found' && "${{ steps.validate-tools.outputs.kubectl-version }}" != 'skipped' ]]; then
|
||||
echo " - kubectl: ${{ steps.validate-tools.outputs.kubectl-version }}"
|
||||
fi
|
||||
echo " - Docker: ${{ steps.validate-tools.outputs.docker-version }}"
|
||||
echo " - kubectl: ${{ steps.validate-tools.outputs.kubectl-version }}"
|
||||
fi
|
||||
if [[ "${{ inputs.kube-config }}" != '' && "${{ inputs.enable-validation }}" != 'false' && "${{ steps.verify-kubectl.outputs.current-context }}" != '' ]]; then
|
||||
if [[ "${{ inputs.kube-config }}" != '' && "${{ inputs.enable-validation }}" != 'false' ]]; then
|
||||
echo " - 当前上下文: ${{ steps.verify-kubectl.outputs.current-context }}"
|
||||
fi
|
||||
|
||||
@@ -58,7 +58,7 @@ validate_binary() {
|
||||
main() {
|
||||
: "${GITHUB_OUTPUT:?GITHUB_OUTPUT 未设置}" >/dev/null
|
||||
|
||||
local enable_validation="${ENABLE_VALIDATION:-false}"
|
||||
local enable_validation="${ENABLE_VALIDATION:-true}"
|
||||
|
||||
if [[ "$enable_validation" != "true" ]]; then
|
||||
log_info "已通过统一开关禁用环境校验"
|
||||
@@ -67,7 +67,6 @@ main() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
# 当 enable-validation 为 true 时,Docker 和 kubectl 都是必需的
|
||||
validate_binary "docker" "true" "docker --version" "docker-version"
|
||||
validate_binary "kubectl" "true" "kubectl version --client --short 2>/dev/null || kubectl version --client" "kubectl-version"
|
||||
}
|
||||
|
||||
+55
-145
@@ -6,14 +6,9 @@ branding:
|
||||
|
||||
inputs:
|
||||
cache-prefix:
|
||||
description: '缓存前缀名称(留空则自动使用项目名)'
|
||||
description: '缓存前缀名称'
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
cache-hash:
|
||||
description: '缓存hash值(留空则自动使用 pnpm-lock.yaml 或 package.json)'
|
||||
required: false
|
||||
default: ''
|
||||
default: 'modules'
|
||||
|
||||
force-install:
|
||||
description: '是否强制安装 (true/false)'
|
||||
@@ -30,10 +25,10 @@ inputs:
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
strict-lockfile-check:
|
||||
description: '严格检查 lockfile 是否被修改 (true/false)'
|
||||
cache-hash:
|
||||
description: '缓存hash值(推荐使用hashFiles)'
|
||||
required: false
|
||||
default: 'true'
|
||||
default: ''
|
||||
|
||||
clean-project-store:
|
||||
description: '安装后清理项目根目录的 .pnpm-store (true/false)'
|
||||
@@ -60,17 +55,15 @@ runs:
|
||||
id: detect
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if ! command -v pnpm >/dev/null 2>&1; then
|
||||
echo "❌ pnpm 未安装,请先使用 pnpm/action-setup 安装" >&2
|
||||
echo "pnpm 未安装"
|
||||
exit 1
|
||||
fi
|
||||
VERSION=$(pnpm --version 2>/dev/null | tr -d '\n' | tr -d '\r')
|
||||
VERSION=$(pnpm --version | tr -d '\n')
|
||||
if [[ -z "$VERSION" ]]; then
|
||||
echo "❌ 无法获取 pnpm 版本" >&2
|
||||
echo "无法获取pnpm版本"
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ 检测到 pnpm 版本: $VERSION"
|
||||
echo "pnpm-version=${VERSION}" >> "$GITHUB_OUTPUT"
|
||||
echo "PNPM_VERSION=${VERSION}" >> "$GITHUB_ENV"
|
||||
|
||||
@@ -79,60 +72,27 @@ runs:
|
||||
shell: bash
|
||||
env:
|
||||
PNPM_VERSION: ${{ steps.detect.outputs.pnpm-version }}
|
||||
LOCKFILE_HASH: ${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
PACKAGE_HASH: ${{ hashFiles('**/package.json') }}
|
||||
FALLBACK_HASH: ${{ hashFiles('pnpm-lock.yaml') }}
|
||||
PACKAGE_HASH: ${{ hashFiles('package.json') }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
# 智能选择最佳 hash 策略
|
||||
if [[ -n "${{ inputs.cache-hash }}" ]]; then
|
||||
CACHE_HASH="${{ inputs.cache-hash }}"
|
||||
HASH_SOURCE="custom"
|
||||
elif [[ -n "${LOCKFILE_HASH}" ]]; then
|
||||
CACHE_HASH="${LOCKFILE_HASH}"
|
||||
HASH_SOURCE="pnpm-lock.yaml"
|
||||
elif [[ -n "${FALLBACK_HASH}" ]]; then
|
||||
CACHE_HASH="${FALLBACK_HASH}"
|
||||
elif [[ -n "${PACKAGE_HASH}" ]]; then
|
||||
CACHE_HASH="${PACKAGE_HASH}"
|
||||
HASH_SOURCE="package.json"
|
||||
else
|
||||
CACHE_HASH=""
|
||||
HASH_SOURCE="none"
|
||||
fi
|
||||
|
||||
# 生成简短的 hash 用于 key
|
||||
if [[ -n "$CACHE_HASH" ]]; then
|
||||
CACHE_HASH_SHORT=$(echo "$CACHE_HASH" | head -c 12)
|
||||
else
|
||||
CACHE_HASH_SHORT="no-lock"
|
||||
CACHE_HASH_SHORT="no-hash"
|
||||
fi
|
||||
|
||||
# 智能获取缓存前缀
|
||||
if [[ -n "${{ inputs.cache-prefix }}" ]]; then
|
||||
CACHE_PREFIX="${{ inputs.cache-prefix }}"
|
||||
else
|
||||
# 获取当前工作目录相对于仓库根目录的路径,避免 monorepo 子包冲突
|
||||
REPO_ROOT="$GITHUB_WORKSPACE"
|
||||
CURRENT_DIR="$(pwd)"
|
||||
|
||||
# 计算相对路径
|
||||
if [[ "$CURRENT_DIR" == "$REPO_ROOT" ]]; then
|
||||
# 在仓库根目录,使用仓库名
|
||||
CACHE_PREFIX=$(basename "$REPO_ROOT" 2>/dev/null || echo "project")
|
||||
else
|
||||
# 在子目录,使用相对路径(替换 / 为 -)
|
||||
REL_PATH="${CURRENT_DIR#$REPO_ROOT/}"
|
||||
CACHE_PREFIX=$(echo "$REL_PATH" | tr '/' '-')
|
||||
fi
|
||||
fi
|
||||
|
||||
# 构建缓存 key
|
||||
CACHE_KEY="${{ runner.os }}-${CACHE_PREFIX}-pnpm-v${PNPM_VERSION}-${CACHE_HASH_SHORT}"
|
||||
RESTORE_PREFIX="${{ runner.os }}-${CACHE_PREFIX}-pnpm-v${PNPM_VERSION}-"
|
||||
|
||||
echo "📝 缓存 key: ${CACHE_KEY}"
|
||||
echo "📝 Hash 来源: ${HASH_SOURCE} (${CACHE_HASH_SHORT})"
|
||||
echo "📝 缓存前缀: ${CACHE_PREFIX}"
|
||||
|
||||
PNPM_VERSION="${PNPM_VERSION}"
|
||||
CACHE_KEY="${{ runner.os }}-pnpm-v${PNPM_VERSION}-store-${{ inputs.cache-prefix }}-${CACHE_HASH_SHORT}"
|
||||
RESTORE_PREFIX="${{ runner.os }}-pnpm-v${PNPM_VERSION}-store-${{ inputs.cache-prefix }}-"
|
||||
echo "key=${CACHE_KEY}" >> "$GITHUB_OUTPUT"
|
||||
echo "restore-prefix=${RESTORE_PREFIX}" >> "$GITHUB_OUTPUT"
|
||||
echo "hash=${CACHE_HASH}" >> "$GITHUB_OUTPUT"
|
||||
@@ -147,28 +107,16 @@ runs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 优先级:Docker 默认路径 > pnpm store path
|
||||
STORE_DIR_CANDIDATE=""
|
||||
|
||||
# 1. 检查 Docker 环境默认路径
|
||||
if [[ -d "/pnpm/store" ]]; then
|
||||
STORE_DIR_CANDIDATE="/pnpm/store"
|
||||
echo "📝 检测到 Docker 环境,使用默认路径: $STORE_DIR_CANDIDATE"
|
||||
# 2. 通过 pnpm 命令获取
|
||||
else
|
||||
STORE_DIR_CANDIDATE=$(pnpm store path --silent 2>/dev/null | grep -v '^[[:space:]]*$' | tail -n1 | tr -d '\r\n')
|
||||
if [[ -n "$STORE_DIR_CANDIDATE" ]]; then
|
||||
echo "📝 通过 pnpm store path 获取: $STORE_DIR_CANDIDATE"
|
||||
fi
|
||||
fi
|
||||
STORE_DIR_CANDIDATE=$(pnpm store path --silent 2>/dev/null || true)
|
||||
STORE_DIR_CANDIDATE=$(echo "$STORE_DIR_CANDIDATE" | tail -n1 | tr -d '\r')
|
||||
|
||||
if [[ -z "$STORE_DIR_CANDIDATE" ]]; then
|
||||
echo "❌ 无法确定 pnpm store 路径" >&2
|
||||
echo "💡 提示: 确保 pnpm 配置正确或检查 /pnpm/store 目录" >&2
|
||||
echo "❌ pnpm store path 未返回有效路径。可在运行前设置 PNPM_STORE_DIR=/path/to/store 或检查 pnpm 配置" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "📦 pnpm store 路径: $STORE_DIR_CANDIDATE"
|
||||
echo "pnpm store path: $STORE_DIR_CANDIDATE"
|
||||
echo "PNPM_STORE_DIR=${STORE_DIR_CANDIDATE}" >> "$GITHUB_ENV"
|
||||
echo "path=${STORE_DIR_CANDIDATE}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: 拉取缓存
|
||||
@@ -184,94 +132,56 @@ runs:
|
||||
shell: bash
|
||||
run: |
|
||||
if [[ "${{ steps.cache.outputs.cache-hit }}" == "true" ]]; then
|
||||
echo "✅ 缓存完全命中"
|
||||
echo "缓存命中"
|
||||
else
|
||||
echo "⚠️ 缓存未命中或部分命中,将从网络下载依赖"
|
||||
echo "缓存未命中"
|
||||
fi
|
||||
|
||||
- name: 安装依赖
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
# 获取 store 路径(优先使用已配置的路径)
|
||||
STORE_PATH="${{ steps.cache-path.outputs.path }}"
|
||||
echo "📦 pnpm store 路径: $STORE_PATH"
|
||||
|
||||
# 记录安装前的 lockfile 状态
|
||||
LOCKFILE_BEFORE=""
|
||||
if [[ -f "pnpm-lock.yaml" ]]; then
|
||||
LOCKFILE_BEFORE=$(md5sum pnpm-lock.yaml 2>/dev/null || md5 pnpm-lock.yaml 2>/dev/null || echo "")
|
||||
fi
|
||||
|
||||
# 处理自定义安装命令
|
||||
STORE_DIR="${PNPM_STORE_DIR:-${{ steps.cache-path.outputs.path }}}"
|
||||
export PNPM_STORE_DIR="$STORE_DIR"
|
||||
export npm_config_store_dir="$PNPM_STORE_DIR"
|
||||
export PNPM_CONFIG_STORE_DIR="$PNPM_STORE_DIR"
|
||||
echo "📦 Using PNPM_STORE_DIR=$PNPM_STORE_DIR"
|
||||
if [[ -n "${{ inputs.install-command }}" ]]; then
|
||||
echo "🔧 使用自定义安装命令: ${{ inputs.install-command }}"
|
||||
eval "${{ inputs.install-command }}"
|
||||
exit 0
|
||||
fi
|
||||
if [[ "${{ steps.cache.outputs.cache-hit }}" == "true" ]]; then
|
||||
FLAGS=("--offline" "--frozen-lockfile")
|
||||
else
|
||||
# 构建安装参数
|
||||
FLAGS=("--prefer-offline" "--frozen-lockfile")
|
||||
|
||||
if [[ "${{ inputs.force-install }}" == "true" ]]; then
|
||||
FLAGS+=("--force")
|
||||
echo "⚠️ 强制重新安装模式"
|
||||
fi
|
||||
|
||||
INSTALL_ARGS="${{ inputs.install-args }}"
|
||||
|
||||
# 显示执行命令
|
||||
if [[ -n "$INSTALL_ARGS" ]]; then
|
||||
echo "🔧 执行: pnpm install ${FLAGS[*]} ${INSTALL_ARGS}"
|
||||
pnpm install "${FLAGS[@]}" ${INSTALL_ARGS}
|
||||
else
|
||||
echo "🔧 执行: pnpm install ${FLAGS[*]}"
|
||||
pnpm install "${FLAGS[@]}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 清理项目本地 .pnpm-store (如果存在且与全局 store 不同)
|
||||
if [[ "${{ inputs.clean-project-store }}" == "true" && -d ".pnpm-store" ]]; then
|
||||
GLOBAL_STORE=$(cd "$STORE_PATH" 2>/dev/null && pwd || echo "")
|
||||
LOCAL_STORE=$(cd .pnpm-store 2>/dev/null && pwd || echo "")
|
||||
|
||||
if [[ -n "$GLOBAL_STORE" && -n "$LOCAL_STORE" && "$GLOBAL_STORE" != "$LOCAL_STORE" ]]; then
|
||||
echo "🧹 清理项目本地 .pnpm-store 目录"
|
||||
rm -rf .pnpm-store || true
|
||||
fi
|
||||
if [[ "${{ inputs.force-install }}" == "true" ]]; then
|
||||
FLAGS+=("--force")
|
||||
fi
|
||||
|
||||
# 严格检查 lockfile 是否被意外修改
|
||||
if [[ "${{ inputs.strict-lockfile-check }}" == "true" && -n "$LOCKFILE_BEFORE" ]]; then
|
||||
LOCKFILE_AFTER=""
|
||||
if [[ -f "pnpm-lock.yaml" ]]; then
|
||||
LOCKFILE_AFTER=$(md5sum pnpm-lock.yaml 2>/dev/null || md5 pnpm-lock.yaml 2>/dev/null || echo "")
|
||||
fi
|
||||
|
||||
if [[ "$LOCKFILE_BEFORE" != "$LOCKFILE_AFTER" ]]; then
|
||||
echo "" >&2
|
||||
echo "❌ 检测到 pnpm-lock.yaml 在安装过程中被修改" >&2
|
||||
echo "" >&2
|
||||
echo "📋 变更内容:" >&2
|
||||
git diff pnpm-lock.yaml || true
|
||||
echo "" >&2
|
||||
echo "💡 原因: package.json 与 pnpm-lock.yaml 不同步" >&2
|
||||
echo "💡 解决: 在本地运行 'pnpm install' 并提交更新后的 lockfile" >&2
|
||||
echo "💡 或者: 设置 strict-lockfile-check: 'false' 跳过此检查" >&2
|
||||
echo "" >&2
|
||||
exit 1
|
||||
fi
|
||||
INSTALL_ARGS="${{ inputs.install-args }}"
|
||||
echo "🔧 执行 pnpm install ${FLAGS[*]} ${INSTALL_ARGS}"
|
||||
if [[ -n "$INSTALL_ARGS" ]]; then
|
||||
pnpm install "${FLAGS[@]}" $INSTALL_ARGS
|
||||
else
|
||||
pnpm install "${FLAGS[@]}"
|
||||
fi
|
||||
if [[ "${{ inputs.clean-project-store }}" == "true" && -d ".pnpm-store" && "$(cd "$PNPM_STORE_DIR" 2>/dev/null && pwd)" != "$(cd .pnpm-store 2>/dev/null && pwd)" ]]; then
|
||||
rm -rf .pnpm-store || true
|
||||
fi
|
||||
echo "🧾 git status --short"
|
||||
CHANGES=$(git status --short || true)
|
||||
if [[ -n "$CHANGES" ]]; then
|
||||
echo "$CHANGES"
|
||||
echo "❌ 安装依赖后检测到工作区存在未提交变更。请检查上述文件,必要时更新配置或在调用前设置 PNPM_STORE_DIR。" >&2
|
||||
exit 1
|
||||
else
|
||||
echo "✅ 工作区保持干净"
|
||||
fi
|
||||
|
||||
echo "✅ 依赖安装完成"
|
||||
|
||||
- name: 总结
|
||||
shell: bash
|
||||
run: |
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "📊 pnpm 安装总结"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo " pnpm 版本: $PNPM_VERSION"
|
||||
echo " 缓存命中: ${{ steps.cache.outputs.cache-hit }}"
|
||||
echo " 缓存 key: ${{ steps.cache-key.outputs.key }}"
|
||||
echo " Store 路径: ${{ steps.cache-path.outputs.path }}"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "pnpm版本: $PNPM_VERSION"
|
||||
echo "缓存命中: ${{ steps.cache.outputs.cache-hit }}"
|
||||
echo "缓存key: ${{ steps.cache-key.outputs.key }}"
|
||||
|
||||
@@ -1,318 +0,0 @@
|
||||
# Setup OpenCode Action
|
||||
|
||||
使用 npm 全局安装 opencode-ai 并缓存,支持版本检测和自动更新。
|
||||
|
||||
## 功能特性
|
||||
|
||||
- ✅ **npm 安装**:使用 npm 全局安装,简单快速
|
||||
- 🚀 **智能缓存**:缓存 npm 包和全局安装,加速后续构建
|
||||
- 🔄 **自动更新**:版本变化时自动更新
|
||||
- 🇨🇳 **国内镜像**:支持淘宝镜像源,国内环境友好
|
||||
- ⚡ **快速恢复**:缓存命中时跳过安装,秒级完成
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 基础用法
|
||||
|
||||
```yaml
|
||||
- name: 安装 OpenCode
|
||||
uses: actions/xgj/setup-opencode@v1
|
||||
```
|
||||
|
||||
### 国内环境使用(推荐)
|
||||
|
||||
```yaml
|
||||
- name: 安装 OpenCode(淘宝镜像)
|
||||
uses: actions/xgj/setup-opencode@v1
|
||||
with:
|
||||
version: 'latest'
|
||||
use-taobao-registry: 'true'
|
||||
```
|
||||
|
||||
### 指定版本
|
||||
|
||||
```yaml
|
||||
- name: 安装 OpenCode 1.2.3
|
||||
uses: ./.gitea/actions/setup-opencode
|
||||
with:
|
||||
version: '1.2.3'
|
||||
```
|
||||
|
||||
### 使用最新版本
|
||||
|
||||
```yaml
|
||||
- name: 安装最新版 OpenCode
|
||||
uses: actions/xgj/setup-opencode@v1
|
||||
with:
|
||||
version: 'latest'
|
||||
```
|
||||
|
||||
### 自定义 npm 包名
|
||||
|
||||
```yaml
|
||||
- name: 安装自定义包
|
||||
uses: actions/xgj/setup-opencode@v1
|
||||
with:
|
||||
package-name: 'opencode-ai' # 默认就是 opencode-ai,这里仅作演示
|
||||
version: '1.2.3'
|
||||
```
|
||||
|
||||
### 自定义 npm 镜像源
|
||||
|
||||
```yaml
|
||||
- name: 使用自定义镜像源
|
||||
uses: actions/xgj/setup-opencode@v1
|
||||
with:
|
||||
version: 'latest'
|
||||
npm-registry: 'https://registry.npmmirror.com'
|
||||
```
|
||||
|
||||
### 强制重新安装
|
||||
|
||||
```yaml
|
||||
- name: 强制重新安装 OpenCode
|
||||
uses: actions/xgj/setup-opencode@v1
|
||||
with:
|
||||
version: '1.2.3'
|
||||
skip-cache: 'true'
|
||||
```
|
||||
|
||||
### 使用输出
|
||||
|
||||
```yaml
|
||||
- name: 安装 OpenCode
|
||||
id: setup-opencode
|
||||
uses: actions/xgj/setup-opencode@v1
|
||||
with:
|
||||
version: 'latest'
|
||||
|
||||
- name: 显示版本信息
|
||||
run: |
|
||||
echo "安装版本: ${{ steps.setup-opencode.outputs.version }}"
|
||||
echo "缓存命中: ${{ steps.setup-opencode.outputs.cache-hit }}"
|
||||
echo "执行更新: ${{ steps.setup-opencode.outputs.updated }}"
|
||||
|
||||
- name: 使用 OpenCode
|
||||
run: |
|
||||
opencode --version
|
||||
opencode build
|
||||
```
|
||||
|
||||
## 输入参数
|
||||
|
||||
| 参数 | 描述 | 必填 | 默认值 |
|
||||
| ---- | ---- | ---- | ------ |
|
||||
| `version` | OpenCode 版本号(例如: 1.0.0, latest) | 否 | `latest` |
|
||||
| `package-name` | npm 包名 | 否 | `opencode-ai` |
|
||||
| `use-taobao-registry` | 使用淘宝 npm 镜像源 (true/false) | 否 | `false` |
|
||||
| `npm-registry` | 自定义 npm 镜像源地址 | 否 | `` |
|
||||
| `cache-prefix` | 缓存前缀名称 | 否 | `opencode-npm` |
|
||||
| `skip-cache` | 跳过缓存,强制重新安装 (true/false) | 否 | `false` |
|
||||
|
||||
## 输出
|
||||
|
||||
| 输出 | 描述 |
|
||||
| ---- | ---- |
|
||||
| `version` | 安装的 OpenCode 版本 |
|
||||
| `cache-hit` | 缓存是否命中 (true/false) |
|
||||
| `updated` | 是否执行了更新 (true/false) |
|
||||
|
||||
## 工作原理
|
||||
|
||||
1. **参数验证**:验证输入参数的有效性
|
||||
2. **配置镜像源**:根据配置设置 npm 镜像源(支持淘宝镜像)
|
||||
3. **缓存检查**:根据包名和版本生成缓存键,尝试恢复缓存
|
||||
4. **版本比对**:
|
||||
- 检查已安装版本是否与请求版本一致
|
||||
- 版本一致:跳过安装
|
||||
- 版本不一致或未安装:执行 npm 安装
|
||||
5. **npm 安装**:使用 `npm install -g` 全局安装指定版本
|
||||
6. **保存缓存**:缓存 npm 包和全局安装目录
|
||||
|
||||
## 缓存策略
|
||||
|
||||
- **缓存内容**:
|
||||
- `~/.npm` - npm 缓存目录
|
||||
- `/usr/local/lib/node_modules/{package}` - 全局安装的包
|
||||
- `/usr/local/bin/{package}` - 全局命令
|
||||
- **缓存键格式**:`{OS}-{cache-prefix}-{package-name}-{version}`
|
||||
- **缓存更新**:版本号变化时自动更新缓存
|
||||
- **缓存生命周期**:遵循 GitHub Actions 缓存默认生命周期(最多 7 天未使用)
|
||||
|
||||
## 完整示例
|
||||
|
||||
### 示例 1:基础 CI/CD 流程
|
||||
|
||||
```yaml
|
||||
name: Build with OpenCode
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 安装 OpenCode
|
||||
uses: actions/xgj/setup-opencode@v1
|
||||
with:
|
||||
version: '1.2.3'
|
||||
|
||||
- name: 构建项目
|
||||
run: |
|
||||
opencode build --release
|
||||
|
||||
- name: 运行测试
|
||||
run: |
|
||||
opencode test
|
||||
```
|
||||
|
||||
### 示例 2:国内环境使用
|
||||
|
||||
```yaml
|
||||
name: Build in China
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: 安装 OpenCode(淘宝镜像)
|
||||
uses: actions/xgj/setup-opencode@v1
|
||||
with:
|
||||
version: 'latest'
|
||||
use-taobao-registry: 'true'
|
||||
|
||||
- name: 构建
|
||||
run: opencode build
|
||||
```
|
||||
|
||||
### 示例 3:多版本测试
|
||||
|
||||
```yaml
|
||||
name: Test Multiple Versions
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
opencode-version: ['1.0.0', '1.1.0', '1.2.0', 'latest']
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: 安装 OpenCode ${{ matrix.opencode-version }}
|
||||
uses: actions/xgj/setup-opencode@v1
|
||||
with:
|
||||
version: ${{ matrix.opencode-version }}
|
||||
|
||||
- name: 运行测试
|
||||
run: |
|
||||
echo "Testing with OpenCode ${{ matrix.opencode-version }}"
|
||||
opencode --version
|
||||
opencode test
|
||||
```
|
||||
|
||||
### 示例 4:带缓存状态检查
|
||||
|
||||
```yaml
|
||||
name: Build with Cache Info
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: 安装 OpenCode
|
||||
id: opencode
|
||||
uses: actions/xgj/setup-opencode@v1
|
||||
with:
|
||||
version: 'latest'
|
||||
use-taobao-registry: 'true'
|
||||
|
||||
- name: 显示缓存状态
|
||||
run: |
|
||||
if [[ "${{ steps.opencode.outputs.cache-hit }}" == "true" ]]; then
|
||||
echo "✅ 使用缓存,节省时间!"
|
||||
else
|
||||
echo "📥 首次安装或版本更新"
|
||||
fi
|
||||
|
||||
if [[ "${{ steps.opencode.outputs.updated }}" == "true" ]]; then
|
||||
echo "🔄 OpenCode 已更新到 ${{ steps.opencode.outputs.version }}"
|
||||
fi
|
||||
|
||||
- name: 构建
|
||||
run: opencode build
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **国内环境**:🇨🇳 在国内使用时,强烈建议设置 `use-taobao-registry: 'true'` 使用淘宝镜像源
|
||||
2. **版本格式**:版本号应遵循语义化版本规范(如 1.2.3)
|
||||
3. **npm 环境**:需要 Node.js 和 npm 已安装(GitHub Actions 默认已安装)
|
||||
4. **全局安装**:使用 `npm install -g` 全局安装,命令自动添加到 PATH
|
||||
5. **缓存限制**:GitHub Actions 缓存有大小限制(10GB)
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 国内网络问题
|
||||
|
||||
```yaml
|
||||
- name: 使用淘宝镜像源
|
||||
uses: actions/xgj/setup-opencode@v1
|
||||
with:
|
||||
version: '1.2.3'
|
||||
use-taobao-registry: 'true'
|
||||
```
|
||||
|
||||
### 自定义镜像源
|
||||
|
||||
```yaml
|
||||
- name: 使用自定义镜像
|
||||
uses: actions/xgj/setup-opencode@v1
|
||||
with:
|
||||
version: '1.2.3'
|
||||
npm-registry: 'https://registry.npmmirror.com'
|
||||
```
|
||||
|
||||
### 安装失败
|
||||
|
||||
```yaml
|
||||
- name: 清除缓存重新安装
|
||||
uses: actions/xgj/setup-opencode@v1
|
||||
with:
|
||||
version: '1.2.3'
|
||||
skip-cache: 'true'
|
||||
```
|
||||
|
||||
### 版本不匹配
|
||||
|
||||
检查 `updated` 输出,如果为 `true` 表示已更新到新版本。
|
||||
|
||||
## 优势
|
||||
|
||||
相比二进制安装方式,npm 安装具有以下优势:
|
||||
|
||||
- ✅ **简单直接**:一条 `npm install -g` 命令搞定
|
||||
- ✅ **依赖管理**:npm 自动处理依赖关系
|
||||
- ✅ **版本管理**:npm 原生支持版本管理
|
||||
- ✅ **跨平台**:npm 包通常支持多平台
|
||||
- ✅ **更新方便**:版本更新只需修改版本号
|
||||
- ✅ **缓存高效**:缓存 npm 目录和全局安装,恢复快速
|
||||
|
||||
## 许可证
|
||||
|
||||
与主仓库保持一致。
|
||||
@@ -1,288 +0,0 @@
|
||||
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 }}"
|
||||
GLOBAL_ROOT="${{ steps.npm-paths.outputs.global-root }}"
|
||||
NEED_INSTALL="true"
|
||||
|
||||
# 检查包目录是否存在(更可靠,不依赖命令名)
|
||||
PACKAGE_DIR="${GLOBAL_ROOT}/${PACKAGE}"
|
||||
|
||||
if [[ -d "${PACKAGE_DIR}" ]]; then
|
||||
# 从 package.json 获取版本
|
||||
PACKAGE_JSON="${PACKAGE_DIR}/package.json"
|
||||
if [[ -f "${PACKAGE_JSON}" ]]; then
|
||||
INSTALLED_VERSION=$(grep -o '"version"[[:space:]]*:[[:space:]]*"[^"]*"' "${PACKAGE_JSON}" | head -1 | cut -d'"' -f4 || echo "unknown")
|
||||
else
|
||||
INSTALLED_VERSION="unknown"
|
||||
fi
|
||||
|
||||
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: 保存缓存
|
||||
if: steps.check-installed.outputs.need-install == '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: |
|
||||
# 直接从 opencode 命令获取版本
|
||||
if command -v opencode &> /dev/null; then
|
||||
VERSION=$(opencode --version 2>/dev/null | head -n1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' || echo "unknown")
|
||||
|
||||
if [[ "${VERSION}" != "unknown" ]]; then
|
||||
echo "version=${VERSION}" >> $GITHUB_OUTPUT
|
||||
echo "✅ OpenCode 版本: ${VERSION}"
|
||||
else
|
||||
# 如果命令输出格式不同,尝试直接输出
|
||||
VERSION=$(opencode --version 2>/dev/null | head -n1 || echo "unknown")
|
||||
echo "version=${VERSION}" >> $GITHUB_OUTPUT
|
||||
echo "✅ OpenCode 版本: ${VERSION}"
|
||||
fi
|
||||
else
|
||||
# 备用方案:使用已解析的版本号
|
||||
VERSION="${{ steps.resolve-version.outputs.version }}"
|
||||
echo "version=${VERSION}" >> $GITHUB_OUTPUT
|
||||
echo "⚠️ opencode 命令不可用,使用已解析版本: ${VERSION}"
|
||||
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 已准备就绪!"
|
||||
@@ -1,36 +0,0 @@
|
||||
name: Basic OpenCode Usage
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, develop ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 安装 OpenCode
|
||||
id: setup-opencode
|
||||
uses: actions/xgj/setup-opencode@v1
|
||||
with:
|
||||
version: 'latest'
|
||||
|
||||
- name: 显示安装信息
|
||||
run: |
|
||||
echo "OpenCode 版本: ${{ steps.setup-opencode.outputs.version }}"
|
||||
echo "缓存命中: ${{ steps.setup-opencode.outputs.cache-hit }}"
|
||||
echo "执行更新: ${{ steps.setup-opencode.outputs.updated }}"
|
||||
|
||||
- name: 验证安装
|
||||
run: |
|
||||
opencode --version
|
||||
which opencode
|
||||
|
||||
- name: 使用 OpenCode
|
||||
run: |
|
||||
opencode build
|
||||
@@ -1,33 +0,0 @@
|
||||
name: China Mirror Example
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 安装 OpenCode(淘宝镜像)
|
||||
id: setup
|
||||
uses: actions/xgj/setup-opencode@v1
|
||||
with:
|
||||
version: 'latest'
|
||||
use-taobao-registry: 'true'
|
||||
|
||||
- name: 显示安装信息
|
||||
run: |
|
||||
echo "安装版本: ${{ steps.setup.outputs.version }}"
|
||||
echo "缓存命中: ${{ steps.setup.outputs.cache-hit }}"
|
||||
|
||||
if [[ "${{ steps.setup.outputs.cache-hit }}" == "true" ]]; then
|
||||
echo "✅ 使用缓存,快速完成安装"
|
||||
else
|
||||
echo "📥 通过 npm 安装完成"
|
||||
fi
|
||||
|
||||
- name: 构建项目
|
||||
run: |
|
||||
opencode build --release
|
||||
@@ -1,21 +0,0 @@
|
||||
name: Custom Registry Example
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 使用自定义 npm 镜像源
|
||||
uses: actions/xgj/setup-opencode@v1
|
||||
with:
|
||||
version: '1.2.3'
|
||||
npm-registry: 'https://registry.npmmirror.com'
|
||||
|
||||
- name: 构建
|
||||
run: |
|
||||
opencode build
|
||||
@@ -1,21 +0,0 @@
|
||||
name: Specific Version Example
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 安装 OpenCode 1.2.3
|
||||
uses: actions/xgj/setup-opencode@v1
|
||||
with:
|
||||
version: '1.2.3'
|
||||
cache-prefix: 'opencode-stable'
|
||||
|
||||
- name: 构建项目
|
||||
run: |
|
||||
opencode build --release
|
||||
Reference in New Issue
Block a user