Add Gitea Actions workflows, CI config, and docs
This commit is contained in:
267
.gitea/workflows/ci.yml
Normal file
267
.gitea/workflows/ci.yml
Normal file
@@ -0,0 +1,267 @@
|
||||
# =============================================================================
|
||||
# CI Workflow — Continuous Integration
|
||||
# =============================================================================
|
||||
# Triggers on push and pull_request.
|
||||
#
|
||||
# Detection logic:
|
||||
# 1. Python: if requirements.txt exists → install deps, lint, test.
|
||||
# 2. Node/JS: if package.json exists → npm ci, lint, test, build.
|
||||
# 3. Neither detected → print a message and exit 0 (never fail).
|
||||
#
|
||||
# Controlled by .ci/config.env:
|
||||
# ENABLE_CI — master switch (default: true)
|
||||
# CI_STRICT — if true, lint/test failures fail the workflow
|
||||
# if false, failures are warnings only
|
||||
#
|
||||
# See docs/CI.md for full details.
|
||||
# =============================================================================
|
||||
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# -----------------------------------------------------------------------
|
||||
# Step 1: Checkout the code
|
||||
# -----------------------------------------------------------------------
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Step 2: Load configuration from .ci/config.env
|
||||
# -----------------------------------------------------------------------
|
||||
- name: Load config
|
||||
id: config
|
||||
run: |
|
||||
# Source config.env to get ENABLE_CI, CI_STRICT, etc.
|
||||
if [ -f .ci/config.env ]; then
|
||||
# Export all non-comment, non-empty lines
|
||||
set -a
|
||||
source .ci/config.env
|
||||
set +a
|
||||
echo "Config loaded from .ci/config.env"
|
||||
else
|
||||
echo "WARNING: .ci/config.env not found, using defaults"
|
||||
ENABLE_CI=true
|
||||
CI_STRICT=true
|
||||
fi
|
||||
|
||||
# Pass values to subsequent steps via environment file
|
||||
echo "ENABLE_CI=${ENABLE_CI:-true}" >> "$GITHUB_ENV"
|
||||
echo "CI_STRICT=${CI_STRICT:-true}" >> "$GITHUB_ENV"
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Step 3: Check master switch
|
||||
# -----------------------------------------------------------------------
|
||||
- name: Check if CI is enabled
|
||||
run: |
|
||||
if [ "$ENABLE_CI" != "true" ]; then
|
||||
echo "CI is disabled (ENABLE_CI=$ENABLE_CI). Exiting."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Step 4: Detect project type
|
||||
# -----------------------------------------------------------------------
|
||||
- name: Detect project type
|
||||
id: detect
|
||||
run: |
|
||||
HAS_PYTHON=false
|
||||
HAS_NODE=false
|
||||
|
||||
if [ -f requirements.txt ] || [ -f setup.py ] || [ -f pyproject.toml ]; then
|
||||
HAS_PYTHON=true
|
||||
echo "Detected: Python project"
|
||||
fi
|
||||
|
||||
if [ -f package.json ]; then
|
||||
HAS_NODE=true
|
||||
echo "Detected: Node.js project"
|
||||
fi
|
||||
|
||||
if [ "$HAS_PYTHON" = "false" ] && [ "$HAS_NODE" = "false" ]; then
|
||||
echo "No Python or Node.js project detected. CI will skip gracefully."
|
||||
fi
|
||||
|
||||
echo "HAS_PYTHON=${HAS_PYTHON}" >> "$GITHUB_ENV"
|
||||
echo "HAS_NODE=${HAS_NODE}" >> "$GITHUB_ENV"
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Step 5: Python — Setup & Install
|
||||
# -----------------------------------------------------------------------
|
||||
- name: Set up Python
|
||||
if: env.HAS_PYTHON == 'true'
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.x"
|
||||
|
||||
- name: Install Python dependencies
|
||||
if: env.HAS_PYTHON == 'true'
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
if [ -f requirements.txt ]; then
|
||||
pip install -r requirements.txt
|
||||
fi
|
||||
# Install optional dev tools (won't fail if not needed)
|
||||
pip install ruff black flake8 pytest 2>/dev/null || true
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Step 6: Python — Lint
|
||||
# Runs ruff, then black --check, then flake8. Each is optional:
|
||||
# only runs if the tool is installed AND relevant config exists.
|
||||
# -----------------------------------------------------------------------
|
||||
- name: Python lint
|
||||
if: env.HAS_PYTHON == 'true'
|
||||
run: |
|
||||
EXIT_CODE=0
|
||||
|
||||
# --- ruff ---
|
||||
if command -v ruff >/dev/null 2>&1; then
|
||||
echo ">>> ruff check ."
|
||||
ruff check . || EXIT_CODE=$?
|
||||
else
|
||||
echo "SKIP: ruff not installed"
|
||||
fi
|
||||
|
||||
# --- black ---
|
||||
if command -v black >/dev/null 2>&1; then
|
||||
echo ">>> black --check ."
|
||||
black --check . || EXIT_CODE=$?
|
||||
else
|
||||
echo "SKIP: black not installed"
|
||||
fi
|
||||
|
||||
# --- flake8 ---
|
||||
if command -v flake8 >/dev/null 2>&1; then
|
||||
echo ">>> flake8 ."
|
||||
flake8 . || EXIT_CODE=$?
|
||||
else
|
||||
echo "SKIP: flake8 not installed"
|
||||
fi
|
||||
|
||||
if [ "$EXIT_CODE" -ne 0 ]; then
|
||||
if [ "$CI_STRICT" = "true" ]; then
|
||||
echo "ERROR: Lint failed (CI_STRICT=true)"
|
||||
exit 1
|
||||
else
|
||||
echo "WARNING: Lint issues found (CI_STRICT=false, continuing)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Step 7: Python — Test
|
||||
# Runs pytest if a tests/ directory or pytest config is detected.
|
||||
# -----------------------------------------------------------------------
|
||||
- name: Python test
|
||||
if: env.HAS_PYTHON == 'true'
|
||||
run: |
|
||||
# Check if tests exist
|
||||
HAS_TESTS=false
|
||||
if [ -d tests ] || [ -d test ]; then
|
||||
HAS_TESTS=true
|
||||
fi
|
||||
# Check for pytest config in pyproject.toml or pytest.ini
|
||||
if [ -f pytest.ini ] || [ -f setup.cfg ]; then
|
||||
HAS_TESTS=true
|
||||
fi
|
||||
if [ -f pyproject.toml ] && grep -q '\[tool\.pytest' pyproject.toml 2>/dev/null; then
|
||||
HAS_TESTS=true
|
||||
fi
|
||||
|
||||
if [ "$HAS_TESTS" = "true" ]; then
|
||||
echo ">>> pytest"
|
||||
if ! pytest; then
|
||||
if [ "$CI_STRICT" = "true" ]; then
|
||||
echo "ERROR: Tests failed (CI_STRICT=true)"
|
||||
exit 1
|
||||
else
|
||||
echo "WARNING: Tests failed (CI_STRICT=false, continuing)"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "SKIP: No tests detected (no tests/ dir or pytest config)"
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Step 8: Node.js — Setup & Install
|
||||
# -----------------------------------------------------------------------
|
||||
- name: Set up Node.js
|
||||
if: env.HAS_NODE == 'true'
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "lts/*"
|
||||
|
||||
- name: Install Node dependencies
|
||||
if: env.HAS_NODE == 'true'
|
||||
run: npm ci
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Step 9: Node.js — Lint (only if "lint" script exists in package.json)
|
||||
# -----------------------------------------------------------------------
|
||||
- name: Node lint
|
||||
if: env.HAS_NODE == 'true'
|
||||
run: |
|
||||
if grep -q '"lint"' package.json 2>/dev/null; then
|
||||
echo ">>> npm run lint"
|
||||
if ! npm run lint; then
|
||||
if [ "$CI_STRICT" = "true" ]; then
|
||||
echo "ERROR: Lint failed (CI_STRICT=true)"
|
||||
exit 1
|
||||
else
|
||||
echo "WARNING: Lint issues found (CI_STRICT=false, continuing)"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "SKIP: no 'lint' script in package.json"
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Step 10: Node.js — Test (only if "test" script exists)
|
||||
# -----------------------------------------------------------------------
|
||||
- name: Node test
|
||||
if: env.HAS_NODE == 'true'
|
||||
run: |
|
||||
if grep -q '"test"' package.json 2>/dev/null; then
|
||||
echo ">>> npm test"
|
||||
if ! npm test; then
|
||||
if [ "$CI_STRICT" = "true" ]; then
|
||||
echo "ERROR: Tests failed (CI_STRICT=true)"
|
||||
exit 1
|
||||
else
|
||||
echo "WARNING: Tests failed (CI_STRICT=false, continuing)"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "SKIP: no 'test' script in package.json"
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Step 11: Node.js — Build (only if "build" script exists)
|
||||
# -----------------------------------------------------------------------
|
||||
- name: Node build
|
||||
if: env.HAS_NODE == 'true'
|
||||
run: |
|
||||
if grep -q '"build"' package.json 2>/dev/null; then
|
||||
echo ">>> npm run build"
|
||||
npm run build
|
||||
else
|
||||
echo "SKIP: no 'build' script in package.json"
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Step 12: Summary
|
||||
# -----------------------------------------------------------------------
|
||||
- name: CI Summary
|
||||
if: always()
|
||||
run: |
|
||||
echo "=============================="
|
||||
echo " CI Complete"
|
||||
echo " Python detected: $HAS_PYTHON"
|
||||
echo " Node detected: $HAS_NODE"
|
||||
echo " Strict mode: $CI_STRICT"
|
||||
echo "=============================="
|
||||
Reference in New Issue
Block a user