refrain 0.5.2__tar.gz → 0.5.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {refrain-0.5.2 → refrain-0.5.3}/.github/ISSUE_TEMPLATE/bug_report.yml +12 -3
- {refrain-0.5.2 → refrain-0.5.3}/.github/codeql/codeql-config.yml +1 -1
- {refrain-0.5.2 → refrain-0.5.3}/.github/pull_request_template.md +1 -0
- {refrain-0.5.2 → refrain-0.5.3}/.github/workflows/codeql.yml +3 -3
- {refrain-0.5.2 → refrain-0.5.3}/.github/workflows/release.yml +142 -34
- {refrain-0.5.2 → refrain-0.5.3}/.github/workflows/security.yml +14 -9
- refrain-0.5.3/.github/workflows/tests.yml +106 -0
- {refrain-0.5.2 → refrain-0.5.3}/CHANGELOG.md +296 -6
- {refrain-0.5.2 → refrain-0.5.3}/CONTRIBUTING.md +18 -9
- {refrain-0.5.2 → refrain-0.5.3}/LEGAL.md +39 -13
- refrain-0.5.3/LICENSE +109 -0
- {refrain-0.5.2 → refrain-0.5.3}/PKG-INFO +255 -79
- {refrain-0.5.2 → refrain-0.5.3}/PRIVACY.md +58 -27
- {refrain-0.5.2 → refrain-0.5.3}/README.md +250 -74
- {refrain-0.5.2 → refrain-0.5.3}/SECURITY.md +42 -6
- {refrain-0.5.2 → refrain-0.5.3}/docs/architecture.md +11 -7
- refrain-0.5.3/docs/bluetooth.md +152 -0
- refrain-0.5.3/docs/developer-mode.md +114 -0
- {refrain-0.5.2 → refrain-0.5.3}/docs/faq.md +43 -23
- {refrain-0.5.2 → refrain-0.5.3}/docs/lastfm.md +19 -10
- refrain-0.5.3/docs/releases.md +40 -0
- refrain-0.5.2/ROADMAP.md → refrain-0.5.3/docs/roadmap.md +47 -2
- {refrain-0.5.2 → refrain-0.5.3}/docs/screenshots/README.md +40 -27
- refrain-0.5.3/docs/screenshots/discord-rpc-light.png +0 -0
- refrain-0.5.3/docs/screenshots/discord-rpc.png +0 -0
- refrain-0.5.3/docs/screenshots/history-light.png +0 -0
- refrain-0.5.3/docs/screenshots/history.png +0 -0
- refrain-0.5.3/docs/screenshots/legal-light.png +0 -0
- refrain-0.5.3/docs/screenshots/legal.png +0 -0
- refrain-0.5.3/docs/screenshots/live-log-light.png +0 -0
- refrain-0.5.3/docs/screenshots/live-log.png +0 -0
- refrain-0.5.3/docs/screenshots/notification-light.png +0 -0
- refrain-0.5.3/docs/screenshots/notification.png +0 -0
- refrain-0.5.3/docs/screenshots/render.py +411 -0
- refrain-0.5.3/docs/screenshots/settings-advanced-light.png +0 -0
- refrain-0.5.3/docs/screenshots/settings-advanced.png +0 -0
- refrain-0.5.3/docs/screenshots/settings-general-light.png +0 -0
- refrain-0.5.3/docs/screenshots/settings-general.png +0 -0
- refrain-0.5.3/docs/screenshots/settings-history-light.png +0 -0
- refrain-0.5.3/docs/screenshots/settings-history.png +0 -0
- refrain-0.5.3/docs/screenshots/settings-lastfm-light.png +0 -0
- refrain-0.5.3/docs/screenshots/settings-lastfm.png +0 -0
- refrain-0.5.3/docs/screenshots/settings-sources-light.png +0 -0
- refrain-0.5.3/docs/screenshots/settings-sources.png +0 -0
- refrain-0.5.3/docs/screenshots/settings-updates-light.png +0 -0
- refrain-0.5.3/docs/screenshots/settings-updates.png +0 -0
- refrain-0.5.3/docs/screenshots/social.py +100 -0
- refrain-0.5.3/docs/screenshots/status-light.png +0 -0
- refrain-0.5.3/docs/screenshots/status.png +0 -0
- refrain-0.5.3/docs/screenshots/tray-menu-light.png +0 -0
- refrain-0.5.3/docs/screenshots/tray-menu.png +0 -0
- refrain-0.5.3/docs/screenshots/update-dialog-light.png +0 -0
- refrain-0.5.3/docs/screenshots/update-dialog.png +0 -0
- refrain-0.5.3/docs/screenshots/welcome-light.png +0 -0
- refrain-0.5.3/docs/screenshots/welcome.png +0 -0
- refrain-0.5.3/docs/social-preview.png +0 -0
- refrain-0.5.3/docs/stats.py +245 -0
- {refrain-0.5.2 → refrain-0.5.3}/docs/test-matrix.md +18 -14
- refrain-0.5.3/docs/troubleshooting.md +368 -0
- {refrain-0.5.2 → refrain-0.5.3}/packaging/README.md +94 -13
- refrain-0.5.3/packaging/appimage/AppImageBuilder.yml +64 -0
- refrain-0.5.3/packaging/appimage/prune_qt.py +95 -0
- refrain-0.5.3/packaging/appimage/third_party_notices.py +240 -0
- {refrain-0.5.2 → refrain-0.5.3}/packaging/aur/refrain/.SRCINFO +2 -2
- {refrain-0.5.2 → refrain-0.5.3}/packaging/aur/refrain/PKGBUILD +2 -4
- {refrain-0.5.2 → refrain-0.5.3}/packaging/aur/refrain-git/.SRCINFO +2 -1
- {refrain-0.5.2 → refrain-0.5.3}/packaging/aur/refrain-git/PKGBUILD +5 -2
- {refrain-0.5.2 → refrain-0.5.3}/packaging/flatpak/io.github.Rockykln.Refrain.metainfo.xml +22 -26
- {refrain-0.5.2 → refrain-0.5.3}/packaging/flatpak/io.github.Rockykln.Refrain.yaml +8 -3
- refrain-0.5.3/packaging/release_key.py +263 -0
- {refrain-0.5.2 → refrain-0.5.3}/pyproject.toml +7 -16
- refrain-0.5.3/requirements-dev.lock +732 -0
- refrain-0.5.3/requirements-lowest.txt +4 -0
- refrain-0.5.3/requirements.txt +3 -0
- refrain-0.5.3/src/refrain/__init__.py +1 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/app.py +392 -97
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/autostart.py +19 -7
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/browser.py +2 -9
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/config.py +259 -27
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/cover_art.py +121 -34
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/cover_fetcher.py +164 -64
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/daemon.py +292 -129
- refrain-0.5.3/src/refrain/dev_metrics.py +547 -0
- refrain-0.5.3/src/refrain/diagnostics.py +110 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/discord_app.py +5 -18
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/discord_rpc.py +337 -60
- refrain-0.5.3/src/refrain/ed25519.py +101 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/history.py +33 -30
- refrain-0.5.3/src/refrain/i18n/refrain_cs.qm +0 -0
- refrain-0.5.3/src/refrain/i18n/refrain_cs.ts +2151 -0
- refrain-0.5.3/src/refrain/i18n/refrain_de.qm +0 -0
- refrain-0.5.3/src/refrain/i18n/refrain_de.ts +2144 -0
- refrain-0.5.3/src/refrain/i18n/refrain_en.qm +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/i18n/refrain_en.ts +27 -5
- refrain-0.5.3/src/refrain/i18n/refrain_es.qm +0 -0
- refrain-0.5.3/src/refrain/i18n/refrain_es.ts +2144 -0
- refrain-0.5.3/src/refrain/i18n/refrain_fr.qm +0 -0
- refrain-0.5.3/src/refrain/i18n/refrain_fr.ts +2144 -0
- refrain-0.5.3/src/refrain/i18n/refrain_it.qm +0 -0
- refrain-0.5.3/src/refrain/i18n/refrain_it.ts +2144 -0
- refrain-0.5.3/src/refrain/i18n/refrain_ja.qm +0 -0
- refrain-0.5.3/src/refrain/i18n/refrain_ja.ts +2137 -0
- refrain-0.5.3/src/refrain/i18n/refrain_ko.qm +0 -0
- refrain-0.5.3/src/refrain/i18n/refrain_ko.ts +2137 -0
- refrain-0.5.3/src/refrain/i18n/refrain_nl.qm +0 -0
- refrain-0.5.3/src/refrain/i18n/refrain_nl.ts +2144 -0
- refrain-0.5.3/src/refrain/i18n/refrain_pl.qm +0 -0
- refrain-0.5.3/src/refrain/i18n/refrain_pl.ts +2151 -0
- refrain-0.5.3/src/refrain/i18n/refrain_pt.qm +0 -0
- refrain-0.5.3/src/refrain/i18n/refrain_pt.ts +2144 -0
- refrain-0.5.3/src/refrain/i18n/refrain_ru.qm +0 -0
- refrain-0.5.3/src/refrain/i18n/refrain_ru.ts +2151 -0
- refrain-0.5.3/src/refrain/i18n/refrain_sv.qm +0 -0
- refrain-0.5.3/src/refrain/i18n/refrain_sv.ts +2144 -0
- refrain-0.5.3/src/refrain/i18n/refrain_tr.qm +0 -0
- refrain-0.5.3/src/refrain/i18n/refrain_tr.ts +2137 -0
- refrain-0.5.3/src/refrain/i18n/refrain_uk.qm +0 -0
- refrain-0.5.3/src/refrain/i18n/refrain_uk.ts +2151 -0
- refrain-0.5.3/src/refrain/i18n/refrain_zh_CN.qm +0 -0
- refrain-0.5.3/src/refrain/i18n/refrain_zh_CN.ts +2137 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/logging_setup.py +27 -1
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/paths.py +7 -1
- refrain-0.5.3/src/refrain/qt_libraries.py +115 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/scrobble.py +75 -45
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/scrobble_queue.py +75 -25
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/secrets_store.py +28 -39
- refrain-0.5.3/src/refrain/service_status.py +139 -0
- refrain-0.5.3/src/refrain/single_instance.py +114 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/song_lengths.py +45 -23
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/sources/bluetooth.py +69 -61
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/sources/mpris.py +203 -102
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/sources/mpris_server.py +34 -32
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/startup_check.py +3 -17
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/timing.py +60 -48
- refrain-0.5.3/src/refrain/ui/clock.py +43 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/ui/cursors.py +29 -16
- refrain-0.5.3/src/refrain/ui/external_link.py +33 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/ui/history_window.py +201 -83
- refrain-0.5.3/src/refrain/ui/layout_check.py +281 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/ui/legal_dialog.py +50 -31
- refrain-0.5.3/src/refrain/ui/log_window.py +473 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/ui/settings_window.py +800 -304
- refrain-0.5.3/src/refrain/ui/status_window.py +908 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/ui/tray.py +148 -79
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/ui/update_dialog.py +35 -15
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/ui/welcome_dialog.py +40 -40
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/uninstall.py +11 -27
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/updater.py +215 -67
- refrain-0.5.3/tests/conftest.py +110 -0
- refrain-0.5.3/tests/daemon_fakes.py +359 -0
- refrain-0.5.3/tests/release_signing.py +18 -0
- refrain-0.5.3/tests/test_app_cli.py +184 -0
- refrain-0.5.3/tests/test_app_edges.py +225 -0
- refrain-0.5.3/tests/test_app_helpers.py +241 -0
- refrain-0.5.3/tests/test_app_main.py +1287 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_autostart.py +31 -0
- refrain-0.5.3/tests/test_autostart_more.py +107 -0
- refrain-0.5.3/tests/test_bluetooth_apps.py +105 -0
- refrain-0.5.3/tests/test_bluetooth_source.py +473 -0
- refrain-0.5.3/tests/test_browser.py +128 -0
- refrain-0.5.3/tests/test_browser_edges.py +28 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_button_url.py +5 -6
- refrain-0.5.3/tests/test_clock.py +57 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_config.py +97 -20
- refrain-0.5.3/tests/test_config_edges.py +143 -0
- refrain-0.5.3/tests/test_config_notifications.py +40 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_config_preserve.py +2 -6
- refrain-0.5.3/tests/test_config_validation.py +227 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_cover_art.py +77 -39
- refrain-0.5.3/tests/test_cover_art_edges.py +79 -0
- refrain-0.5.3/tests/test_cover_art_more.py +214 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_cover_fetcher.py +18 -34
- refrain-0.5.3/tests/test_cover_fetcher_cache.py +225 -0
- refrain-0.5.3/tests/test_cover_fetcher_edges.py +105 -0
- refrain-0.5.3/tests/test_cover_history.py +150 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_crash_log.py +2 -2
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_daemon_album_format.py +3 -8
- refrain-0.5.3/tests/test_daemon_edges.py +131 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_daemon_idle.py +8 -26
- refrain-0.5.3/tests/test_daemon_lifecycle.py +496 -0
- refrain-0.5.3/tests/test_daemon_pipeline.py +609 -0
- refrain-0.5.3/tests/test_daemon_service_states.py +143 -0
- refrain-0.5.3/tests/test_daemon_stop.py +45 -0
- refrain-0.5.3/tests/test_daemon_tick_lookups.py +120 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_dbus_dispatch.py +8 -35
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_desktop_entries.py +19 -0
- refrain-0.5.3/tests/test_dev_metrics.py +425 -0
- refrain-0.5.3/tests/test_developer_mode_ui.py +334 -0
- refrain-0.5.3/tests/test_diagnostics.py +96 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_discord_app.py +8 -32
- refrain-0.5.3/tests/test_discord_app_edges.py +26 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_discord_ipc_scan.py +1 -16
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_discord_listening.py +1 -6
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_discord_multi_client.py +14 -32
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_discord_rpc.py +87 -25
- refrain-0.5.3/tests/test_discord_rpc_connect.py +367 -0
- refrain-0.5.3/tests/test_discord_rpc_robustness.py +617 -0
- refrain-0.5.3/tests/test_ed25519.py +183 -0
- refrain-0.5.3/tests/test_external_link.py +58 -0
- refrain-0.5.3/tests/test_foreign_locales.py +88 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_history.py +40 -11
- refrain-0.5.3/tests/test_history_edges.py +261 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_history_window.py +205 -21
- refrain-0.5.3/tests/test_history_window_edges.py +212 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_imports.py +2 -7
- refrain-0.5.3/tests/test_layout_check.py +341 -0
- refrain-0.5.3/tests/test_layout_languages.py +113 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_legal_notice.py +6 -14
- refrain-0.5.3/tests/test_log_window_filter.py +47 -0
- refrain-0.5.3/tests/test_logging_setup.py +128 -0
- refrain-0.5.3/tests/test_logging_setup_edges.py +59 -0
- refrain-0.5.3/tests/test_mpris_controls.py +137 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_mpris_dispatch.py +16 -26
- refrain-0.5.3/tests/test_mpris_edges.py +117 -0
- refrain-0.5.3/tests/test_mpris_server_props.py +381 -0
- refrain-0.5.3/tests/test_mpris_source_more.py +603 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_notify_argv.py +6 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_paths.py +21 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_position_resolver.py +79 -84
- refrain-0.5.3/tests/test_private_files.py +89 -0
- refrain-0.5.3/tests/test_qt_libraries.py +95 -0
- refrain-0.5.3/tests/test_qt_libraries_more.py +85 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_qt_plugin_path.py +5 -23
- refrain-0.5.3/tests/test_readme_stats.py +101 -0
- refrain-0.5.3/tests/test_release_key.py +214 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_scrobble.py +1 -5
- refrain-0.5.3/tests/test_scrobble_edges.py +50 -0
- refrain-0.5.3/tests/test_scrobble_more.py +305 -0
- refrain-0.5.3/tests/test_scrobble_queue_edges.py +75 -0
- refrain-0.5.3/tests/test_scrobble_queue_file.py +194 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_scrobbler.py +59 -32
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_secrets_store.py +118 -20
- refrain-0.5.3/tests/test_secrets_store_edges.py +32 -0
- refrain-0.5.3/tests/test_secrets_store_more.py +234 -0
- refrain-0.5.3/tests/test_service_status.py +120 -0
- refrain-0.5.3/tests/test_settings_app_name.py +74 -0
- refrain-0.5.3/tests/test_settings_apply.py +321 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_settings_history.py +3 -6
- refrain-0.5.3/tests/test_settings_lastfm.py +226 -0
- refrain-0.5.3/tests/test_settings_more.py +366 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_settings_reset.py +5 -16
- refrain-0.5.3/tests/test_settings_unsaved.py +581 -0
- refrain-0.5.3/tests/test_settings_window_edges.py +273 -0
- refrain-0.5.3/tests/test_single_instance.py +117 -0
- refrain-0.5.3/tests/test_single_instance_errors.py +41 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_song_lengths.py +96 -6
- refrain-0.5.3/tests/test_song_lengths_edges.py +33 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_source_selection.py +2 -7
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_startup_check.py +5 -18
- refrain-0.5.3/tests/test_status_window.py +461 -0
- refrain-0.5.3/tests/test_system_certificates.py +57 -0
- refrain-0.5.3/tests/test_theme_colors.py +69 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_timing.py +7 -18
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_translations.py +17 -7
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_tray_init.py +18 -34
- refrain-0.5.3/tests/test_tray_states.py +295 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_ui_cursors.py +70 -21
- refrain-0.5.3/tests/test_ui_edges.py +217 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_ui_locale.py +6 -13
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_uninstall.py +41 -14
- refrain-0.5.3/tests/test_update_dialog_cancel.py +133 -0
- refrain-0.5.3/tests/test_update_dialog_flows.py +208 -0
- refrain-0.5.3/tests/test_update_orchestrator.py +212 -0
- refrain-0.5.3/tests/test_updater.py +757 -0
- refrain-0.5.3/tests/test_updater_paths.py +484 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_welcome_dialog_growth.py +2 -13
- refrain-0.5.3/tests/test_welcome_probes.py +300 -0
- refrain-0.5.2/.github/workflows/tests.yml +0 -68
- refrain-0.5.2/LICENSE +0 -71
- refrain-0.5.2/docs/bluetooth.md +0 -141
- refrain-0.5.2/docs/screenshots/discord-rpc.png +0 -0
- refrain-0.5.2/docs/screenshots/history.png +0 -0
- refrain-0.5.2/docs/screenshots/legal.png +0 -0
- refrain-0.5.2/docs/screenshots/live-log.png +0 -0
- refrain-0.5.2/docs/screenshots/notification.png +0 -0
- refrain-0.5.2/docs/screenshots/settings-advanced.png +0 -0
- refrain-0.5.2/docs/screenshots/settings-general.png +0 -0
- refrain-0.5.2/docs/screenshots/settings-history.png +0 -0
- refrain-0.5.2/docs/screenshots/settings-lastfm.png +0 -0
- refrain-0.5.2/docs/screenshots/settings-sources.png +0 -0
- refrain-0.5.2/docs/screenshots/settings-updates.png +0 -0
- refrain-0.5.2/docs/screenshots/tray-menu.png +0 -0
- refrain-0.5.2/docs/screenshots/update-dialog.png +0 -0
- refrain-0.5.2/docs/screenshots/welcome.png +0 -0
- refrain-0.5.2/packaging/appimage/AppImageBuilder.yml +0 -80
- refrain-0.5.2/requirements.txt +0 -3
- refrain-0.5.2/src/refrain/__init__.py +0 -1
- refrain-0.5.2/src/refrain/i18n/refrain_de.qm +0 -0
- refrain-0.5.2/src/refrain/i18n/refrain_de.ts +0 -1274
- refrain-0.5.2/src/refrain/i18n/refrain_en.qm +0 -0
- refrain-0.5.2/src/refrain/i18n/refrain_es.qm +0 -0
- refrain-0.5.2/src/refrain/i18n/refrain_es.ts +0 -1274
- refrain-0.5.2/src/refrain/i18n/refrain_fr.qm +0 -0
- refrain-0.5.2/src/refrain/i18n/refrain_fr.ts +0 -1274
- refrain-0.5.2/src/refrain/i18n/refrain_it.qm +0 -0
- refrain-0.5.2/src/refrain/i18n/refrain_it.ts +0 -1274
- refrain-0.5.2/src/refrain/i18n/refrain_ja.qm +0 -0
- refrain-0.5.2/src/refrain/i18n/refrain_ja.ts +0 -1269
- refrain-0.5.2/src/refrain/i18n/refrain_pl.qm +0 -0
- refrain-0.5.2/src/refrain/i18n/refrain_pl.ts +0 -1279
- refrain-0.5.2/src/refrain/i18n/refrain_pt.qm +0 -0
- refrain-0.5.2/src/refrain/i18n/refrain_pt.ts +0 -1274
- refrain-0.5.2/src/refrain/i18n/refrain_ru.qm +0 -0
- refrain-0.5.2/src/refrain/i18n/refrain_ru.ts +0 -1279
- refrain-0.5.2/src/refrain/i18n/refrain_zh_CN.qm +0 -0
- refrain-0.5.2/src/refrain/i18n/refrain_zh_CN.ts +0 -1269
- refrain-0.5.2/src/refrain/single_instance.py +0 -53
- refrain-0.5.2/src/refrain/ui/log_window.py +0 -122
- refrain-0.5.2/tests/conftest.py +0 -69
- refrain-0.5.2/tests/test_bluetooth_apps.py +0 -70
- refrain-0.5.2/tests/test_browser.py +0 -57
- refrain-0.5.2/tests/test_mpris_controls.py +0 -57
- refrain-0.5.2/tests/test_settings_lastfm.py +0 -133
- refrain-0.5.2/tests/test_updater.py +0 -320
- {refrain-0.5.2 → refrain-0.5.3}/.editorconfig +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/.gitattributes +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/.github/FUNDING.yml +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/.github/dependabot.yml +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/.gitignore +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/CODE_OF_CONDUCT.md +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/Makefile +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/docs/screenshots/demo-cover.png +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/packaging/flatpak/io.github.Rockykln.Refrain.desktop +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/packaging/flatpak/python-deps.json +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/requirements-dev.txt +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/__main__.py +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/assets/icons/github-mark.svg +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/assets/icons/menu-quit.svg +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/assets/icons/menu-update.svg +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/assets/icons/refrain.png +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/assets/icons/refrain.svg +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/assets/icons/tray-paused-dark.svg +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/assets/icons/tray-paused.svg +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/assets/icons/tray-playing-dark.svg +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/assets/icons/tray-playing.svg +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/assets/icons/tray-stopped-dark.svg +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/assets/icons/tray-stopped.svg +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/assets/refrain.desktop +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/sources/__init__.py +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/sources/base.py +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/src/refrain/ui/__init__.py +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/__init__.py +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_scrobble_queue.py +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_settings_github_icon.py +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_sources_base.py +0 -0
- {refrain-0.5.2 → refrain-0.5.3}/tests/test_update_dialog_body.py +0 -0
|
@@ -13,7 +13,7 @@ body:
|
|
|
13
13
|
attributes:
|
|
14
14
|
label: Refrain version
|
|
15
15
|
description: Run `refrain --version` or check the bottom-right of the settings window.
|
|
16
|
-
placeholder: "0.5.
|
|
16
|
+
placeholder: "0.5.3"
|
|
17
17
|
validations:
|
|
18
18
|
required: true
|
|
19
19
|
|
|
@@ -61,14 +61,23 @@ body:
|
|
|
61
61
|
validations:
|
|
62
62
|
required: true
|
|
63
63
|
|
|
64
|
+
- type: markdown
|
|
65
|
+
attributes:
|
|
66
|
+
value: |
|
|
67
|
+
**Before you paste a log:** issues are public. The log lists the songs you
|
|
68
|
+
played (your listening history) and, in debug mode, the address of your
|
|
69
|
+
Bluetooth device. Read it first and remove anything you don't want public,
|
|
70
|
+
or mail the log to [contact@rockykln.com](mailto:contact@rockykln.com) instead
|
|
71
|
+
and mention your issue number.
|
|
72
|
+
|
|
64
73
|
- type: textarea
|
|
65
74
|
id: logs
|
|
66
75
|
attributes:
|
|
67
76
|
label: Refrain log
|
|
68
77
|
description: |
|
|
69
78
|
Paste the relevant portion of `~/.local/state/refrain/refrain.log`.
|
|
70
|
-
|
|
71
|
-
|
|
79
|
+
It holds no passwords or tokens, but it does contain song titles and,
|
|
80
|
+
in debug mode, Bluetooth device addresses — check it before posting.
|
|
72
81
|
render: shell
|
|
73
82
|
validations:
|
|
74
83
|
required: false
|
|
@@ -9,7 +9,7 @@ queries:
|
|
|
9
9
|
- uses: security-and-quality
|
|
10
10
|
|
|
11
11
|
query-filters:
|
|
12
|
-
# Empty `except` blocks are deliberate in
|
|
12
|
+
# Empty `except` blocks are deliberate in cleanup paths
|
|
13
13
|
# (DBus disconnects, Discord IPC, tray icon teardown). Each site has
|
|
14
14
|
# context in surrounding code; the CodeQL note here would be repeated
|
|
15
15
|
# ~10× without adding signal.
|
|
@@ -34,6 +34,7 @@ whatever's relevant and delete the rest.
|
|
|
34
34
|
|
|
35
35
|
## Checklist
|
|
36
36
|
|
|
37
|
+
- [ ] I agree that my contribution is licensed as described in the "Contributions" section of LICENSE (summary in CONTRIBUTING.md)
|
|
37
38
|
- [ ] `pytest` passes locally
|
|
38
39
|
- [ ] `ruff check .` and `ruff format --check .` are clean
|
|
39
40
|
- [ ] New / changed behavior is covered by tests (or unreachable from tests due to system integration — explain)
|
|
@@ -27,15 +27,15 @@ jobs:
|
|
|
27
27
|
language: [python]
|
|
28
28
|
|
|
29
29
|
steps:
|
|
30
|
-
- uses: actions/checkout@v7
|
|
30
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
31
31
|
|
|
32
32
|
- name: Initialize CodeQL
|
|
33
|
-
uses: github/codeql-action/init@v4
|
|
33
|
+
uses: github/codeql-action/init@1c5b675653bb5c22dbe9b12b556ec555138e09fd # v4.38.1
|
|
34
34
|
with:
|
|
35
35
|
languages: ${{ matrix.language }}
|
|
36
36
|
config-file: ./.github/codeql/codeql-config.yml
|
|
37
37
|
|
|
38
38
|
- name: Perform CodeQL analysis
|
|
39
|
-
uses: github/codeql-action/analyze@v4
|
|
39
|
+
uses: github/codeql-action/analyze@1c5b675653bb5c22dbe9b12b556ec555138e09fd # v4.38.1
|
|
40
40
|
with:
|
|
41
41
|
category: "/language:${{ matrix.language }}"
|
|
@@ -6,31 +6,30 @@ on:
|
|
|
6
6
|
tags:
|
|
7
7
|
- "v*.*.*"
|
|
8
8
|
|
|
9
|
+
# The AppImage build tools are installed unpinned, so the job that runs them
|
|
10
|
+
# only gets read access; the write and OIDC permissions sit on the small
|
|
11
|
+
# attestation and publishing jobs below.
|
|
9
12
|
permissions:
|
|
10
|
-
contents:
|
|
11
|
-
id-token: write # required by PyPA Trusted Publishers (OIDC) for PyPI upload
|
|
13
|
+
contents: read
|
|
12
14
|
|
|
13
15
|
jobs:
|
|
14
|
-
|
|
15
|
-
runs-on: ubuntu-
|
|
16
|
-
environment:
|
|
17
|
-
name: pypi
|
|
18
|
-
url: https://pypi.org/project/refrain/
|
|
16
|
+
build:
|
|
17
|
+
runs-on: ubuntu-24.04
|
|
19
18
|
|
|
20
19
|
steps:
|
|
21
20
|
- name: Checkout (full history for changelog)
|
|
22
|
-
uses: actions/checkout@v7
|
|
21
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
23
22
|
with:
|
|
24
23
|
fetch-depth: 0
|
|
25
24
|
|
|
26
|
-
- uses: actions/setup-python@v7
|
|
25
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
27
26
|
with:
|
|
28
27
|
python-version: "3.12"
|
|
29
28
|
cache: pip
|
|
29
|
+
cache-dependency-path: requirements-dev.lock
|
|
30
30
|
|
|
31
31
|
- name: Install + run tests (gate the release)
|
|
32
32
|
run: |
|
|
33
|
-
python -m pip install --upgrade pip
|
|
34
33
|
# System libs: dbus-python needs the *-dev headers at build
|
|
35
34
|
# time; PySide6.QtWidgets needs the EGL/xkbcommon/GL/fontconfig
|
|
36
35
|
# runtime libs to import (even under QT_QPA_PLATFORM=offscreen).
|
|
@@ -38,10 +37,10 @@ jobs:
|
|
|
38
37
|
sudo apt-get install -y \
|
|
39
38
|
libdbus-1-dev libglib2.0-dev pkg-config \
|
|
40
39
|
libegl1 libxkbcommon0 libfontconfig1 libgl1
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
|
|
44
|
-
pip install -e
|
|
40
|
+
# The pinned, hash-checked tool and runtime versions, then
|
|
41
|
+
# Refrain itself on top.
|
|
42
|
+
pip install --require-hashes -r requirements-dev.lock
|
|
43
|
+
pip install --no-deps -e .
|
|
45
44
|
pytest -q
|
|
46
45
|
|
|
47
46
|
- name: Verify tag matches package version
|
|
@@ -64,7 +63,7 @@ jobs:
|
|
|
64
63
|
fi
|
|
65
64
|
|
|
66
65
|
- name: Verify Flatpak manifest pins this tag
|
|
67
|
-
# The Flatpak build source is a pinned
|
|
66
|
+
# The Flatpak build source is a pinned tag — it isn't
|
|
68
67
|
# rebuilt/published by this workflow (no live Flathub channel),
|
|
69
68
|
# so nothing else catches it going stale. It silently sat on
|
|
70
69
|
# v0.1.4 from then until v0.4.2. This gate makes a stale pin a
|
|
@@ -76,14 +75,9 @@ jobs:
|
|
|
76
75
|
echo "::error::$MANIFEST is not pinned to tag v${TAG}"
|
|
77
76
|
exit 1
|
|
78
77
|
fi
|
|
79
|
-
if ! grep -qE "^ commit: [0-9a-f]{40}$" "$MANIFEST"; then
|
|
80
|
-
echo "::error::$MANIFEST has no valid 40-character commit pin"
|
|
81
|
-
exit 1
|
|
82
|
-
fi
|
|
83
78
|
|
|
84
79
|
- name: Build wheel + sdist
|
|
85
80
|
run: |
|
|
86
|
-
pip install build
|
|
87
81
|
python -m build
|
|
88
82
|
# Keep a clean copy of just the Python distributions for PyPI;
|
|
89
83
|
# the AppImage step writes additional files into dist/ later.
|
|
@@ -93,21 +87,19 @@ jobs:
|
|
|
93
87
|
|
|
94
88
|
# Single-file AppImage so end users can grab one binary from the
|
|
95
89
|
# Releases page and run it without installing anything else.
|
|
96
|
-
#
|
|
97
|
-
#
|
|
90
|
+
# The recipe installs Refrain with the runner's /usr/bin/python3,
|
|
91
|
+
# which must match the Python it bundles from Ubuntu 24.04.
|
|
98
92
|
- name: Install AppImage build deps
|
|
99
|
-
continue-on-error: true
|
|
100
93
|
run: |
|
|
101
94
|
sudo apt-get update
|
|
102
95
|
sudo apt-get install -y \
|
|
103
|
-
|
|
104
|
-
libfuse2 desktop-file-utils \
|
|
96
|
+
python3-pip libfuse2t64 desktop-file-utils \
|
|
105
97
|
zsync appstream patchelf squashfs-tools file
|
|
106
|
-
|
|
98
|
+
# appimage-builder can't parse Ubuntu package versions with newer packaging.
|
|
99
|
+
pip install appimage-builder "packaging<22"
|
|
107
100
|
|
|
108
101
|
- name: Build AppImage
|
|
109
102
|
id: appimage
|
|
110
|
-
continue-on-error: true
|
|
111
103
|
run: |
|
|
112
104
|
TAG="${GITHUB_REF#refs/tags/v}"
|
|
113
105
|
# The recipe pins a literal `version:` value, which determines the
|
|
@@ -122,6 +114,44 @@ jobs:
|
|
|
122
114
|
mv *.AppImage.zsync ../../dist/ 2>/dev/null || true
|
|
123
115
|
ls -la ../../dist/
|
|
124
116
|
|
|
117
|
+
# Every AppImage up to 0.5.2 was published without ever starting.
|
|
118
|
+
- name: Start the AppImage once
|
|
119
|
+
run: |
|
|
120
|
+
TAG="${GITHUB_REF#refs/tags/v}"
|
|
121
|
+
out="$(./dist/Refrain-${TAG}-x86_64.AppImage --appimage-extract-and-run --version)"
|
|
122
|
+
echo "$out"
|
|
123
|
+
[ "$out" = "refrain ${TAG}" ]
|
|
124
|
+
|
|
125
|
+
- name: Check licence notices and Qt modules in the AppImage
|
|
126
|
+
run: |
|
|
127
|
+
TAG="${GITHUB_REF#refs/tags/v}"
|
|
128
|
+
tmp="$(mktemp -d)"
|
|
129
|
+
(cd "$tmp" && "$GITHUB_WORKSPACE/dist/Refrain-${TAG}-x86_64.AppImage" --appimage-extract >/dev/null)
|
|
130
|
+
doc="$tmp/squashfs-root/usr/share/doc/refrain"
|
|
131
|
+
grep -q "^ PySide6_Essentials " "$doc/THIRD-PARTY-NOTICES"
|
|
132
|
+
grep -q "^ python3.12 " "$doc/THIRD-PARTY-NOTICES"
|
|
133
|
+
test -s "$doc/LICENSE" && test -s "$doc/LICENSES/LGPL-3" && test -s "$doc/LICENSES/GPL-3"
|
|
134
|
+
gpl_only="$(find "$tmp/squashfs-root" -iregex '.*\(Lottie\|WaylandCompositor\|VirtualKeyboard\|Charts\|DataVisualization\|Quick3D\|pyside6_addons\).*')"
|
|
135
|
+
if [ -n "$gpl_only" ]; then
|
|
136
|
+
echo "::error::GPL-only Qt parts in the AppImage:"; echo "$gpl_only"; exit 1
|
|
137
|
+
fi
|
|
138
|
+
rm -rf "$tmp"
|
|
139
|
+
|
|
140
|
+
# The in-app updater only installs an AppImage listed here, and only once
|
|
141
|
+
# the owner has signed this file (SHA256SUMS.sig, see packaging/README.md).
|
|
142
|
+
- name: Checksums for the in-app updater
|
|
143
|
+
run: |
|
|
144
|
+
cd dist
|
|
145
|
+
sha256sum *.AppImage > SHA256SUMS
|
|
146
|
+
cat SHA256SUMS
|
|
147
|
+
|
|
148
|
+
- name: Publish the AppImage's third-party notices next to it
|
|
149
|
+
run: |
|
|
150
|
+
cd dist
|
|
151
|
+
./Refrain-*-x86_64.AppImage --appimage-extract usr/share/doc/refrain/THIRD-PARTY-NOTICES > /dev/null
|
|
152
|
+
mv squashfs-root/usr/share/doc/refrain/THIRD-PARTY-NOTICES .
|
|
153
|
+
rm -rf squashfs-root
|
|
154
|
+
|
|
125
155
|
# Extract the matching `## [X.Y.Z]` section from CHANGELOG.md
|
|
126
156
|
# and feed it into the GitHub release body. Without this we'd
|
|
127
157
|
# fall back to GitHub's auto-generated "Full Changelog: …"
|
|
@@ -145,16 +175,79 @@ jobs:
|
|
|
145
175
|
echo "::error::CHANGELOG section for v${TAG} extracted to nothing"
|
|
146
176
|
exit 1
|
|
147
177
|
fi
|
|
178
|
+
cat >> release-notes.md <<'NOTES'
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
The AppImage bundles third-party software under its own licences; the
|
|
183
|
+
list, with versions and where to get the source, is in `THIRD-PARTY-NOTICES`
|
|
184
|
+
below and inside the AppImage. Versions that were taken down, and why, are
|
|
185
|
+
listed in [docs/releases.md](https://github.com/Rockykln/refrain/blob/main/docs/releases.md).
|
|
186
|
+
NOTES
|
|
187
|
+
|
|
188
|
+
- name: Hand the release files to the publishing jobs
|
|
189
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
190
|
+
with:
|
|
191
|
+
name: release
|
|
192
|
+
path: |
|
|
193
|
+
dist/
|
|
194
|
+
release-notes.md
|
|
195
|
+
if-no-files-found: error
|
|
196
|
+
|
|
197
|
+
- name: Hand the PyPI files to the publishing job
|
|
198
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
199
|
+
with:
|
|
200
|
+
name: pypi-dist
|
|
201
|
+
path: pypi-dist/
|
|
202
|
+
if-no-files-found: error
|
|
203
|
+
|
|
204
|
+
attest:
|
|
205
|
+
needs: build
|
|
206
|
+
runs-on: ubuntu-24.04
|
|
207
|
+
permissions:
|
|
208
|
+
contents: read
|
|
209
|
+
id-token: write # Sigstore signing certificate for the attestation
|
|
210
|
+
attestations: write # store the attestation with the repository
|
|
211
|
+
|
|
212
|
+
steps:
|
|
213
|
+
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
214
|
+
with:
|
|
215
|
+
name: release
|
|
216
|
+
|
|
217
|
+
# Verify with: gh attestation verify <file> --repo Rockykln/refrain
|
|
218
|
+
- name: Attest build provenance of the release files
|
|
219
|
+
uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
|
|
220
|
+
with:
|
|
221
|
+
subject-path: |
|
|
222
|
+
dist/*.whl
|
|
223
|
+
dist/*.tar.gz
|
|
224
|
+
dist/*.AppImage
|
|
225
|
+
dist/*.AppImage.zsync
|
|
226
|
+
dist/SHA256SUMS
|
|
227
|
+
dist/THIRD-PARTY-NOTICES
|
|
148
228
|
|
|
149
|
-
|
|
150
|
-
|
|
229
|
+
github-release:
|
|
230
|
+
needs: [build, attest]
|
|
231
|
+
runs-on: ubuntu-24.04
|
|
232
|
+
permissions:
|
|
233
|
+
contents: write # required to create the release
|
|
234
|
+
|
|
235
|
+
steps:
|
|
236
|
+
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
237
|
+
with:
|
|
238
|
+
name: release
|
|
239
|
+
|
|
240
|
+
# A draft: the owner signs SHA256SUMS on their own machine and only then
|
|
241
|
+
# publishes it (packaging/release_key.py release <tag>).
|
|
242
|
+
- name: Create GitHub release (draft)
|
|
243
|
+
uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3
|
|
151
244
|
with:
|
|
152
245
|
# Use our CHANGELOG section (extracted above), not GitHub's
|
|
153
246
|
# auto-generated notes — the in-app update dialog renders
|
|
154
247
|
# this body verbatim so it has to actually be the changelog.
|
|
155
248
|
body_path: release-notes.md
|
|
156
249
|
generate_release_notes: false
|
|
157
|
-
draft:
|
|
250
|
+
draft: true
|
|
158
251
|
prerelease: ${{ contains(github.ref, '-') }} # e.g. v0.2.0-rc1
|
|
159
252
|
name: "Refrain ${{ github.ref_name }}"
|
|
160
253
|
files: |
|
|
@@ -162,6 +255,24 @@ jobs:
|
|
|
162
255
|
dist/*.tar.gz
|
|
163
256
|
dist/*.AppImage
|
|
164
257
|
dist/*.AppImage.zsync
|
|
258
|
+
dist/SHA256SUMS
|
|
259
|
+
dist/THIRD-PARTY-NOTICES
|
|
260
|
+
|
|
261
|
+
pypi:
|
|
262
|
+
# After the GitHub release, as before the jobs were split.
|
|
263
|
+
needs: github-release
|
|
264
|
+
runs-on: ubuntu-24.04
|
|
265
|
+
environment:
|
|
266
|
+
name: pypi
|
|
267
|
+
url: https://pypi.org/project/refrain/
|
|
268
|
+
permissions:
|
|
269
|
+
id-token: write # required by PyPA Trusted Publishers (OIDC) for PyPI upload
|
|
270
|
+
|
|
271
|
+
steps:
|
|
272
|
+
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
273
|
+
with:
|
|
274
|
+
name: pypi-dist
|
|
275
|
+
path: pypi-dist/
|
|
165
276
|
|
|
166
277
|
# PyPI upload via Trusted Publishers (OIDC). No API token needed; the
|
|
167
278
|
# one-time setup is on pypi.org → Manage → Publishing → Add a new
|
|
@@ -170,12 +281,9 @@ jobs:
|
|
|
170
281
|
# Skips silently if the version already exists on PyPI so re-running
|
|
171
282
|
# a release for AppImage-only fixes doesn't fail the workflow.
|
|
172
283
|
- name: Publish to PyPI
|
|
173
|
-
uses: pypa/gh-action-pypi-publish@
|
|
284
|
+
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
|
|
174
285
|
with:
|
|
175
286
|
packages-dir: pypi-dist/
|
|
176
287
|
skip-existing: true
|
|
177
288
|
verbose: true
|
|
178
289
|
attestations: true
|
|
179
|
-
# Don't let an upload hiccup wipe out the GitHub release that
|
|
180
|
-
# already succeeded above — reruns can fix PyPI later.
|
|
181
|
-
continue-on-error: true
|
|
@@ -15,7 +15,6 @@ on:
|
|
|
15
15
|
|
|
16
16
|
permissions:
|
|
17
17
|
contents: read
|
|
18
|
-
security-events: write
|
|
19
18
|
|
|
20
19
|
jobs:
|
|
21
20
|
|
|
@@ -23,15 +22,16 @@ jobs:
|
|
|
23
22
|
name: bandit (python SAST)
|
|
24
23
|
runs-on: ubuntu-latest
|
|
25
24
|
steps:
|
|
26
|
-
- uses: actions/checkout@v7
|
|
25
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
27
26
|
|
|
28
|
-
- uses: actions/setup-python@v7
|
|
27
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
29
28
|
with:
|
|
30
29
|
python-version: "3.12"
|
|
31
30
|
cache: pip
|
|
31
|
+
cache-dependency-path: requirements-dev.lock
|
|
32
32
|
|
|
33
33
|
- name: Install bandit
|
|
34
|
-
run: pip install bandit
|
|
34
|
+
run: pip install --require-hashes -c requirements-dev.lock bandit
|
|
35
35
|
|
|
36
36
|
- name: Run bandit (medium + high severity only)
|
|
37
37
|
# Config (skips, exclude_dirs) lives in pyproject.toml [tool.bandit].
|
|
@@ -42,12 +42,13 @@ jobs:
|
|
|
42
42
|
name: pip-audit (dependency CVEs)
|
|
43
43
|
runs-on: ubuntu-latest
|
|
44
44
|
steps:
|
|
45
|
-
- uses: actions/checkout@v7
|
|
45
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
46
46
|
|
|
47
|
-
- uses: actions/setup-python@v7
|
|
47
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
48
48
|
with:
|
|
49
49
|
python-version: "3.12"
|
|
50
50
|
cache: pip
|
|
51
|
+
cache-dependency-path: requirements-dev.lock
|
|
51
52
|
|
|
52
53
|
- name: Install system headers for dbus-python build
|
|
53
54
|
# dbus-python is a C-extension module; pip-audit's resolver tries
|
|
@@ -60,8 +61,7 @@ jobs:
|
|
|
60
61
|
|
|
61
62
|
- name: Install pip-audit
|
|
62
63
|
run: |
|
|
63
|
-
|
|
64
|
-
pip install pip-audit
|
|
64
|
+
pip install --require-hashes -c requirements-dev.lock pip-audit
|
|
65
65
|
|
|
66
66
|
- name: Run pip-audit on requirements.txt
|
|
67
67
|
# --strict makes the job fail on any known vulnerability in the
|
|
@@ -69,11 +69,16 @@ jobs:
|
|
|
69
69
|
# noise is minimal.
|
|
70
70
|
run: pip-audit -r requirements.txt --strict
|
|
71
71
|
|
|
72
|
+
- name: Run pip-audit on the pinned dev/CI lock
|
|
73
|
+
# Nothing updates requirements-dev.lock on its own; a finding here
|
|
74
|
+
# means: regenerate it (command at the top of the file).
|
|
75
|
+
run: pip-audit -r requirements-dev.lock --require-hashes --disable-pip --strict
|
|
76
|
+
|
|
72
77
|
trufflehog:
|
|
73
78
|
name: trufflehog (secret detection)
|
|
74
79
|
runs-on: ubuntu-latest
|
|
75
80
|
steps:
|
|
76
|
-
- uses: actions/checkout@v7
|
|
81
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
77
82
|
with:
|
|
78
83
|
fetch-depth: 0
|
|
79
84
|
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
name: tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, master]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main, master]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
strategy:
|
|
16
|
+
matrix:
|
|
17
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
18
|
+
fail-fast: false
|
|
19
|
+
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
22
|
+
|
|
23
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
24
|
+
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
25
|
+
with:
|
|
26
|
+
python-version: ${{ matrix.python-version }}
|
|
27
|
+
cache: pip
|
|
28
|
+
cache-dependency-path: requirements-dev.lock
|
|
29
|
+
|
|
30
|
+
- name: Install runtime + test dependencies
|
|
31
|
+
# The newer tests import refrain modules that pull PySide6 /
|
|
32
|
+
# pypresence / dbus-python at module load, so the runtime deps
|
|
33
|
+
# have to be present in CI too. PySide6.QtWidgets requires the
|
|
34
|
+
# EGL / xkbcommon / GL / fontconfig system libs even when run
|
|
35
|
+
# under QT_QPA_PLATFORM=offscreen — without them the import
|
|
36
|
+
# itself fails before the test can opt out.
|
|
37
|
+
run: |
|
|
38
|
+
sudo apt-get update
|
|
39
|
+
sudo apt-get install -y \
|
|
40
|
+
libdbus-1-dev libglib2.0-dev pkg-config \
|
|
41
|
+
libegl1 libxkbcommon0 libfontconfig1 libgl1
|
|
42
|
+
pip install --require-hashes -r requirements-dev.lock
|
|
43
|
+
pip install --no-deps -e .
|
|
44
|
+
|
|
45
|
+
- name: Compile-check every module
|
|
46
|
+
run: python -m compileall -q src/
|
|
47
|
+
|
|
48
|
+
- name: Run tests with coverage
|
|
49
|
+
run: PYTHONPATH=src pytest --cov --cov-report=term-missing --cov-fail-under=99
|
|
50
|
+
|
|
51
|
+
- name: Coverage in the job summary
|
|
52
|
+
if: ${{ !cancelled() && hashFiles('.coverage') != '' }}
|
|
53
|
+
run: |
|
|
54
|
+
{
|
|
55
|
+
echo "### Coverage (Python ${{ matrix.python-version }}): $(coverage report --format=total)%"
|
|
56
|
+
echo
|
|
57
|
+
coverage report --format=markdown
|
|
58
|
+
} >> "$GITHUB_STEP_SUMMARY"
|
|
59
|
+
|
|
60
|
+
lowest:
|
|
61
|
+
# The lower bounds in pyproject.toml, on the oldest supported Python.
|
|
62
|
+
runs-on: ubuntu-latest
|
|
63
|
+
steps:
|
|
64
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
65
|
+
|
|
66
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
67
|
+
with:
|
|
68
|
+
python-version: "3.11"
|
|
69
|
+
cache: pip
|
|
70
|
+
cache-dependency-path: |
|
|
71
|
+
requirements-dev.lock
|
|
72
|
+
requirements-lowest.txt
|
|
73
|
+
|
|
74
|
+
- name: Install the oldest supported dependencies
|
|
75
|
+
run: |
|
|
76
|
+
sudo apt-get update
|
|
77
|
+
sudo apt-get install -y \
|
|
78
|
+
libdbus-1-dev libglib2.0-dev pkg-config \
|
|
79
|
+
libegl1 libxkbcommon0 libfontconfig1 libgl1
|
|
80
|
+
pip install --require-hashes -c requirements-dev.lock pytest
|
|
81
|
+
pip install -r requirements-lowest.txt
|
|
82
|
+
pip install --no-deps -e .
|
|
83
|
+
pip check
|
|
84
|
+
|
|
85
|
+
- name: Run tests
|
|
86
|
+
run: PYTHONPATH=src pytest
|
|
87
|
+
|
|
88
|
+
lint:
|
|
89
|
+
runs-on: ubuntu-latest
|
|
90
|
+
steps:
|
|
91
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
92
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
93
|
+
with:
|
|
94
|
+
python-version: "3.12"
|
|
95
|
+
cache: pip
|
|
96
|
+
cache-dependency-path: requirements-dev.lock
|
|
97
|
+
|
|
98
|
+
- name: Install ruff
|
|
99
|
+
# The version comes from requirements-dev.lock, like everywhere else.
|
|
100
|
+
run: pip install --require-hashes -c requirements-dev.lock ruff
|
|
101
|
+
|
|
102
|
+
- name: Lint with ruff
|
|
103
|
+
run: ruff check . --output-format=github
|
|
104
|
+
|
|
105
|
+
- name: Format check with ruff
|
|
106
|
+
run: ruff format --check .
|