Make CI run cross-platform (#295)

This commit is contained in:
Will Chen
2025-06-03 13:04:16 -07:00
committed by GitHub
parent 83eb721323
commit 7235eab227
16 changed files with 149 additions and 59 deletions

View File

@@ -11,6 +11,7 @@ import { eq } from "drizzle-orm";
import git from "isomorphic-git";
import { getGitAuthor } from "../utils/git_author";
import { ImportAppParams, ImportAppResult } from "../ipc_types";
import { copyDirectoryRecursive } from "../utils/file_utils";
const logger = log.scope("import-handlers");
const handle = createLoggedHandler(logger);
@@ -88,11 +89,10 @@ export function registerImportHandlers() {
throw error;
}
}
// Copy the app folder to the Dyad apps directory, excluding node_modules
await fs.cp(sourcePath, destPath, {
recursive: true,
filter: (source) => !source.includes("node_modules"),
});
// Copy the app folder to the Dyad apps directory.
// Why not use fs.cp? Because we want stable ordering for
// tests.
await copyDirectoryRecursive(sourcePath, destPath);
const isGitRepo = await fs
.access(path.join(destPath, ".git"))

View File

@@ -39,13 +39,19 @@ export async function copyDirectoryRecursive(
) {
await fsPromises.mkdir(destination, { recursive: true });
const entries = await fsPromises.readdir(source, { withFileTypes: true });
// Why do we sort? This ensures stable ordering of files across platforms
// which is helpful for tests (and has no practical downsides).
entries.sort();
for (const entry of entries) {
const srcPath = path.join(source, entry.name);
const destPath = path.join(destination, entry.name);
if (entry.isDirectory()) {
await copyDirectoryRecursive(srcPath, destPath);
// Exclude node_modules directories
if (entry.name !== "node_modules") {
await copyDirectoryRecursive(srcPath, destPath);
}
} else {
await fsPromises.copyFile(srcPath, destPath);
}

View File

@@ -226,7 +226,9 @@ async function collectFiles(dir: string, baseDir: string): Promise<string[]> {
// Skip large configuration files or generated code (just include the path)
function isOmittedFile(relativePath: string): boolean {
return (
relativePath.includes(path.join("src", "components", "ui")) ||
// Why are we not using path.join here?
// Because we have already normalized the path to use /.
relativePath.includes("src/components/ui") ||
relativePath.includes("eslint.config") ||
relativePath.includes("tsconfig.json") ||
relativePath.includes("package-lock.json") ||
@@ -243,7 +245,11 @@ const OMITTED_FILE_CONTENT = "// Contents omitted for brevity";
*/
async function formatFile(filePath: string, baseDir: string): Promise<string> {
try {
const relativePath = path.relative(baseDir, filePath);
const relativePath = path
.relative(baseDir, filePath)
// Why? Normalize Windows-style paths which causes lots of weird issues (e.g. Git commit)
.split(path.sep)
.join("/");
if (isOmittedFile(relativePath)) {
return `<dyad-file path="${relativePath}">
@@ -310,7 +316,11 @@ export async function extractCodebase(appPath: string): Promise<{
const formattedContent = await formatFile(file, appPath);
// Get raw content for the files array
const relativePath = path.relative(appPath, file);
const relativePath = path
.relative(appPath, file)
// Why? Normalize Windows-style paths which causes lots of weird issues (e.g. Git commit)
.split(path.sep)
.join("/");
const fileContent = isOmittedFile(relativePath)
? OMITTED_FILE_CONTENT
: await readFileWithCache(file);