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
33 changes: 24 additions & 9 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ jobs:
run: |
find . -name "*.sh" -not -path "./vendor/*" -exec shellcheck {} +

unit-tests:
name: Unit Tests
php-tests:
name: PHP Tests
runs-on: ubuntu-latest
needs: shellcheck

Expand All @@ -42,12 +42,27 @@ jobs:
run: |
chmod +x php/*.sh
chmod +x php/laravel/*.sh 2>/dev/null || true
chmod +x shell/*.sh 2>/dev/null || true
chmod +x docker/*.sh 2>/dev/null || true
chmod +x simple/*.sh 2>/dev/null || true
chmod +x tests/run_all.sh
chmod +x tests/lib/*.bash
find tests -name "*.sh" -exec chmod +x {} +
find tests/php -name "*.sh" -exec chmod +x {} +

- name: Run all tests
run: ./tests/run_all.sh
- name: Run PHP tests
run: ./tests/php/phpstan/run.sh

python-tests:
name: Python Tests
runs-on: ubuntu-latest
needs: shellcheck

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

- name: Prepare test environment
run: |
chmod +x python/*.sh
chmod +x tests/lib/*.bash
find tests/python -name "*.sh" -exec chmod +x {} +

- name: Run Python tests
run: |
for suite in tests/python/*/run.sh; do "$suite"; done
67 changes: 67 additions & 0 deletions python/check_flake8.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/bin/bash
# ----------------------------------------
# Python Code Style Checker
#
# This script checks Python files for style
# issues using flake8. It runs directly on
# the host (no Docker required).
#
# Usage:
# ./check_style.sh file1.py file2.py ...
# ----------------------------------------

