Repository navigation
fix(host-service): classify missing project directory as NOT_FOUND in workspace-creation git procedures #6316
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,5 @@ | ||
| import { existsSync } from "node:fs"; | ||
| import { TRPCError } from "@trpc/server"; | ||
| import { eq } from "drizzle-orm"; | ||
| import { projects } from "../../../../db/schema"; | ||
| import type { HostServiceContext } from "../../../../types"; | ||
|
|
@@ -24,3 +26,17 @@ export function requireLocalProject( | |
| } | ||
| return localProject; | ||
| } | ||
|
|
||
| // A project directory deleted or moved outside the app is a routine | ||
| // lifecycle state, not a bug — classify it here so simple-git's construct | ||
| // error can't escape a workspace-creation procedure as a reportable 500. | ||
| export function requireProjectRepoPath(localProject: LocalProject): string { | ||
| if (!existsSync(localProject.repoPath)) { | ||
| throw new TRPCError({ | ||
| code: "NOT_FOUND", | ||
| message: "Project directory no longer exists on disk", | ||
| cause: { kind: "PROJECT_DIR_MISSING", repoPath: localProject.repoPath }, | ||
| }); | ||
| } | ||
|
Comment on lines
+33
to
+40
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
node <<'NODE'
const { existsSync, mkdtempSync, rmSync, statSync, writeFileSync } = require("node:fs");
const { join } = require("node:path");
const { tmpdir } = require("node:os");
const root = mkdtempSync(join(tmpdir(), "repo-path-check-"));
try {
const filePath = join(root, "repo");
writeFileSync(filePath, "");
if (!existsSync(filePath) || statSync(filePath).isDirectory()) {
throw new Error("Expected a regular file to exist without being a directory");
}
} finally {
rmSync(root, { recursive: true, force: true });
}
NODERepository: superset-sh/superset Length of output: 158 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
# Locate the reviewed file and inspect the relevant implementation and nearby type/export context.
if [ -f "packages/host-service/src/trpc/router/workspace-creation/shared/local-project.ts" ]; then
echo "== file exists =="
stat -c '%n %s lines' packages/host-service/src/trpc/router/workspace-creation/shared/local-project.ts
echo
echo "== imports and exported functions outline =="
ast-grep outline packages/host-service/src/trpc/router/workspace-creation/shared/local-project.ts || true
echo
echo "== relevant file contents =="
sed -n '1,120p' packages/host-service/src/trpc/router/workspace-creation/shared/local-project.ts
else
echo "Reviewed file not found"
fd -a 'local-project.ts' .
fiRepository: superset-sh/superset Length of output: 218 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
echo "== node availability =="
node --version || true
echo "== file availability =="
if [ -f "packages/host-service/src/trpc/router/workspace-creation/shared/local-project.ts" ]; then
echo "packages/host-service/src/trpc/router/workspace-creation/shared/local-project.ts"
wc -l packages/host-service/src/trpc/router/workspace-creation/shared/local-project.ts
else
fd -a 'local-project.ts' . | sed -n '1,50p'
fi
echo "== relevant file contents =="
sed -n '1,140p' packages/host-service/src/trpc/router/workspace-creation/shared/local-project.ts 2>/dev/null || true
echo "== related paths in workspace creation =="
rg -n "requireProjectRepoPath|localProject\.repoPath|repoPath" packages/host-service/src/trpc/router/workspace-creation packages/host-service/src 2>/dev/null | sed -n '1,120p' || true
echo "== fs behavior probe =="
node <<'NODE'
const fs = require("node:fs");
const { mkdtempSync, rmSync, writeFileSync, mkdirSync, unlinkSync } = require("node:fs");
const path = require("node:path");
const { tmpdir } = require("node:os");
const root = mkdtempSync(path.join(tmpdir(), "repo-path-check-"));
try {
const filePath = path.join(root, "repo");
const dirPath = path.join(root, "repo-dir");
writeFileSync(filePath, "");
mkdirSync(dirPath);
console.log(JSON.stringify({
existsSync_file: fs.existsSync(filePath),
isDirectory_file: fs.statSync(filePath).isDirectory(),
existsSync_dir: fs.existsSync(dirPath),
isDirectory_dir: fs.statSync(dirPath).isDirectory(),
existsSync_missing: fs.existsSync(path.join(root, "missing")),
}));
try {
writeFileSync(path.join(root, "repo"), "x");
} catch (error) {
console.log(JSON.stringify({ write_same_file_error_code: error.code }));
}
try {
fs.mkdirSync(filePath, { recursive: true });
} catch (error) {
console.log(JSON.stringify({ mkdir_over_existing_file_error_code: error.code }));
}
} finally {
rmSync(root, { recursive: true, force: true });
}
NODERepository: superset-sh/superset Length of output: 17250 Validate that
🤖 Prompt for AI Agents |
||
| return localProject.repoPath; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2:
existsSynconly checks that the path exists, not that it is a directory — it returnstruefor regular files too. Sincesimple-gititself validates the path withstatSync(...).isDirectory()before throwingGitConstructError, arepoPaththat resolves to a file (rather than a missing path) will pass this guard but still blow up with the original 500 downstream, defeating the purpose of this fix. UsestatSyncand checkisDirectory(), treatingENOENT/ENOTDIRasPROJECT_DIR_MISSINGand letting other filesystem errors propagate.Prompt for AI agents