Skip to content

Commit f84f70f

Browse files
thomasballingerConvex, Inc.
authored andcommitted
Use color on stderr in CLI even when piping to stdout (#43450)
Use the stderr chalk instance in a few spots to preserve color while piping. GitOrigin-RevId: 0375606679f01119001a7e9582fec65b259284e8
1 parent 15c298c commit f84f70f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+241
-198
lines changed

npm-packages/convex/CHANGELOG.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
# Changelog
22

33
## Unreleased
4+
45
- The `--preview-create` parameter for `npx convex deploy` will now error if
56
used with a deploy key that is not a preview deploy key. Previously, the flag
6-
would be ignored in this situation, and `npx convex deploy` would deploy
7-
to the production deployment. If you were depending on this behavior, make
8-
sure to remove the `--preview-create` flag when deploying to production.
7+
would be ignored in this situation, and `npx convex deploy` would deploy to
8+
the production deployment. If you were depending on this behavior, make sure
9+
to remove the `--preview-create` flag when deploying to production.
910

1011
## 1.29.2
1112

npm-packages/convex/eslint.config.mjs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,14 @@ export default [
155155
"Use a `Filesystem` implementation like `nodeFs` instead of Node's 'fs/promises' package directly. Additionally, use synchronous filesystem IO within our CLI.",
156156
},
157157
],
158+
paths: [
159+
{
160+
name: "chalk",
161+
importNames: ["default"],
162+
message:
163+
"Import { chalkStderr } from 'chalk' instead of the default chalk import. Use chalkStderr for stderr output (most cases). Only use default chalk with an eslint-disable comment if formatting text for stdout (e.g., logOutput() or console.log).",
164+
},
165+
],
158166
},
159167
],
160168
"no-restricted-syntax": [

npm-packages/convex/src/bundler/fs.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// error messages.
33
/* eslint-disable no-restricted-imports */
44
/* eslint-disable no-restricted-syntax */
5-
import chalk from "chalk";
5+
import { chalkStderr } from "chalk";
66
import stdFs, { Dirent, Mode, ReadStream, Stats } from "fs";
77
import * as fsPromises from "fs/promises";
88
import os from "os";
@@ -36,21 +36,21 @@ function warnCrossFilesystem(dstPath: string) {
3636
// It's hard for these to use `logMessage` without creating a circular dependency, so just log directly.
3737
// eslint-disable-next-line no-console
3838
console.warn(
39-
chalk.yellow(
39+
chalkStderr.yellow(
4040
`Temporary directory '${tmpDirRoot}' and project directory '${dstDir}' are on different filesystems.`,
4141
),
4242
);
4343
// eslint-disable-next-line no-console
4444
console.warn(
45-
chalk.gray(
46-
` If you're running into errors with other tools watching the project directory, override the temporary directory location with the ${chalk.bold(
45+
chalkStderr.gray(
46+
` If you're running into errors with other tools watching the project directory, override the temporary directory location with the ${chalkStderr.bold(
4747
tmpDirOverrideVar,
4848
)} environment variable.`,
4949
),
5050
);
5151
// eslint-disable-next-line no-console
5252
console.warn(
53-
chalk.gray(
53+
chalkStderr.gray(
5454
` Be sure to pick a temporary directory that's on the same filesystem as your project.`,
5555
),
5656
);

npm-packages/convex/src/bundler/index.ts

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import path from "path";
2-
import chalk from "chalk";
2+
import { chalkStderr } from "chalk";
33
import esbuild from "esbuild";
44
import { parse as parseAST } from "@babel/parser";
55
import { Identifier, ImportSpecifier } from "@babel/types";
@@ -199,7 +199,7 @@ export async function bundle(
199199
});
200200
}
201201
for (const warning of result.warnings) {
202-
logWarning(chalk.yellow(`esbuild warning: ${warning.text}`));
202+
logWarning(chalkStderr.yellow(`esbuild warning: ${warning.text}`));
203203
}
204204
const sourceMaps = new Map();
205205
const modules: Bundle[] = [];
@@ -305,13 +305,13 @@ export async function bundleAuthConfig(ctx: Context, dir: string) {
305305
: authConfigPath;
306306
if (!ctx.fs.exists(chosenPath)) {
307307
logVerbose(
308-
chalk.yellow(
308+
chalkStderr.yellow(
309309
`Found no auth config file at ${authConfigTsPath} or ${authConfigPath} so there are no configured auth providers`,
310310
),
311311
);
312312
return [];
313313
}
314-
logVerbose(chalk.yellow(`Bundling auth config found at ${chosenPath}`));
314+
logVerbose(chalkStderr.yellow(`Bundling auth config found at ${chosenPath}`));
315315
const result = await bundle(ctx, dir, [chosenPath], true, "browser");
316316
return result.modules;
317317
}
@@ -367,7 +367,7 @@ export async function entryPoints(
367367
const config = path.join(dirPath, "convex.config.ts");
368368
const isComponentDefinition = ctx.fs.exists(config);
369369
if (isComponentDefinition) {
370-
logVerbose(chalk.yellow(`Skipping component directory ${dirPath}`));
370+
logVerbose(chalkStderr.yellow(`Skipping component directory ${dirPath}`));
371371
}
372372
return isComponentDefinition;
373373
};
@@ -397,7 +397,7 @@ export async function entryPoints(
397397
const source = ctx.fs.readUtf8File(fpath);
398398
if (await doesImportConvexHttpRouter(source))
399399
logWarning(
400-
chalk.yellow(
400+
chalkStderr.yellow(
401401
`Found ${fpath}. HTTP action routes will not be imported from this file. Did you mean to include http${extension}?`,
402402
),
403403
);
@@ -409,25 +409,27 @@ export async function entryPoints(
409409

410410
// This should match isEntryPoint in the convex eslint plugin.
411411
if (!ENTRY_POINT_EXTENSIONS.some((ext) => relPath.endsWith(ext))) {
412-
logVerbose(chalk.yellow(`Skipping non-JS file ${fpath}`));
412+
logVerbose(chalkStderr.yellow(`Skipping non-JS file ${fpath}`));
413413
} else if (relPath.startsWith("_generated" + path.sep)) {
414-
logVerbose(chalk.yellow(`Skipping ${fpath}`));
414+
logVerbose(chalkStderr.yellow(`Skipping ${fpath}`));
415415
} else if (base.startsWith(".")) {
416-
logVerbose(chalk.yellow(`Skipping dotfile ${fpath}`));
416+
logVerbose(chalkStderr.yellow(`Skipping dotfile ${fpath}`));
417417
} else if (base.startsWith("#")) {
418-
logVerbose(chalk.yellow(`Skipping likely emacs tempfile ${fpath}`));
418+
logVerbose(chalkStderr.yellow(`Skipping likely emacs tempfile ${fpath}`));
419419
} else if (base === "schema.ts" || base === "schema.js") {
420-
logVerbose(chalk.yellow(`Skipping ${fpath}`));
420+
logVerbose(chalkStderr.yellow(`Skipping ${fpath}`));
421421
} else if ((base.match(/\./g) || []).length > 1) {
422422
// `auth.config.ts` and `convex.config.ts` are important not to bundle.
423423
// `*.test.ts` `*.spec.ts` are common in developer code.
424-
logVerbose(chalk.yellow(`Skipping ${fpath} that contains multiple dots`));
424+
logVerbose(
425+
chalkStderr.yellow(`Skipping ${fpath} that contains multiple dots`),
426+
);
425427
} else if (relPath.includes(" ")) {
426428
logVerbose(
427-
chalk.yellow(`Skipping ${relPath} because it contains a space`),
429+
chalkStderr.yellow(`Skipping ${relPath} because it contains a space`),
428430
);
429431
} else {
430-
logVerbose(chalk.green(`Preparing ${fpath}`));
432+
logVerbose(chalkStderr.green(`Preparing ${fpath}`));
431433
entryPoints.push(fpath);
432434
}
433435
}
@@ -444,7 +446,7 @@ export async function entryPoints(
444446
return true;
445447
}
446448
logVerbose(
447-
chalk.yellow(
449+
chalkStderr.yellow(
448450
`Skipping ${fpath} because it has no export or import to make it a valid TypeScript module`,
449451
),
450452
);

npm-packages/convex/src/bundler/log.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { format } from "util";
2-
import chalk from "chalk";
2+
import { chalkStderr } from "chalk";
33
import ProgressBar, {
44
ProgressBarInstance,
55
ProgressBarOptions,
@@ -98,7 +98,7 @@ export function logFailure(message: string) {
9898
spinner.fail(message);
9999
spinner = null;
100100
} else {
101-
logToStderr(`${chalk.red(`✖`)} ${message}`);
101+
logToStderr(`${chalkStderr.red(`✖`)} ${message}`);
102102
}
103103
}
104104

@@ -108,7 +108,7 @@ export function logFinishedStep(message: string) {
108108
spinner.succeed(message);
109109
spinner = null;
110110
} else {
111-
logToStderr(`${chalk.green(`✔`)} ${message}`);
111+
logToStderr(`${chalkStderr.green(`✔`)} ${message}`);
112112
}
113113
}
114114

npm-packages/convex/src/cli/configure.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import chalk from "chalk";
1+
import { chalkStderr } from "chalk";
22
import { Context } from "../bundler/context.js";
33
import {
44
logFailure,
@@ -260,7 +260,7 @@ export async function _deploymentCredentialsOrConfigure(
260260
const forceAnonymous = process.env.CONVEX_AGENT_MODE === "anonymous";
261261
if (forceAnonymous) {
262262
logWarning(
263-
chalk.yellow.bold(
263+
chalkStderr.yellow.bold(
264264
"CONVEX_AGENT_MODE=anonymous mode is in beta, functionality may change in the future.",
265265
),
266266
);
@@ -461,15 +461,15 @@ export async function handleManuallySetUrlAndAdminKey(
461461
const didErase = await eraseDeploymentEnvVar(ctx);
462462
if (didErase) {
463463
logMessage(
464-
chalk.yellowBright(
464+
chalkStderr.yellowBright(
465465
`Removed the CONVEX_DEPLOYMENT environment variable from .env.local`,
466466
),
467467
);
468468
}
469469
const envVarWrite = await writeConvexUrlToEnvFile(ctx, url);
470470
if (envVarWrite !== null) {
471471
logMessage(
472-
chalk.green(
472+
chalkStderr.green(
473473
`Saved the given --url as ${envVarWrite.envVar} to ${envVarWrite.envFile}`,
474474
),
475475
);
@@ -567,19 +567,19 @@ async function selectNewProject(
567567
return await logAndHandleFetchError(ctx, err);
568568
}
569569
const teamMessage = didChooseBetweenTeams
570-
? " in team " + chalk.bold(teamSlug)
570+
? " in team " + chalkStderr.bold(teamSlug)
571571
: "";
572572
logFinishedStep(
573-
`Created project ${chalk.bold(
573+
`Created project ${chalkStderr.bold(
574574
projectSlug,
575-
)}${teamMessage}, manage it at ${chalk.bold(
575+
)}${teamMessage}, manage it at ${chalkStderr.bold(
576576
projectDashboardUrl(teamSlug, projectSlug),
577577
)}`,
578578
);
579579

580580
if (projectsRemaining <= 2) {
581581
logWarning(
582-
chalk.yellow.bold(
582+
chalkStderr.yellow.bold(
583583
`Your account now has ${projectsRemaining} project${
584584
projectsRemaining === 1 ? "" : "s"
585585
} remaining.`,
@@ -643,7 +643,7 @@ async function selectExistingProject(
643643
showSpinner(`Reinitializing project ${projectSlug}...\n`);
644644
// TODO: Do we need to do codegen for existing projects? (-Ian)
645645
await doInitialCodegen(ctx, { init: false });
646-
logFinishedStep(`Reinitialized project ${chalk.bold(projectSlug)}`);
646+
logFinishedStep(`Reinitialized project ${chalkStderr.bold(projectSlug)}`);
647647
return { teamSlug, projectSlug, devDeployment };
648648
}
649649

npm-packages/convex/src/cli/convexExport.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Command } from "@commander-js/extra-typings";
2-
import chalk from "chalk";
2+
import { chalkStderr } from "chalk";
33
import { ensureHasConvexDependency } from "./lib/utils/utils.js";
44
import { oneoffContext } from "../bundler/context.js";
55
import {
@@ -36,7 +36,7 @@ export const convexExport = new Command("export")
3636
);
3737

3838
const deploymentNotice = options.prod
39-
? ` in your ${chalk.bold("prod")} deployment`
39+
? ` in your ${chalkStderr.bold("prod")} deployment`
4040
: "";
4141
await exportFromDeployment(ctx, {
4242
...options,

npm-packages/convex/src/cli/convexImport.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import chalk from "chalk";
1+
import { chalkStderr } from "chalk";
22
import { ensureHasConvexDependency } from "./lib/utils/utils.js";
33
import { oneoffContext } from "../bundler/context.js";
44
import {
@@ -39,7 +39,7 @@ export const convexImport = new Command("import")
3939
);
4040

4141
const deploymentNotice = options.prod
42-
? ` in your ${chalk.bold("prod")} deployment`
42+
? ` in your ${chalkStderr.bold("prod")} deployment`
4343
: "";
4444

4545
await importIntoDeployment(ctx, filePath, {

npm-packages/convex/src/cli/dashboard.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Command } from "@commander-js/extra-typings";
2-
import chalk from "chalk";
2+
import { chalkStderr } from "chalk";
33
import open from "open";
44
import { Context, oneoffContext } from "../bundler/context.js";
55
import { logMessage, logOutput, logWarning } from "../bundler/log.js";
@@ -41,8 +41,8 @@ export const dashboard = new Command("dashboard")
4141
);
4242

4343
if (deployment.deploymentFields === null) {
44-
const msg = `Self-hosted deployment configured.\n\`${chalk.bold("npx convex dashboard")}\` is not supported for self-hosted deployments.\nSee self-hosting instructions for how to self-host the dashboard.`;
45-
logMessage(chalk.yellow(msg));
44+
const msg = `Self-hosted deployment configured.\n\`${chalkStderr.bold("npx convex dashboard")}\` is not supported for self-hosted deployments.\nSee self-hosting instructions for how to self-host the dashboard.`;
45+
logMessage(chalkStderr.yellow(msg));
4646
return;
4747
}
4848
const dashboardUrl = getDashboardUrl(ctx, deployment.deploymentFields);
@@ -66,7 +66,7 @@ export const dashboard = new Command("dashboard")
6666

6767
async function logOrOpenUrl(ctx: Context, url: string, shouldOpen: boolean) {
6868
if (shouldOpen) {
69-
logMessage(chalk.gray(`Opening ${url} in the default browser...`));
69+
logMessage(chalkStderr.gray(`Opening ${url} in the default browser...`));
7070
try {
7171
// This can fail e.g. on a headless dev machine.
7272
await open(url);

npm-packages/convex/src/cli/data.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import chalk from "chalk";
1+
import { chalkStderr } from "chalk";
22
import { oneoffContext } from "../bundler/context.js";
33
import {
44
deploymentSelectionWithinProjectFromOptions,
@@ -34,7 +34,7 @@ export const data = new Command("data")
3434
);
3535

3636
const deploymentNotice = deployment.deploymentFields?.deploymentName
37-
? `${chalk.bold(deployment.deploymentFields.deploymentName)} deployment's `
37+
? `${chalkStderr.bold(deployment.deploymentFields.deploymentName)} deployment's `
3838
: "";
3939

4040
await dataInDeployment(ctx, {

0 commit comments

Comments
 (0)