Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(core,cli): skip unsupported version of lock file #218

Merged
merged 2 commits into from
Aug 2, 2024
Merged
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
55 changes: 55 additions & 0 deletions cli/fixtures/deno.lock.future

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cli/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ main.action(async function (options, ...source) {

const lock = options.lock === false
? undefined
: options.lock ?? await findLock();
: await findLock(options.lock);

source = source.length ? source : config ? [] : await findSource();

Expand Down
19 changes: 19 additions & 0 deletions cli/main_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,25 @@ describe("CLI", () => {
);
});

it("should ignore an unsupported version of lockfile with a warning", async () => {
const { stdout, stderr } = await molt("--lock deno.lock.future");
assertEquals(
stdout,
dedent`
📦 @conventional-commits/parser ^0.3.0 → ^0.4.0
📦 deno.land/std 0.222.0 → 0.224.0
`,
);
assertEquals(
stderr,
dedent`
Unsupported lockfile version: '4'. Please update the lock file manually.
Collecting dependencies
Fetching updates
`,
);
});

it("should filter dependencies with `--only`", async () => {
const { stdout } = await molt("--only flag");
assertEquals(
Expand Down
16 changes: 13 additions & 3 deletions cli/src/files.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { VERSION } from "@molt/core/locks";
import { exists } from "@std/fs";
import { parse } from "@std/jsonc";

Expand All @@ -16,10 +17,19 @@ async function hasImports(config: string): Promise<boolean> {
return jsonc !== null && typeof jsonc === "object" && "imports" in jsonc;
}

export async function findLock() {
if (await exists("deno.lock")) {
return "deno.lock";
export async function findLock(path?: string) {
path ??= await exists("deno.lock") ? "deno.lock" : undefined;
if (!path) {
return;
}
const { version } = JSON.parse(await Deno.readTextFile(path));
if (version !== VERSION) {
console.warn(
`Unsupported lockfile version: '${version}'. Please update the lock file manually.`,
);
return;
}
return path;
}

export async function findSource() {
Expand Down
19 changes: 15 additions & 4 deletions core/locks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,30 @@ export const empty: LockfileJson = {
*
* @param dependency The dependency to create the lock for.
* @param target The target version to update the dependency to.
* @param original The original lockfile to create the partial lock from.
*
* @returns The `LockfileJson` object representing the partial lock.
* @throws If the version of the original lockfile is not supported.
*/
export function create(
dependency: DependencySpec,
target: string,
extracted: LockfileJson,
original: LockfileJson,
): Promise<LockfileJson> {
if (original.version !== VERSION) {
throw new Error(`Unsupported lockfile version: ${original.version}`);
}
return isRemote(dependency)
? createRemoteLock(dependency, extracted)
? createRemoteLock(dependency, original)
: createPackageLock(dependency as DependencySpec<"jsr" | "npm">, target);
}

async function createRemoteLock(
dep: DependencySpec<"http" | "https">,
extracted: LockfileJson,
original: LockfileJson,
): Promise<LockfileJson> {
const { kind, name, constraint, path } = dep;
const reqs = Object.keys(extracted.remote).filter((req) =>
const reqs = Object.keys(original.remote).filter((req) =>
[kind, name, path ?? ""].every((part) => req.includes(part))
);
const lockfile = parseFromJson("", empty);
Expand Down Expand Up @@ -238,6 +245,7 @@ async function getJsrDependencies(
* @param lockfile The `Lockfile` object to extract the partial lock for the dependency from.
* @param dependency The dependency to extract the partial lock for.
* @returns The `LockfileJson` object representing the partial lock.
* @throws If the lockfile version is not supported.
*
* @example
* ```ts
Expand All @@ -249,6 +257,9 @@ export async function extract(
lockfile: LockfileJson,
dependency: DependencySpec,
): Promise<LockfileJson | undefined> {
if (lockfile.version !== VERSION) {
throw new Error(`Unsupported lockfile version: ${lockfile.version}`);
}
return isRemote(dependency)
? await extractRemote(lockfile, dependency)
: extractPackage(lockfile, dependency as DependencySpec<"jsr" | "npm">);
Expand Down
35 changes: 30 additions & 5 deletions core/locks_test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as fs from "@chiezo/amber/fs";
import { assertEquals } from "@std/assert";
import { assertEquals, assertRejects } from "@std/assert";
import { afterEach, beforeEach, describe, it } from "@std/testing/bdd";
import { parse } from "./specs.ts";
import { create, extract, type LockfileJson, query } from "./locks.ts";
Expand Down Expand Up @@ -50,11 +50,23 @@ describe("create", () => {
beforeEach(() => fs.mock());
afterEach(() => fs.dispose());

it("should throw an error for an unsupported lockfile version", async () => {
await assertRejects(
async () => {
await create(parse("jsr:@std/testing@^0.222.0"), "0.222.0", {
version: "4",
} as LockfileJson);
},
Error,
"Unsupported lockfile version: 4",
);
});

it("should create a partial lock for a package with a patch update", async () => {
const lock = await create(
parse("jsr:@std/assert@^0.222.0"),
"0.222.1",
{} as LockfileJson,
{ version: "3" } as LockfileJson,
);
assertEquals(lock, {
version: "3",
Expand Down Expand Up @@ -86,7 +98,7 @@ describe("create", () => {
const lock = await create(
parse("jsr:@std/assert@^0.226.0"),
"0.226.0",
{} as LockfileJson,
{ version: "3" } as LockfileJson,
);
assertEquals(lock, {
version: "3",
Expand Down Expand Up @@ -116,7 +128,7 @@ describe("create", () => {
const lock = await create(
parse("jsr:@core/match@^0.2.0"),
"0.2.5",
{} as LockfileJson,
{ version: "3" } as LockfileJson,
);
assertEquals(lock, {
version: "3",
Expand Down Expand Up @@ -149,7 +161,7 @@ describe("create", () => {
const lock = await create(
parse("npm:@conventional-commits/parser@^0.4.0"),
"0.4.1",
{} as LockfileJson,
{ version: "3" } as LockfileJson,
);
assertEquals(lock, {
version: "3",
Expand Down Expand Up @@ -246,6 +258,19 @@ describe("extract", () => {
beforeEach(() => fs.mock());
afterEach(() => fs.dispose());

it("should throw an error for an unsupported lockfile version", async () => {
await assertRejects(
async () => {
await extract(
{ version: "4" } as LockfileJson,
parse("jsr:@std/testing@^0.222.0"),
);
},
Error,
"Unsupported lockfile version: 4",
);
});

it("should return undefined for an unlocked package", async () => {
const dep = parse("jsr:@std/testing@^0.222.0");
const lock = await extract(LOCKFILE, dep);
Expand Down