Skip to content

Commit e55ca02

Browse files
authored
Adding profile support to the v3 CLI (#953)
1 parent 9304c44 commit e55ca02

File tree

10 files changed

+173
-154
lines changed

10 files changed

+173
-154
lines changed

packages/cli-v3/src/cli/common.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ export const CommonCommandOptions = z.object({
1010
apiUrl: z.string().optional(),
1111
logLevel: z.enum(["debug", "info", "log", "warn", "error", "none"]).default("log"),
1212
skipTelemetry: z.boolean().default(false),
13+
profile: z.string().default("default"),
1314
});
1415

1516
export type CommonCommandOptions = z.infer<typeof CommonCommandOptions>;
1617

1718
export function commonOptions(command: Command) {
1819
return command
20+
.option("--profile <profile>", "The login profile to use", "default")
1921
.option("-a, --api-url <value>", "Override the API URL", "https://api.trigger.dev")
2022
.option(
2123
"-l, --log-level <level>",
@@ -25,9 +27,9 @@ export function commonOptions(command: Command) {
2527
.option("--skip-telemetry", "Opt-out of sending telemetry");
2628
}
2729

28-
export class SkipLoggingError extends Error {}
29-
export class SkipCommandError extends Error {}
30-
export class OutroCommandError extends SkipCommandError {}
30+
export class SkipLoggingError extends Error { }
31+
export class SkipCommandError extends Error { }
32+
export class OutroCommandError extends SkipCommandError { }
3133

3234
export async function handleTelemetry(action: () => Promise<void>) {
3335
try {

packages/cli-v3/src/cli/index.ts

+2-32
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,10 @@ import { configureDeployCommand } from "../commands/deploy.js";
33
import { configureDevCommand } from "../commands/dev.js";
44
import { configureInitCommand } from "../commands/init.js";
55
import { configureLoginCommand } from "../commands/login.js";
6-
import { logoutCommand } from "../commands/logout.js";
7-
import { updateCommand } from "../commands/update.js";
6+
import { configureLogoutCommand } from "../commands/logout.js";
87
import { configureWhoamiCommand } from "../commands/whoami.js";
98
import { COMMAND_NAME } from "../consts.js";
109
import { getVersion } from "../utilities/getVersion.js";
11-
import { printInitialBanner } from "../utilities/initialBanner.js";
1210

1311
export const program = new Command();
1412

@@ -19,35 +17,7 @@ program
1917

2018
configureLoginCommand(program);
2119
configureInitCommand(program);
22-
23-
program
24-
.command("logout")
25-
.description("Logout of Trigger.dev")
26-
.version(getVersion(), "-v, --version", "Display the version number")
27-
.action(async (options) => {
28-
try {
29-
await printInitialBanner(false);
30-
await logoutCommand(options);
31-
//todo login command
32-
} catch (e) {
33-
//todo error reporting
34-
throw e;
35-
}
36-
});
37-
3820
configureDevCommand(program);
3921
configureDeployCommand(program);
40-
41-
program
42-
.command("update")
43-
.description(
44-
"Updates all @trigger.dev/* packages to their latest compatible versions or the specified version"
45-
)
46-
.argument("[path]", "The path to the directory that contains the package.json file", ".")
47-
.option("-t, --to <version tag>", "The version to update to (ex: 2.1.4)", "latest")
48-
.action(async (path, options) => {
49-
await printInitialBanner(false);
50-
await updateCommand(path, options);
51-
});
52-
5322
configureWhoamiCommand(program);
23+
configureLogoutCommand(program);

packages/cli-v3/src/commands/deploy.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) {
134134

135135
intro("Deploying project");
136136

137-
const authorization = await login({ embedded: true, defaultApiUrl: options.apiUrl });
137+
const authorization = await login({ embedded: true, defaultApiUrl: options.apiUrl, profile: options.profile });
138138

139139
if (!authorization.ok) {
140140
if (authorization.error === "fetch failed") {

packages/cli-v3/src/commands/dev.tsx

+24-39
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { ClientOptions, WebSocket as wsWebSocket } from "ws";
2424
import { z } from "zod";
2525
import * as packageJson from "../../package.json";
2626
import { CliApiClient } from "../apiClient";
27-
import { CommonCommandOptions } from "../cli/common.js";
27+
import { CommonCommandOptions, commonOptions, wrapCommandAction } from "../cli/common.js";
2828
import { readConfig } from "../utilities/configFiles";
2929
import { printStandloneInitialBanner } from "../utilities/initialBanner.js";
3030
import { detectPackageNameFromImportPath } from "../utilities/installPackages";
@@ -47,46 +47,31 @@ const DevCommandOptions = CommonCommandOptions.extend({
4747
type DevCommandOptions = z.infer<typeof DevCommandOptions>;
4848

4949
export function configureDevCommand(program: Command) {
50-
program
51-
.command("dev")
52-
.description("Run your Trigger.dev tasks locally")
53-
.argument("[path]", "The path to the project", ".")
54-
.option(
55-
"-l, --log-level <level>",
56-
"The log level to use (debug, info, log, warn, error, none)",
57-
"log"
58-
)
59-
.option(
60-
"-c, --config <config file>",
61-
"The name of the config file, found at [path]",
62-
"trigger.config.mjs"
63-
)
64-
.option(
65-
"-p, --project-ref <project ref>",
66-
"The project ref. Required if there is no config file."
67-
)
68-
.option("--debugger", "Enable the debugger")
69-
.option("--debug-otel", "Enable OpenTelemetry debugging")
70-
.action(async (path, options) => {
71-
try {
72-
await devCommand(path, options);
73-
} catch (e) {
74-
//todo error reporting
75-
throw e;
76-
}
50+
return commonOptions(
51+
program
52+
.command("dev")
53+
.description("Run your Trigger.dev tasks locally")
54+
.argument("[path]", "The path to the project", ".")
55+
.option(
56+
"-c, --config <config file>",
57+
"The name of the config file, found at [path]",
58+
"trigger.config.mjs"
59+
)
60+
.option(
61+
"-p, --project-ref <project ref>",
62+
"The project ref. Required if there is no config file."
63+
)
64+
.option("--debugger", "Enable the debugger")
65+
.option("--debug-otel", "Enable OpenTelemetry debugging")
66+
).action(async (path, options) => {
67+
wrapCommandAction("dev", DevCommandOptions, options, async (opts) => {
68+
await devCommand(path, opts);
7769
});
70+
});
7871
}
7972

80-
export async function devCommand(dir: string, anyOptions: unknown) {
81-
const options = DevCommandOptions.safeParse(anyOptions);
82-
83-
if (!options.success) {
84-
console.log(fromZodError(options.error).toString());
85-
86-
process.exit(1);
87-
}
88-
89-
const authorization = await isLoggedIn();
73+
export async function devCommand(dir: string, options: DevCommandOptions) {
74+
const authorization = await isLoggedIn(options.profile);
9075

9176
if (!authorization.ok) {
9277
if (authorization.error === "fetch failed") {
@@ -101,7 +86,7 @@ export async function devCommand(dir: string, anyOptions: unknown) {
10186
let watcher;
10287

10388
try {
104-
const devInstance = await startDev(dir, options.data, authorization.auth);
89+
const devInstance = await startDev(dir, options, authorization.auth);
10590
watcher = devInstance.watcher;
10691
const { waitUntilExit } = devInstance.devReactElement;
10792
await waitUntilExit();

packages/cli-v3/src/commands/init.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ async function _initCommand(dir: string, options: InitCommandOptions) {
8080

8181
intro("Initializing project");
8282

83-
const authorization = await login({ embedded: true, defaultApiUrl: options.apiUrl });
83+
const authorization = await login({ embedded: true, defaultApiUrl: options.apiUrl, profile: options.profile });
8484

8585
if (!authorization.ok) {
8686
if (authorization.error === "fetch failed") {
@@ -96,6 +96,7 @@ async function _initCommand(dir: string, options: InitCommandOptions) {
9696
"cli.userId": authorization.userId,
9797
"cli.email": authorization.email,
9898
"cli.config.apiUrl": authorization.auth.apiUrl,
99+
"cli.config.profile": authorization.profile,
99100
});
100101

101102
if (!options.overrideConfig) {

packages/cli-v3/src/commands/login.ts

+12-6
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@ import {
1414
wrapCommandAction,
1515
} from "../cli/common.js";
1616
import { chalkLink } from "../utilities/colors.js";
17-
import { readAuthConfigFile, writeAuthConfigFile } from "../utilities/configFiles.js";
17+
import { readAuthConfigProfile, writeAuthConfigProfile } from "../utilities/configFiles.js";
1818
import { getVersion } from "../utilities/getVersion.js";
1919
import { printInitialBanner } from "../utilities/initialBanner.js";
2020
import { LoginResult } from "../utilities/session.js";
2121
import { whoAmI } from "./whoami.js";
22+
import { logger } from "../utilities/logger.js";
2223

2324
export const LoginCommandOptions = CommonCommandOptions.extend({
2425
apiUrl: z.string(),
@@ -48,12 +49,13 @@ export async function loginCommand(options: unknown) {
4849
}
4950

5051
async function _loginCommand(options: LoginCommandOptions) {
51-
return login({ defaultApiUrl: options.apiUrl, embedded: false });
52+
return login({ defaultApiUrl: options.apiUrl, embedded: false, profile: options.profile });
5253
}
5354

5455
export type LoginOptions = {
5556
defaultApiUrl?: string;
5657
embedded?: boolean;
58+
profile?: string;
5759
};
5860

5961
export async function login(options?: LoginOptions): Promise<LoginResult> {
@@ -63,16 +65,17 @@ export async function login(options?: LoginOptions): Promise<LoginResult> {
6365

6466
span.setAttributes({
6567
"cli.config.apiUrl": opts.defaultApiUrl,
68+
"cli.options.profile": opts.profile,
6669
});
6770

6871
if (!opts.embedded) {
6972
intro("Logging in to Trigger.dev");
7073
}
7174

72-
const authConfig = readAuthConfigFile();
75+
const authConfig = readAuthConfigProfile(options?.profile);
7376

7477
if (authConfig && authConfig.accessToken) {
75-
const whoAmIResult = await whoAmI(undefined, opts.embedded);
78+
const whoAmIResult = await whoAmI({ profile: options?.profile ?? "default", skipTelemetry: !span.isRecording(), logLevel: logger.loggerLevel }, opts.embedded);
7679

7780
if (!whoAmIResult.success) {
7881
throw new Error(whoAmIResult.error);
@@ -106,6 +109,7 @@ export async function login(options?: LoginOptions): Promise<LoginResult> {
106109

107110
return {
108111
ok: true as const,
112+
profile: options?.profile ?? "default",
109113
userId: whoAmIResult.data.userId,
110114
email: whoAmIResult.data.email,
111115
dashboardUrl: whoAmIResult.data.dashboardUrl,
@@ -126,6 +130,7 @@ export async function login(options?: LoginOptions): Promise<LoginResult> {
126130

127131
return {
128132
ok: true as const,
133+
profile: options?.profile ?? "default",
129134
userId: whoAmIResult.data.userId,
130135
email: whoAmIResult.data.email,
131136
dashboardUrl: whoAmIResult.data.dashboardUrl,
@@ -170,9 +175,9 @@ export async function login(options?: LoginOptions): Promise<LoginResult> {
170175

171176
getPersonalAccessTokenSpinner.stop(`Logged in with token ${indexResult.obfuscatedToken}`);
172177

173-
writeAuthConfigFile({ accessToken: indexResult.token, apiUrl: opts.defaultApiUrl });
178+
writeAuthConfigProfile({ accessToken: indexResult.token, apiUrl: opts.defaultApiUrl }, options?.profile);
174179

175-
const whoAmIResult = await whoAmI(undefined, opts.embedded);
180+
const whoAmIResult = await whoAmI({ profile: options?.profile ?? "default", skipTelemetry: !span.isRecording(), logLevel: logger.loggerLevel }, opts.embedded);
176181

177182
if (!whoAmIResult.success) {
178183
throw new Error(whoAmIResult.error);
@@ -188,6 +193,7 @@ export async function login(options?: LoginOptions): Promise<LoginResult> {
188193

189194
return {
190195
ok: true as const,
196+
profile: options?.profile ?? "default",
191197
userId: whoAmIResult.data.userId,
192198
email: whoAmIResult.data.email,
193199
dashboardUrl: whoAmIResult.data.dashboardUrl,
+32-6
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,41 @@
1-
import { readAuthConfigFile, writeAuthConfigFile } from "../utilities/configFiles.js";
1+
import { Command } from "commander";
2+
import { readAuthConfigProfile, writeAuthConfigProfile } from "../utilities/configFiles.js";
23
import { logger } from "../utilities/logger.js";
4+
import { CommonCommandOptions, commonOptions, handleTelemetry, wrapCommandAction } from "../cli/common.js";
5+
import { printInitialBanner } from "../utilities/initialBanner.js";
6+
import { z } from "zod";
37

4-
export async function logoutCommand(options: any) {
5-
const config = readAuthConfigFile();
8+
const LogoutCommandOptions = CommonCommandOptions;
9+
10+
type LogoutCommandOptions = z.infer<typeof LogoutCommandOptions>;
11+
12+
export function configureLogoutCommand(program: Command) {
13+
return commonOptions(program
14+
.command("logout")
15+
.description("Logout of Trigger.dev"))
16+
.action(async (options) => {
17+
await handleTelemetry(async () => {
18+
await printInitialBanner(false);
19+
await logoutCommand(options);
20+
});
21+
});
22+
}
23+
24+
export async function logoutCommand(options: unknown) {
25+
return await wrapCommandAction("logoutCommand", LogoutCommandOptions, options, async (opts) => {
26+
return await logout(opts);
27+
});
28+
}
29+
30+
export async function logout(options: LogoutCommandOptions) {
31+
const config = readAuthConfigProfile(options.profile);
632

733
if (!config?.accessToken) {
8-
logger.info("You are already logged out");
34+
logger.info(`You are already logged out [${options.profile ?? "default"}]`);
935
return;
1036
}
1137

12-
writeAuthConfigFile({ ...config, accessToken: undefined, apiUrl: undefined });
38+
writeAuthConfigProfile({ ...config, accessToken: undefined, apiUrl: undefined }, options.profile);
1339

14-
logger.info("Logged out");
40+
logger.info(`Logged out of Trigger.dev [${options.profile ?? "default"}]`);
1541
}

0 commit comments

Comments
 (0)