Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
88ad16c86f | ||
|
|
45ce268db6 | ||
|
|
c1ab18fd9f | ||
|
|
52d6457797 | ||
|
|
4c9be79282 | ||
|
|
324f0f706f | ||
|
|
f7a8c1816f | ||
|
|
d14914a453 | ||
|
|
2a1d56d2fc | ||
|
|
c8ed065486 | ||
|
|
8e6c1924b8 | ||
|
|
04dbd0bb0c | ||
|
|
9b697fbb05 |
@@ -39,8 +39,9 @@ RUN npm ci --omit=dev || npm install --production && \
|
||||
RUN apk del python3 make g++ vips-dev
|
||||
|
||||
# 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/src/db/migrations ./dist/db/migrations
|
||||
|
||||
# Copy migration script and migrated images
|
||||
COPY --from=builder /app/migrate-production.js ./migrate-production.js
|
||||
|
||||
@@ -1,43 +1,84 @@
|
||||
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 { env } from '../config/env.js';
|
||||
|
||||
export class GitService {
|
||||
private git: SimpleGit;
|
||||
private workspaceDir: string;
|
||||
private parentDir: string;
|
||||
private repoUrl: string;
|
||||
private token: string;
|
||||
|
||||
constructor() {
|
||||
this.workspaceDir = env.GIT_WORKSPACE_DIR;
|
||||
this.parentDir = path.dirname(this.workspaceDir);
|
||||
this.repoUrl = env.GIT_REPO_URL;
|
||||
this.token = env.GIT_TOKEN;
|
||||
this.git = simpleGit();
|
||||
}
|
||||
|
||||
async initialize() {
|
||||
// Ensure workspace directory exists
|
||||
await mkdir(this.workspaceDir, { recursive: true });
|
||||
// Elternverzeichnis muss existieren - simple-git startet git von dort aus
|
||||
await mkdir(this.parentDir, { recursive: true });
|
||||
|
||||
// Add token to repo URL for authentication
|
||||
const authenticatedUrl = this.repoUrl.replace(
|
||||
'https://',
|
||||
`https://oauth2:${this.token}@`
|
||||
`https://oauth2:${encodeURIComponent(this.token)}@`
|
||||
);
|
||||
|
||||
try {
|
||||
// Check if repo already exists
|
||||
await this.git.cwd(this.workspaceDir);
|
||||
await this.git.status();
|
||||
console.log('Repository already exists, pulling latest...');
|
||||
await this.git.pull();
|
||||
} catch {
|
||||
// Clone if doesn't exist
|
||||
let usable = false;
|
||||
|
||||
if (existsSync(path.join(this.workspaceDir, '.git'))) {
|
||||
try {
|
||||
this.git = simpleGit(this.workspaceDir);
|
||||
await this.git.status();
|
||||
console.log('Repository already exists, pulling latest...');
|
||||
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...');
|
||||
|
||||
// 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 });
|
||||
|
||||
// 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.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
|
||||
@@ -47,6 +88,14 @@ export class GitService {
|
||||
|
||||
async commitAndPush(message: string): Promise<string> {
|
||||
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.push('origin', 'main');
|
||||
|
||||
@@ -59,7 +108,15 @@ export class GitService {
|
||||
}
|
||||
|
||||
async reset() {
|
||||
await this.git.reset(['--hard', 'HEAD']);
|
||||
await this.git.clean('f', ['-d']);
|
||||
// Nur zuruecksetzen wenn wirklich ein Repo da ist - sonst laeuft git
|
||||
// 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']);
|
||||
}
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 138 KiB |
|
After Width: | Height: | Size: 170 KiB |
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 153 KiB |
|
After Width: | Height: | Size: 162 KiB |
|
After Width: | Height: | Size: 168 KiB |
|
After Width: | Height: | Size: 168 KiB |
|
After Width: | Height: | Size: 129 KiB |
|
After Width: | Height: | Size: 1021 KiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 2.0 MiB |
|
After Width: | Height: | Size: 2.6 MiB |
|
After Width: | Height: | Size: 2.6 MiB |
|
After Width: | Height: | Size: 1.8 MiB |
|
After Width: | Height: | Size: 2.6 MiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 2.6 MiB |
|
After Width: | Height: | Size: 488 KiB |
@@ -28,52 +28,44 @@ Plätze sind begrenzt! Jetzt reservieren unter 🍀WA 077 232 27 70
|
||||
`,
|
||||
},
|
||||
{
|
||||
image: "/images/events/ml0s9u8a-d8eqee.jpeg",
|
||||
title: "St.Patricks Day",
|
||||
date: "2026-03-17",
|
||||
image: "/images/events/mr82c7eh-yp87hy.jpeg",
|
||||
title: "Richie Live",
|
||||
date: "2026-08-27",
|
||||
description: `
|
||||
🍀 It’s Paddy’s Time! Freu dich auf echtes St.-Patrick’s-Day-Feeling mit Live‑Dudelsackmusik, Guinness vom Fass und natürlich grünem Bier. Zieh etwas Grünes an, bring deine Freunde mit und stoß mit uns an – Sláinte! 🍻
|
||||
SOLD OUT! - Richie hat das Image eines Weltenbummlers und Musikkünstlers. In der Ostschweiz ist er bereits bestens bekannt.🍀Warteliste: WA 077 232 27 70
|
||||
`,
|
||||
},
|
||||
{
|
||||
image: "/images/events/mk6wdnz2-rpxzvl.jpeg",
|
||||
title: "Pg Petricca - LIVE",
|
||||
date: "2026-03-20",
|
||||
image: "/images/events/mrnpux59-b3075p.jpeg",
|
||||
title: "Hannes LIVE",
|
||||
date: "2026-09-10",
|
||||
description: `
|
||||
LIVE Musik mit Pg Petricca! - Folk & Blues.
|
||||
Eintritt ist Frei / Hutkollekte
|
||||
Reservation unter 🍀WA 077 232 27 70
|
||||
Er ist zurück!🥰🍀Johannes ist wieder bei uns! Eine weitere unvergessliche Irish-Night!!🍀Sei dabei! Reservationen🍀via WA 077 232 27 70
|
||||
`,
|
||||
},
|
||||
{
|
||||
image: "/images/events/mmnlxydh-924q8d.jpeg",
|
||||
title: "Chris Live",
|
||||
date: "2026-04-16",
|
||||
image: "/images/events/mrngoyyy-49rz7u.jpeg",
|
||||
title: "Danielle&Nina",
|
||||
date: "2026-09-24",
|
||||
description: `
|
||||
Guitar & Songwriter. Geboren in den USA und geprägt von einem Leben voller Bewegung und Musik.
|
||||
🍀WA 077 232 27 70
|
||||
`,
|
||||
},
|
||||
{
|
||||
image: "/images/events/mmnlz7pc-wwdvwe.jpeg",
|
||||
title: "Aushilfe gesucht",
|
||||
date: "2026-03-12",
|
||||
description: `
|
||||
🍀4 Abende im Monat oder nach Absprache🍀Die besten Stammgäste 🍀Gute Entlöhnung 🍀Familiäre Atmosphäre und mehr! WA 077 232 27 70
|
||||
SOLD OUT! - First time on stage – und das direkt im Gallus Pub!🎤✨
|
||||
Danielle & Nina bringen Irish Folk & liebevolle Cover Songs.🍀Warteliste: WA 077 232 27 70
|
||||
`,
|
||||
}
|
||||
];
|
||||
|
||||
const images = [
|
||||
{ src: "/images/gallery/miywxkwh-m4xaww.webp", alt: "miywxkwh-m4xaww.webp" },
|
||||
{ src: "/images/gallery/miyxgbqr-n3zzrg.png", alt: "miyxgbqr-n3zzrg.png" },
|
||||
{ src: "/images/gallery/miyxgfh1-c7zawh.png", alt: "miyxgfh1-c7zawh.png" },
|
||||
{ src: "/images/gallery/miyxgjff-wjtyim.png", alt: "miyxgjff-wjtyim.png" },
|
||||
{ src: "/images/gallery/miyxgn6h-jsaltu.png", alt: "miyxgn6h-jsaltu.png" },
|
||||
{ src: "/images/gallery/mj67l5x3-pdasw8.jpeg", alt: "mj67l5x3-pdasw8.jpeg" },
|
||||
{ src: "/images/gallery/mj67mw2z-3pd81q.jpeg", alt: "mj67mw2z-3pd81q.jpeg" },
|
||||
{ src: "/images/gallery/mj67nwjs-6oaijj.jpeg", alt: "mj67nwjs-6oaijj.jpeg" },
|
||||
{ src: "/images/gallery/mj67ove6-el3pf7.png", alt: "mj67ove6-el3pf7.png" }
|
||||
{ src: "/images/gallery/mndhrrtl-s4o8dn.png", alt: "mndhrrtl-s4o8dn.png" },
|
||||
{ src: "/images/gallery/mndhtjvz-965yra.jpeg", alt: "mndhtjvz-965yra.jpeg" },
|
||||
{ src: "/images/gallery/mndi3625-lnnggc.jpeg", alt: "mndi3625-lnnggc.jpeg" },
|
||||
{ src: "/images/gallery/mndi7upa-qxukqg.jpeg", alt: "mndi7upa-qxukqg.jpeg" },
|
||||
{ src: "/images/gallery/mndi8kzg-oazjp8.jpeg", alt: "mndi8kzg-oazjp8.jpeg" },
|
||||
{ src: "/images/gallery/mndiabuo-m29xj0.jpeg", alt: "mndiabuo-m29xj0.jpeg" },
|
||||
{ src: "/images/gallery/mndicr59-n8suoy.jpeg", alt: "mndicr59-n8suoy.jpeg" },
|
||||
{ src: "/images/gallery/mndieqns-mjs7xe.jpeg", alt: "mndieqns-mjs7xe.jpeg" },
|
||||
{ src: "/images/gallery/mndif8nv-aptjf6.jpeg", alt: "mndif8nv-aptjf6.jpeg" },
|
||||
{ src: "/images/gallery/mndiggta-hnldkv.jpeg", alt: "mndiggta-hnldkv.jpeg" },
|
||||
{ src: "/images/gallery/mndih8lp-woprt4.webp", alt: "mndih8lp-woprt4.webp" }
|
||||
];
|
||||
---
|
||||
|
||||
|
||||