From 6f5021638c82b42f4707c660a4dda1107413f8b4 Mon Sep 17 00:00:00 2001 From: ergosteur <1992147+ergosteur@users.noreply.github.com> Date: Sat, 7 Mar 2026 02:45:17 -0500 Subject: [PATCH] feat: add Dockerfile and GitHub Actions workflow for GHCR deployment --- .dockerignore | 10 ++++++ .github/workflows/docker-publish.yml | 47 ++++++++++++++++++++++++++++ Dockerfile | 38 ++++++++++++++++++++++ package.json | 4 +-- 4 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 .dockerignore create mode 100644 .github/workflows/docker-publish.yml create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..79fa3e3 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,10 @@ +node_modules +dist +.git +.github +_sample-archives +Dockerfile +.dockerignore +README.md +GEMINI.md +metadata.json diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 0000000..6c2e924 --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,47 @@ +name: Docker Build and Publish + +on: + push: + tags: + - 'v*' + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + type=sha + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..916b36a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,38 @@ +# Stage 1: Build +FROM node:20-slim AS build + +WORKDIR /app + +# Install build dependencies +COPY package*.json ./ +RUN npm ci + +# Copy source and build frontend +COPY . . +RUN npm run build + +# Stage 2: Runtime +FROM node:20-slim AS runtime + +# Set production environment +ENV NODE_ENV=production +ENV PORT=3000 +ENV ARCHIVES_DIR=/archives + +WORKDIR /app + +# Install runtime dependencies only +COPY package*.json ./ +RUN npm ci --omit=dev + +# Copy built assets and server +COPY --from=build /app/dist ./dist +COPY --from=build /app/server.ts ./ + +# Ensure archives directory exists +RUN mkdir -p /archives + +EXPOSE 3000 + +# Start server using tsx +CMD ["npx", "tsx", "server.ts"] diff --git a/package.json b/package.json index 1743c65..24d0adc 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "react-example", "private": true, - "version": "0.0.0", + "version": "1.1.0", "type": "module", "scripts": { "dev": "vite --port=3000 --host=0.0.0.0", @@ -26,6 +26,7 @@ "react": "^19.0.0", "react-dom": "^19.0.0", "tailwind-merge": "^3.5.0", + "tsx": "^4.21.0", "vite": "^6.2.0", "xz-decompress": "^0.2.3" }, @@ -34,7 +35,6 @@ "@types/node": "^22.14.0", "autoprefixer": "^10.4.21", "tailwindcss": "^4.1.14", - "tsx": "^4.21.0", "typescript": "~5.8.2", "vite": "^6.2.0", "vite-plugin-pwa": "^1.2.0"