Files
xgj/pnpm-install/action.yml

229 lines
7.3 KiB
YAML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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: 'pnpm依赖安装与缓存'
description: '专注于pnpm的依赖缓存与安装加速重复执行'
branding:
icon: 'package'
color: 'yellow'
inputs:
cache-prefix:
description: '缓存前缀名称'
required: false
default: 'modules'
force-install:
description: '是否强制安装 (true/false)'
required: false
default: 'false'
install-command:
description: '自定义安装命令(若设置则完全覆盖默认命令)'
required: false
default: ''
install-args:
description: '附加到默认安装命令的参数(当未提供 install-command 时生效)'
required: false
default: ''
cache-hash:
description: '缓存hash值推荐使用hashFiles'
required: false
default: ''
clean-project-store:
description: '安装后清理项目根目录的 .pnpm-store (true/false)'
required: false
default: 'false'
outputs:
cache-hit:
description: '是否命中缓存 (true/false)'
value: ${{ steps.cache.outputs.cache-hit }}
cache-key:
description: '使用的缓存key'
value: ${{ steps.cache-key.outputs.key }}
cache-path:
description: '缓存路径(用于调试与复用)'
value: ${{ steps.cache-path.outputs.path }}
runs:
using: 'composite'
steps:
- name: 检查pnpm
id: detect
shell: bash
run: |
if ! command -v pnpm >/dev/null 2>&1; then
echo "pnpm 未安装"
exit 1
fi
VERSION=$(pnpm --version | tr -d '\n')
if [[ -z "$VERSION" ]]; then
echo "无法获取pnpm版本"
exit 1
fi
echo "pnpm-version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "PNPM_VERSION=${VERSION}" >> "$GITHUB_ENV"
- name: 生成缓存key
id: cache-key
shell: bash
env:
PNPM_VERSION: ${{ steps.detect.outputs.pnpm-version }}
FALLBACK_HASH: ${{ hashFiles('pnpm-lock.yaml') }}
PACKAGE_HASH: ${{ hashFiles('package.json') }}
run: |
set -euo pipefail
if [[ -n "${{ inputs.cache-hash }}" ]]; then
CACHE_HASH="${{ inputs.cache-hash }}"
elif [[ -n "${FALLBACK_HASH}" ]]; then
CACHE_HASH="${FALLBACK_HASH}"
elif [[ -n "${PACKAGE_HASH}" ]]; then
CACHE_HASH="${PACKAGE_HASH}"
else
CACHE_HASH=""
fi
if [[ -n "$CACHE_HASH" ]]; then
CACHE_HASH_SHORT=$(echo "$CACHE_HASH" | head -c 12)
else
CACHE_HASH_SHORT="no-hash"
fi
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"
- name: 确定缓存路径
id: cache-path
shell: bash
run: |
set -euo pipefail
DEFAULT_STORE="${RUNNER_TEMP:-$HOME}/.pnpm-store"
STORE_DIR_CANDIDATE="${PNPM_STORE_DIR:-${npm_config_store_dir:-}}"
probe_config () {
local file="$1"
if [[ -n "$STORE_DIR_CANDIDATE" || -z "$file" || ! -f "$file" ]]; then
return
fi
local raw
raw=$(grep -E '^[[:space:]]*store-dir[[:space:]]*=' "$file" | tail -n1 | cut -d= -f2- || true)
if [[ -z "$raw" ]]; then
return
fi
raw=$(echo "$raw" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
if [[ -z "$raw" ]]; then
return
fi
if [[ "$raw" == /* || "$raw" =~ ^[A-Za-z]:[\\/] ]]; then
STORE_DIR_CANDIDATE="$raw"
else
local base
base=$(cd "$(dirname "$file")" && pwd)
STORE_DIR_CANDIDATE="$base/$raw"
fi
}
probe_config "${NPM_CONFIG_USERCONFIG:-}"
echo " Checked userconfig: ${NPM_CONFIG_USERCONFIG:-<unset>} -> ${STORE_DIR_CANDIDATE:-<none>}"
probe_config ".npmrc"
echo " Checked project .npmrc -> ${STORE_DIR_CANDIDATE:-<none>}"
probe_config "$HOME/.npmrc"
echo " Checked home .npmrc -> ${STORE_DIR_CANDIDATE:-<none>}"
if [[ -z "$STORE_DIR_CANDIDATE" ]]; then
STORE_DIR_CANDIDATE=$(pnpm store path --silent 2>/dev/null || true)
STORE_DIR_CANDIDATE=$(echo "$STORE_DIR_CANDIDATE" | tail -n1 | tr -d '\r')
fi
if [[ -z "$STORE_DIR_CANDIDATE" ]]; then
STORE_DIR_CANDIDATE="$DEFAULT_STORE"
fi
echo " Final store candidate: $STORE_DIR_CANDIDATE"
mkdir -p "$STORE_DIR_CANDIDATE"
case "$STORE_DIR_CANDIDATE" in
/*)
CACHE_PATH="$STORE_DIR_CANDIDATE"
;;
~*)
CACHE_PATH="$(eval echo "$STORE_DIR_CANDIDATE")"
;;
*)
CACHE_PATH="$(cd "$STORE_DIR_CANDIDATE" 2>/dev/null && pwd)"
if [[ -z "$CACHE_PATH" ]]; then
CACHE_PATH="$STORE_DIR_CANDIDATE"
fi
;;
esac
echo "pnpm store path: $CACHE_PATH"
echo "PNPM_STORE_DIR=${CACHE_PATH}" >> "$GITHUB_ENV"
echo "path=${CACHE_PATH}" >> "$GITHUB_OUTPUT"
- name: 拉取缓存
id: cache
uses: actions/cache@v4
with:
path: ${{ steps.cache-path.outputs.path }}
key: ${{ steps.cache-key.outputs.key }}
restore-keys: |
${{ steps.cache-key.outputs.restore-prefix }}
- name: 显示缓存状态
shell: bash
run: |
if [[ "${{ steps.cache.outputs.cache-hit }}" == "true" ]]; then
echo "缓存命中"
else
echo "缓存未命中"
fi
- name: 安装依赖
shell: bash
run: |
set -euo pipefail
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")
fi
if [[ "${{ inputs.force-install }}" == "true" ]]; then
FLAGS+=("--force")
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"
git status --short || true
- name: 总结
shell: bash
run: |
echo "pnpm版本: $PNPM_VERSION"
echo "缓存命中: ${{ steps.cache.outputs.cache-hit }}"
echo "缓存key: ${{ steps.cache-key.outputs.key }}"