Skip to content

Commit

Permalink
Merge pull request #4 from piotr-oles/feature/add-lock-file-storage
Browse files Browse the repository at this point in the history
feat: add lock file storage
  • Loading branch information
piotr-oles authored Feb 24, 2021
2 parents f31af93 + af044c1 commit 6590b6c
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 36 deletions.
10 changes: 4 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
<div align="center">

<h1>karton </h1>
<p>Create sandbox for E2E tests 📦</p>
<p>Test your package in a sandbox 📦</p>
<p>⚠️ In development ⚠️</p>

</div>

## Installation

This loader requires minimum Node.js 10
This package requires minimum Node.js 10

```sh
# with npm
Expand Down Expand Up @@ -47,17 +48,14 @@ describe('my-package', () => {
});
afterAll(async () => {
await sandbox.cleanup();
await myPackage.remove();
})

it.each([
externalPackage('webpack', '^4.0.0'),
externalPackage('webpack', '^5.0.0')
])('works with webpack %p', async (webpack) => {
await sandbox.load(path.join(__dirname, 'fixtures/basic'));
await sandbox.install('yarn', {
dependencies: [myPackage, webpack]
});
await sandbox.install('yarn', [myPackage, webpack]);
const result = await sandbox.exec('node src/test.js');

expect(result).toEqual('my-package awesome output');
Expand Down
86 changes: 56 additions & 30 deletions src/sandbox.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { resolve, dirname } from "path";
import fs from "fs-extra";
import os from "os";
import crypto from "crypto";
import { exec, ChildProcess } from "child_process";
import spawn from "cross-spawn";
import stripAnsi from "strip-ansi";
Expand All @@ -9,28 +10,24 @@ import { defaultLogger, Logger } from "./logger";
import { Package } from "./package";
import { retry, RetryOptions, wait } from "./async";

type PackageManager = "yarn" | "npm";

interface InstallOverwrites {
dependencies?: Package[];
devDependencies?: Package[];
optionalDependencies?: Package[];
}

interface CommandOptions {
cwd?: string;
env?: Record<string, string>;
}

interface InstallOptions {
lockDirectory?: string;
}

interface Sandbox {
context: string;
reset(options?: RetryOptions): Promise<void>;
cleanup(options?: RetryOptions): Promise<void>;
load(directory: string, options?: RetryOptions): Promise<void>;
install(
manager: PackageManager,
overwrites: InstallOverwrites,
options?: RetryOptions
manager: "yarn" | "npm",
overwrites: Package[],
options?: InstallOptions & RetryOptions
): Promise<void>;
write(path: string, content: string, options?: RetryOptions): Promise<void>;
read(path: string, options?: RetryOptions): Promise<string>;
Expand Down Expand Up @@ -103,9 +100,9 @@ async function createSandbox(logger: Logger = defaultLogger): Promise<Sandbox> {
return retry(() => fs.copy(directory, context), logger, options);
},
install: async (
manager: PackageManager,
overwrites: InstallOverwrites = {},
options?: RetryOptions
manager: "yarn" | "npm",
overwrites: Package[],
options?: InstallOptions & RetryOptions
) => {
logger.log("Installing dependencies...");

Expand All @@ -115,36 +112,65 @@ async function createSandbox(logger: Logger = defaultLogger): Promise<Sandbox> {
);
}

const packageJSON = JSON.parse(
const originalPackageJSON = JSON.parse(
await sandbox.read("package.json", options)
);
for (const target of [
"dependencies",
"devDependencies",
"optionalDependencies",
] as const) {
const packages = overwrites[target];
if (packages) {
if (!packageJSON[target]) {
packageJSON[target] = {};
}
for (const pkg of packages) {
packageJSON[target][pkg.name] = pkg.version;
}
}
const packageJSON = {
...originalPackageJSON,
dependencies: originalPackageJSON.dependencies || {},
};
for (const { name, version } of overwrites) {
packageJSON.dependencies[name] = version;
}
await sandbox.write(
"package.json",
JSON.stringify(packageJSON, undefined, " "),
options
);

let lockFile: string | undefined;
if (options?.lockDirectory) {
lockFile = resolve(
options.lockDirectory,
`${crypto
.createHash("md5")
.update(
JSON.stringify([
manager,
overwrites.filter((pkg) => pkg.immutable),
originalPackageJSON.dependencies,
originalPackageJSON.devDependencies,
])
)
.digest("hex")}.lock`
);
}

const tryToLoadLockFile = async (managerFile: string) => {
if (lockFile && (await fs.pathExists(lockFile))) {
await sandbox.write(
managerFile,
await fs.readFile(lockFile, "utf-8")
);
}
};

const tryToStoreLockFile = async (managerFile: string) => {
if (lockFile && (await sandbox.exists(managerFile))) {
await fs.writeFile(lockFile, await sandbox.read(managerFile));
}
};

switch (manager) {
case "yarn":
await tryToLoadLockFile("yarn.lock");
await sandbox.exec(`yarn install --prefer-offline`, options);
await tryToStoreLockFile("yarn.lock");
break;
case "npm":
await tryToLoadLockFile("package-lock.json");
await sandbox.exec(`npm install`, options);
await tryToStoreLockFile("package-lock.json");
break;
}
},
Expand Down Expand Up @@ -313,4 +339,4 @@ async function createSandbox(logger: Logger = defaultLogger): Promise<Sandbox> {
return sandbox;
}

export { Sandbox, createSandbox, PackageManager, InstallOverwrites };
export { Sandbox, createSandbox };

0 comments on commit 6590b6c

Please sign in to comment.