Skip to content

Commit 4bb22d6

Browse files
committed
Archiving branch via the CLI working
1 parent b8bdd60 commit 4bb22d6

File tree

5 files changed

+118
-50
lines changed

5 files changed

+118
-50
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { type ActionFunctionArgs, json } from "@remix-run/server-runtime";
2+
import { tryCatch } from "@trigger.dev/core";
3+
import { z } from "zod";
4+
import { prisma } from "~/db.server";
5+
import { ArchiveBranchService } from "~/services/archiveBranch.server";
6+
import { logger } from "~/services/logger.server";
7+
import { authenticateApiRequestWithPersonalAccessToken } from "~/services/personalAccessToken.server";
8+
9+
const ParamsSchema = z.object({
10+
projectRef: z.string(),
11+
});
12+
13+
const BodySchema = z.object({
14+
branch: z.string(),
15+
});
16+
17+
export async function action({ request, params }: ActionFunctionArgs) {
18+
if (request.method !== "POST") {
19+
return json({ error: "Method not allowed" }, { status: 405 });
20+
}
21+
22+
logger.info("Archive branch", { url: request.url, params });
23+
24+
const authenticationResult = await authenticateApiRequestWithPersonalAccessToken(request);
25+
if (!authenticationResult) {
26+
return json({ error: "Invalid or Missing Access Token" }, { status: 401 });
27+
}
28+
29+
const parsedParams = ParamsSchema.safeParse(params);
30+
31+
if (!parsedParams.success) {
32+
return json({ error: "Invalid Params" }, { status: 400 });
33+
}
34+
35+
const { projectRef } = parsedParams.data;
36+
37+
const [error, body] = await tryCatch(request.json());
38+
if (error) {
39+
return json({ error: error.message }, { status: 400 });
40+
}
41+
42+
const parsed = BodySchema.safeParse(body);
43+
if (!parsed.success) {
44+
return json({ error: parsed.error.message }, { status: 400 });
45+
}
46+
47+
const environment = await prisma.runtimeEnvironment.findFirst({
48+
select: {
49+
id: true,
50+
archivedAt: true,
51+
},
52+
where: {
53+
organization: {
54+
members: {
55+
some: {
56+
userId: authenticationResult.userId,
57+
},
58+
},
59+
},
60+
project: {
61+
externalRef: projectRef,
62+
},
63+
branchName: parsed.data.branch,
64+
},
65+
});
66+
67+
if (!environment) {
68+
return json({ error: "Branch not found" }, { status: 404 });
69+
}
70+
71+
if (environment.archivedAt) {
72+
return json({ error: "Branch already archived" }, { status: 400 });
73+
}
74+
75+
const service = new ArchiveBranchService();
76+
const result = await service.call(authenticationResult.userId, {
77+
environmentId: environment.id,
78+
});
79+
80+
if (result.success) {
81+
return json(result);
82+
} else {
83+
return json(result, { status: 400 });
84+
}
85+
}

