Skip to content
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
5 changes: 5 additions & 0 deletions .changeset/poor-clubs-kick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@vlandoss/run-run": patch
---

Add `pkgs` command
1 change: 1 addition & 0 deletions packages/run-run/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"commander": "13.1.0",
"glob": "^11.0.2",
"is-ci": "4.1.0",
"memoize": "^10.2.0",
"rimraf": "6.0.1",
"typescript": "5.8.2"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ Commands:
tsc|typecheck check if TypeScript code is well typed 🎨
clean [options] delete dirty folders or files such as
node_modules, etc 🗑️
pkgs|packages [options] list unique affected packages from list of files
📦
help [command] display help for command

Acknowledgment:
Expand Down Expand Up @@ -43,6 +45,8 @@ Commands:
tsc|typecheck check if TypeScript code is well typed 🎨
clean [options] delete dirty folders or files such as
node_modules, etc 🗑️
pkgs|packages [options] list unique affected packages from list of files
📦
help [command] display help for command

Acknowledgment:
Expand Down Expand Up @@ -143,6 +147,18 @@ Under the hood, this command uses the rimraf.js to delete dirty folders or files
"
`;

exports[`should match help messages for all commands: help-command-pkgs 1`] = `
"Usage: rr pkgs|packages [options]

list unique affected packages from list of files 📦

Options:
--files <files...> list of files to check
--decorator [type] type of decorator to use (choices: "turbo")
-h, --help display help for command
"
`;

exports[`should match help messages for all commands: help-command-tools 1`] = `
"Usage: rr tools [options] [command]

Expand Down
75 changes: 75 additions & 0 deletions packages/run-run/src/program/commands/pkgs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import path from "node:path";
import { type Command, createCommand, Option } from "commander";
import memoize from "memoize";
import type { Context } from "#/services/ctx";
import { logger } from "#/services/logger";

// Currently only "turbo" is supported, but this can be extended in the future
const decorators = ["turbo"] as const;

type Options = {
files: string[];
decorator?: (typeof decorators)[number];
};

export function createPkgsCommand(ctx: Context) {
return createCommand("pkgs")
.alias("packages")
.description("list unique affected packages from list of files 📦")
.addOption(new Option("--files <files...>", "list of files to check"))
.addOption(new Option("--decorator [type]", "type of decorator to use").choices(decorators))
.action(async function pkgsAction({ files, decorator }: Options, cmd: Command) {
const { appPkg } = ctx;

if (!appPkg.isMonorepo()) {
const cmdName = cmd.parent?.args[0] ?? cmd.args[0] ?? cmd.name();
logger.error(`The \`${cmdName}\` command can only be run in a monorepo.`);
return process.exit(1);
}

const projects = await appPkg.getWorkspaceProjects();

const getRelativeRootDir = memoize((rootDir: string) => {
const appDir = appPkg.dirPath;

if (!path.isAbsolute(rootDir)) {
return rootDir;
}

return path.relative(appDir, rootDir);
});

function getPackageForFile(filePath: string) {
for (const project of projects) {
const relativeRootDir = getRelativeRootDir(project.rootDir);

if (filePath.startsWith(relativeRootDir)) {
return project;
}
}

return null;
}

const uniquePkgsNames = new Set<string>();

files.forEach((file) => {
const pkg = getPackageForFile(file);
if (pkg?.manifest.name) {
uniquePkgsNames.add(pkg.manifest.name);
}
});

if (!uniquePkgsNames.size) {
return;
}

const pkgsNames = Array.from(uniquePkgsNames);

if (decorator === "turbo") {
console.log(...pkgsNames.map((name) => `--filter=...${name}`));
} else {
console.log(...pkgsNames);
}
});
}
2 changes: 2 additions & 0 deletions packages/run-run/src/program/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { createCheckCommand } from "./commands/check";
import { createCleanCommand } from "./commands/clean";
import { createFormatCommand } from "./commands/format";
import { createLintCommand } from "./commands/lint";
import { createPkgsCommand } from "./commands/pkgs";
import { createRunCommand } from "./commands/run";
import { createToolsCommand } from "./commands/tools";
import { createTypecheckCommand } from "./commands/typecheck";
Expand All @@ -31,6 +32,7 @@ export async function createProgram(options: Options) {
.addCommand(createFormatCommand(ctx))
.addCommand(createTypecheckCommand(ctx))
.addCommand(createCleanCommand())
.addCommand(createPkgsCommand(ctx))
.addCommand(createToolsCommand(ctx), {
hidden: true,
});
Expand Down
39 changes: 26 additions & 13 deletions pnpm-lock.yaml

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