if [ $# -eq 0 ]; then
echo "No files to check"
exit 0
fi

PY_FILES=()
CHECKED_FILES=0
HAS_ERRORS=0

for file in "$@"; do
# Skip non-Python files
if [[ ! "$file" =~ \.py$ ]]; then
continue
fi

# Skip if file doesn't exist
if [ ! -f "$file" ]; then
continue
fi

PY_FILES+=("$file")
done

# Check if there are any Python files to check
if [ ${#PY_FILES[@]} -eq 0 ]; then
echo "No Python files to check"
exit 0
fi

# Run flake8 linter on each file
for file in "${PY_FILES[@]}"; do
CHECKED_FILES=$((CHECKED_FILES + 1))

OUTPUT=$(flake8 --max-line-length=120 "$file" 2>&1)
EXIT_CODE=$?

if [ $EXIT_CODE -ne 0 ]; then
HAS_ERRORS=1
echo "Style errors in: $file"
echo "$OUTPUT"
echo ""
fi
done

# Final result
if [ $HAS_ERRORS -ne 0 ]; then
echo "----------------------------------------"
echo "ERROR: Code style check failed!"
echo "Total files checked: $CHECKED_FILES"
echo "Fix the errors above before committing."
exit 1
fi

echo "Code style check passed! ($CHECKED_FILES files checked)"
exit 0
109 changes: 109 additions & 0 deletions python/check_flake8_in_docker.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#!/bin/bash
# ----------------------------------------
# Python Code Style Checker
#
# This script checks Python files for style
# issues using flake8. It runs directly on
# the host (no Docker required).
#
# Usage:
# ./check_style.sh file1.py file2.py ...
# ----------------------------------------

# -----------------------------
# CONFIG
# -----------------------------
CONTAINER_NAME="app_dev"

# Path mapping: host path prefix -> container path prefix
HOST_APP_PATH="app/"
CONTAINER_APP_PATH="/app/"

# -----------------------------
# FUNCTIONS
# -----------------------------
check_container_running() {
if ! docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
echo "ERROR: Container '$CONTAINER_NAME' is not running"
echo "Start it with: docker-compose -f docker/dev/docker-compose.yml up -d"
exit 1
fi
}

# Convert host path to container path
to_container_path() {
local file="$1"
# Replace app/ with /app/
echo "${file/#${HOST_APP_PATH}/${CONTAINER_APP_PATH}}"
}

# -----------------------------
# MAIN
# -----------------------------
if [ $# -eq 0 ]; then
echo "No files to check"
exit 0
fi

check_container_running

PY_FILES=()
CHECKED_FILES=0
HAS_ERRORS=0

# Collect only .py files from app/ directory
for file in "$@"; do
# Skip non-Python files
if [[ ! "$file" =~ \.py$ ]]; then
continue
fi

# Skip files not in app/ directory (not mounted in container)
if [[ ! "$file" =~ ^app/ ]]; then
continue
fi

# Skip if file doesn't exist
if [ ! -f "$file" ]; then
continue
fi

PY_FILES+=("$file")
done

# Check if there are any Python files to check
if [ ${#PY_FILES[@]} -eq 0 ]; then
echo "No Python files to check"
exit 0
fi

# Run linter on each file via docker exec
for file in "${PY_FILES[@]}"; do
CHECKED_FILES=$((CHECKED_FILES + 1))

container_path=$(to_container_path "$file")

# Run linter inside container
OUTPUT=$(docker exec "$CONTAINER_NAME" flake8 --max-line-length=120 "$container_path" 2>&1)
EXIT_CODE=$?

if [ $EXIT_CODE -ne 0 ]; then
HAS_ERRORS=1
echo "Style errors in: $file"
# Convert container paths back to host paths in output
echo "${OUTPUT//${CONTAINER_APP_PATH}/${HOST_APP_PATH}}"
echo ""
fi
done

# Final result
if [ $HAS_ERRORS -ne 0 ]; then
echo "----------------------------------------"
echo "ERROR: Code style check failed!"
echo "Total files checked: $CHECKED_FILES"
echo "Fix the errors above before committing."
exit 1
fi

echo "Code style check passed! ($CHECKED_FILES files checked)"
exit 0
59 changes: 59 additions & 0 deletions python/check_mypy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/bin/bash

# ------------------------------------------------------------
# Runs mypy static analysis for changed Python files locally.
# Accepts file paths as args and checks only app/*.py files.
# ------------------------------------------------------------

if [ $# -eq 0 ]; then
echo "No files to check"
exit 0
fi

PY_FILES=()

for file in "$@"; do
# Skip non-Python files
if [[ ! "$file" =~ \.py$ ]]; then
continue
fi

# Only files inside app/
if [[ ! "$file" =~ ^app/ ]]; then
continue
fi

# Skip if file doesn't exist
if [ ! -f "$file" ]; then
continue
fi

PY_FILES+=("$file")
done

if [ ${#PY_FILES[@]} -eq 0 ]; then
echo "No Python files to check"
exit 0
fi

OUTPUT=$(mypy \
--pretty \
--show-error-codes \
--ignore-missing-imports \
--follow-imports=skip \
"${PY_FILES[@]}" 2>&1)

EXIT_CODE=$?

if [ $EXIT_CODE -ne 0 ]; then
echo "----------------------------------------"
echo "ERROR: Static analysis failed!"
echo "----------------------------------------"
echo "$OUTPUT"
echo "----------------------------------------"
echo "Total files checked: ${#PY_FILES[@]}"
exit 1
fi

echo "Static analysis passed! (${#PY_FILES[@]} files checked)"
exit 0
85 changes: 85 additions & 0 deletions python/check_mypy_in_docker.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/bin/bash

# ------------------------------------------------------------
# Runs mypy static analysis for changed Python files inside
# the running Docker container. Accepts file paths as args,
# filters only app/*.py, maps them to container paths, and
# executes mypy via docker exec.
# ------------------------------------------------------------

CONTAINER_NAME="app_dev"
HOST_APP_PATH="app/"
CONTAINER_APP_PATH="/app/"

check_container_running() {
if ! docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
echo "ERROR: Container '${CONTAINER_NAME}' is not running"
echo "Start it with: docker-compose -f docker/dev/docker-compose.yml up -d"
exit 1
fi
}

to_container_path() {
local file="$1"
echo "${file/#${HOST_APP_PATH}/${CONTAINER_APP_PATH}}"
}

if [ $# -eq 0 ]; then
echo "No files to check"
exit 0
fi

check_container_running

PY_FILES=()

for file in "$@"; do
# Skip non-Python files
if [[ ! "$file" =~ \.py$ ]]; then
continue
fi

# Skip files not in app/ directory (not mounted in container)
if [[ ! "$file" =~ ^app/ ]]; then
continue
fi

# Skip if file doesn't exist
if [ ! -f "$file" ]; then
continue
fi

PY_FILES+=("$file")
done

if [ ${#PY_FILES[@]} -eq 0 ]; then
echo "No Python files to check"
exit 0
fi

CONTAINER_FILES=()
for file in "${PY_FILES[@]}"; do
CONTAINER_FILES+=("$(to_container_path "$file")")
done

OUTPUT=$(docker exec "$CONTAINER_NAME" mypy \
--pretty \
--show-error-codes \
--ignore-missing-imports \
--follow-imports=skip \
"${CONTAINER_FILES[@]}" 2>&1)

EXIT_CODE=$?

if [ $EXIT_CODE -ne 0 ]; then
echo "----------------------------------------"
echo "ERROR: Static analysis failed!"
echo "----------------------------------------"
echo "${OUTPUT//${CONTAINER_APP_PATH}/${HOST_APP_PATH}}"
echo "----------------------------------------"
echo "Total files checked: ${#PY_FILES[@]}"
exit 1
fi

echo "Static analysis passed! (${#PY_FILES[@]} files checked)"
exit 0
Loading