Skip to content

chore(deps): bump the pip-all group across 1 directory with 5 updates #107

chore(deps): bump the pip-all group across 1 directory with 5 updates

chore(deps): bump the pip-all group across 1 directory with 5 updates #107

Workflow file for this run

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