diff --git a/.dockerignore b/.dockerignore index 13b517a5..d6b3b80e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -12,7 +12,6 @@ !**/build.js !next.config.mjs !sentry.*.config.ts -!instrumentation.ts !public/** !src/** !tests/** diff --git a/.github/workflows/nightly-release.yml b/.github/workflows/nightly-release.yml index 71ee4587..f02ab353 100644 --- a/.github/workflows/nightly-release.yml +++ b/.github/workflows/nightly-release.yml @@ -104,3 +104,10 @@ jobs: tag: nightly rm: true files: cli/runtipi-cli-* + + e2e-tests: + needs: [update-release] + uses: './.github/workflows/e2e.yml' + secrets: inherit + with: + version: ${{ needs.create-tag.outputs.tagname }} diff --git a/Dockerfile.dev b/Dockerfile.dev index 1507a4d1..be90508e 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -46,8 +46,6 @@ COPY ./next.config.mjs ./next.config.mjs # Sentry COPY ./sentry.client.config.ts ./sentry.client.config.ts -COPY ./sentry.edge.config.ts ./sentry.edge.config.ts -COPY ./sentry.server.config.ts ./sentry.server.config.ts COPY ./start.dev.sh ./start.sh diff --git a/packages/shared/src/schemas/socket-schemas.ts b/packages/shared/src/schemas/socket-schemas.ts index 7f37b983..34431fba 100644 --- a/packages/shared/src/schemas/socket-schemas.ts +++ b/packages/shared/src/schemas/socket-schemas.ts @@ -27,17 +27,32 @@ export const socketEventSchema = z.union([ error: z.string().optional(), }), }), + z.object({ + type: z.literal('app-logs-init'), + event: z.literal('initLogs'), + data: z.object({ + appId: z.string(), + maxLines: z.number().optional(), + }), + }), z.object({ type: z.literal('app-logs'), - event: z.union([z.literal('newLogs'), z.literal('viewLogs'), z.literal('stopLogs')]), + event: z.union([z.literal('newLogs'), z.literal('stopLogs')]), data: z.object({ appId: z.string(), lines: z.array(z.string()).optional(), }), }), + z.object({ + type: z.literal('runtipi-logs-init'), + event: z.literal('initLogs'), + data: z.object({ + maxLines: z.number().optional(), + }), + }), z.object({ type: z.literal('runtipi-logs'), - event: z.union([z.literal('newLogs'), z.literal('viewLogs'), z.literal('stopLogs')]), + event: z.union([z.literal('newLogs'), z.literal('stopLogs')]), data: z.object({ lines: z.array(z.string()).optional(), }), diff --git a/packages/worker/src/lib/docker/docker-helpers.ts b/packages/worker/src/lib/docker/docker-helpers.ts index e7b1203d..fa2e3a45 100644 --- a/packages/worker/src/lib/docker/docker-helpers.ts +++ b/packages/worker/src/lib/docker/docker-helpers.ts @@ -55,7 +55,7 @@ const getBaseComposeArgsApp = async (appId: string) => { const getBaseComposeArgsTipi = async () => { const args: string[] = [`--env-file ${path.join(DATA_DIR, '.env')}`]; - args.push(`--project-name tipi`); + args.push(`--project-name runtipi`); const composeFile = path.join(DATA_DIR, 'docker-compose.yml'); args.push(`-f ${composeFile}`); @@ -89,20 +89,22 @@ export const compose = async (appId: string, command: string) => { }; export const handleViewRuntipiLogsEvent = async (socket: Socket, event: SocketEvent) => { - const parsedEvent = socketEventSchema.safeParse(event); + const { success, data } = socketEventSchema.safeParse(event); - if (!parsedEvent.success) { + if (!success) { logger.error('Invalid viewLogs event data:', event); return; } - if (parsedEvent.data.type !== 'runtipi-logs' && parsedEvent.data.event !== 'viewLogs') { + if (data.type !== 'runtipi-logs-init') { return; } + const { maxLines } = data.data; + const args = await getBaseComposeArgsTipi(); - args.push('logs --follow -n 25'); + args.push(`logs --follow -n ${maxLines || 25}`); const logsCommand = `docker-compose ${args.join(' ')}`; @@ -114,7 +116,6 @@ export const handleViewRuntipiLogsEvent = async (socket: Socket, event: SocketEv socket.on('runtipi-logs', (data) => { if (data.event === 'stopLogs') { - console.log('Stopping logs'); logs.kill('SIGINT'); } }); @@ -146,18 +147,14 @@ export const handleViewAppLogsEvent = async (socket: Socket, event: SocketEvent) return; } - if (parsedEvent.data.type !== 'app-logs') { + if (parsedEvent.data.type !== 'app-logs-init') { return; } - if (parsedEvent.data.event !== 'viewLogs') { - return; - } - - const { appId } = parsedEvent.data.data; + const { appId, maxLines } = parsedEvent.data.data; const args = await getBaseComposeArgsApp(appId); - args.push('logs --follow -n 25'); + args.push(`logs --follow -n ${maxLines || 25}`); const logsCommand = `docker-compose ${args.join(' ')}`; diff --git a/packages/worker/src/lib/socket/SocketManager.ts b/packages/worker/src/lib/socket/SocketManager.ts index 2dc51132..3ec3b5f3 100644 --- a/packages/worker/src/lib/socket/SocketManager.ts +++ b/packages/worker/src/lib/socket/SocketManager.ts @@ -10,8 +10,8 @@ class SocketManager { const io = new Server(5001, { cors: { origin: '*' }, path: '/worker/socket.io' }); io.on('connection', async (socket) => { - socket.on('app-logs', (event) => handleViewAppLogsEvent(socket, event)); - socket.on('runtipi-logs', (event) => handleViewRuntipiLogsEvent(socket, event)); + socket.on('app-logs-init', (event) => handleViewAppLogsEvent(socket, event)); + socket.on('runtipi-logs-init', (event) => handleViewRuntipiLogsEvent(socket, event)); socket.on('disconnect', () => {}); }); diff --git a/src/app/(dashboard)/app-store/[id]/components/AppDetailsTabs/AppLogs.tsx b/src/app/(dashboard)/app-store/[id]/components/AppDetailsTabs/AppLogs.tsx index 36a0391e..b4bb445c 100644 --- a/src/app/(dashboard)/app-store/[id]/components/AppDetailsTabs/AppLogs.tsx +++ b/src/app/(dashboard)/app-store/[id]/components/AppDetailsTabs/AppLogs.tsx @@ -12,7 +12,7 @@ export const AppLogs = ({ appId }: { appId: string }) => { useSocket({ selector: { type: 'app-logs', event: 'newLogs', data: { property: 'appId', value: appId } }, onCleanup: () => setLogs([]), - emitOnConnect: { type: 'app-logs', event: 'viewLogs', data: { appId } }, + emitOnConnect: { type: 'app-logs-init', event: 'initLogs', data: { appId, maxLines } }, emitOnDisconnect: { type: 'app-logs', event: 'stopLogs', data: { appId } }, onEvent: (_, data) => { setLogs((prevLogs) => { diff --git a/src/app/(dashboard)/settings/components/LogsContainer/LogsContainer.tsx b/src/app/(dashboard)/settings/components/LogsContainer/LogsContainer.tsx index fd20c932..f2e76f98 100644 --- a/src/app/(dashboard)/settings/components/LogsContainer/LogsContainer.tsx +++ b/src/app/(dashboard)/settings/components/LogsContainer/LogsContainer.tsx @@ -12,7 +12,7 @@ export const LogsContainer = () => { useSocket({ selector: { type: 'runtipi-logs', event: 'newLogs' }, onCleanup: () => setLogs([]), - emitOnConnect: { type: 'runtipi-logs', event: 'viewLogs', data: {} }, + emitOnConnect: { type: 'runtipi-logs-init', event: 'initLogs', data: { maxLines } }, emitOnDisconnect: { type: 'runtipi-logs', event: 'stopLogs', data: {} }, onEvent: (_, data) => { setLogs((prevLogs) => { diff --git a/src/lib/socket/useSocket.test.ts b/src/lib/socket/useSocket.test.ts index d8c29d55..008a8e51 100644 --- a/src/lib/socket/useSocket.test.ts +++ b/src/lib/socket/useSocket.test.ts @@ -37,7 +37,7 @@ describe('useSocket', () => { }); it('should emit on connect if emitOnConnect is provided', () => { - const emitOnConnect = { type: 'runtipi-logs', event: 'viewLogs', data: {} } as const; + const emitOnConnect = { type: 'runtipi-logs', event: 'stopLogs', data: {} } as const; renderHook(() => useSocket({ selector: { type: 'runtipi-logs' }, emitOnConnect })); expect(mockSocket.on).toHaveBeenCalledWith('connect', expect.any(Function));