Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -808,6 +808,33 @@ jobs:
fi
echo "OK: composed sfw blocked lodahs (exit $CODE, block-line found)"

test-pnpm:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2

- name: Setup Vite+ with global pnpm
uses: ./
with:
pnpm: true
run-install: false
cache: false

- name: Verify pnpm is installed globally
shell: bash
run: |
global_list="$(vp list -g pnpm)"
echo "$global_list"
if [[ "$global_list" == *"No global packages matching 'pnpm'"* ]]; then
echo "pnpm was not installed globally" >&2
exit 1
fi
pnpm --version

test-azure-runtime:
strategy:
fail-fast: false
Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ GitHub Action, GitLab CI/CD remote template, and Azure Pipelines step template t
- GitHub Action: cache project dependencies with auto-detection of lock files
- Optionally run `vp install` after setup
- Optionally wrap `vp install` with [Socket Firewall Free (`sfw`)](https://docs.socket.dev/docs/socket-firewall-free) to block malicious dependencies
- Optionally install pnpm globally
- Support for all major package managers (npm, pnpm, yarn, bun)
- GitLab CI/CD support through a reusable `include:remote` template
- Azure Pipelines support through a reusable step template and compiled runtime
Expand Down Expand Up @@ -110,6 +111,19 @@ steps:
cache: true
```

### With pnpm

Certain tools invoke `pnpm` directly without using `vp`. Install
pnpm globally to make its executable available.

```yaml
steps:
- uses: actions/checkout@v6
- uses: voidzero-dev/setup-vp@v1.18.0
with:
pnpm: true
```

### Version from `package.json` / Catalog

Keep a single source of truth for the Vite+ version by resolving it from the
Expand Down Expand Up @@ -338,6 +352,7 @@ jobs:
| `working-directory` | Project directory used for relative paths, lockfile auto-detection, environment checks, and default install | No | Workspace root |
| `run-install` | Run `vp install` after setup. Accepts boolean or YAML object with `cwd`/`args` | No | `true` |
| `sfw` | Wrap `vp install` with [Socket Firewall Free](https://docs.socket.dev/docs/socket-firewall-free) (`sfw`) | No | `false` |
| `pnpm` | Install pnpm globally | No | `false` |
| `cache` | Enable caching of project dependencies | No | `false` |
| `cache-dependency-path` | Path to lock file for cache key generation | No | Auto-detected |
| `registry-url` | Optional registry to set up for auth. Sets the registry in `.npmrc` and reads auth from `NODE_AUTH_TOKEN` | No | |
Expand Down
4 changes: 4 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ inputs:
description: "Wrap `vp install` with Socket Firewall Free (sfw) to block malicious dependency fetches. Works on Linux, macOS, and Windows (macOS/Windows require Vite+ v0.1.23+). See https://docs.socket.dev/docs/socket-firewall-free."
required: false
default: "false"
pnpm:
description: "Install pnpm globally."
required: false
default: "false"
node-version:
description: "Node.js version to install via `vp env use`. Omit this input and node-version-file to let Vite+ resolve the version. `vp env default <version>` sets the user-level default. Vite+ checks the project, this default, and then the latest LTS release."
required: false
Expand Down
6 changes: 3 additions & 3 deletions dist/index.mjs

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { saveState, getState, setFailed, info, setOutput, warning } from "@actio
import { exec, getExecOutput } from "@actions/exec";
import { getInputs } from "./inputs.js";
import { installVitePlus } from "./install-viteplus.js";
import { installPnpm } from "./install-pnpm.js";
import { setupSfw } from "./install-sfw.js";
import { runViteInstall } from "./run-install.js";
import { restoreCache } from "./cache-restore.js";
Expand Down Expand Up @@ -59,7 +60,10 @@ async function runMain(inputs: Inputs): Promise<void> {
// (downloads our pinned binary), unsupported platform (falls back).
const effectiveSfw = await setupSfw(inputs);

// Step 7: Run vp install if requested
// Step 7: Install pnpm globally for tools that invoke `pnpm` directly.
await installPnpm(inputs);

// Step 8: Run vp install if requested
if (inputs.runInstall.length > 0) {
await runViteInstall({ ...inputs, sfw: effectiveSfw });
}
Expand Down
13 changes: 13 additions & 0 deletions src/inputs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ describe("getInputs", () => {
workingDirectory: undefined,
runInstall: [],
sfw: false,
pnpm: false,
cache: false,
cacheDependencyPath: undefined,
});
Expand Down Expand Up @@ -132,6 +133,18 @@ describe("getInputs", () => {
expect(inputs.sfw).toBe(true);
});

it("should parse pnpm input", () => {
vi.mocked(getInput).mockReturnValue("");
vi.mocked(getBooleanInput).mockImplementation((name) => {
if (name === "pnpm") return true;
return false;
});

const inputs = getInputs();

expect(inputs.pnpm).toBe(true);
});

it("should parse node-version-file input", () => {
vi.mocked(getInput).mockImplementation((name) => {
if (name === "node-version-file") return ".nvmrc";
Expand Down
1 change: 1 addition & 0 deletions src/inputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export function getInputs(): Inputs {
workingDirectory: getInput("working-directory") || undefined,
runInstall: parseRunInstall(getInput("run-install")),
sfw: getBooleanInput("sfw"),
pnpm: getBooleanInput("pnpm"),
cache: getBooleanInput("cache"),
cacheDependencyPath: getInput("cache-dependency-path") || undefined,
registryUrl: getInput("registry-url") || undefined,
Expand Down
47 changes: 47 additions & 0 deletions src/install-pnpm.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { info } from "@actions/core";
import { exec } from "@actions/exec";
import { beforeEach, describe, expect, it, vi } from "vite-plus/test";
import { installPnpm } from "./install-pnpm.js";
import type { Inputs } from "./types.js";

vi.mock("@actions/core", () => ({
info: vi.fn(),
}));

vi.mock("@actions/exec", () => ({
exec: vi.fn(),
}));

describe("installPnpm", () => {
beforeEach(() => {
vi.resetAllMocks();
});

it("installs pnpm globally when true", async () => {
const inputs: Inputs = {
version: "latest",
runInstall: [{}],
sfw: false,
pnpm: true,
cache: false,
};
await installPnpm(inputs);

expect(info).toHaveBeenCalledWith("Installing pnpm globally...");
expect(exec).toHaveBeenCalledWith("vp", ["install", "-g", "pnpm"]);
});

it("does not install pnpm globally when false", async () => {
const inputs: Inputs = {
version: "latest",
runInstall: [{}],
sfw: false,
pnpm: false,
cache: false,
};
await installPnpm(inputs);

expect(info).not.toHaveBeenCalled();
expect(exec).not.toHaveBeenCalled();
});
});
10 changes: 10 additions & 0 deletions src/install-pnpm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { info } from "@actions/core";
import { exec } from "@actions/exec";
import type { Inputs } from "./types.js";

export async function installPnpm(inputs: Inputs): Promise<void> {
if (!inputs.pnpm) return;

info("Installing pnpm globally...");
await exec("vp", ["install", "-g", "pnpm"]);
}
1 change: 1 addition & 0 deletions src/install-sfw.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ function makeInputs(overrides: Partial<Inputs> = {}): Inputs {
workingDirectory: undefined,
runInstall: [{}],
sfw: true,
pnpm: false,
cache: false,
cacheDependencyPath: undefined,
registryUrl: undefined,
Expand Down
1 change: 1 addition & 0 deletions src/install-viteplus.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const baseInputs: Inputs = {
workingDirectory: undefined,
runInstall: [],
sfw: false,
pnpm: false,
cache: false,
cacheDependencyPath: undefined,
registryUrl: undefined,
Expand Down
1 change: 1 addition & 0 deletions src/run-install.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const baseInputs: Inputs = {
version: "latest",
runInstall: [{}],
sfw: true,
pnpm: false,
cache: false,
};

Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export interface Inputs {
readonly workingDirectory?: string;
readonly runInstall: RunInstall[];
readonly sfw: boolean;
readonly pnpm: boolean;
readonly cache: boolean;
readonly cacheDependencyPath?: string;
readonly registryUrl?: string;
Expand Down
5 changes: 5 additions & 0 deletions src/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ describe("getConfiguredProjectDir", () => {
workingDirectory: "web",
runInstall: [],
sfw: false,
pnpm: false,
cache: false,
cacheDependencyPath: undefined,
registryUrl: undefined,
Expand All @@ -314,6 +315,7 @@ describe("getConfiguredProjectDir", () => {
workingDirectory: undefined,
runInstall: [],
sfw: false,
pnpm: false,
cache: false,
cacheDependencyPath: undefined,
registryUrl: undefined,
Expand All @@ -333,6 +335,7 @@ describe("getConfiguredProjectDir", () => {
workingDirectory: "web",
runInstall: [],
sfw: false,
pnpm: false,
cache: false,
cacheDependencyPath: undefined,
registryUrl: undefined,
Expand All @@ -354,6 +357,7 @@ describe("getConfiguredProjectDir", () => {
workingDirectory: "web",
runInstall: [],
sfw: false,
pnpm: false,
cache: false,
cacheDependencyPath: undefined,
registryUrl: undefined,
Expand Down Expand Up @@ -388,6 +392,7 @@ describe("resolvePath", () => {
workingDirectory: "web",
runInstall: [],
sfw: false,
pnpm: false,
cache: false,
cacheDependencyPath: undefined,
registryUrl: undefined,
Expand Down
1 change: 1 addition & 0 deletions src/version-file.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,7 @@ describe("resolveVitePlusVersion (precedence)", () => {
workingDirectory: undefined,
runInstall: [],
sfw: false,
pnpm: false,
cache: false,
cacheDependencyPath: undefined,
registryUrl: undefined,
Expand Down