fix: preserve runtime furni assets during deploy
CI / check (push) Successful in 46s
CI / release (push) Skipped
CI / deploy (push) Successful in 1m33s

This commit is contained in:
Simo committed 2026-08-02 17:32:32 +02:00
1 parent cde15ad022
commit 0c8e62357f
2 files changed
+57 -2

No files matched your search

+6 -1
View File
@@ -177,10 +177,15 @@ jobs:
cd "${LIVE}"
echo "Hard reset live tree to origin/main (no nuclear src wipe)..."
git reset --hard origin/main
# Keep env, uploads, and deps we are about to replace from stage.
# Keep env, uploads, runtime-imported furni assets, and deps we are
# about to replace from stage. The app can write furni files while it
# remains online during staging, so cleaning those paths races with
# active imports and can fail with "Directory not empty".
git clean -fd \
-e .env -e .env.local -e .env.production -e .env*.local \
-e storage -e public/cache \
-e public/swf/dcr/hof_furni \
-e public/nitro-assets/bundled/furniture \
-e node_modules -e node_modules.prev -e .next -e .next.prev
if ! git diff --exit-code HEAD -- src >/dev/null; then
+51 -1
View File
@@ -1,4 +1,13 @@
import { readFileSync } from "node:fs";
import { spawnSync } from "node:child_process";
import {
existsSync,
mkdirSync,
mkdtempSync,
readFileSync,
rmSync,
writeFileSync,
} from "node:fs";
import { tmpdir } from "node:os";
import { resolve } from "node:path";
import { describe, expect, it } from "vitest";
@@ -42,6 +51,47 @@ describe("production deploy workflow", () => {
expect(deployJob).toContain("pnpm install --frozen-lockfile");
});
it("preserves runtime furni assets when cleaning the live checkout", () => {
const cleanStart = deployJob.indexOf("git clean -fd \\");
const commandLines: string[] = [];
for (const line of deployJob.slice(cleanStart).split(/\r?\n/)) {
commandLines.push(line);
if (!line.trimEnd().endsWith("\\")) break;
}
const cleanLines = commandLines.join(" ");
const excludes = Array.from(
cleanLines.matchAll(/-e\s+([^\s\\]+)/g),
).flatMap(([, pattern]) => ["-e", pattern]);
const work = mkdtempSync(resolve(tmpdir(), "epicnext-deploy-clean-"));
const runtimeFiles = [
"public/swf/dcr/hof_furni/icons/runtime_icon.png",
"public/swf/dcr/hof_furni/swf/runtime.swf",
"public/nitro-assets/bundled/furniture/runtime.nitro",
];
try {
spawnSync("git", ["init", "--quiet"], { cwd: work });
for (const file of [...runtimeFiles, "remove-me.tmp"]) {
const absolute = resolve(work, file);
mkdirSync(resolve(absolute, ".."), { recursive: true });
writeFileSync(absolute, "runtime");
}
const clean = spawnSync("git", ["clean", "-fd", ...excludes], {
cwd: work,
encoding: "utf8",
});
expect(clean.status, clean.stderr).toBe(0);
for (const file of runtimeFiles) {
expect(existsSync(resolve(work, file)), file).toBe(true);
}
expect(existsSync(resolve(work, "remove-me.tmp"))).toBe(false);
} finally {
rmSync(work, { recursive: true, force: true });
}
});
it("reclaims ownership before git operations so www-data files can be overwritten", () => {
const chownCmd = `sudo chown -R "${userVar}:${groupVar}"`;
expect(toContainLiteral(workflow, chownCmd)).toBe(true);