diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..06d0337 --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,129 @@ +name: CI + +on: + push: + branches: [master] + pull_request: + branches: [master] + +jobs: + syntax-check: + runs-on: linux_amd64 + steps: + - name: Checkout + run: | + git clone --depth 1 --branch "${GITHUB_REF_NAME}" \ + "https://oauth2:${{ github.token }}@${GITHUB_SERVER_URL#https://}/${GITHUB_REPOSITORY}.git" . + + - name: Python 2 syntax check + run: | + echo "Checking Python 2 syntax..." + failed=0 + for f in ppf.py proxywatchd.py scraper.py httpd.py \ + config.py dbs.py fetch.py connection_pool.py \ + engines.py translations.py http2.py \ + mysqlite.py misc.py comboparse.py soup_parser.py; do + if [ -f "$f" ]; then + if python2 -m py_compile "$f" 2>/dev/null; then + echo "OK $f" + else + echo "FAIL $f" + failed=1 + fi + fi + done + exit $failed + + - name: Python 3 syntax check + run: | + echo "Checking Python 3 syntax..." + for f in *.py; do + python3 -m py_compile "$f" 2>/dev/null && echo "OK $f" || echo "WARN $f" + done + + memory-leak-check: + runs-on: linux_amd64 + container: + image: python:2.7-slim + steps: + - name: Checkout + run: | + apt-get update && apt-get install -y git + git clone --depth 1 --branch "${GITHUB_REF_NAME}" \ + "https://oauth2:${{ github.token }}@${GITHUB_SERVER_URL#https://}/${GITHUB_REPOSITORY}.git" . + + - name: Install dependencies + run: | + pip install --quiet objgraph || true + + - name: Check for memory leak patterns + run: | + echo "Scanning for common memory leak patterns..." + failed=0 + + # Check for unbounded list/dict growth without limits + echo "Checking for unbounded collections..." + for f in ppf.py proxywatchd.py scraper.py httpd.py; do + if [ -f "$f" ]; then + # Look for .append() without corresponding size limits + if grep -n "\.append(" "$f" | grep -v "# bounded" | grep -v "_max\|max_\|limit\|[:]\|pop(" > /tmp/unbounded 2>/dev/null; then + count=$(wc -l < /tmp/unbounded) + if [ "$count" -gt 20 ]; then + echo "WARN $f: $count potential unbounded appends" + fi + fi + fi + done + + # Check for circular references + echo "Checking for potential circular references..." + for f in ppf.py proxywatchd.py scraper.py httpd.py connection_pool.py; do + if [ -f "$f" ]; then + if grep -n "self\.\w* = self" "$f" 2>/dev/null; then + echo "WARN $f: potential self-reference" + fi + fi + done + + # Check for __del__ methods (often problematic) + echo "Checking for __del__ methods..." + for f in *.py; do + if grep -n "def __del__" "$f" 2>/dev/null; then + echo "WARN $f: has __del__ method (may cause leaks)" + fi + done + + # Check that gc is imported where needed + echo "Checking gc module usage..." + for f in proxywatchd.py httpd.py; do + if [ -f "$f" ]; then + if ! grep -q "^import gc" "$f" && ! grep -q "^from gc" "$f"; then + echo "INFO $f: gc module not imported" + fi + fi + done + + echo "Memory leak pattern scan complete" + + - name: Static import check + run: | + echo "Verifying imports..." + python2 -c " +import sys +sys.path.insert(0, '.') +try: + import config + print('OK config') +except Exception as e: + print('FAIL config:', e) +try: + import misc + print('OK misc') +except Exception as e: + print('FAIL misc:', e) +try: + import mysqlite + print('OK mysqlite') +except Exception as e: + print('FAIL mysqlite:', e) +"