diff --git a/Makefile b/Makefile index 4ceea71..9cb2aff 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,15 @@ SHELL := /bin/bash -.PHONY: help packages clean-builds gradle-update docs +.PHONY: help packages clean-builds gradle-update docs analyze test doctor help: ## Show available commands @echo "Available commands:" @echo "" @echo " make help Show this help" @echo " make packages Run 'flutter packages get' for all apps" + @echo " make analyze Run 'flutter analyze' for all apps" + @echo " make test Run 'flutter test' for all apps with tests" + @echo " make doctor Check every app for configuration drift" @echo " make clean-builds Move all build folders to trash" @echo " make gradle-update Upgrade Gradle wrappers" @echo " make docs Regenerate documentation/EXAMPLES.md" @@ -24,6 +27,15 @@ help: ## Show available commands packages: ## Run flutter packages get for all apps ./scripts/get_packages.sh +analyze: ## Run flutter analyze for all apps + ./scripts/analyze_all.sh + +test: ## Run flutter test for all apps that have tests + ./scripts/test_all.sh + +doctor: ## Check all apps for configuration drift + ./scripts/repo_doctor.sh + clean-builds: ## Move all build folders to trash ./scripts/delete_build_folder.sh diff --git a/bmi_calculator/android/gradle/wrapper/gradle-wrapper.properties b/bmi_calculator/android/gradle/wrapper/gradle-wrapper.properties index a20f2c4..1e922f4 100644 --- a/bmi_calculator/android/gradle/wrapper/gradle-wrapper.properties +++ b/bmi_calculator/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.0-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-all.zip diff --git a/documentation/MAINTENANCE.md b/documentation/MAINTENANCE.md index 825f7ab..24e4364 100644 --- a/documentation/MAINTENANCE.md +++ b/documentation/MAINTENANCE.md @@ -8,6 +8,9 @@ All maintenance commands are available through the `Makefile` at the repository | --- | --- | | `make help` | Show all available commands | | `make packages` | Run `flutter packages get` for all example apps | +| `make analyze` | Run `flutter analyze` for all example apps | +| `make test` | Run `flutter test` for all example apps that have tests | +| `make doctor` | Check every app for configuration drift | | `make clean-builds` | Move all build folders to trash | | `make gradle-update` | Upgrade Gradle wrappers to the latest version | | `make docs` | Regenerate `documentation/EXAMPLES.md` from the app folders | @@ -16,6 +19,17 @@ All maintenance commands are available through the `Makefile` at the repository `make gradle-update` upgrades the Gradle wrapper of every example app. +## Drift checks + +`make doctor` scans every example app and reports configuration drift: non-standard +SDK constraints, missing `analysis_options.yaml` or `flutter_lints`, pubspec names +that do not match their folder, Android `applicationId`s outside the +`github.nisrulz.*` convention, non-standard Gradle versions, apps missing from +`EXAMPLES.md`, and generated files accidentally tracked in git. It exits non-zero +when issues are found, so you can use it as a pre-commit gate. + +Run `make analyze` after changing any app to confirm `flutter analyze` is clean. + | Option | Description | | --- | --- | | `VERSION=` | Target a specific Gradle version. Default: latest from GitHub | @@ -37,6 +51,7 @@ in `/android/app/` before they can be built: - `firebase_google_authentication` - `google_signin` +- `push_notifications` - `using_firebase_db` The file is never committed because it contains your Firebase project config. diff --git a/push_notifications/android/gradle/wrapper/gradle-wrapper.properties b/push_notifications/android/gradle/wrapper/gradle-wrapper.properties index 3fa8f86..69dd0d0 100644 --- a/push_notifications/android/gradle/wrapper/gradle-wrapper.properties +++ b/push_notifications/android/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,9 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.0-bin.zip networkTimeout=10000 +retries=0 +retryBackOffMs=500 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/scripts/analyze_all.sh b/scripts/analyze_all.sh new file mode 100755 index 0000000..813f617 --- /dev/null +++ b/scripts/analyze_all.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Runs `flutter analyze` in every example app and reports the results. +# Exits non-zero if any app has analyzer issues. + +source "$(dirname "${BASH_SOURCE[0]}")/common.sh" + +clean=0 +issues=0 +failed=0 +apps_with_issues=() + +analyze_app() { + local dir="$1" + local app + app=$(basename "$dir") + + local out + if ! out=$(cd "$dir" && flutter analyze 2>&1); then + failed=$((failed + 1)) + return + fi + + local summary + summary=$(echo "$out" | tail -1) + if echo "$out" | grep -q "No issues found"; then + clean=$((clean + 1)) + else + issues=$((issues + 1)) + apps_with_issues+=("$app") + printf " %-30s %s\n" "$app" "$summary" + fi +} + +separator +echo " Running flutter analyze for all Flutter apps:" +for_each_app pubspec.yaml analyze_app +separator +printf " %-16s %s\n" "Clean:" "$clean" +printf " %-16s %s\n" "With issues:" "$issues" +printf " %-16s %s\n" "Failed to run:" "$failed" +if [ "${#apps_with_issues[@]}" -gt 0 ]; then + echo " Apps with issues:" + printf " %s\n" "${apps_with_issues[@]}" +fi +separator + +[ "$issues" -eq 0 ] && [ "$failed" -eq 0 ] \ No newline at end of file diff --git a/scripts/repo_doctor.sh b/scripts/repo_doctor.sh new file mode 100755 index 0000000..e6c8fed --- /dev/null +++ b/scripts/repo_doctor.sh @@ -0,0 +1,104 @@ +#!/usr/bin/env bash +set -uo pipefail + +# Reports repository drift across all example apps. +# Run after adding or modifying an app, or before a release. +# Exits non-zero if any issues are found. + +source "$(dirname "${BASH_SOURCE[0]}")/common.sh" + +STD_SDK='sdk: ">=3.0.0 <4.0.0"' +GRADLE_MODE="9.7.0" + +issues=0 + +report() { + local label="$1" + shift + if [ "$#" -eq 0 ]; then + return + fi + issues=1 + echo "" + echo " $label:" + for item in "$@"; do + printf " %s\n" "$item" + done +} + +collect() { + local label="$1" + shift + local found=() + for app in ./*; do + if [ -f "$app/pubspec.yaml" ]; then + local name + name=$(basename "$app") + "$@" "$app" "$name" && found+=("$name") + fi + done + report "$label" "${found[@]}" +} + +check_sdk() { + local app="$1" name="$2" + ! grep -qF "$STD_SDK" "$app/pubspec.yaml" +} + +check_lints() { + local app="$1" name="$2" + [ ! -f "$app/analysis_options.yaml" ] || ! grep -q "flutter_lints" "$app/pubspec.yaml" +} + +check_name() { + local app="$1" name="$2" + [ "$(grep -m1 '^name:' "$app/pubspec.yaml" | awk '{print $2}')" != "$name" ] +} + +check_android_id() { + local app="$1" name="$2" + local f="$app/android/app/build.gradle.kts" + [ ! -f "$f" ] && return 1 + ! grep -q 'namespace = "github\.nisrulz\.' "$f" +} + +check_gradle() { + local app="$1" name="$2" + local props="$app/android/gradle/wrapper/gradle-wrapper.properties" + [ ! -f "$props" ] && return 1 + ! grep -q "$GRADLE_MODE" "$props" +} + +check_docs() { + local app="$1" name="$2" + ! grep -q "(/$name)" documentation/EXAMPLES.md +} + +separator +echo " Repository doctor:" +echo " Checking all apps for configuration drift." + +collect "Apps with a non-standard SDK constraint" check_sdk +collect "Apps missing analysis_options.yaml or flutter_lints" check_lints +collect "Apps whose pubspec name does not match the folder" check_name +collect "Apps not using the github.nisrulz.* Android applicationId" check_android_id +collect "Apps not on the standard Gradle version" check_gradle +collect "Apps missing from documentation/EXAMPLES.md (run 'make docs')" check_docs + +# Tracked generated files that should not be in git. +tracked_generated=$(git ls-files | grep -E "\.dart_tool/|GeneratedPluginRegistrant|\.flutter-plugins-dependencies|pubspec\.lock" || true) +if [ -n "$tracked_generated" ]; then + issues=1 + echo "" + echo " Tracked generated files (remove with 'git rm --cached'):" + echo "$tracked_generated" | sed 's/^/ /' +fi + +separator +if [ "$issues" -eq 0 ]; then + echo " All checks passed." +else + echo " Issues found. Fix them before committing." + exit 1 +fi +separator \ No newline at end of file diff --git a/scripts/test_all.sh b/scripts/test_all.sh new file mode 100755 index 0000000..5ff7401 --- /dev/null +++ b/scripts/test_all.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Runs `flutter test` in every example app that has a test directory. +# Exits non-zero if any test run fails. + +source "$(dirname "${BASH_SOURCE[0]}")/common.sh" + +passed=0 +failed=0 +skipped=0 +failed_apps=() + +run_tests() { + local dir="$1" + local app + app=$(basename "$dir") + + if [ ! -d "$dir/test" ]; then + skipped=$((skipped + 1)) + return + fi + + if (cd "$dir" && flutter test >/dev/null 2>&1); then + passed=$((passed + 1)) + else + failed=$((failed + 1)) + failed_apps+=("$app") + fi +} + +separator +echo " Running flutter test for all Flutter apps:" +for_each_app pubspec.yaml run_tests +separator +printf " %-16s %s\n" "Passed:" "$passed" +printf " %-16s %s\n" "Failed:" "$failed" +printf " %-16s %s\n" "No tests:" "$skipped" +if [ "${#failed_apps[@]}" -gt 0 ]; then + echo " Failed apps:" + printf " %s\n" "${failed_apps[@]}" +fi +separator + +[ "$failed" -eq 0 ] \ No newline at end of file