Skip to content

Commit 2d17a07

Browse files
committed
fix: add node-version to vp cache key, revert version-dir approach
Include the resolved node-version in the cache key so multi-Node matrix builds each get their own cache entry. Revert the version-specific directory + symlink approach in favor of caching the entire ~/.vite-plus/ as a black box — avoids coupling to vp's internal installation layout. Node version is now resolved before installVitePlus() so it can be included in the cache key.
1 parent 51d8ec1 commit 2d17a07

6 files changed

Lines changed: 122 additions & 168 deletions

File tree

dist/index.mjs

Lines changed: 75 additions & 75 deletions
Large diffs are not rendered by default.

src/cache-vp.test.ts

Lines changed: 33 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { resolveVersion, restoreVpCache, saveVpCache } from "./cache-vp.js";
44
import { State } from "./types.js";
55
import { restoreCache, saveCache } from "@actions/cache";
66
import { saveState, getState, warning } from "@actions/core";
7-
import { existsSync, symlinkSync, mkdirSync } from "node:fs";
87

98
// Mock @actions/cache
109
vi.mock("@actions/cache", () => ({
@@ -21,18 +20,6 @@ vi.mock("@actions/core", () => ({
2120
getState: vi.fn(),
2221
}));
2322

24-
// Mock node:fs
25-
vi.mock("node:fs", async () => {
26-
const actual = await vi.importActual<typeof import("node:fs")>("node:fs");
27-
return {
28-
...actual,
29-
existsSync: vi.fn(),
30-
symlinkSync: vi.fn(),
31-
mkdirSync: vi.fn(),
32-
rmSync: vi.fn(),
33-
};
34-
});
35-
3623
describe("resolveVersion", () => {
3724
afterEach(() => {
3825
vi.restoreAllMocks();
@@ -94,51 +81,51 @@ describe("restoreVpCache", () => {
9481
vi.resetAllMocks();
9582
});
9683

97-
it("should return true on cache hit and create symlinks", async () => {
98-
vi.mocked(restoreCache).mockResolvedValue(`setup-vp-Linux-${arch()}-0.1.8`);
99-
vi.mocked(existsSync).mockReturnValue(false);
84+
it("should return true on cache hit", async () => {
85+
const expectedKey = `setup-vp-Linux-${arch()}-0.1.8-node20`;
86+
vi.mocked(restoreCache).mockResolvedValue(expectedKey);
10087

101-
const result = await restoreVpCache("0.1.8");
88+
const result = await restoreVpCache("0.1.8", "20");
10289

10390
expect(result).toBe(true);
104-
expect(saveState).toHaveBeenCalledWith(
105-
State.VpCachePrimaryKey,
106-
`setup-vp-Linux-${arch()}-0.1.8`,
107-
);
108-
expect(saveState).toHaveBeenCalledWith(
109-
State.VpCacheMatchedKey,
110-
`setup-vp-Linux-${arch()}-0.1.8`,
91+
expect(saveState).toHaveBeenCalledWith(State.VpCachePrimaryKey, expectedKey);
92+
expect(saveState).toHaveBeenCalledWith(State.VpCacheMatchedKey, expectedKey);
93+
});
94+
95+
it("should include node version in cache key", async () => {
96+
vi.mocked(restoreCache).mockResolvedValue(undefined);
97+
98+
await restoreVpCache("0.1.8", "22");
99+
100+
expect(restoreCache).toHaveBeenCalledWith(
101+
["/home/runner/.vite-plus"],
102+
`setup-vp-Linux-${arch()}-0.1.8-node22`,
111103
);
112-
expect(saveState).toHaveBeenCalledWith(State.VpCacheVersion, "0.1.8");
113-
// Verify symlinks were created
114-
expect(symlinkSync).toHaveBeenCalledTimes(2);
115-
expect(mkdirSync).toHaveBeenCalled();
116104
});
117105

118-
it("should cache the version-specific directory, not the whole home", async () => {
106+
it("should handle empty node version", async () => {
119107
vi.mocked(restoreCache).mockResolvedValue(undefined);
120108

121-
await restoreVpCache("0.1.8");
109+
await restoreVpCache("0.1.8", "");
122110

123111
expect(restoreCache).toHaveBeenCalledWith(
124-
["/home/runner/.vite-plus/0.1.8"],
125-
`setup-vp-Linux-${arch()}-0.1.8`,
112+
["/home/runner/.vite-plus"],
113+
`setup-vp-Linux-${arch()}-0.1.8-node`,
126114
);
127115
});
128116

129117
it("should return false on cache miss", async () => {
130118
vi.mocked(restoreCache).mockResolvedValue(undefined);
131119

132-
const result = await restoreVpCache("0.1.8");
120+
const result = await restoreVpCache("0.1.8", "20");
133121

134122
expect(result).toBe(false);
135-
expect(symlinkSync).not.toHaveBeenCalled();
136123
});
137124

138125
it("should return false and warn on cache restore error", async () => {
139126
vi.mocked(restoreCache).mockRejectedValue(new Error("cache error"));
140127

141-
const result = await restoreVpCache("0.1.8");
128+
const result = await restoreVpCache("0.1.8", "20");
142129

143130
expect(result).toBe(false);
144131
expect(warning).toHaveBeenCalled();
@@ -164,10 +151,10 @@ describe("saveVpCache", () => {
164151
});
165152

166153
it("should skip when primary key matches matched key", async () => {
167-
vi.mocked(getState).mockImplementation((key: string) => {
168-
if (key === State.VpCachePrimaryKey) return `setup-vp-Linux-${arch()}-0.1.8`;
169-
if (key === State.VpCacheMatchedKey) return `setup-vp-Linux-${arch()}-0.1.8`;
170-
if (key === State.VpCacheVersion) return "0.1.8";
154+
const key = `setup-vp-Linux-${arch()}-0.1.8-node20`;
155+
vi.mocked(getState).mockImplementation((k: string) => {
156+
if (k === State.VpCachePrimaryKey) return key;
157+
if (k === State.VpCacheMatchedKey) return key;
171158
return "";
172159
});
173160

@@ -176,26 +163,22 @@ describe("saveVpCache", () => {
176163
expect(saveCache).not.toHaveBeenCalled();
177164
});
178165

179-
it("should save only the version-specific directory on cache miss", async () => {
180-
vi.mocked(getState).mockImplementation((key: string) => {
181-
if (key === State.VpCachePrimaryKey) return `setup-vp-Linux-${arch()}-0.1.8`;
182-
if (key === State.VpCacheVersion) return "0.1.8";
166+
it("should save cache on cache miss", async () => {
167+
const key = `setup-vp-Linux-${arch()}-0.1.8-node20`;
168+
vi.mocked(getState).mockImplementation((k: string) => {
169+
if (k === State.VpCachePrimaryKey) return key;
183170
return "";
184171
});
185172
vi.mocked(saveCache).mockResolvedValue(12345);
186173

187174
await saveVpCache();
188175

189-
expect(saveCache).toHaveBeenCalledWith(
190-
["/home/runner/.vite-plus/0.1.8"],
191-
`setup-vp-Linux-${arch()}-0.1.8`,
192-
);
176+
expect(saveCache).toHaveBeenCalledWith(["/home/runner/.vite-plus"], key);
193177
});
194178

195179
it("should handle save errors gracefully", async () => {
196-
vi.mocked(getState).mockImplementation((key: string) => {
197-
if (key === State.VpCachePrimaryKey) return `setup-vp-Linux-${arch()}-0.1.8`;
198-
if (key === State.VpCacheVersion) return "0.1.8";
180+
vi.mocked(getState).mockImplementation((k: string) => {
181+
if (k === State.VpCachePrimaryKey) return `setup-vp-Linux-${arch()}-0.1.8-node20`;
199182
return "";
200183
});
201184
vi.mocked(saveCache).mockRejectedValue(new Error("ReserveCacheError"));

src/cache-vp.ts

Lines changed: 7 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import { restoreCache, saveCache } from "@actions/cache";
22
import { info, debug, saveState, getState, warning } from "@actions/core";
33
import { arch, platform } from "node:os";
4-
import { join } from "node:path";
5-
import { mkdirSync, symlinkSync, rmSync, existsSync } from "node:fs";
64
import { State } from "./types.js";
75
import { getVitePlusHome } from "./utils.js";
86

@@ -29,24 +27,21 @@ export async function resolveVersion(versionInput: string): Promise<string | und
2927
}
3028
}
3129

32-
export async function restoreVpCache(version: string): Promise<boolean> {
30+
export async function restoreVpCache(version: string, nodeVersion: string): Promise<boolean> {
3331
const vpHome = getVitePlusHome();
34-
const versionDir = join(vpHome, version);
3532
const runnerOS = process.env.RUNNER_OS || platform();
3633
const runnerArch = arch();
37-
const primaryKey = `setup-vp-${runnerOS}-${runnerArch}-${version}`;
34+
const primaryKey = `setup-vp-${runnerOS}-${runnerArch}-${version}-node${nodeVersion}`;
3835

3936
debug(`Vp cache key: ${primaryKey}`);
40-
debug(`Vp cache path: ${versionDir}`);
37+
debug(`Vp cache path: ${vpHome}`);
4138
saveState(State.VpCachePrimaryKey, primaryKey);
42-
saveState(State.VpCacheVersion, version);
4339

4440
try {
45-
const matchedKey = await restoreCache([versionDir], primaryKey);
41+
const matchedKey = await restoreCache([vpHome], primaryKey);
4642
if (matchedKey) {
4743
info(`Vite+ restored from cache (key: ${matchedKey})`);
4844
saveState(State.VpCacheMatchedKey, matchedKey);
49-
linkVpVersion(vpHome, version);
5045
return true;
5146
}
5247
} catch (error) {
@@ -56,35 +51,11 @@ export async function restoreVpCache(version: string): Promise<boolean> {
5651
return false;
5752
}
5853

59-
/**
60-
* Recreate the symlinks that the install script normally creates:
61-
* ~/.vite-plus/current → {version}
62-
* ~/.vite-plus/bin/vp → ../current/bin/vp
63-
*/
64-
function linkVpVersion(vpHome: string, version: string): void {
65-
const currentLink = join(vpHome, "current");
66-
const binDir = join(vpHome, "bin");
67-
const binLink = join(binDir, process.platform === "win32" ? "vp.exe" : "vp");
68-
69-
// current → version directory
70-
if (existsSync(currentLink)) rmSync(currentLink);
71-
symlinkSync(version, currentLink);
72-
73-
// bin/vp → ../current/bin/vp
74-
mkdirSync(binDir, { recursive: true });
75-
if (existsSync(binLink)) rmSync(binLink);
76-
symlinkSync(
77-
join("..", "current", "bin", process.platform === "win32" ? "vp.exe" : "vp"),
78-
binLink,
79-
);
80-
}
81-
8254
export async function saveVpCache(): Promise<void> {
8355
const primaryKey = getState(State.VpCachePrimaryKey);
8456
const matchedKey = getState(State.VpCacheMatchedKey);
85-
const version = getState(State.VpCacheVersion);
8657

87-
if (!primaryKey || !version) {
58+
if (!primaryKey) {
8859
debug("No vp cache key found. Skipping save.");
8960
return;
9061
}
@@ -95,8 +66,8 @@ export async function saveVpCache(): Promise<void> {
9566
}
9667

9768
try {
98-
const versionDir = join(getVitePlusHome(), version);
99-
const cacheId = await saveCache([versionDir], primaryKey);
69+
const vpHome = getVitePlusHome();
70+
const cacheId = await saveCache([vpHome], primaryKey);
10071
if (cacheId === -1) {
10172
warning("Vp cache save failed or was skipped.");
10273
return;

src/index.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,16 @@ async function runMain(inputs: Inputs): Promise<void> {
1414
// Mark that post action should run
1515
saveState(State.IsPost, "true");
1616

17-
// Step 1: Install Vite+
18-
await installVitePlus(inputs);
19-
20-
// Step 2: Set up Node.js version if specified
17+
// Step 1: Resolve Node.js version (needed for cache key)
2118
let nodeVersion = inputs.nodeVersion;
2219
if (!nodeVersion && inputs.nodeVersionFile) {
2320
nodeVersion = resolveNodeVersionFile(inputs.nodeVersionFile);
2421
}
2522

23+
// Step 2: Install Vite+ (with cache keyed by vp version + node version)
24+
await installVitePlus(inputs, nodeVersion || "");
25+
26+
// Step 3: Set up Node.js version if specified
2627
if (nodeVersion) {
2728
info(`Setting up Node.js ${nodeVersion} via vp env use...`);
2829
await exec("vp", ["env", "use", nodeVersion]);

src/install-viteplus.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ import { getVitePlusHome } from "./utils.js";
99
const INSTALL_URL_SH = "https://viteplus.dev/install.sh";
1010
const INSTALL_URL_PS1 = "https://viteplus.dev/install.ps1";
1111

12-
export async function installVitePlus(inputs: Inputs): Promise<void> {
12+
export async function installVitePlus(inputs: Inputs, nodeVersion: string): Promise<void> {
1313
const { version } = inputs;
1414

1515
// Try to resolve version and restore from cache
1616
const resolvedVersion = await resolveVersion(version);
1717
if (resolvedVersion) {
18-
const cacheHit = await restoreVpCache(resolvedVersion);
18+
const cacheHit = await restoreVpCache(resolvedVersion, nodeVersion);
1919
if (cacheHit) {
2020
ensureVitePlusBinInPath();
2121
info(`${DISPLAY_NAME} restored from cache`);

src/types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ export enum State {
4848
InstalledVersion = "INSTALLED_VERSION",
4949
VpCachePrimaryKey = "VP_CACHE_PRIMARY_KEY",
5050
VpCacheMatchedKey = "VP_CACHE_MATCHED_KEY",
51-
VpCacheVersion = "VP_CACHE_VERSION",
5251
}
5352

5453
// Output keys

0 commit comments

Comments
 (0)