Skip to content

Garnix CI - #75

Merged
gfauredev merged 33 commits into
mainfrom
garnix-ci
Mar 9, 2026
Merged

Garnix CI#75
gfauredev merged 33 commits into
mainfrom
garnix-ci

Conversation

@gfauredev

Copy link
Copy Markdown
Owner

Use Garnix for CI jobs that can be run isolated and to leverage automatic caching and environment setup.

gfauredev added 30 commits March 9, 2026 17:05
Flake lock file updates:

• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/dd9b079222d43e1943b6ebd802f04fd959dc8e61?narHash=sha256-I45esRSssFtJ8p/gLHUZ1OUaaTaVLluNkABkk6arQwE%3D' (2026-02-27)
  → 'github:NixOS/nixpkgs/9dcb002ca1690658be4a04645215baea8b95f31d?narHash=sha256-9jVDGZnvCckTGdYT53d/EfznygLskyLQXYwJLKMPsZs%3D' (2026-03-08)
• Updated input 'rust-overlay':
    'github:oxalica/rust-overlay/9879be11f30fd3bbf848e653a7f991549e8973b5?narHash=sha256-Jrc0J3AH%2BiNJDlUze3%2BFJZv2R0BZnhANFnD52V4kyvI%3D' (2026-03-01)
  → 'github:oxalica/rust-overlay/3c06fdbbd36ff60386a1e590ee0cd52dcd1892bf?narHash=sha256-Wik8%2BxApNfldpUFjPmJkPdg0RrvUPSWGIZis%2BA/0N1w%3D' (2026-03-09)
@github-actions

github-actions Bot commented Mar 9, 2026

Copy link
Copy Markdown

📊 Coverage Report (from Garnix cache)

Total Line Coverage: 90.1217391304348%

