fix: package prebuilt app for deployment
CI / verify (push) Failing after 4m44s

This commit is contained in:
2026-09-17 22:53:49 +08:00
parent f6968e3401
commit bc0545527f
4 changed files with 27 additions and 5 deletions
-1
View File
@@ -1,6 +1,5 @@
.git
.gitea
.next
node_modules
data/projects/*
!.gitkeep
+1
View File
@@ -31,6 +31,7 @@ jobs:
STUDIO_USERNAME: studio
STUDIO_PASSWORD: ${{ secrets.STUDIO_PASSWORD }}
DEPLOY_PORT: ${{ vars.DEPLOY_PORT }}
DEPLOY_DOCKERFILE: Dockerfile.deploy
GITHUB_SHA: ${{ gitea.sha }}
run: |
if [ -z "$STUDIO_PASSWORD" ]; then
+17
View File
@@ -0,0 +1,17 @@
FROM node:24-bookworm-slim
WORKDIR /app
ENV NODE_ENV=production \
NEXT_TELEMETRY_DISABLED=1 \
PORT=3000 \
HOSTNAME=0.0.0.0
RUN groupadd --system --gid 1001 studio && useradd --system --uid 1001 --gid studio studio
COPY --chown=studio:studio .next/standalone ./
COPY --chown=studio:studio .next/static ./.next/static
COPY --chown=studio:studio templates ./templates
COPY --chown=studio:studio vendor ./vendor
RUN mkdir -p /app/data/projects && chown -R studio:studio /app/data
USER studio
EXPOSE 3000
VOLUME ["/app/data/projects"]
HEALTHCHECK --interval=5s --timeout=3s --start-period=15s --retries=8 CMD ["node", "-e", "fetch('http://127.0.0.1:3000/api/health').then(r=>{if(!r.ok)process.exit(1)}).catch(()=>process.exit(1))"]
CMD ["node", "server.js"]
+9 -4
View File
@@ -12,6 +12,8 @@ const image = `${service}:${sha}`;
const port = process.env.DEPLOY_PORT || "3000";
const password = process.env.STUDIO_PASSWORD;
const username = process.env.STUDIO_USERNAME || "studio";
const dockerfile = process.env.DEPLOY_DOCKERFILE || "Dockerfile";
const usePrebuiltOutput = dockerfile === "Dockerfile.deploy";
if (!password) throw new Error("STUDIO_PASSWORD secret is required");
if (!/^\d{2,5}$/.test(port) || Number(port) > 65535) throw new Error("DEPLOY_PORT must be a valid TCP port");
@@ -40,19 +42,22 @@ async function waitForHealth(container, timeoutMs = 90_000) {
}
async function followBuild(stream) {
await new Promise((resolve, reject) => {
docker.modem.followProgress(stream, (error, output) => error ? reject(error) : resolve(output), (event) => {
const output = await new Promise((resolve, reject) => {
docker.modem.followProgress(stream, (error, events) => error ? reject(error) : resolve(events), (event) => {
if (event.stream) process.stdout.write(event.stream);
if (event.error) process.stderr.write(`${event.error}\n`);
});
});
const failure = output.find((event) => event.error || event.errorDetail?.message);
if (failure) throw new Error(failure.error || failure.errorDetail.message);
}
console.log(`Building ${image}`);
const context = tar.pack(process.cwd(), {
ignore: (name) => [".git", ".next", "node_modules"].some((part) => name === part || name.includes(`/${part}/`)),
ignore: (name) => [".git", "node_modules", ...usePrebuiltOutput ? [] : [".next"]]
.some((part) => name === part || name.includes(`/${part}/`)),
});
await followBuild(await docker.buildImage(context, { t: image, dockerfile: "Dockerfile" }));
await followBuild(await docker.buildImage(context, { t: image, dockerfile }));
try { await docker.createVolume({ Name: volume }); } catch (error) { if (error.statusCode !== 409) throw error; }
await removeContainer(candidate);