Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
184 changes: 184 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]

env:
NODE_VERSION: '20'
PNPM_VERSION: '10'

jobs:
# ====================
# Backend Tests
# ====================
backend-test:
name: Backend Tests
runs-on: ubuntu-latest

services:
postgres:
image: timescale/timescaledb:latest-pg16
env:
POSTGRES_DB: logward_test
POSTGRES_USER: logward_test
POSTGRES_PASSWORD: test_password
ports:
- 5433:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5

redis:
image: redis:7-alpine
ports:
- 6380:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5

mailhog:
image: mailhog/mailhog:latest
ports:
- 1025:1025
- 8025:8025

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Build shared package
run: pnpm --filter '@logward/shared' build

- name: Run backend tests with coverage
working-directory: packages/backend
env:
NODE_ENV: test
DATABASE_URL: postgresql://logward_test:test_password@localhost:5433/logward_test
DATABASE_HOST: localhost
DATABASE_PORT: 5433
DB_USER: logward_test
DB_PASSWORD: test_password
DB_NAME: logward_test
REDIS_URL: redis://localhost:6380
API_KEY_SECRET: test_secret_key_32_chars_long!!!
SMTP_HOST: localhost
SMTP_PORT: 1025
SMTP_USER: ''
SMTP_PASS: ''
SMTP_FROM: test@logward.dev
RATE_LIMIT_MAX: 1000
RATE_LIMIT_WINDOW: 60000
run: pnpm test:ci -- --coverage

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: packages/backend/coverage/lcov.info
flags: backend
name: backend-coverage
fail_ci_if_error: false
verbose: true

- name: Check coverage threshold
working-directory: packages/backend
run: |
COVERAGE=$(cat coverage/coverage-summary.json | jq '.total.lines.pct')
echo "Line coverage: $COVERAGE%"
if (( $(echo "$COVERAGE < 70" | bc -l) )); then
echo "::error::Coverage $COVERAGE% is below 70% threshold"
exit 1
fi
echo "::notice::Coverage $COVERAGE% meets the 70% threshold"

# ====================
# Typecheck
# ====================
typecheck:
name: TypeScript Check
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Build shared package
run: pnpm --filter '@logward/shared' build

- name: Typecheck backend
run: pnpm --filter '@logward/backend' typecheck

- name: Typecheck frontend
env:
PUBLIC_API_URL: http://localhost:8080
run: pnpm --filter '@logward/frontend' typecheck

# ====================
# Build Docker Images
# ====================
build:
name: Build Docker Images
runs-on: ubuntu-latest
needs: [backend-test, typecheck]

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build backend image
uses: docker/build-push-action@v5
with:
context: .
file: packages/backend/Dockerfile
push: false
tags: logward/backend:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Build frontend image
uses: docker/build-push-action@v5
with:
context: .
file: packages/frontend/Dockerfile
push: false
tags: logward/frontend:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,6 @@ coverage/
.temp/
tmp/
/.claude/
claude.md
claude.md
/packages/backend/.claude/
/packages/backend/load-tests/
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
<a href="https://logward.dev/docs">Docs</a>
</p>

<a href="https://github.com/logward-dev/logward/actions/workflows/ci.yml"><img src="https://github.com/logward-dev/logward/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
<a href="https://codecov.io/gh/logward-dev/logward"><img src="https://codecov.io/gh/logward-dev/logward/branch/main/graph/badge.svg" alt="Coverage"></a>
<img src="https://img.shields.io/badge/license-AGPLv3-blue.svg" alt="License">
<img src="https://img.shields.io/badge/status-alpha-orange.svg" alt="Status">
<img src="https://img.shields.io/badge/cloud-free_during_alpha-success.svg" alt="Free Cloud">
Expand Down
84 changes: 84 additions & 0 deletions docker-compose.test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
services:
postgres-test:
image: timescale/timescaledb:latest-pg16
container_name: logward-postgres-test
environment:
POSTGRES_DB: logward_test
POSTGRES_USER: logward_test
POSTGRES_PASSWORD: test_password
ports:
- "5433:5432"
tmpfs:
- /var/lib/postgresql/data # In-memory for speed
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U logward_test" ]
interval: 5s
timeout: 3s
retries: 5
networks:
- logward-test-network

redis-test:
image: redis:7-alpine
container_name: logward-redis-test
command: redis-server --requirepass test_password
ports:
- "6380:6379"
healthcheck:
test: [ "CMD", "redis-cli", "-a", "test_password", "ping" ]
interval: 5s
timeout: 3s
retries: 5
networks:
- logward-test-network

mailhog-test:
image: mailhog/mailhog:latest
container_name: logward-mailhog-test
ports:
- "1025:1025" # SMTP
- "8025:8025" # API/UI
networks:
- logward-test-network

# Backend for E2E and load testing
backend-test:
build:
context: .
dockerfile: packages/backend/Dockerfile
container_name: logward-backend-test
environment:
NODE_ENV: test
PORT: 8080
DATABASE_URL: postgresql://logward_test:test_password@postgres-test:5432/logward_test
DATABASE_HOST: postgres-test
DB_USER: logward_test
REDIS_URL: redis://:test_password@redis-test:6379
API_KEY_SECRET: test_secret_key_32_chars_long!!!
SMTP_HOST: mailhog-test
SMTP_PORT: 1025
SMTP_USER: ""
SMTP_PASS: ""
SMTP_FROM: test@logward.dev
# Higher rate limits for load testing (100 req/s = 6000/min, use 100000 for safety)
RATE_LIMIT_MAX: 100000
RATE_LIMIT_WINDOW: 60000
ports:
- "3001:8080"
depends_on:
postgres-test:
condition: service_healthy
redis-test:
condition: service_healthy
healthcheck:
test: [ "CMD", "node", "-e", "require('http').get('http://localhost:8080/health', (r) => r.statusCode === 200 ? process.exit(0) : process.exit(1))" ]
interval: 10s
timeout: 5s
retries: 10
start_period: 30s
networks:
- logward-test-network

networks:
logward-test-network:
driver: bridge
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@
},
"engines": {
"node": ">=20.0.0",
"pnpm": ">=8.0.0"
"pnpm": ">=10.0.0"
}
}
34 changes: 34 additions & 0 deletions packages/backend/.env.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Test Environment Variables
DATABASE_URL=postgresql://logward_test:test_password@localhost:5433/logward_test
DB_NAME=logward_test
DB_USER=logward_test
DB_PASSWORD=test_password

# Redis
REDIS_PASSWORD=test_password
REDIS_URL=redis://:test_password@localhost:6380

# API
API_KEY_SECRET=test_secret_key_32_chars_long!!!
PORT=8081
HOST=127.0.0.1

# SMTP (Mock - MailHog or similar)
SMTP_HOST=localhost
SMTP_PORT=1025
SMTP_USER=test@example.com
SMTP_PASS=test_password
SMTP_FROM=noreply@test.logward.local

# Rate Limiting
RATE_LIMIT_MAX=1000
RATE_LIMIT_WINDOW=60000

# Environment
NODE_ENV=test

# Internal Logging (disabled for tests)
INTERNAL_LOGGING_ENABLED=false

# Service Name
SERVICE_NAME=logward-backend-test
Loading
Loading