Skip to content

Commit 4f90229

Browse files
authored
Tighten landing page spacing and harden git status fallback (#81)
* Optimize landing page spacing and git status fallback - Tighten marketing page layout spacing - Return empty git status for missing workspace paths - Clean up theme docs and branding tables * Import Git status details type in GitCore
1 parent bf7a40e commit 4f90229

2 files changed

Lines changed: 75 additions & 7 deletions

File tree

apps/server/src/git/Layers/GitCore.test.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { existsSync } from "node:fs";
1+
import fs, { existsSync } from "node:fs";
22
import path from "node:path";
33

44
import * as NodeServices from "@effect/platform-node/NodeServices";
@@ -1277,6 +1277,35 @@ it.layer(TestLayer)("git integration", (it) => {
12771277
}),
12781278
);
12791279

1280+
it.effect("returns an empty status for a missing workspace path", () =>
1281+
Effect.gen(function* () {
1282+
const tmp = yield* makeTmpDir();
1283+
yield* initRepoWithCommit(tmp);
1284+
const core = yield* GitCore;
1285+
1286+
expect(existsSync(tmp)).toBe(true);
1287+
yield* Effect.sync(() => fs.rmSync(tmp, { recursive: true, force: true }));
1288+
1289+
const details = yield* core.statusDetails(tmp);
1290+
expect(details).toEqual(
1291+
expect.objectContaining({
1292+
branch: null,
1293+
hasWorkingTreeChanges: false,
1294+
hasConflicts: false,
1295+
conflictedFiles: [],
1296+
hasUpstream: false,
1297+
aheadCount: 0,
1298+
behindCount: 0,
1299+
upstreamRef: null,
1300+
pr: null,
1301+
}),
1302+
);
1303+
expect(details.workingTree.files).toEqual([]);
1304+
expect(details.workingTree.insertions).toBe(0);
1305+
expect(details.workingTree.deletions).toBe(0);
1306+
}),
1307+
);
1308+
12801309
it.effect("computes ahead count against base branch when no upstream is configured", () =>
12811310
Effect.gen(function* () {
12821311
const tmp = yield* makeTmpDir();

apps/server/src/git/Layers/GitCore.ts

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
type GitCoreShape,
2828
type ExecuteGitInput,
2929
type ExecuteGitResult,
30+
type GitStatusDetails,
3031
} from "../Services/GitCore.ts";
3132
import { ServerConfig } from "../../config.ts";
3233
import { decodeJsonResult } from "@okcode/shared/schemaJson";
@@ -121,6 +122,23 @@ function parsePorcelainConflictPath(line: string): string | null {
121122
return parsePorcelainPath(line);
122123
}
123124

125+
const EMPTY_STATUS_DETAILS = {
126+
branch: null,
127+
hasWorkingTreeChanges: false,
128+
hasConflicts: false,
129+
conflictedFiles: [],
130+
workingTree: {
131+
files: [],
132+
insertions: 0,
133+
deletions: 0,
134+
},
135+
hasUpstream: false,
136+
aheadCount: 0,
137+
behindCount: 0,
138+
upstreamRef: null,
139+
pr: null,
140+
} satisfies GitStatusDetails;
141+
124142
function parseBranchLine(line: string): { name: string; current: boolean } | null {
125143
const trimmed = line.trim();
126144
if (trimmed.length === 0) return null;
@@ -1042,15 +1060,34 @@ export const makeGitCore = (options?: { executeOverride?: GitCoreShape["execute"
10421060

10431061
const statusDetails: GitCoreShape["statusDetails"] = (cwd) =>
10441062
Effect.gen(function* () {
1063+
const cwdStat = yield* fileSystem.stat(cwd).pipe(Effect.catch(() => Effect.succeed(null)));
1064+
if (!cwdStat || cwdStat.type !== "Directory") {
1065+
return EMPTY_STATUS_DETAILS;
1066+
}
1067+
10451068
yield* refreshStatusUpstreamIfStale(cwd).pipe(Effect.ignoreCause({ log: true }));
10461069

1047-
const [statusStdout, unstagedNumstatStdout, stagedNumstatStdout] = yield* Effect.all(
1070+
const status = yield* executeGit(
1071+
"GitCore.statusDetails.status",
1072+
cwd,
1073+
["status", "--porcelain=2", "--branch"],
1074+
{ allowNonZeroExit: true },
1075+
);
1076+
if (status.code !== 0) {
1077+
const stderr = status.stderr.trim();
1078+
if (stderr.toLowerCase().includes("not a git repository")) {
1079+
return EMPTY_STATUS_DETAILS;
1080+
}
1081+
return yield* createGitCommandError(
1082+
"GitCore.statusDetails.status",
1083+
cwd,
1084+
["status", "--porcelain=2", "--branch"],
1085+
stderr.length > 0 ? stderr : `git status failed with code ${status.code}.`,
1086+
);
1087+
}
1088+
1089+
const [unstagedNumstatStdout, stagedNumstatStdout] = yield* Effect.all(
10481090
[
1049-
runGitStdout("GitCore.statusDetails.status", cwd, [
1050-
"status",
1051-
"--porcelain=2",
1052-
"--branch",
1053-
]),
10541091
runGitStdout("GitCore.statusDetails.unstagedNumstat", cwd, ["diff", "--numstat"]),
10551092
runGitStdout("GitCore.statusDetails.stagedNumstat", cwd, [
10561093
"diff",
@@ -1061,6 +1098,8 @@ export const makeGitCore = (options?: { executeOverride?: GitCoreShape["execute"
10611098
{ concurrency: "unbounded" },
10621099
);
10631100

1101+
const statusStdout = status.stdout;
1102+
10641103
let branch: string | null = null;
10651104
let upstreamRef: string | null = null;
10661105
let aheadCount = 0;

0 commit comments

Comments
 (0)