Skip to content

Commit

Permalink
feat(cli): pnpm is default package manager (#419)
Browse files Browse the repository at this point in the history
* Install dependencies using pnpm

* Use pnpm installer

* Fix cli tests
  • Loading branch information
sebastijankuzner authored Feb 2, 2024
1 parent d22af15 commit 72b59ed
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 33 deletions.
37 changes: 21 additions & 16 deletions packages/cli/source/services/installer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe<{

installer.install("@mainsail/core");

spySync.calledWith("yarn global add @mainsail/core@latest --force", { shell: true });
spySync.calledWith("pnpm install -g @mainsail/core@latest", { shell: true });
});

it("#install - should install specific package when tag is provided", ({ installer }) => {
Expand All @@ -38,7 +38,7 @@ describe<{

installer.install("@mainsail/core", "3.0.0");

spySync.calledWith("yarn global add @mainsail/[email protected] --force", { shell: true });
spySync.calledWith("pnpm install -g @mainsail/[email protected]", { shell: true });
});

it("#install - should throw when exit code isn't 0", ({ installer }) => {
Expand All @@ -51,20 +51,25 @@ describe<{

assert.throws(() => installer.install("@mainsail/core"), "stderr");

spySync.calledWith("yarn global add @mainsail/core@latest --force", { shell: true });
spySync.calledWith("pnpm install -g @mainsail/core@latest", { shell: true });
});

it("#installPeerDependencies - should install each peer dependency", ({ installer }) => {
const spyInstallRangeLatest = stub(installer, "installRangeLatest");

const spySync = stub(execa, "sync").returnValue({
exitCode: 0,
stdout: JSON.stringify({ data: { pm2: "4.5.0", somepkg: "^1.0.0" } }),
});
const spySync = stub(execa, "sync")
.returnValueOnce({
exitCode: 0,
stdout: JSON.stringify({ pm2: "4.5.0", somepkg: "^1.0.0" }),
})
.returnValue({
exitCode: 0,
stdout: "",
});

installer.installPeerDependencies("@mainsail/core", "3.0.0");

spySync.calledWith("yarn info @mainsail/[email protected] peerDependencies --json", {
spySync.calledWith("pnpm info @mainsail/[email protected] peerDependencies --json", {
shell: true,
});

Expand All @@ -77,12 +82,12 @@ describe<{

const spySync = stub(execa, "sync").returnValue({
exitCode: 0,
stdout: JSON.stringify({}),
stdout: "",
});

installer.installPeerDependencies("@mainsail/core", "3.0.0");

spySync.calledWith("yarn info @mainsail/[email protected] peerDependencies --json", {
spySync.calledWith("pnpm info @mainsail/[email protected] peerDependencies --json", {
shell: true,
});

Expand All @@ -97,7 +102,7 @@ describe<{

assert.throws(() => installer.installPeerDependencies("@mainsail/core"), "stderr");

spySync.calledWith("yarn info @mainsail/core@latest peerDependencies --json", {
spySync.calledWith("pnpm info @mainsail/core@latest peerDependencies --json", {
shell: true,
});
});
Expand All @@ -107,12 +112,12 @@ describe<{

const spySync = stub(execa, "sync").returnValue({
exitCode: 0,
stdout: JSON.stringify({ data: ["3.0.0", "3.1.0", "3.0.0-next.9"] }),
stdout: JSON.stringify(["3.0.0", "3.1.0", "3.0.0-next.9"]),
});

installer.installRangeLatest("@mainsail/core", "^3.0.0 <3.4.0");

spySync.calledWith("yarn info @mainsail/core versions --json", {
spySync.calledWith("pnpm info @mainsail/core versions --json", {
shell: true,
});

Expand All @@ -127,7 +132,7 @@ describe<{

assert.throws(() => installer.installRangeLatest("@mainsail/core", "^3.0.0 <3.4.0"), "stderr");

spySync.calledWith("yarn info @mainsail/core versions --json", {
spySync.calledWith("pnpm info @mainsail/core versions --json", {
shell: true,
});
});
Expand All @@ -137,15 +142,15 @@ describe<{
}) => {
const spySync = stub(execa, "sync").returnValue({
exitCode: 0,
stdout: JSON.stringify({ data: ["3.0.0", "3.0.0-next.9"] }),
stdout: JSON.stringify(["3.0.0", "3.0.0-next.9"]),
});

assert.throws(
() => installer.installRangeLatest("@mainsail/core", "^4.0.0 <4.4.0"),
"No @mainsail/core version to satisfy ^4.0.0 <4.4.0".replace(/[\s#$()*+,.?[\\\]^{|}-]/g, "\\$&"),
);

spySync.calledWith("yarn info @mainsail/core versions --json", {
spySync.calledWith("pnpm info @mainsail/core versions --json", {
shell: true,
});
});
Expand Down
57 changes: 46 additions & 11 deletions packages/cli/source/services/installer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,62 @@ import { rcompare, satisfies } from "semver";

import { execa } from "../execa";

type Package = {
pkg: string;
version: string;
};

/**
* @export
* @class Installer
*/
@injectable()
export class Installer {
public install(package_: string, tag = "latest"): void {
/**
* @param {string} pkg
* @memberof Installer
*/
public install(package_: string, tag: string = "latest"): void {
this.installPeerDependencies(package_, tag);

const { stdout, stderr, exitCode } = execa.sync(`yarn global add ${package_}@${tag} --force`, { shell: true });
const { stdout, stderr, exitCode } = execa.sync(`pnpm install -g ${package_}@${tag}`, { shell: true });

if (exitCode !== 0) {
throw new Error(`"yarn global add ${package_}@${tag} --force" exited with code ${exitCode}\n${stderr}`);
throw new Error(`"pnpm install -g ${package_}@${tag}" exited with code ${exitCode}\n${stderr}`);
}

console.log(stdout);
}

public installPeerDependencies(package_: string, tag = "latest"): void {
const { stdout, stderr, exitCode } = execa.sync(`yarn info ${package_}@${tag} peerDependencies --json`, {
public installPeerDependencies(package_: string, tag: string = "latest"): void {
const { stdout, stderr, exitCode } = execa.sync(`pnpm info ${package_}@${tag} peerDependencies --json`, {
shell: true,
});

if (exitCode !== 0) {
throw new Error(
`"yarn info ${package_}@${tag} peerDependencies --json" exited with code ${exitCode}\n${stderr}`,
`"pnpm info ${package_}@${tag} peerDependencies --json" exited with code ${exitCode}\n${stderr}`,
);
}

for (const [peerPackage, peerPackageSemver] of Object.entries(JSON.parse(stdout).data ?? {})) {
this.installRangeLatest(peerPackage, peerPackageSemver as string);
const installedPackages = this.getInstalled();

for (const [peerPackage, peerPackageSemver] of Object.entries(stdout !== "" ? JSON.parse(stdout) : {})) {
const installedPackage = installedPackages.find((installed) => installed.pkg === peerPackage);
if (!installedPackage || !satisfies(installedPackage.version, peerPackageSemver as string)) {
this.installRangeLatest(peerPackage, peerPackageSemver as string);
}
}
}

public installRangeLatest(package_: string, range: string): void {
const { stdout, stderr, exitCode } = execa.sync(`yarn info ${package_} versions --json`, { shell: true });
const { stdout, stderr, exitCode } = execa.sync(`pnpm info ${package_} versions --json`, { shell: true });

if (exitCode !== 0) {
throw new Error(`"yarn info ${package_} versions --json" exited with code ${exitCode}\n${stderr}`);
throw new Error(`"pnpm info ${package_} versions --json" exited with code ${exitCode}\n${stderr}`);
}

const versions = (JSON.parse(stdout).data as string[])
const versions = (stdout !== "" ? (JSON.parse(stdout) as string[]) : [])
.filter((v) => satisfies(v, range))
.sort((a, b) => rcompare(a, b));

Expand All @@ -50,4 +68,21 @@ export class Installer {

this.install(package_, versions[0]);
}

private getInstalled(): Package[] {
const { stdout, stderr, exitCode } = execa.sync(`pnpm list -g --json`, { shell: true });

if (exitCode !== 0) {
throw new Error(`"pnpm list -g --json" exited with code ${exitCode}\n${stderr}`);
}

if (stdout === "") {
return [];
}

return Object.entries<{ version: string }>(JSON.parse(stdout)[0].dependencies).map(([package_, meta]) => ({
pkg: package_,
version: meta.version,
}));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export abstract class AbstractSource implements Source {
}

protected async installDependencies(packageName: string): Promise<void> {
execa.sync(`yarn`, ["install", "--production"], { cwd: this.getDestPath(packageName) });
execa.sync(`pnpm`, ["install", "--production"], { cwd: this.getDestPath(packageName) });
}

protected getOriginPath(): string {
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/source/services/source-providers/file.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ describe<{
const packageName = "@arkecosystem/utils";
removeSync.calledWith(join(dataPath, packageName));
removeSync.calledWith(join(temporaryPath, "package"));
spyOnExeca.calledWith(`yarn`, ["install", "--production"], {
spyOnExeca.calledWith(`pnpm`, ["install", "--production"], {
cwd: join(dataPath, packageName),
});
});
Expand Down Expand Up @@ -78,7 +78,7 @@ describe<{
const packageName = "@arkecosystem/utils";
removeSync.calledWith(join(dataPath, packageName));
removeSync.calledWith(join(temporaryPath, "package"));
spyOnExeca.calledWith(`yarn`, ["install", "--production"], {
spyOnExeca.calledWith(`pnpm`, ["install", "--production"], {
cwd: join(dataPath, packageName),
});
});
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/source/services/source-providers/git.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ describe<{
removeSync.calledWith(targetPath);
removeSync.calledWith(join(tempPath, "package"));
spyOnExeca.calledWith(`git`, ["clone", repository, join(tempPath, "package")]);
spyOnExeca.calledWith(`yarn`, ["install", "--production"], {
spyOnExeca.calledWith(`pnpm`, ["install", "--production"], {
cwd: join(dataPath, packageName),
});
});
Expand All @@ -62,7 +62,7 @@ describe<{
// Assert
spyOnExeca.calledWith(`git`, ["reset", "--hard"], { cwd: join(dataPath, packageName) });
spyOnExeca.calledWith(`git`, ["pull"], { cwd: join(dataPath, packageName) });
spyOnExeca.calledWith(`yarn`, ["install", "--production"], {
spyOnExeca.calledWith(`pnpm`, ["install", "--production"], {
cwd: join(dataPath, packageName),
});
});
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/source/services/source-providers/npm.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ describe<{
moveSync.calledWith(`${tempPath}/package`, pathPlugin);
removeSync.calledWith(pathPlugin);
removeSync.calledWith(`${tempPath}/${packageName}.tgz`);
spyOnExeca.calledWith(`yarn`, ["install", "--production"], {
spyOnExeca.calledWith(`pnpm`, ["install", "--production"], {
cwd: join(dataPath, packageName),
});
});
Expand Down

0 comments on commit 72b59ed

Please sign in to comment.