ice/.forgejo/workflows/ci.yml
Claude Code 3b48e804da Add .zip extension to coverage report artifact name
This makes the artifact more recognizable in the Forgejo UI as a downloadable zip file.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-07 21:58:21 -04:00

239 lines
No EOL
6.9 KiB
YAML

name: CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
lint:
runs-on: self-hosted
name: Lint Code
steps:
- name: Checkout code
uses: https://code.forgejo.org/actions/checkout@v4
- name: Setup Node.js
run: |
node --version
npm --version
- name: Install dependencies
run: npm ci
- name: Run ESLint
run: npm run lint
type-check:
runs-on: self-hosted
name: TypeScript Type Check
steps:
- name: Checkout code
uses: https://code.forgejo.org/actions/checkout@v4
- name: Setup Node.js
run: |
node --version
npm --version
- name: Install dependencies
run: npm ci
- name: Run TypeScript compiler
run: npx tsc --noEmit
test:
runs-on: self-hosted
name: Run Tests (Node ${{ matrix.node-version }})
strategy:
matrix:
node-version: [18, 20]
steps:
- name: Checkout code
uses: https://code.forgejo.org/actions/checkout@v4
- name: Setup Node.js
run: |
node --version
npm --version
- name: Install dependencies
run: npm ci
- name: Run npm tests
run: npm test
coverage:
runs-on: self-hosted
name: Test Coverage
steps:
- name: Checkout code
uses: https://code.forgejo.org/actions/checkout@v4
- name: Setup Node.js
run: |
node --version
npm --version
- name: Install dependencies
run: npm ci
- name: Run tests with coverage
run: npm run test:coverage
- name: Upload coverage reports
uses: https://code.forgejo.org/forgejo/upload-artifact@v4
with:
name: coverage-report.zip
path: coverage/
build:
runs-on: self-hosted
name: Build Project
steps:
- name: Checkout code
uses: https://code.forgejo.org/actions/checkout@v4
- name: Setup Node.js
run: |
node --version
npm --version
- name: Install dependencies
run: npm ci
- name: Build TypeScript
run: npm run build:ts
- name: Build Frontend
run: npm run build:frontend
- name: Build CSS
run: npm run build-css
- name: Verify build outputs
run: |
echo "Checking backend build..."
test -f dist/server.js || exit 1
echo "Checking frontend build..."
test -f public/dist/app-main.js || exit 1
test -f public/dist/app-admin.js || exit 1
test -f public/dist/app-privacy.js || exit 1
echo "Checking CSS build..."
test -f public/style.css || exit 1
echo "✅ All build outputs verified!"
security:
runs-on: self-hosted
name: Security Checks
steps:
- name: Checkout code
uses: https://code.forgejo.org/actions/checkout@v4
- name: Setup Node.js
run: |
node --version
npm --version
- name: Install dependencies
run: npm ci
- name: Run npm audit
run: npm audit --audit-level=high
continue-on-error: true
- name: Check for secrets
run: |
echo "Checking for potential secrets..."
# Check for hardcoded Mapbox tokens (pk. or sk. prefixes)
if find . -name "*.js" -o -name "*.ts" | grep -v node_modules | grep -v dist | grep -v .git | xargs grep -E "(pk\.|sk\.)[a-zA-Z0-9]{50,}" > /dev/null 2>&1; then
echo "❌ Found hardcoded Mapbox token!"
find . -name "*.js" -o -name "*.ts" | grep -v node_modules | grep -v dist | grep -v .git | xargs grep -E "(pk\.|sk\.)[a-zA-Z0-9]{50,}"
exit 1
fi
# Check for hardcoded admin passwords (exclude test files and obvious fallbacks)
if find . -name "*.js" -o -name "*.ts" | grep -v node_modules | grep -v dist | grep -v .git | grep -v tests | xargs grep -E "ADMIN_PASSWORD.*=.*['\"][^'\"]{8,}['\"]" | grep -v "admin123" | grep -v "test_" > /dev/null 2>&1; then
echo "❌ Found hardcoded admin password!"
find . -name "*.js" -o -name "*.ts" | grep -v node_modules | grep -v dist | grep -v .git | grep -v tests | xargs grep -E "ADMIN_PASSWORD.*=.*['\"][^'\"]{8,}['\"]" | grep -v "admin123" | grep -v "test_"
exit 1
fi
echo "✅ No hardcoded secrets found"
validate-i18n:
runs-on: self-hosted
name: Validate i18n Files
steps:
- name: Checkout code
uses: https://code.forgejo.org/actions/checkout@v4
- name: Setup Node.js
run: |
node --version
npm --version
- name: Validate JSON files
run: |
echo "Validating i18n JSON files..."
for file in src/i18n/locales/*.json; do
echo "Checking $file..."
node -e "JSON.parse(require('fs').readFileSync('$file', 'utf8'))" || exit 1
done
echo "✅ All i18n files are valid JSON"
- name: Check translation keys match
run: |
echo "Comparing translation keys..."
node -e "
const fs = require('fs');
const en = JSON.parse(fs.readFileSync('src/i18n/locales/en.json', 'utf8'));
const esMX = JSON.parse(fs.readFileSync('src/i18n/locales/es-MX.json', 'utf8'));
function getKeys(obj, prefix = '') {
let keys = [];
for (const key in obj) {
const fullKey = prefix ? prefix + '.' + key : key;
if (typeof obj[key] === 'object' && !Array.isArray(obj[key])) {
keys = keys.concat(getKeys(obj[key], fullKey));
} else {
keys.push(fullKey);
}
}
return keys.sort();
}
const enKeys = getKeys(en);
const esMXKeys = getKeys(esMX);
const missingInEs = enKeys.filter(k => !esMXKeys.includes(k));
const missingInEn = esMXKeys.filter(k => !enKeys.includes(k));
if (missingInEs.length > 0) {
console.error('❌ Keys in en.json missing from es-MX.json:', missingInEs);
process.exit(1);
}
if (missingInEn.length > 0) {
console.error('❌ Keys in es-MX.json missing from en.json:', missingInEn);
process.exit(1);
}
console.log('✅ All translation keys match between locales');
"