version: "3" silent: true tasks: default: desc: Run all checks (analyze + unit tests + widget tests + integration, in parallel) deps: [check] _nix-check: internal: true run: once cmds: - cmd: | if ! nix show-config experimental-features 2>/dev/null | grep -q "nix-command" || ! nix show-config experimental-features 2>/dev/null | grep -q "flakes"; then echo "CRITICAL: Nix experimental features 'nix-command' and 'flakes' must be enabled." echo "Attempting to fix by updating ~/.config/nix/nix.conf ..." mkdir -p ~/.config/nix CONF=~/.config/nix/nix.conf if [ ! -f "$CONF" ]; then echo "experimental-features = nix-command flakes" > "$CONF" elif ! grep -q "experimental-features" "$CONF"; then echo "experimental-features = nix-command flakes" >> "$CONF" elif ! grep -E "experimental-features.*nix-command" "$CONF" || ! grep -E "experimental-features.*flakes" "$CONF"; then echo "Your $CONF already has experimental-features but is missing 'nix-command' or 'flakes'." echo "Please add them manually to the 'experimental-features' line." exit 1 fi echo "Local configuration updated. Please re-run your command." exit 1 fi _preflight: internal: true run: once deps: [_nix-check] preconditions: - sh: test "${DIRENV_DIR#-}" = "{{.TASKFILE_DIR}}" msg: "Not in nix dev shell. Run: nix develop" cmds: - scripts/silent_on_success.sh pre-commit install _flutter-check: internal: true run: once deps: [_preflight] cmds: - cmd: scripts/silent_on_success.sh fvm install --skip-pub-get - cmd: scripts/silent_on_success.sh fvm use --skip-pub-get setup: desc: Fully set up the dev environment (FVM, pub get, codegen, hooks) deps: [_preflight, _codegen, generate-changelog] cmds: - echo "Setup complete." generate-changelog: desc: Generate assets/changelog.txt from git history cmds: - mkdir -p assets - 'git log -n 50 --pretty=format:"* %ad [%h](https://codeberg.org/guettli/sharedinbox/commit/%H): %s" --date=short > assets/changelog.txt' _pub-get: internal: true run: once deps: [_flutter-check] cmds: - scripts/silent_on_success.sh fvm flutter pub get --suppress-analytics _linux-deps-check: internal: true run: once preconditions: - sh: command -v clang >/dev/null 2>&1 msg: "Linux desktop deps missing. Run: sudo apt-get install -y clang cmake ninja-build pkg-config libgtk-3-dev libstdc++-12-dev" - sh: pkg-config --exists gtk+-3.0 2>/dev/null msg: "Linux desktop deps missing. Run: sudo apt-get install -y clang cmake ninja-build pkg-config libgtk-3-dev libstdc++-12-dev" install-hooks: desc: Install pre-commit hooks (requires pre-commit; see .pre-commit-config.yaml) cmds: - pre-commit install _codegen: internal: true run: once deps: [_pub-get] sources: - lib/**/*.dart - pubspec.yaml generates: - lib/**/*.g.dart cmds: - scripts/silent_on_success.sh fvm flutter pub run build_runner build --delete-conflicting-outputs codegen: desc: Generate Drift DB code (run after any schema change) deps: [_preflight, _pub-get] sources: - lib/**/*.dart - pubspec.yaml generates: - lib/**/*.g.dart cmds: - fvm flutter pub run build_runner build --delete-conflicting-outputs analyze: desc: Static analysis (flutter analyze) deps: [_preflight, _codegen] sources: - lib/**/*.dart - test/**/*.dart - pubspec.yaml - analysis_options.yaml cmds: - scripts/run_analyze.sh format: desc: Format all Dart source files deps: [_preflight] sources: - "**/*.dart" cmds: - fvm dart format lib test analyze-fix: desc: Auto-fix lint issues with dart fix --apply deps: [_preflight] sources: - lib/**/*.dart - test/**/*.dart cmds: - fvm dart fix --apply test: desc: Unit tests + coverage gate (fails if any non-excluded lib/ file is missing) deps: [_preflight, _codegen] sources: - lib/**/*.dart - test/unit/**/*.dart generates: - coverage/lcov.info cmds: - scripts/run_unit_tests.sh test-widget: desc: Widget tests — headless, no display or network required deps: [_preflight, _codegen] sources: - lib/**/*.dart - test/widget/**/*.dart cmds: - scripts/run_widget_tests.sh test-flutter: desc: Full Flutter test suite (unit + widget + integration) deps: [_preflight] sources: - lib/**/*.dart - test/**/*.dart - integration_test/**/*.dart cmds: - fvm flutter test integration: desc: Integration tests against a local Stalwart mail server deps: [_flutter-check] sources: - lib/**/*.dart - test/integration/**/*.dart cmds: - stalwart-dev/test.sh integration-ui: desc: UI E2E tests on Linux via Xvfb — headless, no emulator needed deps: [_preflight, _linux-deps-check, _pub-get] sources: - lib/**/*.dart - integration_test/app_e2e_test.dart cmds: - stalwart-dev/integration_ui_test.sh integration-android: desc: UI integration tests on a connected Android emulator (Stalwart on host, emulator reaches it via 10.0.2.2) deps: [_preflight, _android-sdk-check, _android-avd-setup] sources: - lib/**/*.dart - integration_test/app_e2e_test.dart - android/**/* generates: - build/integration-android.done cmds: - stalwart-dev/integration_android_test.sh - touch build/integration-android.done build-linux: desc: Build the Linux desktop app (debug) deps: [_preflight, _linux-deps-check, _codegen, generate-changelog] method: timestamp sources: - lib/**/*.dart - linux/**/* - pubspec.yaml generates: - build/linux/x64/debug/bundle/sharedinbox cmds: - scripts/silent_on_success.sh fvm flutter build linux --debug --no-pub build-linux-release: desc: Build the Linux desktop app (release) deps: [_preflight, _linux-deps-check, _codegen, generate-changelog] method: timestamp sources: - lib/**/*.dart - linux/**/* - pubspec.yaml generates: - build/linux/x64/release/bundle/sharedinbox cmds: - scripts/silent_on_success.sh fvm flutter build linux --release --no-pub _android-avd-setup: internal: true run: once status: - test -f "${ANDROID_HOME:-$HOME/Android/Sdk}/emulator/emulator" - test -d "$HOME/.android/avd/sharedinbox_test.avd" cmds: - cmd: | SDK="${ANDROID_HOME:-$HOME/Android/Sdk}" SDKMANAGER="$SDK/cmdline-tools/latest/bin/sdkmanager" AVDMANAGER="$SDK/cmdline-tools/latest/bin/avdmanager" yes | "$SDKMANAGER" --licenses >/dev/null 2>&1 || true "$SDKMANAGER" "emulator" "system-images;android-34;google_apis;x86_64" echo no | "$AVDMANAGER" create avd \ --name sharedinbox_test \ --package "system-images;android-34;google_apis;x86_64" \ --device pixel_4 \ --force _android-sdk-check: internal: true run: once preconditions: - sh: test -d "${ANDROID_HOME:-$HOME/Android/Sdk}" msg: | Android SDK not found. Install it with: wget https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip -O /tmp/cmdtools.zip mkdir -p ~/Android/Sdk/cmdline-tools unzip /tmp/cmdtools.zip -d ~/Android/Sdk/cmdline-tools mv ~/Android/Sdk/cmdline-tools/cmdline-tools ~/Android/Sdk/cmdline-tools/latest ~/Android/Sdk/cmdline-tools/latest/bin/sdkmanager "platform-tools" "build-tools;34.0.0" "platforms;android-34" - sh: ls "${ANDROID_HOME:-$HOME/Android/Sdk}/platforms/" 2>/dev/null | grep -qE '^android-([3-9][4-9]|[4-9][0-9]|[1-9][0-9]{2,})$' msg: | Android platform 34 or higher not found. Install it with: ${ANDROID_HOME:-$HOME/Android/Sdk}/cmdline-tools/latest/bin/sdkmanager "build-tools;34.0.0" "platforms;android-34" build-android: desc: Build a release APK deps: [_preflight, _android-sdk-check, _pub-get, generate-changelog] method: timestamp sources: - lib/**/*.dart - android/**/* - pubspec.yaml generates: - build/app/outputs/flutter-apk/app-release.apk cmds: - ANDROID_HOME=${ANDROID_HOME:-$HOME/Android/Sdk} fvm flutter build apk --release --no-pub | grep -Ev "was tree-shaken|Tree-shaking can be disabled" build-android-bundle: desc: Build a release App Bundle (AAB) deps: [_preflight, _android-sdk-check, _pub-get, generate-changelog] method: timestamp sources: - lib/**/*.dart - android/**/* - pubspec.yaml generates: - build/app/outputs/bundle/release/app-release.aab cmds: - ANDROID_HOME=${ANDROID_HOME:-$HOME/Android/Sdk} fvm flutter build appbundle --release --no-pub | grep -Ev "was tree-shaken|Tree-shaking can be disabled" deploy-android: desc: Build release APK and upload via scp to $ANDROID_APK_SCP_USER@$ANDROID_APK_SCP_HOST:$ANDROID_APK_SCP_PATH deps: [check, build-android] sources: - build/app/outputs/flutter-apk/app-release.apk generates: - build/deploy-android.done dotenv: [".env"] preconditions: - sh: test -n "$ANDROID_APK_SCP_HOST" msg: "ANDROID_APK_SCP_HOST is not set in .env" - sh: test -n "$ANDROID_APK_SCP_USER" msg: "ANDROID_APK_SCP_USER is not set in .env" - sh: test -n "$ANDROID_APK_SCP_PATH" msg: "ANDROID_APK_SCP_PATH is not set in .env" cmds: # integration-android runs after check (not in parallel) so the two E2E # test suites don't compete for CPU and slow the Android emulator. - task: integration-android - scripts/deploy_android.sh - touch build/deploy-android.done run: desc: Run the app on Linux desktop deps: [_preflight, _linux-deps-check, _pub-get] cmds: - fvm flutter run -d linux --no-pub run-android: desc: Run the app on a connected Android emulator (boots sharedinbox_test AVD if needed) deps: [_preflight, _android-sdk-check, _android-avd-setup, _pub-get] cmds: - stalwart-dev/run_android.sh coverage: desc: Coverage gate — run after test (and optionally integration) have written lcov.info deps: [_preflight] cmds: - fvm dart run scripts/check_coverage.dart website-dev: desc: Run Hugo development server cmds: - fvm flutter pub global run # Just a placeholder if nix shell hook isn't active - nix develop --command hugo server --source website -D website-build: desc: Build the static website cmds: - nix develop --command hugo --source website --minify website-deploy: desc: Deploy the website via rsync to public_html deps: [website-build] cmds: - | rsync -avz --delete \ -e "ssh -o StrictHostKeyChecking=no" \ website/public/ \ ${SSH_USER}@${SSH_HOST}:public_html/ check-fast: desc: Pre-commit checks — analyze + unit tests + widget tests (no build, no integration) deps: [analyze, test, test-widget, check-hygiene] check-hygiene: desc: Verify that no forbidden files (like home dir config) are tracked cmds: - | FORBIDDEN=".ssh .bashrc .config .local .cache .gitconfig .android Android .gradle .pub-cache .dartServer .flutter .dart-cli-completion .atuin .bash_logout .profile .zcompdump .zshrc snap .emulator_console_auth_token .lesshst .metadata .tmux.conf" TRACKED=$(git ls-files $FORBIDDEN 2>/dev/null) if [ -n "$TRACKED" ]; then echo "ERROR: The following forbidden files are tracked in git:" echo "$TRACKED" echo "Please remove them with 'git rm --cached '" exit 1 fi echo "Hygiene check passed." _integrations: internal: true run: once cmds: - task: integration - task: integration-ui check: desc: Full check suite — unit tests first, then integration (merges coverage), then gate deps: [analyze, test-widget, build-linux, test] cmds: - task: _integrations - task: coverage