From dfd66cde0b6692edb5abafc131209b3e4f35b2ac Mon Sep 17 00:00:00 2001 From: David Gwilliam Date: Tue, 31 Mar 2026 22:11:20 -0700 Subject: [PATCH 01/12] ci: add CI image builder workflow and Dockerfile --- .gitea/workflows/ci-image-builder.yml | 82 +++++++++++++++++++++++++++ Dockerfile.ci | 46 +++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 .gitea/workflows/ci-image-builder.yml create mode 100644 Dockerfile.ci diff --git a/.gitea/workflows/ci-image-builder.yml b/.gitea/workflows/ci-image-builder.yml new file mode 100644 index 0000000..05f057b --- /dev/null +++ b/.gitea/workflows/ci-image-builder.yml @@ -0,0 +1,82 @@ +# CI Image Builder Workflow +# Automatically builds and pushes CI images when dependencies change +# Uses GitHub Container Registry (GHCR) or any container registry + +name: CI Image Builder + +on: + push: + branches: + - main + paths: + - 'package.json' + - 'package-lock.json' + - 'Dockerfile.ci' + - '.gitea/workflows/ci-image-builder.yml' + workflow_dispatch: + inputs: + force_rebuild: + description: 'Force rebuild even if no changes detected' + required: false + default: 'false' + type: boolean + +env: + # Use GHCR or your own registry + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }}/ci-runner + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=sha,prefix={{branch}}- + type=ref,event=branch + type=ref,event=pr + type=raw,value=latest,enable={{is_default_branch}} + + - name: Build and push CI image + uses: docker/build-push-action@v5 + with: + context: . + file: Dockerfile.ci + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Update workflow documentation + run: | + echo "CI Image built and pushed successfully!" + echo "" + echo "Available tags:" + echo " - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" + echo " - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}" + echo "" + echo "To use in workflows:" + echo " container:" + echo " image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" diff --git a/Dockerfile.ci b/Dockerfile.ci new file mode 100644 index 0000000..36429f2 --- /dev/null +++ b/Dockerfile.ci @@ -0,0 +1,46 @@ +# CI Runner Image for EuchreCamp +# Pre-installed with all dependencies to speed up CI runs +# This image is rebuilt automatically when package.json changes + +FROM node:20-alpine + +# Install system dependencies needed for various tasks +RUN apk add --no-cache \ + bash \ + git \ + curl \ + python3 \ + make \ + g++ \ + && rm -rf /var/cache/apk/* + +# Set working directory +WORKDIR /app + +# Copy package files first (for better caching) +COPY package*.json ./ + +# Install ALL dependencies including dev dependencies +# This is done at image build time, not at CI runtime +RUN npm ci + +# Copy Prisma schema (needed for Prisma client generation) +COPY prisma/schema.prisma ./prisma/ + +# Generate Prisma client +RUN npx prisma generate + +# Copy the rest of the application +COPY . . + +# Set environment variables for CI environment +ENV NODE_ENV=production +ENV DATABASE_PROVIDER=sqlite +ENV DATABASE_URL=file:./prisma/ci.db +ENV BETTER_AUTH_SECRET=test-secret-key-for-ci-only + +# Verify installations +RUN node --version && npm --version && git --version && npx prisma --version + +# Default command +CMD ["/bin/sh"] -- 2.52.0 From b686c3673e28d6be9a8627d30f407f37f3c408be Mon Sep 17 00:00:00 2001 From: David Gwilliam Date: Tue, 31 Mar 2026 22:12:21 -0700 Subject: [PATCH 02/12] chore: add script for building CI image locally --- scripts/build-ci-image.sh | 44 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100755 scripts/build-ci-image.sh diff --git a/scripts/build-ci-image.sh b/scripts/build-ci-image.sh new file mode 100755 index 0000000..8353fb8 --- /dev/null +++ b/scripts/build-ci-image.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# Build and test the CI runner image locally + +set -e + +IMAGE_NAME="euchre-camp-ci" +TAG="${1:-latest}" + +echo "Building CI runner image..." +echo "Image: ${IMAGE_NAME}:${TAG}" +echo "" + +# Build the image +docker build \ + -f Dockerfile.ci \ + -t ${IMAGE_NAME}:${TAG} \ + . + +echo "" +echo "✅ Image built successfully!" +echo "" + +# Test the image +echo "Testing CI image..." +docker run --rm ${IMAGE_NAME}:${TAG} sh -c " + echo 'Node.js version:' && node --version + echo 'npm version:' && npm --version + echo 'Git version:' && git --version + echo 'Prisma version:' && npx prisma --version + echo '' + echo 'Installed packages (top 10):' + npm list --depth=0 | head -10 +" + +echo "" +echo "✅ CI image is ready to use!" +echo "" +echo "To use in GitHub Actions/Gitea Actions:" +echo " container:" +echo " image: ${IMAGE_NAME}:${TAG}" +echo "" +echo "To push to registry:" +echo " docker tag ${IMAGE_NAME}:${TAG} registry.example.com/${IMAGE_NAME}:${TAG}" +echo " docker push registry.example.com/${IMAGE_NAME}:${TAG}" -- 2.52.0 From 941d857feb10df754f61e2d170fad84abdb8b3c0 Mon Sep 17 00:00:00 2001 From: David Gwilliam Date: Tue, 31 Mar 2026 22:12:42 -0700 Subject: [PATCH 03/12] docs: update documentation with CI image info --- AGENTS.md | 20 ++++++++++++++++++++ README.md | 28 ++++++++++++++++++++++++++++ justfile | 10 ++++++++++ 3 files changed, 58 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 464ab1c..cc1bd0c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -127,6 +127,26 @@ npm run db:setup-postgres DATABASE_PROVIDER=sqlite DATABASE_URL=file:./prisma/ci.db npm run test:acceptance ``` +### CI Runner Image + +To speed up CI runs, the project uses a pre-built CI runner image with all dependencies pre-installed. + +**Building the CI image locally:** +```bash +./scripts/build-ci-image.sh [tag] +``` + +**Using the CI image:** +- Workflows automatically use `ghcr.io//ci-runner:latest` when available +- Falls back to `node:20-alpine` if image is not found +- Image is automatically rebuilt when `package.json` changes + +**CI Image contains:** +- Node.js 20 Alpine +- All npm dependencies pre-installed +- Prisma client pre-generated +- System tools (bash, git, python, make, g++) + ### CI/CD Pipeline The project uses Gitea Actions for continuous integration: diff --git a/README.md b/README.md index 2dd2f42..43809f9 100644 --- a/README.md +++ b/README.md @@ -373,6 +373,31 @@ The application uses Gitea Actions for continuous integration and deployment: - Docker image building and testing - Registry push and deployment +4. **CI Image Builder** (`.gitea/workflows/ci-image-builder.yml`): Runs when dependencies change + - Automatically builds CI runner image with all dependencies pre-installed + - Triggered by changes to `package.json`, `package-lock.json`, or `Dockerfile.ci` + +### CI Runner Image + +To avoid installing dependencies on every workflow run, we use a pre-built CI runner image: + +**Dockerfile.ci** - Contains: +- Node.js 20 Alpine +- All npm dependencies pre-installed +- Prisma client pre-generated +- System tools (bash, git, python, make, g++) + +**Automatic Rebuilding:** +- The CI image is automatically rebuilt when `package.json` or `package-lock.json` changes +- Images are tagged with commit SHA for traceability +- Falls back to `node:20-alpine` if custom image is not available + +**Manual Build:** +```bash +docker build -f Dockerfile.ci -t euchre-camp-ci:latest . +docker run --rm euchre-camp-ci:latest node --version +``` + ### Database Strategy for CI - **CI Tests**: SQLite database (fast, no server required) - **Production**: PostgreSQL (production-like environment) @@ -385,6 +410,9 @@ npm run test:run # Run acceptance tests with SQLite DATABASE_PROVIDER=sqlite DATABASE_URL=file:./prisma/ci.db npm run test:acceptance + +# Run tests in CI container (if built) +docker run --rm -v $(pwd):/app -w /app euchre-camp-ci:latest npm run test:run ``` ## Docker Deployment diff --git a/justfile b/justfile index eb24680..b25676e 100644 --- a/justfile +++ b/justfile @@ -173,6 +173,16 @@ pr-validate: lint typecheck test-unit test-acceptance-sqlite ci-postgres: lint typecheck test-unit test-acceptance-postgres docker-build @echo "CI Pipeline with PostgreSQL completed successfully!" +# --- CI Image --- + +# Build CI runner image locally +ci-build: + @./scripts/build-ci-image.sh + +# Build CI runner image with custom tag +ci-build-tag TAG: + @./scripts/build-ci-image.sh {{TAG}} + # --- Utilities --- # Show help information -- 2.52.0 From 3983049d2c4d2161876c5938e6e14a68356f2a52 Mon Sep 17 00:00:00 2001 From: David Gwilliam Date: Tue, 31 Mar 2026 22:17:47 -0700 Subject: [PATCH 04/12] fix: use correct docker registry and image name --- .gitea/workflows/ci-image-builder.yml | 82 +++++++++++++-------------- .gitea/workflows/pr.yml | 21 +------ .gitea/workflows/test.yml | 9 +-- scripts/build-ci-image.sh | 8 +-- 4 files changed, 47 insertions(+), 73 deletions(-) diff --git a/.gitea/workflows/ci-image-builder.yml b/.gitea/workflows/ci-image-builder.yml index 05f057b..80f27c4 100644 --- a/.gitea/workflows/ci-image-builder.yml +++ b/.gitea/workflows/ci-image-builder.yml @@ -22,16 +22,15 @@ on: type: boolean env: - # Use GHCR or your own registry - REGISTRY: ghcr.io - IMAGE_NAME: ${{ github.repository }}/ci-runner + # Use your existing Docker registry + REGISTRY: docker.notsosm.art + IMAGE_NAME: euchre-camp-ci-runner jobs: - build-and-push: + build-ci-image: runs-on: ubuntu-latest - permissions: - contents: read - packages: write + # Skip if this is an auto-generated version bump commit + if: "!contains(github.event.head_commit.message, 'chore: bump version')" steps: - name: Checkout code @@ -40,42 +39,41 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Log in to Container Registry - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract metadata - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - tags: | - type=sha,prefix={{branch}}- - type=ref,event=branch - type=ref,event=pr - type=raw,value=latest,enable={{is_default_branch}} - - - name: Build and push CI image - uses: docker/build-push-action@v5 - with: - context: . - file: Dockerfile.ci - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max - - - name: Update workflow documentation + - name: Build CI image run: | - echo "CI Image built and pushed successfully!" - echo "" - echo "Available tags:" - echo " - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" - echo " - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}" + docker build \ + -f Dockerfile.ci \ + -t ${{ env.IMAGE_NAME }}:latest \ + -t ${{ env.IMAGE_NAME }}:$(git rev-parse --short HEAD) \ + . + + - name: Test CI image + run: | + docker run --rm \ + ${{ env.IMAGE_NAME }}:latest \ + sh -c "node --version && npm --version && npx prisma --version" + + - name: Push to registry + run: | + echo "Pushing to ${{ env.REGISTRY }}..." + # Check if we can authenticate to the registry using DOCKER_LOGIN and DOCKER_PASSWORD secrets + if [ -n "${{ secrets.DOCKER_LOGIN }}" ] && [ -n "${{ secrets.DOCKER_PASSWORD }}" ]; then + if docker login ${{ env.REGISTRY }} -u ${{ secrets.DOCKER_LOGIN }} -p ${{ secrets.DOCKER_PASSWORD }} 2>/dev/null; then + docker tag ${{ env.IMAGE_NAME }}:latest ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + echo "Successfully pushed CI image to ${{ env.REGISTRY }}" + else + echo "Warning: Docker login failed with provided credentials" + echo "CI image built locally but not pushed to registry" + fi + else + echo "Warning: DOCKER_LOGIN or DOCKER_PASSWORD secrets not configured" + echo "CI image built locally but not pushed to registry" + fi + + - name: Show usage instructions + run: | + echo "CI Image built successfully!" echo "" echo "To use in workflows:" echo " container:" diff --git a/.gitea/workflows/pr.yml b/.gitea/workflows/pr.yml index 9a2660d..2b7d55a 100644 --- a/.gitea/workflows/pr.yml +++ b/.gitea/workflows/pr.yml @@ -9,20 +9,13 @@ jobs: unit-tests: runs-on: ubuntu-latest container: - image: node:20-alpine + image: docker.notsosm.art/euchre-camp-ci-runner:latest options: --user root steps: - - name: Install system dependencies - run: | - apk add --no-cache bash git - - name: Checkout code uses: actions/checkout@v4 - - name: Install dependencies - run: npm ci - - name: Run unit tests run: npm run test:run @@ -30,7 +23,7 @@ jobs: runs-on: ubuntu-latest needs: unit-tests container: - image: node:20-alpine + image: docker.notsosm.art/euchre-camp-ci-runner:latest options: --user root env: DATABASE_PROVIDER: sqlite @@ -38,19 +31,9 @@ jobs: BETTER_AUTH_SECRET: test-secret-key-for-ci-only steps: - - name: Install system dependencies - run: | - apk add --no-cache bash git - - name: Checkout code uses: actions/checkout@v4 - - name: Install dependencies - run: npm ci - - - name: Generate Prisma client - run: npx prisma generate - - name: Setup SQLite database run: | # Create SQLite database file diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index bcf53e3..ebf8657 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -9,21 +9,14 @@ jobs: unit-tests: runs-on: ubuntu-latest container: - image: node:20-alpine + image: docker.notsosm.art/euchre-camp-ci-runner:latest options: --user root # Skip if this is an auto-generated version bump commit (handled by release workflow) if: "!contains(github.event.head_commit.message, 'chore: bump version')" steps: - - name: Install system dependencies - run: | - apk add --no-cache bash git - - name: Checkout code uses: actions/checkout@v4 - - name: Install dependencies - run: npm ci - - name: Run unit tests run: npm run test:run diff --git a/scripts/build-ci-image.sh b/scripts/build-ci-image.sh index 8353fb8..403e356 100755 --- a/scripts/build-ci-image.sh +++ b/scripts/build-ci-image.sh @@ -3,7 +3,7 @@ set -e -IMAGE_NAME="euchre-camp-ci" +IMAGE_NAME="euchre-camp-ci-runner" TAG="${1:-latest}" echo "Building CI runner image..." @@ -37,8 +37,8 @@ echo "✅ CI image is ready to use!" echo "" echo "To use in GitHub Actions/Gitea Actions:" echo " container:" -echo " image: ${IMAGE_NAME}:${TAG}" +echo " image: docker.notsosm.art/${IMAGE_NAME}:${TAG}" echo "" echo "To push to registry:" -echo " docker tag ${IMAGE_NAME}:${TAG} registry.example.com/${IMAGE_NAME}:${TAG}" -echo " docker push registry.example.com/${IMAGE_NAME}:${TAG}" +echo " docker tag ${IMAGE_NAME}:${TAG} docker.notsosm.art/${IMAGE_NAME}:${TAG}" +echo " docker push docker.notsosm.art/${IMAGE_NAME}:${TAG}" -- 2.52.0 From 4c2687498fcd31496d9b19f8d9525d8f5b0ab6f9 Mon Sep 17 00:00:00 2001 From: David Gwilliam Date: Tue, 31 Mar 2026 22:41:11 -0700 Subject: [PATCH 05/12] fix: update workflows to checkout in /app directory --- .gitea/workflows/pr.yml | 4 ++++ .gitea/workflows/test.yml | 2 ++ 2 files changed, 6 insertions(+) diff --git a/.gitea/workflows/pr.yml b/.gitea/workflows/pr.yml index 2b7d55a..107be03 100644 --- a/.gitea/workflows/pr.yml +++ b/.gitea/workflows/pr.yml @@ -15,6 +15,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + with: + path: /app - name: Run unit tests run: npm run test:run @@ -33,6 +35,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + with: + path: /app - name: Setup SQLite database run: | diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index ebf8657..7f5aebd 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -17,6 +17,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + with: + path: /app - name: Run unit tests run: npm run test:run -- 2.52.0 From c611c68822ad994ae093b624a92d9414c972ad2b Mon Sep 17 00:00:00 2001 From: David Gwilliam Date: Tue, 31 Mar 2026 22:53:40 -0700 Subject: [PATCH 06/12] fix: use symlinks to link node_modules from container --- .gitea/workflows/pr.yml | 14 ++++++++++---- .gitea/workflows/test.yml | 7 +++++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/.gitea/workflows/pr.yml b/.gitea/workflows/pr.yml index 107be03..3d4dd35 100644 --- a/.gitea/workflows/pr.yml +++ b/.gitea/workflows/pr.yml @@ -15,8 +15,11 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 - with: - path: /app + + - name: Link node_modules from container + run: | + # Create symlink to pre-installed node_modules in container + ln -sf /app/node_modules ./node_modules - name: Run unit tests run: npm run test:run @@ -35,8 +38,11 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 - with: - path: /app + + - name: Link node_modules from container + run: | + # Create symlink to pre-installed node_modules in container + ln -sf /app/node_modules ./node_modules - name: Setup SQLite database run: | diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index 7f5aebd..b5cf26a 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -17,8 +17,11 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 - with: - path: /app + + - name: Link node_modules from container + run: | + # Create symlink to pre-installed node_modules in container + ln -sf /app/node_modules ./node_modules - name: Run unit tests run: npm run test:run -- 2.52.0 From ba180ae6e1f494bf000e3a914de7c4273c12f30c Mon Sep 17 00:00:00 2001 From: David Gwilliam Date: Tue, 31 Mar 2026 22:57:10 -0700 Subject: [PATCH 07/12] fix: move node_modules to /workspace in CI image and update symlink --- .gitea/workflows/pr.yml | 6 ++++-- .gitea/workflows/test.yml | 2 +- Dockerfile.ci | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.gitea/workflows/pr.yml b/.gitea/workflows/pr.yml index 3d4dd35..85afec2 100644 --- a/.gitea/workflows/pr.yml +++ b/.gitea/workflows/pr.yml @@ -19,7 +19,9 @@ jobs: - name: Link node_modules from container run: | # Create symlink to pre-installed node_modules in container - ln -sf /app/node_modules ./node_modules + # Container has node_modules at /workspace/node_modules + # Gitea Actions checks out at /workspace/david/euchre_camp + ln -sf /workspace/node_modules ./node_modules - name: Run unit tests run: npm run test:run @@ -42,7 +44,7 @@ jobs: - name: Link node_modules from container run: | # Create symlink to pre-installed node_modules in container - ln -sf /app/node_modules ./node_modules + ln -sf /workspace/node_modules ./node_modules - name: Setup SQLite database run: | diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index b5cf26a..ed4ab16 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -21,7 +21,7 @@ jobs: - name: Link node_modules from container run: | # Create symlink to pre-installed node_modules in container - ln -sf /app/node_modules ./node_modules + ln -sf /workspace/node_modules ./node_modules - name: Run unit tests run: npm run test:run diff --git a/Dockerfile.ci b/Dockerfile.ci index 36429f2..6e0908e 100644 --- a/Dockerfile.ci +++ b/Dockerfile.ci @@ -15,7 +15,7 @@ RUN apk add --no-cache \ && rm -rf /var/cache/apk/* # Set working directory -WORKDIR /app +WORKDIR /workspace # Copy package files first (for better caching) COPY package*.json ./ -- 2.52.0 From 81c93bafc111e2650d0294aae8f1de55aa6917d0 Mon Sep 17 00:00:00 2001 From: David Gwilliam Date: Tue, 31 Mar 2026 23:01:36 -0700 Subject: [PATCH 08/12] fix: use NODE_PATH env var instead of symlinks --- .gitea/workflows/pr.yml | 15 +++------------ .gitea/workflows/test.yml | 7 ++----- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/.gitea/workflows/pr.yml b/.gitea/workflows/pr.yml index 85afec2..0edc9a2 100644 --- a/.gitea/workflows/pr.yml +++ b/.gitea/workflows/pr.yml @@ -11,18 +11,13 @@ jobs: container: image: docker.notsosm.art/euchre-camp-ci-runner:latest options: --user root + env: + NODE_PATH: /workspace/node_modules steps: - name: Checkout code uses: actions/checkout@v4 - - name: Link node_modules from container - run: | - # Create symlink to pre-installed node_modules in container - # Container has node_modules at /workspace/node_modules - # Gitea Actions checks out at /workspace/david/euchre_camp - ln -sf /workspace/node_modules ./node_modules - - name: Run unit tests run: npm run test:run @@ -36,16 +31,12 @@ jobs: DATABASE_PROVIDER: sqlite DATABASE_URL: file:./prisma/ci.db BETTER_AUTH_SECRET: test-secret-key-for-ci-only + NODE_PATH: /workspace/node_modules steps: - name: Checkout code uses: actions/checkout@v4 - - name: Link node_modules from container - run: | - # Create symlink to pre-installed node_modules in container - ln -sf /workspace/node_modules ./node_modules - - name: Setup SQLite database run: | # Create SQLite database file diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index ed4ab16..19f6be1 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -13,15 +13,12 @@ jobs: options: --user root # Skip if this is an auto-generated version bump commit (handled by release workflow) if: "!contains(github.event.head_commit.message, 'chore: bump version')" + env: + NODE_PATH: /workspace/node_modules steps: - name: Checkout code uses: actions/checkout@v4 - - name: Link node_modules from container - run: | - # Create symlink to pre-installed node_modules in container - ln -sf /workspace/node_modules ./node_modules - - name: Run unit tests run: npm run test:run -- 2.52.0 From b445d9044a1439ec0e642789445156fb64194a9e Mon Sep 17 00:00:00 2001 From: David Gwilliam Date: Tue, 31 Mar 2026 23:01:48 -0700 Subject: [PATCH 09/12] chore: revert Dockerfile back to /app directory --- Dockerfile.ci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.ci b/Dockerfile.ci index 6e0908e..36429f2 100644 --- a/Dockerfile.ci +++ b/Dockerfile.ci @@ -15,7 +15,7 @@ RUN apk add --no-cache \ && rm -rf /var/cache/apk/* # Set working directory -WORKDIR /workspace +WORKDIR /app # Copy package files first (for better caching) COPY package*.json ./ -- 2.52.0 From 4116884f9f6def9889078d4b329c3ffe5adbc534 Mon Sep 17 00:00:00 2001 From: David Gwilliam Date: Tue, 31 Mar 2026 23:02:56 -0700 Subject: [PATCH 10/12] fix: add /app/node_modules to PATH and NODE_PATH --- .gitea/workflows/pr.yml | 6 ++++-- .gitea/workflows/test.yml | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/pr.yml b/.gitea/workflows/pr.yml index 0edc9a2..310f72a 100644 --- a/.gitea/workflows/pr.yml +++ b/.gitea/workflows/pr.yml @@ -12,7 +12,8 @@ jobs: image: docker.notsosm.art/euchre-camp-ci-runner:latest options: --user root env: - NODE_PATH: /workspace/node_modules + NODE_PATH: /app/node_modules + PATH: /app/node_modules/.bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin steps: - name: Checkout code @@ -31,7 +32,8 @@ jobs: DATABASE_PROVIDER: sqlite DATABASE_URL: file:./prisma/ci.db BETTER_AUTH_SECRET: test-secret-key-for-ci-only - NODE_PATH: /workspace/node_modules + NODE_PATH: /app/node_modules + PATH: /app/node_modules/.bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin steps: - name: Checkout code diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index 19f6be1..01aa945 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -14,7 +14,8 @@ jobs: # Skip if this is an auto-generated version bump commit (handled by release workflow) if: "!contains(github.event.head_commit.message, 'chore: bump version')" env: - NODE_PATH: /workspace/node_modules + NODE_PATH: /app/node_modules + PATH: /app/node_modules/.bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin steps: - name: Checkout code -- 2.52.0 From 397594a9df258dae7a137686126f99c4d1ee66c5 Mon Sep 17 00:00:00 2001 From: David Gwilliam Date: Tue, 31 Mar 2026 23:04:22 -0700 Subject: [PATCH 11/12] fix: symlink from /app/node_modules to workspace --- .gitea/workflows/pr.yml | 16 ++++++++++++---- .gitea/workflows/test.yml | 8 ++++++-- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/.gitea/workflows/pr.yml b/.gitea/workflows/pr.yml index 310f72a..f056317 100644 --- a/.gitea/workflows/pr.yml +++ b/.gitea/workflows/pr.yml @@ -12,13 +12,17 @@ jobs: image: docker.notsosm.art/euchre-camp-ci-runner:latest options: --user root env: - NODE_PATH: /app/node_modules - PATH: /app/node_modules/.bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + NODE_PATH: /workspace/david/euchre_camp/node_modules steps: - name: Checkout code uses: actions/checkout@v4 + - name: Link node_modules from container + run: | + # Create symlink from container's node_modules to workspace + ln -sf /app/node_modules /workspace/david/euchre_camp/node_modules + - name: Run unit tests run: npm run test:run @@ -32,13 +36,17 @@ jobs: DATABASE_PROVIDER: sqlite DATABASE_URL: file:./prisma/ci.db BETTER_AUTH_SECRET: test-secret-key-for-ci-only - NODE_PATH: /app/node_modules - PATH: /app/node_modules/.bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + NODE_PATH: /workspace/david/euchre_camp/node_modules steps: - name: Checkout code uses: actions/checkout@v4 + - name: Link node_modules from container + run: | + # Create symlink from container's node_modules to workspace + ln -sf /app/node_modules /workspace/david/euchre_camp/node_modules + - name: Setup SQLite database run: | # Create SQLite database file diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index 01aa945..1537d15 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -14,12 +14,16 @@ jobs: # Skip if this is an auto-generated version bump commit (handled by release workflow) if: "!contains(github.event.head_commit.message, 'chore: bump version')" env: - NODE_PATH: /app/node_modules - PATH: /app/node_modules/.bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + NODE_PATH: /workspace/david/euchre_camp/node_modules steps: - name: Checkout code uses: actions/checkout@v4 + - name: Link node_modules from container + run: | + # Create symlink from container's node_modules to workspace + ln -sf /app/node_modules /workspace/david/euchre_camp/node_modules + - name: Run unit tests run: npm run test:run -- 2.52.0 From d24e810ad164005e9b2c19424b31cb247bb996e0 Mon Sep 17 00:00:00 2001 From: David Gwilliam Date: Tue, 31 Mar 2026 23:10:50 -0700 Subject: [PATCH 12/12] refactor: revert CI image approach and use standard npm ci in workflows The CI image approach with pre-installed dependencies doesn't work with Gitea Actions due to workspace mounting issues. When Gitea Actions runs a container job, it mounts the workspace at a specific path (e.g., /workspace/david/euchre_camp), which hides the container's /app directory where dependencies were installed. Changes: - Reverted pr.yml unit-tests to use node:20-alpine with npm ci - Updated pr.yml acceptance-tests to use mcr.microsoft.com/playwright image with npm ci - Updated test.yml to use node:20-alpine with npm ci - Removed ci-image-builder.yml workflow - Removed Dockerfile.ci and build-ci-image.sh - Updated AGENTS.md and README.md to document the deprecation - Updated justfile to remove CI image commands The standard approach of running npm ci in each workflow is the recommended approach for Gitea Actions. --- .gitea/workflows/ci-image-builder.yml | 80 --------------------------- .gitea/workflows/pr.yml | 29 +++++----- .gitea/workflows/test.yml | 10 +--- AGENTS.md | 31 ++++++----- Dockerfile.ci | 46 --------------- README.md | 41 +++++--------- justfile | 12 +--- scripts/build-ci-image.sh | 44 --------------- 8 files changed, 53 insertions(+), 240 deletions(-) delete mode 100644 .gitea/workflows/ci-image-builder.yml delete mode 100644 Dockerfile.ci delete mode 100755 scripts/build-ci-image.sh diff --git a/.gitea/workflows/ci-image-builder.yml b/.gitea/workflows/ci-image-builder.yml deleted file mode 100644 index 80f27c4..0000000 --- a/.gitea/workflows/ci-image-builder.yml +++ /dev/null @@ -1,80 +0,0 @@ -# CI Image Builder Workflow -# Automatically builds and pushes CI images when dependencies change -# Uses GitHub Container Registry (GHCR) or any container registry - -name: CI Image Builder - -on: - push: - branches: - - main - paths: - - 'package.json' - - 'package-lock.json' - - 'Dockerfile.ci' - - '.gitea/workflows/ci-image-builder.yml' - workflow_dispatch: - inputs: - force_rebuild: - description: 'Force rebuild even if no changes detected' - required: false - default: 'false' - type: boolean - -env: - # Use your existing Docker registry - REGISTRY: docker.notsosm.art - IMAGE_NAME: euchre-camp-ci-runner - -jobs: - build-ci-image: - runs-on: ubuntu-latest - # Skip if this is an auto-generated version bump commit - if: "!contains(github.event.head_commit.message, 'chore: bump version')" - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Build CI image - run: | - docker build \ - -f Dockerfile.ci \ - -t ${{ env.IMAGE_NAME }}:latest \ - -t ${{ env.IMAGE_NAME }}:$(git rev-parse --short HEAD) \ - . - - - name: Test CI image - run: | - docker run --rm \ - ${{ env.IMAGE_NAME }}:latest \ - sh -c "node --version && npm --version && npx prisma --version" - - - name: Push to registry - run: | - echo "Pushing to ${{ env.REGISTRY }}..." - # Check if we can authenticate to the registry using DOCKER_LOGIN and DOCKER_PASSWORD secrets - if [ -n "${{ secrets.DOCKER_LOGIN }}" ] && [ -n "${{ secrets.DOCKER_PASSWORD }}" ]; then - if docker login ${{ env.REGISTRY }} -u ${{ secrets.DOCKER_LOGIN }} -p ${{ secrets.DOCKER_PASSWORD }} 2>/dev/null; then - docker tag ${{ env.IMAGE_NAME }}:latest ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest - docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest - echo "Successfully pushed CI image to ${{ env.REGISTRY }}" - else - echo "Warning: Docker login failed with provided credentials" - echo "CI image built locally but not pushed to registry" - fi - else - echo "Warning: DOCKER_LOGIN or DOCKER_PASSWORD secrets not configured" - echo "CI image built locally but not pushed to registry" - fi - - - name: Show usage instructions - run: | - echo "CI Image built successfully!" - echo "" - echo "To use in workflows:" - echo " container:" - echo " image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" diff --git a/.gitea/workflows/pr.yml b/.gitea/workflows/pr.yml index f056317..4894686 100644 --- a/.gitea/workflows/pr.yml +++ b/.gitea/workflows/pr.yml @@ -9,19 +9,15 @@ jobs: unit-tests: runs-on: ubuntu-latest container: - image: docker.notsosm.art/euchre-camp-ci-runner:latest + image: node:20-alpine options: --user root - env: - NODE_PATH: /workspace/david/euchre_camp/node_modules steps: - name: Checkout code uses: actions/checkout@v4 - - name: Link node_modules from container - run: | - # Create symlink from container's node_modules to workspace - ln -sf /app/node_modules /workspace/david/euchre_camp/node_modules + - name: Install dependencies + run: npm ci - name: Run unit tests run: npm run test:run @@ -30,22 +26,29 @@ jobs: runs-on: ubuntu-latest needs: unit-tests container: - image: docker.notsosm.art/euchre-camp-ci-runner:latest + image: mcr.microsoft.com/playwright:v1.58.0-jammy options: --user root env: DATABASE_PROVIDER: sqlite DATABASE_URL: file:./prisma/ci.db BETTER_AUTH_SECRET: test-secret-key-for-ci-only - NODE_PATH: /workspace/david/euchre_camp/node_modules steps: - name: Checkout code uses: actions/checkout@v4 - - name: Link node_modules from container - run: | - # Create symlink from container's node_modules to workspace - ln -sf /app/node_modules /workspace/david/euchre_camp/node_modules + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install dependencies + run: npm ci + + - name: Generate Prisma client + run: npx prisma generate + env: + DATABASE_URL: postgresql://user:pass@localhost:5432/dummy - name: Setup SQLite database run: | diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index 1537d15..2a3e21e 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -9,21 +9,17 @@ jobs: unit-tests: runs-on: ubuntu-latest container: - image: docker.notsosm.art/euchre-camp-ci-runner:latest + image: node:20-alpine options: --user root # Skip if this is an auto-generated version bump commit (handled by release workflow) if: "!contains(github.event.head_commit.message, 'chore: bump version')" - env: - NODE_PATH: /workspace/david/euchre_camp/node_modules steps: - name: Checkout code uses: actions/checkout@v4 - - name: Link node_modules from container - run: | - # Create symlink from container's node_modules to workspace - ln -sf /app/node_modules /workspace/david/euchre_camp/node_modules + - name: Install dependencies + run: npm ci - name: Run unit tests run: npm run test:run diff --git a/AGENTS.md b/AGENTS.md index cc1bd0c..9fad454 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -129,23 +129,26 @@ DATABASE_PROVIDER=sqlite DATABASE_URL=file:./prisma/ci.db npm run test:acceptanc ### CI Runner Image -To speed up CI runs, the project uses a pre-built CI runner image with all dependencies pre-installed. +**Note:** The CI runner image approach has been deprecated for Gitea Actions workflows. -**Building the CI image locally:** -```bash -./scripts/build-ci-image.sh [tag] -``` +The original attempt to use a pre-built CI runner image with pre-installed dependencies encountered fundamental issues with how Gitea Actions handles workspace mounting. When Gitea Actions runs a container job, it mounts the workspace at a specific path (e.g., `/workspace/david/euchre_camp`), which hides the container's `/app` directory where dependencies were installed. -**Using the CI image:** -- Workflows automatically use `ghcr.io//ci-runner:latest` when available -- Falls back to `node:20-alpine` if image is not found -- Image is automatically rebuilt when `package.json` changes +**Current Approach:** +- Workflows use standard `node:20-alpine` or `mcr.microsoft.com/playwright` containers +- Dependencies are installed via `npm ci` in each workflow run +- This is the recommended approach for Gitea Actions -**CI Image contains:** -- Node.js 20 Alpine -- All npm dependencies pre-installed -- Prisma client pre-generated -- System tools (bash, git, python, make, g++) +**Why the CI image approach doesn't work:** +1. Dockerfile.ci installs dependencies in `/app` +2. Gitea Actions mounts workspace at `/workspace/david/euchre_camp` +3. Workspace mount hides the `/app` directory +4. Symlinks from `/app/node_modules` don't work because `/app` is hidden + +**Alternative for performance:** +If CI performance becomes an issue, consider: +- Using GitHub Actions cache for node_modules +- Using a self-hosted runner with persistent workspace +- Using the main Dockerfile's `test-runner` target for release workflows (which works because it builds a complete image) ### CI/CD Pipeline The project uses Gitea Actions for continuous integration: diff --git a/Dockerfile.ci b/Dockerfile.ci deleted file mode 100644 index 36429f2..0000000 --- a/Dockerfile.ci +++ /dev/null @@ -1,46 +0,0 @@ -# CI Runner Image for EuchreCamp -# Pre-installed with all dependencies to speed up CI runs -# This image is rebuilt automatically when package.json changes - -FROM node:20-alpine - -# Install system dependencies needed for various tasks -RUN apk add --no-cache \ - bash \ - git \ - curl \ - python3 \ - make \ - g++ \ - && rm -rf /var/cache/apk/* - -# Set working directory -WORKDIR /app - -# Copy package files first (for better caching) -COPY package*.json ./ - -# Install ALL dependencies including dev dependencies -# This is done at image build time, not at CI runtime -RUN npm ci - -# Copy Prisma schema (needed for Prisma client generation) -COPY prisma/schema.prisma ./prisma/ - -# Generate Prisma client -RUN npx prisma generate - -# Copy the rest of the application -COPY . . - -# Set environment variables for CI environment -ENV NODE_ENV=production -ENV DATABASE_PROVIDER=sqlite -ENV DATABASE_URL=file:./prisma/ci.db -ENV BETTER_AUTH_SECRET=test-secret-key-for-ci-only - -# Verify installations -RUN node --version && npm --version && git --version && npx prisma --version - -# Default command -CMD ["/bin/sh"] diff --git a/README.md b/README.md index 43809f9..df765b7 100644 --- a/README.md +++ b/README.md @@ -368,35 +368,27 @@ The application uses Gitea Actions for continuous integration and deployment: - Unit tests for quick feedback - Skips auto-generated version bumps -3. **Release Workflow** (`.gitea/workflows/release.yml`): Runs on main branch pushes - - Version bumping and tagging - - Docker image building and testing - - Registry push and deployment - -4. **CI Image Builder** (`.gitea/workflows/ci-image-builder.yml`): Runs when dependencies change - - Automatically builds CI runner image with all dependencies pre-installed - - Triggered by changes to `package.json`, `package-lock.json`, or `Dockerfile.ci` + 3. **Release Workflow** (`.gitea/workflows/release.yml`): Runs on main branch pushes + - Version bumping and tagging + - Docker image building and testing + - Registry push and deployment ### CI Runner Image -To avoid installing dependencies on every workflow run, we use a pre-built CI runner image: +**Note:** The CI runner image approach has been deprecated for Gitea Actions workflows. -**Dockerfile.ci** - Contains: -- Node.js 20 Alpine -- All npm dependencies pre-installed -- Prisma client pre-generated -- System tools (bash, git, python, make, g++) +The original attempt to use a pre-built CI runner image with pre-installed dependencies encountered fundamental issues with how Gitea Actions handles workspace mounting. When Gitea Actions runs a container job, it mounts the workspace at a specific path (e.g., `/workspace/david/euchre_camp`), which hides the container's `/app` directory where dependencies were installed. -**Automatic Rebuilding:** -- The CI image is automatically rebuilt when `package.json` or `package-lock.json` changes -- Images are tagged with commit SHA for traceability -- Falls back to `node:20-alpine` if custom image is not available +**Current Approach:** +- Workflows use standard `node:20-alpine` or `mcr.microsoft.com/playwright` containers +- Dependencies are installed via `npm ci` in each workflow run +- This is the recommended approach for Gitea Actions -**Manual Build:** -```bash -docker build -f Dockerfile.ci -t euchre-camp-ci:latest . -docker run --rm euchre-camp-ci:latest node --version -``` +**Why the CI image approach doesn't work:** +1. Dockerfile.ci installs dependencies in `/app` +2. Gitea Actions mounts workspace at `/workspace/david/euchre_camp` +3. Workspace mount hides the `/app` directory +4. Symlinks from `/app/node_modules` don't work because `/app` is hidden ### Database Strategy for CI - **CI Tests**: SQLite database (fast, no server required) @@ -410,9 +402,6 @@ npm run test:run # Run acceptance tests with SQLite DATABASE_PROVIDER=sqlite DATABASE_URL=file:./prisma/ci.db npm run test:acceptance - -# Run tests in CI container (if built) -docker run --rm -v $(pwd):/app -w /app euchre-camp-ci:latest npm run test:run ``` ## Docker Deployment diff --git a/justfile b/justfile index b25676e..ce44c9a 100644 --- a/justfile +++ b/justfile @@ -173,16 +173,6 @@ pr-validate: lint typecheck test-unit test-acceptance-sqlite ci-postgres: lint typecheck test-unit test-acceptance-postgres docker-build @echo "CI Pipeline with PostgreSQL completed successfully!" -# --- CI Image --- - -# Build CI runner image locally -ci-build: - @./scripts/build-ci-image.sh - -# Build CI runner image with custom tag -ci-build-tag TAG: - @./scripts/build-ci-image.sh {{TAG}} - # --- Utilities --- # Show help information @@ -256,6 +246,8 @@ workflow-status: @echo "PR Workflow: Runs unit + acceptance tests on pull requests" @echo "Test Workflow: Runs unit tests on all branch pushes" @echo "Release Workflow: Runs on main branch pushes (version bump + Docker build)" + @echo "" + @echo "Note: CI image approach deprecated due to Gitea Actions workspace mounting" # Check current database provider db-status: diff --git a/scripts/build-ci-image.sh b/scripts/build-ci-image.sh deleted file mode 100755 index 403e356..0000000 --- a/scripts/build-ci-image.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash -# Build and test the CI runner image locally - -set -e - -IMAGE_NAME="euchre-camp-ci-runner" -TAG="${1:-latest}" - -echo "Building CI runner image..." -echo "Image: ${IMAGE_NAME}:${TAG}" -echo "" - -# Build the image -docker build \ - -f Dockerfile.ci \ - -t ${IMAGE_NAME}:${TAG} \ - . - -echo "" -echo "✅ Image built successfully!" -echo "" - -# Test the image -echo "Testing CI image..." -docker run --rm ${IMAGE_NAME}:${TAG} sh -c " - echo 'Node.js version:' && node --version - echo 'npm version:' && npm --version - echo 'Git version:' && git --version - echo 'Prisma version:' && npx prisma --version - echo '' - echo 'Installed packages (top 10):' - npm list --depth=0 | head -10 -" - -echo "" -echo "✅ CI image is ready to use!" -echo "" -echo "To use in GitHub Actions/Gitea Actions:" -echo " container:" -echo " image: docker.notsosm.art/${IMAGE_NAME}:${TAG}" -echo "" -echo "To push to registry:" -echo " docker tag ${IMAGE_NAME}:${TAG} docker.notsosm.art/${IMAGE_NAME}:${TAG}" -echo " docker push docker.notsosm.art/${IMAGE_NAME}:${TAG}" -- 2.52.0