Skip to content
Merged
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ A collection of reusable GitHub Actions workflows and composite actions for Zote

### Composite actions

- [x] Setup JavaScript (`setup-js`): checkout, then automatically pick the toolchain
- [x] `setup-vp`: [Vite+](https://github.com/voidzero-dev/setup-vp) setup (auto-detected when `vite-plus` is in the devDependencies of `package.json`)
- [x] `setup-node`: Node.js + package manager setup and dependency install
- [x] Setup JavaScript (`setup-js`): checkout, then auto-pick a toolchain
- [x] Vite+ ([voidzero-dev/setup-vp](https://github.com/voidzero-dev/setup-vp)) when `vite-plus` is a devDependency
- [x] [pnpm/setup](https://github.com/pnpm/setup) when pnpm > 11 or version undeclared
- [x] `setup-node` (internal) otherwise (npm / yarn / pnpm ≤ 11)

### Reusable GitHub Actions workflows

Expand Down
95 changes: 80 additions & 15 deletions setup-js/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ inputs:
description: Whether to fetch all commits and submodules.
default: "false"

# --- shared by setup-node and setup-vp ---
# --- shared by setup-node and Vite+ ---
auto-install:
description: "Whether to automatically install dependencies."
default: "true"
Expand All @@ -25,18 +25,18 @@ inputs:
required: false
default: "true"

# --- setup-node only (ignored when Vite+ is used) ---
# --- Node.js setup (ignored when Vite+ is used) ---
node-version:
description: "Version Spec of the version to use. Examples: 12.x, 10.15.1, >=10.15.0. Ignored when Vite+ is used."
description: "Version Spec of the Node.js version to use. Examples: 12.x, 10.15.1, >=10.15.0. Ignored when Vite+ is used. When pnpm is set up via pnpm/setup (pnpm > 11 or undeclared), this is passed as its `runtime` input, with `lts/*` translated to `lts`."
default: "lts/*"

package-manager:
description: "Package manager to use. Examples: npm, yarn, pnpm. Leave empty to auto-detect. Ignored when Vite+ is used."
description: "Package manager to use. Examples: npm, yarn, pnpm. Leave empty to auto-detect from lock files. Ignored when Vite+ is used. When pnpm is detected (or forced), pnpm > 11 or an undeclared version uses pnpm/setup@v2; pnpm <= 11 uses setup-node (pnpm/action-setup)."
default: ""

# --- setup-vp only ---
# --- Vite+ only ---
vp:
description: "Use Vite+ (setup-vp) instead of the classic Node.js setup. 'true'/'false' to force; leave empty to auto-detect from the devDependencies of package.json (vite-plus)."
description: "Use Vite+ (voidzero-dev/setup-vp) instead of the classic Node.js setup. 'true'/'false' to force; leave empty to auto-detect from the devDependencies of package.json (vite-plus)."
required: false
default: ""

Expand All @@ -48,6 +48,7 @@ inputs:
runs:
using: composite
steps:
# --- Checkout ---
- name: Checkout
uses: actions/checkout@v7
with:
Expand All @@ -56,8 +57,9 @@ runs:
fetch-depth: "${{ inputs.fetch-all == 'true' && '0' || '1' }}"
submodules: "${{ inputs.fetch-all == 'true' && 'recursive' || false }}"

# --- Detect toolchain and package manager ---
- name: Detect Vite+ usage
id: vp
id: detect-vp
shell: bash
run: |
USE_VP="${{ inputs.vp }}"
Expand All @@ -71,25 +73,88 @@ runs:
fi
fi
echo "use_vp=$USE_VP" >> $GITHUB_OUTPUT
if [[ "$USE_VP" == "true" ]]; then
echo "Using Vite+ (setup-vp)"
echo "Vite+ usage: $USE_VP"

- name: Detect package manager
id: detect-pm
if: ${{ steps.detect-vp.outputs.use_vp != 'true' }}
shell: bash
run: |
PM="${{ inputs.package-manager }}"
if [[ -z "$PM" ]]; then
if [[ -f "pnpm-lock.yaml" ]]; then
PM="pnpm"
elif [[ -f "yarn.lock" ]]; then
PM="yarn"
elif [[ -f "package-lock.json" ]]; then
PM="npm"
else
echo "No lock file found. Defaulting to pnpm."
PM="pnpm"
fi
fi
echo "pm=$PM" >> $GITHUB_OUTPUT
echo "Package manager: $PM"

- name: Detect pnpm version and strategy
id: detect-pnpm
if: ${{ steps.detect-vp.outputs.use_vp != 'true' && steps.detect-pm.outputs.pm == 'pnpm' }}
shell: bash
run: |
# pnpm >= 12 (or an undeclared version, which resolves to the latest
# pnpm, always >= 12) can use pnpm/setup@v2, which installs pnpm and a
# Node.js runtime in one step. pnpm <= 11 keeps the classic
# setup-node path (pnpm/action-setup): pnpm/setup only supports
# >= 11, and v11 ships no binary for Intel macOS runners.
USE_NEW=false
PM_VERSION=""
if [[ -f package.json ]]; then
# Top-level "packageManager": "pnpm@12.1.0[+sha256...]"
PM_VERSION=$(sed -n 's/.*"packageManager"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' package.json | head -1)
# Or devEngines.packageManager.version
if [[ -z "$PM_VERSION" ]]; then
PM_VERSION=$(sed -n 's/.*"packageManager"[[:space:]]*:[[:space:]]*{[^}]*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' package.json | head -1)
fi
fi
if [[ -n "$PM_VERSION" ]]; then
# Extract the first number (major): handles "12.1.0", "pnpm@12.1.0",
# "12.1.0+sha256...", "^12.0.0", ">=12" and "12.x".
MAJOR=$(echo "$PM_VERSION" | sed 's/[^0-9]*\([0-9]*\).*/\1/')
echo "Detected pnpm version: $PM_VERSION (major: $MAJOR)"
if [[ "$MAJOR" =~ ^[0-9]+$ ]] && [[ "$MAJOR" -gt 11 ]]; then
USE_NEW=true
fi
else
echo "Using classic Node.js setup (setup-node)"
echo "No pnpm version declared in package.json"
USE_NEW=true
fi
echo "use_new_pnpm=$USE_NEW" >> $GITHUB_OUTPUT
echo "pnpm strategy: use_new_pnpm=$USE_NEW"

- name: Setup Vite+ (setup-vp)
if: ${{ steps.vp.outputs.use_vp == 'true' }}
uses: $/setup-vp
# --- Setup ---
- name: Setup Vite+ (voidzero-dev/setup-vp)
if: ${{ steps.detect-vp.outputs.use_vp == 'true' }}
uses: voidzero-dev/setup-vp@v1
with:
version: ${{ inputs.vp-version }}
run-install: ${{ inputs.auto-install }}
cache: ${{ inputs.cache }}

- name: Setup pnpm + Node.js (pnpm/setup)
if: ${{ steps.detect-vp.outputs.use_vp != 'true' && steps.detect-pnpm.outputs.use_new_pnpm == 'true' }}
uses: pnpm/setup@v2
with:
# node-version is a setup-node spec (lts/*, 22.x, >=20.0.0); pnpm/setup
# expects its own runtime spec (node@<version>), so translate the default.
runtime: ${{ (inputs.node-version == '' || inputs.node-version == 'lts/*') && 'node@lts' || format('node@{0}', inputs.node-version) }}
install: ${{ inputs.auto-install }}
cache: ${{ inputs.cache }}

- name: Setup Node.js (setup-node)
if: ${{ steps.vp.outputs.use_vp != 'true' }}
if: ${{ steps.detect-vp.outputs.use_vp != 'true' && steps.detect-pnpm.outputs.use_new_pnpm != 'true' }}
uses: $/setup-node
with:
node-version: ${{ inputs.node-version }}
auto-install: ${{ inputs.auto-install }}
package-manager: ${{ inputs.package-manager }}
package-manager: ${{ steps.detect-pm.outputs.pm }}
cache: ${{ inputs.cache }}
12 changes: 9 additions & 3 deletions setup-js/example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,15 @@ jobs:
steps:
- name: Setup JS (auto-detect Vite+)
uses: zotero-plugin-dev/workflows/setup-js@main
# By default, setup-vp is used when `vite-plus` is found in the
# devDependencies of package.json. Set `vp: 'true'` or `vp: 'false'`
# to force a specific setup.
# By default, the Vite+ setup (voidzero-dev/setup-vp) is used when
# `vite-plus` is found in the devDependencies of package.json. Set
# `vp: 'true'` or `vp: 'false'` to force a specific setup.
#
# When pnpm is used, pnpm > 11 (or an undeclared pnpm version) is
# set up via pnpm/setup@v2, which also installs the Node.js runtime
# (`node-version` is passed through, with `lts/*` translated to
# `lts`); pnpm <= 11 keeps the classic setup-node path
# (pnpm/action-setup).
# with:
# vp: "true"
# vp-version: "0.2.0"
Expand Down
33 changes: 7 additions & 26 deletions setup-node/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ inputs:
description: Whether to automatically install dependencies.
default: "true"

# Internal: the package manager is detected by setup-js and passed in here.
package-manager:
description: "Package manager to use. Examples: npm, yarn, pnpm. Leave empty to auto-detect."
default: ""
description: "Package manager to use. Examples: npm, yarn, pnpm. Required."
required: true

cache:
description: "Whether to cache dependencies."
Expand All @@ -22,40 +23,20 @@ inputs:
runs:
using: composite
steps:
- name: Auto detect package manager
id: detect
shell: bash
run: |
if [[ -n "${{ inputs.package-manager }}" ]]; then
echo "pm=${{ inputs.package-manager }}" >> $GITHUB_OUTPUT
exit 0
fi

if [[ -f "pnpm-lock.yaml" ]]; then
echo "pm=pnpm" >> $GITHUB_OUTPUT
elif [[ -f "yarn.lock" ]]; then
echo "pm=yarn" >> $GITHUB_OUTPUT
elif [[ -f "package-lock.json" ]]; then
echo "pm=npm" >> $GITHUB_OUTPUT
else
echo "No lock file found. Defaulting to pnpm."
echo "pm=pnpm" >> $GITHUB_OUTPUT
fi

- name: Install pnpm
if: ${{ steps.detect.outputs.pm == 'pnpm' }}
if: ${{ inputs.package-manager == 'pnpm' }}
uses: pnpm/action-setup@v6

- name: Setup node
uses: actions/setup-node@v7
with:
node-version: ${{ inputs.node-version }}
cache: ${{ inputs.cache == 'true' && steps.detect.outputs.pm || '' }}
cache: ${{ inputs.cache == 'true' && inputs.package-manager || '' }}
registry-url: "https://registry.npmjs.org"

- name: Install dependencies
if: ${{ inputs.auto-install == 'true' }}
shell: bash
run: |
echo "Using package manager: ${{ steps.detect.outputs.pm }}"
${{ steps.detect.outputs.pm }} install
echo "Using package manager: ${{ inputs.package-manager }}"
${{ inputs.package-manager }} install
28 changes: 0 additions & 28 deletions setup-vp/action.yml

This file was deleted.