463 lines
16 KiB
Makefile
463 lines
16 KiB
Makefile
# Justfile for White Noise Flutter project
|
|
|
|
# Default recipe - show available commands
|
|
default:
|
|
@just --list
|
|
|
|
# Pre-commit checks: run the same checks as CI locally (quiet mode - minimal output)
|
|
precommit:
|
|
@just _run-quiet "deps-flutter" "flutter deps"
|
|
@just _run-quiet "deps-rust" "rust deps"
|
|
@just _run-quiet "l10n" "l10n generation"
|
|
@just _run-quiet "validate-locales-keys" "l10n validation"
|
|
@just _run-quiet "fix" "auto-fix"
|
|
@just _run-quiet "format" "formatting"
|
|
@just _run-quiet "lint" "linting"
|
|
@just _run-quiet "test-flutter" "flutter tests"
|
|
@just _run-quiet "test-rust" "rust tests"
|
|
@echo "✅ PRECOMMIT PASSED"
|
|
|
|
# Pre-commit checks with verbose output (shows all command output)
|
|
precommit-verbose:
|
|
just deps-flutter
|
|
just deps-rust
|
|
just l10n
|
|
just validate-locales-keys
|
|
just fix
|
|
just format
|
|
just lint
|
|
just test-flutter
|
|
just test-rust
|
|
@echo ""
|
|
@echo "════════════════════════════════════════"
|
|
@echo "✅ ALL PRECOMMIT CHECKS PASSED"
|
|
@echo "════════════════════════════════════════"
|
|
|
|
# Pre-commit checks without auto-fixing (for releases)
|
|
precommit-check:
|
|
just deps-flutter
|
|
just deps-rust
|
|
just l10n-check
|
|
just validate-locales-keys
|
|
just check-rust-format
|
|
just check-dart-format
|
|
just lint
|
|
just test-flutter
|
|
just test-rust
|
|
@echo "✅ All pre-commit checks passed!"
|
|
|
|
# ==============================================================================
|
|
# CODE GENERATION
|
|
# ==============================================================================
|
|
|
|
# Generate Rust bridge code
|
|
generate:
|
|
@echo "🔄 Generating flutter_rust_bridge code..."
|
|
@flutter_rust_bridge_codegen generate > /dev/null 2>&1 || flutter_rust_bridge_codegen generate
|
|
|
|
# Clean and regenerate Rust bridge code
|
|
regenerate: clean-bridge generate
|
|
|
|
# Generate localizations from ARB files
|
|
l10n:
|
|
@echo "🌍 Generating localizations..."
|
|
flutter gen-l10n
|
|
|
|
# Validate l10n files are in sync (fails if regeneration would change anything)
|
|
l10n-check:
|
|
@echo "🔍 Checking l10n files are up-to-date..."
|
|
flutter gen-l10n
|
|
@if ! git diff --quiet lib/l10n/generated/; then \
|
|
echo "❌ Generated l10n files are out of sync. Run 'just l10n' and commit."; \
|
|
git diff --name-only lib/l10n/generated/; \
|
|
exit 1; \
|
|
fi
|
|
@echo "✅ L10n files are up-to-date"
|
|
|
|
# ==============================================================================
|
|
# DEPENDENCIES
|
|
# ==============================================================================
|
|
|
|
# Install/update all dependencies
|
|
deps: deps-rust deps-flutter
|
|
|
|
# Install/update Rust dependencies
|
|
deps-rust:
|
|
@echo "📦 Installing Rust dependencies..."
|
|
cd rust && cargo fetch
|
|
|
|
# Install/update Flutter dependencies
|
|
deps-flutter:
|
|
@echo "📦 Installing Flutter dependencies..."
|
|
@flutter pub get > /dev/null 2>&1 || flutter pub get
|
|
@cd widgetbook && (flutter pub get > /dev/null 2>&1 || flutter pub get)
|
|
|
|
# ==============================================================================
|
|
# RUST OPERATIONS
|
|
# ==============================================================================
|
|
|
|
# Build Rust library for development (debug)
|
|
build-rust-debug:
|
|
@echo "🔨 Building Rust library (debug)..."
|
|
cd rust && cargo build
|
|
|
|
# Test Rust code
|
|
test-rust:
|
|
@echo "🧪 Testing Rust code..."
|
|
cd rust && cargo test
|
|
|
|
# Test Rust code with minimal output (for agents/CI)
|
|
test-rust-quiet:
|
|
@cd rust && cargo test -q
|
|
|
|
# Format Rust code
|
|
format-rust:
|
|
@echo "💅 Formatting Rust code..."
|
|
cd rust && cargo fmt
|
|
|
|
# Check Rust code formatting (CI-style check)
|
|
check-rust-format:
|
|
@echo "🔍 Checking Rust code formatting..."
|
|
cd rust && cargo fmt --check
|
|
|
|
# Lint Rust code
|
|
lint-rust:
|
|
@echo "🧹 Linting Rust code..."
|
|
cd rust && cargo clippy --package rust_lib_whitenoise -- -D warnings
|
|
|
|
# Run Rust documentation
|
|
docs-rust:
|
|
@echo "📚 Generating Rust documentation..."
|
|
cd rust && cargo doc --open
|
|
|
|
# ==============================================================================
|
|
# FLUTTER OPERATIONS
|
|
# ==============================================================================
|
|
|
|
# Run Flutter analyzer
|
|
analyze:
|
|
@echo "🔍 Running Flutter analyzer..."
|
|
flutter analyze --fatal-infos
|
|
@echo "🔍 Running Flutter analyzer (widgetbook)..."
|
|
cd widgetbook && flutter analyze --fatal-infos
|
|
|
|
# Format Dart code
|
|
format-dart:
|
|
@echo "💅 Formatting Dart code..."
|
|
dart format lib/ test/ integration_test/ widgetbook/lib/
|
|
|
|
# Check Dart code formatting (CI-style check)
|
|
check-dart-format:
|
|
@echo "🔍 Checking Dart code formatting..."
|
|
dart format --set-exit-if-changed lib/ test/ integration_test/ widgetbook/lib/
|
|
|
|
# Test Flutter code
|
|
test-flutter:
|
|
@echo "🧪 Testing Flutter code..."
|
|
@if [ -d "test" ]; then \
|
|
flutter test --reporter=compact && echo "✅ Flutter tests passed!" || (echo "❌ Flutter tests failed!" && exit 1); \
|
|
else \
|
|
echo "No test directory found. Create tests in test/ directory."; \
|
|
fi
|
|
|
|
# Test Flutter code with minimal output (for agents/CI)
|
|
test-flutter-quiet:
|
|
@if [ -d "test" ]; then \
|
|
flutter test --no-pub --reporter=failures-only; \
|
|
else \
|
|
echo "No test directory found."; \
|
|
fi
|
|
|
|
# Resolves the integration-test device: the given id, else the one booted simulator.
|
|
_resolve-device device:
|
|
@device="{{ device }}"; \
|
|
if [ -n "$device" ]; then echo "$device"; exit 0; fi; \
|
|
booted=$(xcrun simctl list devices booted 2>/dev/null | grep -oiE '[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}'); \
|
|
count=$(printf '%s' "$booted" | grep -c .); \
|
|
if [ "$count" -eq 1 ]; then \
|
|
echo "Using booted simulator $booted" >&2; \
|
|
echo "$booted"; \
|
|
elif [ "$count" -eq 0 ]; then \
|
|
echo "No device id given and no booted simulator found. Boot one, pass a device id, or set WHITENOISE_INTEGRATION_DEVICE." >&2; \
|
|
exit 1; \
|
|
else \
|
|
echo "Multiple booted simulators — pass a device id or set WHITENOISE_INTEGRATION_DEVICE:" >&2; \
|
|
xcrun simctl list devices booted >&2; \
|
|
exit 1; \
|
|
fi
|
|
|
|
# Run Flutter integration tests. Requires local Nostr relays on ports 8080 and 7777.
|
|
|
|
# Run one file by passing its path: `just int-test integration_test/messaging_interactions_test.dart`.
|
|
# Device: WHITENOISE_INTEGRATION_DEVICE, else the one booted simulator.
|
|
int-test target="integration_test/all_tests.dart" device=env("WHITENOISE_INTEGRATION_DEVICE", "") flavor="staging":
|
|
@echo "🧪 Testing Flutter integration flows..."
|
|
@device=$(just _resolve-device "{{ device }}") || exit 1; \
|
|
if [ -n "{{ flavor }}" ]; then \
|
|
flutter test -d "$device" --flavor {{ flavor }} {{ target }}; \
|
|
else \
|
|
flutter test -d "$device" {{ target }}; \
|
|
fi
|
|
|
|
# Run Flutter integration tests with minimal output. Requires local Nostr relays on ports 8080 and 7777.
|
|
|
|
# Run one file by passing its path: `just int-test-quiet integration_test/messaging_interactions_test.dart`.
|
|
# Device: WHITENOISE_INTEGRATION_DEVICE, else the one booted simulator.
|
|
int-test-quiet target="integration_test/all_tests.dart" device=env("WHITENOISE_INTEGRATION_DEVICE", "") flavor="staging":
|
|
@if [ ! -e "{{ target }}" ]; then \
|
|
echo "No integration test target found at {{ target }}."; \
|
|
exit 1; \
|
|
fi; \
|
|
device=$(just _resolve-device "{{ device }}") || exit 1; \
|
|
if [ -n "{{ flavor }}" ]; then \
|
|
flutter test -d "$device" --flavor {{ flavor }} --no-pub --reporter=failures-only {{ target }}; \
|
|
else \
|
|
flutter test -d "$device" --no-pub --reporter=failures-only {{ target }}; \
|
|
fi
|
|
|
|
coverage min="99":
|
|
@echo "🧪 Running Flutter tests with coverage..."
|
|
flutter test --coverage && \
|
|
./scripts/check-coverage.sh --min {{ min }}
|
|
|
|
coverage-report:
|
|
@echo "🧪 Generating coverage report..."
|
|
flutter test --coverage && \
|
|
./scripts/check-coverage.sh && \
|
|
genhtml coverage/lcov.info -o coverage/html
|
|
@echo "📊 Coverage report generated at coverage/html/index.html"
|
|
|
|
validate-locales-keys:
|
|
@echo "🔍 Validating l10n keys..."
|
|
./scripts/validate-locales-keys.sh
|
|
|
|
test-release-scripts:
|
|
@bash test/scripts/validate_release_version_test.sh
|
|
@bash test/scripts/release_automation_config_test.sh
|
|
|
|
# ==============================================================================
|
|
# CLEANING
|
|
# ==============================================================================
|
|
|
|
# Clean generated bridge files only
|
|
clean-bridge:
|
|
@echo "🧹 Cleaning generated bridge files..."
|
|
rm -f rust/src/frb_generated.rs
|
|
rm -rf lib/src/rust/
|
|
|
|
# Clean Flutter build cache
|
|
clean-flutter:
|
|
@echo "🧹 Cleaning Flutter build cache..."
|
|
flutter clean
|
|
|
|
# Clean Rust build cache
|
|
clean-rust:
|
|
@echo "🧹 Cleaning Rust build cache..."
|
|
cd rust && cargo clean
|
|
|
|
# Clean everything (bridge files + flutter + rust)
|
|
clean-all: clean-bridge clean-flutter clean-rust
|
|
@echo "✨ All clean!"
|
|
|
|
# ==============================================================================
|
|
# WIDGETBOOK
|
|
# ==============================================================================
|
|
|
|
deps-widgetbook:
|
|
@echo "📦 Installing Widgetbook dependencies..."
|
|
@cd widgetbook && (flutter pub get > /dev/null 2>&1 || flutter pub get)
|
|
|
|
generate-widgetbook:
|
|
@echo "🔄 Generating Widgetbook stories..."
|
|
cd widgetbook && dart run build_runner build --delete-conflicting-outputs
|
|
|
|
widgetbook-macos: deps-widgetbook generate-widgetbook
|
|
@echo "📖 Running Widgetbook on macOS..."
|
|
cd widgetbook && flutter run -d macos
|
|
|
|
widgetbook-linux: deps-widgetbook generate-widgetbook
|
|
@echo "📖 Running Widgetbook on Linux..."
|
|
cd widgetbook && flutter run -d linux
|
|
|
|
# ==============================================================================
|
|
# FORMATTING & LINTING
|
|
# ==============================================================================
|
|
|
|
# Format all code (Rust + Dart)
|
|
format: format-rust format-dart
|
|
|
|
# Lint all code (Rust + Dart)
|
|
lint: lint-rust analyze
|
|
|
|
# Fix common issues
|
|
fix:
|
|
@echo "🔧 Fixing common issues..."
|
|
cd rust && cargo fix --allow-dirty
|
|
dart fix --apply
|
|
|
|
# ==============================================================================
|
|
# BUILDING - ANDROID
|
|
|
|
# ==============================================================================
|
|
build-android:
|
|
./scripts/build_android.sh
|
|
|
|
build-android-quiet:
|
|
@./scripts/build_android.sh > /dev/null 2>&1 && echo "✅ Android build complete" || { echo "❌ Android build failed"; false; }
|
|
|
|
# Build per-ABI split APKs (separate .apk per architecture)
|
|
build-split-apk flavor="production":
|
|
./scripts/build_android.sh && flutter build apk --flavor {{ flavor }} --split-per-abi
|
|
|
|
# Build an Android App Bundle (per-ABI splitting handled by Play Store)
|
|
build-aab flavor="production":
|
|
./scripts/build_android.sh && flutter build appbundle --flavor {{ flavor }}
|
|
|
|
when-apk: (build-split-apk "staging")
|
|
|
|
# Build versioned release artifacts for all platforms (APKs + IPA) into build/releases/
|
|
|
|
# Produces split APKs with .sha256 sidecar files, an IPA (macOS only), and build_info.txt
|
|
build-release:
|
|
./scripts/build_release.sh
|
|
|
|
# Android-only release artifacts
|
|
build-release-android:
|
|
./scripts/build_release.sh --android
|
|
|
|
# iOS-only release artifacts (macOS only)
|
|
build-release-ios:
|
|
./scripts/build_release.sh --ios
|
|
|
|
# ==============================================================================
|
|
# RELEASE AUTOMATION
|
|
# ==============================================================================
|
|
|
|
# Validate release version metadata, optionally against a git tag
|
|
release-doctor tag="":
|
|
@if [ -n "{{ tag }}" ]; then \
|
|
bundle exec fastlane release_doctor tag:"{{ tag }}"; \
|
|
else \
|
|
bundle exec fastlane release_doctor; \
|
|
fi
|
|
|
|
# Build staging Android release artifacts with Fastlane
|
|
release-build-android-staging tag="":
|
|
@if [ -n "{{ tag }}" ]; then \
|
|
bundle exec fastlane build_android_staging tag:"{{ tag }}"; \
|
|
else \
|
|
bundle exec fastlane build_android_staging; \
|
|
fi
|
|
|
|
# Build production Android release artifacts with Fastlane
|
|
release-build-android-production tag="":
|
|
@if [ -n "{{ tag }}" ]; then \
|
|
bundle exec fastlane build_android_production tag:"{{ tag }}"; \
|
|
else \
|
|
bundle exec fastlane build_android_production; \
|
|
fi
|
|
|
|
# Build staging iOS IPA for App Store Connect/TestFlight with Fastlane
|
|
release-build-ios-staging tag="":
|
|
@if [ -n "{{ tag }}" ]; then \
|
|
bundle exec fastlane build_ios_staging tag:"{{ tag }}"; \
|
|
else \
|
|
bundle exec fastlane build_ios_staging; \
|
|
fi
|
|
|
|
# Build production iOS IPA for App Store Connect/TestFlight with Fastlane
|
|
release-build-ios-production tag="":
|
|
@if [ -n "{{ tag }}" ]; then \
|
|
bundle exec fastlane build_ios_production tag:"{{ tag }}"; \
|
|
else \
|
|
bundle exec fastlane build_ios_production; \
|
|
fi
|
|
|
|
# Build staging app release artifacts with Fastlane
|
|
release-build-staging tag="":
|
|
@if [ -n "{{ tag }}" ]; then \
|
|
bundle exec fastlane build_staging_release tag:"{{ tag }}"; \
|
|
else \
|
|
bundle exec fastlane build_staging_release; \
|
|
fi
|
|
|
|
# Build production app release artifacts with Fastlane
|
|
release-build-production tag="":
|
|
@if [ -n "{{ tag }}" ]; then \
|
|
bundle exec fastlane build_production_release tag:"{{ tag }}"; \
|
|
else \
|
|
bundle exec fastlane build_production_release; \
|
|
fi
|
|
|
|
# Build staging and production release artifacts with Fastlane
|
|
release-build-all tag="":
|
|
@if [ -n "{{ tag }}" ]; then \
|
|
bundle exec fastlane build_all_release_artifacts tag:"{{ tag }}"; \
|
|
else \
|
|
bundle exec fastlane build_all_release_artifacts; \
|
|
fi
|
|
|
|
# ==============================================================================
|
|
# BUILDING - iOS
|
|
# ==============================================================================
|
|
|
|
# Build Rust native libraries for iOS (device + simulator)
|
|
build-ios:
|
|
./scripts/build_ios.sh
|
|
|
|
# Build Rust native libraries for iOS (quiet, for agents/CI)
|
|
build-ios-quiet:
|
|
@./scripts/build_ios.sh > /dev/null 2>&1 && echo "✅ iOS build complete" || { echo "❌ iOS build failed"; false; }
|
|
|
|
# Build a production IPA for App Store Connect submission
|
|
build-production-ipa:
|
|
./scripts/build_ios.sh && flutter build ipa --flavor production --export-method app-store
|
|
|
|
# Build a staging IPA for App Store Connect submission
|
|
build-staging-ipa:
|
|
./scripts/build_ios.sh && flutter build ipa --flavor staging --export-method app-store
|
|
|
|
# Build a staging IPA for local device installation (development signing)
|
|
build-staging-ipa-dev:
|
|
./scripts/build_ios.sh && flutter build ipa --flavor staging --export-method development
|
|
|
|
# ==============================================================================
|
|
# RUN
|
|
# ==============================================================================
|
|
|
|
# Run the app on a connected device (staging flavor by default)
|
|
run flavor="staging":
|
|
flutter run --flavor {{ flavor }}
|
|
|
|
# Run the app on a connected device (production flavor)
|
|
run-production:
|
|
flutter run --flavor production
|
|
|
|
# Build Rust libs and install on connected iOS device
|
|
# Usage: just install-ios <device> [flavor] [extra flags]
|
|
# Example: just install-ios "JG 16e Test"
|
|
|
|
# Example: just install-ios "JG 16e Test" production --release
|
|
install-ios device flavor="staging" *FLAGS="":
|
|
./scripts/build_ios.sh && flutter run --flavor {{ flavor }} -d "{{ device }}" {{ FLAGS }}
|
|
|
|
# ==============================================================================
|
|
# HELPER RECIPES
|
|
# ==============================================================================
|
|
|
|
# Run a recipe quietly, showing only name and pass/fail status (internal use)
|
|
[private]
|
|
_run-quiet recipe label:
|
|
#!/usr/bin/env bash
|
|
TMPFILE=$(mktemp)
|
|
trap 'rm -f "$TMPFILE"' EXIT
|
|
printf "%-20s" "{{ label }}..."
|
|
if just {{ recipe }} > "$TMPFILE" 2>&1; then
|
|
echo "✓"
|
|
else
|
|
echo "✗"
|
|
echo ""
|
|
cat "$TMPFILE"
|
|
exit 1
|
|
fi
|