Skip to content

Commit 8dbf504

Browse files
committed
WIP for CLI preview archive command
1 parent b3873f1 commit 8dbf504

File tree

2 files changed

+174
-0
lines changed

2 files changed

+174
-0
lines changed

packages/cli-v3/src/apiClient.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,21 @@ export class CliApiClient {
182182
);
183183
}
184184

185+
async archiveBranch(branch: string) {
186+
if (!this.accessToken) {
187+
throw new Error("archiveBranch: No access token");
188+
}
189+
190+
return wrapZodFetch(
191+
z.object({ success: z.boolean() }),
192+
`${this.apiURL}/api/v1/branches/${branch}/archive`,
193+
{
194+
method: "POST",
195+
headers: this.getHeaders(),
196+
}
197+
);
198+
}
199+
185200
async getEnvironmentVariables(projectRef: string) {
186201
if (!this.accessToken) {
187202
throw new Error("getEnvironmentVariables: No access token");
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
import { intro, log, outro } from "@clack/prompts";
2+
import { getBranch, prepareDeploymentError } from "@trigger.dev/core/v3";
3+
import { InitializeDeploymentResponseBody } from "@trigger.dev/core/v3/schemas";
4+
import { Command, Option as CommandOption } from "commander";
5+
import { resolve } from "node:path";
6+
import { x } from "tinyexec";
7+
import { z } from "zod";
8+
import { isCI } from "std-env";
9+
import { CliApiClient } from "../apiClient.js";
10+
import { buildWorker } from "../build/buildWorker.js";
11+
import { resolveAlwaysExternal } from "../build/externals.js";
12+
import {
13+
CommonCommandOptions,
14+
commonOptions,
15+
handleTelemetry,
16+
SkipLoggingError,
17+
wrapCommandAction,
18+
} from "../cli/common.js";
19+
import { loadConfig } from "../config.js";
20+
import { buildImage } from "../deploy/buildImage.js";
21+
import {
22+
checkLogsForErrors,
23+
checkLogsForWarnings,
24+
printErrors,
25+
printWarnings,
26+
saveLogs,
27+
} from "../deploy/logs.js";
28+
import { chalkError, cliLink, isLinksSupported, prettyError } from "../utilities/cliOutput.js";
29+
import { loadDotEnvVars } from "../utilities/dotEnv.js";
30+
import { printStandloneInitialBanner } from "../utilities/initialBanner.js";
31+
import { logger } from "../utilities/logger.js";
32+
import { getProjectClient, upsertBranch } from "../utilities/session.js";
33+
import { getTmpDir } from "../utilities/tempDirectories.js";
34+
import { spinner } from "../utilities/windows.js";
35+
import { login } from "./login.js";
36+
import { updateTriggerPackages } from "./update.js";
37+
import { setGithubActionsOutputAndEnvVars } from "../utilities/githubActions.js";
38+
import { isDirectory } from "../utilities/fileSystem.js";
39+
import { createGitMeta } from "../utilities/gitMeta.js";
40+
import { verifyDirectory } from "./deploy.js";
41+
42+
const PreviewCommandOptions = CommonCommandOptions.extend({
43+
branch: z.string().optional(),
44+
config: z.string().optional(),
45+
projectRef: z.string().optional(),
46+
skipUpdateCheck: z.boolean().default(false),
47+
envFile: z.string().optional(),
48+
});
49+
50+
type PreviewCommandOptions = z.infer<typeof PreviewCommandOptions>;
51+
52+
export function configureDeployCommand(program: Command) {
53+
return commonOptions(
54+
program
55+
.command("preview archive")
56+
.description("Archive a preview branch")
57+
.argument("[path]", "The path to the project", ".")
58+
.option(
59+
"-b, --branch <branch>",
60+
"The preview branch to deploy to when passing --env preview. If not provided, we'll detect your local git branch."
61+
)
62+
.option("--skip-update-check", "Skip checking for @trigger.dev package updates")
63+
.option("-c, --config <config file>", "The name of the config file, found at [path]")
64+
.option(
65+
"-p, --project-ref <project ref>",
66+
"The project ref. Required if there is no config file. This will override the project specified in the config file."
67+
)
68+
.option(
69+
"--env-file <env file>",
70+
"Path to the .env file to load into the CLI process. Defaults to .env in the project directory."
71+
)
72+
).action(async (path, options) => {
73+
await handleTelemetry(async () => {
74+
await printStandloneInitialBanner(true);
75+
await previewArchiveCommand(path, options);
76+
});
77+
});
78+
}
79+
80+
export async function previewArchiveCommand(dir: string, options: unknown) {
81+
return await wrapCommandAction(
82+
"previewArchiveCommand",
83+
PreviewCommandOptions,
84+
options,
85+
async (opts) => {
86+
return await _previewArchiveCommand(dir, opts);
87+
}
88+
);
89+
}
90+
91+
async function _previewArchiveCommand(dir: string, options: PreviewCommandOptions) {
92+
intro(`Archiving preview branch`);
93+
94+
if (!options.skipUpdateCheck) {
95+
await updateTriggerPackages(dir, { ...options }, true, true);
96+
}
97+
98+
const cwd = process.cwd();
99+
const projectPath = resolve(cwd, dir);
100+
101+
verifyDirectory(dir, projectPath);
102+
103+
const authorization = await login({
104+
embedded: true,
105+
defaultApiUrl: options.apiUrl,
106+
profile: options.profile,
107+
});
108+
109+
if (!authorization.ok) {
110+
if (authorization.error === "fetch failed") {
111+
throw new Error(
112+
`Failed to connect to ${authorization.auth?.apiUrl}. Are you sure it's the correct URL?`
113+
);
114+
} else {
115+
throw new Error(
116+
`You must login first. Use the \`login\` CLI command.\n\n${authorization.error}`
117+
);
118+
}
119+
}
120+
121+
const resolvedConfig = await loadConfig({
122+
cwd: projectPath,
123+
overrides: { project: options.projectRef },
124+
configFile: options.config,
125+
});
126+
127+
logger.debug("Resolved config", resolvedConfig);
128+
129+
const gitMeta = await createGitMeta(resolvedConfig.workspaceDir);
130+
logger.debug("gitMeta", gitMeta);
131+
132+
const branch = getBranch({ specified: options.branch, gitMeta });
133+
134+
if (!branch) {
135+
throw new Error(
136+
"Didn't auto-detect branch, so you need to specify a preview branch. Use --branch <branch>."
137+
);
138+
}
139+
140+
const projectClient = await getProjectClient({
141+
accessToken: authorization.auth.accessToken,
142+
apiUrl: authorization.auth.apiUrl,
143+
projectRef: resolvedConfig.project,
144+
env: "preview",
145+
branch,
146+
profile: options.profile,
147+
});
148+
149+
if (!projectClient) {
150+
throw new Error("Failed to get project client");
151+
}
152+
153+
const $buildSpinner = spinner();
154+
$buildSpinner.start(`Archiving "${branch}"`);
155+
156+
const result = await projectClient.client.archiveBranch(branch);
157+
158+
$buildSpinner.stop(`Successfully archived ${branch}`);
159+
}

0 commit comments

Comments
 (0)