Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
f218484
Initial plan
Copilot Feb 22, 2026
0ae8b90
Harmonize CI/CD: CI on PRs, CD on main; move Maestro e2e to CI; fix M…
Copilot Feb 22, 2026
1c0a04e
Fix Android e2e tests: pre-launch app before Maestro and add stopApp:…
Copilot Feb 22, 2026
bd58557
Fix Maestro e2e: monkey on single line, CDP socket poll replaces sleep
Copilot Feb 22, 2026
c866d06
Fix Maestro e2e: replace multi-line while loop with sleep 20 (per-lin…
Copilot Feb 22, 2026
7074556
Fix Maestro typo: waitForAnimationsToEnd -> waitForAnimationToEnd (si…
Copilot Feb 22, 2026
977f88d
Fix Maestro tests: use default launchApp, 90s timeout, remove pre-lau…
Copilot Feb 22, 2026
546cbf0
Fix Maestro tests: use google_apis emulator target for Chrome WebView…
Copilot Feb 23, 2026
6944640
Fix APK build target: use x86_64-linux-android; add UI dump diagnostics
Copilot Feb 23, 2026
ecc9ee2
Add comprehensive diagnostics: screenshot, logcat, CDP check, artifac…
Copilot Feb 24, 2026
5df5d7b
Fix Android e2e: add tabindex=0 to headings for Chrome WebView access…
Copilot Feb 24, 2026
d9ed707
Fix Maestro e2e: stopApp:false + for-loop CDP socket wait + 30s DOM l…
Copilot Feb 25, 2026
37d1fa5
Fix Maestro e2e: correct CDP socket name + remove launchApp to preven…
Copilot Feb 25, 2026
f929a05
Fix Maestro e2e: add launchApp for CDP + body background-color CSS fix
Copilot Feb 25, 2026
4c97ebb
Fix Maestro e2e: pre-launch warm-up + 90s timeout to beat race condit…
Copilot Feb 26, 2026
f2f2425
Merge branch 'main' into copilot/harmonize-ci-cd-workflow
gfauredev Feb 26, 2026
72b2734
Fix Maestro e2e: remove launchApp + 60s pre-launch sleep to eliminate…
Copilot Feb 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 45 additions & 73 deletions .github/workflows/cd-android.yml → .github/workflows/cd.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
name: CD – Android
name: CD

# Triggers:
# • push to main → builds and updates the rolling "latest-android" pre-release
# • release event → attaches the artifacts to the newly published GitHub release
# • manual → same as push to main
on:
push:
branches: [main]
Expand All @@ -12,10 +8,50 @@ on:
workflow_dispatch:

permissions:
contents: write # required to create/update releases and upload assets
contents: write
pages: write
id-token: write

jobs:
# ── Job 1: build arm64 APK (for distribution) + all-arch AAB ──────────────
deploy-web:
name: Deploy to GitHub Pages
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
concurrency:
group: "pages"
cancel-in-progress: false
steps:
- uses: actions/checkout@v4

- uses: dtolnay/rust-toolchain@stable
with:
targets: wasm32-unknown-unknown

- uses: swatinem/rust-cache@v2

- name: Install Dioxus CLI
uses: taiki-e/install-action@v2
with:
tool: dioxus-cli

- name: Build
run: dx build --release --platform web --base-path /LogOut

- name: Setup Pages
uses: actions/configure-pages@v4

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: ./target/dx/log-workout/release/web/public

- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

# ── Build arm64 APK (for distribution) + all-arch AAB ─────────────────────
build-android:
name: Build Android APK (arm64) & AAB (all archs)
runs-on: ubuntu-latest
Expand All @@ -30,7 +66,7 @@ jobs:
java-version: "17"
distribution: temurin

# ── Step 1: Build arm64-only APK ──────────────────────────────────────
# ── Step 1: Build arm64-only APK ──────────────────────────────────────
# Installing only the arm64 target ensures dx produces a single-ABI APK.
- name: Install arm64 Rust target
uses: dtolnay/rust-toolchain@stable
Expand Down Expand Up @@ -62,7 +98,7 @@ jobs:
cp "$SRC" logout-android-arm64.apk
echo "path=logout-android-arm64.apk" >> "$GITHUB_OUTPUT"

# ── Step 2: Add remaining targets and build all-arch AAB ──────────────
# ── Step 2: Add remaining targets and build all-arch AAB ──────────────
# The arm64 Rust artifacts are cached; only the three extra targets compile.
- name: Add remaining Android Rust targets
run: rustup target add armv7-linux-androideabi i686-linux-android x86_64-linux-android
Expand Down Expand Up @@ -146,67 +182,3 @@ jobs:
--notes "$NOTES" \
--repo "$GITHUB_REPOSITORY"
fi

# ── Job 2: Android E2E tests using Maestro on an x86_64 emulator ──────────
e2e-android:
name: Android E2E Tests (Maestro)
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: "17"
distribution: temurin

# Build for x86_64 so the APK runs on the CI emulator.
- name: Install x86_64 Android Rust target
uses: dtolnay/rust-toolchain@stable
with:
targets: x86_64-linux-android

- uses: swatinem/rust-cache@v2

- name: Install Dioxus CLI
uses: taiki-e/install-action@v2
with:
tool: dioxus-cli

- name: Build x86_64 APK for emulator testing
run: >-
dx build
--platform android
--release
--no-default-features
--features mobile-platform

- name: Locate x86_64 APK
id: apk
run: |
SRC=$(find target/dx -name "*.apk" -maxdepth 10 | head -1)
[ -n "$SRC" ] || { echo "::error::No APK found under target/dx"; exit 1; }
echo "Found APK: $SRC"
echo "path=$(realpath "$SRC")" >> "$GITHUB_OUTPUT"

# Enable KVM for hardware-accelerated Android emulation on ubuntu-latest.
- name: Enable KVM
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm

- name: Install Maestro
run: |
curl -Ls "https://get.maestro.mobile.dev" | bash
echo "$HOME/.maestro/bin" >> "$GITHUB_PATH"

- name: Run Maestro flows on Android emulator
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 33
arch: x86_64
script: |
adb install "${{ steps.apk.outputs.path }}"
maestro test maestro/
93 changes: 93 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -289,3 +289,96 @@ jobs:
- name: Fail if any E2E test failed
if: steps.e2e.outcome == 'failure'
run: exit 1

e2e-android:
name: Android E2E Tests (Maestro)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: "17"
distribution: temurin

# Build for x86_64 so the APK runs on the CI emulator.
# Omit --release so Rust compiles with debug_assertions=true. wry 0.53+
# defaults devtools=true when debug_assertions is on, which calls
# WebView.setWebContentsDebuggingEnabled(true) — enabling the Chrome
# DevTools Protocol (CDP) socket that Maestro uses to read WebView content.
- name: Install x86_64 Android Rust target
uses: dtolnay/rust-toolchain@stable
with:
targets: x86_64-linux-android

- uses: swatinem/rust-cache@v2

- name: Install Dioxus CLI
uses: taiki-e/install-action@v2
with:
tool: dioxus-cli

- name: Build x86_64 APK for emulator testing
run: >-
dx build
--platform android
--target x86_64-linux-android
--no-default-features
--features mobile-platform

- name: Locate x86_64 APK
id: apk
run: |
SRC=$(find target/dx -name "*.apk" -maxdepth 10 | head -1)
[ -n "$SRC" ] || { echo "::error::No APK found under target/dx"; exit 1; }
echo "Found APK: $SRC"
echo "path=$(realpath "$SRC")" >> "$GITHUB_OUTPUT"

# Enable KVM for hardware-accelerated Android emulation on ubuntu-latest.
- name: Enable KVM
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm

- name: Install Maestro
run: |
curl -Ls "https://get.maestro.mobile.dev" | bash
echo "$HOME/.maestro/bin" >> "$GITHUB_PATH"

- name: Run Maestro flows on Android emulator
id: maestro
# continue-on-error so the artifact upload step below always runs
continue-on-error: true
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 33
arch: x86_64
# google_apis provides the Google Chrome WebView (chromium-based) with
# full Chrome DevTools Protocol (CDP) support. The default AOSP system
# image ships a stripped-down WebView that Maestro cannot inspect via
# CDP, causing all text assertions to time out.
target: google_apis
script: |
adb install "${{ steps.apk.outputs.path }}"
# Pre-launch the app so the JVM and Chrome WebView warm up before Maestro starts.
# Without this, Maestro's UIAutomator2 polling during extendedWaitUntil slows
# cold-start rendering from ~22 s to ~60 s, hitting the timeout boundary.
adb shell monkey -p com.gfaure.logworkout -c android.intent.category.LAUNCHER 1
sleep 60
MAESTRO_CLI_NO_ANALYTICS=1 maestro test maestro/

- name: Upload diagnostics
if: always()
uses: actions/upload-artifact@v4
with:
name: android-e2e-diagnostics
path: |
~/.maestro/tests/
if-no-files-found: ignore
retention-days: 7

- name: Fail if Maestro tests failed
if: steps.maestro.outcome == 'failure'
run: exit 1
59 changes: 0 additions & 59 deletions .github/workflows/deploy.yml

This file was deleted.

6 changes: 6 additions & 0 deletions assets/styles.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/* ===== Base / Reset ===== */
body {
background-color: #111;
color: #e0e0e0;
}

/* ===== Global / Shared ===== */
.container {
padding: 20px;
Expand Down
3 changes: 1 addition & 2 deletions maestro/launch.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# Smoke test: the app launches and displays the home screen.
appId: com.gfaure.logworkout
---
- launchApp
- extendedWaitUntil:
visible:
text: "LogOut"
timeout: 15000
timeout: 30000
- assertVisible: "Log your workOut"
3 changes: 1 addition & 2 deletions maestro/navigation.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
# Test: navigate to the exercise browser via the bottom navigation bar.
appId: com.gfaure.logworkout
---
- launchApp
- extendedWaitUntil:
visible:
text: "LogOut"
timeout: 15000
timeout: 30000
- tapOn: "📚"
- assertVisible: "Exercise Database"
- tapOn: "💪"
Expand Down
3 changes: 1 addition & 2 deletions maestro/session.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
# Test: start a new workout session then cancel it.
appId: com.gfaure.logworkout
---
- launchApp
- extendedWaitUntil:
visible:
text: "LogOut"
timeout: 15000
timeout: 30000
- tapOn: "+"
- assertVisible: "Active Session"
- tapOn: "Cancel Session"
Expand Down
2 changes: 1 addition & 1 deletion src/components/active_session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ pub fn SessionView() -> Element {
header {
class: "session-header",
div {
h2 { class: "session-header__title", "⏱️ Active Session" }
h2 { class: "session-header__title", tabindex: 0, "⏱️ Active Session" }
p {
class: "session-header__timer",
onclick: move |_| {
Expand Down
2 changes: 1 addition & 1 deletion src/components/exercise_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ pub fn ExerciseListPage() -> Element {

header {
class: "page-header",
h1 { class: "page-title", "📚 Exercise Database" }
h1 { class: "page-title", tabindex: 0, "📚 Exercise Database" }
p { class: "page-subtitle",
"Browse {total} exercises"
}
Expand Down
4 changes: 2 additions & 2 deletions src/components/home.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ pub fn HomePage() -> Element {
} else {
section { class: "sessions-tab",
header { class: "sessions-tab__header",
h1 { class: "app-title", "💪 LogOut" }
p { class: "app-tagline", "Turn off your computer, Log your workOut" }
h1 { class: "app-title", tabindex: 0, "💪 LogOut" }
p { class: "app-tagline", tabindex: 0, "Turn off your computer, Log your workOut" }
}
if completed_sessions().is_empty() {
div { class: "sessions-empty",
Expand Down
Loading