apps/webapp/app/routes/api.v1.projects.$projectRef.branches.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ const ParamsSchema = z.object({
1313
type ParamsSchema = z.infer<typeof ParamsSchema>;
1414

1515
export async function action({ request, params }: ActionFunctionArgs) {
16-
logger.info("projects get env", { url: request.url });
16+
if (request.method !== "POST") {
17+
return json({ error: "Method not allowed" }, { status: 405 });
18+
}
19+
20+
logger.info("project upsert branch", { url: request.url });
1721

1822
const authenticationResult = await authenticateApiRequestWithPersonalAccessToken(request);
1923
if (!authenticationResult) {

packages/cli-v3/src/apiClient.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,17 +182,18 @@ export class CliApiClient {
182182
);
183183
}
184184

185-
async archiveBranch(branch: string) {
185+
async archiveBranch(projectRef: string, branch: string) {
186186
if (!this.accessToken) {
187187
throw new Error("archiveBranch: No access token");
188188
}
189189

190190
return wrapZodFetch(
191-
z.object({ success: z.boolean() }),
192-
`${this.apiURL}/api/v1/branches/${branch}/archive`,
191+
z.object({ branch: z.object({ id: z.string() }) }),
192+
`${this.apiURL}/api/v1/projects/${projectRef}/branches/archive`,
193193
{
194194
method: "POST",
195195
headers: this.getHeaders(),
196+
body: JSON.stringify({ branch }),
196197
}
197198
);
198199
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { configureWorkersCommand } from "../commands/workers/index.js";
1414
import { configureSwitchProfilesCommand } from "../commands/switch.js";
1515
import { configureTriggerTaskCommand } from "../commands/trigger.js";
1616
import { configurePromoteCommand } from "../commands/promote.js";
17+
import { configurePreviewCommand } from "../commands/preview.js";
1718

1819
export const program = new Command();
1920

@@ -32,6 +33,7 @@ configureLogoutCommand(program);
3233
configureListProfilesCommand(program);
3334
configureSwitchProfilesCommand(program);
3435
configureUpdateCommand(program);
36+
configurePreviewCommand(program);
3537
// configureWorkersCommand(program);
3638
// configureTriggerTaskCommand(program);
3739

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

Lines changed: 22 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,45 @@
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";
1+
import { intro } from "@clack/prompts";
2+
import { getBranch } from "@trigger.dev/core/v3";
3+
import { Command } from "commander";
54
import { resolve } from "node:path";
6-
import { x } from "tinyexec";
75
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";
126
import {
137
CommonCommandOptions,
148
commonOptions,
159
handleTelemetry,
16-
SkipLoggingError,
1710
wrapCommandAction,
1811
} from "../cli/common.js";
1912
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";
13+
import { createGitMeta } from "../utilities/gitMeta.js";
3014
import { printStandloneInitialBanner } from "../utilities/initialBanner.js";
3115
import { logger } from "../utilities/logger.js";
32-
import { getProjectClient, upsertBranch } from "../utilities/session.js";
33-
import { getTmpDir } from "../utilities/tempDirectories.js";
16+
import { getProjectClient } from "../utilities/session.js";
3417
import { spinner } from "../utilities/windows.js";
18+
import { verifyDirectory } from "./deploy.js";
3519
import { login } from "./login.js";
3620
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";
21+
import { CliApiClient } from "../apiClient.js";
4122

4223
const PreviewCommandOptions = CommonCommandOptions.extend({
4324
branch: z.string().optional(),
4425
config: z.string().optional(),
4526
projectRef: z.string().optional(),
4627
skipUpdateCheck: z.boolean().default(false),
47-
envFile: z.string().optional(),
4828
});
4929

5030
type PreviewCommandOptions = z.infer<typeof PreviewCommandOptions>;
5131

52-
export function configureDeployCommand(program: Command) {
53-
return commonOptions(
54-
program
55-
.command("preview archive")
32+
export function configurePreviewCommand(program: Command) {
33+
const preview = program.command("preview").description("Modify preview branches");
34+
35+
commonOptions(
36+
preview
37+
.command("archive")
5638
.description("Archive a preview branch")
5739
.argument("[path]", "The path to the project", ".")
5840
.option(
5941
"-b, --branch <branch>",
60-
"The preview branch to deploy to when passing --env preview. If not provided, we'll detect your local git branch."
42+
"The preview branch to archive. If not provided, we'll detect your local git branch."
6143
)
6244
.option("--skip-update-check", "Skip checking for @trigger.dev package updates")
6345
.option("-c, --config <config file>", "The name of the config file, found at [path]")
@@ -137,23 +119,17 @@ async function _previewArchiveCommand(dir: string, options: PreviewCommandOption
137119
);
138120
}
139121

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-
}
122+
const apiClient = new CliApiClient(authorization.auth.apiUrl, authorization.auth.accessToken);
152123

153124
const $buildSpinner = spinner();
154125
$buildSpinner.start(`Archiving "${branch}"`);
155126

156-
const result = await projectClient.client.archiveBranch(branch);
127+
const result = await apiClient.archiveBranch(resolvedConfig.project, branch);
157128

158-
$buildSpinner.stop(`Successfully archived ${branch}`);
129+
if (result.success) {
130+
$buildSpinner.stop(`Successfully archived "${branch}"`);
131+
} else {
132+
$buildSpinner.stop(`Failed to archive "${branch}".`);
133+
logger.error(result.error);
134+
}
159135
}

0 commit comments

Comments
 (0)