From 28feeb3599c63a6a15ea6cf3e74fdb22822ce9f7 Mon Sep 17 00:00:00 2001 From: ruscher Date: Fri, 9 Oct 2026 00:11:02 -0300 Subject: [PATCH 1/2] test: unwritable history folder also when tests run as root CI runs in an archlinux container as root, and root ignores a read-only folder: the history was saved and test_unwritable_folder_is_reported_not_raised failed. The folder is now made impossible by giving it a regular file as parent, which stops root too. --- tests/test_history_recovery.py | 19 ++++++++----------- tests/test_tts_streaming.py | 23 +++++++++++------------ 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/tests/test_history_recovery.py b/tests/test_history_recovery.py index 18fed18..8261352 100644 --- a/tests/test_history_recovery.py +++ b/tests/test_history_recovery.py @@ -153,17 +153,14 @@ def test_save_never_overwrites_an_existing_entry(hdir, tmp_path): def test_unwritable_folder_is_reported_not_raised(tmp_path, monkeypatch): - # The Music folder is read-only: the history folder cannot be created. - locked = tmp_path / "locked" - locked.mkdir() - locked.chmod(0o500) - monkeypatch.setattr(hs, "_MUSIC_DIR", locked) - try: - assert hs.save_reading(text="x", backend="rhvoice", voice_id="v") is None - assert hs.new_recording("rhvoice", time.time()) is None - assert hs.repair_history()["error"] == "" # nothing to repair, no crash - finally: - locked.chmod(0o700) + # The history folder cannot be created. (Its parent is a file, not a + # read-only folder: CI runs as root, and root ignores permissions.) + blocker = tmp_path / "blocker" + blocker.write_text("") + monkeypatch.setattr(hs, "_MUSIC_DIR", blocker / "Music") + assert hs.save_reading(text="x", backend="rhvoice", voice_id="v") is None + assert hs.new_recording("rhvoice", time.time()) is None + assert hs.repair_history()["error"] == "" # nothing to repair, no crash def test_durations_of_older_entries_are_filled_in(hdir, tmp_path): diff --git a/tests/test_tts_streaming.py b/tests/test_tts_streaming.py index 1e49438..08df17b 100644 --- a/tests/test_tts_streaming.py +++ b/tests/test_tts_streaming.py @@ -327,18 +327,17 @@ def test_readings_in_sequence_each_have_an_entry(fakes): def test_history_folder_without_permission_never_breaks_reading(fakes, monkeypatch): - locked = fakes / "locked" # read-only Music folder: no history folder possible - locked.mkdir() - locked.chmod(0o500) - monkeypatch.setattr(hs, "_MUSIC_DIR", locked) - try: - svc = ts.TTSService(settings=_settings()) - assert svc.speak("Ainda assim leio.", backend="rhvoice", voice_id="x", volume=50) - _run_watch(svc) - assert svc.state is TTSState.IDLE # the reading itself is fine - assert played(fakes) - finally: - locked.chmod(0o700) + # No history folder possible: its parent is a file (root-proof, unlike a + # read-only folder — CI runs as root). + blocker = fakes / "blocker" + blocker.write_text("") + monkeypatch.setattr(hs, "_MUSIC_DIR", blocker / "Music") + svc = ts.TTSService(settings=_settings()) + assert svc.speak("Ainda assim leio.", backend="rhvoice", voice_id="x", volume=50) + _run_watch(svc) + assert svc.state is TTSState.IDLE # the reading itself is fine + assert played(fakes) + assert not hs.get_history_dir().exists() @pytest.mark.parametrize(("backend", "voice"), [("rhvoice", "x"), ("kokoro", "kokoro:pf_dora")]) From 0acaaf0fafdc7141b073d6a3c11a911a98b1062b Mon Sep 17 00:00:00 2001 From: ruscher Date: Fri, 9 Oct 2026 00:13:39 -0300 Subject: [PATCH 2/2] ci: one run per commit, no translation/build jobs in forks - CI ran every pull request twice: once for the push to its branch and once for the pull_request event. Pushes now trigger it only on main; a newer commit cancels the run it replaces. - Translate and Build Package runs only in the biglinux organization. Forks lack the translation keys and the builder token: the translation step hung until GitHub's 6-hour limit. It now has a 90-minute timeout, and runs on the same branch queue instead of pushing over each other. --- .github/workflows/ci.yml | 10 +++++++++- .github/workflows/translate-and-build-package.yml | 10 ++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index afb2e50..b46966b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,14 +2,22 @@ name: CI # Checks only: nothing is committed or published. Runs in an Arch Linux # container with the official repositories, like the package build. +# A branch with a pull request is checked once, by the pull_request event +# (push alone would run the same commit twice). main is checked on push. on: pull_request: push: - branches: [ "**" ] + branches: [ main ] + workflow_dispatch: permissions: contents: read +# A newer commit on the same pull request or branch replaces the run in progress. +concurrency: + group: ci-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: python: runs-on: ubuntu-latest diff --git a/.github/workflows/translate-and-build-package.yml b/.github/workflows/translate-and-build-package.yml index de407b7..60a95c5 100644 --- a/.github/workflows/translate-and-build-package.yml +++ b/.github/workflows/translate-and-build-package.yml @@ -16,9 +16,19 @@ on: permissions: contents: write +# One run per branch at a time: each one commits and pushes translations. +concurrency: + group: translate-${{ github.ref }} + cancel-in-progress: false + jobs: build: + # Only in the biglinux organization: forks have neither the translation + # keys nor the builder token, and the translation step would hang until + # GitHub's 6-hour limit. + if: github.repository_owner == 'biglinux' runs-on: ubuntu-latest + timeout-minutes: 90 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1