chore(deps): bump ruff, boto3 and playwright; block librosa 1.0+ on t… #109
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: Integration Tests | |
| on: | |
| pull_request: | |
| branches: [ main, develop ] | |
| push: | |
| branches: [ develop ] | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| # Rapid pushes to the same PR/branch stack Docker + service-container jobs; | |
| # keep only the newest run per ref. | |
| concurrency: | |
| group: "${{ github.workflow }}-${{ github.ref }}" | |
| cancel-in-progress: true | |
| jobs: | |
| integration: | |
| name: Integration (Postgres + SeaweedFS) | |
| runs-on: ubuntu-latest | |
| # Skip for fork PRs — untrusted code could modify requirements/test files | |
| # (guard consistent with test.yml's other jobs). | |
| if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) }} | |
| timeout-minutes: 20 | |
| # Real PostgreSQL via the Actions service container. Health-gated so the | |
| # job's steps don't start until the DB accepts connections. | |
| services: | |
| postgres: | |
| image: postgres:16 | |
| env: | |
| POSTGRES_USER: bitwize | |
| POSTGRES_PASSWORD: bitwize | |
| POSTGRES_DB: bitwize_test | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd "pg_isready -U bitwize -d bitwize_test" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| env: | |
| # The env gate: only with this set do the double-gated integration tests | |
| # actually run (otherwise they skip). Everything else feeds the fixtures. | |
| BITWIZE_INTEGRATION: "1" | |
| PYTHONUTF8: "1" | |
| # Postgres (matches the service container above) | |
| PGHOST: localhost | |
| PGPORT: "5432" | |
| PGDATABASE: bitwize_test | |
| PGUSER: bitwize | |
| PGPASSWORD: bitwize | |
| # SeaweedFS S3 gateway (dummy creds — SeaweedFS with no identity config | |
| # accepts any signed request) | |
| S3_ENDPOINT_URL: http://localhost:8333 | |
| S3_ACCESS_KEY_ID: bitwizekey | |
| S3_SECRET_ACCESS_KEY: bitwizesecret | |
| S3_BUCKET: bitwize-integration | |
| S3_REGION: us-east-1 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Set up Python | |
| uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| python-version: '3.11' | |
| cache: 'pip' | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -r requirements-test.txt | |
| pip install -r requirements.txt | |
| # SeaweedFS as a plain container on the host network so its S3 gateway is | |
| # reachable at localhost:8333 regardless of the binder's default bind | |
| # address. Pinned tag. Anonymous S3 (no -s3.config) accepts the dummy creds. | |
| - name: Start SeaweedFS S3 gateway | |
| run: | | |
| docker run -d --name seaweedfs --network host \ | |
| chrislusf/seaweedfs:4.39 \ | |
| server -s3 | |
| - name: Wait for SeaweedFS S3 endpoint | |
| run: | | |
| for i in $(seq 1 30); do | |
| code=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:8333" || true) | |
| if [ -n "$code" ] && [ "$code" != "000" ]; then | |
| echo "SeaweedFS S3 gateway is up (HTTP $code)" | |
| exit 0 | |
| fi | |
| echo "waiting for SeaweedFS S3 gateway... ($i/30)" | |
| sleep 2 | |
| done | |
| echo "SeaweedFS S3 gateway did not become ready in time" | |
| docker logs seaweedfs || true | |
| exit 1 | |
| - name: Run integration tests | |
| run: | | |
| python -m pytest tests/integration/test_postgres_db_tools.py tests/integration/test_s3_upload_seaweedfs.py -m integration -v --tb=short | |
| - name: SeaweedFS logs (on failure) | |
| if: failure() | |
| run: docker logs seaweedfs || true | |
| musescore: | |
| name: Integration (MuseScore PDF export / ${{ matrix.os }}) | |
| runs-on: ${{ matrix.os }} | |
| # Same fork-PR guard as the other jobs — untrusted code could modify | |
| # requirements/test files. | |
| if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) }} | |
| timeout-minutes: 20 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| # MuseScore is free with a real CLI, so unlike AnthemScore (licensed, | |
| # not CI-testable) its Windows path IS verifiable. choco installs it to | |
| # C:\Program Files\MuseScore 4\bin\MuseScore4.exe — the first entry in | |
| # find_musescore()'s Windows table, which detects it with no help. | |
| os: [ubuntu-latest, windows-latest] | |
| env: | |
| # The env gate: only with this set does the double-gated MuseScore test | |
| # actually run (otherwise it collect-and-skips like the normal suite). | |
| BITWIZE_INTEGRATION: "1" | |
| PYTHONUTF8: "1" | |
| # Linux only: MuseScore is a Qt GUI app, so its CLI runs headless via the | |
| # offscreen platform plugin. Windows runners have an interactive session, | |
| # so no platform override is needed (empty = Qt's default plugin). | |
| QT_QPA_PLATFORM: ${{ matrix.os == 'ubuntu-latest' && 'offscreen' || '' }} | |
| # Linux only: apt `musescore3` installs /usr/bin/mscore3, which | |
| # find_musescore() detects on its own; this is a belt-and-braces fallback. | |
| # On Windows find_musescore() resolves MuseScore4.exe directly, so the | |
| # test never consults this (find_musescore() or MUSESCORE_BIN). | |
| MUSESCORE_BIN: ${{ matrix.os == 'ubuntu-latest' && '/usr/bin/mscore3' || '' }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Set up Python | |
| uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| python-version: '3.11' | |
| cache: 'pip' | |
| - name: Install MuseScore (musescore3) + xvfb | |
| if: runner.os == 'Linux' | |
| run: | | |
| sudo apt-get update | |
| # xvfb is a headless fallback if the offscreen plugin misbehaves on the | |
| # runner; the primary path is QT_QPA_PLATFORM=offscreen. | |
| sudo apt-get install -y musescore3 xvfb | |
| echo "mscore3 on PATH: $(command -v mscore3 || echo '(not on PATH)')" | |
| ls -l /usr/bin/mscore3 /usr/bin/musescore3 || true | |
| - name: Install MuseScore (Chocolatey) | |
| if: runner.os == 'Windows' | |
| run: choco install musescore -y --no-progress | |
| - name: MuseScore diagnostics | |
| shell: bash | |
| run: | | |
| # Cross-platform: bash resolves to Git Bash on the Windows runner. Prints | |
| # what the product's own detector finds, on whichever OS this leg is. | |
| python -c "import importlib.util as u, sys; sys.path.insert(0, '.'); \ | |
| s = u.spec_from_file_location('ps', 'tools/sheet-music/prepare_singles.py'); \ | |
| m = u.module_from_spec(s); s.loader.exec_module(m); \ | |
| print('find_musescore() ->', m.find_musescore())" | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -r requirements-test.txt | |
| pip install -r requirements.txt | |
| - name: Run MuseScore integration test (Linux) | |
| if: runner.os == 'Linux' | |
| run: | | |
| python -m pytest tests/integration/test_musescore_export.py -m integration -v --tb=short | |
| # MuseScore 4's FIRST launch on a clean Windows profile initializes its | |
| # AppData tree (settings + the crashpad logs/dumps dirs). The very first CLI | |
| # invocation races that init and its export intermittently (~1 in 2) fails | |
| # with a crashpad error: | |
| # filesystem_win.cc GetFileAttributes ...\logs\dumps\attachments\...: cannot find | |
| # Warm up once (pre-create the crashpad dir + a throwaway convert, tolerating | |
| # failure) so the profile is initialized, then run the real test with a | |
| # couple of retries as belt-and-braces. A persistent failure — all attempts — | |
| # still fails the job, so this masks only the first-launch race, not a real | |
| # regression. | |
| - name: Warm up MuseScore and run integration test (Windows) | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| $bin = "C:\Program Files\MuseScore 4\bin\MuseScore4.exe" | |
| $dumps = Join-Path $env:LOCALAPPDATA "MuseScore\MuseScore4\logs\dumps\attachments" | |
| New-Item -ItemType Directory -Force -Path $dumps | Out-Null | |
| $warmup = Join-Path $env:RUNNER_TEMP "warmup.pdf" | |
| $fixture = "tests\integration\fixtures\minimal.musicxml" | |
| Write-Host "== warm-up convert (first-launch profile init; failure tolerated) ==" | |
| & $bin -o $warmup $fixture 2>&1 | Out-Host | |
| Write-Host "warm-up exit: $LASTEXITCODE (tolerated)" | |
| $attempts = 3 | |
| for ($i = 1; $i -le $attempts; $i++) { | |
| Write-Host "== MuseScore integration test attempt $i/$attempts ==" | |
| python -m pytest tests/integration/test_musescore_export.py -m integration -v --tb=short | |
| if ($LASTEXITCODE -eq 0) { Write-Host "passed on attempt $i"; exit 0 } | |
| Write-Host "attempt $i failed (exit $LASTEXITCODE)" | |
| Start-Sleep -Seconds 3 | |
| } | |
| Write-Host "::error::MuseScore integration test failed all $attempts attempts (not the first-launch flake)" | |
| exit 1 | |
| afconvert: | |
| name: Integration (ADM afconvert / macOS) | |
| runs-on: macos-latest | |
| # Same fork-PR guard as the other jobs — untrusted code could modify | |
| # requirements/test files. | |
| if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) }} | |
| timeout-minutes: 20 | |
| env: | |
| # The env gate: only with this set does the double-gated afconvert test | |
| # actually run (otherwise it collect-and-skips like the normal suite). | |
| # afconvert is a built-in macOS system binary, so — unlike the | |
| # Postgres/MuseScore jobs — nothing installs it; only ffmpeg is added. | |
| BITWIZE_INTEGRATION: "1" | |
| PYTHONUTF8: "1" | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Set up Python | |
| uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| python-version: '3.11' | |
| cache: 'pip' | |
| - name: Install ffmpeg (Homebrew) | |
| # ffmpeg generates the WAV fixture (lavfi) and decodes afconvert's m4a. | |
| run: brew install ffmpeg | |
| - name: afconvert diagnostics | |
| run: | | |
| # afconvert ships with macOS — no install. The product probes for it by | |
| # PRESENCE (shutil.which), not by running `afconvert --help`, precisely | |
| # because `afconvert --help` exits 2 on macOS (a usage convention) — the | |
| # old check=True probe caught that and silently disabled afconvert on | |
| # every mac. So just prove presence here; do NOT gate on --help's exit. | |
| which afconvert | |
| # `afconvert --help` exits 2 by convention — capture it without failing | |
| # the step (documents the exact behaviour the presence-probe sidesteps). | |
| set +e | |
| afconvert --help >/dev/null 2>&1 | |
| echo "afconvert --help exit code: $? (non-zero is expected and harmless)" | |
| set -e | |
| ffmpeg -version | head -1 | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -r requirements-test.txt | |
| pip install -r requirements.txt | |
| - name: Run afconvert integration test | |
| run: | | |
| python -m pytest tests/integration/test_afconvert_macos.py -m integration -v --tb=short |