name: Tests on: push: branches: - main - master - dev pull_request: branches: - main - master - dev workflow_dispatch: jobs: lint-frontend: name: Lint Frontend (HTMLHint + ESLint) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Node.js uses: actions/setup-node@v4 with: node-version: "20" cache: npm - name: Install frontend lint tools run: npm ci - name: HTMLHint — lint HTML templates run: npm run lint:html - name: ESLint — lint inline JavaScript run: npm run lint:js lint-shell: name: Lint Shell Scripts (ShellCheck) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install ShellCheck run: sudo apt-get install -y shellcheck - name: ShellCheck — lint all .sh files run: | find . -name "*.sh" \ -not -path "./.git/*" \ -not -path "./node_modules/*" \ -not -path "./.venv/*" \ -not -path "./venv/*" \ -not -path "./dist/*" \ -print0 | xargs -0 shellcheck --severity=warning lint: name: Lint (ruff) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.11" cache: pip - name: Install ruff run: pip install "ruff==0.15.15" - name: ruff check — fail on any lint error # Whole tree, not just modules/ and tests/: scripts/ and the root-level # scripts (meshcore_bot.py, validate_config.py, generate_website.py, …) # ship to users too. Excludes come from pyproject's [tool.ruff]. run: ruff check . - name: Log injection check — fail on new unsanitized logger calls run: python scripts/check_log_injection.py - name: Config validation — fail on unrecognized sections in shipped configs run: | set -e for f in config.ini.example config.ini.minimal-example config.ini.quickstart config.min.ini config-pymc.ini; do if [ -f "$f" ]; then echo "Validating $f" python validate_config.py --config "$f" --strict fi done typecheck: name: Type check (mypy) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.11" cache: pip - name: Install dependencies run: | pip install --upgrade pip pip install -e ".[test,geo]" pip install mypy - name: mypy — strict overrides on typed modules run: mypy modules/ --ignore-missing-imports package: name: Build and smoke-test distributions runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.11" cache: pip - name: Build wheel and source distribution run: | python -m pip install --upgrade pip build twine python -m build python -m twine check dist/* - name: Install and smoke-test wheel outside the source tree run: | python -m venv /tmp/meshcore-wheel-smoke /tmp/meshcore-wheel-smoke/bin/pip install dist/*.whl cd /tmp /tmp/meshcore-wheel-smoke/bin/python "$GITHUB_WORKSPACE/scripts/smoke_test_wheel.py" /tmp/meshcore-wheel-smoke/bin/python "$GITHUB_WORKSPACE/scripts/smoke_test_no_geo.py" /tmp/meshcore-wheel-smoke/bin/meshcore-bot --help >/dev/null /tmp/meshcore-wheel-smoke/bin/meshcore-viewer --help >/dev/null test: name: Tests (Python ${{ matrix.python-version }}) runs-on: ubuntu-latest strategy: fail-fast: false matrix: python-version: ["3.10", "3.11", "3.12", "3.13"] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} cache: pip - name: Install dependencies run: | pip install --upgrade pip # `geo` (us, pycountry) is optional at runtime but drives US state and # country normalization; without it ~27 location tests skip and the AQI # prefix-budget behavior silently differs from a real install. pip install -e ".[test,geo]" - name: Run tests with coverage run: pytest tests/ -v --tb=short