Skip to content
Closed
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
4 changes: 2 additions & 2 deletions apps/cli/src/commands/bottom.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { bottom as coreBottom } from "@array/core/commands/bottom";
import { printNav } from "../utils/output";
import { printNavResult } from "../utils/output";
import { unwrap } from "../utils/run";

export async function bottom(): Promise<void> {
printNav("down", unwrap(await coreBottom()));
printNavResult(unwrap(await coreBottom()));
}
19 changes: 2 additions & 17 deletions apps/cli/src/commands/checkout.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,8 @@
import { checkout as checkoutCmd } from "@array/core/commands/checkout";
import { changeLabel } from "@array/core/slugify";
import { cyan, dim, formatSuccess, message } from "../utils/output";
import { printNavResult } from "../utils/output";
import { requireArg, unwrap } from "../utils/run";

export async function checkout(id: string): Promise<void> {
requireArg(id, "Usage: arr checkout <id>");

const result = unwrap(await checkoutCmd(id));

// Handle trunk checkout - creates new empty change on main
if (id === "main" || id === "master" || id === "trunk") {
message(formatSuccess(`Switched to ${cyan(id)}`));
return;
}

const label = changeLabel(result.change.description, result.change.changeId);
message(
formatSuccess(
`Switched to ${cyan(label)}: ${result.change.description || dim("(no description)")}`,
),
);
printNavResult(unwrap(await checkoutCmd(id)));
}
25 changes: 2 additions & 23 deletions apps/cli/src/commands/down.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,7 @@
import { down as coreDown } from "@array/core/commands/down";
import { COMMANDS } from "../registry";
import {
arr,
cyan,
dim,
formatChangeId,
green,
hint,
message,
} from "../utils/output";
import { printNavResult } from "../utils/output";
import { unwrap } from "../utils/run";

export async function down(): Promise<void> {
const result = unwrap(await coreDown());

if (result.createdOnTrunk) {
message(`${green("◉")} Started fresh on ${cyan("main")}`);
hint(`Run ${arr(COMMANDS.top)} to go back to your stack`);
} else {
const shortId = formatChangeId(
result.changeId.slice(0, 8),
result.changeIdPrefix,
);
const desc = result.description || dim("(empty)");
message(`↓ ${green(desc)} ${shortId}`);
}
printNavResult(unwrap(await coreDown()));
}
58 changes: 58 additions & 0 deletions apps/cli/src/commands/get.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { get as coreGet } from "@array/core/commands/get";
import type { CommandMeta } from "@array/core/commands/types";
import type { ArrContext } from "@array/core/engine";
import {
cyan,
dim,
formatError,
formatSuccess,
hint,
magenta,
message,
status,
} from "../utils/output";

export const meta: CommandMeta = {
name: "get",
args: "<branch|pr#>",
description:
"Restore a branch and its stack from remote by name or PR number",
category: "workflow",
};

export async function get(ctx: ArrContext, target?: string): Promise<void> {
if (!target) {
console.error(formatError("Missing argument: branch name or PR number"));
hint("Usage: arr get <branch> or arr get <pr#>");
process.exit(1);
}

status(`Getting ${target} from remote...`);

const result = await coreGet({
target,
engine: ctx.engine,
cwd: ctx.cwd,
});

if (!result.ok) {
console.error(formatError(result.error.message));
process.exit(1);
}

const { stack, targetBranch } = result.value;

message(formatSuccess(`Restored and switched to ${cyan(targetBranch)}`));

if (stack.length > 1) {
message(dim("Stack:"));
for (const branch of stack) {
const isTarget = branch.branchName === targetBranch;
const prLabel = magenta(`PR #${branch.prNumber}`);
const branchLabel = cyan(branch.branchName);
const marker = isTarget ? " ← you are here" : "";

message(` ${branchLabel} ${dim(`(${prLabel})`)}${marker}`);
}
}
}
23 changes: 10 additions & 13 deletions apps/cli/src/commands/hidden/dump-refs.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { $ } from "bun";
import { getTrackedBranchNames, readMetadata } from "@array/core/git/metadata";

/**
* Hidden debug command to dump all arr refs metadata.
Expand All @@ -8,23 +8,20 @@ import { $ } from "bun";
* metadata about changes (PR info, etc.).
*/
export async function dumpRefs(): Promise<void> {
const result =
await $`git for-each-ref refs/arr --format='%(refname:short)'`.quiet();
const refs = result.stdout.toString().trim().split("\n").filter(Boolean);
const branches = getTrackedBranchNames();

if (refs.length === 0) {
if (branches.length === 0) {
console.log("No arr refs found.");
return;
}

for (const ref of refs) {
console.log(`=== ${ref} ===`);
const blob = await $`git cat-file blob refs/${ref}`.quiet();
const content = blob.stdout.toString().trim();
try {
console.log(JSON.stringify(JSON.parse(content), null, 2));
} catch {
console.log(content);
for (const branchName of branches) {
console.log(`=== arr/${branchName} ===`);
const meta = readMetadata(branchName);
if (meta) {
console.log(JSON.stringify(meta, null, 2));
} else {
console.log("(failed to read metadata)");
}
console.log();
}
Expand Down
Loading
Loading