chore(deps): bump grafana/grafana from 12.4.10 to 13.2.1 #652
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Test Suite | |
| on: | |
| pull_request: | |
| branches: [main, develop] | |
| push: | |
| branches: [main, develop] | |
| workflow_dispatch: | |
| # One run per workflow per ref. Merging a queue of dependency PRs fires a | |
| # run per commit on main, and every one but the newest is already stale by | |
| # the time a runner picks it up. | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| validate-compose: | |
| name: Validate Docker Compose | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v4 | |
| - name: Validate docker-compose.yml | |
| run: | | |
| docker compose config > /dev/null | |
| echo "✓ docker-compose.yml is valid" | |
| - name: Check for docker-compose syntax issues | |
| run: | | |
| docker compose config --quiet | |
| echo "✓ No syntax errors found" | |
| validate-env: | |
| name: Validate Environment Configuration | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Validate .env.example exists | |
| run: | | |
| if [ ! -f .env.example ]; then | |
| echo "✗ .env.example not found" | |
| exit 1 | |
| fi | |
| echo "✓ .env.example exists" | |
| - name: Check .env.example format | |
| run: | | |
| # Check for basic environment variable format | |
| if ! grep -qE '^[A-Z_]+=.*$' .env.example; then | |
| echo "✗ .env.example has invalid format" | |
| exit 1 | |
| fi | |
| echo "✓ .env.example format is valid" | |
| - name: Check for required variables | |
| run: | | |
| required_vars=( | |
| "VAULT_ADDR" | |
| "VAULT_TOKEN" | |
| "POSTGRES_USER" | |
| "POSTGRES_DB" | |
| "POSTGRES_PASSWORD" | |
| "MYSQL_USER" | |
| "MYSQL_DATABASE" | |
| "RABBITMQ_VHOST" | |
| "MONGODB_USER" | |
| "MONGODB_DATABASE" | |
| ) | |
| missing=0 | |
| for var in "${required_vars[@]}"; do | |
| if ! grep -q "^${var}=" .env.example; then | |
| echo "✗ Missing required variable: $var" | |
| missing=1 | |
| fi | |
| done | |
| if [ $missing -eq 1 ]; then | |
| exit 1 | |
| fi | |
| echo "✓ All required variables present (Vault-managed credentials)" | |
| validate-scripts: | |
| name: Validate Shell Scripts | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Check script executability | |
| run: | | |
| scripts=( | |
| "manage-colima.sh" | |
| "configs/vault/scripts/vault-init.sh" | |
| "configs/vault/scripts/vault-bootstrap.sh" | |
| ) | |
| for script in "${scripts[@]}"; do | |
| if [ -f "$script" ] && [ ! -x "$script" ]; then | |
| echo "✗ Script not executable: $script" | |
| exit 1 | |
| fi | |
| done | |
| echo "✓ All scripts are executable" | |
| - name: Check for bash shebangs | |
| run: | | |
| scripts=$(find . -name "*.sh" -type f) | |
| for script in $scripts; do | |
| shebang=$(head -n 1 "$script") | |
| if [[ ! "$shebang" =~ ^#!/bin/bash$ ]] && \ | |
| [[ ! "$shebang" =~ ^#!/usr/bin/env\ bash$ ]] && \ | |
| [[ ! "$shebang" =~ ^#!/bin/sh$ ]]; then | |
| echo "✗ Missing or incorrect shebang in: $script" | |
| echo " Found: $shebang" | |
| echo " Expected: #!/bin/bash, #!/usr/bin/env bash, or #!/bin/sh" | |
| exit 1 | |
| fi | |
| done | |
| echo "✓ All scripts have proper shebangs" | |
| validate-configs: | |
| name: Validate Configuration Files | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Validate JSON files | |
| run: | | |
| json_files=$(find configs -name "*.json" -type f) | |
| if [ -n "$json_files" ]; then | |
| for file in $json_files; do | |
| if ! python3 -m json.tool "$file" > /dev/null 2>&1; then | |
| echo "✗ Invalid JSON in: $file" | |
| exit 1 | |
| fi | |
| done | |
| echo "✓ All JSON files are valid" | |
| else | |
| echo "ℹ No JSON files to validate" | |
| fi | |
| - name: Validate YAML files | |
| run: | | |
| yaml_files=$(find configs -name "*.yml" -o -name "*.yaml" -type f) | |
| if [ -n "$yaml_files" ]; then | |
| pip install pyyaml | |
| for file in $yaml_files; do | |
| if ! python3 -c "import yaml; yaml.safe_load(open('$file'))" 2>/dev/null; then | |
| echo "✗ Invalid YAML in: $file" | |
| exit 1 | |
| fi | |
| done | |
| echo "✓ All YAML files are valid" | |
| else | |
| echo "ℹ No YAML files to validate" | |
| fi | |
| test-documentation: | |
| name: Test Documentation | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Check README exists and is not empty | |
| run: | | |
| if [ ! -f README.md ]; then | |
| echo "✗ README.md not found" | |
| exit 1 | |
| fi | |
| if [ ! -s README.md ]; then | |
| echo "✗ README.md is empty" | |
| exit 1 | |
| fi | |
| echo "✓ README.md exists and has content" | |
| # wiki/ is left out on purpose: it mirrors GitHub-wiki pages, whose links | |
| # are wiki page names and verbatim copies of docs/ paths that resolve on | |
| # the wiki, never in this tree (27 of them fail here, none elsewhere). | |
| # The checker is pinned because 3.13.x exited 0 on dead links; the | |
| # "ERROR:" marker is a second detector in case that ever recurs. The | |
| # config counts 403 and 429 as alive: bot protection (dev.mysql.com) | |
| # and rate limiting answer those to a CI runner, while a removed page | |
| # answers 404 or 410 and still fails. | |
| - name: Check for broken markdown links | |
| run: | | |
| npm install --no-save --no-package-lock --no-audit --no-fund markdown-link-check@3.15.0 | |
| checked=0 | |
| failed=0 | |
| while read -r file; do | |
| checked=$((checked + 1)) | |
| # The runner's bash -e would end the script on the first failing | |
| # substitution, before anything is printed; `|| rc=$?` keeps the | |
| # loop alive so every file is reported. | |
| rc=0 | |
| out=$(./node_modules/.bin/markdown-link-check -q \ | |
| -c .github/workflows/markdown-link-check-config.json "$file" 2>&1) || rc=$? | |
| if [ "$rc" -ne 0 ] || echo "$out" | grep -q "ERROR:"; then | |
| echo "$out" | |
| failed=$((failed + 1)) | |
| fi | |
| done < <(find . -name '*.md' -not -path './wiki/*' -not -path '*/node_modules/*' | sort) | |
| echo "Checked $checked Markdown files, $failed with dead links" | |
| [ "$failed" -eq 0 ] | |
| # tests/test-documentation-accuracy.sh cross-checks the documentation | |
| # against docker-compose.yml, the AppRole bootstrap and the wiki | |
| # mirror. It had never run in CI, and three of its tests had drifted | |
| # red unnoticed; from here on it gates. | |
| - name: Check documentation accuracy | |
| run: bash tests/test-documentation-accuracy.sh | |
| - name: Validate required documentation sections | |
| run: | | |
| required_sections=( | |
| "Quick Start" | |
| "Installation" | |
| "Prerequisites" | |
| "Services" | |
| "Troubleshooting" | |
| ) | |
| for section in "${required_sections[@]}"; do | |
| if ! grep -qi "## $section" README.md; then | |
| echo "⚠ Missing recommended section: $section" | |
| fi | |
| done | |
| echo "✓ Documentation validation complete" | |
| test-python: | |
| name: Test Python Scripts | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Set up Python | |
| uses: actions/setup-python@v7 | |
| with: | |
| python-version: '3.11' | |
| - name: Check Python syntax | |
| run: | | |
| python_files=$(find scripts tests -name "*.py" -type f) | |
| if [ -n "$python_files" ]; then | |
| for file in $python_files; do | |
| if ! python3 -m py_compile "$file"; then | |
| echo "✗ Syntax error in: $file" | |
| exit 1 | |
| fi | |
| done | |
| echo "✓ All Python files have valid syntax" | |
| else | |
| echo "ℹ No Python files to validate" | |
| fi | |
| unit-tests: | |
| name: Unit Tests | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Set up Python | |
| uses: actions/setup-python@v7 | |
| with: | |
| python-version: '3.11' | |
| - name: Set up Go | |
| uses: actions/setup-go@v7 | |
| with: | |
| go-version-file: 'reference-apps/golang/go.mod' | |
| - name: Set up Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| # Current LTS. The mongodb driver both Node.js apps pin requires | |
| # Node >= 20, which the node:18-alpine images they ship do not meet; | |
| # that is a Dockerfile problem to fix separately, not a reason to test | |
| # on a runtime the dependencies reject. | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v7 | |
| with: | |
| node-version: '22' | |
| - name: Install Python test dependencies | |
| run: | | |
| pip install pytest pytest-asyncio pytest-cov pytest-mock httpx | |
| - name: Run FastAPI unit tests | |
| run: | | |
| cd reference-apps/fastapi | |
| pip install -r requirements.txt | |
| # Run tests that don't require external services | |
| pytest tests/ -v --ignore=tests/test_integration.py -k "not integration" \ | |
| --tb=short | |
| - name: Run Go unit tests | |
| run: | | |
| cd reference-apps/golang | |
| go test -v -short ./... | |
| - name: Run Rust unit tests | |
| run: | | |
| cd reference-apps/rust | |
| # The package is a single binary crate; --lib finds no target. | |
| cargo test -- --test-threads=1 | |
| - name: Run Node.js unit tests | |
| run: | | |
| cd reference-apps/nodejs | |
| npm ci | |
| npm test | |
| - name: Run TypeScript unit tests | |
| run: | | |
| cd reference-apps/typescript-api-first | |
| npm ci | |
| npm test | |
| - name: Test summary | |
| run: | | |
| echo "==========================================" | |
| echo "Unit Test Summary" | |
| echo "==========================================" | |
| echo "" | |
| echo "Unit tests that need no running services were executed for the" | |
| echo "FastAPI, Go, Rust, Node.js and TypeScript reference apps." | |
| echo "" | |
| echo "For full integration tests, run locally with:" | |
| echo " ./devstack start --profile standard" | |
| echo " ./tests/run-all-tests.sh" | |
| integration-test: | |
| name: Integration Test (Basic) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Create .env from example | |
| run: cp .env.example .env | |
| - name: Validate Docker Compose can parse files | |
| run: | | |
| docker compose config > /dev/null | |
| echo "✓ Docker Compose configuration is valid" | |
| - name: Check service definitions (no profile) | |
| run: | | |
| services=$(docker compose config --services) | |
| echo "Services with no profile: $services" | |
| # Vault should always be available (no profile) | |
| if ! echo "$services" | grep -q "^vault$"; then | |
| echo "✗ Missing vault (should have no profile)" | |
| exit 1 | |
| fi | |
| echo "✓ Vault is defined (no profile required)" | |
| - name: Check minimal profile services | |
| run: | | |
| services=$(docker compose --profile minimal config --services) | |
| expected_services=( | |
| "vault" | |
| "postgres" | |
| "pgbouncer" | |
| "redis-1" | |
| "forgejo" | |
| ) | |
| echo "Minimal profile services:" | |
| echo "$services" | |
| for service in "${expected_services[@]}"; do | |
| if ! echo "$services" | grep -q "^${service}$"; then | |
| echo "✗ Missing expected service in minimal profile: $service" | |
| exit 1 | |
| fi | |
| done | |
| echo "✓ All minimal profile services are defined" | |
| - name: Check standard profile services | |
| run: | | |
| services=$(docker compose --profile standard config --services) | |
| expected_services=( | |
| "vault" | |
| "postgres" | |
| "pgbouncer" | |
| "mysql" | |
| "mongodb" | |
| "redis-1" | |
| "redis-2" | |
| "redis-3" | |
| "rabbitmq" | |
| "forgejo" | |
| ) | |
| echo "Standard profile services:" | |
| echo "$services" | |
| for service in "${expected_services[@]}"; do | |
| if ! echo "$services" | grep -q "^${service}$"; then | |
| echo "✗ Missing expected service in standard profile: $service" | |
| exit 1 | |
| fi | |
| done | |
| echo "✓ All standard profile services are defined" | |
| test-summary: | |
| name: Test Summary | |
| runs-on: ubuntu-latest | |
| needs: | |
| - validate-compose | |
| - validate-env | |
| - validate-scripts | |
| - validate-configs | |
| - test-documentation | |
| - test-python | |
| - unit-tests | |
| - integration-test | |
| if: always() | |
| steps: | |
| - name: Check test results | |
| run: | | |
| failed=0 | |
| if [ "${{ needs.validate-compose.result }}" != "success" ]; then | |
| echo "❌ Docker Compose validation failed" | |
| failed=1 | |
| fi | |
| if [ "${{ needs.validate-env.result }}" != "success" ]; then | |
| echo "❌ Environment validation failed" | |
| failed=1 | |
| fi | |
| if [ "${{ needs.validate-scripts.result }}" != "success" ]; then | |
| echo "❌ Script validation failed" | |
| failed=1 | |
| fi | |
| if [ "${{ needs.validate-configs.result }}" != "success" ]; then | |
| echo "❌ Config validation failed" | |
| failed=1 | |
| fi | |
| if [ "${{ needs.test-documentation.result }}" != "success" ]; then | |
| echo "❌ Documentation tests failed" | |
| failed=1 | |
| fi | |
| if [ "${{ needs.test-python.result }}" != "success" ]; then | |
| echo "❌ Python syntax check failed" | |
| failed=1 | |
| fi | |
| if [ "${{ needs.integration-test.result }}" != "success" ]; then | |
| echo "❌ Integration tests failed" | |
| failed=1 | |
| fi | |
| if [ "${{ needs.unit-tests.result }}" != "success" ]; then | |
| echo "❌ Unit tests failed" | |
| failed=1 | |
| fi | |
| if [ $failed -eq 1 ]; then | |
| exit 1 | |
| fi | |
| echo "✅ All tests passed" |