Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fdd3793ee1 | ||
|
|
88ad16c86f |
+2
-1
@@ -39,8 +39,9 @@ RUN npm ci --omit=dev || npm install --production && \
|
|||||||
RUN apk del python3 make g++ vips-dev
|
RUN apk del python3 make g++ vips-dev
|
||||||
|
|
||||||
# Copy built files from builder
|
# Copy built files from builder
|
||||||
|
# Hinweis: Drizzle-Migrationen werden nicht kopiert - das Schema wird zur
|
||||||
|
# Laufzeit von initDatabase() angelegt, src/db/migrations existiert nicht.
|
||||||
COPY --from=builder /app/dist ./dist
|
COPY --from=builder /app/dist ./dist
|
||||||
COPY --from=builder /app/src/db/migrations ./dist/db/migrations
|
|
||||||
|
|
||||||
# Copy migration script and migrated images
|
# Copy migration script and migrated images
|
||||||
COPY --from=builder /app/migrate-production.js ./migrate-production.js
|
COPY --from=builder /app/migrate-production.js ./migrate-production.js
|
||||||
|
|||||||
@@ -1,43 +1,84 @@
|
|||||||
import simpleGit, { SimpleGit } from 'simple-git';
|
import simpleGit, { SimpleGit } from 'simple-git';
|
||||||
import { mkdir, rm } from 'fs/promises';
|
import { mkdir, rm, cp } from 'fs/promises';
|
||||||
|
import { existsSync } from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { env } from '../config/env.js';
|
import { env } from '../config/env.js';
|
||||||
|
|
||||||
export class GitService {
|
export class GitService {
|
||||||
private git: SimpleGit;
|
private git: SimpleGit;
|
||||||
private workspaceDir: string;
|
private workspaceDir: string;
|
||||||
|
private parentDir: string;
|
||||||
private repoUrl: string;
|
private repoUrl: string;
|
||||||
private token: string;
|
private token: string;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.workspaceDir = env.GIT_WORKSPACE_DIR;
|
this.workspaceDir = env.GIT_WORKSPACE_DIR;
|
||||||
|
this.parentDir = path.dirname(this.workspaceDir);
|
||||||
this.repoUrl = env.GIT_REPO_URL;
|
this.repoUrl = env.GIT_REPO_URL;
|
||||||
this.token = env.GIT_TOKEN;
|
this.token = env.GIT_TOKEN;
|
||||||
this.git = simpleGit();
|
this.git = simpleGit();
|
||||||
}
|
}
|
||||||
|
|
||||||
async initialize() {
|
async initialize() {
|
||||||
// Ensure workspace directory exists
|
// Elternverzeichnis muss existieren - simple-git startet git von dort aus
|
||||||
await mkdir(this.workspaceDir, { recursive: true });
|
await mkdir(this.parentDir, { recursive: true });
|
||||||
|
|
||||||
// Add token to repo URL for authentication
|
// Add token to repo URL for authentication
|
||||||
const authenticatedUrl = this.repoUrl.replace(
|
const authenticatedUrl = this.repoUrl.replace(
|
||||||
'https://',
|
'https://',
|
||||||
`https://oauth2:${this.token}@`
|
`https://oauth2:${encodeURIComponent(this.token)}@`
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
let usable = false;
|
||||||
// Check if repo already exists
|
|
||||||
await this.git.cwd(this.workspaceDir);
|
if (existsSync(path.join(this.workspaceDir, '.git'))) {
|
||||||
await this.git.status();
|
try {
|
||||||
console.log('Repository already exists, pulling latest...');
|
this.git = simpleGit(this.workspaceDir);
|
||||||
await this.git.pull();
|
await this.git.status();
|
||||||
} catch {
|
console.log('Repository already exists, pulling latest...');
|
||||||
// Clone if doesn't exist
|
await this.git.pull();
|
||||||
|
usable = true;
|
||||||
|
} catch (error) {
|
||||||
|
// Token aus der Meldung entfernen - git gibt die Remote-URL mit aus
|
||||||
|
const msg = error instanceof Error ? error.message : String(error);
|
||||||
|
console.warn(
|
||||||
|
'Existing workspace unusable, re-cloning:',
|
||||||
|
msg.replace(/\/\/[^@\s/]*@/g, '//***@')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!usable) {
|
||||||
console.log('Cloning repository...');
|
console.log('Cloning repository...');
|
||||||
|
|
||||||
|
// Hochgeladene Bilder liegen im Workspace und wuerden beim Loeschen
|
||||||
|
// verschwinden - vorher wegsichern, nach dem Clone zurueckspielen
|
||||||
|
const imagesDir = path.join(this.workspaceDir, 'public', 'images');
|
||||||
|
const backupDir = path.join(this.parentDir, '.workspace-images-backup');
|
||||||
|
const hasImages = existsSync(imagesDir);
|
||||||
|
|
||||||
|
await rm(backupDir, { recursive: true, force: true });
|
||||||
|
if (hasImages) {
|
||||||
|
await cp(imagesDir, backupDir, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
await rm(this.workspaceDir, { recursive: true, force: true });
|
await rm(this.workspaceDir, { recursive: true, force: true });
|
||||||
|
|
||||||
|
// Aus dem existierenden Elternverzeichnis klonen, nicht aus dem
|
||||||
|
// soeben geloeschten Zielverzeichnis (sonst: spawn git ENOENT)
|
||||||
|
this.git = simpleGit(this.parentDir);
|
||||||
await this.git.clone(authenticatedUrl, this.workspaceDir);
|
await this.git.clone(authenticatedUrl, this.workspaceDir);
|
||||||
await this.git.cwd(this.workspaceDir);
|
this.git = simpleGit(this.workspaceDir);
|
||||||
|
|
||||||
|
if (hasImages) {
|
||||||
|
// force: false -> was schon im Repo liegt, bleibt unangetastet
|
||||||
|
await cp(backupDir, imagesDir, {
|
||||||
|
recursive: true,
|
||||||
|
force: false,
|
||||||
|
errorOnExist: false,
|
||||||
|
});
|
||||||
|
await rm(backupDir, { recursive: true, force: true });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure git user
|
// Configure git user
|
||||||
@@ -47,6 +88,14 @@ export class GitService {
|
|||||||
|
|
||||||
async commitAndPush(message: string): Promise<string> {
|
async commitAndPush(message: string): Promise<string> {
|
||||||
await this.git.add('.');
|
await this.git.add('.');
|
||||||
|
|
||||||
|
const status = await this.git.status();
|
||||||
|
if (status.isClean()) {
|
||||||
|
// Nichts zu committen - aktuellen Stand zurueckgeben statt zu scheitern
|
||||||
|
const current = await this.git.log({ maxCount: 1 });
|
||||||
|
return current.latest?.hash || '';
|
||||||
|
}
|
||||||
|
|
||||||
await this.git.commit(message);
|
await this.git.commit(message);
|
||||||
await this.git.push('origin', 'main');
|
await this.git.push('origin', 'main');
|
||||||
|
|
||||||
@@ -59,7 +108,15 @@ export class GitService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async reset() {
|
async reset() {
|
||||||
await this.git.reset(['--hard', 'HEAD']);
|
// Nur zuruecksetzen wenn wirklich ein Repo da ist - sonst laeuft git
|
||||||
await this.git.clean('f', ['-d']);
|
// im Prozess-Arbeitsverzeichnis und raeumt dort auf
|
||||||
|
if (!existsSync(path.join(this.workspaceDir, '.git'))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const git = simpleGit(this.workspaceDir);
|
||||||
|
await git.reset(['--hard', 'HEAD']);
|
||||||
|
// Uploads ausnehmen - die sind noch nicht committed und waeren sonst weg
|
||||||
|
await git.clean('f', ['-d', '-e', 'public/images']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user