ci: add gitea workflow for syntax and memory leak checks
- Python 2/3 syntax validation - Static analysis for memory leak patterns - Unbounded collection detection - Circular reference checks
This commit is contained in:
129
.gitea/workflows/ci.yml
Normal file
129
.gitea/workflows/ci.yml
Normal file
@@ -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)
|
||||
"
|
||||
Reference in New Issue
Block a user