修改 meta.json 规则, 涉及version 、group 字段.
This commit is contained in:
@@ -0,0 +1,260 @@
|
||||
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
||||
import fs from "fs";
|
||||
import os from "os";
|
||||
import path from "path";
|
||||
|
||||
const RUN_MANUAL = process.env.KIT_REMOTE_MANU_TEST === "1";
|
||||
const manualDescribe = RUN_MANUAL ? describe : describe.skip;
|
||||
const manualTest = RUN_MANUAL ? test : test.skip;
|
||||
|
||||
let Remote;
|
||||
if (RUN_MANUAL) {
|
||||
require("../src/init");
|
||||
Remote = require("../src/remote");
|
||||
}
|
||||
|
||||
async function createRemote() {
|
||||
const remote = new Remote();
|
||||
await remote.init();
|
||||
return remote;
|
||||
}
|
||||
|
||||
function writeFixtureProject(tempDir, version, content, options = {}) {
|
||||
const projectId = options.id || "myapp";
|
||||
const group = options.group === undefined ? "/modules" : options.group;
|
||||
const projectDir = path.resolve(tempDir, `fixture-${projectId}-${version || "auto"}-${Math.random().toString(16).slice(2)}`);
|
||||
fs.mkdirSync(projectDir, { recursive: true });
|
||||
|
||||
const filePath = path.resolve(projectDir, "myapp.txt");
|
||||
fs.writeFileSync(filePath, content, "utf-8");
|
||||
|
||||
fs.writeFileSync(path.resolve(projectDir, "meta.json"), JSON.stringify({
|
||||
id: projectId,
|
||||
group,
|
||||
version,
|
||||
desc: "test app",
|
||||
official_url: "https://example.test/myapp",
|
||||
dist: [
|
||||
{
|
||||
path: filePath,
|
||||
os: "any",
|
||||
platform: "any",
|
||||
filename: "myapp.txt",
|
||||
type: "data"
|
||||
}
|
||||
]
|
||||
}, null, 4), "utf-8");
|
||||
|
||||
return projectDir;
|
||||
}
|
||||
|
||||
function normalizeRemotePath(value) {
|
||||
if (!value || value === "/") {
|
||||
return "/";
|
||||
}
|
||||
return path.posix.normalize("/" + String(value).replace(/\\/g, "/")).replace(/\/+$/g, "") || "/";
|
||||
}
|
||||
|
||||
function remoteProjectPath(group, projectId) {
|
||||
const normalizedGroup = group === undefined ? "/modules" : normalizeRemotePath(group);
|
||||
return normalizeRemotePath(path.posix.join(normalizedGroup, projectId));
|
||||
}
|
||||
|
||||
async function deleteRemotePath(remote, remotePath) {
|
||||
try {
|
||||
if (remote.client && remote.client.deleteFile && await remote.client.exists(remotePath)) {
|
||||
await remote.client.deleteFile(remotePath);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(`cleanup remote failed ${remotePath}: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
let tempDir;
|
||||
let localStore;
|
||||
let remote;
|
||||
let runId;
|
||||
let counter;
|
||||
let projectIds;
|
||||
let remoteRoots;
|
||||
|
||||
beforeEach(async () => {
|
||||
if (!RUN_MANUAL) {
|
||||
return;
|
||||
}
|
||||
tempDir = fs.mkdtempSync(path.resolve(os.tmpdir(), "kit-remote-manu-test-"));
|
||||
localStore = $sConfig.getLocalStorePath();
|
||||
remote = await createRemote();
|
||||
runId = `${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
||||
counter = 0;
|
||||
projectIds = [];
|
||||
remoteRoots = [];
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
if (!RUN_MANUAL) {
|
||||
return;
|
||||
}
|
||||
for (const remoteRoot of remoteRoots.reverse()) {
|
||||
await deleteRemotePath(remote, remoteRoot);
|
||||
}
|
||||
for (const projectId of projectIds) {
|
||||
fs.rmSync(path.resolve(localStore, "modules", projectId), { recursive: true, force: true });
|
||||
}
|
||||
fs.rmSync(tempDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
function nextProjectId() {
|
||||
const projectId = `myapp-${runId}-${++counter}`.toLowerCase();
|
||||
projectIds.push(projectId);
|
||||
return projectId;
|
||||
}
|
||||
|
||||
function trackRemote(group, projectId) {
|
||||
const root = remoteProjectPath(group, projectId);
|
||||
remoteRoots.push(root);
|
||||
return root;
|
||||
}
|
||||
|
||||
manualDescribe("remote module public API manual webdav", () => {
|
||||
manualTest("exposes documented public methods", async () => {
|
||||
expect(typeof remote.check).toBe("function");
|
||||
expect(typeof remote.publish).toBe("function");
|
||||
expect(typeof remote.install).toBe("function");
|
||||
expect(typeof remote.list).toBe("function");
|
||||
expect(typeof remote.use).toBe("function");
|
||||
expect(typeof remote.rollback).toBe("function");
|
||||
expect(typeof remote.remove).toBe("function");
|
||||
});
|
||||
|
||||
manualTest("check validates an available webdav client", async () => {
|
||||
expect(await remote.check()).toBe(true);
|
||||
});
|
||||
|
||||
manualTest("publish stores files under default group /modules/id", async () => {
|
||||
const projectId = nextProjectId();
|
||||
trackRemote("/modules", projectId);
|
||||
const projectDir = writeFixtureProject(tempDir, "1.0", "hello v1", { id: projectId });
|
||||
|
||||
await remote.publish(projectDir);
|
||||
|
||||
const metadata = JSON.parse(await remote.client.getFileContents(`/modules/${projectId}/metadata.json`, { format: "text" }));
|
||||
const version = JSON.parse(await remote.client.getFileContents(`/modules/${projectId}/1.0/version.json`, { format: "text" }));
|
||||
const artifact = await remote.client.getFileContents(`/modules/${projectId}/1.0/any/any/myapp.txt`, { format: "text" });
|
||||
|
||||
expect(metadata.project_id).toBe(projectId);
|
||||
expect(metadata.group).toBe("/modules");
|
||||
expect(metadata.version).toBe("1.0");
|
||||
expect(metadata.versions).toBeUndefined();
|
||||
expect(metadata.latest_version).toBeUndefined();
|
||||
expect(version.artifacts[0].path).toBe("any/any/myapp.txt");
|
||||
expect(artifact).toBe("hello v1");
|
||||
}, 30000);
|
||||
|
||||
manualTest("publish supports custom nested group", async () => {
|
||||
const projectId = nextProjectId();
|
||||
const group = `/kit-manual-test/${runId}/docker/net`;
|
||||
trackRemote(group, projectId);
|
||||
await remote.publish(writeFixtureProject(tempDir, "2.0", "docker net", { id: projectId, group }));
|
||||
|
||||
const metadata = JSON.parse(await remote.client.getFileContents(`${group}/${projectId}/metadata.json`, { format: "text" }));
|
||||
const artifact = await remote.client.getFileContents(`${group}/${projectId}/2.0/any/any/myapp.txt`, { format: "text" });
|
||||
|
||||
expect(metadata.group).toBe(group);
|
||||
expect(metadata.version).toBe("2.0");
|
||||
expect(artifact).toBe("docker net");
|
||||
}, 30000);
|
||||
|
||||
manualTest("empty group stores project at repository root", async () => {
|
||||
const projectId = nextProjectId();
|
||||
trackRemote("", projectId);
|
||||
await remote.publish(writeFixtureProject(tempDir, "1.0", "root group", { id: projectId, group: "" }));
|
||||
|
||||
const metadata = JSON.parse(await remote.client.getFileContents(`/${projectId}/metadata.json`, { format: "text" }));
|
||||
expect(metadata.group).toBe("/");
|
||||
expect(await remote.client.getFileContents(`/${projectId}/1.0/any/any/myapp.txt`, { format: "text" })).toBe("root group");
|
||||
}, 30000);
|
||||
|
||||
manualTest("explicit version fails when remote version already exists", async () => {
|
||||
const projectId = nextProjectId();
|
||||
trackRemote("/modules", projectId);
|
||||
await remote.publish(writeFixtureProject(tempDir, "1.0", "hello v1", { id: projectId }));
|
||||
|
||||
await expect(remote.publish(writeFixtureProject(tempDir, "1.0", "hello again", { id: projectId }))).rejects.toThrow("远程版本已存在");
|
||||
}, 30000);
|
||||
|
||||
manualTest("blank version increments remote version tail or starts at 1.0", async () => {
|
||||
const projectId = nextProjectId();
|
||||
trackRemote("/modules", projectId);
|
||||
|
||||
await remote.publish(writeFixtureProject(tempDir, "", "first auto", { id: projectId }));
|
||||
let metadata = JSON.parse(await remote.client.getFileContents(`/modules/${projectId}/metadata.json`, { format: "text" }));
|
||||
expect(metadata.version).toBe("1.0");
|
||||
|
||||
await remote.publish(writeFixtureProject(tempDir, "", "second auto", { id: projectId }));
|
||||
metadata = JSON.parse(await remote.client.getFileContents(`/modules/${projectId}/metadata.json`, { format: "text" }));
|
||||
expect(metadata.version).toBe("1.1");
|
||||
expect(await remote.client.getFileContents(`/modules/${projectId}/1.1/any/any/myapp.txt`, { format: "text" })).toBe("second auto");
|
||||
}, 30000);
|
||||
|
||||
manualTest("install downloads latest version from default group", async () => {
|
||||
const projectId = nextProjectId();
|
||||
trackRemote("/modules", projectId);
|
||||
await remote.publish(writeFixtureProject(tempDir, "1.0", "hello v1", { id: projectId }));
|
||||
|
||||
const installed = await remote.install(projectId);
|
||||
|
||||
const moduleRoot = path.resolve(localStore, "modules", projectId);
|
||||
const installJson = JSON.parse(fs.readFileSync(path.resolve(moduleRoot, ".meta", "install.json"), "utf-8"));
|
||||
const installedFile = fs.readFileSync(path.resolve(moduleRoot, "versions", "1.0", "any", "any", "myapp.txt"), "utf-8");
|
||||
|
||||
expect(installed).toBe("1.0");
|
||||
expect(installedFile).toBe("hello v1");
|
||||
expect(installJson.current_version).toBe("1.0");
|
||||
expect(installJson.installed_versions).toContain("1.0");
|
||||
expect(fs.existsSync(path.resolve(moduleRoot, "current"))).toBe(true);
|
||||
}, 30000);
|
||||
|
||||
manualTest("install can target a custom group path", async () => {
|
||||
const projectId = nextProjectId();
|
||||
const group = `/kit-manual-test/${runId}/docker/net`;
|
||||
trackRemote(group, projectId);
|
||||
await remote.publish(writeFixtureProject(tempDir, "1.0", "docker install", { id: projectId, group }));
|
||||
|
||||
const installed = await remote.install(`${group}/${projectId}`);
|
||||
const installedFile = fs.readFileSync(path.resolve(localStore, "modules", projectId, "versions", "1.0", "any", "any", "myapp.txt"), "utf-8");
|
||||
|
||||
expect(installed).toBe("1.0");
|
||||
expect(installedFile).toBe("docker install");
|
||||
}, 30000);
|
||||
|
||||
manualTest("list use rollback and remove manage installed versions", async () => {
|
||||
const projectId = nextProjectId();
|
||||
trackRemote("/modules", projectId);
|
||||
await remote.publish(writeFixtureProject(tempDir, "1.0", "hello v1", { id: projectId }));
|
||||
await remote.install(projectId);
|
||||
await remote.publish(writeFixtureProject(tempDir, "2.0", "hello v2", { id: projectId }));
|
||||
await remote.install(projectId);
|
||||
|
||||
expect(await remote.list(projectId)).toEqual(["1.0", "2.0"]);
|
||||
|
||||
await remote.rollback(projectId);
|
||||
let installJson = JSON.parse(fs.readFileSync(path.resolve(localStore, "modules", projectId, ".meta", "install.json"), "utf-8"));
|
||||
expect(installJson.current_version).toBe("1.0");
|
||||
|
||||
await remote.use(`${projectId}@2.0`);
|
||||
installJson = JSON.parse(fs.readFileSync(path.resolve(localStore, "modules", projectId, ".meta", "install.json"), "utf-8"));
|
||||
expect(installJson.current_version).toBe("2.0");
|
||||
|
||||
await remote.remove(`${projectId}@1.0`);
|
||||
installJson = JSON.parse(fs.readFileSync(path.resolve(localStore, "modules", projectId, ".meta", "install.json"), "utf-8"));
|
||||
expect(installJson.installed_versions).toEqual(["2.0"]);
|
||||
expect(fs.existsSync(path.resolve(localStore, "modules", projectId, "versions", "1.0"))).toBe(false);
|
||||
}, 30000);
|
||||
});
|
||||
|
||||
if (!RUN_MANUAL) {
|
||||
describe("remote manual webdav tests", () => {
|
||||
test.skip("set KIT_REMOTE_MANU_TEST=1 and run bun test test/remote_manu_test.js", () => {});
|
||||
});
|
||||
}
|
||||
+193
-42
@@ -2,17 +2,101 @@
|
||||
import fs from "fs";
|
||||
import os from "os";
|
||||
import path from "path";
|
||||
import { Readable, Writable } from "stream";
|
||||
import Remote from "../src/remote";
|
||||
|
||||
require("../src/init")
|
||||
async function createRemote() {
|
||||
const Remote = require("../src/remote")
|
||||
const remote = new Remote();
|
||||
await remote.init()
|
||||
return remote
|
||||
class MemoryWebdavClient {
|
||||
constructor() {
|
||||
this.files = new Map();
|
||||
this.dirs = new Set(["/"]);
|
||||
}
|
||||
|
||||
normalize(remotePath) {
|
||||
const normalized = path.posix.normalize("/" + String(remotePath || "").replace(/\\/g, "/"));
|
||||
return normalized === "/" ? "/" : normalized.replace(/\/$/, "");
|
||||
}
|
||||
|
||||
async exists(remotePath) {
|
||||
const key = this.normalize(remotePath);
|
||||
return this.dirs.has(key) || this.files.has(key);
|
||||
}
|
||||
|
||||
async createDirectory(remotePath) {
|
||||
const key = this.normalize(remotePath);
|
||||
const parts = key.split("/").filter(Boolean);
|
||||
let current = "";
|
||||
for (const part of parts) {
|
||||
current += "/" + part;
|
||||
this.dirs.add(current);
|
||||
}
|
||||
}
|
||||
|
||||
async getDirectoryContents(remotePath) {
|
||||
const dir = this.normalize(remotePath);
|
||||
const prefix = dir === "/" ? "/" : dir + "/";
|
||||
const names = new Map();
|
||||
for (const item of [...this.dirs, ...this.files.keys()]) {
|
||||
if (item === dir || !item.startsWith(prefix)) {
|
||||
continue;
|
||||
}
|
||||
const rest = item.slice(prefix.length);
|
||||
const name = rest.split("/")[0];
|
||||
names.set(name, prefix + name);
|
||||
}
|
||||
return [...names].map(([basename, filename]) => ({ basename, filename, type: this.dirs.has(this.normalize(filename)) ? "directory" : "file" }));
|
||||
}
|
||||
|
||||
async putFileContents(remotePath, content) {
|
||||
const key = this.normalize(remotePath);
|
||||
await this.createDirectory(path.posix.dirname(key));
|
||||
this.files.set(key, Buffer.isBuffer(content) ? content : Buffer.from(String(content)));
|
||||
}
|
||||
|
||||
async getFileContents(remotePath, options = {}) {
|
||||
const key = this.normalize(remotePath);
|
||||
if (!this.files.has(key)) {
|
||||
throw new Error(`missing ${key}`);
|
||||
}
|
||||
const data = this.files.get(key);
|
||||
return options.format === "text" ? data.toString("utf-8") : data;
|
||||
}
|
||||
|
||||
createWriteStream(remotePath) {
|
||||
const key = this.normalize(remotePath);
|
||||
const chunks = [];
|
||||
const stream = new Writable({
|
||||
write(chunk, encoding, callback) {
|
||||
chunks.push(Buffer.from(chunk));
|
||||
callback();
|
||||
}
|
||||
});
|
||||
stream.on("finish", () => {
|
||||
this.createDirectory(path.posix.dirname(key));
|
||||
this.files.set(key, Buffer.concat(chunks));
|
||||
});
|
||||
return stream;
|
||||
}
|
||||
|
||||
createReadStream(remotePath) {
|
||||
const key = this.normalize(remotePath);
|
||||
if (!this.files.has(key)) {
|
||||
throw new Error(`missing ${key}`);
|
||||
}
|
||||
return Readable.from(this.files.get(key));
|
||||
}
|
||||
|
||||
async stat(remotePath) {
|
||||
const key = this.normalize(remotePath);
|
||||
const data = this.files.get(key);
|
||||
if (!data) {
|
||||
throw new Error(`missing ${key}`);
|
||||
}
|
||||
return { size: data.length };
|
||||
}
|
||||
}
|
||||
|
||||
function writeFixtureProject(tempDir, version, content) {
|
||||
const projectDir = path.resolve(tempDir, `fixture-${version}`);
|
||||
function writeFixtureProject(tempDir, version, content, group = "/modules") {
|
||||
const projectDir = path.resolve(tempDir, `fixture-${version || "auto"}-${Math.random().toString(16).slice(2)}`);
|
||||
fs.mkdirSync(projectDir, { recursive: true });
|
||||
|
||||
const filePath = path.resolve(projectDir, "myapp.txt");
|
||||
@@ -20,6 +104,7 @@ function writeFixtureProject(tempDir, version, content) {
|
||||
|
||||
fs.writeFileSync(path.resolve(projectDir, "meta.json"), JSON.stringify({
|
||||
id: "myapp",
|
||||
group,
|
||||
version,
|
||||
desc: "test app",
|
||||
official_url: "https://example.test/myapp",
|
||||
@@ -37,21 +122,35 @@ function writeFixtureProject(tempDir, version, content) {
|
||||
return projectDir;
|
||||
}
|
||||
|
||||
function createRemote() {
|
||||
const remote = new Remote();
|
||||
remote.client = new MemoryWebdavClient();
|
||||
return remote;
|
||||
}
|
||||
|
||||
let tempDir;
|
||||
let localStore;
|
||||
let oldLogger;
|
||||
let oldConfig;
|
||||
|
||||
beforeEach(() => {
|
||||
tempDir = fs.mkdtempSync(path.resolve(os.tmpdir(), "kit-remote-test"));
|
||||
localStore = $sConfig.getLocalStorePath();
|
||||
tempDir = fs.mkdtempSync(path.resolve(os.tmpdir(), "kit-remote-test-"));
|
||||
localStore = path.resolve(tempDir, "local-store");
|
||||
oldLogger = globalThis.$logger;
|
||||
oldConfig = globalThis.$sConfig;
|
||||
globalThis.$logger = { info() {}, warn() {}, error() {}, debug() {} };
|
||||
globalThis.$sConfig = { getLocalStorePath: () => localStore };
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
globalThis.$logger = oldLogger;
|
||||
globalThis.$sConfig = oldConfig;
|
||||
fs.rmSync(tempDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
describe("remote module public API", () => {
|
||||
test("1-1 exposes documented public methods", async() => {
|
||||
const remote = await createRemote();
|
||||
test("exposes documented public methods", () => {
|
||||
const remote = createRemote();
|
||||
expect(typeof remote.check).toBe("function");
|
||||
expect(typeof remote.publish).toBe("function");
|
||||
expect(typeof remote.install).toBe("function");
|
||||
@@ -61,67 +160,119 @@ describe("remote module public API", () => {
|
||||
expect(typeof remote.remove).toBe("function");
|
||||
});
|
||||
|
||||
test("1-2 check validates an available webdav client", async () => {
|
||||
const remote = await createRemote();
|
||||
test("check validates an available webdav client", async () => {
|
||||
const remote = createRemote();
|
||||
expect(await remote.check()).toBe(true);
|
||||
});
|
||||
|
||||
test("1-3 publish stores metadata and version artifacts in webdav layout", async () => {
|
||||
const remote = await createRemote();
|
||||
const projectDir = writeFixtureProject(tempDir, "1.0.0", "hello v1");
|
||||
test("publish stores files under default group /modules/id", async () => {
|
||||
const remote = createRemote();
|
||||
const projectDir = writeFixtureProject(tempDir, "1.0", "hello v1");
|
||||
|
||||
await remote.publish(projectDir);
|
||||
|
||||
const metadata = JSON.parse(await remote.client.getFileContents("/myapp/metadata.json", { format: "text" }));
|
||||
const version = JSON.parse(await remote.client.getFileContents("/myapp/1.0.0/version.json", { format: "text" }));
|
||||
const artifact = await remote.client.getFileContents("/myapp/1.0.0/any/any/myapp.txt", { format: "text" });
|
||||
const metadata = JSON.parse(await remote.client.getFileContents("/modules/myapp/metadata.json", { format: "text" }));
|
||||
const version = JSON.parse(await remote.client.getFileContents("/modules/myapp/1.0/version.json", { format: "text" }));
|
||||
const artifact = await remote.client.getFileContents("/modules/myapp/1.0/any/any/myapp.txt", { format: "text" });
|
||||
|
||||
expect(metadata.project_id).toBe("myapp");
|
||||
expect(metadata.latest_version).toBe("1.0.0");
|
||||
expect(metadata.versions).toContain("1.0.0");
|
||||
expect(metadata.group).toBe("/modules");
|
||||
expect(metadata.version).toBe("1.0");
|
||||
expect(metadata.versions).toBeUndefined();
|
||||
expect(metadata.latest_version).toBeUndefined();
|
||||
expect(version.artifacts[0].path).toBe("any/any/myapp.txt");
|
||||
expect(artifact).toBe("hello v1");
|
||||
}, 30000);
|
||||
});
|
||||
|
||||
test("install downloads latest matching artifact and records local state", async () => {
|
||||
const remote = await createRemote();
|
||||
const projectDir = writeFixtureProject(tempDir, "1.0.0", "hello v1");
|
||||
await remote.publish(projectDir);
|
||||
test("publish supports custom nested group", async () => {
|
||||
const remote = createRemote();
|
||||
await remote.publish(writeFixtureProject(tempDir, "2.0", "docker net", "/docker/net"));
|
||||
|
||||
const metadata = JSON.parse(await remote.client.getFileContents("/docker/net/myapp/metadata.json", { format: "text" }));
|
||||
const artifact = await remote.client.getFileContents("/docker/net/myapp/2.0/any/any/myapp.txt", { format: "text" });
|
||||
|
||||
expect(metadata.group).toBe("/docker/net");
|
||||
expect(metadata.version).toBe("2.0");
|
||||
expect(artifact).toBe("docker net");
|
||||
});
|
||||
|
||||
test("empty group stores project at repository root", async () => {
|
||||
const remote = createRemote();
|
||||
await remote.publish(writeFixtureProject(tempDir, "1.0", "root group", ""));
|
||||
|
||||
const metadata = JSON.parse(await remote.client.getFileContents("/myapp/metadata.json", { format: "text" }));
|
||||
expect(metadata.group).toBe("/");
|
||||
expect(await remote.client.getFileContents("/myapp/1.0/any/any/myapp.txt", { format: "text" })).toBe("root group");
|
||||
});
|
||||
|
||||
test("explicit version fails when remote version already exists", async () => {
|
||||
const remote = createRemote();
|
||||
await remote.publish(writeFixtureProject(tempDir, "1.0", "hello v1"));
|
||||
|
||||
await expect(remote.publish(writeFixtureProject(tempDir, "1.0", "hello again"))).rejects.toThrow("远程版本已存在");
|
||||
});
|
||||
|
||||
test("blank version increments remote version tail or starts at 1.0", async () => {
|
||||
const remote = createRemote();
|
||||
|
||||
await remote.publish(writeFixtureProject(tempDir, "", "first auto"));
|
||||
let metadata = JSON.parse(await remote.client.getFileContents("/modules/myapp/metadata.json", { format: "text" }));
|
||||
expect(metadata.version).toBe("1.0");
|
||||
|
||||
await remote.publish(writeFixtureProject(tempDir, "", "second auto"));
|
||||
metadata = JSON.parse(await remote.client.getFileContents("/modules/myapp/metadata.json", { format: "text" }));
|
||||
expect(metadata.version).toBe("1.1");
|
||||
expect(await remote.client.getFileContents("/modules/myapp/1.1/any/any/myapp.txt", { format: "text" })).toBe("second auto");
|
||||
});
|
||||
|
||||
test("install downloads latest version from default group", async () => {
|
||||
const remote = createRemote();
|
||||
await remote.publish(writeFixtureProject(tempDir, "1.0", "hello v1"));
|
||||
|
||||
const installed = await remote.install("myapp");
|
||||
|
||||
const moduleRoot = path.resolve(localStore, "modules", "myapp");
|
||||
const installJson = JSON.parse(fs.readFileSync(path.resolve(moduleRoot, ".meta", "install.json"), "utf-8"));
|
||||
const installedFile = fs.readFileSync(path.resolve(moduleRoot, "versions", "1.0.0", "any", "any", "myapp.txt"), "utf-8");
|
||||
const installedFile = fs.readFileSync(path.resolve(moduleRoot, "versions", "1.0", "any", "any", "myapp.txt"), "utf-8");
|
||||
|
||||
expect(installed).toBe("1.0.0");
|
||||
expect(installed).toBe("1.0");
|
||||
expect(installedFile).toBe("hello v1");
|
||||
expect(installJson.current_version).toBe("1.0.0");
|
||||
expect(installJson.installed_versions).toContain("1.0.0");
|
||||
expect(installJson.current_version).toBe("1.0");
|
||||
expect(installJson.installed_versions).toContain("1.0");
|
||||
expect(fs.existsSync(path.resolve(moduleRoot, "current"))).toBe(true);
|
||||
});
|
||||
|
||||
test("install can target a custom group path", async () => {
|
||||
const remote = createRemote();
|
||||
await remote.publish(writeFixtureProject(tempDir, "1.0", "docker install", "/docker/net"));
|
||||
|
||||
const installed = await remote.install("/docker/net/myapp");
|
||||
const installedFile = fs.readFileSync(path.resolve(localStore, "modules", "myapp", "versions", "1.0", "any", "any", "myapp.txt"), "utf-8");
|
||||
|
||||
expect(installed).toBe("1.0");
|
||||
expect(installedFile).toBe("docker install");
|
||||
});
|
||||
|
||||
test("list use rollback and remove manage installed versions", async () => {
|
||||
const remote = await createRemote();
|
||||
await remote.publish(writeFixtureProject(tempDir, "1.0.0", "hello v1"));
|
||||
const remote = createRemote();
|
||||
await remote.publish(writeFixtureProject(tempDir, "1.0", "hello v1"));
|
||||
await remote.install("myapp");
|
||||
await remote.publish(writeFixtureProject(tempDir, "2.0.0", "hello v2"));
|
||||
await remote.publish(writeFixtureProject(tempDir, "2.0", "hello v2"));
|
||||
await remote.install("myapp");
|
||||
|
||||
expect(await remote.list("myapp")).toEqual(["1.0.0", "2.0.0"]);
|
||||
expect(await remote.list("myapp")).toEqual(["1.0", "2.0"]);
|
||||
|
||||
await remote.rollback("myapp");
|
||||
let installJson = JSON.parse(fs.readFileSync(path.resolve(localStore, "modules", "myapp", ".meta", "install.json"), "utf-8"));
|
||||
expect(installJson.current_version).toBe("1.0.0");
|
||||
expect(installJson.current_version).toBe("1.0");
|
||||
|
||||
await remote.use("myapp@2.0.0");
|
||||
await remote.use("myapp@2.0");
|
||||
installJson = JSON.parse(fs.readFileSync(path.resolve(localStore, "modules", "myapp", ".meta", "install.json"), "utf-8"));
|
||||
expect(installJson.current_version).toBe("2.0.0");
|
||||
expect(installJson.current_version).toBe("2.0");
|
||||
|
||||
await remote.remove("myapp@1.0.0");
|
||||
await remote.remove("myapp@1.0");
|
||||
installJson = JSON.parse(fs.readFileSync(path.resolve(localStore, "modules", "myapp", ".meta", "install.json"), "utf-8"));
|
||||
expect(installJson.installed_versions).toEqual(["2.0.0"]);
|
||||
expect(fs.existsSync(path.resolve(localStore, "modules", "myapp", "versions", "1.0.0"))).toBe(false);
|
||||
expect(installJson.installed_versions).toEqual(["2.0"]);
|
||||
expect(fs.existsSync(path.resolve(localStore, "modules", "myapp", "versions", "1.0"))).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user