Replace curl-based install of dagger/task with a hard check that
fails immediately if any tool is missing from the runner image,
pointing to .forgejo/Dockerfile as the fix location.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Based on ghcr.io/catthehacker/ubuntu:go-24.04 with stunnel4,
netcat-openbsd, dagger v0.20.8 and task v3.48.0 baked in so
nothing is downloaded during CI runs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace apt-get install with a hard check — if the packages are missing
the job fails immediately with a clear error. Avoids flaky failures when
archive.ubuntu.com is unreachable.
Install once on the runner: sudo apt-get install -y stunnel4 netcat-openbsd
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements issue #132. Builds debug app APK + androidTest APK via Dagger,
then runs them on Firebase Test Lab using the FIREBASE_TEST_LAB_SERVICE_ACCOUNT_KEY
secret and FIREBASE_PROJECT_ID variable.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The old workflow built with build-android-bundle (debug-signed) then uploaded
separately. publish-android stamps the versionCode, re-signs with the release
keystore, and uploads in one Dagger call.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Pass --build-number $(date +%s) to flutter build for both APK and AAB
so each CI run gets a unique version code (fixes "already been used" error)
- Extract UploadToPlayStore(aab, playStoreConfig) as its own Dagger function
so the build and upload are independently callable
- Add build-android-bundle task (exports AAB via dagger export) and
upload-android-bundle task (calls UploadToPlayStore with the local file)
- CI deploy-playstore job now has two steps: Build Android Bundle and
Upload to Play Store, so a failed upload can be retried without rebuilding
- deploy-apk also gets --build-number to avoid version code collisions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Both BuildAndroidApk and BuildAndroidRelease were using the debug
signing config because the keystore and password were never forwarded
into the Dagger container. Add setupKeystore() helper that decodes
ANDROID_KEYSTORE_BASE64 into android/app/upload-keystore.jks and
sets ANDROID_KEYSTORE_PASSWORD, then wire both secrets through
DeployApk, PublishAndroid, and the Taskfile/CI env blocks.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Decodes ANDROID_KEYSTORE_BASE64 and prints the SHA1 fingerprint via
keytool before invoking the Dagger build, to confirm which key is in
the secret vs. what the build actually uses.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The ubuntu-latest pool now includes nodes that run Docker containers with
user namespace isolation, causing chown of the workspace to fail before
checkout can run. The codeberg-small label routes consistently to the
actions-tiny nodes (act-latest image, no user namespace restriction) where
Dagger CI succeeded previously.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The ubuntu-latest runner uses Docker containers (ghcr.io/catthehacker/ubuntu:act-22.04)
which don't have task or dagger pre-installed. These steps were mistakenly removed when
switching from the dagger-dagger host runner back to ubuntu-latest.
Also adds DAGGER_NO_NAG=1 to all dagger-invoking steps.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add Dagger to flake.nix
- Create Dagger module in ci/ with Flutter build/test logic
- Update .forgejo/workflows/ci.yml to use Dagger
- Move Android emulator tests to separate disabled workflow
- Add .daggerignore to exclude host junk
The standalone "Check mocks are up to date" step ran build_runner AOT
compilation separately, then task check ran it again (check-mocks is
already a dep of check). The double invocation caused the build_runner
AOT compile to receive SIGTERM on the CI runner in run 4027578.
task check already verifies mocks via its check-mocks dep, so the
standalone step is redundant.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The deploy steps in build-linux and deploy-playstore already use
continue-on-error: true when SSH secrets may be absent, but
publish-website did not — causing a hard failure when SSH_USER is unset.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The builds page at /builds/ was empty because generate-build-history
only ran inside deploy-playstore; if that job failed early (e.g. Play
Store secrets not configured) the website was never updated, and the
build-linux job never triggered a website update at all.
Changes:
- generate_build_history.py: extend to cover Linux tarballs in addition
to Android APKs, capped at MAX_BUILDS_PER_PLATFORM (30) each
- Taskfile: add website-publish task (generate-build-history +
website-deploy), exclude *.tar.gz from rsync, update descriptions
- .forgejo/workflows/ci.yml: add publish-website job that waits for
both build-linux and deploy-playstore (using always() so it runs
even when deploy-playstore fails), then removes the duplicate
generate/deploy steps from deploy-playstore
- .github/workflows/ci.yml: add deploy job that deploys Linux build,
generates build history, builds Hugo site, and rsyncs to server
- .gitignore: ignore website/content/builds/_index.md (generated),
Python __pycache__, and widget test failure screenshots
- stalwart-dev/integration_ui_test.sh: use ${USER:-$(id -un)} for
robustness in environments where USER is unset
- scripts/test_generate_build_history.py: unit tests for parse_builds
and render_entries covering both platforms
Generated content (builds/_index.md and per-day pages) is not tracked
in git; it is produced at CI time and rsynced to the server.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add check-mocks task that re-runs build_runner and fails if any
*.mocks.dart file differs from what is committed. Wired into
check-fast (pre-commit) and added as an early CI step so stale
mocks are caught before the full test suite runs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Builds and deploys Windows once a day (02:00 UTC) instead of on every
push to main. Skips the build if no commits landed on main in the last
24 hours. Kept disabled (if: false) until a windows-runner is
registered.
Closes#77
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
timeout-minutes doesn't start until a runner accepts the job, so the
job would queue indefinitely. Disable with if: false for now — change
back to github.ref == 'refs/heads/main' once a windows-runner runner
is set up.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
60-minute wait blocks every run. 5 minutes lets it fail fast with
continue-on-error, leaving the rest of the workflow unaffected.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The windows-runner self-hosted runner doesn't exist yet, so the job
would block the run indefinitely. With continue-on-error + timeout it
fails gracefully once a runner is registered and picks up the job.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds build-windows-release and deploy-windows-to-server Taskfile tasks,
a build-windows CI job (requires a windows-runner self-hosted runner),
and extends updateInfoProvider to also cover Platform.isWindows.
latest.json is now extended with a 'windows' key; both deploy tasks
preserve the other platform's URL when updating the file.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Build task embeds GIT_HASH via --dart-define; new deploy-linux-to-server task
packages a tar.gz and updates latest.json on the server. The account list screen
shows a MaterialBanner when a newer Linux build is available.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
SSH secrets (SSH_USER, SSH_HOST, SSH_PRIVATE_KEY) are not yet configured
as repository secrets. Mark the four SSH-dependent steps continue-on-error
so the Play Store deploy job succeeds while those secrets are pending.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The deploy-apk-to-server task depends on build-android which signs the
APK — it needs the keystore password or the packageRelease Gradle task
fails.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- scripts/generate_build_history.py: SSH into server, list APKs under
public_html/builds/YYYY/MM/DD/, fetch commit titles from Codeberg API,
and write Hugo content pages to website/content/builds/
- Taskfile: add deploy-apk-to-server and generate-build-history tasks;
add --exclude='*.apk' to website-deploy rsync so APKs survive redeploy
- CI: after Play Store deploy, set up SSH key, scp APK, generate history,
then deploy website
- .gitignore: exclude website/content/builds/ (generated at deploy time)
- website/hugo.toml: add Builds nav item
Closes#73
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>