/build/source/src/main.rs:
    1|       |//! **`LogOut`** – Turn off your computer, Log your workOut
    2|       |//!
    3|       |//! A simple, efficient and cross-platform workout logging application with
    4|       |//! 800+ built-in exercises.  The app is built with [Dioxus] and targets both
    5|       |//! PWA (web) and native Android / desktop platforms.
    6|       |//!
    7|       |//! [Dioxus]: https://dioxuslabs.com
    8|       |
    9|       |use dioxus::prelude::*;
   10|       |
   11|       |mod components;
   12|       |mod models;
   13|       |mod services;
   14|       |/// Pure utility helpers (date formatting, URL resolution, timestamp helpers).
   15|       |pub mod utils;
   16|       |
   17|       |use components::{
   18|       |    AddExercise, Analytics, Credits, EditExercise, Exercises, GlobalSessionHeader, Home,
   19|       |};
   20|       |
   21|       |/// Global context signal for the congratulations toast shown after completing a session.
   22|       |#[derive(Clone, Copy)]
   23|       |pub struct CongratulationsSignal(pub Signal<bool>);
   24|       |
   25|       |/// Global context signal for a general-purpose toast message.
   26|       |#[derive(Clone, Copy)]
   27|       |pub struct ToastSignal(pub Signal<Option<String>>);
   28|       |
   29|       |/// Global context signal that, when `true`, shows a persistent notification-
   30|       |/// permission warning toast.  The toast prompts the user to click it in order
   31|       |/// to trigger the browser permission dialog.
   32|       |#[derive(Clone, Copy)]
   33|       |pub struct NotificationPermissionToastSignal(pub Signal<bool>);
   34|       |
   35|       |/// Global context signal used to show/hide the rest-duration input form in
   36|       |/// the active [`SessionView`].  The form is toggled by clicking the timer in
   37|       |/// the [`GlobalSessionHeader`] which lives in the layout and is shared across
   38|       |/// all pages.
   39|       |#[derive(Clone, Copy)]
   40|       |pub struct ShowRestInputSignal(pub Signal<bool>);
   41|       |
   42|       |/// Auto-dismiss delay for toasts in milliseconds.
   43|       |const TOAST_DISMISS_MS: u32 = 3_000;
   44|       |
   45|       |/// Global context signal for pre-filling the exercise list search query.
   46|       |#[derive(Clone, Copy)]
   47|       |pub struct ExerciseSearchSignal(pub Signal<Option<String>>);
   48|       |
   49|       |/// Global context signal holding a pending deep-link action that requires the
   50|       |/// exercise list to be loaded before it can be executed (e.g. creating a past
   51|       |/// session with specific exercises).
   52|       |#[derive(Clone, Copy)]
   53|       |pub struct PendingDeepLinkSignal(pub Signal<Option<utils::DeepLinkAction>>);
   54|       |
   55|      0|#[derive(Clone, Routable, Debug, PartialEq)]
   56|       |#[rustfmt::skip]
   57|       |enum Route {
   58|       |    #[layout(DeepLinkLayout)]
   59|       |    #[route("/")]
   60|       |    Home {},
   61|       |    #[route("/exercises")]
   62|       |    Exercises {},
   63|       |    #[route("/analytics")]
   64|       |    Analytics {},
   65|       |    #[route("/credits")]
   66|       |    Credits {},
   67|       |    #[route("/add-exercise")]
   68|       |    AddExercise {},
   69|       |    #[route("/edit-exercise/:id")]
   70|       |    EditExercise { id: String },
   71|       |}
   72|       |
   73|      0|fn main() {
   74|       |    // Initialize logger
   75|      0|    dioxus_logger::init(dioxus_logger::tracing::Level::INFO).expect("failed to init logger");
   76|       |
   77|       |    // Initialize Android-specific paths and channels
   78|       |    #[cfg(target_os = "android")]
   79|       |    {
   80|       |        // Try to get the internal data directory from the environment or system properties.
   81|       |        // Dioxus/Tao on Android typically sets some environment variables or we can
   82|       |        // rely on the JNI bridge `setDataDir` to be called by the Java side.
   83|       |        services::android_notifications::setup_notification_channel();
   84|       |    }
   85|       |    #[cfg(all(not(target_arch = "wasm32"), not(target_os = "android")))]
   86|      0|    {
   87|      0|        // Desktop notifications or other setup
   88|      0|    }
   89|       |
   90|       |    // Register service worker for offline image caching
   91|      0|    services::service_worker::register_service_worker();
   92|       |
   93|       |    // Prevent the device screen from sleeping while the app is open
   94|      0|    services::wake_lock::enable_wake_lock();
   95|       |
   96|      0|    launch(App);
   97|      0|}
   98|       |
   99|       |#[component]
  100|       |fn App() -> Element {
  101|       |    // Provide shared state signals via context
  102|       |    services::storage::provide_app_state();
  103|       |    services::exercise_db::provide_exercises();
  104|      0|    use_context_provider(|| CongratulationsSignal(Signal::new(false)));
  105|      0|    use_context_provider(|| ToastSignal(Signal::new(None)));
  106|      0|    use_context_provider(|| NotificationPermissionToastSignal(Signal::new(false)));
  107|      0|    use_context_provider(|| ExerciseSearchSignal(Signal::new(None)));
  108|      0|    use_context_provider(|| PendingDeepLinkSignal(Signal::new(None)));
  109|      0|    use_context_provider(|| ShowRestInputSignal(Signal::new(false)));
  110|       |
  111|       |    // Show the notification permission warning toast when permission has not yet
  112|       |    // been granted.  The toast prompts the user to click it — respecting browsers
  113|       |    // that require a user gesture before the permission dialog can be shown.
  114|       |    #[cfg(all(target_arch = "wasm32", feature = "web-platform"))]
  115|       |    {
  116|       |        let mut notif_toast = use_context::<NotificationPermissionToastSignal>().0;
  117|       |        use_hook(move || {
  118|       |            use web_sys::NotificationPermission;
  119|       |            match web_sys::Notification::permission() {
  120|       |                NotificationPermission::Default | NotificationPermission::Denied => {
  121|       |                    notif_toast.set(true);
  122|       |                }
  123|       |                _ => {}
  124|       |            }
  125|       |        });
  126|       |    }
  127|       |
  128|       |    rsx! {
  129|       |        Stylesheet { href: asset!("/assets/style.scss") }
  130|       |        Router::<Route> {}
  131|       |        CongratulationsToast {}
  132|       |        Toast {}
  133|       |        NotificationPermissionToast {}
  134|      0|    }
  135|       |}
  136|       |
  137|       |/// Layout component rendered inside the Router context for all routes.
  138|       |///
  139|       |/// Handles `logworkout://` deep links (and their web equivalents via `?dl_*`
  140|       |/// URL query parameters) on first mount.  Navigation links require the Router
  141|       |/// context, so this component is the right place to call `use_navigator()`.
  142|       |///
  143|       |/// **Immediate actions** (URL storage, exercise search pre-fill, navigation)
  144|       |/// are executed inside `use_hook` which runs once per component mount.
  145|       |///
  146|       |/// **Deferred actions** (creating a past session) are stored in
  147|       |/// [`PendingDeepLinkSignal`] and executed via `use_effect` once the exercise
  148|       |/// list has been loaded from the network/cache.
  149|       |#[component]
  150|       |fn DeepLinkLayout() -> Element {
  151|       |    #[cfg(target_arch = "wasm32")]
  152|       |    {
  153|       |        use utils::DeepLinkAction;
  154|       |
  155|       |        let nav = use_navigator();
  156|       |        let exercises_sig = services::exercise_db::use_exercises();
  157|       |        let mut search_signal = consume_context::<ExerciseSearchSignal>().0;
  158|       |        let mut pending = consume_context::<PendingDeepLinkSignal>().0;
  159|       |
  160|       |        // ── First-mount: parse URL params and execute immediate actions ──────
  161|       |        use_hook(move || {
  162|       |            let Some(action) = utils::parse_web_deep_link() else {
  163|       |                return;
  164|       |            };
  165|       |            match action {
  166|       |                DeepLinkAction::Navigate(path) => {
  167|       |                    let route = path_to_route(&path);
  168|       |                    nav.push(route);
  169|       |                }
  170|       |                DeepLinkAction::SearchExercises(q) => {
  171|       |                    search_signal.set(Some(q));
  172|       |                    nav.push(Route::Exercises {});
  173|       |                }
  174|       |                DeepLinkAction::SetDbUrl(url) => {
  175|       |                    // Normalise the URL before persisting so it is always
  176|       |                    // ready to be used as a base URL (scheme + trailing slash).
  177|       |                    let url = utils::normalize_db_url(&url);
  178|       |                    // Persist the new URL in localStorage immediately so that
  179|       |                    // `get_exercise_db_url()` picks it up when exercises reload.
  180|       |                    if let Some(window) = web_sys::window() {
  181|       |                        if let Ok(Some(storage)) = window.local_storage() {
  182|       |                            if url.is_empty() || url == utils::EXERCISE_DB_BASE_URL {
  183|       |                                let _ = storage.remove_item(utils::EXERCISE_DB_URL_STORAGE_KEY);
  184|       |                            } else {
  185|       |                                let _ = storage.set_item(utils::EXERCISE_DB_URL_STORAGE_KEY, &url);
  186|       |                            }
  187|       |                        }
  188|       |                    }
  189|       |                    services::exercise_db::clear_fetch_cache();
  190|       |                    // Immediately reload exercises so the UI reflects the new URL
  191|       |                    let toast = consume_context::<ToastSignal>().0;
  192|       |                    spawn(async move {
  193|       |                        services::exercise_db::reload_exercises(exercises_sig, toast).await;
  194|       |                    });
  195|       |                }
  196|       |                DeepLinkAction::StartSession(exercise_ids) => {
  197|       |                    let mut session = models::WorkoutSession::new();
  198|       |                    session.pending_exercise_ids = exercise_ids;
  199|       |                    services::storage::save_session(session);

... (truncated, see Garnix for full report)

@github-actions

github-actions Bot commented Mar 9, 2026

Copy link
Copy Markdown

❌ Maestro Web E2E Failures

📜 Maestro Console Output (Last 100 lines)
copying path '/nix/store/q8zb95f4m2aahbdi6jl7wh3cjwc4p855-cups-2.4.16' from 'http://127.0.0.1:37515'...
copying path '/nix/store/qccg8a9rgcpdkybjadvq511gxrflk61m-ungoogled-chromium-unwrapped-145.0.7632.159' from 'http://127.0.0.1:37515'...
copying path '/nix/store/1yyiqpg6nhbfclgi0czkii2mqrczwk6n-gtk+-2.24.33' from 'http://127.0.0.1:37515'...
copying path '/nix/store/q43d6pbb9qxyhj6hq4id5mdg6gfrz6gv-gtk+3-3.24.51' from 'http://127.0.0.1:37515'...
copying path '/nix/store/n38lqimcp8jy648dg6qwz4f9p45ajg0k-roc-toolkit-0.4.0' from 'http://127.0.0.1:37515'...
copying path '/nix/store/ip1zll830af00llffx8s711dhvr51vmq-ffmpeg-headless-8.0.1-lib' from 'http://127.0.0.1:37515'...
copying path '/nix/store/lakdsf2fqlp84ygjq1p5a00avi3kymp7-openjdk-8u472-b08-jre' from 'http://127.0.0.1:37515'...
copying path '/nix/store/rwkg6mdhrv2j9471kqmck3i4cn6z5g1x-nodejs-slim-24.13.0-corepack' from 'http://127.0.0.1:37515'...
copying path '/nix/store/84a9a50f29spa8s45bpamq658srndhdf-nodejs-slim-24.13.0-npm' from 'http://127.0.0.1:37515'...
copying path '/nix/store/2c52z0rvldik0rll2xz2ip5dl1c8f3pw-openjdk-21.0.10+7' from 'http://127.0.0.1:37515'...
copying path '/nix/store/qzcvvzg2vspifdzpsyaamq26pl889r9n-openjdk-minimal-jre-21.0.10+7' from 'http://127.0.0.1:37515'...
copying path '/nix/store/hlj8rs0wbdicfn7hadav77r3nvk4a44d-openjdk-17.0.18+8' from 'http://127.0.0.1:37515'...
copying path '/nix/store/zk8v6lc5x2izxblkcqgxv0dyclfqzi0w-chromaprint-1.6.0' from 'http://127.0.0.1:37515'...
copying path '/nix/store/mk3db6i5w5g4b1bdwrcwp0ys4cypk51n-gstreamer-1.26.5' from 'http://127.0.0.1:37515'...
copying path '/nix/store/jpg6mfa3gisdsqvkqnswgc8mbxz1bk0x-python3.13-protobuf-6.33.5' from 'http://127.0.0.1:37515'...
copying path '/nix/store/sy0c7j0npsq33d9zhnnzvjnzc52f4y0p-nodejs-24.13.0' from 'http://127.0.0.1:37515'...
copying path '/nix/store/d4c8nl9x9rd3di2dvr982wh3yp8zppir-python3-3.13.12-env' from 'http://127.0.0.1:37515'...
copying path '/nix/store/kgf6zn39f6mxg0l3hjx29rpg7a0y3viv-gst-plugins-base-1.26.5' from 'http://127.0.0.1:37515'...
copying path '/nix/store/zrn94ppg0n93fwylvpbcb5a6m29xqr9y-libcanberra-0.30' from 'http://127.0.0.1:37515'...
copying path '/nix/store/ca3p5fy9l9dnk0zhkh74jl1srw7jnhkp-libnice-0.1.22' from 'http://127.0.0.1:37515'...
copying path '/nix/store/0mka05jxrk63rw1sp0s1amk5p8hgnd7n-android-tools-35.0.2' from 'http://127.0.0.1:37515'...
copying path '/nix/store/716f9vxn5aan1g1pfv1pmn5jiks4gnhi-typescript-5.9.3' from 'http://127.0.0.1:37515'...
copying path '/nix/store/bv61xzzqwvy7qnklz33r5y6yamiknhms-yaml-language-server-1.21.0' from 'http://127.0.0.1:37515'...
copying path '/nix/store/wyv137n1hj4as51jhisijqzdqjw3nd1y-vscode-langservers-extracted-4.10.0' from 'http://127.0.0.1:37515'...
copying path '/nix/store/xbaymj7dxkqhyxs01404153simhsqya1-libcamera-0.7.0' from 'http://127.0.0.1:37515'...
copying path '/nix/store/fcqhn9m2sih0rmhw1j1ffxrkl8vw7248-pipewire-1.4.10' from 'http://127.0.0.1:37515'...
copying path '/nix/store/jn9wngbhqmijdw4m2czilnhl4pw4jcdp-typescript-language-server-5.1.3' from 'http://127.0.0.1:37515'...
copying path '/nix/store/q3c4ljw4vh5444dgbc7brygg5zjz0383-apksigner-35.0.6' from 'http://127.0.0.1:37515'...
copying path '/nix/store/i8cnggy5khh40aqrf0hcml71829bwglj-openal-soft-1.24.3' from 'http://127.0.0.1:37515'...
copying path '/nix/store/x6adcywj0fgd4air162d1pphzh8cjvqn-gst-plugins-bad-1.26.5' from 'http://127.0.0.1:37515'...
copying path '/nix/store/gpbc2mhlvsd4i9qxbgja5s8ainlj1wk7-openjdk-8u472-b08' from 'http://127.0.0.1:37515'...
copying path '/nix/store/r5ifa1m0sqa6ny76jgglds7gr540837m-gtk4-4.20.3' from 'http://127.0.0.1:37515'...
copying path '/nix/store/1kmz4nrlxb1zyimgvfkxcd2v2adgkapn-androidsdk-tools' from 'https://cache.garnix.io'...
copying path '/nix/store/z3mpvfz7rxj26kmnp6znjvj9rwykmqs6-maestro-2.1.0' from 'http://127.0.0.1:37515'...
copying path '/nix/store/nyihv9av5yjmdq3z3i7vwlq7k3dqj27b-ungoogled-chromium-145.0.7632.159' from 'http://127.0.0.1:37515'...
copying path '/nix/store/5m60ppfzidhlxb1fhzjka3hxj125sg2k-android-sdk-build-tools-34.0.0' from 'https://cache.garnix.io'...
copying path '/nix/store/1p9dqvcby0b4pvbypp099l6xpg0i1rh1-android-sdk-build-tools-36.0.0' from 'https://cache.garnix.io'...
copying path '/nix/store/s6szq77fijn04zcjk5kmf05g830frgms-android-sdk-build-tools-35.0.0' from 'https://cache.garnix.io'...
copying path '/nix/store/gs8wqb5xnwsw5898gv7j4v71v3jsbnc9-android-sdk-ndk-29.0.14206865' from 'https://cache.garnix.io'...
copying path '/nix/store/9f053ssykal4mcm8yp5z4a4jm3alqi72-androidsdk' from 'https://cache.garnix.io'...
building '/nix/store/dg012ns8j8as3yd0swhz5rmgkz54ap9r-nix-shell-env.drv'...
this path will be fetched (107.5 KiB download, 107.4 KiB unpacked):
  /nix/store/5vmwpgmif2wa2hw5ip3ab6q40wvyfw2w-bash-interactive-5.3p9-man
copying path '/nix/store/5vmwpgmif2wa2hw5ip3ab6q40wvyfw2w-bash-interactive-5.3p9-man' from 'http://127.0.0.1:37515'...
💪 LogOut Dev Environment Ready
- Rust rustc 1.94.0 (4a4ef493e 2026-03-02)
- Dioxus CLI dioxus 0.7.3 (was built without git repository)
- Android SDK /nix/store/9f053ssykal4mcm8yp5z4a4jm3alqi72-androidsdk/libexec/android-sdk
- Android NDK /nix/store/gs8wqb5xnwsw5898gv7j4v71v3jsbnc9-android-sdk-ndk-29.0.14206865/libexec/android-sdk/ndk-bundle
Anonymous analytics enabled. To opt out, set MAESTRO_CLI_NO_ANALYTICS environment variable to any value before running Maestro.


Web support is in Beta. We would appreciate your feedback!


Could not start a new session. Response code 500. Message: session not created: Chrome instance exited. Examine ChromeDriver verbose log to determine the cause. 
Host info: host: 'runnervm0kj6c', ip: '10.1.0.77'
Build info: version: '4.38.0', revision: '6b412e825c*'
System info: os.name: 'Linux', os.arch: 'amd64', os.version: '6.14.0-1017-azure', java.version: '21.0.10'
Driver info: org.openqa.selenium.chrome.ChromeDriver
Command: [null, newSession {capabilities=[Capabilities {browserName: chrome, goog:chromeOptions: {args: [--remote-allow-origins=*, --disable-search-engine-cho..., --lang=en, --password-store=basic], binary: /usr/bin/google-chrome, extensions: [], prefs: {credentials_enable_service: false, profile.password_manager_enabled: false, profile.password_manager_leak_detection: false}}}]}]

The stack trace was:
org.openqa.selenium.SessionNotCreatedException: Could not start a new session. Response code 500. Message: session not created: Chrome instance exited. Examine ChromeDriver verbose log to determine the cause. 
Host info: host: 'runnervm0kj6c', ip: '10.1.0.77'
Build info: version: '4.38.0', revision: '6b412e825c*'
System info: os.name: 'Linux', os.arch: 'amd64', os.version: '6.14.0-1017-azure', java.version: '21.0.10'
Driver info: org.openqa.selenium.chrome.ChromeDriver
Command: [null, newSession {capabilities=[Capabilities {browserName: chrome, goog:chromeOptions: {args: [--remote-allow-origins=*, --disable-search-engine-cho..., --lang=en, --password-store=basic], binary: /usr/bin/google-chrome, extensions: [], prefs: {credentials_enable_service: false, profile.password_manager_enabled: false, profile.password_manager_leak_detection: false}}}]}]
	at org.openqa.selenium.remote.ProtocolHandshake.createSession(ProtocolHandshake.java:114)
	at org.openqa.selenium.remote.ProtocolHandshake.createSession(ProtocolHandshake.java:75)
	at org.openqa.selenium.remote.ProtocolHandshake.createSession(ProtocolHandshake.java:61)
	at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:187)
	at org.openqa.selenium.remote.service.DriverCommandExecutor.invokeExecute(DriverCommandExecutor.java:216)
	at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:174)
	at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:557)
	at org.openqa.selenium.remote.RemoteWebDriver.startSession(RemoteWebDriver.java:246)
	at org.openqa.selenium.remote.RemoteWebDriver.<init>(RemoteWebDriver.java:174)
	at org.openqa.selenium.chromium.ChromiumDriver.<init>(ChromiumDriver.java:99)
	at org.openqa.selenium.chrome.ChromeDriver.<init>(ChromeDriver.java:88)
	at org.openqa.selenium.chrome.ChromeDriver.<init>(ChromeDriver.java:83)
	at maestro.drivers.CdpWebDriver.createSeleniumDriver(CdpWebDriver.kt:102)
	at maestro.drivers.CdpWebDriver.open(CdpWebDriver.kt:74)
	at maestro.Maestro$Companion.web(Maestro.kt:653)
	at maestro.cli.session.MaestroSessionManager.pickWebDevice(MaestroSessionManager.kt:436)
	at maestro.cli.session.MaestroSessionManager.createMaestro(MaestroSessionManager.kt:247)
	at maestro.cli.session.MaestroSessionManager.newSession(MaestroSessionManager.kt:104)
	at maestro.cli.session.MaestroSessionManager.newSession$default(MaestroSessionManager.kt:65)
	at maestro.cli.command.TestCommand.runShardSuite(TestCommand.kt:465)
	at maestro.cli.command.TestCommand.access$runShardSuite(TestCommand.kt:80)
	at maestro.cli.command.TestCommand$handleSessions$1$results$1$1.invokeSuspend(TestCommand.kt:424)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:34)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
	at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:111)
	at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:99)
	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:585)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:802)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:706)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:693)

📸 Screenshots

@gfauredev
gfauredev merged commit e4880c5 into main Mar 9, 2026
1 of 2 checks passed
@gfauredev
gfauredev deleted the garnix-ci branch March 9, 2026 21:19
@github-actions

github-actions Bot commented Mar 9, 2026

Copy link
Copy Markdown

📊 Coverage Report (from Garnix cache)

Total Line Coverage: %


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant