Update docs and CI to local testing

This commit is contained in:
adilallo
2026-04-23 19:00:55 -06:00
parent 701db2aa1a
commit ce204bff03
10 changed files with 98 additions and 587 deletions
-469
View File
@@ -1,469 +0,0 @@
name: CI Pipeline
run-name: "${{ gitea.actor }} triggered CI pipeline"
on:
workflow_dispatch: {} # Manual trigger only - run tests locally before merging
# Auto-runs disabled for solo development
# Re-enable when ready for collaborators:
# pull_request:
# branches: [main]
# types: [opened, reopened, synchronize]
env:
NODE_VERSION: "20"
NEXT_TELEMETRY_DISABLED: "1"
jobs:
test:
runs-on: [self-hosted, macos-latest]
env:
NODE_OPTIONS: "--max_old_space_size=8192 --max_semi_space_size=128"
CI: true
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "${{ env.NODE_VERSION }}"
cache: npm
- run: npm ci --no-audit --fund=false
- run: npm test -- --reporter=dot --maxConcurrency=1
# If the Codecov Action fails on Gitea, replace this with the bash uploader below
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
token: "${{ secrets.CODECOV_TOKEN }}"
files: ./coverage/lcov.info
flags: unittests
# Bash uploader alternative (uncomment if the action above has issues)
# - name: Upload coverage to Codecov (bash)
# run: |
# curl -s https://codecov.io/bash > codecov.sh
# bash codecov.sh -t "${{ secrets.CODECOV_TOKEN }}" -f coverage/lcov.info -F unittests
e2e:
runs-on: [self-hosted, macos-latest]
strategy:
matrix:
browser: [chromium, firefox, webkit]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "${{ env.NODE_VERSION }}"
cache: npm
- run: npm ci --no-audit --fund=false
- name: Install Playwright
run: "npx playwright install --with-deps ${{ matrix.browser }}"
- run: npm run build
- name: E2E (start + test + teardown)
run: |
set -euo pipefail
export PORT="${PORT:-3010}"
export HOST="127.0.0.1"
mkdir -p .next
# ensure build exists
test -d .next || { echo "❌ Missing .next build output"; exit 1; }
echo "🚀 Starting Next.js server for E2E testing..."
# Start Next directly with node so $! is the real node PID
node node_modules/next/dist/bin/next start -p "$PORT" -H "$HOST" > .next/runner.log 2>&1 &
SVPID=$!
echo "$SVPID" > .next/runner.pid
echo "🌐 Server PID: $SVPID"
# Wait for readiness
echo "⏳ Waiting for server to be ready..."
npx wait-on -t 120000 "tcp:$HOST:$PORT"
curl -fsS "http://$HOST:$PORT" >/dev/null
echo "✅ App is responding at http://$HOST:$PORT"
# Run tests
echo "🧪 Running E2E tests for ${{ matrix.browser }}..."
BASE_URL="http://$HOST:$PORT" npx playwright test --project=${{ matrix.browser }} --reporter=list || TEST_EXIT_CODE=$?
# Teardown
echo "🧹 Cleaning up server..."
kill "$SVPID" 2>/dev/null || true
echo "✅ Server cleanup complete"
env:
NEXT_TELEMETRY_DISABLED: "1"
NODE_ENV: production
NODE_OPTIONS: "--max-old-space-size=8192"
# package artifacts (keeps file count small)
- name: Package E2E artifacts
if: failure()
run: |
tar -czf playwright-${{ matrix.browser }}.tgz playwright-report test-results || true
- name: Upload E2E artifacts
if: failure()
uses: actions/upload-artifact@v3
with:
name: playwright-results-${{ matrix.browser }}
path: playwright-${{ matrix.browser }}.tgz
retention-days: 30
visual-regression:
runs-on: [self-hosted, macos-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "${{ env.NODE_VERSION }}"
cache: npm
- run: npm ci --no-audit --fund=false
- name: Install Playwright
run: npx playwright install --with-deps
- run: npm run build
# 1) Sanity check that the build exists
- name: Verify Next build output
run: |
set -euo pipefail
ls -la .next || true
test -f .next/BUILD_ID || (echo "No Next build output (.next) did build fail?" && exit 1)
- name: Visual Regression (start + test + teardown)
run: |
set -euo pipefail
export PORT="${PORT:-3010}"
export HOST="127.0.0.1"
mkdir -p .next
# ensure build exists
test -d .next || { echo "❌ Missing .next build output"; exit 1; }
echo "🚀 Starting Next.js server for visual regression testing..."
# Ensure port is free before starting
echo "🔍 Checking if port $PORT is available..."
if lsof -ti:$PORT >/dev/null 2>&1; then
echo "⚠️ Port $PORT is in use, killing existing processes..."
lsof -ti:$PORT | xargs kill -9 2>/dev/null || true
sleep 2
fi
# Start Next with explicit memory settings for CI stability
echo "🚀 Starting Next.js server on $HOST:$PORT..."
# Set environment variable and start server
export NODE_OPTIONS="--max-old-space-size=4096"
nohup node node_modules/next/dist/bin/next start -p "$PORT" -H "$HOST" > .next/runner.log 2>&1 &
SVPID=$!
echo "$SVPID" > .next/runner.pid
echo "🌐 Server PID: $SVPID"
# Give the server a moment to start
sleep 5
# Check if the server process is still running
if ! kill -0 "$SVPID" 2>/dev/null; then
echo "❌ Server process died immediately after starting"
echo "📋 Server logs:"
cat .next/runner.log || true
exit 1
fi
echo "✅ Server process is running (PID: $SVPID)"
# Wait for readiness with better error handling
echo "⏳ Waiting for server to be ready..."
npx wait-on -t 120000 "tcp:$HOST:$PORT"
# Verify server is actually responding to all test routes
echo "🔍 Verifying server readiness for all test routes..."
for i in {1..15}; do
# Check all routes that will be tested in visual regression
if curl -fsS "http://$HOST:$PORT" >/dev/null 2>&1 && \
curl -fsS "http://$HOST:$PORT/blog" >/dev/null 2>&1 && \
curl -fsS "http://$HOST:$PORT/blog/resolving-active-conflicts" >/dev/null 2>&1; then
echo "✅ App is responding to all test routes at http://$HOST:$PORT"
break
else
echo "⏳ Attempt $i/15: Server not ready for all routes yet, waiting..."
sleep 3
if [ $i -eq 15 ]; then
echo "❌ Server failed to respond to all routes after 15 attempts"
echo "📋 Server logs:"
cat .next/runner.log || true
echo "🔍 Testing individual routes:"
curl -I "http://$HOST:$PORT" || echo "❌ Homepage failed"
curl -I "http://$HOST:$PORT/blog" || echo "❌ Blog failed"
curl -I "http://$HOST:$PORT/blog/resolving-active-conflicts" || echo "❌ Blog post failed"
exit 1
fi
fi
done
# Give server a moment to fully settle after all routes are ready
echo "⏳ Allowing server to fully settle..."
sleep 10
# Final verification that server is still responding
echo "🔍 Final server health check..."
if ! curl -fsS "http://$HOST:$PORT" >/dev/null 2>&1; then
echo "❌ Server health check failed after settlement period"
echo "📋 Server logs:"
cat .next/runner.log || true
exit 1
fi
echo "✅ Server is healthy and ready for tests"
# Run visual regression tests with server monitoring
echo "🧪 Running visual regression tests..."
# Start comprehensive server monitoring in background
(
while true; do
# Check if server process is still running
if ! kill -0 "$SVPID" 2>/dev/null; then
echo "❌ Server process died during test execution"
echo "📋 Server logs:"
cat .next/runner.log || true
break
fi
# Check if server is responding
if ! curl -fsS "http://$HOST:$PORT" >/dev/null 2>&1; then
echo "⚠️ Server health check failed - server may have crashed"
echo "📋 Current server logs:"
tail -20 .next/runner.log || true
break
fi
sleep 5
done
) &
HEALTH_PID=$!
# Run tests with increased timeout and conservative settings for CI stability
BASE_URL="http://$HOST:$PORT" npx playwright test tests/e2e/visual-regression.spec.ts --timeout=120000 --workers=1 --retries=1
# Stop health monitoring
kill $HEALTH_PID 2>/dev/null || true
# Teardown with better error handling
echo "🧹 Cleaning up server..."
kill "$SVPID" 2>/dev/null || true
# Wait for server to actually stop
for i in {1..10}; do
if ! kill -0 "$SVPID" 2>/dev/null; then
echo "✅ Server process stopped"
break
else
echo "⏳ Waiting for server to stop... ($i/10)"
sleep 2
if [ $i -eq 10 ]; then
echo "⚠️ Force killing server process"
kill -9 "$SVPID" 2>/dev/null || true
fi
fi
done
echo "✅ Server cleanup complete"
env:
NEXT_TELEMETRY_DISABLED: "1"
NODE_ENV: production
NODE_OPTIONS: "--max-old-space-size=8192"
- name: Package visual artifacts
if: failure()
run: |
# Include server logs for debugging
echo "📋 Server logs for debugging:"
cat .next/runner.log || echo "No server logs found"
# Package test results and logs
tar -czf visual-regression.tgz test-results tests/e2e/visual-regression.spec.ts-snapshots .next/runner.log || true
- name: Upload visual artifacts
if: failure()
uses: actions/upload-artifact@v3
with:
name: visual-regression-results
path: visual-regression.tgz
retention-days: 30
- name: Stop app
if: always()
run: |
if [ -f .next/runner.pid ]; then
kill $(cat .next/runner.pid) 2>/dev/null || true
fi
performance:
runs-on: [self-hosted, macos-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "${{ env.NODE_VERSION }}"
cache: npm
- run: npm ci --no-audit --fund=false
- name: Build application
run: npm run build
# 1) Sanity check that the build exists
- name: Verify Next build output
run: |
set -euo pipefail
ls -la .next || true
test -f .next/BUILD_ID || (echo "No Next build output (.next) did build fail?" && exit 1)
- name: Install Chrome via Puppeteer (mac_arm)
run: |
# Install Chrome (arm64) into a local cache
set -euo pipefail
mkdir -p .cache/puppeteer
# 1) Install and capture the build id that was actually installed
INSTALL_OUT="$(npx @puppeteer/browsers install chrome@stable --platform=mac_arm --path .cache/puppeteer)"
echo "$INSTALL_OUT"
# INSTALL_OUT looks like: "chrome@140.0.7339.80 /abs/path/to/.../Google Chrome for Testing"
BUILD_ID="$(printf '%s\n' "$INSTALL_OUT" | awk '{print $1}' | cut -d@ -f2)"
echo "Detected Chrome build: $BUILD_ID"
# 2) Ask for the executable path using the explicit build id
CHROME_PATH="$(npx @puppeteer/browsers executable-path chrome@"$BUILD_ID" --platform=mac_arm --path .cache/puppeteer || true)"
echo "Chrome executable path (via CLI): ${CHROME_PATH:-<empty>}"
# 3) Fallback: resolve the binary directly from the cache if the CLI returned empty
if [ -z "$CHROME_PATH" ]; then
CHROME_PATH="$(/usr/bin/find ".cache/puppeteer/chrome" -type f -path "*/chrome-mac-arm64/Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing" -print -quit || true)"
echo "Chrome executable path (via find): ${CHROME_PATH:-<empty>}"
fi
# 4) Hard fail if still empty
if [ -z "$CHROME_PATH" ] || [ ! -x "$CHROME_PATH" ]; then
echo "❌ Chrome path is empty or not executable"
ls -la .cache/puppeteer || true
exit 1
fi
# 5) Export for subsequent steps in this job and later ones
echo "CHROME_PATH=$CHROME_PATH" >> "$GITHUB_ENV"
"$CHROME_PATH" --version || true
- name: Ensure arm64 Node for Lighthouse
run: |
set -euo pipefail
echo "node before: $(node -v) arch=$(node -p 'process.arch')"
if [ "$(node -p 'process.arch')" != "arm64" ]; then
NODE_VER=20.17.0
curl -fsSLO "https://nodejs.org/dist/v${NODE_VER}/node-v${NODE_VER}-darwin-arm64.tar.xz"
tar -xJf "node-v${NODE_VER}-darwin-arm64.tar.xz"
# Make arm64 node take effect in THIS step:
export PATH="$PWD/node-v${NODE_VER}-darwin-arm64/bin:$PATH"
# And persist for subsequent steps:
echo "$PWD/node-v${NODE_VER}-darwin-arm64/bin" >> "$GITHUB_PATH"
fi
echo "node after: $(node -v) arch=$(node -p 'process.arch')"
echo "uname -m: $(uname -m)"
# Get Chrome path for this step
CHROME_PATH=$(npx @puppeteer/browsers executable-path chrome@stable --platform=mac_arm --path .cache/puppeteer)
echo "Chrome path: $CHROME_PATH"
"$CHROME_PATH" --version || true
- name: Performance (start + test + teardown)
run: |
set -euo pipefail
export PORT=3010 HOST=127.0.0.1
mkdir -p .next
test -d .next || { echo "❌ Missing .next build output"; exit 1; }
echo "🚀 Starting Next.js server for performance testing..."
node node_modules/next/dist/bin/next start -p "$PORT" -H "$HOST" > .next/runner.log 2>&1 &
SVPID=$!
npx wait-on -t 120000 "tcp:$HOST:$PORT"
curl -fsS "http://$HOST:$PORT" >/dev/null
echo "✅ App is responding at http://$HOST:$PORT"
# Ensure we're using arm64 Node for Lighthouse
echo "Node arch: $(node -p "process.arch")"
# Get Chrome path directly in this step (same logic as installation step)
INSTALL_OUT="$(npx @puppeteer/browsers install chrome@stable --platform=mac_arm --path .cache/puppeteer 2>/dev/null || true)"
BUILD_ID="$(printf '%s\n' "$INSTALL_OUT" | awk '{print $1}' | cut -d@ -f2)"
echo "Using Chrome build: $BUILD_ID"
# Try CLI first, then fallback to find
CHROME_PATH="$(npx @puppeteer/browsers executable-path chrome@"$BUILD_ID" --platform=mac_arm --path .cache/puppeteer 2>/dev/null || true)"
if [ -z "$CHROME_PATH" ]; then
CHROME_PATH="$(/usr/bin/find ".cache/puppeteer/chrome" -type f -path "*/chrome-mac-arm64/Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing" -print -quit 2>/dev/null || true)"
fi
echo "Chrome path: $CHROME_PATH"
# Verify Chrome path is not empty
if [ -z "$CHROME_PATH" ]; then
echo "❌ Chrome path is empty - Chrome installation may have failed"
exit 1
fi
# Verify Chrome executable exists and is executable
if [ ! -x "$CHROME_PATH" ]; then
echo "❌ Chrome executable not found or not executable: $CHROME_PATH"
ls -la .cache/puppeteer/ || true
exit 1
fi
"$CHROME_PATH" --version
# Run LHCI with arm64 Node + arm64 Chrome
# Test homepage and blog pages using config file
npx lhci autorun --chrome-path="$CHROME_PATH"
kill "$SVPID" 2>/dev/null || true
env:
NEXT_TELEMETRY_DISABLED: "1"
NODE_ENV: production
NODE_OPTIONS: "--max-old-space-size=8192"
- name: Upload Performance Artifacts
if: failure()
uses: actions/upload-artifact@v3
with:
name: performance-results
path: |
lhci-results
.next/analyze
.next/monitoring
.next/web-vitals
.next/test-results
retention-days: 30
lint:
runs-on: [self-hosted, macos-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "${{ env.NODE_VERSION }}"
cache: npm
- run: npm ci --no-audit --fund=false
- name: Prisma schema
run: npx prisma validate
env:
DATABASE_URL: postgresql://ci:ci@127.0.0.1:5432/ci
- run: npm run lint
- run: npm exec prettier -- --check "**/*.{js,jsx,ts,tsx,json,css,md}"
build:
runs-on: [self-hosted, macos-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "${{ env.NODE_VERSION }}"
cache: npm
- run: npm ci --no-audit --fund=false
- run: npm run build
- run: npm run storybook:build:github
-74
View File
@@ -1,74 +0,0 @@
name: Migrate Smoke
run-name: "${{ gitea.actor }} triggered migrate smoke"
on:
workflow_dispatch: {}
pull_request:
branches: [main]
paths:
- "prisma/**"
- ".gitea/workflows/migrate-smoke.yaml"
push:
branches: [main]
paths:
- "prisma/**"
- ".gitea/workflows/migrate-smoke.yaml"
env:
NODE_VERSION: "20"
NEXT_TELEMETRY_DISABLED: "1"
# Non-default host port so a local dev Postgres on 5432 keeps working.
PG_HOST_PORT: "5433"
POSTGRES_USER: communityrule
POSTGRES_PASSWORD: communityrule
POSTGRES_DB: communityrule
jobs:
migrate:
runs-on: [self-hosted, macos-latest]
env:
CI: true
DATABASE_URL: "postgresql://communityrule:communityrule@127.0.0.1:5433/communityrule"
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "${{ env.NODE_VERSION }}"
cache: npm
- name: Start Postgres
run: |
set -euo pipefail
docker rm -f migrate-smoke-pg >/dev/null 2>&1 || true
docker run -d --name migrate-smoke-pg \
-e POSTGRES_USER="$POSTGRES_USER" \
-e POSTGRES_PASSWORD="$POSTGRES_PASSWORD" \
-e POSTGRES_DB="$POSTGRES_DB" \
-p "${PG_HOST_PORT}:5432" \
postgres:16-alpine
- name: Wait for Postgres
run: |
set -euo pipefail
for i in {1..30}; do
if docker exec migrate-smoke-pg pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB" >/dev/null 2>&1; then
echo "Postgres ready after ${i}s"
exit 0
fi
sleep 1
done
echo "Postgres did not become ready in 30s"
docker logs migrate-smoke-pg || true
exit 1
- run: npm ci --no-audit --fund=false
- name: Apply migrations
run: npm run db:deploy
- name: Verify Prisma can connect to migrated DB
run: echo "SELECT 1;" | npx --no-install prisma db execute --stdin --url "$DATABASE_URL"
- name: Stop Postgres
if: always()
run: docker rm -f migrate-smoke-pg >/dev/null 2>&1 || true