├── .github └── workflows │ ├── _deploy-android-app.yml │ ├── _deploy-env-apps.yml │ ├── _deploy-ios-app.yml │ ├── _test_with_coverage.yml │ ├── build.yml │ ├── deploy-prod-apps.yml │ ├── deploy-uat-apps.yml │ └── notify-pull-requests.yml ├── .gitignore ├── .metadata ├── .releaserc.json ├── .releaserc.prod.json ├── .releaserc.uat.json ├── README.md ├── analysis_options.yaml ├── app ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── orevial │ │ │ │ │ └── flutter_ci_cd_demo │ │ │ │ │ └── MainActivity.kt │ │ │ └── res │ │ │ │ ├── drawable-v21 │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable │ │ │ │ └── launch_background.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── values-night │ │ │ │ └── styles.xml │ │ │ │ └── values │ │ │ │ └── styles.xml │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── settings.gradle ├── ios │ ├── .gitignore │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── WorkspaceSettings.xcsettings │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── Dev.xcscheme │ │ │ ├── Prod.xcscheme │ │ │ └── UAT.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── Runner │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ └── README.md │ │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ │ ├── Info.plist │ │ └── Runner-Bridging-Header.h ├── lib │ ├── app.dart │ ├── main_dev.dart │ ├── main_prod.dart │ ├── main_uat.dart │ └── pages │ │ └── home_page.dart ├── pubspec.lock ├── pubspec.yaml └── test │ └── app_test.dart ├── coverage └── .gitkeep ├── coverage_report └── .gitkeep ├── design_system ├── lib │ ├── design │ │ ├── colors.design.dart │ │ ├── spacings.design.dart │ │ └── theme.dart │ └── design_system.dart ├── pubspec.lock ├── pubspec.yaml └── test │ └── design_test.dart ├── melos.yaml ├── scripts ├── combine-coverage.sh ├── generate-html-coverage.sh ├── keystore_properties_template.yaml ├── pubspec_template.yaml ├── semver.sh └── test-with-coverage.sh └── test_reports └── .gitkeep /.github/workflows/_deploy-android-app.yml: -------------------------------------------------------------------------------- 1 | name: 📦🚀 Build & deploy Android app for an environment 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | environment-name: 7 | required: true 8 | type: string 9 | environment-url: 10 | required: true 11 | type: string 12 | package-name: 13 | required: true 14 | type: string 15 | release-status: 16 | required: true 17 | type: string 18 | short-environment-name: 19 | required: true 20 | type: string 21 | flavor: 22 | required: true 23 | type: string 24 | new-pubspec-version: 25 | required: true 26 | type: string 27 | 28 | jobs: 29 | deployAndroid: 30 | name: 🤖📦🚀 Build & deploy Android ${{ inputs.short-environment-name }} release 31 | runs-on: ubuntu-latest 32 | environment: 33 | name: ${{ inputs.environment-name }} 34 | url: ${{ inputs.environment-url }} 35 | steps: 36 | - name: ⬇️ Checkout repository 37 | uses: actions/checkout@v3 38 | - name: ⚙️ Setup Java 39 | uses: actions/setup-java@v3 40 | with: 41 | distribution: 'zulu' 42 | java-version: "12.x" 43 | cache: 'gradle' 44 | id: java 45 | - name: ⚙️ Setup Flutter 46 | uses: subosito/flutter-action@v2 47 | with: 48 | flutter-version: "3.7.0" 49 | channel: 'stable' 50 | cache: true 51 | id: flutter 52 | - name: 🔐 Retrieve base64 keystore and decode it to a file 53 | env: 54 | KEYSTORE_BASE64: ${{ secrets.KEYSTORE_FILE_BASE64 }} 55 | run: echo $KEYSTORE_BASE64 | base64 --decode > "${{ github.workspace }}/android-keystore.jks" 56 | - name: 📝🔐 Create keystore.properties file 57 | env: 58 | KEYSTORE_PROPERTIES_PATH: ${{ github.workspace }}/app/android/keystore.properties 59 | run: | 60 | echo '${{ inputs.flavor }}StoreFile=${{ github.workspace }}/android-keystore.jks' > $KEYSTORE_PROPERTIES_PATH 61 | echo '${{ inputs.flavor }}KeyAlias=${{ secrets.KEYSTORE_KEY_ALIAS }}' >> $KEYSTORE_PROPERTIES_PATH 62 | echo '${{ inputs.flavor }}StorePassword=${{ secrets.KEYSTORE_PASSWORD }}' >> $KEYSTORE_PROPERTIES_PATH 63 | echo '${{ inputs.flavor }}KeyPassword=${{ secrets.KEYSTORE_KEY_PASSWORD }}' >> $KEYSTORE_PROPERTIES_PATH 64 | - name: 📝 Edit pubspec version 65 | run: | 66 | sed -Ei "s/^version: (.*)/version: ${{ inputs.new-pubspec-version }}/" app/pubspec.yaml 67 | - name: ⚙️ Setup Melos 68 | uses: bluefireteam/melos-action@v2 69 | - name: ⚙️ Install dependencies for all packages 70 | run: melos build:pub_get:all 71 | - name: 🤖📦 Create Android ${{ inputs.short-environment-name }} appbundle release 72 | run: | 73 | pushd app 74 | mkdir debug-symbols 75 | flutter build appbundle \ 76 | --release \ 77 | --flavor ${{ inputs.flavor }} \ 78 | --target lib/main_${{ inputs.flavor }}.dart 79 | popd 80 | - name: 🤖🚀 Upload Android ${{ inputs.short-environment-name }} Release to Play Store 81 | uses: r0adkll/upload-google-play@v1.0.19 82 | with: 83 | packageName: ${{ inputs.package-name }} 84 | track: internal 85 | status: ${{ inputs.release-status }} 86 | releaseFiles: ${{ github.workspace }}/app/build/app/outputs/bundle/${{ inputs.flavor }}Release/app-${{ inputs.flavor }}-release.aab 87 | serviceAccountJsonPlainText: "${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_KEY_JSON }}" 88 | - name: 💬 Pick a random success catchphrase 89 | if: success() 90 | id: success_catchphrase 91 | run: | 92 | sentences=('🤩 AMAZING !' 'Woop woop 🎉' 'Oh wow 😮' '😎 Yeahhhh !' '📣 Amazing announcement !' '📢 Your attention please...' '👏 Great work !' '🍾 Champagne !' '🙌 High five !' '🥳 Time to celebrate !') 93 | arrayLength=${#sentences[@]} 94 | randomNumber=$(($RANDOM%$arrayLength)) 95 | pickedSentence=${sentences[$randomNumber]} 96 | echo "picked_sentence=$pickedSentence" >> $GITHUB_OUTPUT 97 | - name: 🔔✅ Send success notif to Discord 98 | if: success() 99 | uses: sarisia/actions-status-discord@v1 100 | with: 101 | webhook: ${{ secrets.DISCORD_DEPLOYMENT_WEBHOOK_URL }} 102 | avatar_url: ${{ secrets.DISCORD_DEPLOYMENT_WEBHOOK_AVATAR }} 103 | username: "${{ inputs.short-environment-name }} notifier" 104 | content: "${{ steps.success_catchphrase.outputs.picked_sentence }}" 105 | title: "🤖 New version of ${{ inputs.environment-name }} app available !" 106 | description: | 107 | Version `${{ inputs.new-pubspec-version }}` 108 | Click [here](${{ inputs.environment-url }}) to download 109 | url: ${{ inputs.environment-url }} 110 | nofail: true 111 | nodetail: true 112 | - name: 🔔❌ Send failure notif to Discord 113 | if: failure() 114 | uses: sarisia/actions-status-discord@v1 115 | env: 116 | RUN_URL: "https://github.com/orevial/flutter-ci-cd-demo/actions/runs/${{ github.run_id }}" 117 | with: 118 | webhook: ${{ secrets.DISCORD_BUILD_WEBHOOK_URL }} 119 | avatar_url: ${{ secrets.DISCORD_DEPLOYMENT_WEBHOOK_AVATAR }} 120 | username: "${{ inputs.short-environment-name }} notifier" 121 | content: "Oh no 😢" 122 | title: "🤖 Release of ${{ inputs.environment-name }} app has failed..." 123 | description: | 124 | Failed job: 🍏📦🚀 Build & deploy iOS ${{ inputs.short-environment-name }} release 125 | Failed to release version `${{ inputs.new-pubspec-version }}` of ${{ inputs.environment-name }} app 126 | Click [here](${{ env.RUN_URL }}) to go to failed run output 127 | url: ${{ env.RUN_URL }} 128 | nofail: true 129 | nodetail: true -------------------------------------------------------------------------------- /.github/workflows/_deploy-env-apps.yml: -------------------------------------------------------------------------------- 1 | name: 📦🚀 Build & deploy iOS & Android app 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | # Common inputs 7 | short-environment-name: 8 | required: true 9 | type: string 10 | flavor: 11 | required: true 12 | type: string 13 | new-pubspec-version: 14 | required: true 15 | type: string 16 | # Android specific inputs 17 | android-environment-name: 18 | required: true 19 | type: string 20 | android-environment-url: 21 | required: true 22 | type: string 23 | android-package-name: 24 | required: true 25 | type: string 26 | android-release-status: 27 | required: true 28 | type: string 29 | # iOS specific inputs 30 | ios-environment-name: 31 | required: true 32 | type: string 33 | ios-environment-url: 34 | required: true 35 | type: string 36 | 37 | jobs: 38 | deployAndroid: 39 | name: 🤖📦🚀 Build & deploy Android ${{ inputs.short-environment-name }} release 40 | uses: ./.github/workflows/_deploy-android-app.yml 41 | secrets: inherit 42 | with: 43 | environment-name: ${{ inputs.android-environment-name }} 44 | environment-url: ${{ inputs.android-environment-url }} 45 | package-name: ${{ inputs.android-package-name }} 46 | release-status: ${{ inputs.android-release-status }} 47 | short-environment-name: ${{ inputs.short-environment-name }} 48 | flavor: ${{ inputs.flavor }} 49 | new-pubspec-version: ${{ inputs.new-pubspec-version }} 50 | deployIos: 51 | name: 🍏📦🚀 Build & deploy iOS ${{ inputs.short-environment-name }} release 52 | uses: ./.github/workflows/_deploy-ios-app.yml 53 | secrets: inherit 54 | with: 55 | environment-name: ${{ inputs.ios-environment-name }} 56 | environment-url: ${{ inputs.ios-environment-url }} 57 | short-environment-name: ${{ inputs.short-environment-name }} 58 | flavor: ${{ inputs.flavor }} 59 | new-pubspec-version: ${{ inputs.new-pubspec-version }} -------------------------------------------------------------------------------- /.github/workflows/_deploy-ios-app.yml: -------------------------------------------------------------------------------- 1 | name: 📦🚀 Build & deploy iOS app for an environment 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | environment-name: 7 | required: true 8 | type: string 9 | environment-url: 10 | required: true 11 | type: string 12 | short-environment-name: 13 | required: true 14 | type: string 15 | flavor: 16 | required: true 17 | type: string 18 | new-pubspec-version: 19 | required: true 20 | type: string 21 | 22 | jobs: 23 | deployIos: 24 | name: 🍏📦🚀 Build & deploy iOS ${{ inputs.short-environment-name }} release 25 | runs-on: macos-latest 26 | environment: 27 | name: ${{ inputs.environment-name }} 28 | url: ${{ inputs.environment-url }} 29 | steps: 30 | - name: ⬇️ Checkout repository 31 | uses: actions/checkout@v3 32 | - name: 🔐 Install Apple certificate and provisioning profile 33 | env: 34 | P12_DISTRIBUTION_CERTIFICATE_BASE64: "${{ secrets.IOS_P12_DISTRIBUTION_CERTIFICATE_BASE64 }}" 35 | P12_DISTRIBUTION_CERTIFICATE_PASSWORD: "${{ secrets.IOS_P12_DISTRIBUTION_CERTIFICATE_PASSWORD }}" 36 | DISTRIBUTION_PROVISIONING_PROFILE_BASE64: "${{ secrets.IOS_DISTRIBUTION_PROVISIONING_PROFILE_BASE64 }}" 37 | KEYCHAIN_PASSWORD: "${{ secrets.IOS_RUNNER_LOCAL_KEYCHAIN_PASSWORD }}" 38 | EXPORT_OPTIONS_BASE64: "${{ secrets.IOS_EXPORT_OPTIONS_BASE64 }}" 39 | run: | 40 | # create variables 41 | CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 42 | PROVISIONING_PROFILE_PATH=$RUNNER_TEMP/build_pp.mobileprovision 43 | KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db 44 | EXPORT_OPTIONS_PATH="${{ github.workspace }}/app/ios/Runner/ExportOptions.plist" 45 | 46 | # import certificate, provisioning profile and export options from secrets 47 | echo -n "$P12_DISTRIBUTION_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH 48 | echo -n "$DISTRIBUTION_PROVISIONING_PROFILE_BASE64" | base64 --decode -o $PROVISIONING_PROFILE_PATH 49 | echo -n "$EXPORT_OPTIONS_BASE64" | base64 --decode -o $EXPORT_OPTIONS_PATH 50 | 51 | # create temporary keychain 52 | security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH 53 | security set-keychain-settings -lut 21600 $KEYCHAIN_PATH 54 | security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH 55 | 56 | # import certificate to keychain 57 | security import $CERTIFICATE_PATH -P "$P12_DISTRIBUTION_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH 58 | security list-keychain -d user -s $KEYCHAIN_PATH 59 | 60 | # apply provisioning profile 61 | mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles 62 | cp $PROVISIONING_PROFILE_PATH ~/Library/MobileDevice/Provisioning\ Profiles 63 | - name: 📝 Edit pubspec version 64 | run: | 65 | sed -Ei "" "s/^version: (.*)/version: ${{ inputs.new-pubspec-version }}/" app/pubspec.yaml 66 | - name: ⚙️ Setup Flutter 67 | uses: subosito/flutter-action@v2 68 | with: 69 | flutter-version: "3.7.0" 70 | channel: 'stable' 71 | cache: true 72 | id: flutter 73 | - name: ⚙️ Setup Melos 74 | uses: bluefireteam/melos-action@v2 75 | - name: ⚙️ Install dependencies for all packages 76 | run: melos build:pub_get:all 77 | - name: 🍏📦 Create iOS ${{ inputs.short-environment-name }} appbundle release 78 | run: | 79 | pushd app/ 80 | flutter build ipa \ 81 | --release \ 82 | --flavor ${{ inputs.flavor }} \ 83 | --target lib/main_${{ inputs.flavor }}.dart \ 84 | --export-options-plist=ios/Runner/ExportOptions.plist 85 | popd 86 | - name: 🍏🚀 Deploy to App Store (Testflight) 87 | uses: apple-actions/upload-testflight-build@v1 88 | with: 89 | app-path: ${{ github.workspace }}/app/build/ios/ipa/flutter_ci_cd_demo.ipa 90 | issuer-id: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }} 91 | api-key-id: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }} 92 | api-private-key: ${{ secrets.APP_STORE_CONNECT_API_PRIVATE_KEY }} 93 | - name: 💬 Pick a random success catchphrase 94 | if: success() 95 | id: success_catchphrase 96 | run: | 97 | sentences=('🤩 AMAZING !' 'Woop woop 🎉' 'Oh wow 😮' '😎 Yeahhhh !' '📣 Amazing announcement !' '📢 Your attention please...' '👏 Great work !' '🍾 Champagne !' '🙌 High five !' '🥳 Time to celebrate !') 98 | arrayLength=${#sentences[@]} 99 | randomNumber=$(($RANDOM%$arrayLength)) 100 | pickedSentence=${sentences[$randomNumber]} 101 | echo "picked_sentence=$pickedSentence" >> $GITHUB_OUTPUT 102 | - name: 🔔✅ Send success notif to Discord 103 | if: success() 104 | uses: sarisia/actions-status-discord@v1 105 | with: 106 | webhook: ${{ secrets.DISCORD_DEPLOYMENT_WEBHOOK_URL }} 107 | avatar_url: ${{ secrets.DISCORD_DEPLOYMENT_WEBHOOK_AVATAR }} 108 | username: "${{ inputs.short-environment-name }} notifier" 109 | content: "${{ steps.success_catchphrase.outputs.picked_sentence }}" 110 | title: "🍏 New version of ${{ inputs.environment-name }} app available !" 111 | description: | 112 | Version `${{ inputs.new-pubspec-version }}` 113 | Click [here](${{ inputs.environment-url }}) to download 114 | url: ${{ inputs.environment-url }} 115 | nofail: true 116 | nodetail: true 117 | - name: 🔔❌ Send failure notif to Discord 118 | if: failure() 119 | uses: sarisia/actions-status-discord@v1 120 | env: 121 | RUN_URL: "https://github.com/orevial/flutter-ci-cd-demo/actions/runs/${{ github.run_id }}" 122 | with: 123 | webhook: ${{ secrets.DISCORD_BUILD_WEBHOOK_URL }} 124 | avatar_url: ${{ secrets.DISCORD_DEPLOYMENT_WEBHOOK_AVATAR }} 125 | username: "${{ inputs.short-environment-name }} notifier" 126 | content: "Oh no 😢" 127 | title: "🍏 Release of ${{ inputs.environment-name }} app has failed..." 128 | description: | 129 | Failed job: 🍏📦🚀 Build & deploy iOS ${{ inputs.short-environment-name }} release 130 | Failed to release version `${{ inputs.new-pubspec-version }}` of ${{ inputs.environment-name }} app 131 | Click [here](${{ env.RUN_URL }}) to go to failed run output 132 | url: ${{ env.RUN_URL }} 133 | nofail: true 134 | nodetail: true -------------------------------------------------------------------------------- /.github/workflows/_test_with_coverage.yml: -------------------------------------------------------------------------------- 1 | name: 🧪 Test with coverage 📊 2 | 3 | on: 4 | workflow_call: 5 | 6 | jobs: 7 | coverage: 8 | name: 🧪 Test 9 | runs-on: ubuntu-latest 10 | timeout-minutes: 30 11 | steps: 12 | - name: ⬇️ Checkout repository 13 | uses: actions/checkout@v3 14 | - name: ⚙️ Install lcov 15 | run: | 16 | sudo apt-get update 17 | sudo apt-get -y install lcov 18 | - name: ⚙️ Setup Flutter 19 | uses: subosito/flutter-action@v2 20 | with: 21 | channel: 'stable' 22 | cache: true 23 | - name: ⚙️ Setup Melos 24 | uses: bluefireteam/melos-action@v2 25 | - name: ⚙️ Install dependencies for all packages 26 | run: melos build:pub_get:all 27 | - name: 🧪 Run tests with coverage 28 | run: melos test:with-lcov-coverage:all 29 | - name: 🧪✅❌ Publish test results 30 | id: compute_test_results 31 | uses: dorny/test-reporter@v1.6.0 32 | with: 33 | name: '🧪📊 Unit tests report' 34 | path: test_reports/*_test_report.json 35 | reporter: 'flutter-json' 36 | max-annotations: '50' 37 | token: ${{ secrets.GITHUB_TOKEN }} 38 | - name: 🪪 Create passing test results badge 39 | if: github.event_name == 'push' && github.event.ref == 'refs/heads/main' 40 | uses: schneegans/dynamic-badges-action@v1.6.0 41 | with: 42 | auth: ${{ secrets.BADGE_GIST_TOKEN }} 43 | gistID: "2e904f1d8a9ef0e1e1458de1e7fcfba6" 44 | filename: "passing-tests-badge.json" 45 | label: 'Tests' 46 | message: '${{ steps.compute_test_results.outputs.passed }} passed, ${{ steps.compute_test_results.outputs.failed }} failed' 47 | namedLogo: "TestCafe" 48 | labelColor: 'lightgrey' 49 | color: ${{ steps.compute_test_results.outputs.failed == 0 && 'brightgreen' || 'red' }} 50 | - name: 🧪📊 Publish coverage report 51 | if: github.event_name == 'pull_request' 52 | uses: romeovs/lcov-reporter-action@v0.3.1 53 | with: 54 | lcov-file: coverage_report/cleaned_combined_lcov.info 55 | github-token: ${{ secrets.GITHUB_TOKEN }} 56 | title: 'Coverage Report' 57 | - name: 🥤 Extract test coverage percentage 58 | if: github.event_name == 'push' && github.event.ref == 'refs/heads/main' 59 | run: | 60 | melos run test:generate-html-coverage 61 | grep -o '.*headerCovTableEntryLo.*' coverage_report/index.html | sed -E 's/.*>(.*) %<.*/\1/' > coverage_percentage.txt 62 | percentage=$(cat coverage_percentage.txt) 63 | echo "Coverage percentage: $percentage" 64 | echo "coverage_percentage=$percentage" >> $GITHUB_ENV 65 | - name: 🪪 Create test coverage badge 66 | if: github.event_name == 'push' && github.event.ref == 'refs/heads/main' 67 | uses: schneegans/dynamic-badges-action@v1.6.0 68 | with: 69 | auth: ${{ secrets.BADGE_GIST_TOKEN }} 70 | gistID: "2e904f1d8a9ef0e1e1458de1e7fcfba6" 71 | filename: "test-coverage-badge.json" 72 | label: 'Test coverage' 73 | message: '${{ env.coverage_percentage }} %' 74 | namedLogo: "Codecov" 75 | labelColor: 'lightgrey' 76 | valColorRange: ${{ env.coverage_percentage }} 77 | minColorRange: 50 78 | maxColorRange: 80 79 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: 🔨🧪 Build & Test 2 | 3 | permissions: write-all 4 | 5 | concurrency: 6 | group: ${{ github.workflow }}-${{ github.head_ref }} 7 | cancel-in-progress: true 8 | 9 | on: 10 | pull_request: 11 | types: 12 | - opened 13 | - reopened 14 | - synchronize 15 | - ready_for_review 16 | branches: 17 | - 'main' 18 | paths-ignore: 19 | - '**.md' 20 | - 'doc/**' 21 | - '.git/' 22 | - '.vscode/' 23 | 24 | jobs: 25 | testAndCoverage: 26 | name: 🧪 Test 27 | if: github.event.pull_request.draft == false 28 | uses: ./.github/workflows/_test_with_coverage.yml 29 | secrets: inherit 30 | 31 | analyze: 32 | name: Analyze 33 | if: github.event.pull_request.draft == false 34 | timeout-minutes: 30 35 | runs-on: ubuntu-latest 36 | steps: 37 | - name: ⬇️ Checkout repository 38 | uses: actions/checkout@v3 39 | - name: ⚙️ Setup Flutter 40 | uses: subosito/flutter-action@v2 41 | with: 42 | channel: 'stable' 43 | cache: true 44 | - name: ⚙️ Setup Melos 45 | uses: bluefireteam/melos-action@v2 46 | - name: ⚙️ Install dependencies for all packages 47 | run: melos build:pub_get:all 48 | - name: 📄 Move dummy pubspec.yaml to root 49 | run: cp scripts/pubspec_template.yaml pubspec.yaml 50 | - name: ⚠️ℹ️ Run Dart analysis for app package 51 | uses: zgosalvez/github-actions-analyze-dart@v2.0.9 52 | with: 53 | working-directory: "${{github.workspace}}/app/" 54 | - name: ⚠️ℹ️ Run Dart analysis for data package 55 | uses: zgosalvez/github-actions-analyze-dart@v2.0.9 56 | with: 57 | working-directory: "${{github.workspace}}/design_system/" 58 | - name: 📈 Check metrics 59 | uses: dart-code-checker/dart-code-metrics-action@v3.0.0 60 | with: 61 | github_token: ${{ secrets.GITHUB_TOKEN }} 62 | pull_request_comment: true 63 | check_unused_files: true 64 | folders: 'app, design_system' 65 | 66 | build: 67 | name: Build Android 68 | if: github.event.pull_request.draft == false 69 | runs-on: ubuntu-latest 70 | timeout-minutes: 30 71 | steps: 72 | - name: ⬇️ Checkout repository 73 | uses: actions/checkout@v3 74 | - name: ⚙️ Setup Flutter 75 | uses: subosito/flutter-action@v2 76 | with: 77 | channel: 'stable' 78 | cache: true 79 | - name: ⚙️ Setup Java 80 | uses: actions/setup-java@v3 81 | with: 82 | distribution: 'zulu' 83 | java-version: "12.x" 84 | cache: 'gradle' 85 | id: java 86 | - name: ⚙️ Setup Melos 87 | uses: bluefireteam/melos-action@v2 88 | - name: ⚙️ Install dependencies for all packages 89 | run: melos build:pub_get:all 90 | - name: 🤖🔨 Build Android app 91 | run: | 92 | pushd app/ 93 | flutter build appbundle --debug --flavor dev -t lib/main_dev.dart 94 | popd -------------------------------------------------------------------------------- /.github/workflows/deploy-prod-apps.yml: -------------------------------------------------------------------------------- 1 | name: 📦🚀 Build & deploy Prod release 2 | 3 | permissions: write-all 4 | 5 | on: workflow_dispatch 6 | 7 | jobs: 8 | gitRelease: 9 | name: Create git release for Prod app 10 | runs-on: ubuntu-latest 11 | outputs: 12 | new_pubspec_version: "${{ steps.get_new_pubspec_version.outputs.next_pubspec_version }}" 13 | steps: 14 | - name: 👁️ Check branch validity 15 | if: github.ref != 'refs/heads/main' 16 | run: | 17 | echo "⚠️ Error: you tried to create a release from '${{ github.ref }}' branch but production releases can only be created from 'main' branch" 18 | - name: ⬇️ Checkout repository with tags 19 | uses: actions/checkout@v3 20 | with: 21 | fetch-depth: 0 22 | token: ${{ secrets.RELEASE_AUTOMATOR_PAT }} 23 | - name: 🏷️🧪 Get latest Prod release 24 | id: get_latest_prod_release 25 | uses: "WyriHaximus/github-action-get-previous-tag@v1" 26 | with: 27 | prefix: "release/prod/" 28 | fallback: 0.0.1 29 | - name: ⚙️ Prepare semantic release configuration 30 | run: | 31 | mv .releaserc.prod.json .releaserc.json 32 | - name: 🏷️✍️ Create new Prod release tag 33 | id: semantic_release_info 34 | uses: cycjimmy/semantic-release-action@v3.2.0 35 | env: 36 | GITHUB_TOKEN: ${{ secrets.RELEASE_AUTOMATOR_PAT }} 37 | with: 38 | semantic_version: 19 39 | - name: 📝 Edit pubspec version 40 | id: get_new_pubspec_version 41 | run: | 42 | last_prod_release=$(echo "${{ steps.get_latest_prod_release.outputs.tag }}" | sed -E "s/release\/prod\/(.*)/\1/") 43 | next_pubspec_version=$(./scripts/semver.sh "$last_prod_release" "${{ steps.semantic_release_info.outputs.new_release_version }}") 44 | sed -Ei "s/^version: (.*)/version: $next_pubspec_version/" app/pubspec.yaml 45 | echo "next_pubspec_version=$next_pubspec_version" >> $GITHUB_OUTPUT 46 | - name: 🔀 Push bump commit with changelog to repository 47 | uses: stefanzweifel/git-auto-commit-action@v4.16.0 48 | with: 49 | commit_message: "chore(*): bump to version ${{ steps.get_new_pubspec_version.outputs.next_pubspec_version }} [skip ci]" 50 | - name: 🏷️✍️ Create new Prod release tag 51 | uses: rickstaa/action-create-tag@v1 52 | with: 53 | tag: "release/prod/${{ steps.get_new_pubspec_version.outputs.next_pubspec_version }}" 54 | message: "UAT release ${{ steps.get_new_pubspec_version.outputs.next_pubspec_version }}" 55 | github_token: ${{ secrets.RELEASE_AUTOMATOR_PAT }} 56 | 57 | deployProd: 58 | name: Deploy Prod 59 | uses: ./.github/workflows/_deploy-env-apps.yml 60 | needs: gitRelease 61 | secrets: inherit 62 | with: 63 | android-environment-name: 'Android Prod' 64 | android-environment-url: 'https://play.google.com/console/u/0/developers/7200533445067191438/app/4976229890619914417/tracks/internal-testing' 65 | android-package-name: 'com.orevial' 66 | android-release-status: 'completed' 67 | ios-environment-name: 'iOS Prod' 68 | ios-environment-url: 'https://appstoreconnect.apple.com/apps/1292528725/testflight/ios' 69 | short-environment-name: 'Prod' 70 | flavor: 'prod' 71 | new-pubspec-version: ${{ needs.gitRelease.outputs.new_pubspec_version }} 72 | -------------------------------------------------------------------------------- /.github/workflows/deploy-uat-apps.yml: -------------------------------------------------------------------------------- 1 | name: 📦🚀 Build & deploy UAT release 2 | 3 | permissions: write-all 4 | 5 | on: 6 | push: 7 | branches: 8 | - 'main' 9 | paths-ignore: 10 | - '**.md' 11 | - 'doc/**' 12 | - '.git/' 13 | - '.vscode/' 14 | 15 | jobs: 16 | testAndCoverage: 17 | name: 🧪 Test 18 | uses: ./.github/workflows/_test_with_coverage.yml 19 | secrets: inherit 20 | 21 | gitRelease: 22 | name: Create git release for UAT app 23 | runs-on: ubuntu-latest 24 | outputs: 25 | new_pubspec_version: "${{ steps.get_new_pubspec_version.outputs.next_pubspec_version }}" 26 | steps: 27 | - name: ⬇️ Checkout repository with tags 28 | uses: actions/checkout@v3 29 | with: 30 | fetch-depth: 0 31 | - name: 🏷️🧪 Get latest UAT release 32 | id: get_latest_uat_release 33 | uses: "WyriHaximus/github-action-get-previous-tag@v1" 34 | with: 35 | prefix: "release/uat/" 36 | fallback: 0.0.1 37 | - name: ⚙️ Prepare semantic release configuration 38 | run: | 39 | mv .releaserc.uat.json .releaserc.json 40 | - name: 🏷️🔮 Get next UAT release semver version 41 | id: semantic_release_info 42 | uses: cycjimmy/semantic-release-action@v3.2.0 43 | env: 44 | GITHUB_TOKEN: ${{ secrets.RELEASE_AUTOMATOR_PAT }} 45 | with: 46 | semantic_version: 19 47 | - name: 📝 Calculate complete UAT version for next version 48 | id: get_new_pubspec_version 49 | run: | 50 | last_uat_release=$(echo "${{ steps.get_latest_uat_release.outputs.tag }}" | sed -E "s/release\/uat\/(.*)/\1/") 51 | next_pubspec_version=$(./scripts/semver.sh "$last_uat_release" "${{ steps.semantic_release_info.outputs.new_release_version }}") 52 | echo "next_pubspec_version=$next_pubspec_version" >> $GITHUB_OUTPUT 53 | - name: 🏷️✍️ Create new UAT release tag 54 | uses: rickstaa/action-create-tag@v1 55 | with: 56 | tag: "release/uat/${{ steps.get_new_pubspec_version.outputs.next_pubspec_version }}" 57 | message: "UAT release ${{ steps.get_new_pubspec_version.outputs.next_pubspec_version }}" 58 | github_token: ${{ secrets.RELEASE_AUTOMATOR_PAT }} 59 | 60 | deployUat: 61 | name: Deploy UAT 62 | uses: ./.github/workflows/_deploy-env-apps.yml 63 | needs: gitRelease 64 | secrets: inherit 65 | with: 66 | android-environment-name: 'Android UAT' 67 | android-environment-url: 'https://play.google.com/console/u/0/developers/7200533445067191438/app/4975719898219218293/tracks/internal-testing' 68 | android-package-name: 'com.orevial.uat' 69 | android-release-status: 'completed' 70 | ios-environment-name: 'iOS UAT' 71 | ios-environment-url: 'https://appstoreconnect.apple.com/apps/1664853019/testflight' 72 | short-environment-name: 'UAT' 73 | flavor: 'uat' 74 | new-pubspec-version: ${{ needs.gitRelease.outputs.new_pubspec_version }} 75 | -------------------------------------------------------------------------------- /.github/workflows/notify-pull-requests.yml: -------------------------------------------------------------------------------- 1 | name: 🔔 PR Notifier 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - closed 7 | - review_requested 8 | branches: 9 | - 'main' 10 | pull_request_review: 11 | types: 12 | - submitted 13 | branches: 14 | - 'main' 15 | 16 | jobs: 17 | notifyPREvent: 18 | name: 🔔 Notify Discord of a new Pull Request event 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: 🔔🧑‍💻 Send a notification to known reviewer when a PR review is requested 22 | if: github.event_name == 'pull_request' && github.event.action == 'review_requested' && contains(fromJSON(vars.IDS_GITHUB_TO_DISCORD).*.github_id, github.event.requested_reviewer.login) 23 | uses: sarisia/actions-status-discord@v1 24 | with: 25 | webhook: ${{ secrets.DISCORD_BUILD_WEBHOOK_URL }} 26 | avatar_url: ${{ secrets.DISCORD_BUILD_WEBHOOK_AVATAR }} 27 | username: | 28 | Pull Request notifier 29 | color: 0x12AFFA 30 | content: | 31 | 👋 Hey <@${{ fromJSON(vars.IDS_GITHUB_TO_DISCORD)[github.event.requested_reviewer.login].discord_id }}>, you've been asked to review a PR 🤓 32 | description: | 33 | Go and [check it now](${{ github.event.pull_request.self }}) ! 34 | title: | 35 | Pull Request: ${{ github.event.pull_request.title }} 36 | url: ${{ github.event.pull_request.self }} 37 | noprefix: true 38 | - name: 🔔❓ Send a notification to unknown reviewer when a PR review is requested 39 | if: github.event_name == 'pull_request' && github.event.action == 'review_requested' && !contains(fromJSON(vars.IDS_GITHUB_TO_DISCORD).*.github_id, github.event.requested_reviewer.login) 40 | uses: sarisia/actions-status-discord@v1 41 | with: 42 | webhook: ${{ secrets.DISCORD_BUILD_WEBHOOK_URL }} 43 | avatar_url: ${{ secrets.DISCORD_BUILD_WEBHOOK_AVATAR }} 44 | username: | 45 | Pull Request notifier 46 | color: 0x12AFFA 47 | content: | 48 | 👋 Hey ${{ github.event.requested_reviewer.login }}, you've been asked to review a PR 🤓 49 | description: | 50 | Go and [check it now](${{ github.event.pull_request.self }}) ! 51 | ⚠️ Important: ${{ github.event.requested_reviewer.login }}, your Discord id is not referenced in [Github Actions mappings (`IDS_GITHUB_TO_DISCORD` variable)](https://github.com/orevial/flutter-ci-cd-demo/settings/variables/actions), please add it ! 52 | title: | 53 | Pull Request: ${{ github.event.pull_request.title }} 54 | url: ${{ github.event.pull_request.self }} 55 | noprefix: true 56 | - name: 🔔🧑‍💻 Send a notification to know PR author when a new review is submitted 57 | if: github.event_name == 'pull_request_review' && github.event.action == 'submitted' && contains(fromJSON(vars.IDS_GITHUB_TO_DISCORD).*.github_id, github.event.pull_request.user.login) 58 | uses: sarisia/actions-status-discord@v1 59 | with: 60 | webhook: ${{ secrets.DISCORD_BUILD_WEBHOOK_URL }} 61 | avatar_url: ${{ secrets.DISCORD_BUILD_WEBHOOK_AVATAR }} 62 | username: | 63 | Pull Request notifier 64 | color: 0x1B385E 65 | content: | 66 | 👋 Hey <@${{ fromJSON(vars.IDS_GITHUB_TO_DISCORD)[github.event.pull_request.user.login].discord_id }}>, there's a new review available for your PR 💬 67 | description: | 68 | Go and [check it now](${{ github.event.pull_request.self }}) ! 69 | title: | 70 | Pull Request: ${{ github.event.pull_request.title }} 71 | url: ${{ github.event.pull_request.self }} 72 | noprefix: true 73 | - name: 🔔❓ Send a notification to unknown PR author when a new review is submitted 74 | if: github.event_name == 'pull_request_review' && github.event.action == 'submitted' && !contains(fromJSON(vars.IDS_GITHUB_TO_DISCORD).*.github_id, github.event.pull_request.user.login) 75 | uses: sarisia/actions-status-discord@v1 76 | with: 77 | webhook: ${{ secrets.DISCORD_BUILD_WEBHOOK_URL }} 78 | avatar_url: ${{ secrets.DISCORD_BUILD_WEBHOOK_AVATAR }} 79 | username: | 80 | Pull Request notifier 81 | color: 0x1B385E 82 | content: | 83 | Go and [check it now](${{ github.event.pull_request.self }}) ! 84 | 👋 Hey ${{ github.event.pull_request.user.login }}, there's a new review available for your PR 💬 85 | description: | 86 | ⚠️ Important: ${{ github.event.pull_request.user.login }}, your Discord id is not referenced in [Github Actions mappings (`IDS_GITHUB_TO_DISCORD` variable)](https://github.com/orevial/flutter-ci-cd-demo/settings/variables/actions), please add it ! 87 | title: | 88 | Pull Request: ${{ github.event.pull_request.title }} 89 | url: ${{ github.event.pull_request.self }} 90 | noprefix: true 91 | - name: 🔔🔀 Send a notification when a PR is merged 92 | if: github.event_name == 'pull_request' && github.event.pull_request.merged == true 93 | uses: sarisia/actions-status-discord@v1 94 | with: 95 | webhook: ${{ secrets.DISCORD_BUILD_WEBHOOK_URL }} 96 | avatar_url: ${{ secrets.DISCORD_BUILD_WEBHOOK_AVATAR }} 97 | username: | 98 | Pull Request notifier 99 | color: 0x00C02C 100 | title: | 101 | 🔀✅ PR merged: ${{ github.event.pull_request.title }} merged ! 102 | description: | 103 | Good job, a [pull request](${{ github.event.pull_request.self }}) has been merged ! 104 | Time to start UAT release 📦🚀 105 | url: ${{ github.event.pull_request.self }} 106 | noprefix: true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | build/ 32 | coverage/* 33 | coverage_report/* 34 | junit_test_reports/* 35 | test_reports/* 36 | test_results.xml 37 | **/failures/ 38 | 39 | # Web related 40 | lib/generated_plugin_registrant.dart 41 | 42 | # Exceptions to above rules. 43 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 44 | .metadata 45 | !coverage/.gitkeep 46 | !coverage_report/.gitkeep 47 | !junit_test_reports/.gitkeep 48 | !test_reports/.gitkeep 49 | 50 | .fvm/flutter_sdk 51 | **/.bundle 52 | **/fastlane/report.xml 53 | 54 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled. 5 | 6 | version: 7 | revision: b06b8b2710955028a6b562f5aa6fe62941d6febf 8 | channel: stable 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf 17 | base_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf 18 | - platform: android 19 | create_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf 20 | base_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf 21 | - platform: ios 22 | create_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf 23 | base_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf 24 | 25 | # User provided section 26 | 27 | # List of Local paths (relative to this file) that should be 28 | # ignored by the migrate tool. 29 | # 30 | # Files that are not part of the templates will be ignored by default. 31 | unmanaged_files: 32 | - 'lib/main.dart' 33 | - 'ios/Runner.xcodeproj/project.pbxproj' 34 | -------------------------------------------------------------------------------- /.releaserc.json: -------------------------------------------------------------------------------- 1 | { 2 | "ci": true, 3 | "dryRun": true, 4 | "branches": [ 5 | "main" 6 | ], 7 | "tagFormat": "release/prod/${version}", 8 | "plugins": [ 9 | "@semantic-release/commit-analyzer", 10 | "@semantic-release/release-notes-generator", 11 | [ 12 | "@semantic-release/changelog", 13 | { 14 | "changelogFile": "CHANGELOG.md", 15 | "changelogTitle": "# CHANGELOG" 16 | } 17 | ] 18 | ] 19 | } -------------------------------------------------------------------------------- /.releaserc.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "ci": true, 3 | "dryRun": true, 4 | "branches": [ 5 | "main" 6 | ], 7 | "tagFormat": "release/prod/${version}", 8 | "plugins": [ 9 | "@semantic-release/commit-analyzer", 10 | "@semantic-release/release-notes-generator", 11 | [ 12 | "@semantic-release/changelog", 13 | { 14 | "changelogFile": "CHANGELOG.md", 15 | "changelogTitle": "# CHANGELOG" 16 | } 17 | ] 18 | ] 19 | } -------------------------------------------------------------------------------- /.releaserc.uat.json: -------------------------------------------------------------------------------- 1 | { 2 | "ci": true, 3 | "dryRun": true, 4 | "branches": [ 5 | "main" 6 | ], 7 | "tagFormat": "release/prod/${version}", 8 | "plugins": [ 9 | "@semantic-release/commit-analyzer", 10 | "@semantic-release/release-notes-generator", 11 | [ 12 | "@semantic-release/changelog", 13 | { 14 | "changelogFile": "CHANGELOG.md", 15 | "changelogTitle": "# CHANGELOG" 16 | } 17 | ] 18 | ] 19 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # flutter_ci_cd_demo 2 | 3 | A new Flutter project. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) 13 | 14 | For help getting started with Flutter development, view the 15 | [online documentation](https://docs.flutter.dev/), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | ################################################################################## 2 | ## Linter rules for all packages ## 3 | ## ----------------------------- ## 4 | ## Note that there is no need to define another ## 5 | ## analysis-options.yaml in each package because they will ## 6 | ## automatically go up the tree if not found in the package. See here: ## 7 | ## https://dart.dev/guides/language/analysis-options#the-analysis-options-file ## 8 | ################################################################################## 9 | include: package:very_good_analysis/analysis_options.3.0.1.yaml 10 | 11 | ## 12 | # Lint rules to be used for apps without developer facing API. i.e. command line tools and Flutter applications 13 | ## 14 | analyzer: 15 | language: 16 | strict-casts: true 17 | strict-inference: true 18 | strict-raw-types: true 19 | errors: 20 | # treat missing required parameters as an error (not a hint) 21 | missing_required_param: error 22 | # treat missing returns as an error (not a hint) 23 | missing_return: error 24 | # Reassignment should be treated as warning (not a hint) 25 | parameter_assignments: warning 26 | plugins: 27 | - dart_code_metrics 28 | 29 | # Exclude auto-generated files from dart analysis 30 | exclude: 31 | - '**/lib/**.freezed.dart' 32 | - '**/lib/**/di.config.dart' 33 | - '**/lib/**.g.dart' 34 | - '**/lib/**.gr.dart' 35 | - '**/test/**.freezed.dart' 36 | - '**/test/**.g.dart' 37 | - '**/lib/i18n/**.i69n.dart' 38 | 39 | dart_code_metrics: 40 | metrics: 41 | cyclomatic-complexity: 20 42 | halstead-volume: 150 43 | lines-of-code: 100 44 | source-lines-of-code: 75 45 | maintainability-index: 50 46 | maximum-nesting-level: 5 47 | maximum-nesting: 5 48 | number-of-methods: 10 49 | number-of-parameters: 4 50 | technical-debt: 51 | threshold: 16 52 | todo-cost: 4 53 | ignore-cost: 8 54 | ignore-for-file-cost: 16 55 | as-dynamic-cost: 16 56 | deprecated-annotations-cost: 2 57 | file-nullsafety-migration-cost: 2 58 | unit-type: "hours" 59 | anti-patterns: 60 | - long-method: 61 | exclude: 62 | - '**/test/**_test.dart' 63 | # Although Bloc methods should be split to separate methods, it is okay to have a long 64 | # constructors within blocs because this is where the on<> method are used 65 | # !MONITOR! 66 | # Maybe: 67 | # - lib/bloc/**/*_bloc.dart 68 | # While this is generally a good practice, sometimes it's just more convenient to pass 69 | # a longer list of parameters. Plus Dart named parameters make it easier to understand what 70 | # the parameters actually mean in the context of a method call 71 | # - long-parameter-list 72 | rules: 73 | ######################################################################## 74 | ## DART CODE METRICS PLUGIN: ENABLED RULES ## 75 | ## ## 76 | ## Rules below are all the rules from dart-code-metrics that we use. ## 77 | ######################################################################## 78 | - avoid-banned-imports: 79 | entries: 80 | # Deny Flutter imports from core, data and domain packages 81 | - paths: [ "packages/core/.*.dart", "packages/data/.*.dart", "packages/domain/.*.dart" ] 82 | deny: [ "package:flutter/.*.dart" ] 83 | message: "Do not import Flutter Material Design library, we should not depend on it!" 84 | # Deny data and presentation imports from domain package 85 | - paths: [ "packages/domain/.*.dart" ] 86 | deny: [ "package:data/.*.dart", "package:presentation/.*.dart" ] 87 | message: "Domain package should not depend on data or presentation layers!" 88 | # Deny data imports from presentation package 89 | - paths: [ "packages/presentation/.*.dart" ] 90 | deny: [ "package:data/.*.dart" ] 91 | message: "Presentation package should not depend on data layer!" 92 | # Absolutely no package should depend on app (except itself, of course) 93 | - paths: [ "packages/core/.*.dart", "packages/data/.*.dart", "packages/domain/.*.dart", "packages/presentation/.*.dart" ] 94 | deny: [ "package:app/.*.dart" ] 95 | message: "Do not import app package, we should not depend on it!" 96 | - paths: [ "packages/presentation/screens/home/*.dart" ] 97 | deny: [ "package:flutter/widgets.dart" ] 98 | message: "Test 1" 99 | - paths: [ "packages/presentation/screens/home/.*.dart" ] 100 | deny: [ "package:flutter/widgets.dart" ] 101 | message: "Test 2" 102 | # Newly added !MONITOR! 103 | - avoid-cascade-after-if-null 104 | - avoid-collection-methods-with-unrelated-types 105 | - avoid-double-slash-imports 106 | - avoid-duplicate-exports 107 | - avoid-global-state 108 | - avoid-missing-enum-constant-in-map 109 | - avoid-nested-conditional-expressions: 110 | acceptable-level: 1 111 | # !MONITOR! 112 | # Maybe: While this rule is interesting, it leads to only false-positives in our case because we use 113 | # non-ascii symbols correctly : '€' only in european flavors, and others that don't relate 114 | # to specific locales such as '≈', '∞'... 115 | - avoid-non-ascii-symbols 116 | # Newly added !MONITOR! 117 | - avoid-redundant-async 118 | # !MONITOR! 119 | # Maybe: our custom exceptions thrown in catch blocks seem legit 120 | #- avoid-throw-in-catch-block 121 | # !MONITOR! 122 | # Maybe: While this rule can be useful, there are too many scenari where having top level declarations 123 | # make sense (e.g. shared alchemist/golden config, common mocks, shared widgets, etc) 124 | - avoid-top-level-members-in-tests: 125 | exclude: 126 | - "**/test/mocks/**" 127 | - avoid-unnecessary-conditionals 128 | - avoid-unnecessary-type-assertions 129 | - avoid-unnecessary-type-casts 130 | - avoid-unrelated-type-assertions 131 | - avoid-unused-parameters 132 | - binary-expression-operand-order 133 | - double-literal-format 134 | # !MONITOR! 135 | # This rule is pretty opinionated, which is okay if the starting team agrees on the 136 | # order that this rule enforces 137 | # Let's try the default ordering : https://dartcodemetrics.dev/docs/rules/common/member-ordering 138 | - member-ordering 139 | - missing-test-assertion: 140 | include-assertions: [ 'verify', 'verifyNever' ] 141 | - no-boolean-literal-compare 142 | # !MONITOR! 143 | # Maybe: Although sometimes useful (and helped remove a lot of useless code), 144 | # empty blocks can also be okay to use in Flutter. Examples: 145 | # - empty state reload `setState(() {})` 146 | # - callbacks `() {}` 147 | - no-empty-block: 148 | exclude: 149 | - "**/test/**" 150 | - no-equal-then-else 151 | # !MONITOR! 152 | # Maybe: Although a lot of magic number could be avoided by using widgets or other stuff, 153 | # this rule adds too much noise overall. 154 | # We should still try and reduce a lot of magic numbers though. 155 | # Maybe add: 156 | # exclude: 157 | # - "**/test/**" 158 | - no-magic-number: 159 | allowed: [ -1, 0, 1, 2 ] 160 | exclude: 161 | - "**/test/**" 162 | - no-object-declaration 163 | - prefer-commenting-analyzer-ignores 164 | - prefer-correct-identifier-length: 165 | exceptions: 166 | # counters 167 | - i 168 | - j 169 | # coordinates 170 | - x 171 | - y 172 | # various 173 | - id 174 | - db 175 | # Theme spacings 176 | - xs 177 | - xl 178 | - s 179 | - m 180 | - sm 181 | - l 182 | - lm 183 | - prefer-correct-test-file-name 184 | - prefer-correct-type-name: 185 | min-length: 3 186 | max-length: 50 187 | - prefer-enums-by-name 188 | - prefer-first 189 | - prefer-immediate-return 190 | # Newly added !MONITOR! 191 | - prefer-iterable-of 192 | - prefer-last 193 | # Newly added !MONITOR! 194 | - prefer-static-class: 195 | - ignore-private: true 196 | - prefer-trailing-comma 197 | # Flutter specific 198 | - always-remove-listener 199 | # Newly added !MONITOR! 200 | - avoid-border-all 201 | - avoid-expanded-as-spacer 202 | # !MONITOR! 203 | # Maybe: Although it is good practice to extract widget builders methods to custom widget 204 | # (mostly from a performance point-of-view), we have way too many of them and sometimes 205 | # functions are okay for very small portions of code 206 | - avoid-returning-widgets: 207 | exclude: 208 | - '**/test/**_test.dart' 209 | # Newly added !MONITOR! 210 | - avoid-shrink-wrap-in-lists 211 | - avoid-unnecessary-setstate 212 | - avoid-wrapping-in-padding 213 | # Newly added !MONITOR! 214 | - check-for-equals-in-render-object-setters 215 | # Newly added !MONITOR! 216 | - consistent-update-render-object 217 | # Newly added !MONITOR! 218 | - prefer-const-border-radius 219 | - prefer-correct-edge-insets-constructor 220 | # !MONITOR! 221 | # Maybe: Although it is good practice to try and separate widgets into different files, sometimes 222 | # it's okay to put multiple simple widgets into the same file so this rule might be too restrictive. 223 | # However, the rule might work as we can ignore private widgets from the rule, let's now monitor it... 224 | - prefer-single-widget-per-file: 225 | ignore-private-widgets: true 226 | - prefer-using-list-view 227 | # Newly added !MONITOR! 228 | - use-setstate-synchronously 229 | 230 | - avoid-passing-async-when-sync-expected: 231 | exclude: 232 | - '**/test/**' 233 | 234 | ######################################################################## 235 | ## DART CODE METRICS PLUGIN: DISABLED RULES ## 236 | ## ## 237 | ## Rules below are all the rules from dart-code-metrics ## 238 | ## that we DO NOT use, and why. ## 239 | ######################################################################## 240 | # Doesn't seem very useful, named arguments are already named so who cares 241 | # if they are passed in order... 242 | # arguments-ordering 243 | 244 | # Although mostly useful over the app, creates too much clutter when running DCM analyze action on CI, 245 | # for some reason... 246 | #- avoid-dynamic: 247 | # exclude: 248 | # - "**/test/**" 249 | 250 | # It's sometimes justified to use non-null assertion operator, this rule is too generic to be really useful 251 | # - avoid-non-null-assertion 252 | 253 | # Not sure if that rule could be useful for us... 254 | # - ban-name 255 | 256 | # This rule seems would introduce some very opinionated views 257 | # - format-comment 258 | 259 | # We will be using freezed instead of equatable, this rule doesn't apply for us 260 | # - list-all-equatable-fields 261 | 262 | # Too many false positive with Flutter widget system 263 | # - no-equal-arguments 264 | 265 | # Mostly uninteresting 266 | # - prefer-match-file-name 267 | 268 | # Too many false positives : there are many cases where it's okay not to use 269 | # the return value of a method call 270 | # - avoid-ignoring-return-values: 271 | 272 | # Although it is good practice to extract long callbacks to methods, 273 | # this rule is too restritive. Sometimes a 2-3 lines inline callback is more readable than a function, 274 | # and the function might be overkill 275 | # - prefer-extracting-callbacks 276 | 277 | # Coding style preference, too opinionated 278 | # - newline-before-return 279 | 280 | # Too opinionated, then is just fine and is sometimes more readable than async/await succession 281 | # - prefer-async-await 282 | 283 | # Too opinionated and often less readable than the good ol' if/else. 284 | # Plus conflicts with package:lint default rule 'prefer_if_elements_to_conditional_expressions' 285 | # - prefer-conditional-expressions 286 | 287 | # Mostly uninteresting 288 | # - tag-name 289 | 290 | # late keyword is okay to use 291 | # - avoid-late-keyword 292 | 293 | # Annoying as hell when using context variables 294 | # - prefer-moving-to-variable 295 | 296 | linter: 297 | rules: 298 | ######################################################################## 299 | ## CUSTOM RULES ## 300 | ## ----------------------- ## 301 | ## ## 302 | ## Those rules are either : ## 303 | ## - disabled in inherited package and enabled here (if true here) ## 304 | ## - enabled in inherited package and disabled here (if false here) ## 305 | ######################################################################## 306 | 307 | always_put_required_named_parameters_first: true 308 | 309 | # Since nullsafety landed in dart, `int?` is completely fine to return null and `int` can't return `null` at all. 310 | # 311 | # In general there are plenty of valid reasons to return `null`, not a useful rule 312 | # 313 | # Dart SDK: >= 2.0.0 • (Linter v0.1.31) 314 | avoid_returning_null: true 315 | 316 | # Nobody wants to manually wrap lines when changing a few words. This rule is too hard to be a "general" rule 317 | lines_longer_than_80_chars: false 318 | 319 | # Types for local variables can improve readability and shouldn't be forced to be removed. 320 | # 321 | # Dart SDK: >= 2.0.0 • (Linter v0.1.30) 322 | # 323 | omit_local_variable_types: false 324 | 325 | # Defining interfaces (abstract classes), with only one method, makes sense architecture wise 326 | # Discussion: https://github.com/passsy/dart-lint/issues/2 327 | # 328 | # 329 | one_member_abstracts: false 330 | 331 | # Only relevant for packages, not applications or general dart code 332 | package_api_docs: false 333 | 334 | # Definitely not a rule for standard dart code. Maybe relevant for packages 335 | public_member_api_docs: false 336 | 337 | # There is no argument which makes int literals better than double literals for doubles. 338 | # 339 | prefer_int_literals: false 340 | 341 | # "Any sorting is better than no sorting"... probably but it's also a lot of work 342 | # for little added value on pub dependencies. Sometimes it's even less readable 343 | # because logical groups can be made with packages that might now follow each other 344 | # in the alphabetical order 345 | sort_pub_dependencies: false 346 | 347 | # Use whatever makes you happy. lint doesn't define a style 348 | # Conflicts with prefer_double_quotes 349 | # 350 | prefer_single_quotes: false 351 | 352 | # Working, results in consistent code. But too opinionated 353 | # Discussion: https://github.com/passsy/dart-lint/issues/1 354 | # 355 | # Also, we rather want to use member-ordering rule from Dart Code Metrics 356 | # (https://dartcodemetrics.dev/docs/rules/common/member-ordering) to 357 | # have consistent code that match our opinionated way to do it 358 | # 359 | sort_constructors_first: false 360 | 361 | ######################################################################## 362 | ## Dart 2.19 rules ## 363 | ## ----------------------- ## 364 | ## ## 365 | ## We use the plugin "very_good_analysis" in version 3.1.0 ## 366 | ## as our base rules set. ## 367 | ## However as of 2023/02/06 new Dart 2.19 rules have not been ## 368 | ## added to this plugin yet, so we will put them there for now. ## 369 | ######################################################################## 370 | 371 | # !MONITOR! 372 | # New Dart 2.19 rule (as of 2023/02/06) 373 | collection_methods_unrelated_type: true 374 | 375 | # !MONITOR! 376 | # New Dart 2.19 rule (as of 2023/02/06) 377 | combinators_ordering: true 378 | 379 | # !MONITOR! 380 | # New Dart 2.19 rule (as of 2023/02/06) 381 | dangling_library_doc_comments: true 382 | 383 | # !MONITOR! 384 | # New Dart 2.19 rule (as of 2023/02/06) 385 | library_annotations: true 386 | 387 | # !MONITOR! 388 | # New Dart 2.19 rule (as of 2023/02/06) 389 | unnecessary_library_directive: true 390 | 391 | # !MONITOR! 392 | # New Dart 2.19 rule (as of 2023/02/06) 393 | implicit_call_tearoffs: true 394 | 395 | # !MONITOR! 396 | # New Dart 2.19 rule (as of 2023/02/06) 397 | unreachable_from_main: true 398 | 399 | # !MONITOR! 400 | # New Dart 2.19 rule (as of 2023/02/06) 401 | use_string_in_part_of_directives: true 402 | 403 | ######################################################################## 404 | ## INHERITED ENABLED RULES ## 405 | ## ----------------------- ## 406 | ## ## 407 | ## Rules below come from package ## 408 | ## https://pub.dev/packages/very_good_analysis ## 409 | ######################################################################## 410 | # Prevents accidental return type changes which results in a breaking API change. 411 | # Enforcing return type makes API changes visible in a diff 412 | # 413 | # - always_declare_return_types 414 | 415 | # All non nullable named parameters should be and annotated with @required. 416 | # This allows API consumers to get warnings via lint rather than a crash a runtime. 417 | # Might become obsolete with Non-Nullable types 418 | # 419 | # - always_require_non_null_named_parameters 420 | 421 | # Protect against unintentionally overriding superclass members 422 | # 423 | # - annotate_overrides 424 | 425 | # Highlights boolean expressions which can be simplified 426 | # - avoid_bool_literals_in_conditional_expressions 427 | 428 | # Errors aren't for catching but to prevent prior to runtime 429 | # 430 | # - avoid_catching_errors 431 | 432 | # Never accidentally use dynamic invocations, as it makes type error very hard to find 433 | # Dart SDK: unreleased • (Linter v1.0) 434 | # - avoid_dynamic_calls 435 | 436 | # Since all dart code may be compiled to JS this should be considered. 437 | # Disable it manually when you're explicitly not targeting web 438 | # 439 | # - avoid_double_and_int_checks 440 | 441 | # Prevents accidental empty else cases. See samples in documentation 442 | # 443 | # - avoid_empty_else 444 | 445 | # Use different quotes instead of escaping 446 | # Dart SDK: >= 2.8.0-dev.11.0 • (Linter v0.1.111) 447 | # - avoid_escaping_inner_quotes 448 | 449 | # Prevents unnecessary allocation of a field 450 | # 451 | # - avoid_field_initializers_in_const_classes 452 | 453 | # Since lint `parameter_assignments` is enabled, the final parameter doesn't add more safety, it would be just verbose 454 | # Conflicts with prefer_final_parameters 455 | # 456 | # - avoid_final_parameters 457 | 458 | # Prevents allocating a lambda and allows return/break/continue control flow statements inside the loop 459 | # 460 | # Dart SDK: >= 2.0.0 • (Linter v0.1.30) 461 | # 462 | # - avoid_function_literals_in_foreach_calls 463 | 464 | # Removes redundant `= null;` 465 | # - avoid_init_to_null 466 | 467 | # Not useful for coding golf, but in every environment where code is maintained by multiple authors. 468 | # 469 | # Dart SDK: 2.13.0 • (Linter v1.1.0) 470 | # 471 | # - avoid_multiple_declarations_per_line 472 | 473 | # Null checks aren't required in ==() operators 474 | # 475 | # - avoid_null_checks_in_equality_operators 476 | 477 | # Good APIs don't use ambiguous boolean parameters. Instead use named parameters 478 | # - avoid_positional_boolean_parameters 479 | 480 | # Don't call print in production code 481 | # 482 | # - avoid_print 483 | 484 | # Always prefer function references over typedefs. 485 | # Jumping twice in code to see the signature of a lambda sucks. This is different from the flutter analysis_options 486 | # - avoid_private_typedef_functions 487 | 488 | # Setters always return void, therefore defining void is redundant 489 | # 490 | # - avoid_return_types_on_setters 491 | 492 | # Don't use `Future?`, therefore never return null instead of a Future. 493 | # Will become obsolete one Non-Nullable types land 494 | # - avoid_returning_null_for_future 495 | 496 | # Use empty returns, don't show off with you knowledge about dart internals. 497 | # - avoid_returning_null_for_void 498 | 499 | # Prevents logical inconsistencies. It's good practice to define getters for all existing setters. 500 | # - avoid_setters_without_getters 501 | 502 | # Don't reuse a type parameter when one with the same name already exists in the same scope 503 | # 504 | # - avoid_shadowing_type_parameters 505 | 506 | # A single cascade operator can be replaced with a normal method call 507 | # 508 | # - avoid_single_cascade_in_expression_statements 509 | 510 | # Don't use .toString() in production code which might be minified 511 | # Dart SDK: >= 2.10.0-144.0.dev • (Linter v0.1.119) 512 | # - avoid_type_to_string 513 | 514 | # Don't use a parameter names which can be confused with a types (i.e. int, bool, num, ...) 515 | # 516 | # - avoid_types_as_parameter_names 517 | 518 | # Containers without parameters have no effect and can be removed 519 | # - avoid_unnecessary_containers 520 | 521 | # Unused parameters should be removed 522 | # - avoid_unused_constructor_parameters 523 | 524 | # For async functions use `Future` as return value, not `void` 525 | # This allows usage of the await keyword and prevents operations from running in parallel. 526 | # 527 | # - avoid_void_async 528 | 529 | # Flutter mobile only: Web packages aren't available in mobile flutter apps 530 | # - avoid_web_libraries_in_flutter 531 | 532 | # Use the await keyword only for futures. There is nothing to await in synchronous code 533 | # 534 | # - await_only_futures 535 | 536 | # Follow the style guide and use UpperCamelCase for extensions 537 | # 538 | # - camel_case_extensions 539 | 540 | # Follow the style guide and use UpperCamelCase for class names and typedefs 541 | # 542 | # - camel_case_types 543 | 544 | # Prevents leaks and code executing after their lifecycle. 545 | # Discussion https://github.com/passsy/dart-lint/issues/4 546 | # 547 | # 548 | # - cancel_subscriptions 549 | 550 | # Don't cast T? to T. Use ! instead 551 | # Dart SDK: >= 2.11.0-182.0.dev • (Linter v0.1.120) 552 | # - cast_nullable_to_non_nullable 553 | 554 | # Checks that files in conditional imports exist 555 | # 556 | # Linter v1.16.0 557 | # - conditional_uri_does_not_exist 558 | 559 | # Prevents hard to debug code 560 | # 561 | # - control_flow_in_finally 562 | 563 | # Single line `if`s are fine, but when a new line splits the bool expression and body curly braces 564 | # are recommended. It prevents the danging else problem and easily allows the addition of more lines inside 565 | # the if body 566 | # 567 | # Dart SDK: >= 2.0.0 • (Linter v0.1.57) 568 | # 569 | # - curly_braces_in_flow_control_structures 570 | 571 | # Requires all referenced dependencies to be declared as direct dependencies in pubspec.yaml. Transitive 572 | # dependencies might be removed by a dependency, breaking your code. 573 | # 574 | # Dart SDK: 2.14.0-172.0.dev • (Linter v1.5.0) 575 | # 576 | # - depend_on_referenced_packages 577 | 578 | # When deprecating classes, also deprecate the constructor. When deprecating fields, also deprecate the constructor 579 | # parameter. That rule is useful for apps and especially for packages 580 | # 581 | # Dart SDK: 2.13.0 • (Linter v1.0.0) 582 | # 583 | # - deprecated_consistency 584 | 585 | # Follows dart style. Fully supported by IDEs and no manual effort for a consistent style 586 | # 587 | # - directives_ordering 588 | 589 | # Add a comment why no further error handling is required 590 | # 591 | # - empty_catches 592 | 593 | # Removed empty constructor bodies 594 | # 595 | # - empty_constructor_bodies 596 | 597 | # Don't allow empty if bodies. Works together with curly_braces_in_flow_control_structures 598 | # 599 | # - empty_statements 600 | 601 | # That's good habit, but not necessary. It might be useful for some parsers that split lines based on the 602 | # new line character. Common in simple bash scripts. 603 | # 604 | # Most IDEs do this automatically, therefore zero effort for devs 605 | # 606 | # Dart SDK: >=2.14.0-360.0.dev • (Linter v1.8.0) 607 | # 608 | # - eol_at_end_of_file 609 | 610 | # Enums aren't powerful enough, now enum like classes get the same linting support 611 | # 612 | # Dart SDK: >= 2.9.0-12.0.dev • (Linter v0.1.116) 613 | # 614 | # - exhaustive_cases 615 | 616 | # Follow dart file naming schema 617 | # - file_names 618 | 619 | # hashCode and equals need to be consistent. One can't live without another. 620 | # - hash_and_equals 621 | 622 | # DON'T import implementation files from another package. 623 | # If you need access to some internal code, create an issue 624 | # - implementation_imports 625 | 626 | # Although there are some false positives, this lint generally catches unnecessary checks 627 | # - https://github.com/dart-lang/linter/issues/811 628 | # 629 | # 630 | # - invariant_booleans 631 | 632 | # Type check for `Iterable.contains(other)` where `other is! T` 633 | # Without this, `contains` will always report false. Those errors are usually very hard to catch. 634 | # 635 | # - iterable_contains_unrelated_type 636 | 637 | # Hint to join return and assignment. 638 | # 639 | # - join_return_with_assignment 640 | 641 | # Add leading \n which which makes multiline strings easier to read 642 | # Dart SDK: >= 2.8.0-dev.16.0 • (Linter v0.1.113) 643 | # - leading_newlines_in_multiline_strings 644 | 645 | # Makes sure a library name is a valid dart identifier. 646 | # This comes in handy for test files combining multiple tests where the file name can be used as identifier 647 | # 648 | # ``` 649 | # import src/some_test.dart as some_test; 650 | # 651 | # main() { 652 | # some_test.main(); 653 | # } 654 | # ``` 655 | # 656 | # - library_names 657 | 658 | # Follow dart style 659 | # 660 | # - library_prefixes 661 | 662 | # Type check for List.remove(item) where item is! T 663 | # The list can't contain item. Those errors are not directly obvious especially when refactoring. 664 | # - list_remove_unrelated_type 665 | 666 | # Don't forget the whitespaces at the end 667 | # 668 | # Dart SDK: >= 2.8.0-dev.10.0 • (Linter v0.1.110) 669 | # 670 | # - missing_whitespace_between_adjacent_strings 671 | 672 | # Concat Strings obviously with `+` inside a list. 673 | # 674 | # - no_adjacent_strings_in_list 675 | 676 | # Second case is basically dead code which will never be reached. 677 | # 678 | # - no_duplicate_case_values 679 | 680 | # private library prefixes don't exist, don't try to introduce concepts that have no effect 681 | # 682 | # Linter v1.15 683 | # - no_leading_underscores_for_library_prefixes 684 | 685 | # private identifier prefixes don't exist, don't try to introduce concepts that have no effect 686 | # 687 | # Linter v1.15 688 | # - no_leading_underscores_for_local_identifiers 689 | 690 | # Flutter only: `createState` shouldn't pass information into the state 691 | # 692 | # - no_logic_in_create_state 693 | 694 | # calling `runtimeType` may be a performance problem 695 | # Dart SDK: >= 2.8.0-dev.10.0 • (Linter v0.1.110) 696 | # - no_runtimeType_toString 697 | 698 | # Follow dart style naming conventions 699 | # 700 | # - non_constant_identifier_names 701 | 702 | # Don't call unnecessary conversion methods on primitives 703 | # 704 | # Dart SDK: 2.14.0-172.0.dev • (Linter v1.5.0) 705 | # 706 | # - noop_primitive_operations 707 | 708 | # Generic T might have a value of String or String?. Both are valid. 709 | # This lint triggers when ! is used on T? casting (String?)? to String and not (String?)? to String? 710 | # Dart SDK: >= 2.11.0-182.0.dev • (Linter v0.1.120) 711 | # - null_check_on_nullable_type_parameter 712 | 713 | # Might become irrelevant when non-nullable types land in dart. Until then use this lint check which checks for 714 | # non null arguments for specific dart sdk methods. 715 | # 716 | # - null_closures 717 | 718 | 719 | # Highlights unintentionally overridden fields. 720 | # overridden_fields 721 | 722 | # Follow dart style package naming convention 723 | # 724 | # Dart SDK: >= 2.0.0 • (Linter v0.1.31) 725 | # 726 | # - package_names 727 | 728 | # Seems very rare, especially for applications. 729 | # - package_prefixed_library_names 730 | 731 | # Most likely a mistake, if not: bad practice 732 | # 733 | # - parameter_assignments 734 | 735 | # Makes it easier to migrate to const constructors and to have final fields 736 | # 737 | # - prefer_asserts_in_initializer_lists 738 | 739 | # Collection literals are shorter. They exists, use them. 740 | # 741 | # - prefer_collection_literals 742 | 743 | # Use the ??= operator when possible 744 | # 745 | # - prefer_conditional_assignment 746 | 747 | # Always use const when possible, make runtime faster 748 | # 749 | # prefer_const_constructors 750 | 751 | # Add a const constructor when possible 752 | # 753 | # prefer_const_constructors_in_immutables 754 | 755 | # final is good, const is better 756 | # prefer_const_declarations 757 | 758 | # Always use const when possible, make runtime faster 759 | # 760 | # prefer_const_literals_to_create_immutables 761 | 762 | # Dart has named constructors. Static methods in other languages (java) are a workaround which don't have 763 | # named constructors. 764 | # 765 | # prefer_constructors_over_static_methods 766 | 767 | # Contains may be faster and is easier to read 768 | # 769 | # - prefer_contains 770 | 771 | # Prevent confusion with call-side when using named parameters 772 | # 773 | # - prefer_equal_for_default_values 774 | 775 | # Avoid accidental reassignments and allows the compiler to do optimizations. 776 | # 777 | # - prefer_final_fields 778 | 779 | # Helps avoid accidental reassignments and allows the compiler to do optimizations. 780 | # 781 | # - prefer_final_in_for_each 782 | 783 | # Helps avoid accidental reassignments and allows the compiler to do optimizations. 784 | # 785 | # - prefer_final_locals 786 | 787 | # Saves lot of code 788 | # 789 | # - prefer_for_elements_to_map_fromIterable 790 | 791 | # As Dart allows local function declarations, it is a good practice to use them in the place of function literals. 792 | # - prefer_function_declarations_over_variables 793 | 794 | # For consistency 795 | # 796 | # - prefer_generic_function_type_aliases 797 | 798 | # Allows potential usage of const 799 | # - prefer_if_elements_to_conditional_expressions 800 | 801 | # Dart has a special operator for this, use it 802 | # 803 | # - prefer_if_null_operators 804 | 805 | # Terser code 806 | # - prefer_initializing_formals 807 | 808 | # Easier move towards const, and way easier to read 809 | # 810 | # - prefer_inlined_adds 811 | 812 | # Interpolate, use less "", '' and + 813 | # - prefer_interpolation_to_compose_strings 814 | 815 | # Iterables do not necessary know their length 816 | # 817 | # - prefer_is_empty 818 | 819 | # Easier to read 820 | # 821 | # Dart SDK: >= 2.0.0 • (Linter v0.1.5) 822 | # 823 | # - prefer_is_not_empty 824 | 825 | # Use the `foo is! Foo` instead of `!(foo is Foo)` 826 | # - prefer_is_not_operator 827 | 828 | # Easier to read 829 | # 830 | # - prefer_iterable_whereType 831 | 832 | # It's shorter and should be preferred. Especially helpful for devs new to dart. 833 | # 834 | # Dart SDK: 2.14.0-2.0.dev • (Linter v1.3.0) 835 | # 836 | # - prefer_null_aware_method_calls 837 | 838 | # Makes expressions with null checks easier to read. 839 | # - prefer_null_aware_operators 840 | 841 | # Allows potential usage of const 842 | # 843 | # - prefer_spread_collections 844 | 845 | # Define types 846 | # 847 | # - prefer_typing_uninitialized_variables 848 | 849 | # Null is not a type, use void 850 | # - prefer_void_to_null 851 | 852 | # Document the replacement API 853 | # - provide_deprecation_message 854 | 855 | # Hints accidental recursions 856 | # 857 | # - recursive_getters 858 | 859 | # Dartfmt formats differently when adding trailing commas. This lint makes sure there is zero doubt in how code 860 | # should be formatted. 861 | # 862 | # This rule is debatable, though. 863 | # A non-representative [vote](https://twitter.com/passsy/status/1427220769050972162) shows a strong tendency towards 864 | # enabling this rule. Especially because the code example does only include the debatable formatting changes. There 865 | # are more, especially in Flutter build methods which make the code clearly better. 866 | # 867 | # Dart SDK: 2.14.0-2.0.dev • (Linter v1.3.0) 868 | # 869 | # - require_trailing_commas 870 | 871 | # Use https in pubspec.yaml 872 | # 873 | # Linter v1.15 874 | # - secure_pubspec_urls 875 | 876 | # Flutter only, prefer SizedBox over Container which offers a const constructors 877 | # Dart SDK: >= 2.9.0-4.0.dev • (Linter v0.1.115) 878 | # - sized_box_for_whitespace 879 | 880 | # Use the SizeBox.expand or SizeBox.shrink constructor instead of setting both width and height 881 | # to `0` or `double.infinity` 882 | # 883 | # Linter v1.15 884 | # - sized_box_shrink_expand 885 | 886 | # Follow dart style use triple slashes 887 | # 888 | # - slash_for_doc_comments 889 | 890 | # Flutter only, always put child last 891 | # 892 | # - sort_child_properties_last 893 | 894 | # Default constructor comes first. 895 | # 896 | # - sort_unnamed_constructors_first 897 | 898 | # First test, then cast 899 | # 900 | # - test_types_in_equals 901 | 902 | # Hard to debug and bad style 903 | # 904 | # - throw_in_finally 905 | 906 | # Help the compiler at compile time with non-null asserts rather than crashing at runtime 907 | # Dart SDK: >= 2.11.0-182.0.dev • (Linter v0.1.120) 908 | # - tighten_type_of_initializing_formals 909 | 910 | # Type annotations make the compiler intelligent, use them 911 | # - type_annotate_public_apis 912 | 913 | # Don't add types for already typed constructor parameters. 914 | # 915 | # - type_init_formals 916 | 917 | # Remove async/await clutter when not required 918 | # - unnecessary_await_in_return 919 | 920 | # Remove unnecessary braces 921 | # 922 | # - unnecessary_brace_in_string_interps 923 | 924 | # Yes, const everywhere. But not in an already const scope 925 | # 926 | # unnecessary_const 927 | 928 | # unnecessary_constructor_name 929 | 930 | # Getter/setters can be added later on in a non API breaking manner 931 | # 932 | # - unnecessary_getters_setters 933 | 934 | # Remove the optional `new` keyword 935 | # 936 | # - unnecessary_new 937 | 938 | # Don't assign `null` when value is already `null`. 939 | # 940 | # - unnecessary_null_aware_assignments 941 | 942 | # Remove ! when already non-nullable 943 | # Dart SDK: >= 2.10.0-144.0.dev • (Linter v0.1.119) 944 | # - unnecessary_null_checks 945 | 946 | # Don't assign `null` when value is already `null`. 947 | # 948 | # - unnecessary_null_in_if_null_operators 949 | 950 | # If a variable doesn't change and is initialized, no need to define it as nullable (NNDB) 951 | # Dart SDK: >= 2.10.0-10.0.dev • (Linter v0.1.118) 952 | # - unnecessary_nullable_for_final_variable_declarations 953 | 954 | # Remove overrides which simply call super 955 | # - unnecessary_overrides 956 | 957 | # Remove clutter where possible 958 | # - unnecessary_parenthesis 959 | 960 | # Use raw string only when needed 961 | # Dart SDK: >= 2.8.0-dev.11.0 • (Linter v0.1.111) 962 | # - unnecessary_raw_strings 963 | 964 | # Avoid magic overloads of + operators 965 | # - unnecessary_statements 966 | 967 | # Remove unnecessary escape characters 968 | # Dart SDK: >= 2.8.0-dev.11.0 • (Linter v0.1.111) 969 | # - unnecessary_string_escapes 970 | 971 | # - unnecessary_late 972 | 973 | # Completely unnecessary code, simplify to save a few CPU cycles 974 | # 975 | # Dart SDK: >= 2.8.0-dev.10.0 • (Linter v0.1.110) 976 | # 977 | # - unnecessary_string_interpolations 978 | 979 | # The variable is clear, remove clutter 980 | # 981 | # - unnecessary_this 982 | 983 | # Highlights potential bugs where unrelated types are compared with another. (always *not* equal). 984 | # 985 | # - unrelated_type_equality_checks 986 | 987 | # Web only 988 | # 989 | # - unsafe_html 990 | 991 | # Very useful in preventing Flutter BuildContext bugs in async callbacks 992 | # 993 | # Dart SDK: 2.13.0 • (Linter v1.1.0) 994 | # 995 | # - use_build_context_synchronously 996 | 997 | # Yet another "Container might be overkill" lint 998 | # 999 | # Linter v1.15 1000 | # - use_decorated_box 1001 | 1002 | # Always use hex syntax Color(0x00000001), never Color(1) 1003 | # 1004 | # - use_full_hex_values_for_flutter_colors 1005 | 1006 | # Always use generic function type syntax, don't mix styles 1007 | # 1008 | # - use_function_type_syntax_for_parameters 1009 | 1010 | # Don't use the modulo operator for isEven/isOdd checks 1011 | # 1012 | # Linter v0.1.116 1013 | # - use_is_even_rather_than_modulo 1014 | 1015 | # Replace const values with predefined constants 1016 | # `const Duration(seconds: 0)` -> `Duration.zero` 1017 | # 1018 | # Dart SDK: 2.13.0 • (Linter v1.0.0) 1019 | # 1020 | # use_named_constants 1021 | 1022 | # Some might argue `late` is a code smell, this lint is very opinionated. It triggers only for private fields and 1023 | # therefore might actually cleanup some code. 1024 | # There is no performance impact either way https://github.com/dart-lang/linter/pull/2189#discussion_r457945301 1025 | # 1026 | # Dart SDK: >= 2.10.0-10.0.dev • (Linter v0.1.118) 1027 | # 1028 | # - use_late_for_private_fields_and_variables 1029 | 1030 | # Use rethrow to preserve the original stacktrace. 1031 | # 1032 | # Dart SDK: >= 2.0.0 • (Linter v0.1.31) 1033 | # 1034 | # - use_rethrow_when_possible 1035 | 1036 | # Use the setter syntax 1037 | # 1038 | # - use_setters_to_change_properties 1039 | 1040 | # In most cases, using a string buffer is preferred for composing strings due to its improved performance. 1041 | # - use_string_buffers 1042 | 1043 | # Don't use try-catch with fail(), instead catch the error with the `throwsA` matcher. The big advantage: 1044 | # When another error is thrown, the assertion fails whereas catching a specific error would miss the catch block 1045 | # 1046 | # Dart SDK: 2.14.0-172.0.dev • (Linter v1.5.0) 1047 | # 1048 | # - use_test_throws_matchers 1049 | 1050 | # Catches invalid regular expressions. 1051 | # 1052 | # - valid_regexps 1053 | 1054 | # Don't assign anything to void 1055 | # - void_checks 1056 | 1057 | # Carries more meaning than a generic Container 1058 | # - use_colored_box 1059 | 1060 | # - always_use_package_imports # project rule to differentiate external package imports from our code 1061 | # - avoid_relative_lib_imports # obviously if above is true this one is true too 1062 | 1063 | # It is expected that mutable objects which override hash & equals shouldn't be used as keys for hashmaps. 1064 | # avoid_equals_and_hash_code_on_mutable_classes 1065 | 1066 | # Only useful when targeting JS 1067 | # Warns about too large integers when compiling to JS 1068 | # 1069 | # - avoid_js_rounded_ints 1070 | 1071 | # - avoid_redundant_argument_values 1072 | 1073 | # - avoid_renaming_method_parameters 1074 | 1075 | # - avoid_returning_this 1076 | 1077 | # - constant_identifier_names 1078 | 1079 | # - flutter_style_todos 1080 | 1081 | # - no_default_cases 1082 | 1083 | # Since Errors aren't intended to be caught (see avoid_catching_errors), throwing anything 1084 | # doesn't cause trouble. 1085 | # - only_throw_errors 1086 | 1087 | # - prefer_adjacent_string_concatenation 1088 | 1089 | # - prefer_asserts_with_message 1090 | 1091 | # - unnecessary_to_list_in_spreads 1092 | 1093 | # - use_enums 1094 | 1095 | # Useful for testing and debug purposes 1096 | # - use_key_in_widget_constructors 1097 | 1098 | # - use_raw_strings 1099 | 1100 | # - use_super_parameters 1101 | 1102 | # - use_to_and_as_if_applicable 1103 | 1104 | ######################################################################## 1105 | ## INHERITED ENABLED RULES: NEED MONITORING ! ## 1106 | ## ------------------------------------------ ## 1107 | ## ## 1108 | ## Those rules need monitoring because we are not sure yet ## 1109 | ## if they are pertinent or will just create clutter. ## 1110 | ## ## 1111 | ## Rules below come from package ## 1112 | ## https://pub.dev/packages/very_good_analysis ## 1113 | ######################################################################## 1114 | 1115 | # !MONITOR! 1116 | # Too many false positives. 1117 | # Using the pedantic package for the unawaited function doesn't make code better readable 1118 | # unawaited_futures # @orevial not sure about this one, I would usually enable it but we might want unawaited futures, let's check at how many cases are send and if they are legit : probably deactive after analyze 1119 | 1120 | # !MONITOR! 1121 | # Flutter setState is a good example where a lambda should always be used. 1122 | # 1123 | # Some generic code sometimes requires lambdas, otherwise the generic type isn't forwarded correctly. 1124 | # 1125 | # - unnecessary_lambdas 1126 | 1127 | # !MONITOR! 1128 | # Write `if (nullableBool ?? false)` instead of `if (nullableBool == true)` 1129 | # Not enabled, because `nullableBool == true` is very explicit, whereas `nullableBool ?? false` requires 1130 | # cognitive effort to process 1131 | # 1132 | # Dart SDK: 2.13.0 • (Linter v1.0.0) 1133 | # 1134 | # - use_if_null_to_convert_nulls_to_bools 1135 | 1136 | # !MONITOR! 1137 | # Good for libraries to prevent unnecessary code paths. 1138 | # False positives may occur for applications when boolean properties are generated by external programs 1139 | # producing auto-generated source code 1140 | # 1141 | # Known issue: while(true) loops https://github.com/dart-lang/linter/issues/453 1142 | # 1143 | # 1144 | # - literal_only_boolean_expressions 1145 | 1146 | # !MONITOR! 1147 | # Might cause frame drops because of synchronous file access on mobile, especially on older phones with slow storage. 1148 | # There are no known measurements sync access does *not* drop frames. 1149 | # 1150 | # - avoid_slow_async_io 1151 | 1152 | # !MONITOR! 1153 | # The cascade syntax is weird and you shouldn't be forced to use it. 1154 | # Potential false positives: 1155 | # https://github.com/dart-lang/linter/issues/1589 1156 | # 1157 | # - cascade_invocations 1158 | 1159 | # !MONITOR! 1160 | # Potential false positives: 1161 | # - https://github.com/dart-lang/linter/issues/1142 1162 | # 1163 | # - comment_references 1164 | 1165 | 1166 | ######################################################################## 1167 | ## INHERITED DISABLED RULES ## 1168 | ## ------------------------ ## 1169 | ## ## 1170 | ## Rules below come from package ## 1171 | ## https://pub.dev/packages/very_good_analysis ## 1172 | ######################################################################## 1173 | 1174 | # All methods should define a return type. dynamic is no exception. 1175 | # Violates Effective Dart "PREFER annotating with dynamic instead of letting inference fail" 1176 | # 1177 | # - avoid_annotating_with_dynamic 1178 | 1179 | # A leftover from dart1, should be deprecated 1180 | # 1181 | # - https://github.com/dart-lang/linter/issues/1401 1182 | # - avoid_as 1183 | 1184 | # There are no strong arguments to enable this rule because it is very strict. Catching anything is useful 1185 | # and common even if not always the most correct thing to do. 1186 | # 1187 | # - avoid_catches_without_on_clauses 1188 | 1189 | # Adding the type is not required, but sometimes improves readability. Therefore removing it doesn't always help 1190 | # - avoid_types_on_closure_parameters 1191 | 1192 | # False positives, not reliable enough 1193 | # - https://github.com/dart-lang/linter/issues/1381 1194 | # 1195 | # 1196 | # - close_sinks 1197 | 1198 | # Still experimental and pretty much work when enforced 1199 | # - diagnostic_describe_all_properties 1200 | 1201 | # String.fromEnvironment looks up env variables at compile time. The variable is baked in by the compiler 1202 | # and can't be changed by environment variables. 1203 | # 1204 | # For dart apps: 1205 | # Better look up an environment variable at runtime with Platform.environment 1206 | # or use code generation to define variables at compile time. 1207 | # 1208 | # For Flutter apps: 1209 | # String.fromEnvironment is the recommended way to include variables defined with `flutter build --dart-define` 1210 | # 1211 | # 1212 | # Dart SDK: >= 2.10.0-0.0.dev • (Linter v0.1.117) 1213 | # - do_not_use_environment 1214 | 1215 | # Single line methods + implementation makes it hard to write comments for that line. 1216 | # Dense code isn't necessarily better code. 1217 | # 1218 | # - prefer_expression_function_bodies 1219 | 1220 | # While prefer_final_fields and prefer_final_locals is enabled, this lint would add a lot of clutter to methods, 1221 | # especially lambdas. 1222 | # parameter_assignments is already enabled, catching this error 1223 | # Conflicts with avoid_final_parameters 1224 | # 1225 | # Dart SDK: 2.14.0-172.0.dev • (Linter v1.5.0) 1226 | # 1227 | # - prefer_final_parameters 1228 | 1229 | # Dense code isn't necessarily better code 1230 | # 1231 | # - prefer_foreach 1232 | 1233 | # Users of a 3rd party mixins can't change 3rd party code to use the mixin syntax. 1234 | # This makes the rule useless 1235 | # - prefer_mixin 1236 | 1237 | # Use whatever makes you happy. lint doesn't define a style 1238 | # Conflicts with prefer_single_quotes 1239 | # 1240 | # - prefer_double_quotes 1241 | 1242 | # Disabled because `final` prevents accidental reassignment 1243 | # - unnecessary_final 1244 | 1245 | # - prefer_relative_imports 1246 | 1247 | # - always_put_control_body_on_new_line 1248 | 1249 | # - always_specify_types 1250 | 1251 | # Can usually be replaced with an extension 1252 | # => Yes, but sometimes static classes are okay... 1253 | # 1254 | # Dart SDK: >= 2.0.0 • (Linter v0.1.31) 1255 | # 1256 | # - avoid_classes_with_only_static_members 1257 | 1258 | # Don't break value types by implementing them 1259 | # - avoid_implementing_value_types 1260 | 1261 | # unnecessary_null_aware_operator_on_extension_on_nullable 1262 | 1263 | # use_string_in_part_of_directives -------------------------------------------------------------------------------- /app/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /app/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | // Note: we need to put dummy keystore so that compiler does not complain 29 | def keystorePropertiesFile = rootProject.file("keystore.properties") 30 | def keystoreProperties = new Properties() 31 | if (keystorePropertiesFile.exists() && !keystorePropertiesFile.isDirectory()) { 32 | keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) 33 | } else { 34 | keystoreProperties['uatStoreFile'] = 'dummy.keystore'; 35 | keystoreProperties['prodStoreFile'] = 'dummy.keystore'; 36 | } 37 | 38 | if (keystoreProperties['uatStoreFile'] == null) { 39 | keystoreProperties['uatStoreFile'] = 'dummy.keystore' 40 | } 41 | 42 | if (keystoreProperties['prodStoreFile'] == null) { 43 | keystoreProperties['prodStoreFile'] = 'dummy.keystore' 44 | } 45 | 46 | android { 47 | compileSdkVersion flutter.compileSdkVersion 48 | ndkVersion flutter.ndkVersion 49 | 50 | compileOptions { 51 | sourceCompatibility JavaVersion.VERSION_1_8 52 | targetCompatibility JavaVersion.VERSION_1_8 53 | } 54 | 55 | kotlinOptions { 56 | jvmTarget = '1.8' 57 | } 58 | 59 | sourceSets { 60 | main.java.srcDirs += 'src/main/kotlin' 61 | } 62 | 63 | defaultConfig { 64 | applicationId "com.orevial.flutter_ci_cd_demo" 65 | minSdkVersion Math.max(flutter.minSdkVersion, 21) 66 | targetSdkVersion flutter.targetSdkVersion 67 | versionCode flutterVersionCode.toInteger() 68 | versionName flutterVersionName 69 | } 70 | 71 | flavorDimensions "flavor-type" 72 | 73 | signingConfigs { 74 | uatRelease { 75 | storeFile file(keystoreProperties['uatStoreFile']) 76 | storePassword keystoreProperties['uatStorePassword'] 77 | keyAlias keystoreProperties['uatKeyAlias'] 78 | keyPassword keystoreProperties['uatKeyPassword'] 79 | } 80 | 81 | prodRelease { 82 | storeFile file(keystoreProperties['prodStoreFile']) 83 | storePassword keystoreProperties['prodStorePassword'] 84 | keyAlias keystoreProperties['prodKeyAlias'] 85 | keyPassword keystoreProperties['prodKeyPassword'] 86 | } 87 | } 88 | 89 | productFlavors { 90 | dev { 91 | dimension "flavor-type" 92 | resValue "string", "app_name", "CI/CD Demo - Dev" 93 | applicationIdSuffix ".dev" 94 | versionNameSuffix "-dev" 95 | } 96 | uat { 97 | dimension "flavor-type" 98 | resValue "string", "app_name", "CI/CD Demo - UAT" 99 | applicationIdSuffix ".uat" 100 | versionNameSuffix "-uat" 101 | signingConfig signingConfigs.uatRelease 102 | } 103 | prod { 104 | dimension "flavor-type" 105 | resValue "string", "app_name", "CI/CD Demo" 106 | signingConfig signingConfigs.prodRelease 107 | } 108 | } 109 | } 110 | 111 | flutter { 112 | source '../..' 113 | } 114 | 115 | dependencies { 116 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 117 | } 118 | -------------------------------------------------------------------------------- /app/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 15 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/android/app/src/main/kotlin/com/orevial/flutter_ci_cd_demo/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.orevial.flutter_ci_cd_demo 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /app/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /app/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/6b3f3baaa0cba69b98f7cc98fbdc31f65bf0dadb/app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/6b3f3baaa0cba69b98f7cc98fbdc31f65bf0dadb/app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/6b3f3baaa0cba69b98f7cc98fbdc31f65bf0dadb/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/6b3f3baaa0cba69b98f7cc98fbdc31f65bf0dadb/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/6b3f3baaa0cba69b98f7cc98fbdc31f65bf0dadb/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /app/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /app/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.7.10' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:7.2.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | mavenCentral() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /app/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /app/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip 6 | -------------------------------------------------------------------------------- /app/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /app/ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /app/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 11.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /app/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /app/ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 54; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 12 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 13 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 14 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 15 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXCopyFilesBuildPhase section */ 19 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 20 | isa = PBXCopyFilesBuildPhase; 21 | buildActionMask = 2147483647; 22 | dstPath = ""; 23 | dstSubfolderSpec = 10; 24 | files = ( 25 | ); 26 | name = "Embed Frameworks"; 27 | runOnlyForDeploymentPostprocessing = 0; 28 | }; 29 | /* End PBXCopyFilesBuildPhase section */ 30 | 31 | /* Begin PBXFileReference section */ 32 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 33 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 34 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 35 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 36 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 37 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 38 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 39 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 40 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 42 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 43 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 44 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 45 | /* End PBXFileReference section */ 46 | 47 | /* Begin PBXFrameworksBuildPhase section */ 48 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 49 | isa = PBXFrameworksBuildPhase; 50 | buildActionMask = 2147483647; 51 | files = ( 52 | ); 53 | runOnlyForDeploymentPostprocessing = 0; 54 | }; 55 | /* End PBXFrameworksBuildPhase section */ 56 | 57 | /* Begin PBXGroup section */ 58 | 9740EEB11CF90186004384FC /* Flutter */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 62 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 63 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 64 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 65 | ); 66 | name = Flutter; 67 | sourceTree = ""; 68 | }; 69 | 97C146E51CF9000F007C117D = { 70 | isa = PBXGroup; 71 | children = ( 72 | 9740EEB11CF90186004384FC /* Flutter */, 73 | 97C146F01CF9000F007C117D /* Runner */, 74 | 97C146EF1CF9000F007C117D /* Products */, 75 | ); 76 | sourceTree = ""; 77 | }; 78 | 97C146EF1CF9000F007C117D /* Products */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | 97C146EE1CF9000F007C117D /* Runner.app */, 82 | ); 83 | name = Products; 84 | sourceTree = ""; 85 | }; 86 | 97C146F01CF9000F007C117D /* Runner */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 90 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 91 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 92 | 97C147021CF9000F007C117D /* Info.plist */, 93 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 94 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 95 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 96 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 97 | ); 98 | path = Runner; 99 | sourceTree = ""; 100 | }; 101 | /* End PBXGroup section */ 102 | 103 | /* Begin PBXNativeTarget section */ 104 | 97C146ED1CF9000F007C117D /* Runner */ = { 105 | isa = PBXNativeTarget; 106 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 107 | buildPhases = ( 108 | 9740EEB61CF901F6004384FC /* Run Script */, 109 | 97C146EA1CF9000F007C117D /* Sources */, 110 | 97C146EB1CF9000F007C117D /* Frameworks */, 111 | 97C146EC1CF9000F007C117D /* Resources */, 112 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 113 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 114 | ); 115 | buildRules = ( 116 | ); 117 | dependencies = ( 118 | ); 119 | name = Runner; 120 | productName = Runner; 121 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 122 | productType = "com.apple.product-type.application"; 123 | }; 124 | /* End PBXNativeTarget section */ 125 | 126 | /* Begin PBXProject section */ 127 | 97C146E61CF9000F007C117D /* Project object */ = { 128 | isa = PBXProject; 129 | attributes = { 130 | LastUpgradeCheck = 1300; 131 | ORGANIZATIONNAME = ""; 132 | TargetAttributes = { 133 | 97C146ED1CF9000F007C117D = { 134 | CreatedOnToolsVersion = 7.3.1; 135 | LastSwiftMigration = 1100; 136 | }; 137 | }; 138 | }; 139 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 140 | compatibilityVersion = "Xcode 9.3"; 141 | developmentRegion = en; 142 | hasScannedForEncodings = 0; 143 | knownRegions = ( 144 | en, 145 | Base, 146 | ); 147 | mainGroup = 97C146E51CF9000F007C117D; 148 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 149 | projectDirPath = ""; 150 | projectRoot = ""; 151 | targets = ( 152 | 97C146ED1CF9000F007C117D /* Runner */, 153 | ); 154 | }; 155 | /* End PBXProject section */ 156 | 157 | /* Begin PBXResourcesBuildPhase section */ 158 | 97C146EC1CF9000F007C117D /* Resources */ = { 159 | isa = PBXResourcesBuildPhase; 160 | buildActionMask = 2147483647; 161 | files = ( 162 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 163 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 164 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 165 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 166 | ); 167 | runOnlyForDeploymentPostprocessing = 0; 168 | }; 169 | /* End PBXResourcesBuildPhase section */ 170 | 171 | /* Begin PBXShellScriptBuildPhase section */ 172 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 173 | isa = PBXShellScriptBuildPhase; 174 | alwaysOutOfDate = 1; 175 | buildActionMask = 2147483647; 176 | files = ( 177 | ); 178 | inputPaths = ( 179 | ); 180 | name = "Thin Binary"; 181 | outputPaths = ( 182 | ); 183 | runOnlyForDeploymentPostprocessing = 0; 184 | shellPath = /bin/sh; 185 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 186 | }; 187 | 9740EEB61CF901F6004384FC /* Run Script */ = { 188 | isa = PBXShellScriptBuildPhase; 189 | alwaysOutOfDate = 1; 190 | buildActionMask = 2147483647; 191 | files = ( 192 | ); 193 | inputPaths = ( 194 | ); 195 | name = "Run Script"; 196 | outputPaths = ( 197 | ); 198 | runOnlyForDeploymentPostprocessing = 0; 199 | shellPath = /bin/sh; 200 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 201 | }; 202 | /* End PBXShellScriptBuildPhase section */ 203 | 204 | /* Begin PBXSourcesBuildPhase section */ 205 | 97C146EA1CF9000F007C117D /* Sources */ = { 206 | isa = PBXSourcesBuildPhase; 207 | buildActionMask = 2147483647; 208 | files = ( 209 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 210 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 211 | ); 212 | runOnlyForDeploymentPostprocessing = 0; 213 | }; 214 | /* End PBXSourcesBuildPhase section */ 215 | 216 | /* Begin PBXVariantGroup section */ 217 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 218 | isa = PBXVariantGroup; 219 | children = ( 220 | 97C146FB1CF9000F007C117D /* Base */, 221 | ); 222 | name = Main.storyboard; 223 | sourceTree = ""; 224 | }; 225 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 226 | isa = PBXVariantGroup; 227 | children = ( 228 | 97C147001CF9000F007C117D /* Base */, 229 | ); 230 | name = LaunchScreen.storyboard; 231 | sourceTree = ""; 232 | }; 233 | /* End PBXVariantGroup section */ 234 | 235 | /* Begin XCBuildConfiguration section */ 236 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 237 | isa = XCBuildConfiguration; 238 | buildSettings = { 239 | ALWAYS_SEARCH_USER_PATHS = NO; 240 | CLANG_ANALYZER_NONNULL = YES; 241 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 242 | CLANG_CXX_LIBRARY = "libc++"; 243 | CLANG_ENABLE_MODULES = YES; 244 | CLANG_ENABLE_OBJC_ARC = YES; 245 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 246 | CLANG_WARN_BOOL_CONVERSION = YES; 247 | CLANG_WARN_COMMA = YES; 248 | CLANG_WARN_CONSTANT_CONVERSION = YES; 249 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 250 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 251 | CLANG_WARN_EMPTY_BODY = YES; 252 | CLANG_WARN_ENUM_CONVERSION = YES; 253 | CLANG_WARN_INFINITE_RECURSION = YES; 254 | CLANG_WARN_INT_CONVERSION = YES; 255 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 256 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 257 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 258 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 259 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 260 | CLANG_WARN_STRICT_PROTOTYPES = YES; 261 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 262 | CLANG_WARN_UNREACHABLE_CODE = YES; 263 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 264 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 265 | COPY_PHASE_STRIP = NO; 266 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 267 | ENABLE_NS_ASSERTIONS = NO; 268 | ENABLE_STRICT_OBJC_MSGSEND = YES; 269 | GCC_C_LANGUAGE_STANDARD = gnu99; 270 | GCC_NO_COMMON_BLOCKS = YES; 271 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 272 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 273 | GCC_WARN_UNDECLARED_SELECTOR = YES; 274 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 275 | GCC_WARN_UNUSED_FUNCTION = YES; 276 | GCC_WARN_UNUSED_VARIABLE = YES; 277 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 278 | MTL_ENABLE_DEBUG_INFO = NO; 279 | SDKROOT = iphoneos; 280 | SUPPORTED_PLATFORMS = iphoneos; 281 | TARGETED_DEVICE_FAMILY = "1,2"; 282 | VALIDATE_PRODUCT = YES; 283 | }; 284 | name = Profile; 285 | }; 286 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 287 | isa = XCBuildConfiguration; 288 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 289 | buildSettings = { 290 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 291 | CLANG_ENABLE_MODULES = YES; 292 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 293 | DEVELOPMENT_TEAM = 4SSCF9D3M8; 294 | ENABLE_BITCODE = NO; 295 | INFOPLIST_FILE = Runner/Info.plist; 296 | LD_RUNPATH_SEARCH_PATHS = ( 297 | "$(inherited)", 298 | "@executable_path/Frameworks", 299 | ); 300 | PRODUCT_BUNDLE_IDENTIFIER = com.orevial.flutterCiCdDemo; 301 | PRODUCT_NAME = "$(TARGET_NAME)"; 302 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 303 | SWIFT_VERSION = 5.0; 304 | VERSIONING_SYSTEM = "apple-generic"; 305 | }; 306 | name = Profile; 307 | }; 308 | 7645275C29A8277C00230228 /* Debug-UAT */ = { 309 | isa = XCBuildConfiguration; 310 | buildSettings = { 311 | ALWAYS_SEARCH_USER_PATHS = NO; 312 | CLANG_ANALYZER_NONNULL = YES; 313 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 314 | CLANG_CXX_LIBRARY = "libc++"; 315 | CLANG_ENABLE_MODULES = YES; 316 | CLANG_ENABLE_OBJC_ARC = YES; 317 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 318 | CLANG_WARN_BOOL_CONVERSION = YES; 319 | CLANG_WARN_COMMA = YES; 320 | CLANG_WARN_CONSTANT_CONVERSION = YES; 321 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 322 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 323 | CLANG_WARN_EMPTY_BODY = YES; 324 | CLANG_WARN_ENUM_CONVERSION = YES; 325 | CLANG_WARN_INFINITE_RECURSION = YES; 326 | CLANG_WARN_INT_CONVERSION = YES; 327 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 328 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 329 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 330 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 331 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 332 | CLANG_WARN_STRICT_PROTOTYPES = YES; 333 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 334 | CLANG_WARN_UNREACHABLE_CODE = YES; 335 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 336 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 337 | COPY_PHASE_STRIP = NO; 338 | DEBUG_INFORMATION_FORMAT = dwarf; 339 | ENABLE_STRICT_OBJC_MSGSEND = YES; 340 | ENABLE_TESTABILITY = YES; 341 | GCC_C_LANGUAGE_STANDARD = gnu99; 342 | GCC_DYNAMIC_NO_PIC = NO; 343 | GCC_NO_COMMON_BLOCKS = YES; 344 | GCC_OPTIMIZATION_LEVEL = 0; 345 | GCC_PREPROCESSOR_DEFINITIONS = ( 346 | "DEBUG=1", 347 | "$(inherited)", 348 | ); 349 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 350 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 351 | GCC_WARN_UNDECLARED_SELECTOR = YES; 352 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 353 | GCC_WARN_UNUSED_FUNCTION = YES; 354 | GCC_WARN_UNUSED_VARIABLE = YES; 355 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 356 | MTL_ENABLE_DEBUG_INFO = YES; 357 | ONLY_ACTIVE_ARCH = YES; 358 | SDKROOT = iphoneos; 359 | TARGETED_DEVICE_FAMILY = "1,2"; 360 | }; 361 | name = "Debug-UAT"; 362 | }; 363 | 7645275D29A8277C00230228 /* Debug-UAT */ = { 364 | isa = XCBuildConfiguration; 365 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 366 | buildSettings = { 367 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 368 | CLANG_ENABLE_MODULES = YES; 369 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 370 | DEVELOPMENT_TEAM = 4SSCF9D3M8; 371 | ENABLE_BITCODE = NO; 372 | INFOPLIST_FILE = Runner/Info.plist; 373 | LD_RUNPATH_SEARCH_PATHS = ( 374 | "$(inherited)", 375 | "@executable_path/Frameworks", 376 | ); 377 | PRODUCT_BUNDLE_IDENTIFIER = "com.orevial.flutter-ci-cd-demo.uat"; 378 | PRODUCT_NAME = "$(TARGET_NAME)"; 379 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 380 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 381 | SWIFT_VERSION = 5.0; 382 | VERSIONING_SYSTEM = "apple-generic"; 383 | }; 384 | name = "Debug-UAT"; 385 | }; 386 | 7645275E29A8278A00230228 /* Debug-Dev */ = { 387 | isa = XCBuildConfiguration; 388 | buildSettings = { 389 | ALWAYS_SEARCH_USER_PATHS = NO; 390 | CLANG_ANALYZER_NONNULL = YES; 391 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 392 | CLANG_CXX_LIBRARY = "libc++"; 393 | CLANG_ENABLE_MODULES = YES; 394 | CLANG_ENABLE_OBJC_ARC = YES; 395 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 396 | CLANG_WARN_BOOL_CONVERSION = YES; 397 | CLANG_WARN_COMMA = YES; 398 | CLANG_WARN_CONSTANT_CONVERSION = YES; 399 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 400 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 401 | CLANG_WARN_EMPTY_BODY = YES; 402 | CLANG_WARN_ENUM_CONVERSION = YES; 403 | CLANG_WARN_INFINITE_RECURSION = YES; 404 | CLANG_WARN_INT_CONVERSION = YES; 405 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 406 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 407 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 408 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 409 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 410 | CLANG_WARN_STRICT_PROTOTYPES = YES; 411 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 412 | CLANG_WARN_UNREACHABLE_CODE = YES; 413 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 414 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 415 | COPY_PHASE_STRIP = NO; 416 | DEBUG_INFORMATION_FORMAT = dwarf; 417 | ENABLE_STRICT_OBJC_MSGSEND = YES; 418 | ENABLE_TESTABILITY = YES; 419 | GCC_C_LANGUAGE_STANDARD = gnu99; 420 | GCC_DYNAMIC_NO_PIC = NO; 421 | GCC_NO_COMMON_BLOCKS = YES; 422 | GCC_OPTIMIZATION_LEVEL = 0; 423 | GCC_PREPROCESSOR_DEFINITIONS = ( 424 | "DEBUG=1", 425 | "$(inherited)", 426 | ); 427 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 428 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 429 | GCC_WARN_UNDECLARED_SELECTOR = YES; 430 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 431 | GCC_WARN_UNUSED_FUNCTION = YES; 432 | GCC_WARN_UNUSED_VARIABLE = YES; 433 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 434 | MTL_ENABLE_DEBUG_INFO = YES; 435 | ONLY_ACTIVE_ARCH = YES; 436 | SDKROOT = iphoneos; 437 | TARGETED_DEVICE_FAMILY = "1,2"; 438 | }; 439 | name = "Debug-Dev"; 440 | }; 441 | 7645275F29A8278A00230228 /* Debug-Dev */ = { 442 | isa = XCBuildConfiguration; 443 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 444 | buildSettings = { 445 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 446 | CLANG_ENABLE_MODULES = YES; 447 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 448 | DEVELOPMENT_TEAM = 4SSCF9D3M8; 449 | ENABLE_BITCODE = NO; 450 | INFOPLIST_FILE = Runner/Info.plist; 451 | LD_RUNPATH_SEARCH_PATHS = ( 452 | "$(inherited)", 453 | "@executable_path/Frameworks", 454 | ); 455 | PRODUCT_BUNDLE_IDENTIFIER = "com.orevial.flutter-ci-cd-demo.dev"; 456 | PRODUCT_NAME = "$(TARGET_NAME)"; 457 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 458 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 459 | SWIFT_VERSION = 5.0; 460 | VERSIONING_SYSTEM = "apple-generic"; 461 | }; 462 | name = "Debug-Dev"; 463 | }; 464 | 7645276029A8279900230228 /* Release-UAT */ = { 465 | isa = XCBuildConfiguration; 466 | buildSettings = { 467 | ALWAYS_SEARCH_USER_PATHS = NO; 468 | CLANG_ANALYZER_NONNULL = YES; 469 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 470 | CLANG_CXX_LIBRARY = "libc++"; 471 | CLANG_ENABLE_MODULES = YES; 472 | CLANG_ENABLE_OBJC_ARC = YES; 473 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 474 | CLANG_WARN_BOOL_CONVERSION = YES; 475 | CLANG_WARN_COMMA = YES; 476 | CLANG_WARN_CONSTANT_CONVERSION = YES; 477 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 478 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 479 | CLANG_WARN_EMPTY_BODY = YES; 480 | CLANG_WARN_ENUM_CONVERSION = YES; 481 | CLANG_WARN_INFINITE_RECURSION = YES; 482 | CLANG_WARN_INT_CONVERSION = YES; 483 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 484 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 485 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 486 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 487 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 488 | CLANG_WARN_STRICT_PROTOTYPES = YES; 489 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 490 | CLANG_WARN_UNREACHABLE_CODE = YES; 491 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 492 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 493 | COPY_PHASE_STRIP = NO; 494 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 495 | ENABLE_NS_ASSERTIONS = NO; 496 | ENABLE_STRICT_OBJC_MSGSEND = YES; 497 | GCC_C_LANGUAGE_STANDARD = gnu99; 498 | GCC_NO_COMMON_BLOCKS = YES; 499 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 500 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 501 | GCC_WARN_UNDECLARED_SELECTOR = YES; 502 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 503 | GCC_WARN_UNUSED_FUNCTION = YES; 504 | GCC_WARN_UNUSED_VARIABLE = YES; 505 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 506 | MTL_ENABLE_DEBUG_INFO = NO; 507 | SDKROOT = iphoneos; 508 | SUPPORTED_PLATFORMS = iphoneos; 509 | SWIFT_COMPILATION_MODE = wholemodule; 510 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 511 | TARGETED_DEVICE_FAMILY = "1,2"; 512 | VALIDATE_PRODUCT = YES; 513 | }; 514 | name = "Release-UAT"; 515 | }; 516 | 7645276129A8279900230228 /* Release-UAT */ = { 517 | isa = XCBuildConfiguration; 518 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 519 | buildSettings = { 520 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 521 | CLANG_ENABLE_MODULES = YES; 522 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 523 | DEVELOPMENT_TEAM = 4SSCF9D3M8; 524 | ENABLE_BITCODE = NO; 525 | INFOPLIST_FILE = Runner/Info.plist; 526 | LD_RUNPATH_SEARCH_PATHS = ( 527 | "$(inherited)", 528 | "@executable_path/Frameworks", 529 | ); 530 | PRODUCT_BUNDLE_IDENTIFIER = "com.orevial.flutter-ci-cd-demo.uat"; 531 | PRODUCT_NAME = "$(TARGET_NAME)"; 532 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 533 | SWIFT_VERSION = 5.0; 534 | VERSIONING_SYSTEM = "apple-generic"; 535 | }; 536 | name = "Release-UAT"; 537 | }; 538 | 7645276229A827A400230228 /* Release-Dev */ = { 539 | isa = XCBuildConfiguration; 540 | buildSettings = { 541 | ALWAYS_SEARCH_USER_PATHS = NO; 542 | CLANG_ANALYZER_NONNULL = YES; 543 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 544 | CLANG_CXX_LIBRARY = "libc++"; 545 | CLANG_ENABLE_MODULES = YES; 546 | CLANG_ENABLE_OBJC_ARC = YES; 547 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 548 | CLANG_WARN_BOOL_CONVERSION = YES; 549 | CLANG_WARN_COMMA = YES; 550 | CLANG_WARN_CONSTANT_CONVERSION = YES; 551 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 552 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 553 | CLANG_WARN_EMPTY_BODY = YES; 554 | CLANG_WARN_ENUM_CONVERSION = YES; 555 | CLANG_WARN_INFINITE_RECURSION = YES; 556 | CLANG_WARN_INT_CONVERSION = YES; 557 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 558 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 559 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 560 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 561 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 562 | CLANG_WARN_STRICT_PROTOTYPES = YES; 563 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 564 | CLANG_WARN_UNREACHABLE_CODE = YES; 565 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 566 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 567 | COPY_PHASE_STRIP = NO; 568 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 569 | ENABLE_NS_ASSERTIONS = NO; 570 | ENABLE_STRICT_OBJC_MSGSEND = YES; 571 | GCC_C_LANGUAGE_STANDARD = gnu99; 572 | GCC_NO_COMMON_BLOCKS = YES; 573 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 574 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 575 | GCC_WARN_UNDECLARED_SELECTOR = YES; 576 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 577 | GCC_WARN_UNUSED_FUNCTION = YES; 578 | GCC_WARN_UNUSED_VARIABLE = YES; 579 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 580 | MTL_ENABLE_DEBUG_INFO = NO; 581 | SDKROOT = iphoneos; 582 | SUPPORTED_PLATFORMS = iphoneos; 583 | SWIFT_COMPILATION_MODE = wholemodule; 584 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 585 | TARGETED_DEVICE_FAMILY = "1,2"; 586 | VALIDATE_PRODUCT = YES; 587 | }; 588 | name = "Release-Dev"; 589 | }; 590 | 7645276329A827A400230228 /* Release-Dev */ = { 591 | isa = XCBuildConfiguration; 592 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 593 | buildSettings = { 594 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 595 | CLANG_ENABLE_MODULES = YES; 596 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 597 | DEVELOPMENT_TEAM = 4SSCF9D3M8; 598 | ENABLE_BITCODE = NO; 599 | INFOPLIST_FILE = Runner/Info.plist; 600 | LD_RUNPATH_SEARCH_PATHS = ( 601 | "$(inherited)", 602 | "@executable_path/Frameworks", 603 | ); 604 | PRODUCT_BUNDLE_IDENTIFIER = "com.orevial.flutter-ci-cd-demo.de"; 605 | PRODUCT_NAME = "$(TARGET_NAME)"; 606 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 607 | SWIFT_VERSION = 5.0; 608 | VERSIONING_SYSTEM = "apple-generic"; 609 | }; 610 | name = "Release-Dev"; 611 | }; 612 | 97C147031CF9000F007C117D /* Debug-Prod */ = { 613 | isa = XCBuildConfiguration; 614 | buildSettings = { 615 | ALWAYS_SEARCH_USER_PATHS = NO; 616 | CLANG_ANALYZER_NONNULL = YES; 617 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 618 | CLANG_CXX_LIBRARY = "libc++"; 619 | CLANG_ENABLE_MODULES = YES; 620 | CLANG_ENABLE_OBJC_ARC = YES; 621 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 622 | CLANG_WARN_BOOL_CONVERSION = YES; 623 | CLANG_WARN_COMMA = YES; 624 | CLANG_WARN_CONSTANT_CONVERSION = YES; 625 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 626 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 627 | CLANG_WARN_EMPTY_BODY = YES; 628 | CLANG_WARN_ENUM_CONVERSION = YES; 629 | CLANG_WARN_INFINITE_RECURSION = YES; 630 | CLANG_WARN_INT_CONVERSION = YES; 631 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 632 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 633 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 634 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 635 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 636 | CLANG_WARN_STRICT_PROTOTYPES = YES; 637 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 638 | CLANG_WARN_UNREACHABLE_CODE = YES; 639 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 640 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 641 | COPY_PHASE_STRIP = NO; 642 | DEBUG_INFORMATION_FORMAT = dwarf; 643 | ENABLE_STRICT_OBJC_MSGSEND = YES; 644 | ENABLE_TESTABILITY = YES; 645 | GCC_C_LANGUAGE_STANDARD = gnu99; 646 | GCC_DYNAMIC_NO_PIC = NO; 647 | GCC_NO_COMMON_BLOCKS = YES; 648 | GCC_OPTIMIZATION_LEVEL = 0; 649 | GCC_PREPROCESSOR_DEFINITIONS = ( 650 | "DEBUG=1", 651 | "$(inherited)", 652 | ); 653 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 654 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 655 | GCC_WARN_UNDECLARED_SELECTOR = YES; 656 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 657 | GCC_WARN_UNUSED_FUNCTION = YES; 658 | GCC_WARN_UNUSED_VARIABLE = YES; 659 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 660 | MTL_ENABLE_DEBUG_INFO = YES; 661 | ONLY_ACTIVE_ARCH = YES; 662 | SDKROOT = iphoneos; 663 | TARGETED_DEVICE_FAMILY = "1,2"; 664 | }; 665 | name = "Debug-Prod"; 666 | }; 667 | 97C147041CF9000F007C117D /* Release-Prod */ = { 668 | isa = XCBuildConfiguration; 669 | buildSettings = { 670 | ALWAYS_SEARCH_USER_PATHS = NO; 671 | CLANG_ANALYZER_NONNULL = YES; 672 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 673 | CLANG_CXX_LIBRARY = "libc++"; 674 | CLANG_ENABLE_MODULES = YES; 675 | CLANG_ENABLE_OBJC_ARC = YES; 676 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 677 | CLANG_WARN_BOOL_CONVERSION = YES; 678 | CLANG_WARN_COMMA = YES; 679 | CLANG_WARN_CONSTANT_CONVERSION = YES; 680 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 681 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 682 | CLANG_WARN_EMPTY_BODY = YES; 683 | CLANG_WARN_ENUM_CONVERSION = YES; 684 | CLANG_WARN_INFINITE_RECURSION = YES; 685 | CLANG_WARN_INT_CONVERSION = YES; 686 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 687 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 688 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 689 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 690 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 691 | CLANG_WARN_STRICT_PROTOTYPES = YES; 692 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 693 | CLANG_WARN_UNREACHABLE_CODE = YES; 694 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 695 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 696 | COPY_PHASE_STRIP = NO; 697 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 698 | ENABLE_NS_ASSERTIONS = NO; 699 | ENABLE_STRICT_OBJC_MSGSEND = YES; 700 | GCC_C_LANGUAGE_STANDARD = gnu99; 701 | GCC_NO_COMMON_BLOCKS = YES; 702 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 703 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 704 | GCC_WARN_UNDECLARED_SELECTOR = YES; 705 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 706 | GCC_WARN_UNUSED_FUNCTION = YES; 707 | GCC_WARN_UNUSED_VARIABLE = YES; 708 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 709 | MTL_ENABLE_DEBUG_INFO = NO; 710 | SDKROOT = iphoneos; 711 | SUPPORTED_PLATFORMS = iphoneos; 712 | SWIFT_COMPILATION_MODE = wholemodule; 713 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 714 | TARGETED_DEVICE_FAMILY = "1,2"; 715 | VALIDATE_PRODUCT = YES; 716 | }; 717 | name = "Release-Prod"; 718 | }; 719 | 97C147061CF9000F007C117D /* Debug-Prod */ = { 720 | isa = XCBuildConfiguration; 721 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 722 | buildSettings = { 723 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 724 | CLANG_ENABLE_MODULES = YES; 725 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 726 | DEVELOPMENT_TEAM = 4SSCF9D3M8; 727 | ENABLE_BITCODE = NO; 728 | INFOPLIST_FILE = Runner/Info.plist; 729 | LD_RUNPATH_SEARCH_PATHS = ( 730 | "$(inherited)", 731 | "@executable_path/Frameworks", 732 | ); 733 | PRODUCT_BUNDLE_IDENTIFIER = "com.orevial.flutter-ci-cd-demo"; 734 | PRODUCT_NAME = "$(TARGET_NAME)"; 735 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 736 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 737 | SWIFT_VERSION = 5.0; 738 | VERSIONING_SYSTEM = "apple-generic"; 739 | }; 740 | name = "Debug-Prod"; 741 | }; 742 | 97C147071CF9000F007C117D /* Release-Prod */ = { 743 | isa = XCBuildConfiguration; 744 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 745 | buildSettings = { 746 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 747 | CLANG_ENABLE_MODULES = YES; 748 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 749 | DEVELOPMENT_TEAM = 4SSCF9D3M8; 750 | ENABLE_BITCODE = NO; 751 | INFOPLIST_FILE = Runner/Info.plist; 752 | LD_RUNPATH_SEARCH_PATHS = ( 753 | "$(inherited)", 754 | "@executable_path/Frameworks", 755 | ); 756 | PRODUCT_BUNDLE_IDENTIFIER = "com.orevial.flutter-ci-cd-demo"; 757 | PRODUCT_NAME = "$(TARGET_NAME)"; 758 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 759 | SWIFT_VERSION = 5.0; 760 | VERSIONING_SYSTEM = "apple-generic"; 761 | }; 762 | name = "Release-Prod"; 763 | }; 764 | /* End XCBuildConfiguration section */ 765 | 766 | /* Begin XCConfigurationList section */ 767 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 768 | isa = XCConfigurationList; 769 | buildConfigurations = ( 770 | 97C147031CF9000F007C117D /* Debug-Prod */, 771 | 7645275E29A8278A00230228 /* Debug-Dev */, 772 | 7645275C29A8277C00230228 /* Debug-UAT */, 773 | 97C147041CF9000F007C117D /* Release-Prod */, 774 | 7645276229A827A400230228 /* Release-Dev */, 775 | 7645276029A8279900230228 /* Release-UAT */, 776 | 249021D3217E4FDB00AE95B9 /* Profile */, 777 | ); 778 | defaultConfigurationIsVisible = 0; 779 | defaultConfigurationName = "Release-Prod"; 780 | }; 781 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 782 | isa = XCConfigurationList; 783 | buildConfigurations = ( 784 | 97C147061CF9000F007C117D /* Debug-Prod */, 785 | 7645275F29A8278A00230228 /* Debug-Dev */, 786 | 7645275D29A8277C00230228 /* Debug-UAT */, 787 | 97C147071CF9000F007C117D /* Release-Prod */, 788 | 7645276329A827A400230228 /* Release-Dev */, 789 | 7645276129A8279900230228 /* Release-UAT */, 790 | 249021D4217E4FDB00AE95B9 /* Profile */, 791 | ); 792 | defaultConfigurationIsVisible = 0; 793 | defaultConfigurationName = "Release-Prod"; 794 | }; 795 | /* End XCConfigurationList section */ 796 | }; 797 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 798 | } 799 | -------------------------------------------------------------------------------- /app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Dev.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Prod.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /app/ios/Runner.xcodeproj/xcshareddata/xcschemes/UAT.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /app/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/6b3f3baaa0cba69b98f7cc98fbdc31f65bf0dadb/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/6b3f3baaa0cba69b98f7cc98fbdc31f65bf0dadb/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/6b3f3baaa0cba69b98f7cc98fbdc31f65bf0dadb/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/6b3f3baaa0cba69b98f7cc98fbdc31f65bf0dadb/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/6b3f3baaa0cba69b98f7cc98fbdc31f65bf0dadb/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/6b3f3baaa0cba69b98f7cc98fbdc31f65bf0dadb/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/6b3f3baaa0cba69b98f7cc98fbdc31f65bf0dadb/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/6b3f3baaa0cba69b98f7cc98fbdc31f65bf0dadb/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/6b3f3baaa0cba69b98f7cc98fbdc31f65bf0dadb/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/6b3f3baaa0cba69b98f7cc98fbdc31f65bf0dadb/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/6b3f3baaa0cba69b98f7cc98fbdc31f65bf0dadb/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/6b3f3baaa0cba69b98f7cc98fbdc31f65bf0dadb/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/6b3f3baaa0cba69b98f7cc98fbdc31f65bf0dadb/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/6b3f3baaa0cba69b98f7cc98fbdc31f65bf0dadb/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/6b3f3baaa0cba69b98f7cc98fbdc31f65bf0dadb/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/6b3f3baaa0cba69b98f7cc98fbdc31f65bf0dadb/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/6b3f3baaa0cba69b98f7cc98fbdc31f65bf0dadb/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/6b3f3baaa0cba69b98f7cc98fbdc31f65bf0dadb/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /app/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /app/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CADisableMinimumFrameDurationOnPhone 6 | 7 | CFBundleDevelopmentRegion 8 | $(DEVELOPMENT_LANGUAGE) 9 | CFBundleDisplayName 10 | Flutter Ci Cd Demo 11 | CFBundleExecutable 12 | $(EXECUTABLE_NAME) 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | flutter_ci_cd_demo 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | $(FLUTTER_BUILD_NAME) 23 | CFBundleSignature 24 | ???? 25 | CFBundleVersion 26 | $(FLUTTER_BUILD_NUMBER) 27 | LSRequiresIPhoneOS 28 | 29 | UIApplicationSupportsIndirectInputEvents 30 | 31 | UILaunchStoryboardName 32 | LaunchScreen 33 | UIMainStoryboardFile 34 | Main 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | UISupportedInterfaceOrientations~ipad 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationPortraitUpsideDown 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | UIViewControllerBasedStatusBarAppearance 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /app/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /app/lib/app.dart: -------------------------------------------------------------------------------- 1 | import 'package:design_system/design_system.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_ci_cd_demo/pages/home_page.dart'; 4 | 5 | class FlutterDemo extends StatelessWidget { 6 | final String env; 7 | 8 | const FlutterDemo({ 9 | required this.env, 10 | super.key, 11 | }); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return MaterialApp( 16 | title: 'Flutter CI/CD demo app', 17 | theme: lightTheme, 18 | home: HomePage(env: env), 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/lib/main_dev.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_ci_cd_demo/app.dart'; 3 | 4 | void main() { 5 | runApp(FlutterDemo(env: 'Dev')); 6 | } 7 | -------------------------------------------------------------------------------- /app/lib/main_prod.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_ci_cd_demo/app.dart'; 3 | 4 | void main() { 5 | runApp(FlutterDemo(env: 'Prod')); 6 | } 7 | -------------------------------------------------------------------------------- /app/lib/main_uat.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_ci_cd_demo/app.dart'; 3 | 4 | void main() { 5 | runApp(FlutterDemo(env: 'UAT')); 6 | } 7 | -------------------------------------------------------------------------------- /app/lib/pages/home_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:design_system/design/spacings.design.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class HomePage extends StatelessWidget { 5 | final String env; 6 | 7 | const HomePage({ 8 | required this.env, 9 | super.key, 10 | }); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Scaffold( 15 | appBar: AppBar(title: Text('Flutter CI/CD demo')), 16 | body: Center( 17 | child: Column( 18 | mainAxisSize: MainAxisSize.min, 19 | children: [ 20 | Text( 21 | '🏠 Welcome to Flutter CI/CD demo page !', 22 | style: Theme.of(context).textTheme.bodyLarge, 23 | ), 24 | SizedBox(height: ThemeSpacing.l), 25 | Text('Your are currently on $env environment'), 26 | ], 27 | ), 28 | ), 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "2.10.0" 12 | boolean_selector: 13 | dependency: transitive 14 | description: 15 | name: boolean_selector 16 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "2.1.1" 20 | characters: 21 | dependency: transitive 22 | description: 23 | name: characters 24 | sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "1.2.1" 28 | clock: 29 | dependency: transitive 30 | description: 31 | name: clock 32 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "1.1.1" 36 | collection: 37 | dependency: transitive 38 | description: 39 | name: collection 40 | sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "1.17.0" 44 | cupertino_icons: 45 | dependency: "direct main" 46 | description: 47 | name: cupertino_icons 48 | sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "1.0.5" 52 | design_system: 53 | dependency: "direct main" 54 | description: 55 | path: "../design_system" 56 | relative: true 57 | source: path 58 | version: "1.0.0" 59 | fake_async: 60 | dependency: transitive 61 | description: 62 | name: fake_async 63 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" 64 | url: "https://pub.dev" 65 | source: hosted 66 | version: "1.3.1" 67 | flutter: 68 | dependency: "direct main" 69 | description: flutter 70 | source: sdk 71 | version: "0.0.0" 72 | flutter_lints: 73 | dependency: "direct dev" 74 | description: 75 | name: flutter_lints 76 | sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c 77 | url: "https://pub.dev" 78 | source: hosted 79 | version: "2.0.1" 80 | flutter_test: 81 | dependency: "direct dev" 82 | description: flutter 83 | source: sdk 84 | version: "0.0.0" 85 | js: 86 | dependency: transitive 87 | description: 88 | name: js 89 | sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" 90 | url: "https://pub.dev" 91 | source: hosted 92 | version: "0.6.5" 93 | lints: 94 | dependency: transitive 95 | description: 96 | name: lints 97 | sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" 98 | url: "https://pub.dev" 99 | source: hosted 100 | version: "2.0.1" 101 | matcher: 102 | dependency: transitive 103 | description: 104 | name: matcher 105 | sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" 106 | url: "https://pub.dev" 107 | source: hosted 108 | version: "0.12.13" 109 | material_color_utilities: 110 | dependency: transitive 111 | description: 112 | name: material_color_utilities 113 | sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 114 | url: "https://pub.dev" 115 | source: hosted 116 | version: "0.2.0" 117 | meta: 118 | dependency: transitive 119 | description: 120 | name: meta 121 | sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" 122 | url: "https://pub.dev" 123 | source: hosted 124 | version: "1.8.0" 125 | path: 126 | dependency: transitive 127 | description: 128 | name: path 129 | sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b 130 | url: "https://pub.dev" 131 | source: hosted 132 | version: "1.8.2" 133 | sky_engine: 134 | dependency: transitive 135 | description: flutter 136 | source: sdk 137 | version: "0.0.99" 138 | source_span: 139 | dependency: transitive 140 | description: 141 | name: source_span 142 | sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 143 | url: "https://pub.dev" 144 | source: hosted 145 | version: "1.9.1" 146 | stack_trace: 147 | dependency: transitive 148 | description: 149 | name: stack_trace 150 | sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 151 | url: "https://pub.dev" 152 | source: hosted 153 | version: "1.11.0" 154 | stream_channel: 155 | dependency: transitive 156 | description: 157 | name: stream_channel 158 | sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" 159 | url: "https://pub.dev" 160 | source: hosted 161 | version: "2.1.1" 162 | string_scanner: 163 | dependency: transitive 164 | description: 165 | name: string_scanner 166 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" 167 | url: "https://pub.dev" 168 | source: hosted 169 | version: "1.2.0" 170 | term_glyph: 171 | dependency: transitive 172 | description: 173 | name: term_glyph 174 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 175 | url: "https://pub.dev" 176 | source: hosted 177 | version: "1.2.1" 178 | test_api: 179 | dependency: transitive 180 | description: 181 | name: test_api 182 | sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 183 | url: "https://pub.dev" 184 | source: hosted 185 | version: "0.4.16" 186 | vector_math: 187 | dependency: transitive 188 | description: 189 | name: vector_math 190 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 191 | url: "https://pub.dev" 192 | source: hosted 193 | version: "2.1.4" 194 | sdks: 195 | dart: ">=2.19.0 <4.0.0" 196 | flutter: ">=3.7.0" 197 | -------------------------------------------------------------------------------- /app/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_ci_cd_demo 2 | description: A new Flutter project. 3 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 4 | 5 | version: 1.0.0+1 6 | 7 | environment: 8 | sdk: '>=2.19.0 <3.0.0' 9 | flutter: ">=3.7.0 <4.0.0" 10 | 11 | dependencies: 12 | flutter: 13 | sdk: flutter 14 | design_system: 15 | path: ../design_system 16 | cupertino_icons: ^1.0.2 17 | 18 | dev_dependencies: 19 | flutter_test: 20 | sdk: flutter 21 | 22 | flutter_lints: ^2.0.0 23 | 24 | flutter: 25 | uses-material-design: true 26 | -------------------------------------------------------------------------------- /app/test/app_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility in the flutter_test package. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter_ci_cd_demo/app.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | void main() { 12 | testWidgets('App is displayed', (WidgetTester tester) async { 13 | await tester.pumpWidget(const FlutterDemo(env: 'Test')); 14 | 15 | expect(find.text('Flutter CI/CD demo'), findsOneWidget); 16 | expect(find.text('Your are currently on Test environment'), findsOneWidget); 17 | }); 18 | } 19 | -------------------------------------------------------------------------------- /coverage/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/6b3f3baaa0cba69b98f7cc98fbdc31f65bf0dadb/coverage/.gitkeep -------------------------------------------------------------------------------- /coverage_report/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/6b3f3baaa0cba69b98f7cc98fbdc31f65bf0dadb/coverage_report/.gitkeep -------------------------------------------------------------------------------- /design_system/lib/design/colors.design.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | const MaterialColor kMaterialPrimarySwatch = 4 | MaterialColor(0xFFAF4B00, { 5 | 50: Color(0xFFF9EAE6), 6 | 100: Color(0xFFF9CFBA), 7 | 200: Color(0xFFF6B18D), 8 | 300: Color(0xFFF3945F), 9 | 400: Color(0xFFF07F3A), 10 | 500: Color(0xFFED6D0F), 11 | 600: Color(0xFFE3660A), 12 | 700: Color(0xFFD55F05), 13 | 800: Color(0xFFC85803), 14 | 900: Color(0xFFAF4B00), 15 | }); 16 | 17 | // Useless method but we need at least one method 18 | // to be called for coverage report to be generated... 19 | MaterialColor getMaterialPrimarySwatch() { 20 | return kMaterialPrimarySwatch; 21 | } 22 | -------------------------------------------------------------------------------- /design_system/lib/design/spacings.design.dart: -------------------------------------------------------------------------------- 1 | // Small spacing ids are legit, they are well-known identifier 2 | //ignore_for_file: prefer-correct-identifier-length 3 | 4 | class ThemeSize { 5 | static const double xxs = 4.0; 6 | static const double xs = 8.0; 7 | static const double s = 12.0; 8 | static const double sm = 16.0; 9 | static const double m = 24.0; 10 | static const double lm = 32.0; 11 | static const double l = 40.0; 12 | static const double xl = 48.0; 13 | static const double xxl = 56.0; 14 | } 15 | 16 | typedef ThemeSpacing = ThemeSize; 17 | -------------------------------------------------------------------------------- /design_system/lib/design/theme.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'colors.design.dart'; 4 | 5 | final ThemeData lightTheme = ThemeData( 6 | primarySwatch: kMaterialPrimarySwatch, 7 | ); 8 | -------------------------------------------------------------------------------- /design_system/lib/design_system.dart: -------------------------------------------------------------------------------- 1 | export 'design/theme.dart'; 2 | -------------------------------------------------------------------------------- /design_system/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "2.10.0" 12 | boolean_selector: 13 | dependency: transitive 14 | description: 15 | name: boolean_selector 16 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "2.1.1" 20 | characters: 21 | dependency: transitive 22 | description: 23 | name: characters 24 | sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "1.2.1" 28 | clock: 29 | dependency: transitive 30 | description: 31 | name: clock 32 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "1.1.1" 36 | collection: 37 | dependency: transitive 38 | description: 39 | name: collection 40 | sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "1.17.0" 44 | fake_async: 45 | dependency: transitive 46 | description: 47 | name: fake_async 48 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "1.3.1" 52 | flutter: 53 | dependency: "direct main" 54 | description: flutter 55 | source: sdk 56 | version: "0.0.0" 57 | flutter_test: 58 | dependency: "direct dev" 59 | description: flutter 60 | source: sdk 61 | version: "0.0.0" 62 | js: 63 | dependency: transitive 64 | description: 65 | name: js 66 | sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" 67 | url: "https://pub.dev" 68 | source: hosted 69 | version: "0.6.5" 70 | matcher: 71 | dependency: transitive 72 | description: 73 | name: matcher 74 | sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" 75 | url: "https://pub.dev" 76 | source: hosted 77 | version: "0.12.13" 78 | material_color_utilities: 79 | dependency: transitive 80 | description: 81 | name: material_color_utilities 82 | sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 83 | url: "https://pub.dev" 84 | source: hosted 85 | version: "0.2.0" 86 | meta: 87 | dependency: transitive 88 | description: 89 | name: meta 90 | sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" 91 | url: "https://pub.dev" 92 | source: hosted 93 | version: "1.8.0" 94 | path: 95 | dependency: transitive 96 | description: 97 | name: path 98 | sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b 99 | url: "https://pub.dev" 100 | source: hosted 101 | version: "1.8.2" 102 | sky_engine: 103 | dependency: transitive 104 | description: flutter 105 | source: sdk 106 | version: "0.0.99" 107 | source_span: 108 | dependency: transitive 109 | description: 110 | name: source_span 111 | sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 112 | url: "https://pub.dev" 113 | source: hosted 114 | version: "1.9.1" 115 | stack_trace: 116 | dependency: transitive 117 | description: 118 | name: stack_trace 119 | sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 120 | url: "https://pub.dev" 121 | source: hosted 122 | version: "1.11.0" 123 | stream_channel: 124 | dependency: transitive 125 | description: 126 | name: stream_channel 127 | sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" 128 | url: "https://pub.dev" 129 | source: hosted 130 | version: "2.1.1" 131 | string_scanner: 132 | dependency: transitive 133 | description: 134 | name: string_scanner 135 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" 136 | url: "https://pub.dev" 137 | source: hosted 138 | version: "1.2.0" 139 | term_glyph: 140 | dependency: transitive 141 | description: 142 | name: term_glyph 143 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 144 | url: "https://pub.dev" 145 | source: hosted 146 | version: "1.2.1" 147 | test_api: 148 | dependency: transitive 149 | description: 150 | name: test_api 151 | sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 152 | url: "https://pub.dev" 153 | source: hosted 154 | version: "0.4.16" 155 | vector_math: 156 | dependency: transitive 157 | description: 158 | name: vector_math 159 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 160 | url: "https://pub.dev" 161 | source: hosted 162 | version: "2.1.4" 163 | sdks: 164 | dart: ">=2.19.0 <4.0.0" 165 | flutter: ">=3.7.0" 166 | -------------------------------------------------------------------------------- /design_system/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: design_system 2 | description: Design 3 | version: 1.0.0 4 | publish_to: none 5 | 6 | environment: 7 | sdk: '>=2.19.0 <3.0.0' 8 | flutter: ">=3.7.0 <4.0.0" 9 | 10 | dependencies: 11 | # Flutter SDK dependencies 12 | flutter: 13 | sdk: flutter 14 | 15 | dev_dependencies: 16 | flutter_test: 17 | sdk: flutter 18 | 19 | flutter: 20 | uses-material-design: true -------------------------------------------------------------------------------- /design_system/test/design_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:design_system/design/colors.design.dart'; 2 | import 'package:design_system/design/spacings.design.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_test/flutter_test.dart'; 5 | 6 | void main() { 7 | test('Colors are fine', () { 8 | expect( 9 | getMaterialPrimarySwatch().shade900, 10 | Color(0xFFAF4B00), 11 | ); 12 | }); 13 | 14 | test('Theme spacings are fine', () { 15 | expect(ThemeSpacing.l, 40.0); 16 | }); 17 | } 18 | -------------------------------------------------------------------------------- /melos.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_ci_cd_demo 2 | 3 | packages: 4 | - app 5 | - design_system 6 | 7 | scripts: 8 | ############################################### 9 | ## BUILD COMMANDS ## 10 | ############################################### 11 | build:pub_get:all: 12 | run: flutter pub get 13 | exec: 14 | concurrency: 6 15 | description: Install all dependencies 16 | 17 | build:clean: 18 | run: | 19 | flutter clean && \ 20 | flutter pub get 21 | exec: 22 | concurrency: 6 23 | description: Clean Flutter package and install dependencies 24 | 25 | build:clean:all: 26 | run: melos run --no-select build:clean 27 | description: Clean Flutter package and install dependencies for all packages 28 | 29 | build:codegen:build: 30 | run: flutter pub run build_runner build --delete-conflicting-outputs 31 | exec: 32 | concurrency: 1 33 | orderDependents: true 34 | select-package: 35 | depends-on: "build_runner" 36 | description: Run code generation using build_runner in a specific package 37 | 38 | build:codegen:build:all: 39 | run: melos run build:codegen:build --no-select 40 | description: Run code generation using build_runner for all packages in the project 41 | 42 | build:codegen:watch: 43 | run: flutter pub run build_runner watch --delete-conflicting-outputs 44 | exec: 45 | concurrency: 1 46 | orderDependents: true 47 | select-package: 48 | depends-on: "build_runner" 49 | description: Run code generation using build_runner in a specific package, and watch any changes in this package 50 | 51 | build:build-dev-app: 52 | exec: flutter build appbundle --release --flavor dev -t lib/main_dev.dart 53 | description: Build dev app 54 | select-package: 55 | scope: "flutter_ci_cd_demo" 56 | 57 | build:build-uat-app: 58 | exec: flutter build appbundle --release --flavor uat -t lib/main_uat.dart 59 | description: Build UAT app 60 | select-package: 61 | scope: "flutter_ci_cd_demo" 62 | 63 | build:build-prod-app: 64 | exec: flutter build appbundle --release --flavor prod -t lib/main_prod.dart 65 | description: Build prod app 66 | select-package: 67 | scope: "flutter_ci_cd_demo" 68 | 69 | ############################################### 70 | ## QUALITY COMMANDS ## 71 | ############################################### 72 | quality:analyze: 73 | exec: | 74 | flutter analyze --no-fatal-infos --no-fatal-warnings && \ 75 | flutter pub run dart_code_metrics:metrics analyze --no-fatal-warnings . && \ 76 | flutter format . 77 | select-package: 78 | dir-exists: 79 | - lib 80 | description: | 81 | Run Flutter static analysis checks and format 82 | Note: you can also rely on your IDEs Dart Analysis / Issues window. 83 | 84 | quality:analyze:all: 85 | run: melos run --no-select quality:analyze 86 | description: | 87 | Run Flutter static analysis checks and format all packages 88 | Note: you can also rely on your IDEs Dart Analysis / Issues window. 89 | 90 | quality:dcm-checks: 91 | exec: | 92 | flutter pub run dart_code_metrics:metrics check-unnecessary-nullable --no-fatal-found . && \ 93 | flutter pub run dart_code_metrics:metrics check-unused-code --no-fatal-unused --exclude "{**.g.dart,**.gen.dart,**.freezed.dart}" . && \ 94 | flutter pub run dart_code_metrics:metrics check-unused-files --no-fatal-unused . && \ 95 | flutter pub run dart_code_metrics:metrics check-unused-l10n --no-fatal-unused . 96 | select-package: 97 | dir-exists: 98 | - lib 99 | description: Run Dart Code Metrics (DCM) extended checks 100 | 101 | quality:dcm-checks:all: 102 | run: melos run --no-select quality:dcm-checks 103 | description: Run Dart Code Metrics (DCM) extended checks on all packages 104 | 105 | 106 | ############################################### 107 | ## TEST COMMANDS ## 108 | ############################################### 109 | test: 110 | run: flutter test --no-pub --reporter compact 111 | exec: 112 | concurrency: 6 113 | select-package: 114 | dir-exists: 115 | - test 116 | description: Run `flutter test` for a specific package. 117 | 118 | test:all: 119 | run: melos run test --no-select 120 | description: Run all Flutter tests in this project. 121 | 122 | test:update-goldens: 123 | run: flutter test --no-pub --reporter compact --update-goldens 124 | exec: 125 | concurrency: 6 126 | select-package: 127 | dir-exists: 128 | - test 129 | scope: 130 | - "design_system" 131 | - "flutter_ci_cd_demo" 132 | description: Run `flutter test` and update goldens for a specific package. 133 | 134 | test:update-goldens:all: 135 | run: melos run test:update-goldens --no-select 136 | description: Run Flutter tests and update goldens for all packages in this project 137 | 138 | test:with-lcov-coverage: 139 | run: MELOS_ROOT_PATH/scripts/test-with-coverage.sh MELOS_ROOT_PATH MELOS_PACKAGE_PATH MELOS_PACKAGE_NAME 140 | exec: 141 | concurrency: 6 142 | select-package: 143 | dir-exists: 144 | - test 145 | description: Run Flutter tests and publish local lcov coverage for a specific package 146 | 147 | test:with-lcov-coverage:all: 148 | run: | 149 | melos run test:with-lcov-coverage --no-select && \ 150 | melos run test:combine-coverage 151 | description: Run Flutter tests for all packages and generate a combined lcov coverage report 152 | 153 | test:with-html-coverage: 154 | run: | 155 | MELOS_ROOT_PATH/scripts/test-with-coverage.sh MELOS_ROOT_PATH MELOS_PACKAGE_PATH MELOS_PACKAGE_NAME && \ 156 | melos run test:combine-coverage && \ 157 | melos run test:generate-html-coverage 158 | exec: 159 | concurrency: 6 160 | select-package: 161 | dir-exists: 162 | - test 163 | description: Run Flutter tests for a specific package and updates global HTML coverage report 164 | 165 | test:with-html-coverage:all: 166 | run: | 167 | melos run test:with-lcov-coverage --no-select && \ 168 | melos run test:combine-coverage && \ 169 | melos run test:generate-html-coverage 170 | echo "🧪📊 You can find coverage report in the following folder: MELOS_ROOT_PATH/coverage_report/index.html\n\n💡To open it just run: open MELOS_ROOT_PATH/coverage_report/index.html" 171 | description: Run Flutter tests for all packages and generate a combined HTML coverage report 172 | 173 | test:with-html-coverage:all:auto-open: 174 | run: | 175 | melos run test:with-lcov-coverage --no-select && \ 176 | melos run test:combine-coverage && \ 177 | melos run test:generate-html-coverage 178 | open MELOS_ROOT_PATH/coverage_report/index.html 179 | description: Run Flutter tests for all packages and generate a combined HTML coverage report 180 | 181 | test:combine-coverage: 182 | run: MELOS_ROOT_PATH/scripts/combine-coverage.sh MELOS_ROOT_PATH 183 | description: Combine individual lcov coverage into a single lcov coverage file 184 | 185 | test:generate-html-coverage: 186 | run: MELOS_ROOT_PATH/scripts/generate-html-coverage.sh MELOS_ROOT_PATH 187 | description: Take combined lcov file and generate a human-readable HTML report 188 | 189 | run:dev-app: 190 | exec: flutter run -t 'MELOS_ROOT_PATH/app/lib/main_dev.dart' --flavor dev 191 | select-package: 192 | scope: "flutter_ci_cd_demo" 193 | 194 | ############################################### 195 | ## RUN COMMANDS ## 196 | ############################################### 197 | run:uat-app: 198 | exec: flutter run -t 'MELOS_ROOT_PATH/app/lib/main_uat.dart' --flavor uat 199 | select-package: 200 | scope: "flutter_ci_cd_demo" 201 | 202 | run:prod-app: 203 | exec: flutter run -t 'MELOS_ROOT_PATH/app/lib/main_prod.dart' --flavor prod 204 | select-package: 205 | scope: "flutter_ci_cd_demo" 206 | 207 | environment: 208 | sdk: '>=2.19.0 <3.0.0' 209 | flutter: ">=3.7.0 <4.0.0" 210 | -------------------------------------------------------------------------------- /scripts/combine-coverage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | PROJECT_ROOT_PATH=$1 4 | while read FILENAME; do 5 | LCOV_INPUT_FILES="$LCOV_INPUT_FILES -a \"$PROJECT_ROOT_PATH/coverage/$FILENAME\"" 6 | done < <( ls "$1/coverage/" ) 7 | 8 | eval lcov "${LCOV_INPUT_FILES}" -o $PROJECT_ROOT_PATH/coverage_report/combined_lcov.info 9 | 10 | lcov --remove $PROJECT_ROOT_PATH/coverage_report/combined_lcov.info \ 11 | "lib/main_*.dart" \ 12 | "*.gr.dart" \ 13 | "*.g.dart" \ 14 | "*.freezed.dart" \ 15 | "*di.config.dart" \ 16 | "*.i69n.dart" \ 17 | "*/generated/*" \ 18 | "*.theme_extension.dart" \ 19 | -o $PROJECT_ROOT_PATH/coverage_report/cleaned_combined_lcov.info -------------------------------------------------------------------------------- /scripts/generate-html-coverage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## Generate coverage report 4 | PROJECT_ROOT_PATH=$1 5 | genhtml -o $PROJECT_ROOT_PATH/coverage_report/ $PROJECT_ROOT_PATH/coverage_report/cleaned_combined_lcov.info 6 | -------------------------------------------------------------------------------- /scripts/keystore_properties_template.yaml: -------------------------------------------------------------------------------- 1 | prodStoreFile=dumbValue 2 | prodStorePassword=dumbValue 3 | prodKeyAlias=dumbValue 4 | prodKeyPassword=dumbValue 5 | 6 | uatStoreFile=dumbValue 7 | uatKeyAlias=dumbValue 8 | uatStorePassword=dumbValue 9 | uatKeyPassword=dumbValue -------------------------------------------------------------------------------- /scripts/pubspec_template.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_ci_cd_demo 2 | description: Dart Code Metrics helper for aggregated report generation 3 | 4 | environment: 5 | sdk: '>=2.19.0 <3.0.0' 6 | flutter: ">=3.7.0 <4.0.0" -------------------------------------------------------------------------------- /scripts/semver.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | RE='([0-9]+)\.([0-9]+)\.([0-9]+)\+?([0-9]+)?' 4 | 5 | lastVersion="$1" 6 | 7 | if [ -z "$2" ] 8 | then 9 | nextVersion=$lastVersion 10 | else 11 | nextVersion="$2" 12 | fi 13 | 14 | LAST_UAT_BUILD_NUMBER=`echo $lastVersion | sed -E "s/$RE/\4/"` 15 | 16 | NEXT_VERSION_MAJOR=`echo $nextVersion | sed -E "s/$RE/\1/"` 17 | NEXT_VERSION_MINOR=`echo $nextVersion | sed -E "s/$RE/\2/"` 18 | NEXT_VERSION_PATCH=`echo $nextVersion | sed -E "s/$RE/\3/"` 19 | 20 | ((LAST_UAT_BUILD_NUMBER++)) 21 | echo "$NEXT_VERSION_MAJOR.$NEXT_VERSION_MINOR.$NEXT_VERSION_PATCH+$LAST_UAT_BUILD_NUMBER" -------------------------------------------------------------------------------- /scripts/test-with-coverage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## Generate coverage report 4 | PROJECT_ROOT_PATH=$1 5 | PACKAGE_PATH=$2 6 | PACKAGE_NAME=$3 7 | 8 | PACKAGE_LCOV_INFO_PATH=$PROJECT_ROOT_PATH/coverage/lcov_$PACKAGE_NAME.info 9 | PACKAGE_TEST_REPORT_PATH=$PROJECT_ROOT_PATH/test_reports/${PACKAGE_NAME}_test_report.json 10 | 11 | mkdir -p $PROJECT_ROOT_PATH/coverage/ 12 | flutter test \ 13 | --no-pub \ 14 | --machine \ 15 | --coverage \ 16 | --coverage-path $PACKAGE_LCOV_INFO_PATH > $PACKAGE_TEST_REPORT_PATH 17 | 18 | escapedPath="$(echo $PACKAGE_PATH | sed 's/\//\\\//g')" 19 | 20 | # Requires gsed on MacOS machines because otherwise sed is not the same... 21 | if [[ "$OSTYPE" =~ ^darwin ]]; then 22 | gsed -i "s/^SF:lib/SF:$escapedPath\/lib/g" $PACKAGE_LCOV_INFO_PATH 23 | else 24 | sed -i "s/^SF:lib/SF:$escapedPath\/lib/g" $PACKAGE_LCOV_INFO_PATH 25 | fi 26 | -------------------------------------------------------------------------------- /test_reports/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orevial/flutter-ci-cd-demo/6b3f3baaa0cba69b98f7cc98fbdc31f65bf0dadb/test_reports/.gitkeep --------------------------------------------------------------------------------