Skip to content

Commit

Permalink
feat(cli): update set-version to match new release structure, add `--…
Browse files Browse the repository at this point in the history
…tag`, `--commit` (#1157)

* feat(cli): add --tag and --commit options to set-version command

* feat(cli): make set-version update all package.json in a project instead of just the current directory
  • Loading branch information
alvrs authored Jul 13, 2023
1 parent 184d5b5 commit c36ffd1
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 36 deletions.
15 changes: 15 additions & 0 deletions .changeset/thin-buses-reply.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
"@latticexyz/cli": minor
---

- update the `set-version` cli command to work with the new release process by adding two new options:
- `--tag`: install the latest version of the given tag. For snapshot releases tags correspond to the branch name, commits to `main` result in an automatic snapshot release, so `--tag main` is equivalent to what used to be `-v canary`
- `--commit`: install a version based on a given commit hash. Since commits from `main` result in an automatic snapshot release it works for all commits on main, and it works for manual snapshot releases from branches other than main
- `set-version` now updates all `package.json` nested below the current working directory (expect `node_modules`), so no need for running it each workspace of a monorepo separately.

Example:

```bash
pnpm mud set-version --tag main && pnpm install
pnpm mud set-version --commit db19ea39 && pnpm install
```
99 changes: 67 additions & 32 deletions packages/cli/src/commands/set-version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ import type { CommandModule } from "yargs";
import { MUDError } from "@latticexyz/common/errors";
import { logError } from "../utils/errors";
import localPackageJson from "../../package.json" assert { type: "json" };
import glob from "glob";

type Options = {
backup?: boolean;
force?: boolean;
restore?: boolean;
mudVersion?: string;
tag?: string;
commit?: string;
link?: string;
};

Expand All @@ -20,7 +23,7 @@ const MUD_PREFIX = "@latticexyz";
const commandModule: CommandModule<Options, Options> = {
command: "set-version",

describe: "Install a custom MUD version and optionally backup the previously installed version",
describe: "Set MUD version in all package.json files and optionally backup the previously installed version",

builder(yargs) {
return yargs.options({
Expand All @@ -30,36 +33,44 @@ const commandModule: CommandModule<Options, Options> = {
description: `Backup fails if a "${BACKUP_FILE}" file is found, unless --force is provided`,
},
restore: { type: "boolean", description: `Restore the previous MUD versions from "${BACKUP_FILE}"` },
mudVersion: { alias: "v", type: "string", description: "The MUD version to install" },
mudVersion: { alias: "v", type: "string", description: "Set MUD to the given version" },
tag: {
alias: "t",
type: "string",
description: "Set MUD to the latest version with the given tag from npm",
},
commit: {
alias: "c",
type: "string",
description: "Set MUD to the version based on a given git commit hash from npm",
},
link: { alias: "l", type: "string", description: "Relative path to the local MUD root directory to link" },
});
},

async handler(options) {
try {
if (!options.mudVersion && !options.link && !options.restore) {
throw new MUDError("`--mudVersion` or `--link` is required unless --restore is provided.");
const mutuallyExclusiveOptions = ["mudVersion", "link", "tag", "commit", "restore"];
const numMutuallyExclusiveOptions = mutuallyExclusiveOptions.reduce(
(acc, opt) => (options[opt] ? acc + 1 : acc),
0
);

if (numMutuallyExclusiveOptions === 0) {
throw new MUDError(`You need to provide one these options: ${mutuallyExclusiveOptions.join(", ")}`);
}

// `link` and `mudVersion` are mutually exclusive
if (options.link && options.mudVersion) {
throw new MUDError("Options `--link` and `--mudVersion` are mutually exclusive");
if (numMutuallyExclusiveOptions > 1) {
throw new MUDError(`These options are mutually exclusive: ${mutuallyExclusiveOptions.join(", ")}`);
}

// Resolve the `canary` version number if needed
options.mudVersion =
options.mudVersion === "canary" ? await getCanaryVersion(localPackageJson.name) : options.mudVersion;

// Read the current package.json
const rootPath = "./package.json";
const { workspaces } = updatePackageJson(rootPath, options);
// Resolve the version number from available options like `tag` or `commit`
options.mudVersion = await resolveVersion(options);

// Load the package.json of each workspace
if (workspaces) {
for (const workspace of workspaces) {
const filePath = path.join(workspace, "/package.json");
updatePackageJson(filePath, options);
}
// Update all package.json below the current working directory (except in node_modules)
const packageJsons = glob.sync("**/package.json").filter((p) => !p.includes("node_modules"));
for (const packageJson of packageJsons) {
updatePackageJson(packageJson, options);
}
} catch (e) {
logError(e);
Expand All @@ -69,6 +80,42 @@ const commandModule: CommandModule<Options, Options> = {
},
};

async function resolveVersion(options: Options) {
// Backwards compatibility to previous behavior of this script where passing "canary" as the version resolved to the latest commit on main
if (options.mudVersion === "canary") options.tag = "main";

let npmResult;
try {
console.log(chalk.blue(`Fetching available versions`));
npmResult = await (await fetch(`https://registry.npmjs.org/${localPackageJson.name}`)).json();
} catch (e) {
throw new MUDError(`Could not fetch available MUD versions`);
}

if (options.tag) {
const version = npmResult["dist-tags"][options.tag];
if (!version) {
throw new MUDError(`Could not find npm version with tag "${options.tag}"`);
}
console.log(chalk.green(`Latest version with tag ${options.tag}: ${version}`));
return version;
}

if (options.commit) {
// Find a version with this commit hash
const commit = options.commit.substring(0, 8); // changesets uses the first 8 characters of the commit hash as version for prereleases/snapshot releases
const version = Object.keys(npmResult["versions"]).find((v) => (v as string).includes(commit));
if (!version) {
throw new MUDError(`Could not find npm version based on commit "${options.commit}"`);
}
console.log(chalk.green(`Version from commit ${options.commit}: ${version}`));
return version;
}

// If neither a tag nor a commit option is given, return the `mudVersion`
return options.mudVersion;
}

function updatePackageJson(filePath: string, options: Options): { workspaces?: string[] } {
const { restore, force, link } = options;
let { backup, mudVersion } = options;
Expand Down Expand Up @@ -167,18 +214,6 @@ function readPackageJson(path: string): {
}
}

async function getCanaryVersion(pkg: string) {
try {
console.log(chalk.blue("fetching MUD canary version..."));
const result = await (await fetch(`https://registry.npmjs.org/${pkg}`)).json();
const canary = result["dist-tags"].canary;
console.log(chalk.green("MUD canary version:", canary));
return canary;
} catch (e) {
throw new MUDError(`Could not fetch canary version of ${pkg}`);
}
}

function logComparison(prev: Record<string, string>, curr: Record<string, string>) {
for (const key in prev) {
if (prev[key] !== curr[key]) {
Expand Down
2 changes: 1 addition & 1 deletion templates/phaser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"dev:client": "pnpm --filter 'client' run dev",
"dev:contracts": "pnpm --filter 'contracts' dev",
"foundry:up": "curl -L https://foundry.paradigm.xyz | bash && bash $HOME/.foundry/bin/foundryup",
"mud:up": "pnpm recursive exec mud set-version -v canary && pnpm install",
"mud:up": "pnpm mud set-version --tag main && pnpm install",
"prepare": "(forge --version || pnpm foundry:up)",
"test": "pnpm recursive run test"
},
Expand Down
2 changes: 1 addition & 1 deletion templates/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"dev:client": "pnpm --filter 'client' run dev",
"dev:contracts": "pnpm --filter 'contracts' dev",
"foundry:up": "curl -L https://foundry.paradigm.xyz | bash && bash $HOME/.foundry/bin/foundryup",
"mud:up": "pnpm recursive exec mud set-version -v canary && pnpm install",
"mud:up": "pnpm mud set-version --tag main && pnpm install",
"prepare": "(forge --version || pnpm foundry:up)",
"test": "pnpm recursive run test"
},
Expand Down
2 changes: 1 addition & 1 deletion templates/threejs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"dev:client": "pnpm --filter 'client' run dev",
"dev:contracts": "pnpm --filter 'contracts' dev",
"foundry:up": "curl -L https://foundry.paradigm.xyz | bash && bash $HOME/.foundry/bin/foundryup",
"mud:up": "pnpm recursive exec mud set-version -v canary && pnpm install",
"mud:up": "pnpm mud set-version --tag main && pnpm install",
"prepare": "(forge --version || pnpm foundry:up)",
"test": "pnpm recursive run test"
},
Expand Down
2 changes: 1 addition & 1 deletion templates/vanilla/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"dev:client": "pnpm --filter 'client' run dev",
"dev:contracts": "pnpm --filter 'contracts' dev",
"foundry:up": "curl -L https://foundry.paradigm.xyz | bash && bash $HOME/.foundry/bin/foundryup",
"mud:up": "pnpm recursive exec mud set-version -v canary && pnpm install",
"mud:up": "pnpm mud set-version --tag main && pnpm install",
"prepare": "(forge --version || pnpm foundry:up)",
"test": "pnpm recursive run test"
},
Expand Down

0 comments on commit c36ffd1

Please sign in to comment.